var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
  for (var prop in b || (b = {}))
    if (__hasOwnProp.call(b, prop))
      __defNormalProp(a, prop, b[prop]);
  if (__getOwnPropSymbols)
    for (var prop of __getOwnPropSymbols(b)) {
      if (__propIsEnum.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    }
  return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
import { $ as tinycolor, Z as lru } from "./index.js";
const ResourceTypes = {
  DataBuffers: "DataBuffers",
  IndexBuffer: "IndexBuffer",
  Uniforms: "Uniforms",
  Textures: "Textures",
  OffscreenTarget: "OffscreenTarget"
};
const SchemaTypes = {
  vec4: "vec4",
  vec3: "vec3",
  vec2: "vec2",
  int: "int",
  float: "float",
  mat4: "mat4",
  mat3: "mat3",
  mat2: "mat2",
  tex2D: "tex2D",
  texCube: "texCube"
};
const GLTypes = {
  Triangles: "Triangles",
  Lines: "Lines",
  Repeat: "Repeat",
  MirroredRepeat: "MirroredRepeat",
  ClampToEdge: "ClampToEdge",
  Nearest: "Nearest",
  Linear: "Linear",
  NearestMipmapNearest: "NearestMipmapNearest",
  LinearMipmapNearest: "LinearMipmapNearest",
  NearestMipmapLinear: "NearestMipmapLinear",
  LinearMipmapLinear: "LinearMipmapLinear",
  RGB: "RGB",
  RGBA: "RGBA",
  SRGB: "SRGB"
};
const RendererConfig = {
  contextAttributes: {},
  extensions: ["OES_element_index_uint", "WEBGL_depth_texture"]
};
const isPowerOf2$1 = (value) => (value & value - 1) === 0;
const mapValue = (obj, valueMapper) => Object.keys(obj).reduce((newObj, key) => __spreadProps(__spreadValues({}, newObj), { [key]: valueMapper(obj, key) }), {});
const getNumComponents = (bufferType) => {
  const { vec2: vec22, vec3: vec32, vec4: vec42, float: float2 } = SchemaTypes;
  const mapping = { [vec22]: 2, [vec32]: 3, [vec42]: 4, [float2]: 1 };
  return mapping[bufferType];
};
const groupResources = (resources) => {
  const Types = ResourceTypes;
  let [dataBuffers, indexResource, uniforms, textures] = [{}, null, {}, {}];
  for (let i = 0; i < resources.length; i++) {
    const resource = resources[i];
    const { type } = resource;
    if (type === Types.DataBuffers) {
      dataBuffers = __spreadValues(__spreadValues({}, dataBuffers), resource.buffers);
    } else if (type === Types.IndexBuffer) {
      indexResource = resource;
    } else if (type === Types.Uniforms) {
      uniforms = __spreadValues(__spreadValues({}, uniforms), resource.state);
    } else if (type === Types.Textures) {
      textures = __spreadValues(__spreadValues({}, textures), resource.textures);
    }
  }
  return [dataBuffers, indexResource, uniforms, textures];
};
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
const getWebGLInstance = (canvas) => {
  return canvas.getContext("webgl");
};
const getExtensions = (gl, config2) => {
  const extensions = {};
  config2.extensions.forEach((name) => {
    extensions[name] = gl.getExtension(name);
  });
  return extensions;
};
const compileShader = (gl, type, source) => {
  const shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    console.error("Error compiling shaders", gl.getShaderInfoLog(shader));
    gl.deleteShader(shader);
    return null;
  }
  return shader;
};
const initShader = (gl, defines, vs2, fs2) => {
  const defineStr = Object.keys(defines).reduce((str, key) => defines[key] ? str + `#define ${key} ${defines[key]}
` : "", "");
  const vertexShader2 = compileShader(gl, gl.VERTEX_SHADER, defineStr + vs2);
  const fragmentShader2 = compileShader(gl, gl.FRAGMENT_SHADER, defineStr + fs2);
  const shaderProgram = gl.createProgram();
  gl.attachShader(shaderProgram, vertexShader2);
  gl.attachShader(shaderProgram, fragmentShader2);
  gl.linkProgram(shaderProgram);
  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
    console.error("Error initing program", gl.getProgramInfoLog(shaderProgram));
    return null;
  }
  return shaderProgram;
};
const initShaderRefs = (gl, defines, schema, vs2, fs2) => {
  const program = initShader(gl, defines, vs2, fs2);
  const attributes = mapValue(schema.buffers, (attributes2, key) => ({
    type: attributes2[key].type,
    location: gl.getAttribLocation(program, key)
  }));
  const uniforms = mapValue(__spreadValues(__spreadValues({}, schema.uniforms), schema.textures), (uniforms2, key) => ({
    type: uniforms2[key].type,
    location: gl.getUniformLocation(program, key)
  }));
  return { program, attributes, uniforms };
};
const clear = (gl, color) => {
  const [r, g, b, a] = color;
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.clearColor(r, g, b, a);
  gl.clearDepth(1);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  gl.enable(gl.DEPTH_TEST);
};
const initDataBuffers = (gl, state) => {
  const buffers = {};
  const bufferKeys = Object.keys(state);
  bufferKeys.forEach((key) => {
    const buffer = gl.createBuffer();
    buffers[key] = buffer;
    updateDataBuffer(gl, buffers[key], state[key]);
  });
  return buffers;
};
const updateDataBuffer = (gl, buffer, array) => {
  const data = array instanceof Float32Array ? array : new Float32Array(array);
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
};
const destroyDataBuffer = (gl, buffer) => {
  gl.deleteBuffer(buffer);
};
const initIndexBuffer = (gl, state) => {
  const { array } = state;
  const buffer = gl.createBuffer();
  updateIndexBuffer(gl, buffer, array);
  return buffer;
};
const updateIndexBuffer = (gl, buffer, array) => {
  const data = array instanceof Uint32Array ? array : new Uint32Array(array);
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW);
};
const destroyIndexBuffer = (gl, buffer) => {
  gl.deleteBuffer(buffer);
};
const compatSRGB = (gl) => {
  const { extensions } = gl;
  return !isSafari && extensions.EXT_SRGB ? extensions.EXT_SRGB.SRGB_EXT : gl.RGBA;
};
const compatSRGBA = (gl) => {
  const { extensions } = gl;
  return !isSafari && extensions.EXT_SRGB ? extensions.EXT_SRGB.SRGB_ALPHA_EXT : gl.RGBA;
};
const nativeTypeHOF = (gl) => (type) => {
  const map = {
    [GLTypes.Repeat]: gl.REPEAT,
    [GLTypes.MirroredRepeat]: gl.MIRRORED_REPEAT,
    [GLTypes.ClampToEdge]: gl.CLAMP_TO_EDGE,
    [GLTypes.Linear]: gl.LINEAR,
    [GLTypes.Nearest]: gl.NEAREST,
    [GLTypes.NearestMipmapNearest]: gl.NEAREST_MIPMAP_NEAREST,
    [GLTypes.LinearMipmapNearest]: gl.LINEAR_MIPMAP_NEAREST,
    [GLTypes.NearestMipmapLinear]: gl.NEAREST_MIPMAP_LINEAR,
    [GLTypes.LinearMipmapLinear]: gl.LINEAR_MIPMAP_LINEAR,
    [GLTypes.RGB]: gl.RGB,
    [GLTypes.RGBA]: gl.RGBA,
    [GLTypes.SRGB]: compatSRGB(gl),
    [GLTypes.SRGBA]: compatSRGBA(gl)
  };
  return map[type];
};
const init2DTexture = (gl, val) => {
  const texture = gl.createTexture();
  update2DTexture(gl, texture, val);
  return texture;
};
const initCubeTexture = (gl, val) => {
  const texture = gl.createTexture();
  updateCubeTexture(gl, texture, val);
  return texture;
};
const initTextures = (gl, state) => {
  const textures = {};
  Object.keys(state).forEach((key) => {
    const texture = state[key].image ? init2DTexture(gl, state[key]) : initCubeTexture(gl, state[key]);
    textures[key] = texture;
  });
  return textures;
};
const supportMipmap = (image) => image && isPowerOf2$1(image.width) && isPowerOf2$1(image.height) && image.nodeName !== "VIDEO";
const update2DTexture = (gl, texture, val) => {
  const native = nativeTypeHOF(gl);
  const { image, flip, space } = val;
  let { wrapS, wrapT, minFilter, magFilter } = val;
  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, texture);
  if (image) {
    if (flip)
      gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    const s = native(space || GLTypes.RGBA);
    gl.texImage2D(gl.TEXTURE_2D, 0, s, s, gl.UNSIGNED_BYTE, image);
    if (supportMipmap(image))
      gl.generateMipmap(gl.TEXTURE_2D);
    if (!supportMipmap(image)) {
      if (!wrapS)
        wrapS = GLTypes.ClampToEdge;
      if (!wrapT)
        wrapT = GLTypes.ClampToEdge;
      if (!minFilter)
        minFilter = GLTypes.Linear;
    }
  }
  if (wrapS)
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, native(wrapS));
  if (wrapT)
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, native(wrapT));
  if (minFilter) {
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, native(minFilter));
  }
  if (magFilter) {
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, native(magFilter));
  }
  return texture;
};
const updateCubeTexture = (gl, texture, val) => {
  const native = nativeTypeHOF(gl);
  const {
    images,
    level,
    flip,
    wrapS,
    wrapT,
    minFilter,
    magFilter,
    space
  } = val;
  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
  if (wrapS) {
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, native(wrapS));
  }
  if (wrapT) {
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, native(wrapT));
  }
  if (minFilter) {
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, native(minFilter));
  }
  if (magFilter) {
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, native(magFilter));
  }
  if (images) {
    if (flip)
      gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    const faces = [
      gl.TEXTURE_CUBE_MAP_POSITIVE_X,
      gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
      gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
      gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
      gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
      gl.TEXTURE_CUBE_MAP_NEGATIVE_Z
    ];
    let count = 0;
    const s = native(space || GLTypes.RGBA);
    for (let i = 0; i < faces.length; i++) {
      for (let j = 0; j <= level; j++) {
        const face = faces[i];
        gl.texImage2D(face, j, s, s, gl.UNSIGNED_BYTE, images[count]);
        count++;
      }
    }
  }
  return texture;
};
const destroyTexture = (gl, texture) => {
  gl.deleteTexture(texture);
};
const initColorOffscreen = (gl, state) => {
  const fbo = gl.createFramebuffer();
  const rbo = gl.createRenderbuffer();
  const colorTexture = gl.createTexture();
  const depthTexture = null;
  const { size } = state;
  gl.bindTexture(gl.TEXTURE_2D, colorTexture);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
  gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size, size);
  gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTexture, 0);
  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rbo);
  const e = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
  if (gl.FRAMEBUFFER_COMPLETE !== e) {
    console.error("Frame buffer object is incomplete: " + e.toString());
  }
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  gl.bindTexture(gl.TEXTURE_2D, null);
  gl.bindRenderbuffer(gl.RENDERBUFFER, null);
  return { fbo, rbo, colorTexture, depthTexture };
};
const initDepthOffscreen = (gl, state) => {
  const { size } = state;
  const fbo = gl.createFramebuffer();
  const rbo = null;
  const colorTexture = gl.createTexture();
  const depthTexture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, colorTexture);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  gl.bindTexture(gl.TEXTURE_2D, depthTexture);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, size, size, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null);
  gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTexture, 0);
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTexture, 0);
  const e = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
  if (e !== gl.FRAMEBUFFER_COMPLETE) {
    console.error("framebuffer not complete", e.toString());
  }
  gl.bindTexture(gl.TEXTURE_2D, null);
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  return { fbo, rbo, colorTexture, depthTexture };
};
const initOffscreen = (gl, state) => {
  if (state.depth)
    return initDepthOffscreen(gl, state);
  else
    return initColorOffscreen(gl, state);
};
const padDefault = (schema, key, val) => {
  return val !== void 0 ? val : schema.uniforms[key].default;
};
const draw = (gl, plugin, dataBuffers, indexResource, uniforms, textures) => {
  const { schema, shaderRefs } = plugin;
  gl.useProgram(shaderRefs.program);
  Object.keys(shaderRefs.attributes).forEach((key) => {
    if (!schema.buffers[key] || schema.buffers[key].type === SchemaTypes.index)
      return;
    const { location } = shaderRefs.attributes[key];
    const { n, type } = schema.buffers[key];
    const numComponents = n || getNumComponents(type);
    gl.bindBuffer(gl.ARRAY_BUFFER, dataBuffers[key]);
    gl.vertexAttribPointer(location, numComponents, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(location);
  });
  const { buffer, state } = indexResource;
  const { offset, count } = state;
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
  let unit = -1;
  Object.keys(shaderRefs.uniforms).forEach((key) => {
    const { type, location } = shaderRefs.uniforms[key];
    let val;
    const isTexure = type === SchemaTypes.tex2D || type === SchemaTypes.texCube;
    if (!isTexure) {
      val = padDefault(schema, key, uniforms[key]);
    }
    const uniformSetterMapping = {
      [SchemaTypes.vec4]: () => gl.uniform4fv(location, val),
      [SchemaTypes.vec3]: () => gl.uniform3fv(location, val),
      [SchemaTypes.vec2]: () => gl.uniform2fv(location, val),
      [SchemaTypes.int]: () => {
        !val || typeof val === "number" || typeof val === "string" ? gl.uniform1i(location, val) : gl.uniform1iv(location, val);
      },
      [SchemaTypes.float]: () => {
        !val || typeof val === "number" || typeof val === "string" ? gl.uniform1f(location, val) : gl.uniform1fv(location, val);
      },
      [SchemaTypes.mat4]: () => gl.uniformMatrix4fv(location, false, val),
      [SchemaTypes.mat3]: () => gl.uniformMatrix3fv(location, false, val),
      [SchemaTypes.mat2]: () => gl.uniformMatrix2fv(location, false, val),
      [SchemaTypes.tex2D]: () => {
        unit++;
        const texture = textures[key];
        if (!texture)
          console.warn(`Missing texture ${key} at unit ${unit}`);
        gl.uniform1i(location, unit);
        gl.activeTexture(gl.TEXTURE0 + unit);
        gl.bindTexture(gl.TEXTURE_2D, texture);
      },
      [SchemaTypes.texCube]: () => {
        unit++;
        const texture = textures[key];
        if (!texture)
          console.warn(`Missing texture ${key} at unit ${unit}`);
        gl.uniform1i(location, unit);
        gl.activeTexture(gl.TEXTURE0 + unit);
        gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
      }
    };
    if (val !== void 0 || isTexure)
      uniformSetterMapping[type]();
  });
  const drawMode = schema.mode === GLTypes.Triangles ? gl.TRIANGLES : gl.LINES;
  gl.drawElements(drawMode, count, gl.UNSIGNED_INT, offset * 4);
};
class ShadePlugin {
  constructor(beam, pluginTemplate) {
    this.beam = beam;
    const {
      buffers = {},
      uniforms = {},
      textures = {},
      mode = GLTypes.Triangles
    } = pluginTemplate;
    this.schema = { buffers, uniforms, textures, mode };
    const { vs: vs2, fs: fs2, defines = {} } = pluginTemplate;
    this.shaderRefs = initShaderRefs(beam.gl, defines, this.schema, vs2, fs2);
  }
  set({ vs: vs2, fs: fs2, defines }) {
  }
}
const createResource = (gl, type, state) => {
  const Types = ResourceTypes;
  class Resource {
    constructor() {
      this.state = state;
      this.type = type;
    }
    set(key, val) {
      this.state[key] = val;
      return this;
    }
  }
  class DataBuffersResource extends Resource {
    constructor() {
      super();
      this.buffers = initDataBuffers(gl, state);
    }
    set(key, val) {
      this.state[key] = val;
      updateDataBuffer(gl, this.buffers[key], val);
      return this;
    }
    destroy(key) {
      destroyDataBuffer(gl, this.buffers[key]);
      delete this.state[key];
    }
  }
  class IndexBufferResource extends Resource {
    constructor() {
      super();
      const { offset = 0, count = state.array.length } = state;
      this.state.offset = offset;
      this.state.count = count;
      this.buffer = initIndexBuffer(gl, state);
    }
    set(state2) {
      const { offset = 0, count = state2.array.length } = state2;
      this.state.offset = offset;
      this.state.count = count;
      updateIndexBuffer(gl, this.buffer, state2.array);
      return this;
    }
    destroy() {
      destroyIndexBuffer(gl, this.buffer);
      delete this.state;
    }
  }
  class UniformsResource extends Resource {
  }
  class TexturesResource extends Resource {
    constructor() {
      super();
      this.textures = initTextures(gl, state);
    }
    set(key, val) {
      const { textures, state: state2 } = this;
      const oldVal = state2[key];
      let texture;
      if (val.constructor.name !== "Object") {
        const offscreenTarget = val;
        texture = offscreenTarget.state.depth ? offscreenTarget.depthTexture : offscreenTarget.colorTexture;
      } else if (oldVal) {
        const newVal = __spreadProps(__spreadValues({}, val), { flip: oldVal.flip, space: oldVal.space });
        if (oldVal.image) {
          texture = update2DTexture(gl, textures[key], newVal);
        } else {
          texture = updateCubeTexture(gl, textures[key], newVal);
        }
      } else {
        texture = val.image ? init2DTexture(gl, val) : initCubeTexture(gl, val);
      }
      textures[key] = texture;
      state2[key] = __spreadValues(__spreadValues({}, state2[key]), val);
      return this;
    }
    destroy(key) {
      destroyTexture(gl, this.textures[key]);
      delete this.state[key];
    }
  }
  class OffscreenTargetResource extends Resource {
    constructor() {
      super();
      const { size = 2048 } = this.state;
      this.state.size = size;
      const {
        fbo,
        rbo,
        colorTexture,
        depthTexture
      } = initOffscreen(gl, state);
      this.fbo = fbo;
      this.rbo = rbo;
      this.colorTexture = colorTexture;
      this.depthTexture = depthTexture;
    }
  }
  const resourceCreatorMap = {
    [Types.DataBuffers]: () => new DataBuffersResource(),
    [Types.IndexBuffer]: () => new IndexBufferResource(),
    [Types.Uniforms]: () => new UniformsResource(),
    [Types.Textures]: () => new TexturesResource(),
    [Types.OffscreenTarget]: () => new OffscreenTargetResource()
  };
  return resourceCreatorMap[type]();
};
class Beam {
  constructor(canvas, config2 = {}) {
    this.gl = getWebGLInstance(canvas);
    this.config = __spreadValues(__spreadValues({}, RendererConfig), config2);
    this.gl.extensions = getExtensions(this.gl, this.config);
  }
  clear(color = [0, 0, 0, 0]) {
    clear(this.gl, color);
    return this;
  }
  draw(plugin, ...resources) {
    const groupedResources = groupResources(resources);
    draw(this.gl, plugin, ...groupedResources);
    return this;
  }
  plugin(pluginTemplate) {
    const plugin = new ShadePlugin(this, pluginTemplate);
    return plugin;
  }
  resource(type, state = {}) {
    return createResource(this.gl, type, state);
  }
  define({ name, onBefore, onAfter }) {
    this[name] = (arg, modifier = () => {
    }) => {
      if (onBefore)
        onBefore(this.gl, arg);
      modifier(arg);
      if (onAfter)
        onAfter(this.gl, arg);
      return this;
    };
  }
}
const beforeWithColor = (gl, resource) => {
  const { state, colorTexture, fbo, rbo } = resource;
  const { size } = state;
  gl.viewport(0, 0, size, size);
  gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
  gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
  gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size, size);
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTexture, 0);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
};
const beforeWithDepth = (gl, resource) => {
  const { state, fbo } = resource;
  const { size } = state;
  gl.viewport(0, 0, size, size);
  gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
  gl.clear(gl.DEPTH_BUFFER_BIT);
};
const Offscreen2DCommand = {
  name: "offscreen2D",
  onBefore(gl, resource) {
    const { depth } = resource.state;
    depth ? beforeWithDepth(gl, resource) : beforeWithColor(gl, resource);
  },
  onAfter(gl) {
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    gl.viewport(0, 0, gl.canvas.clientWidth, gl.canvas.clientHeight);
  }
};
const config = {
  maxWebglCanvasSize: 4096,
  structuresNum: 3,
  whiteColor: "#ffffff",
  normalMapColor: "#807fff",
  metalRoughnessColor: "#0099ff",
  brdfUrl: "https://st-gdx.dancf.com/gaodingx/17/design/20190429-142341-7a2c.png",
  initFontSize: 100,
  ratio: 1,
  timeOut: 2e4,
  defaultFont: "https://st0.dancf.com/csc/3/fonts/0/20190015-164859-b2d8.woff",
  pointLightsNum: 5,
  gradientMaxNum: 4,
  offscreenSize: 1024,
  safeRatio: 1.02,
  beamConfig: {
    contextAttributes: {
      antialias: true
    },
    extensions: [
      "EXT_shader_texture_lod",
      "EXT_SRGB",
      "OES_standard_derivatives",
      "OES_element_index_uint"
    ]
  }
};
const vs$2 = `
  attribute vec4 position;
  uniform mat4 u_MVPMatrix;

  void main() {
    gl_Position = u_MVPMatrix * position;
  }
  `;
