
#include <WFX/scene/TriMesh.h>
#include <WFX/renderer/Renderer.h>
#include <WFX/scene/SceneGraphVisitor.h>

using namespace WFX;
using namespace WFX::math;
using namespace WFX::scene;

TriMesh::TriMesh() : GeometryNode() {
    FaceCount = 0;
    Connectivity = NULL;
    Normals = NULL;
    Mode = MM_Triangles;
}

TriMesh::~TriMesh() {
    delete[] Connectivity;
}

void TriMesh::draw(WFX::renderer::Renderer* r) {
    r->drawTriMesh(*this);
}

void TriMesh::calcNormals() {
    if (!Connectivity)
        return;
    //calc vertex normals
    if (!Normals) 
        Normals = new Vector3[VertexCount];

    memset(Normals,0,VertexCount*sizeof(Vector3));

    UInt* conn = Connectivity;
    for (UInt i=0;i<FaceCount;i++) {
        //indices
        UInt i0 = *conn++;
        UInt i1 = *conn++;
        UInt i2 = *conn++;

        //vertices
        Vector3& v0 = Vertices[i0];
        Vector3& v1 = Vertices[i1];
        Vector3& v2 = Vertices[i2];

        //calc edges and normal
        Vector3 edge1 = v1 - v0;
        Vector3 edge2 = v2 - v0;
        Vector3 normal = edge1.cross(edge2);

        //add normal to vertex normals - length provides weight
        Normals[i0] += normal;
        Normals[i1] += normal;
        Normals[i2] += normal;
    }

}

void TriMesh::accept(SceneGraphVisitor& s) {
    s.visitTriMesh(*this);
}

TriMesh* TriMesh::split(std::vector<bool>& tris) {
    TriMesh* ret = new TriMesh();
    //copy spatial properties
    ret->LocalRotation = LocalRotation;
    ret->LocalTranslation = LocalTranslation;
    ret->LocalScale = LocalScale;
    ret->WorldRotation = WorldRotation;
    ret->WorldTranslation = WorldTranslation;
    ret->WorldScale = WorldScale;
    ret->setModelBound(ModelBound->copy());
    ret->ForceCull = ForceCull;
    ret->MyMaterial = MyMaterial;
    //copy geometry
    ret->FaceCount = 0;
    //find used vertices
    std::vector<bool>::iterator it;
    std::map<UInt, bool> usedVerts;
    UInt i = 0;
    for (it = tris.begin(); it != tris.end(); it++) {
        if (*it) {
            ret->FaceCount++;
            usedVerts[Connectivity[i*3]] = true;
            usedVerts[Connectivity[i*3+1]] = true;
            usedVerts[Connectivity[i*3+2]] = true;
        } 
        i++;         
    }
    //iterate over and copy usedVerts
    ret->Vertices = new Vector3[usedVerts.size()];
    if (Normals)
        ret->Normals = new Vector3[usedVerts.size()];
    if (Colors)
        ret->Colors = new Color[usedVerts.size()];
    if (TexCoords)
        ret->TexCoords = new Vector2[usedVerts.size()];

    std::map<UInt, bool>::iterator vertIt;
    std::map<UInt, UInt> indexMap;
    i = 0;
    for (vertIt = usedVerts.begin(); vertIt != usedVerts.end(); vertIt++) {
        indexMap[(*vertIt).first] = i;
        ret->Vertices[i] = Vertices[(*vertIt).first];
        if (Normals)
            ret->Normals[i] = Normals[(*vertIt).first];
        if (Colors)
            ret->Colors[i] = Colors[(*vertIt).first];
        if (TexCoords)
            ret->TexCoords[i] = TexCoords[(*vertIt).first];
        i++;
    }
    //now create new Connectivity
    ret->Connectivity = new UInt[ret->FaceCount*3];
    i = 0;
    UInt k = 0;
    for (it = tris.begin(); it != tris.end(); it++) {
        if (*it) {
            ret->Connectivity[k*3] = indexMap[Connectivity[i*3]];
            ret->Connectivity[k*3+1] = indexMap[Connectivity[i*3+1]];
            ret->Connectivity[k*3+2] = indexMap[Connectivity[i*3+2]];
            k++;
        }
        i++;
    }
    //ret-> = ;

    return ret;
}

