

export class geo_Vertex{
    edge:number[]=[];
    face:number[]=[];
}

export class geo_Edge{
    v0:number;
    v1:number;
}
export class MeshGeo{
    vb:Float32Array;
    ib:Uint16Array;
    vertexnum=0;
    fstride=0;
    attrib:string;
    //faces:geo_Face[]; face直接用ib即可
    uvfoff=0;//uv在floatarray的偏移。不是byte，是float
    normoff=3;
    vertexes:geo_Vertex[];
    edges:geo_Edge[];
    tmpMem=new Float32Array(32);
    tmpMem1=new Float32Array(32);
    TB = new Float32Array(6);
    /**
     * 
     * @param vb 
     * @param ib 
     * @param fstride {number} vertex的float个数。即vertex的stride/4。 用来计算顶点个数和确定xyz的位置（每个点的前3个）
     * @param uvoff  {number} 用来取出每个点的uv
     * @param attrib {string} 目前没有用上。
     */
    constructor(vb:Float32Array, ib:Uint16Array, fstride:number, uvoff:number, attrib:string){
        this.vb=vb;
        this.ib=ib;
        this.fstride=fstride;
        this.attrib=attrib;
        this.uvfoff=uvoff;
        this.vertexnum = vb.length/fstride;
        this.gatherInfo();
    }

    gatherInfo(){
        this.vertexes = new Array<geo_Vertex>(this.vertexnum).fill(new geo_Vertex());
        this.vertexes.forEach((v,i)=>{
            v = this.vertexes[i]=new geo_Vertex();//每个都要是不同的实例。
            var st=0;
            while(true){
                var vpos = this.ib.indexOf(i,st);
                if(vpos>=0){
                    st=vpos+1;
                    var fid = Math.floor(vpos/3);
                    if(v.face.indexOf(fid)<0){
                        v.face.push(fid);
                    }
                }
                else{
                    break;
                }
            }
        });
    }

    /**
     * 
     * @param verts 
     * @param p0 
     * @param p1 
     * @param p2 
     * @param uv0 {number} uv0的起点的偏移，单位是float
     * @param uv1 
     * @param uv2 
     * @param normal 
     * @param outverts 
     * @param tangent 
     * @param binormal 
     */
    _calcTangent( verts:Float32Array, p0:number, p1:number, p2:number, 
            uv0:number, uv1:number, uv2:number, 
            normal:number, 
            outverts:Float32Array,
            tangent:number, binormal:number){
        this.TB.fill(0);
        var tb=this.TB;        
        var dx0=verts[p1]- verts[p0]; var dy0=verts[p1+1]-verts[p0+1]; var dz0 = verts[p1+2]-verts[p0+2];
        var dx1=verts[p2]- verts[p0]; var dy1=verts[p2+1]-verts[p0+1]; var dz1 = verts[p2+2]-verts[p0+2];
        var du0=verts[uv1]-verts[uv0]; var dv0 = verts[uv1+1]-verts[uv0+1];
        var du1=verts[uv2]-verts[uv0]; var dv1 = verts[uv2+1]-verts[uv0+1];
        var fenmu = du0*dv1-du1*dv0;    //这个分母不能忽略，决定了正负

        if(fenmu>0){
            tb[0] = dx0*dv1-dx1*dv0; tb[1] = dy0*dv1-dy1*dv0; tb[2] = dz0*dv1-dz1*dv0;
            tb[3] = -dx0*du1+dx1*du0; tb[4] = -dy0*du1+dy1*du0; tb[5] = -dz0*du1+dz1*du0;    
        }else{
            tb[0] = -dx0*dv1+dx1*dv0; tb[1] = -dy0*dv1+dy1*dv0; tb[2] = -dz0*dv1+dz1*dv0;
            tb[3] = dx0*du1-dx1*du0; tb[4] = dy0*du1-dy1*du0; tb[5] = dz0*du1-dz1*du0;
        }

        this.vec3_normalize(tb,0);
        this.vec3_normalize(tb,3);
        //console.log(tb[0],tb[1],tb[2]);console.log(tb[3],tb[4],tb[5]);

        this.vec3_cross(tb,0,3);
        var tdb = this.tmpMem[0]*verts[normal] + this.tmpMem[1]*verts[normal+1] + this.tmpMem[2]*verts[normal+2];
        if(tdb<0.0){
            //tb.forEach((v,i)=>{tb[i]=-tb[i];});
        }

        outverts[tangent]=tb[0]; outverts[tangent+1]=tb[1]; outverts[tangent+2]=tb[2];
        outverts[binormal]=tb[3]; outverts[binormal+1]=tb[4]; outverts[binormal+2]=tb[5];
        return true;
    }