const fs$2 = `
  precision lowp float;
  uniform vec4 u_Color;
  void main() {
    gl_FragColor = u_Color;
  }
  `;
const { vec4: vec4$4, mat4: mat4$4 } = SchemaTypes;
const Mesh = {
  vs: vs$2,
  fs: fs$2,
  buffers: {
    position: { type: vec4$4, n: 3 }
  },
  mode: GLTypes.Lines,
  uniforms: {
    u_MVPMatrix: { type: mat4$4 },
    u_Color: { type: vec4$4, default: [1, 0, 0, 1] }
  }
};
const vs$1 = `
precision highp float;
uniform mat4 u_MVPMatrix;
attribute vec4 position;

varying vec3 v_Position1;
varying vec3 v_Position2;

void main() {
    v_Position1 =  position.xyz;
    gl_Position =  u_MVPMatrix * position;
    v_Position2 = gl_Position.xyz / gl_Position.w;
}
`;
const fs$1 = `
precision highp float;
const int LINENUM = 2;
const float prec = 1.;
const float lineWidth = 1.;

uniform mat4 u_MVPMatrixInvert;
uniform vec3 u_Line[3];

varying vec3 v_Position1;
varying vec3 v_Position2;
struct Line {
    vec4 color;
    vec3 equation;
};
uniform Line u_Lines[LINENUM];

float getSmoothLine(vec3 pos, float v){
    return smoothstep(-prec-lineWidth , -lineWidth , v) - 
        smoothstep(lineWidth, lineWidth + prec, v);
}

// a*x + b*y + c=0;
float plotLine(vec3 pos1,  vec3 pos2, vec3 line){
    float molecular = dot(pos1, line);
    // float v = molecular/length(u_MVPMatrixInvert * vec4(line, 1.));
    // float v = molecular/length(u_MVPMatrix * vec4(line, 1.));
    float v = molecular/length(line);
    return getSmoothLine(pos2, v) ;
}

void main() {
    vec4 pct = vec4(0.);
    for(int i = 0; i < LINENUM; i++) {
        float k = plotLine(v_Position1, v_Position2, u_Lines[i].equation);
        pct +=  k* u_Lines[i].color;
    }
    if(pct.w > 0.){
        gl_FragColor = pct;
    }else{
        discard;
    }
    
}
`;
const { vec3: vec3$1, vec4: vec4$3, mat4: mat4$3, float: float$2 } = SchemaTypes;
const Line = {
  vs: vs$1,
  fs: fs$1,
  buffers: {
    position: { type: vec4$3, n: 3 }
  },
  uniforms: {
    u_MVPMatrix: { type: mat4$3 },
    u_time: { type: float$2, default: 0 },
    "u_Lines[0].equation": { type: vec3$1, default: [1, 0, 0] },
    "u_Lines[1].equation": { type: vec3$1, default: [0, 0, 1] },
    "u_Lines[0].color": { type: vec4$3, default: [1, 0, 0, 1] },
    "u_Lines[1].color": { type: vec4$3, default: [0, 1, 0, 1] }
  }
};
const vertexShader = `
    attribute vec4 position;
    #ifdef HAS_NORMALS
        attribute vec4 normal;
    #endif

    #ifdef HAS_TANGENTS
        attribute vec4 a_Tangent;
    #endif

    #ifdef HAS_UV
    attribute vec2 texCoord;
    #endif
    uniform mat4 u_MVPMatrix,u_ModelMatrix,u_NormalMatrix;
    varying vec3 v_Position;
    varying vec2 v_UV;
    #ifdef HAS_NORMALS
        #ifdef HAS_TANGENTS
            varying mat3 v_TBN;
        #else
            varying vec3 v_Normal;
        #endif
    #endif
    void main() {
        vec4 v=u_ModelMatrix*position;
        v_Position=vec3(v.rgb)/v.a;

        #ifdef HAS_NORMALS

            #ifdef HAS_TANGENTS
                vec3 H = normalize(vec3(u_NormalMatrix*vec4(normal.rgb,0.)));
                vec3 u = normalize(vec3(u_ModelMatrix*vec4(a_Tangent.rgb,0.)));
                vec3 b = cross(H,u)*a_Tangent.a;
                v_TBN = mat3(u,b,H);
            #else
                v_Normal = normalize(vec3(u_ModelMatrix*vec4(normal.rgb,0.)));
            #endif

        #endif

        #ifdef HAS_UV
            v_UV=texCoord;
        #else
            v_UV=vec2(0.,0.);
        #endif

        gl_Position=u_MVPMatrix*position;
    }
`;
const fragmentShader = `
#extension GL_EXT_shader_texture_lod: enable
#extension GL_OES_standard_derivatives : enable

precision highp float;

struct PointLight {vec3 pos;vec3 color;};
uniform PointLight u_Lights[NR_POINT_LIGHTS];

struct HemiLight {vec3 dir; vec3 color;};
uniform HemiLight u_HemiLight;

#ifdef USE_IBL
uniform samplerCube u_DiffuseEnvSampler;
uniform samplerCube u_SpecularEnvSampler;
uniform sampler2D u_brdfLUT;
uniform vec3 u_EnvColor;
#endif

#ifdef HAS_BASECOLORMAP
uniform sampler2D u_BaseColorSampler;
uniform mat3 u_TexMat;
#endif

#ifdef USE_GRADIENT
    uniform vec3 u_BoundingBox;
    uniform vec3 u_GradientVec;
    struct gradientStops {
        vec3 color;
        float offset;
    };
    uniform gradientStops u_GradientColor[NR_GRADIENT_COLORS];
#endif

#ifdef HAS_NORMALMAP
    uniform sampler2D u_NormalSampler;
    uniform float u_NormalScale;
    uniform float u_NormalStrength;
#endif

#ifdef HAS_EMISSIVEMAP
    uniform sampler2D u_EmissiveSampler;
    uniform vec3 u_EmissiveFactor;
#endif

#ifdef HAS_METALROUGHNESSMAP
    uniform sampler2D u_MetallicRoughnessSampler;
#endif

#ifdef HAS_OCCLUSIONMAP
    uniform sampler2D u_OcclusionSampler;
    uniform float u_OcclusionStrength;
#endif

uniform vec2 u_MetallicRoughnessValues;
uniform vec4 u_BaseColorFactor;
uniform float u_BaseColorScale;

uniform vec3 u_Camera;


uniform vec4 u_ScaleDiffBaseMR;
uniform vec4 u_ScaleFGDSpec;
uniform vec4 u_ScaleIBLAmbient;
uniform int u_Type;
uniform vec3 u_FaceColor;

varying vec3 v_Position;

varying vec2 v_UV;

#ifdef HAS_NORMALS
    #ifdef HAS_TANGENTS
        varying mat3 v_TBN;
    #else
        varying vec3 v_Normal;
    #endif
#endif

struct PBRInfo {
    float NdotL; 
    float NdotV;
    float NdotH;
    float LdotH;
    float VdotH;
    float perceptualRoughness;
    float metalness;
    vec3 reflectance0;
    vec3 reflectance90;
    float alphaRoughness;
    vec3 diffuseColor;
    vec3 specularColor;
};

const float M_PI = 3.141592653589793;
const float c_MinRoughness = 0.04;

vec4 SRGBtoLINEAR(vec4 srgbIn) {
    #ifdef MANUAL_SRGB

        #ifdef SRGB_FAST_APPROXIMATION
            vec3 linOut = pow(srgbIn.xyz,vec3(2.2));
        #else
            vec3 bLess = step(vec3(0.04045),srgbIn.xyz);
            vec3 linOut = mix( srgbIn.xyz/vec3(12.92), pow((srgbIn.xyz+vec3(0.055))/vec3(1.055),vec3(2.4)), bLess );
        #endif
        return vec4(linOut,srgbIn.w);;
    #else
        return srgbIn;
    #endif
}

vec3 getNormal() {
    #ifndef HAS_TANGENTS
        vec3 pos_dx = dFdx(v_Position);
        vec3 pos_dy = dFdy(v_Position);
        vec3 tex_dx = dFdx(vec3(v_UV, 0.0));
        vec3 tex_dy = dFdy(vec3(v_UV, 0.0));
        vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t);

        #ifdef HAS_NORMALS
            vec3 ng = normalize(v_Normal);
        #else
            vec3 ng = cross(pos_dx, pos_dy);
        #endif

        t = normalize(t - ng * dot(ng, t));
        vec3 b = normalize(cross(ng, t));
        mat3 tbn = mat3(t, b, ng);
    #else
        mat3 tbn = v_TBN;
    #endif

    #ifdef HAS_NORMALMAP
        vec3 n = texture2D(u_NormalSampler, v_UV / u_NormalScale).rgb;
        n = normalize(tbn * ((2.0 * n - 1.0) * vec3(u_NormalStrength, u_NormalStrength, 1.0)));
    #else
        vec3 n = normalize(tbn[2].xyz);
    #endif

    return n;
}

#ifdef USE_IBL
vec3 getIBLContribution(PBRInfo pbrInputs, vec3 n, vec3 reflection) {
    float mipCount = 9.0;
    float lod = (pbrInputs.perceptualRoughness * mipCount);

    vec3 brdf = texture2D(u_brdfLUT, vec2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness)).rgb;
    vec3 diffuseLight = SRGBtoLINEAR(textureCube(u_DiffuseEnvSampler, n)).rgb;

    #ifdef USE_TEX_LOD
        vec3 specularLight = SRGBtoLINEAR(textureCubeLodEXT(u_SpecularEnvSampler, reflection, lod)).rgb;
    #else
        vec3 specularLight = SRGBtoLINEAR(textureCube(u_SpecularEnvSampler, reflection)).rgb;
    #endif

    vec3 diffuse = diffuseLight * pbrInputs.diffuseColor;
    vec3 specular = specularLight * (pbrInputs.specularColor * brdf.x + brdf.y);

    diffuse *= u_ScaleIBLAmbient.x;
    specular *= u_ScaleIBLAmbient.y;

    return diffuse + specular;
}
vec3 getColorEnvContribution(PBRInfo pbrInputs) {
    vec3 brdf = texture2D(u_brdfLUT, vec2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness)).rgb;
    vec3 diffuse = u_EnvColor * pbrInputs.diffuseColor;
    vec3 specular = u_EnvColor * (pbrInputs.specularColor * brdf.x + brdf.y);
    return diffuse + specular;
}
#endif

float hemiIntegral(float angle1){
    float i = sin(angle1);
    return max(0.5 * i * i/(1. - cos(angle1)), 0.);
}

vec3 getHEMIContribution(PBRInfo pbrInputs, vec3 n, vec3 reflection) {
    vec3 brdf = texture2D(u_brdfLUT, vec2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness)).rgb;
    float cosAngle = dot(u_HemiLight.dir, reflection) / (length(u_HemiLight.dir) * length(reflection));
    vec3 tempColor = u_HemiLight.color *  max(cosAngle, 0.);
    vec3 specularlight =  tempColor * hemiIntegral(0.5 * M_PI);
    vec3 diffuselight =  tempColor * hemiIntegral(0.5 * M_PI * pbrInputs.perceptualRoughness) * cosAngle;

    vec3 diffuse = diffuselight * pbrInputs.diffuseColor;
    vec3 specular = specularlight * (pbrInputs.specularColor * brdf.x + brdf.y);

    return diffuse + specular;
}

vec3 diffuse(PBRInfo pbrInputs) {
    return pbrInputs.diffuseColor / M_PI;
}

vec3 specularReflection(PBRInfo pbrInputs) {
    return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0);
}

float geometricOcclusion(PBRInfo pbrInputs) {
    float NdotL = pbrInputs.NdotL;
    float NdotV = pbrInputs.NdotV;
    float r = pbrInputs.alphaRoughness;

    float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL)));
    float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV)));
    return attenuationL * attenuationV;
}

float microfacetDistribution(PBRInfo pbrInputs) {
    float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness;
    float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0;
    return roughnessSq / (M_PI * f * f);
}

void main() {
    float metallic = u_MetallicRoughnessValues.x;
    float perceptualRoughness = u_MetallicRoughnessValues.y;

    #ifdef HAS_METALROUGHNESSMAP
        vec4 mrSample = texture2D(u_MetallicRoughnessSampler, v_UV);
        perceptualRoughness = mrSample.g * perceptualRoughness;
        metallic = mrSample.b * metallic;
    #endif

    perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0);
    metallic = clamp(metallic, 0.0, 1.0);

    float alphaRoughness = perceptualRoughness * perceptualRoughness;

    vec3 f0 = vec3(c_MinRoughness);

    vec3 baseColor0 = vec3(0);
    vec3 baseColor1 = vec3(0);
    vec3 baseColor2 = vec3(0);

    if(u_Type == 0) {
        baseColor0 = u_FaceColor;
    }
    if(u_Type == 1) {
        vec3 uv = u_TexMat * vec3(v_UV,1);
        baseColor1 = vec3(texture2D(u_BaseColorSampler, uv.xy/uv.z));
    }
    if(u_Type == 2) {
        float u_GradientVecLegth = length(u_GradientVec);
        vec3 tempVec1 = vec3(u_BoundingBox[0], u_BoundingBox[1], -u_BoundingBox[2]);
        vec3 tempVec2 = vec3(u_BoundingBox[0], -u_BoundingBox[1], u_BoundingBox[2]);
        vec3 tempVec3 = vec3(u_BoundingBox[0], -u_BoundingBox[1], -u_BoundingBox[2]);
        float radius1 = abs(dot(u_BoundingBox,u_GradientVec)/u_GradientVecLegth);
        float radius2 = abs(dot(tempVec1,u_GradientVec)/u_GradientVecLegth);
        float radius3 = abs(dot(tempVec2,u_GradientVec)/u_GradientVecLegth);
        float radius4 = abs(dot(tempVec3,u_GradientVec)/u_GradientVecLegth);
        radius1 = max(radius1,radius2);
        radius2 = max(radius3,radius4);
        float radius = max(radius1,radius2)*1.0001;

        vec3 startPoint = -radius * normalize(u_GradientVec);
        float distance = dot((v_Position.xyz - startPoint),u_GradientVec)/u_GradientVecLegth;
        float projctionLength = clamp(distance/(2.*radius),u_GradientColor[0].offset,u_GradientColor[NR_GRADIENT_COLORS-1].offset);
        vec3 colorByPos = vec3(1.,0.,0.);

        for(int i = 1; i < NR_GRADIENT_COLORS; ++i) {
            if(projctionLength >= u_GradientColor[i-1].offset && projctionLength <= u_GradientColor[i].offset ){
                float gradientDegree = (projctionLength - u_GradientColor[i-1].offset)/(u_GradientColor[i].offset-u_GradientColor[i-1].offset);
                colorByPos = mix(u_GradientColor[i-1].color,u_GradientColor[i].color,gradientDegree);
                break;
            };
        };

        baseColor2 = colorByPos;
    }

    vec4 baseColor = vec4(baseColor0 + baseColor1 + baseColor2, 1.) * u_BaseColorFactor;

    vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - f0);
    diffuseColor *= 1.0 - metallic;
    vec3 specularColor = mix(f0, baseColor.rgb, metallic);

    float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);

    float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
    vec3 specularEnvironmentR0 = specularColor.rgb;
    vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;

    vec3 n = getNormal();
    vec3 v = normalize(u_Camera - v_Position);
    vec3 reflection = -normalize(reflect(v, n));

    vec3 color = vec3(0, 0, 0);
    float NdotL, NdotV, NdotH, LdotH, VdotH;
    NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
    PBRInfo pbrInputs;
    vec3 F;
    float G, D;
    vec3 diffuseContrib, specContrib;

    for(int i = 0; i < NR_POINT_LIGHTS; ++i) {
        vec3 l = normalize(u_Lights[i].pos - v_Position);
        vec3 h = normalize(l + v);

        NdotL = clamp(dot(n, l), 0.001, 1.0);
        NdotH = clamp(dot(n, h), 0.0, 1.0);
        LdotH = clamp(dot(l, h), 0.0, 1.0);
        VdotH = clamp(dot(v, h), 0.0, 1.0);

        pbrInputs = PBRInfo(
            NdotL,
            NdotV,
            NdotH,
            LdotH,
            VdotH,
            perceptualRoughness,
            metallic,
            specularEnvironmentR0,
            specularEnvironmentR90,
            alphaRoughness,
            diffuseColor,
            specularColor
        );

        F = specularReflection(pbrInputs);
        G = geometricOcclusion(pbrInputs);
        D = microfacetDistribution(pbrInputs);

        diffuseContrib = (1.0 - F) * diffuse(pbrInputs);
        specContrib = F * G * D / (4.0 * NdotL * NdotV);

        vec3 lightColor = NdotL * u_Lights[i].color * (diffuseContrib + specContrib);
        color += lightColor;
    }

    color += getHEMIContribution(pbrInputs, n, reflection);
    #ifdef USE_IBL
        color += length(u_EnvColor)>0. ? getColorEnvContribution(pbrInputs) : getIBLContribution(pbrInputs, n, reflection);;
    #endif

    #ifdef HAS_OCCLUSIONMAP
        float ao = texture2D(u_OcclusionSampler, v_UV).r;
        color = mix(color, color * ao, u_OcclusionStrength);
    #endif

    #ifdef HAS_EMISSIVEMAP
        vec3 emissive = SRGBtoLINEAR(texture2D(u_EmissiveSampler, v_UV)).rgb * u_EmissiveFactor;
        color += emissive;
    #endif

    color = mix(color, F, u_ScaleFGDSpec.x);
    color = mix(color, vec3(G), u_ScaleFGDSpec.y);
    color = mix(color, vec3(D), u_ScaleFGDSpec.z);
    color = mix(color, specContrib, u_ScaleFGDSpec.w);

    color = mix(color, diffuseContrib, u_ScaleDiffBaseMR.x);
    color = mix(color, baseColor.rgb, u_ScaleDiffBaseMR.y);
    color = mix(color, vec3(metallic), u_ScaleDiffBaseMR.z);
    color = mix(color, vec3(perceptualRoughness), u_ScaleDiffBaseMR.w);

    gl_FragColor = vec4(color, baseColor.a);
}
`;
const { int: int$1, float: float$1, vec2: vec2$1, vec3, vec4: vec4$2, mat3, mat4: mat4$2, tex2D: tex2D$1, texCube } = SchemaTypes;
const ThreeText = {
  vs: vertexShader,
  fs: fragmentShader,
  defines: {
    USE_IBL: 1,
    HAS_NORMALS: 1,
    HAS_UV: 1,
    HAS_BASECOLORMAP: 1,
    HAS_METALROUGHNESSMAP: 1,
    HAS_NORMALMAP: 1,
    NR_POINT_LIGHTS: config.pointLightsNum,
    USE_GRADIENT: 1,
    NR_GRADIENT_COLORS: config.gradientMaxNum
  },
  buffers: {
    position: { type: vec4$2, n: 3 },
    normal: { type: vec4$2, n: 3 },
    texCoord: { type: vec2$1, n: 2 }
  },
  uniforms: {
    u_MVPMatrix: { type: mat4$2 },
    u_ModelMatrix: { type: mat4$2 },
    u_NormalMatrix: { type: mat4$2 },
    "u_Lights[0].pos": { type: vec3, default: [1e3, 0, 0] },
    "u_Lights[0].color": { type: vec3, default: [0, 0, 0] },
    "u_Lights[1].pos": { type: vec3, default: [-1e3, 1e3, 1e3] },
    "u_Lights[1].color": { type: vec3, default: [0, 0, 0] },
    "u_Lights[2].pos": { type: vec3, default: [0, 1e3, 1e3] },
    "u_Lights[2].color": { type: vec3, default: [0, 0, 0] },
    "u_Lights[3].pos": { type: vec3, default: [0, -1e3, 1e3] },
    "u_Lights[3].color": { type: vec3, default: [0, 0, 0] },
    "u_Lights[4].pos": { type: vec3, default: [0, 0, 1e3] },
    "u_Lights[4].color": { type: vec3, default: [0, 0, 0] },
    u_Camera: { type: vec3, default: [0, 0, 700] },
    u_BaseColorFactor: { type: vec4$2, default: [1, 1, 1, 1] },
    u_BaseColorScale: { type: float$1, default: 1 },
    u_NormalScale: { type: float$1, default: 1 },
    u_NormalStrength: { type: float$1, default: 0 },
    u_EmissiveFactor: { type: vec3, default: [1, 1, 1] },
    u_OcclusionStrength: { type: float$1, default: 1 },
    u_MetallicRoughnessValues: { type: vec2$1, default: [1, 0] },
    u_ScaleDiffBaseMR: { type: vec4$2, default: [0, 0, 0, 0] },
    u_ScaleFGDSpec: { type: vec4$2, default: [0, 0, 0, 0] },
    u_ScaleIBLAmbient: { type: vec4$2, default: [1, 1, 1, 1] },
    u_BoundingBox: { type: vec3, default: [100, 100, 100] },
    u_GradientVec: { type: vec3, default: [1, 0, 0] },
    "u_GradientColor[0].color": { type: vec3, default: [1, 0, 0] },
    "u_GradientColor[0].offset": { type: float$1, default: 0 },
    "u_GradientColor[1].color": { type: vec3, default: [0, 0, 1] },
    "u_GradientColor[1].offset": { type: float$1, default: 1 },
    "u_GradientColor[2].color": { type: vec3, default: [1, 0, 0] },
    "u_GradientColor[2].offset": { type: float$1, default: 2 },
    "u_GradientColor[3].color": { type: vec3, default: [0, 0, 1] },
    "u_GradientColor[3].offset": { type: float$1, default: 3 },
    u_Type: { type: int$1, default: 0 },
    u_FaceColor: { type: vec3, default: [1, 1, 1] },
    u_TexMat: { type: mat3, default: [1, 0, 0, 0, 1, 0, 0, 0, 1] },
    "u_HemiLight.dir": { type: vec3, default: [0, 0, 1] },
    "u_HemiLight.color": { type: vec3, default: [1, 1, 1] },
    "u_EnvColor": { type: vec3, default: [0, 0, 0] }
  },
  textures: {
    u_DiffuseEnvSampler: { type: texCube },
    u_SpecularEnvSampler: { type: texCube },
    u_brdfLUT: { type: tex2D$1 },
    u_BaseColorSampler: { type: tex2D$1 },
    u_NormalSampler: { type: tex2D$1 },
    u_EmissiveSampler: { type: tex2D$1 },
    u_MetallicRoughnessSampler: { type: tex2D$1 },
    u_OcclusionSampler: { type: tex2D$1 }
  }
};
var EPSILON = 1e-6;
var ARRAY_TYPE = typeof Float32Array !== "undefined" ? Float32Array : Array;
var degree = Math.PI / 180;
function toRadian(a) {
  return a * degree;
}
if (!Math.hypot)
  Math.hypot = function() {
    var y = 0, i = arguments.length;
    while (i--) {
      y += arguments[i] * arguments[i];
    }
    return Math.sqrt(y);
  };
