import { fillRectangle} from "./2d"
import { LayerAB, Scene } from "./Scene"
import { createProgram, createShader } from "./utils"




export class TextureLayer extends LayerAB {


  private vertexShaderCode = /*glsl*/ `
    attribute vec2 a_position;
    attribute vec2 a_texCoord;
    uniform mat4 u_matrix;
    varying vec2 v_texCoord;

    void main() {
      gl_Position = u_matrix * vec4(a_position, 0, 1);
      v_texCoord = a_texCoord;
    }

  `;

  private fragmentShaderCode = /*glsl*/ `
    precision mediump float;
    uniform sampler2D u_image;
    varying vec2 v_texCoord;

    void main() {
      vec4 color = texture2D(u_image, v_texCoord);
      gl_FragColor = color;
    }
  
  `



  program: WebGLProgram


  aPositionLoc: number
  aTexcoordLoc: number
  uMatrixLoc: WebGLUniformLocation
  uScaleLoc: WebGLUniformLocation
  uTexSizeLoc: WebGLUniformLocation

  vertexBuffer: WebGLBuffer
  texcoordBuffer: WebGLBuffer

  vertexArray = new Float32Array(12)
  texCoordArray = new Float32Array(12)

  dispose() {
    let gl = this.scene.gl
    gl.deleteProgram(this.program)
    gl.deleteTexture(this.texture)
    gl.deleteBuffer(this.texcoordBuffer)
    gl.deleteBuffer(this.vertexBuffer)
  }

  constructor(
    public readonly scene: Scene,
    private texture : WebGLTexture, 
    public readonly texWidth: number, 
    public readonly texHeight: number, 
    public readonly width : number, 
    public readonly height : number, 
    private fragmentShader: string | null = null
  ) {
    super()

    const gl = scene.gl;


    this.program = createProgram(gl,
      createShader(gl, gl.VERTEX_SHADER, this.vertexShaderCode)!,
      createShader(gl, gl.FRAGMENT_SHADER, fragmentShader || this.fragmentShaderCode)!)!

    this.aPositionLoc = gl.getAttribLocation(this.program, "a_position")
    this.aTexcoordLoc = gl.getAttribLocation(this.program, "a_texCoord")
    this.uMatrixLoc = gl.getUniformLocation(this.program, "u_matrix")!
    this.uScaleLoc = gl.getUniformLocation(this.program, "u_scale")!
    this.uTexSizeLoc = gl.getUniformLocation(this.program, "u_texSize")!


    fillRectangle(this.vertexArray, 0, 0, 0, width, height )
    fillRectangle(this.texCoordArray, 0, 0, 0, 1, 1)


    this.vertexBuffer = gl.createBuffer()!;
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, this.vertexArray, gl.STATIC_DRAW);


    this.texcoordBuffer = gl.createBuffer()!;
    gl.bindBuffer(gl.ARRAY_BUFFER, this.texcoordBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, this.texCoordArray, gl.STATIC_DRAW);

  }


  get currentScale() : number {
    return this.scene.userMat[0] * (this.width / this.texWidth)
  }


  override draw() {
    const gl = this.scene.gl;
    gl.useProgram(this.program);

    gl.enableVertexAttribArray(this.aPositionLoc);
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
    gl.vertexAttribPointer(this.aPositionLoc, 2, gl.FLOAT, false, 0, 0)

    gl.enableVertexAttribArray(this.aTexcoordLoc);
    gl.bindBuffer(gl.ARRAY_BUFFER, this.texcoordBuffer);
    gl.vertexAttribPointer(this.aTexcoordLoc, 2, gl.FLOAT, false, 0, 0)

    gl.uniformMatrix4fv(this.uMatrixLoc, false, this.scene.drawMatrix)

    gl.uniform1f(this.uScaleLoc, this.currentScale)
    gl.uniform2f(this.uTexSizeLoc, 1. / this.texWidth, 1. / this.texHeight)


    gl.activeTexture(gl.TEXTURE0)
    gl.bindTexture(gl.TEXTURE_2D, this.texture)

    gl.drawArrays(gl.TRIANGLES, 0, 6);

  }


  override scale(scale: number): void {
    //console.log(`scale=${scale}`)
  }

  toString(): string {
    return `TextureLayer()`
  }

}




