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[];

    _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 = {};

        this._vertices = vertices;
        this._normals = normals || new Float32Array(vertices.length);
        this._colors = colors || new Float32Array(vertices.length).map(() => { return 1 });//不传就全是白色
        this._uvs = uvs || new Float32Array(vertices.length / 3 * 2);
        //索引直接用，可能没有
        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
]);


// function createNineTextures(imageUrl: string): Promise<FYGE.Texture[]> {
//     return new Promise((resolve, reject) => {
//         let image = new Image();
//         image.onload = function () {
//             var obj = {}
//             //名字。
//             var name = "lalala";
//             var w = image.width / 3;
//             var h = image.height / 3;
//             //生成9张图的数据
//             for (var i = 0; i < 9; i++)
//                 obj[name + i] = {
//                     "x": i % 3 * w,
//                     "y": ~~(i / 3) * h,
//                     w, h, sw: w, sh: h, ox: 0, oy: 0, ro: false
//                 };
//             var textures = FYGE.createTextureSheet(new FYGE.BaseTexture(image), obj);
//             //取TextureCache里的
//             var arr = [];
//             for (var i = 0; i < 9; i++)arr.push(textures[name + i])
//             resolve(arr)
//         }
//         image.onerror = function () {
//             reject()
//         }
//         image.src = imageUrl
//     })
// }