function create$4() {
  var out = new ARRAY_TYPE(9);
  if (ARRAY_TYPE != Float32Array) {
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
    out[5] = 0;
    out[6] = 0;
    out[7] = 0;
  }
  out[0] = 1;
  out[4] = 1;
  out[8] = 1;
  return out;
}
function translate(out, a, v) {
  var a00 = a[0], a01 = a[1], a02 = a[2], a10 = a[3], a11 = a[4], a12 = a[5], a20 = a[6], a21 = a[7], a22 = a[8], x = v[0], y = v[1];
  out[0] = a00;
  out[1] = a01;
  out[2] = a02;
  out[3] = a10;
  out[4] = a11;
  out[5] = a12;
  out[6] = x * a00 + y * a10 + a20;
  out[7] = x * a01 + y * a11 + a21;
  out[8] = x * a02 + y * a12 + a22;
  return out;
}
function rotate(out, a, rad) {
  var a00 = a[0], a01 = a[1], a02 = a[2], a10 = a[3], a11 = a[4], a12 = a[5], a20 = a[6], a21 = a[7], a22 = a[8], s = Math.sin(rad), c = Math.cos(rad);
  out[0] = c * a00 + s * a10;
  out[1] = c * a01 + s * a11;
  out[2] = c * a02 + s * a12;
  out[3] = c * a10 - s * a00;
  out[4] = c * a11 - s * a01;
  out[5] = c * a12 - s * a02;
  out[6] = a20;
  out[7] = a21;
  out[8] = a22;
  return out;
}
function scale(out, a, v) {
  var x = v[0], y = v[1];
  out[0] = x * a[0];
  out[1] = x * a[1];
  out[2] = x * a[2];
  out[3] = y * a[3];
  out[4] = y * a[4];
  out[5] = y * a[5];
  out[6] = a[6];
  out[7] = a[7];
  out[8] = a[8];
  return out;
}
function create$3() {
  var out = new ARRAY_TYPE(16);
  if (ARRAY_TYPE != Float32Array) {
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
    out[4] = 0;
    out[6] = 0;
    out[7] = 0;
    out[8] = 0;
    out[9] = 0;
    out[11] = 0;
    out[12] = 0;
    out[13] = 0;
    out[14] = 0;
  }
  out[0] = 1;
  out[5] = 1;
  out[10] = 1;
  out[15] = 1;
  return out;
}
function identity(out) {
  out[0] = 1;
  out[1] = 0;
  out[2] = 0;
  out[3] = 0;
  out[4] = 0;
  out[5] = 1;
  out[6] = 0;
  out[7] = 0;
  out[8] = 0;
  out[9] = 0;
  out[10] = 1;
  out[11] = 0;
  out[12] = 0;
  out[13] = 0;
  out[14] = 0;
  out[15] = 1;
  return out;
}
function multiply(out, a, b) {
  var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
  var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
  var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
  var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
  var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
  out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
  out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
  out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
  out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
  b0 = b[4];
  b1 = b[5];
  b2 = b[6];
  b3 = b[7];
  out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
  out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
  out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
  out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
  b0 = b[8];
  b1 = b[9];
  b2 = b[10];
  b3 = b[11];
  out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
  out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
  out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
  out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
  b0 = b[12];
  b1 = b[13];
  b2 = b[14];
  b3 = b[15];
  out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
  out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
  out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
  out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
  return out;
}
function rotateX(out, a, rad) {
  var s = Math.sin(rad);
  var c = Math.cos(rad);
  var a10 = a[4];
  var a11 = a[5];
  var a12 = a[6];
  var a13 = a[7];
  var a20 = a[8];
  var a21 = a[9];
  var a22 = a[10];
  var a23 = a[11];
  if (a !== out) {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    out[12] = a[12];
    out[13] = a[13];
    out[14] = a[14];
    out[15] = a[15];
  }
  out[4] = a10 * c + a20 * s;
  out[5] = a11 * c + a21 * s;
  out[6] = a12 * c + a22 * s;
  out[7] = a13 * c + a23 * s;
  out[8] = a20 * c - a10 * s;
  out[9] = a21 * c - a11 * s;
  out[10] = a22 * c - a12 * s;
  out[11] = a23 * c - a13 * s;
  return out;
}
function rotateY(out, a, rad) {
  var s = Math.sin(rad);
  var c = Math.cos(rad);
  var a00 = a[0];
  var a01 = a[1];
  var a02 = a[2];
  var a03 = a[3];
  var a20 = a[8];
  var a21 = a[9];
  var a22 = a[10];
  var a23 = a[11];
  if (a !== out) {
    out[4] = a[4];
    out[5] = a[5];
    out[6] = a[6];
    out[7] = a[7];
    out[12] = a[12];
    out[13] = a[13];
    out[14] = a[14];
    out[15] = a[15];
  }
  out[0] = a00 * c - a20 * s;
  out[1] = a01 * c - a21 * s;
  out[2] = a02 * c - a22 * s;
  out[3] = a03 * c - a23 * s;
  out[8] = a00 * s + a20 * c;
  out[9] = a01 * s + a21 * c;
  out[10] = a02 * s + a22 * c;
  out[11] = a03 * s + a23 * c;
  return out;
}
function fromTranslation(out, v) {
  out[0] = 1;
  out[1] = 0;
  out[2] = 0;
  out[3] = 0;
  out[4] = 0;
  out[5] = 1;
  out[6] = 0;
  out[7] = 0;
  out[8] = 0;
  out[9] = 0;
  out[10] = 1;
  out[11] = 0;
  out[12] = v[0];
  out[13] = v[1];
  out[14] = v[2];
  out[15] = 1;
  return out;
}
function fromScaling(out, v) {
  out[0] = v[0];
  out[1] = 0;
  out[2] = 0;
  out[3] = 0;
  out[4] = 0;
  out[5] = v[1];
  out[6] = 0;
  out[7] = 0;
  out[8] = 0;
  out[9] = 0;
  out[10] = v[2];
  out[11] = 0;
  out[12] = 0;
  out[13] = 0;
  out[14] = 0;
  out[15] = 1;
  return out;
}
function fromYRotation(out, rad) {
  var s = Math.sin(rad);
  var c = Math.cos(rad);
  out[0] = c;
  out[1] = 0;
  out[2] = -s;
  out[3] = 0;
  out[4] = 0;
  out[5] = 1;
  out[6] = 0;
  out[7] = 0;
  out[8] = s;
  out[9] = 0;
  out[10] = c;
  out[11] = 0;
  out[12] = 0;
  out[13] = 0;
  out[14] = 0;
  out[15] = 1;
  return out;
}
function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
  var x = q[0], y = q[1], z = q[2], w = q[3];
  var x2 = x + x;
  var y2 = y + y;
  var z2 = z + z;
  var xx = x * x2;
  var xy = x * y2;
  var xz = x * z2;
  var yy = y * y2;
  var yz = y * z2;
  var zz = z * z2;
  var wx = w * x2;
  var wy = w * y2;
  var wz = w * z2;
  var sx = s[0];
  var sy = s[1];
  var sz = s[2];
  var ox = o[0];
  var oy = o[1];
  var oz = o[2];
  var out0 = (1 - (yy + zz)) * sx;
  var out1 = (xy + wz) * sx;
  var out2 = (xz - wy) * sx;
  var out4 = (xy - wz) * sy;
  var out5 = (1 - (xx + zz)) * sy;
  var out6 = (yz + wx) * sy;
  var out8 = (xz + wy) * sz;
  var out9 = (yz - wx) * sz;
  var out10 = (1 - (xx + yy)) * sz;
  out[0] = out0;
  out[1] = out1;
  out[2] = out2;
  out[3] = 0;
  out[4] = out4;
  out[5] = out5;
  out[6] = out6;
  out[7] = 0;
  out[8] = out8;
  out[9] = out9;
  out[10] = out10;
  out[11] = 0;
  out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
  out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
  out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
  out[15] = 1;
  return out;
}
function perspectiveNO(out, fovy, aspect, near, far) {
  var f = 1 / Math.tan(fovy / 2), nf;
  out[0] = f / aspect;
  out[1] = 0;
  out[2] = 0;
  out[3] = 0;
  out[4] = 0;
  out[5] = f;
  out[6] = 0;
  out[7] = 0;
  out[8] = 0;
  out[9] = 0;
  out[11] = -1;
  out[12] = 0;
  out[13] = 0;
  out[15] = 0;
  if (far != null && far !== Infinity) {
    nf = 1 / (near - far);
    out[10] = (far + near) * nf;
    out[14] = 2 * far * near * nf;
  } else {
    out[10] = -1;
    out[14] = -2 * near;
  }
  return out;
}
var perspective = perspectiveNO;
function orthoNO(out, left, right, bottom, top, near, far) {
  var lr = 1 / (left - right);
  var bt = 1 / (bottom - top);
  var nf = 1 / (near - far);
  out[0] = -2 * lr;
  out[1] = 0;
  out[2] = 0;
  out[3] = 0;
  out[4] = 0;
  out[5] = -2 * bt;
  out[6] = 0;
  out[7] = 0;
  out[8] = 0;
  out[9] = 0;
  out[10] = 2 * nf;
  out[11] = 0;
  out[12] = (left + right) * lr;
  out[13] = (top + bottom) * bt;
  out[14] = (far + near) * nf;
  out[15] = 1;
  return out;
}
var ortho = orthoNO;
function lookAt(out, eye, center, up) {
  var x0, x1, x2, y0, y1, y2, z0, z1, z2, len2;
  var eyex = eye[0];
  var eyey = eye[1];
  var eyez = eye[2];
  var upx = up[0];
  var upy = up[1];
  var upz = up[2];
  var centerx = center[0];
  var centery = center[1];
  var centerz = center[2];
  if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
    return identity(out);
  }
  z0 = eyex - centerx;
  z1 = eyey - centery;
  z2 = eyez - centerz;
  len2 = 1 / Math.hypot(z0, z1, z2);
  z0 *= len2;
  z1 *= len2;
  z2 *= len2;
  x0 = upy * z2 - upz * z1;
  x1 = upz * z0 - upx * z2;
  x2 = upx * z1 - upy * z0;
  len2 = Math.hypot(x0, x1, x2);
  if (!len2) {
    x0 = 0;
    x1 = 0;
    x2 = 0;
  } else {
    len2 = 1 / len2;
    x0 *= len2;
    x1 *= len2;
    x2 *= len2;
  }
  y0 = z1 * x2 - z2 * x1;
  y1 = z2 * x0 - z0 * x2;
  y2 = z0 * x1 - z1 * x0;
  len2 = Math.hypot(y0, y1, y2);
  if (!len2) {
    y0 = 0;
    y1 = 0;
    y2 = 0;
  } else {
    len2 = 1 / len2;
    y0 *= len2;
    y1 *= len2;
    y2 *= len2;
  }
  out[0] = x0;
  out[1] = y0;
  out[2] = z0;
  out[3] = 0;
  out[4] = x1;
  out[5] = y1;
  out[6] = z1;
  out[7] = 0;
  out[8] = x2;
  out[9] = y2;
  out[10] = z2;
  out[11] = 0;
  out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
  out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
  out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
  out[15] = 1;
  return out;
}
function create$2() {
  var out = new ARRAY_TYPE(3);
  if (ARRAY_TYPE != Float32Array) {
    out[0] = 0;
    out[1] = 0;
    out[2] = 0;
  }
  return out;
}
function length(a) {
  var x = a[0];
  var y = a[1];
  var z = a[2];
  return Math.hypot(x, y, z);
}
function fromValues(x, y, z) {
  var out = new ARRAY_TYPE(3);
  out[0] = x;
  out[1] = y;
  out[2] = z;
  return out;
}
function normalize$2(out, a) {
  var x = a[0];
  var y = a[1];
  var z = a[2];
  var len2 = x * x + y * y + z * z;
  if (len2 > 0) {
    len2 = 1 / Math.sqrt(len2);
  }
  out[0] = a[0] * len2;
  out[1] = a[1] * len2;
  out[2] = a[2] * len2;
  return out;
}
function dot(a, b) {
  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
function cross(out, a, b) {
  var ax = a[0], ay = a[1], az = a[2];
  var bx = b[0], by = b[1], bz = b[2];
  out[0] = ay * bz - az * by;
  out[1] = az * bx - ax * bz;
  out[2] = ax * by - ay * bx;
  return out;
}
function transformMat4(out, a, m) {
  var x = a[0], y = a[1], z = a[2];
  var w = m[3] * x + m[7] * y + m[11] * z + m[15];
  w = w || 1;
  out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
  out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
  out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
  return out;
}
var len = length;
(function() {
  var vec = create$2();
  return function(a, stride, offset, count, fn, arg) {
    var i, l;
    if (!stride) {
      stride = 3;
    }
    if (!offset) {
      offset = 0;
    }
    if (count) {
      l = Math.min(count * stride + offset, a.length);
    } else {
      l = a.length;
    }
    for (i = offset; i < l; i += stride) {
      vec[0] = a[i];
      vec[1] = a[i + 1];
      vec[2] = a[i + 2];
      fn(vec, vec, arg);
      a[i] = vec[0];
      a[i + 1] = vec[1];
      a[i + 2] = vec[2];
    }
    return a;
  };
})();
function create$1() {
  var out = new ARRAY_TYPE(4);
  if (ARRAY_TYPE != Float32Array) {
    out[0] = 0;
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
  }
  return out;
}
function normalize$1(out, a) {
  var x = a[0];
  var y = a[1];
  var z = a[2];
  var w = a[3];
  var len2 = x * x + y * y + z * z + w * w;
  if (len2 > 0) {
    len2 = 1 / Math.sqrt(len2);
  }
  out[0] = x * len2;
  out[1] = y * len2;
  out[2] = z * len2;
  out[3] = w * len2;
  return out;
}
(function() {
  var vec = create$1();
  return function(a, stride, offset, count, fn, arg) {
    var i, l;
    if (!stride) {
      stride = 4;
    }
    if (!offset) {
      offset = 0;
    }
    if (count) {
      l = Math.min(count * stride + offset, a.length);
    } else {
      l = a.length;
    }
    for (i = offset; i < l; i += stride) {
      vec[0] = a[i];
      vec[1] = a[i + 1];
      vec[2] = a[i + 2];
      vec[3] = a[i + 3];
      fn(vec, vec, arg);
      a[i] = vec[0];
      a[i + 1] = vec[1];
      a[i + 2] = vec[2];
      a[i + 3] = vec[3];
    }
    return a;
  };
})();
function create() {
  var out = new ARRAY_TYPE(4);
  if (ARRAY_TYPE != Float32Array) {
    out[0] = 0;
    out[1] = 0;
    out[2] = 0;
  }
  out[3] = 1;
  return out;
}
function setAxisAngle(out, axis, rad) {
  rad = rad * 0.5;
  var s = Math.sin(rad);
  out[0] = s * axis[0];
  out[1] = s * axis[1];
  out[2] = s * axis[2];
  out[3] = Math.cos(rad);
  return out;
}
function slerp(out, a, b, t) {
  var ax = a[0], ay = a[1], az = a[2], aw = a[3];
  var bx = b[0], by = b[1], bz = b[2], bw = b[3];
  var omega, cosom, sinom, scale0, scale1;
  cosom = ax * bx + ay * by + az * bz + aw * bw;
  if (cosom < 0) {
    cosom = -cosom;
    bx = -bx;
    by = -by;
    bz = -bz;
    bw = -bw;
  }
  if (1 - cosom > EPSILON) {
    omega = Math.acos(cosom);
    sinom = Math.sin(omega);
    scale0 = Math.sin((1 - t) * omega) / sinom;
    scale1 = Math.sin(t * omega) / sinom;
  } else {
    scale0 = 1 - t;
    scale1 = t;
  }
  out[0] = scale0 * ax + scale1 * bx;
  out[1] = scale0 * ay + scale1 * by;
  out[2] = scale0 * az + scale1 * bz;
  out[3] = scale0 * aw + scale1 * bw;
  return out;
}
function fromMat3(out, m) {
  var fTrace = m[0] + m[4] + m[8];
  var fRoot;
  if (fTrace > 0) {
    fRoot = Math.sqrt(fTrace + 1);
    out[3] = 0.5 * fRoot;
    fRoot = 0.5 / fRoot;
    out[0] = (m[5] - m[7]) * fRoot;
    out[1] = (m[6] - m[2]) * fRoot;
    out[2] = (m[1] - m[3]) * fRoot;
  } else {
    var i = 0;
    if (m[4] > m[0])
      i = 1;
    if (m[8] > m[i * 3 + i])
      i = 2;
    var j = (i + 1) % 3;
    var k = (i + 2) % 3;
    fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1);
    out[i] = 0.5 * fRoot;
    fRoot = 0.5 / fRoot;
    out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
    out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
    out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
  }
  return out;
}
function fromEuler(out, x, y, z) {
  var halfToRad = 0.5 * Math.PI / 180;
  x *= halfToRad;
  y *= halfToRad;
  z *= halfToRad;
  var sx = Math.sin(x);
  var cx = Math.cos(x);
  var sy = Math.sin(y);
  var cy = Math.cos(y);
  var sz = Math.sin(z);
  var cz = Math.cos(z);
  out[0] = sx * cy * cz - cx * sy * sz;
  out[1] = cx * sy * cz + sx * cy * sz;
  out[2] = cx * cy * sz - sx * sy * cz;
  out[3] = cx * cy * cz + sx * sy * sz;
  return out;
}
var normalize = normalize$1;
(function() {
  var tmpvec3 = create$2();
  var xUnitVec3 = fromValues(1, 0, 0);
  var yUnitVec3 = fromValues(0, 1, 0);
  return function(out, a, b) {
    var dot$1 = dot(a, b);
    if (dot$1 < -0.999999) {
      cross(tmpvec3, xUnitVec3, a);
      if (len(tmpvec3) < 1e-6)
        cross(tmpvec3, yUnitVec3, a);
      normalize$2(tmpvec3, tmpvec3);
      setAxisAngle(out, tmpvec3, Math.PI);
      return out;
    } else if (dot$1 > 0.999999) {
      out[0] = 0;
      out[1] = 0;
      out[2] = 0;
      out[3] = 1;
      return out;
    } else {
      cross(tmpvec3, a, b);
      out[0] = tmpvec3[0];
      out[1] = tmpvec3[1];
      out[2] = tmpvec3[2];
      out[3] = 1 + dot$1;
      return normalize(out, out);
    }
  };
})();
(function() {
  var temp1 = create();
  var temp2 = create();
  return function(out, a, b, c, d, t) {
    slerp(temp1, a, d, t);
    slerp(temp2, b, c, t);
    slerp(out, temp1, temp2, 2 * t * (1 - t));
    return out;
  };
})();
(function() {
  var matr = create$4();
  return function(out, view, right, up) {
    matr[0] = right[0];
    matr[3] = right[1];
    matr[6] = right[2];
    matr[1] = up[0];
    matr[4] = up[1];
    matr[7] = up[2];
    matr[2] = -view[0];
    matr[5] = -view[1];
    matr[8] = -view[2];
    return normalize(out, fromMat3(out, matr));
  };
})();
const { vec4: vec4$1, mat4: mat4$1 } = SchemaTypes;
const vs = `
attribute vec4 position;
uniform mat4 u_TranslateMat;
uniform mat4 u_ScaleMat;
uniform mat4 u_RotateMat;
uniform mat4 u_MVPMatrix;

void main() {
  gl_Position = u_MVPMatrix * u_RotateMat * u_ScaleMat * u_TranslateMat * position;
}
`;
const fs = `
precision highp float;
uniform vec4 u_Color;

void main() {
  gl_FragColor = u_Color;
}
`;
const uitMatrix = create$3();
const Simple = {
  vs,
  fs,
  buffers: {
    position: { type: vec4$1, n: 3 }
  },
  uniforms: {
    u_TranslateMat: { type: mat4$1, default: uitMatrix },
    u_RotateMat: { type: mat4$1, default: uitMatrix },
    u_ScaleMat: { type: mat4$1, default: uitMatrix },
    u_MVPMatrix: { type: mat4$1 },
    u_Color: { type: vec4$1, default: [0.96, 0.6, 0, 0.15] }
  }
};
function homoConvertToRect(vec42) {
  const out = [];
  out[0] = vec42[0] / vec42[3];
  out[1] = vec42[1] / vec42[3];
  out[2] = vec42[2] / vec42[3];
  return out;
}
function multiplyVec3(matrix, vec32) {
  const out = [];
  out[0] = matrix[0] * vec32[0] + matrix[4] * vec32[1] + matrix[8] * vec32[2] + matrix[12];
  out[1] = matrix[1] * vec32[0] + matrix[5] * vec32[1] + matrix[9] * vec32[2] + matrix[13];
  out[2] = matrix[2] * vec32[0] + matrix[6] * vec32[1] + matrix[10] * vec32[2] + matrix[14];
  out[3] = matrix[3] * vec32[0] + matrix[7] * vec32[1] + matrix[11] * vec32[2] + matrix[15];
  return homoConvertToRect(out);
}
function isPowerOf2(num) {
  return (num & num - 1) === 0;
}
const getTexture = (src) => new Promise((resolve) => {
  if (tinycolor(src).isValid()) {
    src = getCanvas(src);
  }
  if (src instanceof HTMLCanvasElement) {
    return resolve(src);
  }
  if (/^http/.test(src)) {
    loadImage(src).then((image) => {
      resolve(image);
    });
  } else {
    resolve(null);
  }
});
const loadImage = (src) => new Promise((resolve) => {
  if (tinycolor(src).isValid()) {
    src = getCanvas(src);
  }
  if (src instanceof HTMLCanvasElement) {
    return resolve(src);
  }
  const image = new Image();
  image.crossOrigin = "";
  image.onload = () => resolve(image);
  image.src = src;
});
const loadCubeMaps = (url) => new Promise((resolve) => {
  extractCubeMapsFromImage(url, 9).then(resolve);
});
const getOffset = (n, maxLevel) => {
  if (n === 0)
    return 0;
  return Math.pow(2, maxLevel - n + 1) + getOffset(n - 1, maxLevel);
};
const getSpecularXY = (dirIndex, baseOffset, size) => {
  if (dirIndex >= 4) {
    return [baseOffset * 2 + size * (dirIndex - 4), baseOffset + size];
  }
  return [baseOffset * 2 + size * dirIndex, baseOffset];
};
const extractToCanvas = (spriteCanvas, x, y, size) => {
  const spriteCtx = spriteCanvas.getContext("2d");
  const imageData = spriteCtx.getImageData(x, y, size, size);
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");
  canvas.width = size;
  canvas.height = size;
  ctx.putImageData(imageData, 0, 0);
  return canvas;
};
const extractCubeMaps = (canvas, level) => {
  const maxSpecularSize = Math.pow(2, level);
  const diffuseSize = canvas.width - maxSpecularSize * 4;
  const dirCount = 6;
  const cubeMaps = [{ level: 0, images: [] }, { level, images: [] }];
  for (let i = 0; i <= level; i++) {
    const baseOffset = getOffset(i, level);
    const size = Math.pow(2, level - i);
    for (let j = 0; j < dirCount; j++) {
      const index = j * (level + 1) + i;
      const [x, y] = getSpecularXY(j, baseOffset, size);
      cubeMaps[1].images[index] = extractToCanvas(canvas, x, y, size);
    }
  }
  const diffuseOffset = maxSpecularSize * 4;
  for (let i = 0; i < dirCount; i++) {
    const [x, y] = [diffuseOffset, i * diffuseSize];
    cubeMaps[0].images[i] = extractToCanvas(canvas, x, y, diffuseSize);
  }
  return cubeMaps;
};
const extractCubeMapsFromImage = (url, level) => {
  return loadImage(url).then((image) => {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    canvas.width = image.width;
    canvas.height = image.height;
    ctx.drawImage(image, 0, 0);
    return canvas;
  }).then((canvas) => {
    return extractCubeMaps(canvas, level);
  });
};
const getCanvas = (color, width = 2, height = 2) => {
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");
  canvas.width = width;
  canvas.height = height;
  ctx.fillStyle = color;
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  return canvas;
};
const rotateCamera = (rotate3d = [0, 0, 0], cameraDistance = 700) => {
  const maxAngle = Math.PI * 0.4;
  rotate3d[0] = Math.sign(rotate3d[0]) * Math.min(Math.abs(rotate3d[0]), maxAngle);
  const eye = fromValues(0, 0, cameraDistance);
  const rotateMat = create$3();
  rotateX(rotateMat, rotateMat, -rotate3d[0]);
  rotateY(rotateMat, rotateMat, -rotate3d[1]);
  transformMat4(eye, eye, rotateMat);
  return eye;
};
const getTexMat = (translateVec = [0, 0], angle = 0, scale$1 = [1, 1]) => {
  const texMat = create$4();
  rotate(texMat, texMat, angle);
  translate(texMat, texMat, translateVec);
  scale(texMat, texMat, scale$1);
  return texMat;
};
const getModelSize = (boundingBox, mvpMat, shadowMatrix, shadow = {
  enable: false,
  blur: 10,
  offset: 0,
  opacity: 1,
  angle: 0
}) => {
  const borderPoints = [
    boundingBox.min,
    [boundingBox.min[0], boundingBox.min[1], boundingBox.max[2]],
    [boundingBox.min[0], boundingBox.max[1], boundingBox.min[2]],
    [boundingBox.min[0], boundingBox.max[1], boundingBox.max[2]],
    [boundingBox.max[0], boundingBox.min[1], boundingBox.min[2]],
    [boundingBox.max[0], boundingBox.min[1], boundingBox.max[2]],
    [boundingBox.max[0], boundingBox.max[1], boundingBox.min[2]],
    boundingBox.max
  ];
  for (let i = 0; i < 8; i++) {
    borderPoints[i] = multiplyVec3(mvpMat, borderPoints[i]);
  }
  const initBox = [borderPoints[0][0], borderPoints[0][0], borderPoints[0][1], borderPoints[0][1]];
  for (let i = 1; i < 8; i++) {
    initBox[0] = Math.min(initBox[0], borderPoints[i][0]);
    initBox[1] = Math.max(initBox[1], borderPoints[i][0]);
    initBox[2] = Math.min(initBox[2], borderPoints[i][1]);
    initBox[3] = Math.max(initBox[3], borderPoints[i][1]);
  }
  if (shadow.enable && shadowMatrix) {
    const radiusTmp = Math.ceil(shadow.blur * 6 + 1);
    const blur = Math.log(radiusTmp / config.offscreenSize + 1);
    const shadowPoints = [
      [initBox[0], initBox[3], 0],
      [initBox[1], initBox[2], 0]
    ];
    const shadowBox = shadowPoints.map((element) => multiplyVec3(shadowMatrix, element));
    const shadowBoxAfterBlur = [
      shadowBox[0][0] - blur,
      shadowBox[1][0] + blur,
      shadowBox[1][1] - blur,
      shadowBox[0][1] + blur
    ];
    initBox[0] = Math.min(shadowBoxAfterBlur[0], initBox[0]);
    initBox[1] = Math.max(shadowBoxAfterBlur[1], initBox[1]);
    initBox[2] = Math.min(shadowBoxAfterBlur[2], initBox[2]);
    initBox[3] = Math.max(shadowBoxAfterBlur[3], initBox[3]);
  }
  return initBox;
};
const createSolidCanvas = (color, width = 2, height = 2) => {
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");
  canvas.width = width;
  canvas.height = height;
  ctx.fillStyle = color;
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  return canvas;
};
const getMapUrls = (materials) => [
  materials.albedo.type === 1 ? materials.albedo.image : materials.albedo.color || "#ffffff",
  materials.normal,
  materials.metalRoughness
];
const getColorVec = (color) => {
  const tinyColor = tinycolor(color);
  const tempColor = tinyColor.toRgb();
  return [tempColor.r / 255, tempColor.g / 255, tempColor.b / 255, tinyColor.getAlpha()];
};
const getColorVec3 = (color, strength = 1, enable = true) => {
  const tempColor = tinycolor(color).toRgb();
  const k = enable ? strength / 255 : 0;
  return [tempColor.r * k, tempColor.g * k, tempColor.b * k];
};
const getFontParserParameter = (font, model) => {
  const layer = model.layers[0];
  const { deformation, warpByWord } = model;
  const fontParserPara = {
    font,
    fontSize: config.initFontSize,
    fontWeight: model.fontWeight,
    extrudeDepth: layer.extrudeDepth,
    curveSegments: layer.curveSegments,
    bevelEnabled: Boolean(layer.bevelSize),
    bevelThickness: layer.bevelThickness,
    bevelSize: layer.bevelSize,
    bevelSegments: 4,
    scale: layer.expand,
    extrudeOffsetX: layer.extrudeOffsetX,
    extrudeOffsetY: layer.extrudeOffsetY,
    lineHeight: model.lineHeight,
    letterSpacing: model.letterSpacing,
    horizon: model.writingMode !== "vertical-rl",
    textAlign: model.textAlign,
    deformation,
    warpByWord
  };
  return fontParserPara;
};
function createPlaneModel([lx = 1, ly = 1], { division = 1, isSimple = false, direc = "z" }) {
  const position = [];
  const normal = [];
  const index = [];
  const texCoord = [];
  let i, j, k, x, y;
  for (i = 0; i <= division; i++) {
    for (j = 0; j <= division; j++) {
      x = -lx + i / division * 2 * lx;
      y = -ly + j / division * 2 * ly;
      switch (direc) {
        case "x":
          position.push(0, x, y);
          normal.push(1, 0, 0);
          break;
        case "y":
          position.push(x, 0, y);
          normal.push(0, 1, 0);
          break;
        default:
          position.push(x, y, 0);
      }
      if (!isSimple) {
        texCoord.push(i / division, j / division);
      }
    }
  }
  for (i = 0; i < division; i++) {
    for (j = 0; j < division; j++) {
      k = (division + 1) * i + j;
      index.push(k, k + 1, k + division + 1, k + 1, k + division + 2, k + division + 1);
    }
  }
  if (isSimple) {
    return {
      data: { position },
      index: { array: index }
    };
  } else {
    return {
      data: { position, normal, texCoord },
      index: { array: index }
    };
  }
}
function createCylinderModel({ radius = 1, div = 10, length: length2 = 10 }) {
  const position = [];
  const indexs = [];
  let angle, y, z;
  for (let i = 0; i < div; i++) {
    angle = 2 * i * Math.PI / div;
    y = Math.sin(angle);
    z = Math.cos(angle);
    position.push(-length2, radius * y, radius * z, length2, radius * y, radius * z);
  }
  position.push(-length2, 0, 0, length2, 0, 0);
  for (let i = 0; i < div - 1; i++) {
    indexs.push(2 * i, 2 * i + 2, 2 * i + 1, 2 * i + 1, 2 * i + 2, 2 * i + 3, 2 * i, 2 * i + 2, 2 * div, 2 * i + 1, 2 * div + 1, 2 * i + 3);
  }
  indexs.push(2 * div - 2, 0, 2 * div - 1, 2 * div - 1, 0, 1, 2 * div - 2, 0, 2 * div, 2 * div - 1, 2 * div + 1, 1);
  return {
    data: { position },
    index: { array: indexs }
  };
}
const { DataBuffers: DataBuffers$1, IndexBuffer: IndexBuffer$1, Uniforms: Uniforms$1, Textures: Textures$1 } = ResourceTypes;
class BasicRenderer {
  constructor(canvas) {
    this.canvas = canvas;
    this.beam = new Beam(canvas);
    this.modelMat = create$3();
    this.viewMat = create$3();
    this.projMat = create$3();
    this.mvpMat = create$3();
    this.commonTextures = this.beam.resource(Textures$1, {});
    this.commonUniforms = this.beam.resource(Uniforms$1, {});
  }
  init(plugin) {
    this.plugin = plugin;
  }
  initCylinder() {
    const { beam } = this;
    const cylinder = createCylinderModel({ radius: 1, div: 10, length: 1 });
    this.cylinderData = beam.resource(DataBuffers$1, cylinder.data);
    this.cylinderIndex = beam.resource(IndexBuffer$1, cylinder.index);
    this.simplePlugin = beam.plugin(Simple);
  }
  setModel(model) {
    this.DataBuffers = this.beam.resource(DataBuffers$1, model.data);
    this.IndexBuffer = this.beam.resource(IndexBuffer$1, model.index);
  }
  setEnvTextures(textures) {
    this.commonTextures = this.beam.resource(Textures$1, textures);
  }
  setOrtho(left = -2, right = 2, bottom = -2, top = 2, near = 0.1, far = 100) {
    ortho(this.projMat, left, right, bottom, top, near, far);
  }
  setPerspective(viewAngle = Math.PI / 6, aspect = 1, zNear = 0.1, zFar = 5e3) {
    perspective(this.projMat, viewAngle, aspect, zNear, zFar);
  }
  updatePointLights(model) {
    const { pointLights, lightsNum } = model;
    const max = lightsNum || config.pointLightsNum;
    for (let i = 0; i < max; i++) {
      if (i < pointLights.length) {
        const { position, color, strength, enable } = pointLights[i];
        this.commonUniforms.set(`u_Lights[${i}].pos`, position).set(`u_Lights[${i}].color`, getColorVec3(color, strength, enable));
      } else {
        this.commonUniforms.set(`u_Lights[${i}].color`, [0, 0, 0]);
      }
    }
  }
  setModelMat(rotate3d = [0, 0, 0], translateVec = [0, 0, 0], scaleVec = [1, 1, 1]) {
    const q = fromEuler(...rotate3d);
    fromRotationTranslationScaleOrigin(this.modelMat, q, translateVec, scaleVec, [0, 0, 0]);
    return this.modelMat;
  }
  getMvpMat(modelMat, viewMat, projMat) {
    modelMat = modelMat || this.modelMat;
    viewMat = viewMat || this.viewMat;
    projMat = projMat || this.projMat;
    multiply(this.tempMat, viewMat, modelMat);
    multiply(this.mvpMat, projMat, this.tempMat);
    return this.mvpMat;
  }
  getMeshLinesIndex() {
    const lineIndexArray = [];
    for (let i = 0; i < this.IndexBuffer.length; i++) {
      const { array } = this.IndexBuffer[i].state;
      for (let j = 0, l = array.length; j < l; j += 3) {
        const [n1, n2, n3] = [array[j], array[j + 1], array[j + 2]];
        lineIndexArray.push(n1, n2, n2, n3, n3, n1);
      }
    }
    this.lineIndexBuffer = this.beam.resource(IndexBuffer$1, { array: lineIndexArray });
  }
  getTexPara(image) {
    if (image && this.isStandTex(image)) {
      return {
        minFilter: GLTypes.LinearMipmapLinear,
        wrapT: GLTypes.Repeat,
        wrapS: GLTypes.Repeat
      };
    } else {
      return {
        minFilter: GLTypes.Linear,
        wrapT: GLTypes.ClampToEdge,
        wrapS: GLTypes.ClampToEdge
      };
    }
  }
  drawGrid() {
    if (!this.lineIndexBuffer) {
      this.getMeshLinesIndex();
      this.linePlugin = this.beam.plugin(Line);
    }
    const resources = [
      this.DataBuffers,
      this.lineIndexBuffer,
      this.commonUniforms
    ];
    this.beam.draw(this.linePlugin, ...resources);
  }
  render() {
    this.beam.clear();
    const resources = [
      this.DataBuffers,
      this.IndexBuffer,
      this.commonUniforms,
      this.commonTextures
    ];
    this.beam.draw(this.plugin, ...resources);
  }
}
class PbrRenderer extends BasicRenderer {
  constructor(canvas) {
    super(canvas);
    this.beam = new Beam(canvas, config.beamConfig);
    if (this.beam.gl.extensions.EXT_shader_texture_lod) {
      ThreeText.defines.USE_TEX_LOD = 1;
    }
    this.plugin = this.beam.plugin(ThreeText);
    this.rotateMat = create$3();
    this.translateMat = create$3();
    this.scaleMat = create$3();
  }
  async init() {
    await loadImage(config.brdfUrl).then((data) => {
      this.commonTextures.set("u_brdfLUT", {
        image: data,
        minFilter: GLTypes.NearestMipmapLinear,
        wrapT: GLTypes.ClampToEdge,
        wrapS: GLTypes.ClampToEdge
      });
    });
    const whiteColor = createSolidCanvas(config.whiteColor);
    const blackColor = createSolidCanvas("#000");
    const images = [];
    for (let i = 0; i < 6; i++) {
      images.push(blackColor);
    }
    const texCube2 = { images, level: 0, minFilter: GLTypes.Linear };
    this.commonTextures.set("u_DiffuseEnvSampler", texCube2);
    this.commonTextures.set("u_SpecularEnvSampler", texCube2);
    this.commonTextures.set("u_EmissiveSampler", { image: whiteColor });
    this.commonTextures.set("u_OcclusionSampler", { image: whiteColor });
    this.commonUniforms.set("u_ModelMatrix", create$3());
  }
  updateCanvasSize(model = {}, zoom = 1) {
    const { canvasBaseSize, canvas } = this;
    let canvasSize = canvasBaseSize * zoom;
    canvas.scaleRatio = 1;
    if (canvasSize > config.maxWebglCanvasSize) {
      const scaleRatio = config.maxWebglCanvasSize / canvasSize;
      zoom *= scaleRatio;
      canvas.scaleRatio = scaleRatio;
      canvasSize = config.maxWebglCanvasSize;
    }
    canvas.width = canvas.height = canvasSize;
    canvas.zoom = zoom;
  }
  updateTextures(images) {
    this.commonTextures.set("u_BaseColorSampler", __spreadValues({ image: images[0] }, this.getTexPara(images[0]))).set("u_NormalSampler", __spreadValues({ image: images[1] }, this.getTexPara(images[1]))).set("u_MetallicRoughnessSampler", __spreadValues({ image: images[2] }, this.getTexPara(images[2])));
  }
  isStandTex(image) {
    return isPowerOf2(image.width) && isPowerOf2(image.height);
  }
  updateMaterials(materials) {
    this.updateTextures(this.textures);
    this.commonUniforms.set("u_Type", materials.albedo.type).set("u_MetallicRoughnessValues", [materials.metalStrength, materials.roughnessStrength]).set("u_NormalStrength", materials.normalDisable ? 0 : materials.normalStrength).set("u_NormalScale", materials.scale).set("u_BaseColorScale", materials.scale);
    switch (materials.albedo.type) {
      case 0:
        const color = tinycolor(materials.albedo.color).toRgb();
        const faceColor = [color.r / 255, color.g / 255, color.b / 255];
        this.commonUniforms.set("u_FaceColor", faceColor);
        const k = materials.albedoStrength;
        const baseColorFactor = [k, k, k, k];
        this.commonUniforms.set("u_BaseColorFactor", baseColorFactor);
        break;
      case 1:
        const scaleRatio = 1 / materials.scale;
        const angle = materials.albedo.texRotateAngle * Math.PI / 180 || 0;
        const texMat = getTexMat(materials.albedo.texTranslate, angle, [scaleRatio, scaleRatio]);
        this.commonUniforms.set("u_TexMat", texMat);
        break;
      case 2:
        this.updateGradient(materials.albedo.gradient);
        break;
    }
  }
  updateGradient(gradient) {
    const { stops } = gradient;
    this.commonUniforms.set("u_GradientVec", gradient.direction);
    for (let i = 0; i < stops.length; i++) {
      const color = tinycolor(stops[i].color).toRgb();
      const colorVec = [color.r / 255, color.g / 255, color.b / 255];
      this.commonUniforms.set(`u_GradientColor[${i}].color`, colorVec).set(`u_GradientColor[${i}].offset`, stops[i].offset);
    }
  }
  async updateEnvironment(model) {
    const { strength, enable, maps } = model.environment;
    const envColor = tinycolor(maps[0]);
    if (envColor.isValid()) {
      this.commonUniforms.set("u_EnvColor", getColorVec3(maps[0], strength, enable));
    } else {
      const loadCubeMapsWithCache = loadCubeMaps(maps[0]);
      await loadCubeMapsWithCache.then((cubeMaps) => {
        cubeMaps[0].minFilter = GLTypes.Linear;
        cubeMaps[1].minFilter = GLTypes.LinearMipmapLinear;
        cubeMaps[0].space = GLTypes.SRGB;
        cubeMaps[1].space = GLTypes.SRGB;
        this.commonTextures.set("u_DiffuseEnvSampler", cubeMaps[0]).set("u_SpecularEnvSampler", cubeMaps[1]);
        this.commonUniforms.set("u_EnvColor", [0, 0, 0]);
      });
    }
    const k = enable ? strength : 0;
    const scaleIBLAmbientVec = [k, k, k, k];
    this.commonUniforms.set("u_ScaleIBLAmbient", scaleIBLAmbientVec);
  }
  async loadMaterials(model) {
    const mapUrls = getMapUrls(model.materials);
    this.textures = await Promise.all(mapUrls.map((value) => {
      return getTexture(value);
    }));
  }
  updateEyeDistance(model) {
    const { safeRatio = 1 } = config;
    this.viewAngle = model.viewAngle * Math.PI / 180;
    this.radius = this.modelSize / 2 * safeRatio;
    this.eyeDistance = this.radius / Math.sin(this.viewAngle / 2);
    this.zNear = this.eyeDistance - this.radius;
    this.zFar = this.eyeDistance + this.radius;
  }
  updateCamera(model) {
    const eye = rotateCamera(model.rotate3d, this.eyeDistance);
    this.commonUniforms.set("u_Camera", eye);
    const { radius = 100, zNear = 0.1, zFar = 1e3 } = this;
    if (model.isOrtho) {
      this.projMat = ortho([], -radius, radius, -radius, radius, zNear, zFar);
    } else {
      const aspect = this.canvas.width / this.canvas.height;
      this.projMat = perspective([], this.viewAngle, aspect, zNear, zFar);
    }
    lookAt(this.viewMat, eye, [0, 0, 0], [0, 1, 0]);
    this.setMvpMat();
    this.commonUniforms.set("u_MVPMatrix", this.mvpMat);
  }
  updateHemiLights(model) {
    const { dir = [0, 0, 1], color = "#ffffff", strength = 1, enable = false } = model.hemiLight;
    this.commonUniforms.set("u_HemiLight.dir", dir);
    this.commonUniforms.set("u_HemiLight.color", getColorVec3(color, strength, enable));
  }
  updateFloodLights(model) {
    if (model.isFloodLightOff) {
      for (let i = 0; i < config.pointLightsNum; i++) {
        this.commonUniforms.set(`u_Lights[${i}].color`, [0, 0, 0]);
      }
      this.commonUniforms.set("u_HemiLight.color", [0, 0, 0]);
    } else {
      this.updatePointLights(model);
      this.updateHemiLights(model);
    }
  }
  setMvpMat() {
    multiply(this.mvpMat, this.projMat, this.viewMat);
    return this.mvpMat;
  }
}
const { vec2, vec4, mat4, tex2D } = SchemaTypes;
const identityMat = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
const fillVS = `
attribute vec4 position;

uniform mat4 u_MVPMatrix;
uniform mat4 u_ShadowMatrix;

void main() {
  vec4 position = u_MVPMatrix * position;
  gl_Position = u_ShadowMatrix * position;
}
`;
const fillFS = `
precision highp float;
uniform vec4 shadowColor;

void main() {
  gl_FragColor = shadowColor;
}
`;
const VoidFill = {
  vs: fillVS,
  fs: fillFS,
  buffers: {
    position: { type: vec4, n: 3 }
  },
  uniforms: {
    u_MVPMatrix: { type: mat4 },
    u_ShadowMatrix: { type: mat4, default: identityMat },
    shadowColor: { type: vec4, default: [0, 0, 0, 0] }
  }
};
const { int, float } = SchemaTypes;
const blurVS = `
attribute vec4 position;
attribute vec2 texCoord;
uniform vec2 shadowOffset;

varying highp vec2 vTexCoord;

void main() {
  gl_Position = position + vec4(shadowOffset * 0.1, 0, 0);
  vTexCoord = texCoord;
}
`;
const blurFS = `
/*
* \u5B8C\u6574\u6A21\u7CCA\u6D41\u7A0B\uFF1A\u5148\u8C03\u7528\u6A2A\u5411\u6A21\u7CCA\uFF08\u6216\u7AD6\uFF09-> Texture -> \u7ED3\u679C\u7EB9\u7406\u4F20\u5165\u518D\u8C03\u7528\u7AD6\u5411\u6A21\u7CCA
*/
precision highp float;
varying vec2 vTexCoord;

// \u57FA\u7840\u56FE\u5C42
uniform sampler2D blurImg; 
// \u534A\u5F84
uniform float sigma;
// \u65B9\u5411
uniform int direction;
// \u56FE\u50CF\u5BBD\u5EA6
uniform float imgWidth;
// \u56FE\u50CF\u9AD8\u5EA6
uniform float imgHeight;

void main() {
  vec4 src = texture2D(blurImg, vTexCoord);
  float kernelRadius = ceil(sigma * 3.0 * 2.0 + 1.0);
  kernelRadius /=2.0;
  float kernelSize = kernelRadius * 2.0 + 1.0;
  // \u5F53 sigma \u5C0F\u4E8E 0 \u65F6\uFF0C\u91C7\u7528\u516C\u5F0F\u5F97\u5230\u53EA\u4E0E n \u6709\u5173\u7684 sigma
  float sigmaX = sigma > 0.0 ? sigma : ((kernelSize - 1.0)*0.5 - 1.0)*0.3 + 0.8;
  float scale2X = -0.5 / (sigmaX*sigmaX); // \u540E\u7EED\u9AD8\u65AF\u8868\u8FBE\u5F0F\u4E2D\u4F7F\u7528

  vec4 rgba = vec4(0.0);
  const float maxKernelSize = 1000.0;
  float stepV = 1.0;
  float weightSum = 0.0;
  for (float y = 0.0; y < maxKernelSize; y++) {
    if (y * stepV >= kernelSize) break;

    // \u95F4\u8DDD\u91C7\u6837
    vec2 uvCoord = vTexCoord + mix(vec2(y * stepV - kernelRadius, 0.0), 
    vec2(0.0, y * stepV - kernelRadius), float (direction == 0)) / vec2(imgWidth, imgHeight);
    vec4 srcTmp = texture2D(blurImg, uvCoord);
    // \u6743\u91CD\u8BA1\u7B97
    vec2 mn = vec2(y * stepV, y * stepV) - (kernelSize - 1.0) * 0.5;
    mn *= mn;
    vec2 weightxy = exp(scale2X * mn);
    float weight = weightxy.x;
    weightSum += weight;
    // \u6A21\u7CCA\u8FC7\u7A0B 
    rgba += srcTmp * weight;
  }
  if (weightSum != 0.0) gl_FragColor = clamp(rgba / weightSum, 0.0, 1.0);
  else gl_FragColor = src;
}
`;
const Blur = {
  vs: blurVS,
  fs: blurFS,
  buffers: {
    position: { type: vec4, n: 3 },
    texCoord: { type: vec2 }
  },
  uniforms: {
    shadowOffset: { type: vec2, default: [0, 0] },
    sigma: { type: float, default: 0 },
    imgWidth: { type: float },
    imgHeight: { type: float },
    direction: { type: int, default: 0 }
  },
  textures: {
    blurImg: { type: tex2D }
  }
};
const { DataBuffers, IndexBuffer, Uniforms, Textures, OffscreenTarget } = ResourceTypes;
class ThreeTextRenderer extends PbrRenderer {
  constructor(canvas, uniformsData = {}) {
    super(canvas, uniformsData);
    this.uniforms = [];
    this.materialTextures = [];
    for (let i = 0; i < config.structuresNum; i++) {
      this.uniforms[i] = this.beam.resource(Uniforms);
      this.materialTextures[i] = this.beam.resource(Textures);
    }
    this.commonUniforms = this.beam.resource(Uniforms, {});
    this.IndexBuffer = [];
    this.textures = [];
    this.meshMap = new lru.LRUMap(5);
    this.fontMap = new lru.LRUMap(5);
    this.initShadow();
  }
  async init() {
    super.init();
    if (!this.loadFont || !this.createTextModel) {
      const { loadFont, createTextModel } = await import(
        /* webpackChunkName: "three-font-parser" */
        "./three-font-parser.esm.js"
      );
      this.loadFont = loadFont;
      this.createTextModel = createTextModel;
    }
  }
  async updateTextModel(model) {
    const layer = model.layers[0];
    if (!model.$fontData) {
      model.$fontData = {};
    }
    let text = model.contents.reduce((rec, b) => rec + b.content, "");
    const RE_NBSP_WITH_SPACE = /&nbsp;|[\f\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/g;
    const UNIFORM_LINE_BREAK = /\r|<br\/?>/g;
    text = text.replace(RE_NBSP_WITH_SPACE, " ");
    text = text.replace(UNIFORM_LINE_BREAK, "\n");
    for (let i = 0, j = 0; i < text.length; i++) {
      if (text[i] !== "\n" && text[i] !== " ") {
        j++;
      }
      if (j >= 20) {
        text = text.slice(0, ++i);
        break;
      }
    }
    if (!text.length) {
      this.meshError = true;
      return;
    } else {
      this.meshError = false;
    }
    const key = text + model.$fontData.id + layer.extrudeDepth + layer.curveSegments + layer.bevelThickness + layer.bevelSize + layer.bevelSegments + layer.expand + layer.extrudeOffsetX + layer.extrudeOffsetY + model.lineHeight + model.letterSpacing + model.textAlign + model.writingMode + JSON.stringify(model.deformation) + JSON.stringify(model.warpByWord);
    this.shapeModel = this.meshMap.get(key);
    if (!this.shapeModel) {
      try {
        this.shapeModel = await this.createTextModel(text, getFontParserParameter(this.font, model));
        this.meshMap.set(key, this.shapeModel);
      } catch (error) {
        throw error;
      }
    }
    const { data, indexArray } = this.shapeModel;
    this.DataBuffers = this.beam.resource(DataBuffers, data);
    for (let i = 0; i < indexArray.length; i++) {
      this.IndexBuffer[i] = this.beam.resource(IndexBuffer, { array: indexArray[i] });
    }
    const { boundingBox } = this.shapeModel;
    this.commonUniforms.set("u_BoundingBox", boundingBox.max);
    this.commonUniforms.set("u_ScaleMat", fromScaling([], [boundingBox.max[0], 1, 1]));
    this.boundingBox = boundingBox;
    this.updateBBox(model);
    this.updateEyeDistance(model);
  }
  updateBBox(model) {
    const { shadow } = model;
    const shadowExpand = shadow.enable ? config.initFontSize : 0;
    this.modelSize = 2 * (Math.hypot(...this.boundingBox.max) + shadowExpand);
    this.shadowExpandRatio = 2 * config.initFontSize / this.modelSize;
    if (this.modelSize <= 1) {
      this.meshError = true;
      return;
    }
    const angle = model.viewAngle * Math.PI / 180;
    this.canvasBaseSize = this.modelSize / (model.isOrtho ? 1 : Math.cos(angle / 2));
  }
  updateCanvasSize(model = { fontSize: 100 }, compositeZoom = 1) {
    const { canvasBaseSize, canvas } = this;
    let canvasSize = Math.floor(canvasBaseSize * model.fontSize / config.initFontSize * compositeZoom);
    canvas.scaleRatio = 1;
    if (canvasSize > config.maxWebglCanvasSize) {
      const scaleRatio = config.maxWebglCanvasSize / canvasSize;
      compositeZoom *= scaleRatio;
      canvas.scaleRatio = scaleRatio;
      canvasSize = config.maxWebglCanvasSize;
    }
    canvas.width = canvasSize;
    canvas.height = canvasSize;
    canvas.compositeZoom = compositeZoom;
  }
  updateTextures(images, i) {
    this.materialTextures[i].set("u_BaseColorSampler", __spreadValues({ image: images[0] }, this.getTexPara(images[0]))).set("u_NormalSampler", __spreadValues({ image: images[1] }, this.getTexPara(images[1]))).set("u_MetallicRoughnessSampler", __spreadValues({ image: images[2] }, this.getTexPara(images[2])));
  }
  updateMaterials(materials = [], signals) {
    for (let i = 0; i < materials.length; i++) {
      if (!signals || signals[2 * i + 1]) {
        const material = materials[i];
        if (!signals || signals[2 * i]) {
          this.updateTextures(this.textures[i], i);
        }
        this.uniforms[i].set("u_Type", material.albedo.type).set("u_MetallicRoughnessValues", [material.metalStrength, material.roughnessStrength]).set("u_NormalStrength", material.normalDisable ? 0 : material.normalStrength).set("u_NormalScale", material.scale).set("u_BaseColorScale", material.scale);
        switch (material.albedo.type) {
          case 0:
            const color = tinycolor(material.albedo.color).toRgb();
            const faceColor = [color.r / 255, color.g / 255, color.b / 255];
            this.uniforms[i].set("u_FaceColor", faceColor);
            const k = material.albedoStrength;
            const baseColorFactor = [k, k, k, k];
            this.uniforms[i].set("u_BaseColorFactor", baseColorFactor);
            break;
          case 1:
            const scaleRatio = 1 / material.scale;
            const angle = material.albedo.texRotateAngle * Math.PI / 180 || 0;
            const texMat = getTexMat(material.albedo.texTranslate, angle, [scaleRatio, scaleRatio]);
            this.uniforms[i].set("u_TexMat", texMat);
            break;
          case 2:
            this.updateGradient(material.albedo.gradient, i);
            break;
        }
      }
    }
  }
  async loadMaterials(model, signals) {
    const { frontMaterials, sideMaterials, bevelMaterials } = model.layers[0];
    const frontMapUrls = getMapUrls(frontMaterials);
    const sideMapUrls = sideMaterials.enable ? getMapUrls(sideMaterials) : [];
    const bevelMapUrls = bevelMaterials.enable ? getMapUrls(bevelMaterials) : [];
    const mapUrls = [frontMapUrls, bevelMapUrls, sideMapUrls];
    for (let i = 0; i < config.structuresNum; i++) {
      if (!signals || signals[2 * i + 1]) {
        this.textures[i] = await Promise.all(mapUrls[i].map((value) => {
          return getTexture(value);
        }));
      }
    }
    if (!this.textures[2].length) {
      this.textures[2] = this.textures[0];
    }
    if (!this.textures[1].length) {
      this.textures[1] = this.textures[2];
    }
  }
  async prepareFont(model) {
    let fontUrl = "";
    if (model.$fontData) {
      fontUrl = model.$fontData.woff;
    } else {
      fontUrl = config.defaultFont;
    }
    let font = this.fontMap.get(fontUrl);
    if (!font) {
      font = await this.loadFont(fontUrl);
      this.fontMap.set(fontUrl, font);
      font.url = fontUrl;
    }
    this.font = font;
  }
  updateCamera(model) {
    const eye = rotateCamera(model.rotate3d, this.eyeDistance);
    this.commonUniforms.set("u_Camera", eye);
    const { radius, zNear = 0.01, zFar = 1e4 } = this;
    if (model.isOrtho) {
      this.projMat = ortho([], -radius, radius, -radius, radius, zNear, zFar);
    } else {
      const aspect = this.canvas.width / this.canvas.height;
      this.projMat = perspective([], this.viewAngle, aspect, zNear, zFar);
    }
    lookAt(this.viewMat, eye, [0, 0, 0], eye.up || [0, 1, 0]);
    this.setMvpMat();
    this.commonUniforms.set("u_MVPMatrix", this.mvpMat);
    const { shadow = { enable: false } } = model;
    if (shadow.enable) {
      this.bindShadowAngle(shadow);
    }
  }
  updateGradient(gradient, j) {
    const { stops } = gradient;
    this.uniforms[j].set("u_GradientVec", gradient.direction);
    for (let i = 0; i < config.gradientMaxNum; i++) {
      if (i < stops.length) {
        this.uniforms[j].set(`u_GradientColor[${i}].color`, getColorVec3(stops[i].color)).set(`u_GradientColor[${i}].offset`, stops[i].offset);
      } else {
        this.uniforms[j].set(`u_GradientColor[${i}].offset`, 2);
      }
    }
  }
  setMvpMat() {
    multiply(this.mvpMat, this.projMat, this.viewMat);
    return this.mvpMat;
  }
  initShadow() {
    const { beam } = this;
    beam.define(Offscreen2DCommand);
    this.fillPlugin = beam.plugin(VoidFill);
    this.blurPlugin = beam.plugin(Blur);
    const { offscreenSize } = config;
    this.offscreenTargets = [
      beam.resource(OffscreenTarget, { size: offscreenSize }),
      beam.resource(OffscreenTarget, { size: offscreenSize })
    ];
    this.offscreenTextures = [
      beam.resource(Textures),
      beam.resource(Textures)
    ];
    const { gl } = beam;
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, this.offscreenTargets[0].colorTexture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.bindTexture(gl.TEXTURE_2D, this.offscreenTargets[1].colorTexture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    this.offscreenTextures[0].set("blurImg", this.offscreenTargets[0]);
    this.offscreenTextures[1].set("blurImg", this.offscreenTargets[1]);
    this.shadowUniforms = beam.resource(Uniforms, {
      sigma: 10,
      imgWidth: offscreenSize,
      imgHeight: offscreenSize,
      direction: 0
    });
    const quad = createPlaneModel([1, 1], {});
    this.quadData = beam.resource(DataBuffers, quad.data);
    this.quadIndex = beam.resource(IndexBuffer, quad.index);
  }
  updateShadow(model) {
    const { shadow } = model;
    this.bindShadowAngle(shadow);
    const { blur, color, offset, angle } = shadow;
    const scale2 = Math.exp(-0.05 * offset);
    const radianAngle = toRadian(angle);
    const radius = offset * this.shadowExpandRatio;
    const translateVec = [radius * Math.cos(radianAngle), radius * Math.sin(radianAngle), 0];
    const scaleVec = [scale2, scale2, 0];
    const scaleMat = fromScaling(create$3(), scaleVec);
    const translateMat = fromTranslation(create$3(), translateVec);
    const shadowMatrix = multiply(create$3(), translateMat, scaleMat);
    this.shadowUniforms.set("u_ShadowMatrix", shadowMatrix);
    this.shadowUniforms.set("shadowColor", getColorVec(color));
    this.shadowUniforms.set("sigma", blur);
  }
  bindShadowAngle(shadow) {
    if (shadow.enable && shadow.isBindRotate) {
      const { offsetRatio = 1 } = shadow;
      const basicZ = fromValues(0, 0, -1);
      const zVecAfterMvp = transformMat4([], basicZ, this.mvpMat);
      const angle = Math.atan2(zVecAfterMvp[1], zVecAfterMvp[0]) * 180 / Math.PI;
      const offset = this.radius * Math.hypot(zVecAfterMvp[1], zVecAfterMvp[0]);
      shadow.angle = angle;
      shadow.offset = offset * offsetRatio;
    }
  }
  drawShadow() {
    const { beam } = this;
    const { gl } = this.beam;
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    beam.offscreen2D(this.offscreenTargets[0], () => {
      for (let i = 0; i < this.IndexBuffer.length; i++) {
        const resources = [
          this.DataBuffers,
          this.IndexBuffer[i],
          this.uniforms[i],
          this.commonUniforms,
          this.shadowUniforms
        ];
        beam.draw(this.fillPlugin, ...resources);
      }
    });
    gl.disable(gl.BLEND);
    gl.viewport(0, 0, this.canvas.width, this.canvas.height);
    this.shadowUniforms.set("direction", 0);
    beam.offscreen2D(this.offscreenTargets[1], () => {
      beam.draw(this.blurPlugin, this.quadData, this.quadIndex, this.offscreenTextures[0], this.shadowUniforms);
    });
    gl.viewport(0, 0, this.canvas.width, this.canvas.height);
    beam.gl.disable(beam.gl.DEPTH_TEST);
    this.shadowUniforms.set("direction", 1);
    beam.draw(this.blurPlugin, this.quadData, this.quadIndex, this.offscreenTextures[1], this.shadowUniforms);
    beam.gl.enable(beam.gl.DEPTH_TEST);
  }
  initCoordinate() {
    const { beam } = this;
    this.meshPlugin = beam.plugin(Mesh);
    const planeSize = config.initFontSize;
    if (!this.cylinderData) {
      this.initCylinder();
    }
    const plane = createPlaneModel([planeSize, planeSize], { isSimple: true, direc: "y" });
    this.planeData = beam.resource(DataBuffers, plane.data);
    this.planeIndex = beam.resource(IndexBuffer, plane.index);
    this.planeBorderIndex = beam.resource(IndexBuffer, { array: [0, 1, 1, 3, 3, 2, 2, 0] });
    this.planeUniforms = beam.resource(Uniforms, {
      "u_Color": getColorVec("#F5980046"),
      "u_ScaleMat": create$3()
    });
    this.planeBorderUniforms = beam.resource(Uniforms, {
      "u_Color": getColorVec("#F59800cb")
    });
    this.axisXUniforms = beam.resource(Uniforms, {
      "u_Color": getColorVec("#E54937ff"),
      "u_RotateMat": fromScaling([], [1, 1.2, 1.2])
    });
    this.axisYUniforms = beam.resource(Uniforms, {
      "u_Color": getColorVec("#2254F4ff"),
      "u_RotateMat": multiply([], fromYRotation([], Math.PI / 2), fromScaling([], [0.5, 1.2, 1.2]))
    });
    this.planeResouuces = [
      this.planeData,
      this.planeIndex,
      this.commonUniforms,
      this.planeUniforms
    ];
    this.planeBorderResources = [
      this.planeData,
      this.planeBorderIndex,
      this.commonUniforms,
      this.planeBorderUniforms
    ];
    this.axisXResources = [
      this.cylinderData,
      this.cylinderIndex,
      this.commonUniforms,
      this.axisXUniforms
    ];
    this.axisYResources = [
      this.cylinderData,
      this.cylinderIndex,
      this.commonUniforms,
      this.axisYUniforms
    ];
  }
  drawCoordinate(model) {
    if (!this.axisXResources) {
      this.initCoordinate(model);
    }
    const { gl } = this.beam;
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    this.beam.draw(this.simplePlugin, ...this.axisXResources);
    this.beam.draw(this.simplePlugin, ...this.axisYResources);
    this.beam.draw(this.simplePlugin, ...this.planeResouuces);
    this.beam.draw(this.meshPlugin, ...this.planeBorderResources);
    gl.disable(gl.BLEND);
  }
  render(model) {
    this.beam.clear();
    if (model.isMesh) {
      this.drawGrid();
    } else {
      if (model && model.shadow.enable) {
        this.drawShadow();
      }
      for (let i = 0; i < this.IndexBuffer.length; i++) {
        const resources = [
          this.DataBuffers,
          this.IndexBuffer[i],
          this.uniforms[i],
          this.commonUniforms,
          this.materialTextures[i],
          this.commonTextures
        ];
        this.beam.draw(this.plugin, ...resources);
      }
      if (model.$showCoordinate) {
        this.drawCoordinate(model);
      }
    }
  }
}
export { ThreeTextRenderer as T, getModelSize as g };