    vec3_cross(vb:Float32Array, v0:number, v1:number){
        var ax = vb[v0], ay=vb[v0+1], az=vb[v0+2];
        var bx = vb[v1], by=vb[v1+1], bz=vb[v1+2];
        this.tmpMem[0] = ay * bz - az * by;
        this.tmpMem[1] = az * bx - ax * bz;
        this.tmpMem[2] = ax * by - ay * bx;
    }

    vec3_length(vb:Float32Array, v0:number){
        var x = vb[v0];
        var y = vb[v0+1];
        var z = vb[v0+2];
        var l = x*x+y*y+z*z;
        return Math.sqrt(l);
    }

    vec3_normalize(vb:Float32Array, v0){
        var l = this.vec3_length(vb,v0);
        if(l<1e-9){
            vb[v0]=0;
            vb[v0+1]=0;
            vb[v0+2]=0;
            return;
        }
        vb[v0]/=l;
        vb[v0+1]/=l;
        vb[v0+2]/=l;
    }

    vec3_copy(vbo:Float32Array, v1:number, vb:Float32Array, v0:number ){
        vbo[v1]=vb[v0];
        vbo[v1+1]=vb[v0+1];
        vbo[v1+2]=vb[v0+2];
    }

    /**
     * 返回tangent和binormal
     */
    calcTangent(){
        var ret={tan:new Float32Array(this.vertexnum*3), binor:new Float32Array(this.vertexnum*3)};
        this.vertexes.forEach((v,i)=>{
            var sum=0;
            //
            var outarr = new Float32Array(6).fill(0);
            v.face.forEach((ef,fi)=>{
                var cout = new Float32Array(6);
                var v0=this.ib[ef*3];
                var v1=this.ib[ef*3+1];
                var v2=this.ib[ef*3+2];
                /* 加上这个效果就全错了
                if(v1==i){
                    [v0,v1]=[v1,v0];
                }
                else if(v2==i){
                    [v0,v2]=[v2,v0];
                }
                */
                var v0p = v0*this.fstride;
                var v1p = v1*this.fstride;
                var v2p = v2*this.fstride;
                if(!this._calcTangent(this.vb,
                    v0p, v1p,v2p,
                    v0p+this.uvfoff, v1p+this.uvfoff,v2p+this.uvfoff,
                    this.normoff,cout,0,3))
                    return ;
                var dbuff = this.tmpMem1;
                dbuff[0]=this.vb[v1p  ]-this.vb[v0p  ];//dx
                dbuff[1]=this.vb[v1p+1]-this.vb[v0p+1];//dy
                dbuff[2]=this.vb[v1p+2]-this.vb[v0p+2];//dz

                dbuff[3]=this.vb[v2p  ]-this.vb[v0p  ];//dx1
                dbuff[4]=this.vb[v2p+1]-this.vb[v0p+1];//dy1
                dbuff[5]=this.vb[v2p+2]-this.vb[v0p+2];//dz1
                this.vec3_cross(dbuff,0,3);
                var l = this.vec3_length(this.tmpMem,0);
                for(var oi=0; oi<6; oi++){
                    outarr[oi]+=cout[oi]*l;
                }
                sum+=l;
            });
            /*
            for(var oi=0; oi<6; oi++){
                outarr[oi]=outarr[oi]/sum;
            }
            */
            this.vec3_normalize(outarr,0);
            this.vec3_normalize(outarr,3);
            this.vec3_copy(ret.tan,i*3, outarr,0);
            this.vec3_copy(ret.binor,i*3, outarr,3);
        });
        return ret;
    }
}