import { Vector3 } from "./math/Vector3";
import { VertexArrayObject, GLBuffer, GLShader } from "../glCore";
import { HashObject } from "../2d/HashObject";
import { Vector2 } from "./math/Vector2";
import { BatchBuffer } from "../2d/renderers/webgl/BatchBuffer";
import { Box3 } from "./math/Box3";
import { Sphere } from "./math/Sphere";
import { Bone3D } from "./bones/Bone3D";



/**
 * 考虑需要记录哪些几何数据
 * 暂时都在构造中执行一次数据的赋值，如果以后涉及需要动态修改数据的，加标记修改，插件里也需要重新upload数据
 * 到时改成对象记录所有attribute。仿three，但是vao还会存在，但是会检查是否更新
 * 感觉东西越来越多，迟早得换成three的方式，到时还要考虑数据要修改的情况，否则做游戏蛋疼，现在不改是担心改了后性能出问题，
 */
export class Geometry extends HashObject {
    /**
     * 顶点坐标3，颜色3，uv2，法线3，到时还是搞成three的那种方式，多属性对象，统一放到vao上
     */
    _vertByteSize: number = (3 + 3 + 2 + 3) * 4;

    _vertices: Float32Array | number[];
    _colors: Float32Array | number[];
    _uvs: Float32Array | number[];
    _normals: Float32Array | number[];

    //记录上面四项数据是否修改了，自行赋值
    attrBufferNeedUpdate: boolean = false;

    _indices: Uint16Array | number[];

    //这两个是为了骨骼动画，都是vec4
    _skinWeight: Float32Array | number[];
    _skinIndex: Float32Array | number[];
    //可自行bind到Mesh，不一定挂在geo上
    bones: Bone3D[]


    boundingBox: Box3 = null;

    boundingSphere: Sphere = null;
    /**
     * 是否按面检测
     */
    doHitFace: boolean = false;
    /**
     * 为了不同渲染器上下文对应自己的vao，不管program吧，可能不同着色器程序，带的attr可能不一样，
     * 在3d的插件上处理
     * 建vao，添加attr属性
     * 激活绑定vao
     * 绑定buffer，
     * 上传buffer数据
     * 绘制
     * 
     */
    // _glVertexArrayObjects: { [key: number]: VertexArrayObject }
    _glVaoBuffer: { [key: number]: VaoBufferInt }

    /**
     * 记录顶点数据用，包括坐标，颜色，uv，法线
     */
    _attrBuffer: BatchBuffer;

    /**
     * 顶点变形数据数组
     */
    _morphPositions: Float32Array[] | number[][];
    /**
     * 法线变形数据数组
     */
    _morphNormals: Float32Array[] | number[][];
    /**
     * 
     * @param vertices 
     * @param indices 
     * @param normals 
     * @param colors 
     * @param uvs 
     */
    constructor(
        vertices: Float32Array | number[],
        indices?: Uint16Array | number[],
        normals?: Float32Array | number[],
        colors?: Float32Array | number[],
        uvs?: Float32Array | number[]
    ) {
        super();
        this._instanceType = "Geometry";
        this._glVaoBuffer = {};
        //_vertices，_normals，_colors，_uvs正常数字数组也行，反正会取出来放到_attrBuffer里
        this._vertices = vertices;
        this._normals = normals || new Float32Array(vertices.length);
        this._colors = colors || (() => {
            var f = new Float32Array(vertices.length);
            for (var i = 0; i < vertices.length; i++)f[i] = 1;
            return f;
        })()//new Float32Array(vertices.length).map(() => { return 1 });//不传就全是白色
        this._uvs = uvs || new Float32Array(vertices.length / 3 * 2);
        //索引直接用，可能没有，需要转成类型化数组，会直接upload
        this._indices = indices ? new Uint16Array(indices) : null;
        //顶点长度先记录，渲染时再加了，先去掉
        // this._attrBuffer = new BatchBuffer(vertices.length / 3 * this._vertByteSize);

    }
    computeBoundingBox() {

        if (!this.boundingBox) this.boundingBox = new Box3();

        var position = this._vertices;

        if (position) {
            this.boundingBox.setFromArray(position);
        } else {
            this.boundingBox.makeEmpty();
        }

        if (isNaN(this.boundingBox.min.x) || isNaN(this.boundingBox.min.y) || isNaN(this.boundingBox.min.z)) console.error("顶点数据有误")
    };

