import ObjectRenderer from "../2d/renderers/webgl/ObjectRenderer";
import { GLShader, GLBuffer, VertexArrayObject } from "../glCore";
import { WebglRenderer } from "../2d/renderers/WebglRenderer";
import { Mesh } from "../2d/mesh";
import { hex2rgb } from "../2d/utils";

export class SpineMesh extends Mesh {
    _renderWebGL(renderer: WebglRenderer) {
        //刷一次
        this.refresh();
        var renderObj = renderer.plugins["spineMesh"];
        if (!renderObj) return;
        renderer.batchManager.setObjectRenderer(renderObj);
        renderObj.render(this);
    }
    _glVaoBuffer: {
        [key: number]: {
            indexBuffer?: GLBuffer,
            posBuffer?: GLBuffer,
            uvBuffer?: GLBuffer,
            vao?: VertexArrayObject //不需要按照着色器区分，因为就一个
        }
    } = {}
}

const vs =
    // "precision highp float;" +
    "attribute vec2 aPosition;" +//位置坐标
    "attribute vec2 aTextureCoord;" +//uv

    "uniform mat3 projectionMatrix;" +//投影矩阵
    "uniform mat3 modelMatrix;" +//mesh全局矩阵

    "varying vec2 vTextureCoord;" +

    "void main(void){" +
    "gl_Position = vec4((projectionMatrix *modelMatrix* vec3(aPosition, 1.0)).xy, 0.0, 1.0);" +
    "vTextureCoord = aTextureCoord;" +
    "}";
//片元着色器程序
const fs = [
    'precision mediump float;',
    'varying vec2 vTextureCoord;',
    'uniform sampler2D uMap;',
    'uniform vec3 uColor;',
    'uniform float uAlpha;',
    'void main(void){',
    "   vec4 color = vec4( uColor, uAlpha );",
    '   gl_FragColor =color * texture2D(uMap, vTextureCoord);',
    '}',
].join('\n');
/**
 * 顶点数量太大时js计算顶点世界坐标性能消耗大，所以考虑传矩阵和原始顶点，着色器里面计算
 * 这个废弃了，最终发现是骨骼的js计算影响了网格性能，和原来批处理无关，
 * TODO所以最终要处理的是骨骼的计算，到时处理吧，为啥用官网的方式显示有问题，不用官网的以后约束不好扩展
 */
export class SpineMeshRenderer extends ObjectRenderer {
    shader: GLShader;
    onContextChange() {
        const gl = this.renderer.gl;
        //初始化使用的着色器和vao（放mesh）
        this.shader = new GLShader(gl, vs, fs);
    }
    start() {
        this.renderer.bindShader(this.shader);
    }
    stop() {
        //刷新
        this.flush();
    }
    //收集mesh
    private meshes: SpineMesh[] = []
    render(spineMesh: SpineMesh) {
        if (!spineMesh.texture || !spineMesh.texture.valid) return;
        this.meshes.push(spineMesh);
    }
    flush() {
        if (!this.meshes.length) return;
        const gl = this.renderer.gl;
        const attrs = this.shader.attributes;
        for (var i = 0; i < this.meshes.length; i++) {
            let mesh = this.meshes[i];
            //纹理
            this.shader.uniforms["uMap"] = this.renderer.textureManager.bindTexture(mesh.texture, undefined, false);
            //矩阵
            this.shader.uniforms["modelMatrix"] = mesh.worldMatrix.toArray(true);
            //颜色
            var color = hex2rgb(mesh.tint);
            this.shader.uniforms["uColor"] = color;
            //透明度
            this.shader.uniforms["uAlpha"] = mesh._worldAlpha;

            var glVaoBuffer = mesh._glVaoBuffer[this.renderer.CONTEXT_UID];
            if (!glVaoBuffer) {
                glVaoBuffer = mesh._glVaoBuffer[this.renderer.CONTEXT_UID] = {
                    indexBuffer: GLBuffer.createIndexBuffer(gl, null, gl.STATIC_DRAW),
                    uvBuffer: GLBuffer.createVertexBuffer(gl, null, gl.STATIC_DRAW),
                    posBuffer: GLBuffer.createVertexBuffer(gl, null, gl.STREAM_DRAW),
                }
                glVaoBuffer.vao = this.renderer.createVao()
                    //索引
                    .addIndex(glVaoBuffer.indexBuffer)
                    //顶点
                    .addAttribute(glVaoBuffer.posBuffer, attrs.aPosition, gl.FLOAT, false, 0, 0)
                    //uv
                    .addAttribute(glVaoBuffer.uvBuffer, attrs.aTextureCoord, gl.FLOAT, true, 0, 0)
                this.renderer.bindVao(glVaoBuffer.vao);
                //顶点位置
                glVaoBuffer.posBuffer.upload(mesh._vertices, 0, false);
                //uvs
                glVaoBuffer.uvBuffer.upload(mesh._uvs, 0, false);
                //索引
                glVaoBuffer.indexBuffer.upload(mesh._indices, 0, false);
            } else {
                this.renderer.bindVao(glVaoBuffer.vao);
                //顶点位置
                glVaoBuffer.posBuffer.upload(mesh._vertices, 0, false);
            }
            //绘制
            glVaoBuffer.vao.draw(gl.TRIANGLES);
        }
        //置空
        this.meshes.length = 0
    }
}

WebglRenderer.registerPlugin('spineMesh', SpineMeshRenderer);