setupWebGLMethods 安装WebGL方法
setupWebGLMethods
类型: MethodDeclaration
定义位置: webgl.ts
描述
安装WebGL方法
参数 GL: 上下文对象
参数
| 参数名 | 类型 | 描述 | 默认值 | 
|---|---|---|---|
| GL | WebGL2RenderingContext | - | - | 
返回值
类型: void
源代码
位置: 第 305 行
private setupWebGLMethods(GL: WebGL2RenderingContext): void {
    // WebGL上下文方法 - 创建程序对象
    GL.createProgramWithShaders = function (vshader: string, fshader: string): WebGLProgram {
      const vertexShader = this.loadShader(this.VERTEX_SHADER, vshader)
      const fragmentShader = this.loadShader(this.FRAGMENT_SHADER, fshader)
      if (!vertexShader || !fragmentShader) {
        throw new Error('Failed to load shaders')
      }
      const program = this.createProgram()
      if (!program) {
        throw new Error('Failed to create program')
      }
      this.attachShader(program, vertexShader)
      this.attachShader(program, fragmentShader)
      this.linkProgram(program)
      if (!this.getProgramParameter(program, this.LINK_STATUS)) {
        const error = this.getProgramInfoLog(program)
        this.deleteProgram(program)
        this.deleteShader(fragmentShader)
        this.deleteShader(vertexShader)
        throw new Error(`Failed to link program: ${error}`)
      }
      return program
    }
    // WebGL上下文方法 - 加载着色器
    GL.loadShader = function (type: number, source: string): WebGLShader {
      const shader = this.createShader(type)
      if (!shader) {
        throw new Error('Failed to create shader')
      }
      this.shaderSource(shader, source)
      this.compileShader(shader)
      if (!this.getShaderParameter(shader, this.COMPILE_STATUS)) {
        const error = this.getShaderInfoLog(shader)
        this.deleteShader(shader)
        console.error(`Failed to compile shader: ${error}`)
      }
      return shader
    }
    // WebGL上下文方法 - 创建图像程序
    GL.createImageProgram = function (): WebGLImageProgram {
      const program = this.createProgramWithShaders(
        `
        attribute   vec2        a_Position;
        attribute   vec2        a_TexCoord;
        attribute   float       a_Opacity;
        uniform     float       u_Flip;
        uniform     mat3        u_Matrix;
        uniform     vec3        u_Ambient;
        uniform     int         u_LightMode;
        uniform     vec2        u_LightCoord;
        uniform     vec4        u_LightTexSize;
        uniform     sampler2D   u_LightSampler;
        varying     vec2        v_TexCoord;
        varying     vec3        v_LightColor;
        varying     float       v_Opacity;
        // 获取光照颜色系数
        vec3 getLightColor() {
          if (u_LightMode == 0) {
            // 光线采样:原始图像
            return vec3(1.0, 1.0, 1.0);
          }
          if (u_LightMode == 1) {
            // 光线采样:全局采样
            return vec3(
              gl_Position.x / u_LightTexSize.x + u_LightTexSize.z,
              gl_Position.y / u_LightTexSize.y * u_Flip + u_LightTexSize.w,
              -1.0
            );
          }
          if (u_LightMode == 2) {
            // 光线采样:锚点采样
            vec2 anchorCoord = (u_Matrix * vec3(u_LightCoord, 1.0)).xy;
            vec2 lightCoord = vec2(
              anchorCoord.x / u_LightTexSize.x + u_LightTexSize.z,
              anchorCoord.y / u_LightTexSize.y * u_Flip + u_LightTexSize.w
            );
            return texture2D(u_LightSampler, lightCoord).rgb;
          }
          if (u_LightMode == 3) {
            // 光线采样:环境光
            return u_Ambient;
          }
        }
        void main() {
          gl_Position.xyw = u_Matrix * vec3(a_Position, 1.0);
          v_TexCoord = a_TexCoord;
          v_LightColor = getLightColor();
          v_Opacity = a_Opacity;
        }
        `,
        `
        precision   highp       float;
        varying     vec2        v_TexCoord;
        varying     vec3        v_LightColor;
        uniform     vec2        u_Viewport;
        uniform     int         u_Masking;
        varying     float       v_Opacity;
        uniform     float       u_Alpha;
        uniform     int         u_ColorMode;
        uniform     vec4        u_Color;
        uniform     vec4        u_Tint;
        uniform     vec4        u_Repeat;
        uniform     sampler2D   u_Sampler;
        uniform     sampler2D   u_MaskSampler;
        uniform     sampler2D   u_LightSampler;
        // 获取光照颜色系数(全局采样)
        vec3 getLightColor() {
          if (v_LightColor.z != -1.0) return v_LightColor;
          return texture2D(u_LightSampler, v_LightColor.xy).rgb;
        }
        void main() {
          if (u_ColorMode == 0) {
            // 颜色模式:纹理采样 + 色调
            gl_FragColor = texture2D(u_Sampler, fract(v_TexCoord));
            if (gl_FragColor.a == 0.0) discard;
            gl_FragColor.rgb = gl_FragColor.rgb * (1.0 - u_Tint.a) + u_Tint.rgb +
            dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114)) * u_Tint.a;
          } else if (u_ColorMode == 1) {
            // 颜色模式:指定颜色
            float alpha = texture2D(u_Sampler, v_TexCoord).a;
            if (alpha == 0.0) discard;
            gl_FragColor = vec4(u_Color.rgb, u_Color.a * alpha);
          } else if (u_ColorMode == 2) {
            // 颜色模式:纹理采样 + 切片
            vec2 uv = vec2(
              mod(v_TexCoord.x - u_Repeat.x, u_Repeat.z) + u_Repeat.x,
              mod(v_TexCoord.y - u_Repeat.y, u_Repeat.w) + u_Repeat.y
            );
            gl_FragColor = texture2D(u_Sampler, uv);
            if (gl_FragColor.a == 0.0) discard;
            gl_FragColor.rgb = gl_FragColor.rgb * (1.0 - u_Tint.a) + u_Tint.rgb +
            dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114)) * u_Tint.a;
          }
          gl_FragColor.rgb *= getLightColor();
          gl_FragColor.a *= v_Opacity * u_Alpha;
          if (u_Masking == 1) {
            vec2 fragCoord = vec2(gl_FragCoord.x, (u_Viewport.y - gl_FragCoord.y));
            gl_FragColor.a *= texture2D(u_MaskSampler, fragCoord / u_Viewport).a;
          }
        }
        `,
      ) as WebGLImageProgram
      this.useProgram(program)
      // 顶点着色器属性
      const a_Position = this.getAttribLocation(program, 'a_Position')
      const a_TexCoord = this.getAttribLocation(program, 'a_TexCoord')
      const a_Opacity = this.getAttribLocation(program, 'a_Opacity')
      const u_Flip = this.getUniformLocation(program, 'u_Flip')
      const u_Matrix = this.getUniformLocation(program, 'u_Matrix')!
      const u_Ambient = this.getUniformLocation(program, 'u_Ambient')!
      const u_LightMode = this.getUniformLocation(program, 'u_LightMode')!
      const u_LightCoord = this.getUniformLocation(program, 'u_LightCoord')!
      const u_LightTexSize = this.getUniformLocation(program, 'u_LightTexSize')!
      // 设置光线采样器指向最后一个纹理
      this.uniform1i(this.getUniformLocation(program, 'u_LightSampler'), this.maxTexUnits - 1)
      // 片元着色器属性
      const u_Viewport = this.getUniformLocation(program, 'u_Viewport')!
      const u_Masking = this.getUniformLocation(program, 'u_Masking')!
      const u_Alpha = this.getUniformLocation(program, 'u_Alpha')!
      const u_ColorMode = this.getUniformLocation(program, 'u_ColorMode')!
      const u_Color = this.getUniformLocation(program, 'u_Color')!
      const u_Tint = this.getUniformLocation(program, 'u_Tint')!
      const u_Repeat = this.getUniformLocation(program, 'u_Repeat')!
      const u_MaskSampler = this.getUniformLocation(program, 'u_MaskSampler')!
      // 创建顶点数组对象
      const vao = this.createVertexArray() as WebGLVertexArrayObjectImage
      this.bindVertexArray(vao)
      this.enableVertexAttribArray(a_Position)
      this.enableVertexAttribArray(a_TexCoord)
      this.enableVertexAttribArray(a_Opacity)
      this.bindBuffer(this.ARRAY_BUFFER, this.vertexBuffer)
      this.vertexAttribPointer(a_Position, 2, this.FLOAT, false, 20, 0)
      this.vertexAttribPointer(a_TexCoord, 2, this.FLOAT, false, 20, 8)
      this.vertexAttribPointer(a_Opacity, 1, this.FLOAT, false, 20, 16)
      this.bindBuffer(this.ELEMENT_ARRAY_BUFFER, this.elementBuffer)
      // 创建顶点数组对象 - 属性[110]
      vao.a110 = this.createVertexArray()!
      this.bindVertexArray(vao.a110)
      this.enableVertexAttribArray(a_Position)
      this.enableVertexAttribArray(a_TexCoord)
      this.bindBuffer(this.ARRAY_BUFFER, this.vertexBuffer)
      this.vertexAttribPointer(a_Position, 2, this.FLOAT, false, 16, 0)
      this.vertexAttribPointer(a_TexCoord, 2, this.FLOAT, false, 16, 8)
      this.bindBuffer(this.ELEMENT_ARRAY_BUFFER, this.elementBuffer)
      // 使用程序对象
      const use = () => {
        if (this.program !== program) {
          this.program = program
          this.useProgram(program)
        }
        if (program.flip !== this.flip) {
          program.flip = this.flip
          this.uniform1f(u_Flip, program.flip)
        }
        if (program.alpha !== this.alpha) {
          program.alpha = this.alpha
          this.uniform1f(u_Alpha, program.alpha)
        }
        if (program.masking !== this.masking) {
          program.masking = this.masking
          if (this.masking) {
            this.uniform1i(u_Masking, 1)
            this.uniform1i(u_MaskSampler, 1)
            this.activeTexture(this.TEXTURE1)
            this.bindTexture(this.TEXTURE_2D, this.maskTexture.base.glTexture)
            this.activeTexture(this.TEXTURE0)
          } else {
            this.uniform1i(u_Masking, 0)
            this.uniform1i(u_MaskSampler, 0)
            this.activeTexture(this.TEXTURE1)
            this.bindTexture(this.TEXTURE_2D, null)
            this.activeTexture(this.TEXTURE0)
          }
        }
        if (this.masking) {
          this.uniform2f(u_Viewport, this.width, this.height)
        }
        this.updateBlending()
        return program
      }
      // 保存程序对象
      program.use = use
      program.vao = vao
      program.flip = 0
      program.alpha = 0
      program.masking = false
      program.a_Position = a_Position
      program.a_TexCoord = a_TexCoord
      program.a_Opacity = a_Opacity
      program.u_Matrix = u_Matrix
      program.u_Ambient = u_Ambient
      program.u_LightMode = u_LightMode
      program.u_LightCoord = u_LightCoord
      program.u_LightTexSize = u_LightTexSize
      program.u_Viewport = u_Viewport
      program.u_Masking = u_Masking
      program.u_MaskSampler = u_MaskSampler
      program.u_ColorMode = u_ColorMode
      program.u_Color = u_Color
      program.u_Tint = u_Tint
      program.u_Repeat = u_Repeat
      return program
    }
    // WebGL上下文方法 - 创建图块程序
    GL.createTileProgram = function (): WebGLTileProgram {
      const program = this.createProgramWithShaders(
        `
        attribute   vec2        a_Position;
        attribute   vec2        a_TexCoord;
        attribute   float       a_TexIndex;
        uniform     float       u_Flip;
        uniform     mat3        u_Matrix;
        uniform     vec3        u_Ambient;
        uniform     int         u_LightMode;
        uniform     vec4        u_LightTexSize;
        uniform     sampler2D   u_LightSampler;
        varying     float       v_TexIndex;
        varying     vec2        v_TexCoord;
        varying     vec3        v_LightColor;
        // 获取光照颜色系数
        vec3 getLightColor() {
          if (u_LightMode == 0) {
            // 光线采样:原始图像
            return vec3(1.0, 1.0, 1.0);
          }
          if (u_LightMode == 1) {
            // 光线采样:全局采样
            return vec3(
              gl_Position.x / u_LightTexSize.x + u_LightTexSize.z,
              gl_Position.y / u_LightTexSize.y * u_Flip + u_LightTexSize.w,
              -1.0
            );
          }
          if (u_LightMode == 2) {
            // 光线采样:环境光
            return u_Ambient;
          }
        }
        void main() {
          gl_Position.xyw = u_Matrix * vec3(a_Position, 1.0);
          v_TexCoord = a_TexCoord;
          v_TexIndex = a_TexIndex;
          v_LightColor = getLightColor();
        }
        `,
        `
        precision   highp       float;
        varying     float       v_TexIndex;
        varying     vec2        v_TexCoord;
        varying     vec3        v_LightColor;
        uniform     float       u_Alpha;
        uniform     sampler2D   u_Samplers[15];
        uniform     sampler2D   u_LightSampler;
        // 采样纹理像素颜色(采样器索引,坐标)
        // 采样器数组的索引必须使用常量
        vec4 sampler(int index, vec2 uv) {
          for (int i = 0; i < 15; i++) {
            if (i == index) {
              return texture2D(u_Samplers[i], uv);
            }
          }
        }
        // 获取光照颜色系数(全局采样)
        vec3 getLightColor() {
          if (v_LightColor.z != -1.0) return v_LightColor;
          return texture2D(u_LightSampler, v_LightColor.xy).rgb;
        }
        void main() {
          gl_FragColor = sampler(int(v_TexIndex), v_TexCoord);
          if (gl_FragColor.a == 0.0) discard;
          gl_FragColor.rgb *= getLightColor();
          gl_FragColor.a *= u_Alpha;
        }
        `,
      ) as WebGLTileProgram
      this.useProgram(program)
      // 顶点着色器属性
      const a_Position = this.getAttribLocation(program, 'a_Position')
      const a_TexCoord = this.getAttribLocation(program, 'a_TexCoord')
      const a_TexIndex = this.getAttribLocation(program, 'a_TexIndex')
      const u_Flip = this.getUniformLocation(program, 'u_Flip')!
      const u_Matrix = this.getUniformLocation(program, 'u_Matrix')!
      const u_Ambient = this.getUniformLocation(program, 'u_Ambient')!
      const u_LightMode = this.getUniformLocation(program, 'u_LightMode')!
      const u_LightTexSize = this.getUniformLocation(program, 'u_LightTexSize')!
      // 设置光线采样器指向最后一个纹理
      this.uniform1i(this.getUniformLocation(program, 'u_LightSampler'), this.maxTexUnits - 1)
      // 片元着色器属性
      const u_Alpha = this.getUniformLocation(program, 'u_Alpha')!
      const u_SamplerLength = this.maxTexUnits - 1
      const u_Samplers = []
      for (let i = 0; i < u_SamplerLength; i++) {
        u_Samplers.push(this.getUniformLocation(program, `u_Samplers[${i}]`)!)
      }
      // 创建顶点数组对象
      const vao = this.createVertexArray()!
      this.bindVertexArray(vao)
      this.enableVertexAttribArray(a_Position)
      this.enableVertexAttribArray(a_TexCoord)
      this.enableVertexAttribArray(a_TexIndex)
      this.bindBuffer(this.ARRAY_BUFFER, this.vertexBuffer)
      this.vertexAttribPointer(a_Position, 2, this.FLOAT, false, 20, 0)
      this.vertexAttribPointer(a_TexCoord, 2, this.FLOAT, false, 20, 8)
      this.vertexAttribPointer(a_TexIndex, 1, this.FLOAT, false, 20, 16)
      this.bindBuffer(this.ELEMENT_ARRAY_BUFFER, this.elementBuffer)
      // 使用程序对象
      const use = () => {
        if (this.program !== program) {
          this.program = program
          this.useProgram(program)
        }
        if (program.flip !== this.flip) {
          program.flip = this.flip
          this.uniform1f(u_Flip, program.flip)
        }
        if (program.alpha !== this.alpha) {
          program.alpha = this.alpha
          this.uniform1f(u_Alpha, program.alpha)
        }
        return program
      }
      // 保存程序对象
      program.use = use
      program.vao = vao
      program.flip = 0
      program.alpha = 0
      program.samplerNum = 1
      program.a_Position = a_Position
      program.a_TexCoord = a_TexCoord
      program.a_TexIndex = a_TexIndex
      program.u_Matrix = u_Matrix
      program.u_Ambient = u_Ambient
      program.u_LightMode = u_LightMode
      program.u_LightTexSize = u_LightTexSize
      program.u_Samplers = u_Samplers
      return program
    }
    // WebGL上下文方法 - 创建精灵程序
    GL.createSpriteProgram = function (): WebGLSpriteProgram {
      const program = this.createProgramWithShaders(
        `
        attribute   vec2        a_Position;
        attribute   vec2        a_TexCoord;
        attribute   vec3        a_TexParam;
        attribute   vec4        a_Tint;
        attribute   vec2        a_LightCoord;
        uniform     float       u_Flip;
        uniform     mat3        u_Matrix;
        uniform     vec4        u_LightTexSize;
        uniform     sampler2D   u_LightSampler;
        varying     float       v_TexIndex;
        varying     float       v_Opacity;
        varying     vec4        v_Tint;
        varying     vec2        v_TexCoord;
        varying     vec3        v_LightColor;
        // 获取光照颜色系数
        vec3 getLightColor() {
          // 参数Z分量是0 = 光线采样:原始图像
          if (a_TexParam.z == 0.0) {
            return vec3(1.0, 1.0, 1.0);
          }
          // 参数Z分量是1 = 光线采样:全局采样
          if (a_TexParam.z == 1.0) {
            return vec3(
              gl_Position.x / u_LightTexSize.x + u_LightTexSize.z,
              gl_Position.y / u_LightTexSize.y * u_Flip + u_LightTexSize.w,
              -1.0
            );
          }
          // 参数Z分量是2 = 光线采样:锚点采样
          if (a_TexParam.z == 2.0) {
            return texture2D(u_LightSampler, a_LightCoord).rgb;
          }
        }
        void main() {
          gl_Position.xyw = u_Matrix * vec3(a_Position, 1.0);
          v_TexIndex = a_TexParam.x;
          // 不透明度归一化(0~255映射为0~1)
          v_Opacity = a_TexParam.y / 255.0;
          // 解压缩色调编码(0~510映射为-1~1)
          v_Tint = a_Tint / 255.0 - 1.0;
          v_TexCoord = a_TexCoord;
          v_LightColor = getLightColor();
        }
        `,
        `
        precision   highp       float;
        varying     float       v_TexIndex;
        varying     float       v_Opacity;
        varying     vec4        v_Tint;
        varying     vec2        v_TexCoord;
        varying     vec3        v_LightColor;
        uniform     float       u_Alpha;
        uniform     sampler2D   u_Samplers[15];
        uniform     sampler2D   u_LightSampler;
        // 采样纹理像素颜色(采样器索引,坐标)
        // 采样器数组的索引必须使用常量
        vec4 sampler(int index, vec2 uv) {
          for (int i = 0; i < 15; i++) {
            if (i == index) {
              return texture2D(u_Samplers[i], uv);
            }
          }
        }
        // 对颜色使用色调
        vec3 tint(vec3 color, vec4 tint) {
          return color.rgb * (1.0 - tint.a) + tint.rgb +
          dot(color.rgb, vec3(0.299, 0.587, 0.114)) * tint.a;
        }
        // 获取光照颜色系数(全局采样)
        vec3 getLightColor() {
          if (v_LightColor.z != -1.0) return v_LightColor;
          return texture2D(u_LightSampler, v_LightColor.xy).rgb;
        }
        void main() {
          gl_FragColor = sampler(int(v_TexIndex), v_TexCoord);
          if (gl_FragColor.a == 0.0) discard;
          gl_FragColor.rgb = tint(gl_FragColor.rgb, v_Tint) * getLightColor();
          gl_FragColor.a *= v_Opacity * u_Alpha;
        }
        `,
      ) as WebGLSpriteProgram
      this.useProgram(program)
      // 顶点着色器属性
      const a_Position = this.getAttribLocation(program, 'a_Position')
      const a_TexCoord = this.getAttribLocation(program, 'a_TexCoord')
      const a_TexParam = this.getAttribLocation(program, 'a_TexParam')
      const a_Tint = this.getAttribLocation(program, 'a_Tint')!
      const a_LightCoord = this.getAttribLocation(program, 'a_LightCoord')!
      const u_Flip = this.getUniformLocation(program, 'u_Flip')!
      const u_Matrix = this.getUniformLocation(program, 'u_Matrix')!
      const u_LightTexSize = this.getUniformLocation(program, 'u_LightTexSize')!
      // 设置光线采样器指向最后一个纹理
      this.uniform1i(this.getUniformLocation(program, 'u_LightSampler'), this.maxTexUnits - 1)
      // 片元着色器属性
      const u_Alpha = this.getUniformLocation(program, 'u_Alpha')
      const u_SamplerLength = this.maxTexUnits - 1
      const u_Samplers = []
      for (let i = 0; i < u_SamplerLength; i++) {
        u_Samplers.push(this.getUniformLocation(program, `u_Samplers[${i}]`)!)
      }
      // 创建顶点数组对象
      const vao = this.createVertexArray()!
      this.bindVertexArray(vao)
      this.enableVertexAttribArray(a_Position)
      this.enableVertexAttribArray(a_TexCoord)
      this.enableVertexAttribArray(a_TexParam)
      this.enableVertexAttribArray(a_Tint)
      this.enableVertexAttribArray(a_LightCoord)
      this.bindBuffer(this.ARRAY_BUFFER, this.vertexBuffer)
      this.vertexAttribPointer(a_Position, 2, this.FLOAT, false, 32, 0)
      this.vertexAttribPointer(a_TexCoord, 2, this.FLOAT, false, 32, 8)
      this.vertexAttribPointer(a_TexParam, 3, this.UNSIGNED_BYTE, false, 32, 16)
      this.vertexAttribPointer(a_Tint, 4, this.UNSIGNED_SHORT, false, 32, 20)
      this.vertexAttribPointer(a_LightCoord, 2, this.UNSIGNED_SHORT, true, 32, 28)
      this.bindBuffer(this.ELEMENT_ARRAY_BUFFER, this.elementBuffer)
      // 使用程序对象
      const use = () => {
        if (this.program !== program) {
          this.program = program
          this.useProgram(program)
        }
        if (program.flip !== this.flip) {
          program.flip = this.flip
          this.uniform1f(u_Flip, program.flip)
        }
        if (program.alpha !== this.alpha) {
          program.alpha = this.alpha
          this.uniform1f(u_Alpha, program.alpha)
        }
        return program
      }
      // 保存程序对象
      program.use = use
      program.vao = vao
      program.flip = 0
      program.alpha = 0
      program.samplerNum = 1
      program.a_Position = a_Position
      program.a_TexCoord = a_TexCoord
      program.a_TexParam = a_TexParam
      program.a_Tint = a_Tint
      program.a_LightCoord = a_LightCoord
      program.u_Matrix = u_Matrix
      program.u_LightTexSize = u_LightTexSize
      program.u_Samplers = u_Samplers
      return program
    }
    // WebGL上下文方法 - 创建粒子程序
    GL.createParticleProgram = function (): WebGLParticleProgram {
      const program = this.createProgramWithShaders(
        `
        attribute   vec2        a_Position;
        attribute   vec2        a_TexCoord;
        attribute   vec4        a_Color;
        uniform     float       u_Flip;
        uniform     mat3        u_Matrix;
        uniform     vec3        u_Ambient;
        uniform     int         u_LightMode;
        uniform     vec4        u_LightTexSize;
        uniform     sampler2D   u_LightSampler;
        varying     vec2        v_TexCoord;
        varying     vec4        v_Color;
        varying     vec3        v_LightColor;
        vec3 getLightColor() {
          if (u_LightMode == 0) {
            // 光线采样:原始图像
            return vec3(1.0, 1.0, 1.0);
          }
          if (u_LightMode == 1) {
            // 光线采样:全局采样
            return vec3(
              gl_Position.x / u_LightTexSize.x + u_LightTexSize.z,
              gl_Position.y / u_LightTexSize.y * u_Flip + u_LightTexSize.w,
              -1.0
            );
          }
          if (u_LightMode == 2) {
            // 光线采样:环境光
            return u_Ambient;
          }
        }
        void main() {
          gl_Position.xyw = u_Matrix * vec3(a_Position, 1.0);
          v_TexCoord = a_TexCoord;
          v_Color = a_Color;
          v_LightColor = getLightColor();
        }
        `,
        `
        precision   highp       float;
        varying     vec2        v_TexCoord;
        varying     vec4        v_Color;
        varying     vec3        v_LightColor;
        uniform     float       u_Alpha;
        uniform     int         u_Mode;
        uniform     vec4        u_Tint;
        uniform     sampler2D   u_Sampler;
        uniform     sampler2D   u_LightSampler;
        vec3 getLightColor() {
          if (v_LightColor.z != -1.0) return v_LightColor;
          return texture2D(u_LightSampler, v_LightColor.xy).rgb;
        }
        void main() {
          if (u_Mode == 0) {
            // 颜色模式:指定颜色
            float alpha = texture2D(u_Sampler, v_TexCoord).a;
            gl_FragColor.a = alpha * v_Color.a * u_Alpha;
            if (gl_FragColor.a == 0.0) discard;
            gl_FragColor.rgb = v_Color.rgb;
          } else if (u_Mode == 1) {
            // 颜色模式:纹理采样 + 色调
            gl_FragColor = texture2D(u_Sampler, v_TexCoord);
            gl_FragColor.a *= v_Color.a * u_Alpha;
            if (gl_FragColor.a == 0.0) discard;
            gl_FragColor.rgb = gl_FragColor.rgb * (1.0 - u_Tint.a) + u_Tint.rgb +
            dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114)) * u_Tint.a;
          }
          gl_FragColor.rgb *= getLightColor();
        }
        `,
      ) as WebGLParticleProgram
      this.useProgram(program)
      // 顶点着色器属性
      const a_Position = this.getAttribLocation(program, 'a_Position')
      const a_TexCoord = this.getAttribLocation(program, 'a_TexCoord')
      const a_Color = this.getAttribLocation(program, 'a_Color')
      const u_Flip = this.getUniformLocation(program, 'u_Flip')!
      const u_Matrix = this.getUniformLocation(program, 'u_Matrix')!
      const u_Ambient = this.getUniformLocation(program, 'u_Ambient')!
      const u_LightMode = this.getUniformLocation(program, 'u_LightMode')!
      const u_LightTexSize = this.getUniformLocation(program, 'u_LightTexSize')!
      this.uniform1i(this.getUniformLocation(program, 'u_LightSampler'), this.maxTexUnits - 1)
      // 片元着色器属性
      const u_Alpha = this.getUniformLocation(program, 'u_Alpha')!
      const u_Mode = this.getUniformLocation(program, 'u_Mode')!
      const u_Tint = this.getUniformLocation(program, 'u_Tint')!
      // 创建顶点数组对象
      const vao = this.createVertexArray()!
      this.bindVertexArray(vao)
      this.enableVertexAttribArray(a_Position)
      this.enableVertexAttribArray(a_TexCoord)
      this.enableVertexAttribArray(a_Color)
      this.bindBuffer(this.ARRAY_BUFFER, this.vertexBuffer)
      this.vertexAttribPointer(a_Position, 2, this.FLOAT, false, 20, 0)
      this.vertexAttribPointer(a_TexCoord, 2, this.FLOAT, false, 20, 8)
      this.vertexAttribPointer(a_Color, 4, this.UNSIGNED_BYTE, true, 20, 16)
      this.bindBuffer(this.ELEMENT_ARRAY_BUFFER, this.elementBuffer)
      // 使用程序对象
      const use = () => {
        if (this.program !== program) {
          this.program = program
          this.useProgram(program)
        }
        if (program.flip !== this.flip) {
          program.flip = this.flip
          this.uniform1f(u_Flip, program.flip)
        }
        if (program.alpha !== this.alpha) {
          program.alpha = this.alpha
          this.uniform1f(u_Alpha, program.alpha)
        }
        this.updateBlending()
        return program
      }
      // 保存程序对象
      program.use = use
      program.vao = vao
      program.flip = 0
      program.alpha = 0
      program.a_Position = a_Position
      program.a_TexCoord = a_TexCoord
      program.a_Color = a_Color
      program.u_Matrix = u_Matrix
      program.u_Ambient = u_Ambient
      program.u_LightMode = u_LightMode
      program.u_LightTexSize = u_LightTexSize
      program.u_Mode = u_Mode
      program.u_Tint = u_Tint
      return program
    }
    // WebGL上下文方法 - 创建光源程序
    GL.createLightProgram = function (): WebGLLightProgram {
      const program = this.createProgramWithShaders(
        `
        attribute   vec2        a_Position;
        attribute   vec2        a_LightCoord;
        attribute   vec4        a_LightColor;
        uniform     mat3        u_Matrix;
        varying     vec2        v_LightCoord;
        varying     vec4        v_LightColor;
        void main() {
          gl_Position.xyw = u_Matrix * vec3(a_Position, 1.0);
          v_LightCoord = a_LightCoord;
          v_LightColor = a_LightColor;
        }
        `,
        `
        precision   highp       float;
        const       float       PI = 3.1415926536;
        varying     vec2        v_LightCoord;
        varying     vec4        v_LightColor;
        uniform     int         u_LightMode;
        uniform     sampler2D   u_LightSampler;
        // 获取光照颜色
        vec3 getLightColor() {
          if (u_LightMode == 0) {
            // 光照模式:点光源
            float dist = length(vec2(
              (v_LightCoord.x - 0.5),
              (v_LightCoord.y - 0.5)
            ));
            // 放弃圆形外面像素
            if (dist > 0.5) discard;
            // 根据距离和强度来计算光照颜色系数
            float angle = dist * PI;
            float factor = mix(1.0 - sin(angle), cos(angle), v_LightColor.a);
            return v_LightColor.rgb * factor;
          }
          if (u_LightMode == 1) {
            // 光照模式:区域光源
            vec4 lightColor = texture2D(u_LightSampler, v_LightCoord);
            if (lightColor.a == 0.0) discard;
            // 从纹理中采样颜色,与光照颜色相乘
            return v_LightColor.rgb * lightColor.rgb * lightColor.a;
          }
          if (u_LightMode == 2) {
            // 光照模式:区域光源(无纹理)
            return v_LightColor.rgb;
          }
        }
        void main() {
          gl_FragColor = vec4(getLightColor(), 1.0);
        }
        `,
      ) as WebGLLightProgram
      this.useProgram(program)
      // u_LightSampler绑定的0号纹理绘制的时候不是必须的
      // 如果纹理已被删除,部分Android Web控制台输出错误警告
      // 顶点着色器属性
      const a_Position = this.getAttribLocation(program, 'a_Position')
      const a_LightCoord = this.getAttribLocation(program, 'a_LightCoord')
      const a_LightColor = this.getAttribLocation(program, 'a_LightColor')
      const u_Matrix = this.getUniformLocation(program, 'u_Matrix')!
      // 片元着色器属性
      const u_LightMode = this.getUniformLocation(program, 'u_LightMode')!
      // 创建顶点数组对象
      const vao = this.createVertexArray() as WebGLVertexArrayObjectLight
      this.bindVertexArray(vao)
      this.enableVertexAttribArray(a_Position)
      this.enableVertexAttribArray(a_LightCoord)
      this.enableVertexAttribArray(a_LightColor)
      this.bindBuffer(this.ARRAY_BUFFER, this.vertexBuffer)
      this.vertexAttribPointer(a_Position, 2, this.FLOAT, false, 32, 0)
      this.vertexAttribPointer(a_LightCoord, 2, this.FLOAT, false, 32, 8)
      this.vertexAttribPointer(a_LightColor, 4, this.FLOAT, false, 32, 16)
      this.bindBuffer(this.ELEMENT_ARRAY_BUFFER, this.elementBuffer)
      // 创建顶点数组对象 - 属性[110]
      vao.a110 = this.createVertexArray()!
      this.bindVertexArray(vao.a110)
      this.enableVertexAttribArray(a_Position)
      this.enableVertexAttribArray(a_LightCoord)
      this.bindBuffer(this.ARRAY_BUFFER, this.vertexBuffer)
      this.vertexAttribPointer(a_Position, 2, this.FLOAT, false, 16, 0)
      this.vertexAttribPointer(a_LightCoord, 2, this.FLOAT, false, 16, 8)
      this.bindBuffer(this.ELEMENT_ARRAY_BUFFER, this.elementBuffer)
      // 使用程序对象
      const use = () => {
        if (this.program !== program) {
          this.program = program
          this.useProgram(program)
        }
        this.updateBlending()
        return program
      }
      // 保存程序对象
      program.use = use
      program.vao = vao
      program.a_Position = a_Position
      program.a_LightCoord = a_LightCoord
      program.a_LightColor = a_LightColor
      program.u_Matrix = u_Matrix
      program.u_LightMode = u_LightMode
      return program
    }
    // WebGL上下文方法 - 创建图形程序
    GL.createGraphicProgram = function (): WebGLGraphicProgram {
      const program = this.createProgramWithShaders(
        `
        attribute   vec2        a_Position;
        attribute   vec4        a_Color;
        uniform     mat3        u_Matrix;
        varying     vec4        v_Color;
        void main() {
          gl_Position.xyw = u_Matrix * vec3(a_Position, 1.0);
          v_Color = a_Color;
        }
        `,
        `
        precision   highp       float;
        varying     vec4        v_Color;
        uniform     float       u_Alpha;
        void main() {
          gl_FragColor.rgb = v_Color.rgb;
          gl_FragColor.a = v_Color.a * u_Alpha;
        }
        `,
      ) as WebGLGraphicProgram
      this.useProgram(program)
      // 顶点着色器属性
      const a_Position = this.getAttribLocation(program, 'a_Position')
      const a_Color = this.getAttribLocation(program, 'a_Color')
      const u_Matrix = this.getUniformLocation(program, 'u_Matrix')!
      // 片元着色器属性
      const u_Alpha = this.getUniformLocation(program, 'u_Alpha')!
      // 创建顶点数组对象
      const vao = this.createVertexArray() as WebGLVertexArrayObjectGraphic
      this.bindVertexArray(vao)
      this.enableVertexAttribArray(a_Position)
      this.enableVertexAttribArray(a_Color)
      this.bindBuffer(this.ARRAY_BUFFER, this.vertexBuffer)
      this.vertexAttribPointer(a_Position, 2, this.FLOAT, false, 12, 0)
      this.vertexAttribPointer(a_Color, 4, this.UNSIGNED_BYTE, true, 12, 8)
      this.bindBuffer(this.ELEMENT_ARRAY_BUFFER, this.elementBuffer)
      // 创建顶点数组对象 - 属性[10]
      vao.a10 = this.createVertexArray()!
      this.bindVertexArray(vao.a10)
      this.enableVertexAttribArray(a_Position)
      this.bindBuffer(this.ARRAY_BUFFER, this.vertexBuffer)
      this.vertexAttribPointer(a_Position, 2, this.FLOAT, false, 0, 0)
      this.bindBuffer(this.ELEMENT_ARRAY_BUFFER, this.elementBuffer)
      // 使用程序对象
      const use = () => {
        if (this.program !== program) {
          this.program = program
          this.useProgram(program)
        }
        if (program.alpha !== this.alpha) {
          program.alpha = this.alpha
          this.uniform1f(u_Alpha, program.alpha)
        }
        this.updateBlending()
        return program
      }
      // 保存程序对象
      program.use = use
      program.vao = vao
      program.alpha = 0
      program.a_Position = a_Position
      program.a_Color = a_Color
      program.u_Matrix = u_Matrix
      return program
    }
    // WebGL上下文方法 - 重置状态
    GL.reset = function (): void {
      this.blend = 'normal'
      this.alpha = 1
      this.matrix.reset()
    }
    // WebGL上下文方法 - 创建混合模式更新器
    GL.createBlendingUpdater = function () {
      // 开启混合功能
      this.enable(this.BLEND)
      // 更新器映射表(启用混合时)
      const A = {
        // 正常模式
        normal: () => {
          this.blendEquation(this.FUNC_ADD)
          this.blendFuncSeparate(this.SRC_ALPHA, this.ONE_MINUS_SRC_ALPHA, this.ONE, this.ZERO)
        },
        // 滤色模式
        screen: () => {
          this.blendEquation(this.FUNC_ADD)
          this.blendFunc(this.ONE, this.ONE_MINUS_SRC_COLOR)
        },
        // 加法模式
        additive: () => {
          this.blendEquation(this.FUNC_ADD)
          this.blendFuncSeparate(this.SRC_ALPHA, this.DST_ALPHA, this.ONE, this.ZERO)
        },
        // 减法模式
        subtract: () => {
          this.blendEquation(this.FUNC_REVERSE_SUBTRACT)
          this.blendFuncSeparate(this.SRC_ALPHA, this.DST_ALPHA, this.ONE, this.ZERO)
        },
        // 最大值模式
        max: () => {
          this.blendEquation(this.MAX)
        },
        // 复制模式
        copy: () => {
          // 关闭混合功能,切换到B组更新器
          this.disable(this.BLEND)
          updaters = B
        },
      }
      // 从复制模式切换到其他模式
      const resume = (): void => {
        // 开启混合功能,切换到A组更新器
        (updaters = A)[blend]()
        this.enable(this.BLEND)
      }
      // 更新器映射表(禁用混合时)
      const B = {
        normal: resume,
        screen: resume,
        additive: resume,
        subtract: resume,
        max: resume,
        copy: Function.empty,
      }
      let updaters = A
      let blend = '' as BlendingMode
      // 返回更新混合模式方法
      return () => {
        if (blend !== this.blend) {
          updaters[blend = this.blend]()
        }
      }
    }
    // WebGL上下文方法 - 设置环境光
    GL.setAmbientLight = function (light: GLAmbientLight): void {
      const ambient = this.ambient
      if (ambient.red !== light.red ||
        ambient.green !== light.green ||
        ambient.blue !== light.blue) {
        ambient.red = light.red
        ambient.green = light.green
        ambient.blue = light.blue
        const program = this.program
        const r = ambient.red / 255
        const g = ambient.green / 255
        const b = ambient.blue / 255
        // 更新以下GL程序的环境光变量
        for (const program of [
          this.imageProgram,
          this.tileProgram,
          this.particleProgram,
        ]) {
          this.useProgram(program)
          this.uniform3f(program.u_Ambient, r, g, b)
        }
        this.useProgram(program)
      }
    }
    // WebGL上下文方法 - 调整光影纹理
    GL.resizeLightMap = function (): void {
      const texture = this.reflectedLightMap
      const width = this.width
      const height = this.height
      if (texture.innerWidth !== width ||
        texture.innerHeight !== height) {
        texture.innerWidth = width
        texture.innerHeight = height
        if (texture.paddingLeft === undefined) {
          const {lightArea} = Data.config
          // 首次调用时计算光影纹理最大扩张值(4倍)
          texture.paddingLeft = Math.min(lightArea.expansionLeft * 4, 512)
          texture.paddingTop = Math.min(lightArea.expansionTop * 4, 512)
          texture.paddingRight = Math.min(lightArea.expansionRight * 4, 512)
          texture.paddingBottom = Math.min(lightArea.expansionBottom * 4, 512)
        }
        const pl = texture.paddingLeft
        const pt = texture.paddingTop
        const pr = texture.paddingRight
        const pb = texture.paddingBottom
        const tWidth = width + pl + pr
        const tHeight = height + pt + pb
        // 重置缩放率(将会重新计算纹理参数)
        texture.scale = 0
        texture.resize(tWidth, tHeight)
        this.bindTexture(this.TEXTURE_2D, null)
        this.updateLightTexSize()
      }
    }
    // WebGL上下文方法 - 更新光照纹理大小
    GL.updateLightTexSize = function (): void {
      const texture = this.reflectedLightMap
      if (texture.width === 0) return
      const width = this.drawingBufferWidth
      const height = this.drawingBufferHeight
      const sizeX = texture.width / width * 2
      const sizeY = texture.height / height * 2
      const centerX = (texture.paddingLeft + width / 2) / texture.width
      const centerY = (texture.paddingTop + height / 2) / texture.height
      const program = this.program
      // 更新以下GL程序的光照纹理参数
      for (const program of [
        this.imageProgram,
        this.tileProgram,
        this.spriteProgram,
        this.particleProgram,
      ]) {
        this.useProgram(program)
        this.uniform4f(program.u_LightTexSize, sizeX, sizeY, centerX, centerY)
      }
      this.useProgram(program)
    }
    // WebGL上下文方法 - 更新纹理采样器数量
    GL.updateSamplerNum = function (samplerNum: number): void {
      // 在旧版的Chrome中,不重置过期的采样器索引会被警告,因此这个算法被保留了下来
      const program = this.program
      if ('samplerNum' in program) {
        const lastNum = program.samplerNum
        // 如果采样器数量发生了变化
        if (lastNum !== samplerNum) {
          const u_Samplers = program.u_Samplers
          if (lastNum < samplerNum) {
            // 如果采样器数量增多,设置新增的采样器索引
            for (let i = lastNum; i < samplerNum; i++) {
              this.uniform1i(u_Samplers[i], i)
            }
          } else {
            // 如果采样器数量减少,重置过期的采样器索引
            for (let i = samplerNum; i < lastNum; i++) {
              this.uniform1i(u_Samplers[i], 0)
            }
          }
          program.samplerNum = samplerNum
        }
      }
    }
    // WebGL上下文方法 - 绑定帧缓冲对象
    GL.bindFBO = function (fbo: WebGLFramebuffer): void {
      this.binding = fbo
      this.flip = 1
      this.bindFramebuffer(this.FRAMEBUFFER, fbo)
    }
    // WebGL上下文方法 - 解除帧缓冲对象的绑定
    GL.unbindFBO = function (): void {
      this.binding = null
      this.flip = -1
      this.bindFramebuffer(this.FRAMEBUFFER, null)
    }
    // 设置视口大小(单位:像素)
    GL.setViewport = function (x: number, y: number, width: number, height: number): void {
      this.width = width
      this.height = height
      this.viewport(x, y, width, height)
    }
    // 重置视口大小
    GL.resetViewport = function () {
      const width = this.drawingBufferWidth
      const height = this.drawingBufferHeight
      this.width = width
      this.height = height
      this.viewport(0, 0, width, height)
    }
    /** WebGL上下文方法 - 激活离屏渲染 */
    GL.enableOffscreen = function enableOffscreen() {
      const {unbindFBO, resetViewport} = GL
      // 离屏模式 - 解除帧缓冲对象的绑定
      function offscreenUnbindFBO(this: typeof GL) {
        this.binding = null
        this.flip = 1
        // 重新绑定到当前离屏纹理的FBO
        this.bindFramebuffer(this.FRAMEBUFFER, this.offscreen.current.fbo)
      }
      // 离屏模式 - 重置窗口大小
      function offscreenResetViewport(this: typeof GL) {
        const base = this.offscreen.current.base
        const width = base.width
        const height = base.height
        this.width = width
        this.height = height
        // 将视口设为当前离屏纹理的大小
        this.viewport(0, 0, width, height)
      }
      return function (this: typeof GL, enabled: boolean): void {
        const offscreen = this.offscreen
        if (offscreen.enabled !== enabled) {
          offscreen.enabled = enabled
          if (enabled) {
            // 如果启用,调整当前离屏纹理大小
            const texture = offscreen.current
            const width = this.drawingBufferWidth
            const height = this.drawingBufferHeight
            if (texture.base.width !== width ||
              texture.base.height !== height) {
              texture.resize(width, height)
            }
            // 替换成离屏渲染模式下的特定方法
            this.unbindFBO = offscreenUnbindFBO
            this.resetViewport = offscreenResetViewport
          } else {
            // 如果禁用,恢复默认的方法
            this.unbindFBO = unbindFBO
            this.resetViewport = resetViewport
          }
          this.unbindFBO()
        }
      }
    }()
    // WebGL上下文方法 - 切换离屏纹理
    GL.switchOffscreen = function (): void {
      const offscreen = this.offscreen
      // 如果启用了离屏渲染
      if (offscreen.enabled) {
        const texture = offscreen.last
        const width = this.drawingBufferWidth
        const height = this.drawingBufferHeight
        // 获取上次离屏纹理,并调整大小
        if (texture.base.width !== width ||
          texture.base.height !== height) {
          texture.resize(width, height)
        }
        // 交换上次和当前的离屏纹理
        offscreen.last = offscreen.current
        offscreen.current = texture
        // 绑定当前离屏纹理的FBO(offscreenUnbindFBO)
        this.unbindFBO()
      }
    }
    // WebGL上下文方法 - 调整画布大小
    GL.resize = function (width: number, height: number): void {
      const canvas = this.canvas
      // 尽量少的画布缓冲区重置次数
      if (canvas.width !== width) {
        canvas.width = width
      }
      if (canvas.height !== height) {
        canvas.height = height
      }
      if (this.width !== width ||
        this.height !== height) {
        // 更新画布大小参数和视口
        this.width = width
        this.height = height
        this.viewport(0, 0, width, height)
        this.maskTexture.resize(width, height)
        this.directLightMap.resize(width, height)
      }
      // 调整光影纹理
      this.resizeLightMap()
    }
    namespace: {
    const defTint: ImageTint = [0, 0, 0, 0]
    // WebGL上下文方法 - 绘制图像
    GL.drawImage = function (texture: Texture, dx: number, dy: number, dw: number, dh: number, tint: ImageTint = defTint): void {
      if (!texture.complete) return
      const program = this.imageProgram.use()
      const vertices = this.arrays[0].float32
      const base = texture.base
      const sx = texture.x
      const sy = texture.y
      const sw = texture.width
      const sh = texture.height
      const tw = base.width
      const th = base.height
      // 计算变换矩阵
      const matrix = Matrix.instance.project(
        this.flip,
        this.width,
        this.height,
      ).multiply(this.matrix)
      // 计算顶点数据
      const dl = dx + 0.004
      const dt = dy + 0.004
      const dr = dl + dw
      const db = dt + dh
      const sl = sx / tw
      const st = sy / th
      const sr = (sx + sw) / tw
      const sb = (sy + sh) / th
      vertices[0] = dl
      vertices[1] = dt
      vertices[2] = sl
      vertices[3] = st
      vertices[4] = dl
      vertices[5] = db
      vertices[6] = sl
      vertices[7] = sb
      vertices[8] = dr
      vertices[9] = db
      vertices[10] = sr
      vertices[11] = sb
      vertices[12] = dr
      vertices[13] = dt
      vertices[14] = sr
      vertices[15] = st
      // 色调归一化
      const red = tint[0] / 255
      const green = tint[1] / 255
      const blue = tint[2] / 255
      const gray = tint[3] / 255
      // 绘制图像
      this.bindVertexArray(program.vao.a110)
      this.vertexAttrib1f(program.a_Opacity, 1)
      this.uniformMatrix3fv(program.u_Matrix, false, matrix)
      this.uniform1i(program.u_LightMode, 0)
      this.uniform1i(program.u_ColorMode, 0)
      this.uniform4f(program.u_Tint, red, green, blue, gray)
      this.bufferData(this.ARRAY_BUFFER, vertices, this.STREAM_DRAW, 0, 16)
      this.bindTexture(this.TEXTURE_2D, base.glTexture)
      this.drawArrays(this.TRIANGLE_FAN, 0, 4)
    }
    }
    // WebGL上下文方法 - 绘制指定颜色的图像
    GL.drawImageWithColor = function (texture: Texture, dx: number, dy: number, dw: number, dh: number, color: number): void {
      if (!texture.complete) return
      const program = this.imageProgram.use()
      const vertices = this.arrays[0].float32
      const base = texture.base
      const sx = texture.x
      const sy = texture.y
      const sw = texture.width
      const sh = texture.height
      const tw = base.width
      const th = base.height
      // 计算变换矩阵
      const matrix = Matrix.instance.project(
        this.flip,
        this.width,
        this.height,
      ).multiply(this.matrix)
      // 计算顶点数据
      const dl = dx + 0.004
      const dt = dy + 0.004
      const dr = dl + dw
      const db = dt + dh
      const sl = sx / tw
      const st = sy / th
      const sr = (sx + sw) / tw
      const sb = (sy + sh) / th
      vertices[0] = dl
      vertices[1] = dt
      vertices[2] = sl
      vertices[3] = st
      vertices[4] = dl
      vertices[5] = db
      vertices[6] = sl
      vertices[7] = sb
      vertices[8] = dr
      vertices[9] = db
      vertices[10] = sr
      vertices[11] = sb
      vertices[12] = dr
      vertices[13] = dt
      vertices[14] = sr
      vertices[15] = st
      // 色调归一化
      const red = (color & 0xff) / 255
      const green = (color >> 8 & 0xff) / 255
      const blue = (color >> 16 & 0xff) / 255
      const gray = (color >> 24 & 0xff) / 255
      // 绘制图像
      this.bindVertexArray(program.vao.a110)
      this.vertexAttrib1f(program.a_Opacity, 1)
      this.uniformMatrix3fv(program.u_Matrix, false, matrix)
      this.uniform1i(program.u_LightMode, 0)
      this.uniform1i(program.u_ColorMode, 1)
      this.uniform4f(program.u_Color, red, green, blue, gray)
      this.bufferData(this.ARRAY_BUFFER, vertices, this.STREAM_DRAW, 0, 16)
      this.bindTexture(this.TEXTURE_2D, base.glTexture)
      this.drawArrays(this.TRIANGLE_FAN, 0, 4)
    }
    // WebGL上下文方法 - 绘制切片图像
    GL.drawSliceImage = function (texture: ImageTexture, dx: number, dy: number, dw: number, dh: number, clip: ImageClip, border: number, tint: ImageTint): void {
      if (!texture.complete) return
      // 计算变换矩阵
      const matrix = Matrix.instance.project(
        this.flip,
        this.width,
        this.height,
      ).multiply(this.matrix)
      .translate(dx + 0.004, dy + 0.004)
      // 更新切片数据
      const sliceClip = texture.sliceClip!
      if (texture.sliceWidth !== dw ||
        texture.sliceHeight !== dh ||
        sliceClip[0] !== clip[0] ||
        sliceClip[1] !== clip[1] ||
        sliceClip[2] !== clip[2] ||
        sliceClip[3] !== clip[3] ||
        texture.sliceBorder !== border) {
        texture.updateSliceData(dw, dh, clip, border)
      }
      // 色调归一化
      const red = tint[0] / 255
      const green = tint[1] / 255
      const blue = tint[2] / 255
      const gray = tint[3] / 255
      // 上传数据
      const program = this.imageProgram.use()
      const vertices = texture.sliceVertices!
      const thresholds = texture.sliceThresholds!
      const count = texture.sliceCount!
      this.bindVertexArray(program.vao.a110)
      this.vertexAttrib1f(program.a_Opacity, 1)
      this.uniformMatrix3fv(program.u_Matrix, false, matrix)
      this.uniform1i(program.u_LightMode, 0)
      this.uniform1i(program.u_ColorMode, 2)
      this.uniform4f(program.u_Tint, red, green, blue, gray)
      this.bufferData(this.ARRAY_BUFFER, vertices, this.STREAM_DRAW, 0, count * 16)
      this.bindTexture(this.TEXTURE_2D, texture.base.glTexture)
      // 绘制切片
      for (let i = 0; i < count; i++) {
        const ti = i * 4
        const x = thresholds[ti]
        const y = thresholds[ti + 1]
        const w = thresholds[ti + 2]
        const h = thresholds[ti + 3]
        this.uniform4f(program.u_Repeat, x, y, w, h)
        this.drawArrays(this.TRIANGLE_FAN, i * 4, 4)
      }
    }
    // WebGL上下文方法 - 填充矩形
    GL.fillRect = function (dx: number, dy: number, dw: number, dh: number, color: number): void {
      const program = this.graphicProgram.use()
      const vertices = this.arrays[0].float32
      const colors = this.arrays[0].uint32
      // 计算变换矩阵
      const matrix = Matrix.instance.project(
        this.flip,
        this.width,
        this.height,
      ).multiply(this.matrix)
      // 计算顶点数据
      const dl = dx
      const dt = dy
      const dr = dx + dw
      const db = dy + dh
      vertices[0] = dl
      vertices[1] = dt
      colors  [2] = color
      vertices[3] = dl
      vertices[4] = db
      colors  [5] = color
      vertices[6] = dr
      vertices[7] = db
      colors  [8] = color
      vertices[9] = dr
      vertices[10] = dt
      colors  [11] = color
      // 绘制图像
      this.bindVertexArray(program.vao)
      this.uniformMatrix3fv(program.u_Matrix, false, matrix)
      this.bufferData(this.ARRAY_BUFFER, vertices, this.STREAM_DRAW, 0, 12)
      this.drawArrays(this.TRIANGLE_FAN, 0, 4)
    }
    // WebGL上下文方法 - 创建普通纹理
    GL.createNormalTexture = function (options: NormalTextureOptions = {}): BaseTexture {
      const texture = new BaseTexture(options)
      this.textureManager.append(texture)
      return texture
    }
    // WebGL上下文方法 - 创建图像纹理
    GL.createImageTexture = function (image: string | HTMLImageElement, options: ImageTextureOptions = {}): BaseTexture {
      const guid = image instanceof Image ? image.guid : image
      const manager = this.textureManager
      let texture = manager.images[guid]
      if (!texture) {
        texture = new BaseTexture(options)
        texture.guid = guid
        manager.append(texture)
        manager.images[guid] = texture
        const initialize = (image: HTMLImageElement) => {
          // 如果纹理还在管理器中,并且加载图像成功
          if (manager.images[guid] === texture && image) {
            texture!.width = Math.min(image.naturalWidth, this.maxTexSize)
            texture!.height = Math.min(image.naturalHeight, this.maxTexSize)
            // 上传RGBA格式的图像数据到纹理
            this.bindTexture(this.TEXTURE_2D, texture!.glTexture)
            this.texImage2D(this.TEXTURE_2D, 0, texture!.format, texture!.width, texture!.height, 0, texture!.format, this.UNSIGNED_BYTE, image)
            // 执行纹理已加载回调
            texture!.reply('load')
          } else {
            // 执行纹理加载错误回调
            texture!.reply('error')
          }
        }
        if (image instanceof HTMLImageElement) {
          initialize(image)
        } else {
          const image = Loader.getImage({guid})
          if (image instanceof HTMLImageElement) {
            initialize(image)
          } else {
            Loader.loadImage({guid}).then(initialize)
          }
        }
      }
      return texture.increaseRefCount()
    }
    // WebGL上下文方法 - 创建纹理帧缓冲对象
    GL.createTextureFBO = function (texture: FBOTexture): WebGLFramebuffer {
      const fbo = this.createFramebuffer()
      if (!fbo) {
        throw new Error('Failed to create frameBuffer')
      }
      // 创建深度模板缓冲区
      texture.depthStencilBuffer = this.createRenderbuffer()
      // 重写纹理方法 - 调整大小
      texture.resize = (width: number, height: number): FBOTexture => {
        Texture.prototype.resize.call(texture, width, height)
        this.bindFramebuffer(this.FRAMEBUFFER, fbo)
        // 绑定纹理到颜色缓冲区
        this.framebufferTexture2D(this.FRAMEBUFFER, this.COLOR_ATTACHMENT0, this.TEXTURE_2D, texture.base.glTexture, 0)
        // 调整深度模板缓冲区大小
        this.bindRenderbuffer(this.RENDERBUFFER, texture.depthStencilBuffer)
        this.framebufferRenderbuffer(this.FRAMEBUFFER, this.DEPTH_STENCIL_ATTACHMENT, this.RENDERBUFFER, texture.depthStencilBuffer)
        this.renderbufferStorage(this.RENDERBUFFER, this.DEPTH_STENCIL, width, height)
        this.bindRenderbuffer(this.RENDERBUFFER, null)
        this.bindFramebuffer(this.FRAMEBUFFER, null)
        return texture
      }
      texture.resize(texture.base.width, texture.base.height)
      return fbo
    }
    // 扩展方法 - 擦除画布
    CanvasRenderingContext2D.prototype.clear = function (): void {
      this.clearRect(0, 0, this.canvas.width, this.canvas.height)
    }
    // 扩展方法 - 调整画布大小
    CanvasRenderingContext2D.prototype.resize = function (width: number, height: number): void {
      const canvas = this.canvas
      if (canvas.width === width &&
        canvas.height === height) {
        // 宽高不变时重置画布
        canvas.width = width
      } else {
        // 尽量少的画布缓冲区重置次数
        if (canvas.width !== width) {
          canvas.width = width
        }
        if (canvas.height !== height) {
          canvas.height = height
        }
      }
    }
  }
文档生成时间:2025/7/21 20:53:39