    computeBoundingSphere() {

        var box = new Box3();
        var vector = new Vector3();

        if (!this.boundingSphere) this.boundingSphere = new Sphere();

        var position = this._vertices;

        if (position) {
            var center = this.boundingSphere.center;
            box.setFromArray(position);
            box.getCenter(center);
            // hoping to find a boundingSphere with a radius smaller than the
            // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
            var maxRadiusSq = 0;
            for (var i = 0, il = position.length; i < il; i += 3) {
                vector.x = position[i];
                vector.y = position[i + 1];
                vector.z = position[i + 2];
                maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(vector));
            }
            this.boundingSphere.radius = Math.sqrt(maxRadiusSq);
            if (isNaN(this.boundingSphere.radius)) console.error("顶点数据有误")
        }
    };

    // copy(){

    // }
    // clone(){}


    destroy() {

    }
}

/**
 * 根据webglRendererId存一个，vao还需要根据着色器程序缓存
 */
export interface VaoBufferInt {
    /**
     * 索引
     */
    indexBuffer?: GLBuffer,
    /**
     * 顶点相关属性，位置，颜色，uv，法线
     */
    attrBuffer: GLBuffer,
    /**
     * 变形位置数据，数组，最大长度8
     */
    morphTargetBuffers?: GLBuffer[],
    /**
     * 变形法线数据，数组，最大长度4
     */
    morphNormalBuffers?: GLBuffer[],

    /**
     * 这两个buffer用于骨骼
     */
    skinWeightBuffer?: GLBuffer,
    skinIndexBuffer?: GLBuffer,
    /**
     * 需要根据着色器程序id作为指向，
     * 灯光重置过着色器，基本要重来一次，上面的buffer可以留着，重新addAttr到新的vao
     */
    vaos: { [key: string]: VertexArrayObject }
}


// var vertices = new Float32Array([
//     2.0, 2.0, 2.0, -2.0, 2.0, 2.0, -2.0, -2.0, 2.0, 2.0, -2.0, 2.0, // v0-v1-v2-v3 front
//     2.0, 2.0, 2.0, 2.0, -2.0, 2.0, 2.0, -2.0, -2.0, 2.0, 2.0, -2.0, // v0-v3-v4-v5 right
//     2.0, 2.0, 2.0, 2.0, 2.0, -2.0, -2.0, 2.0, -2.0, -2.0, 2.0, 2.0, // v0-v5-v6-v1 up
//     -2.0, 2.0, 2.0, -2.0, 2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0, 2.0, // v1-v6-v7-v2 left
//     -2.0, -2.0, -2.0, 2.0, -2.0, -2.0, 2.0, -2.0, 2.0, -2.0, -2.0, 2.0, // v7-v4-v3-v2 down
//     2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0, 2.0, -2.0, 2.0, 2.0, -2.0  // v4-v7-v6-v5 back
// ]);

// var colors = new Float32Array([    // Colors
//     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v0-v1-v2-v3 front
//     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v0-v3-v4-v5 right
//     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v0-v5-v6-v1 up
//     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v1-v6-v7-v2 left
//     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v7-v4-v3-v2 down
//     1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0　    // v4-v7-v6-v5 back
// ]);
// colors = colors.map(() => {
//     return 1
// })

// var normals = new Float32Array([    // Normal
//     0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,  // v0-v1-v2-v3 front
//     1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,  // v0-v3-v4-v5 right
//     0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,  // v0-v5-v6-v1 up
//     -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0,  // v1-v6-v7-v2 left
//     0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0,  // v7-v4-v3-v2 down
//     0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0   // v4-v7-v6-v5 back
// ]);

// var uvs = new Float32Array([
//     1.0, 1.0,
//     0.0, 1.0,
//     0.0, 0.0,
//     1.0, 0.0,

//     1.0, 1.0,
//     0.0, 1.0,
//     0.0, 0.0,
//     1.0, 0.0,

//     1.0, 1.0,
//     0.0, 1.0,
//     0.0, 0.0,
//     1.0, 0.0,

//     1.0, 1.0,
//     0.0, 1.0,
//     0.0, 0.0,
//     1.0, 0.0,

//     1.0, 1.0,
//     0.0, 1.0,
//     0.0, 0.0,
//     1.0, 0.0,

//     1.0, 1.0,
//     0.0, 1.0,
//     0.0, 0.0,
//     1.0, 0.0,
// ]);

// var indices = new Uint16Array([       // Indices of the vertices
//     0, 1, 2, 0, 2, 3,    // front
//     4, 5, 6, 4, 6, 7,    // right
//     8, 9, 10, 8, 10, 11,    // up
//     12, 13, 14, 12, 14, 15,    // left
//     16, 17, 18, 16, 18, 19,    // down
//     20, 21, 22, 20, 22, 23     // back
// ]);



