#include "GeoMeshSimplifier.h" #include "GeoMeshSimpSequence.h" #include "SimplificationMethod.h" #include #include using namespace Geometry; using namespace std; ////////////////////////////////////////////////////////////////////////// // // // MeshSimplifier class // // // ////////////////////////////////////////////////////////////////////////// //------------------------------------------------------------------------- // MeshSimplifier constructor. //------------------------------------------------------------------------- MeshSimplifier::MeshSimplifier( const Mesh *m, TIPOFUNC upb) { // Saves initial state of mesh. mInitialMesh = new Mesh(); *mInitialMesh = *m; objmesh = m; mGeoMesh = NULL; msimpsequence = NULL; indexMeshLeaves = -1; // Sets the actual progress bar function. mUPB = upb; } //------------------------------------------------------------------------- // MeshSimplifier destroyer. //------------------------------------------------------------------------- MeshSimplifier::~MeshSimplifier() { delete mInitialMesh; delete msimpsequence; } //------------------------------------------------------------------------- // Returns the simplified mesh. //------------------------------------------------------------------------- Mesh * MeshSimplifier::GetMesh() { return mGeoMesh; } //------------------------------------------------------------------------- // Set submesh leaves //------------------------------------------------------------------------- void MeshSimplifier::setMeshLeaves(Geometry::Index index) { indexMeshLeaves = index; } //------------------------------------------------------------------------- // Returns the simplification sequence for general meshes. //------------------------------------------------------------------------- MeshSimplificationSequence *MeshSimplifier::GetSimplificationSequence() { return msimpsequence; } //------------------------------------------------------------------------- // Sort mesh bones. //------------------------------------------------------------------------- void MeshSimplifier::sortBones() { VertexBuffer *simplified_vb; VertexBuffer *initial_vb; std::vector *simplified_bones; std::vector *initial_bones; // After simplifying, the object always is shared vertex // so, the bones must be placed in the GeoMesh simplified_bones = &mGeoMesh->mBones; simplified_vb = mGeoMesh->mVertexBuffer; // we assume the original mesh is shared vertex // because before the simplification process // the mesh becomes converted to shared vertex // so, the original bones must be searched in the // Mesh, not in every submesh simplified_bones->clear(); // Vertex buffers. initial_vb = mInitialMesh->mVertexBuffer; // Bones. initial_bones = &mInitialMesh->mBones; // For each bone assignment. for (int b = 0; b < initial_bones->size(); b++) { VertexBoneAssignment assign; int n = (*initial_bones)[b].vertexIndex; // For each vertex. for (int i = 0; i < simplified_vb->mVertexCount; i++) { if (simplified_vb->mPosition[i].x == initial_vb->mPosition[n].x && simplified_vb->mPosition[i].y == initial_vb->mPosition[n].y && simplified_vb->mPosition[i].z == initial_vb->mPosition[n].z) { assign.vertexIndex = i; assign.boneIndex = (*initial_bones)[b].boneIndex; assign.weight = (*initial_bones)[b].weight; simplified_bones->push_back(assign); } } } } ////////////////////////////////////////////////////////////////////////// // // // GeometryBasedSimplifier class // // // ////////////////////////////////////////////////////////////////////////// //------------------------------------------------------------------------- // Constructor. //------------------------------------------------------------------------- GeometryBasedSimplifier::GeometryBasedSimplifier( const Mesh *m, TIPOFUNC upb) :MeshSimplifier(m,upb) { } //------------------------------------------------------------------------- // Destroyer. //------------------------------------------------------------------------- GeometryBasedSimplifier::~GeometryBasedSimplifier() { } //------------------------------------------------------------------------- // Starts the simplification process. Receives as a parameter // the LOD factor in a range of [0,1]. Implements the Simplifier::Simplify // method to perform an image based simplification. //------------------------------------------------------------------------- void GeometryBasedSimplifier::Simplify(Real paramlod) { SimplificationMethod *m_qslim = new SimplificationMethod(objmesh); m_qslim->setMeshLeaves(indexMeshLeaves); msimpsequence = m_qslim->Decimate(paramlod,0,mUPB); mGeoMesh = m_qslim->GetMesh(); // Debug. cout << "Number of bone assignaments: " << mGeoMesh->mBones.size() << endl; // if the initial mesh had shared vertex, // convert the mesh to shared vertex //Mesh *sharedMesh = mGeoMesh->toSharedVertex(); //delete mGeoMesh; //mGeoMesh = sharedMesh; // Sort bones. //sortBones(); delete m_qslim; } //------------------------------------------------------------------------- // Starts the simplification process. Receives as a parameter the // number of vertices of the resulting mesh. // Implements the Simplifier::Simplify method to // perform an image based simplification. //------------------------------------------------------------------------- void GeometryBasedSimplifier::Simplify(uint32 numvertices) { SimplificationMethod *m_qslim = new SimplificationMethod(objmesh); m_qslim->setMeshLeaves(indexMeshLeaves); msimpsequence = m_qslim->Decimate((float)numvertices,1,mUPB); mGeoMesh = m_qslim->GetMesh(); // if the initial mesh had shared vertex, // convert the mesh to shared vertex //Mesh *sharedMesh = mGeoMesh->toSharedVertex(); //delete mGeoMesh; //mGeoMesh = sharedMesh; // Sort bones. //sortBones(); delete m_qslim; } ////////////////////////////////////////////////////////////////////////// // // // ViewPointDrivenSimplifier class // // // ////////////////////////////////////////////////////////////////////////// //------------------------------------------------------------------------ // Class constructor. Will call Simplifier class constructor. //------------------------------------------------------------------------ ViewPointDrivenSimplifier::ViewPointDrivenSimplifier( const Mesh *m, TIPOFUNC upb) :MeshSimplifier(m,upb) { // Set progress update function VMI::mUPB = upb; VMI::width = 256; VMI::height = 256; VMI::bEnableOffScreen = GL_TRUE; VMI::bBeQuiet = GL_FALSE; VMI::bSaveLog = GL_FALSE; VMI::bLoadCamerasFromFile = GL_FALSE; VMI::bRemoveRedundantVertices = GL_TRUE; VMI::cameraType = 3; // 20 viewpoints VMI::radius = 1.3; VMI::fov = 60.0; printf("w: %d h: %d\n", VMI::width, VMI::height); printf( "t: %d c: %d o: %d r: %f\n", VMI::numDemandedTriangles, VMI::cameraType, VMI::bEnableOffScreen, VMI::radius); // Fill up attributes. fillUpPosNorTC(mInitialMesh); VMI::vPositions = vPositions; VMI::vNormals = vNormals; VMI::vTexCoords = vTexCoords; mGeoMesh = new Mesh(); *mGeoMesh = *m; // Transform NoSV Mesh to a SV Mesh. //mGeoMesh = mGeoMesh->toSharedVertex(); // Join Vertices. mTexConserver = new TextureConserver(); mTexConserver->JoinVertices(mGeoMesh); // Loads the vmi mesh structure for a geometry mesh given. VMI::mesh = initMeshStructure(mGeoMesh); // RGB and Alpha. glutInitDisplayMode(GLUT_DEPTH | GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA); glutInitWindowSize(VMI::width, VMI::height); glutInitWindowPosition(100, 100); VMI::vmiWin = glutCreateWindow("VMI"); glewInit(); VMI::init(); if (VMI::bLoadCamerasFromFile == GL_FALSE) VMI::cameras = VMI::setCameras(VMI::radius, VMI::cameraType, &VMI::numCameras); VMI::histogram = VMI::initHistogram( VMI::mesh->currentNumTriangles, VMI::numCameras); VMI::initialIs = VMI::initIs(VMI::numCameras); } //------------------------------------------------------------------------- /// Class destructor. //------------------------------------------------------------------------- ViewPointDrivenSimplifier::~ViewPointDrivenSimplifier(void) { // Free memory VMI::freeMemory(); } /// Starts the simplification process. Receives as a parameter the /// LOD factor in a range of [0,1]. Implements the /// Simplifier::Simplify method to perform an image based simplification. void ViewPointDrivenSimplifier::Simplify(Real percent) { VMI::numDemandedTriangles = (int)(VMI::mesh->numTriangles * percent); if ((VMI::numDemandedTriangles == 0) || (VMI::numDemandedTriangles >= VMI::mesh->currentNumTriangles)) { printf("Illegal number of triangles.\n"); } VMI::display(); // Cleans firts simplification. VMI::freeMemory(); VMI::mesh = initMeshStructure(mInitialMesh); VMI::contractInitialMesh(VMI::mesh); // Load a geometry mesh for vmi mesh. loadMesh(); GetMeshSimpSequence(); // Sort bones. bonesReassignament(); } //------------------------------------------------------------------------- /// Starts the simplification process. Receives as a parameter /// the number of vertices of the resulting mesh. /// Implements the Simplifier::Simplify method to perform /// an image based simplification. //------------------------------------------------------------------------- void ViewPointDrivenSimplifier::Simplify(uint32 numVertices) { float percent; percent = (numVertices * 100.0) / VMI::mesh->numVertices; VMI::numDemandedTriangles = (int)(VMI::mesh->numTriangles * (percent / 100)); if ((VMI::numDemandedTriangles == 0) || (VMI::numDemandedTriangles >= VMI::mesh->currentNumTriangles)) { printf("Illegal number of triangles.\n"); } VMI::display(); // Cleans firts simplification. VMI::freeMemory(); VMI::mesh = initMeshStructure(mInitialMesh); VMI::contractInitialMesh(VMI::mesh); // Load a geometry mesh for vmi mesh. loadMesh(); GetMeshSimpSequence(); // Sort bones. bonesReassignament(); } //------------------------------------------------------------------------- // Gets the VMI mesh simplification sequence. //------------------------------------------------------------------------- void ViewPointDrivenSimplifier::GetMeshSimpSequence() { size_t j = 0; MeshSimplificationSequence::Step current_step; msimpsequence = new MeshSimplificationSequence(); // Copy the mesh simplification sequence. msimpsequence->mSteps = VMI::mSequence->mSteps; msimpsequence->mNewVertices = VMI::mSequence->mNewVertices; } //------------------------------------------------------------------------- // Initialize the mesh of VMI module. //------------------------------------------------------------------------- VMI::Mesh * ViewPointDrivenSimplifier::initMeshStructure(Mesh *geoMesh) { GLuint i, j, v1, v2, v3, n, e, t; VMI::Mesh *vmi_mesh; SubMesh *geosubmesh; VertexBuffer *vertex_buffer; int mesh_index_count; int index; // Reallocate memory for vmi mesh object. vmi_mesh = (VMI::Mesh *)malloc(sizeof(VMI::Mesh)); if (vmi_mesh == NULL) { fprintf(stderr, "Error allocating memory\n"); exit(1); } // Shared vertex buffer. vertex_buffer = geoMesh->mVertexBuffer; // Reallocate memory for vertices of mesh. vmi_mesh->vertices = (VMI::Vertex *)malloc(sizeof(VMI::Vertex) * vertex_buffer->mVertexCount); if (vmi_mesh->vertices == NULL) { fprintf(stderr, "Error allocating memory\n"); exit(1); } // Initialize mesh index count. mesh_index_count = 0; for ( unsigned int submesh = 0; submesh < geoMesh->mSubMeshCount; submesh++) { mesh_index_count += int(geoMesh->mSubMesh[submesh].mIndexCount); } // Reallocate memory for indices. vmi_mesh->triangles = (VMI::Triangle *)malloc(sizeof(VMI::Triangle) * (mesh_index_count / 3)); if (vmi_mesh->triangles == NULL) { fprintf(stderr, "Error allocating memory\n"); exit(1); } printf("Adding vertices..."); // Fill up vertices. for (i = 0; i < vertex_buffer->mVertexCount; i++) { // Vertices start at 0. vmi_mesh->vertices[i].x = vertex_buffer->mPosition[i].x; vmi_mesh->vertices[i].y = vertex_buffer->mPosition[i].y; vmi_mesh->vertices[i].z = vertex_buffer->mPosition[i].z; vmi_mesh->vertices[i].numTriangles = 0; vmi_mesh->vertices[i].triangles = NULL; vmi_mesh->vertices[i].enable = GL_TRUE; vmi_mesh->vertices[i].movable = GL_TRUE; } printf("Ok\n"); vmi_mesh->numVertices = int(vertex_buffer->mVertexCount); vmi_mesh->currentNumVertices = int(vertex_buffer->mVertexCount); printf("Vertices: %d\n",vmi_mesh->numVertices); // Fill up triangles. printf("Adding triangles..."); // Initialize index of triangle. index = 0; // For each submesh. for ( unsigned int submesh = 0; submesh < geoMesh->mSubMeshCount; submesh++) { // Gets actual submesh. geosubmesh = &geoMesh->mSubMesh[submesh]; // For each three vertices. for (i = 0; i < (geosubmesh->mIndexCount / 3); i++) { vmi_mesh->triangles[index].id = index; vmi_mesh->triangles[index].submesh = submesh; vmi_mesh->triangles[index].indices[0] = geosubmesh->mIndex[(3 * i)]; vmi_mesh->triangles[index].indices[1] = geosubmesh->mIndex[(3 * i) + 1]; vmi_mesh->triangles[index].indices[2] = geosubmesh->mIndex[(3 * i) + 2]; vmi_mesh->triangles[index].area = computeTriangleArea(vmi_mesh->vertices, &vmi_mesh->triangles[index]); computeTriangleNormal(vmi_mesh->vertices, &vmi_mesh->triangles[index]); vmi_mesh->triangles[index].saliency = 0.0; vmi_mesh->triangles[index].enable = GL_TRUE; for (j = 0; j < 3; j++) { // Adding triangle index adjacent to 3 vertices. v1 = vmi_mesh->triangles[index].indices[j]; // Reallocate memory for the new adjacent triangle. vmi_mesh->vertices[v1].triangles = (GLuint *)realloc(vmi_mesh->vertices[v1].triangles, (vmi_mesh->vertices[v1].numTriangles + 1) * sizeof(GLuint)); VMI::addItem( (int *)vmi_mesh->vertices[v1].triangles, (int *)&vmi_mesh->vertices[v1].numTriangles, index); } // Increments triangle count. index++; } } printf("Ok\n"); vmi_mesh->numTriangles = mesh_index_count / 3; vmi_mesh->currentNumTriangles = mesh_index_count / 3; printf("Num Triangles: %d\n",vmi_mesh->numTriangles); // E = 3 T / 2 vmi_mesh->edges = (VMI::Edge *)malloc(sizeof(VMI::Edge) * vmi_mesh->numTriangles * 3); if (vmi_mesh->edges == NULL) { fprintf(stderr, "Error allocating memory\n"); exit(1); } printf("Adding edges..."); n = 0; // For each triangle adds three edges. for (i = 0; i < vmi_mesh->numTriangles; i++) { t = 0; v1 = vmi_mesh->triangles[i].indices[0]; v2 = vmi_mesh->triangles[i].indices[1]; v3 = vmi_mesh->triangles[i].indices[2]; if ((e = findEdge(vmi_mesh->edges, n, v1, v2)) == -1) { vmi_mesh->edges[n].u = v1; vmi_mesh->edges[n].v = v2; vmi_mesh->edges[n].triangles = NULL; vmi_mesh->edges[n].numTriangles = 0; vmi_mesh->edges[n].enable = GL_TRUE; // Reallocate memory for the new adjacent triangle vmi_mesh->edges[n].triangles = (GLuint *)realloc(vmi_mesh->edges[n].triangles, (vmi_mesh->edges[n].numTriangles + 1) * sizeof(GLuint)); // Adding triangle i adjacent to edge n VMI::addItem( (int *)vmi_mesh->edges[n].triangles, (int *)&vmi_mesh->edges[n].numTriangles, i); // Adding edge n adjacent to triangle i VMI::addItem((int *)vmi_mesh->triangles[i].edges, (int *)&t, n); n++; } else { // Reallocate memory for the new adjacent triangle. vmi_mesh->edges[e].triangles = (GLuint *)realloc(vmi_mesh->edges[e].triangles, (vmi_mesh->edges[e].numTriangles + 1) * sizeof(GLuint)); // Adding triangle i adjacent to edge e VMI::addItem( (int *)vmi_mesh->edges[e].triangles, (int *)&vmi_mesh->edges[e].numTriangles, i); // Adding edge e adjacent to triangle i VMI::addItem((int *)vmi_mesh->triangles[i].edges, (int *)&t, e); } if ((e = findEdge(vmi_mesh->edges, n, v2, v3)) == -1) { vmi_mesh->edges[n].u = v2; vmi_mesh->edges[n].v = v3; vmi_mesh->edges[n].triangles = NULL; vmi_mesh->edges[n].numTriangles = 0; vmi_mesh->edges[n].enable = GL_TRUE; // Reallocate memory for the new adjacent triangle vmi_mesh->edges[n].triangles = (GLuint *)realloc(vmi_mesh->edges[n].triangles, (vmi_mesh->edges[n].numTriangles + 1) * sizeof(GLuint)); // Adding triangle i adjacent to edge n VMI::addItem((int *)vmi_mesh->edges[n].triangles, (int *)&vmi_mesh->edges[n].numTriangles, i); vmi_mesh->edges[n].triangles = NULL; vmi_mesh->edges[n].numTriangles = 0; // Adding edge n adjacent to triangle i VMI::addItem((int *)vmi_mesh->triangles[i].edges, (int *)&t, n); n++; } else { // Reallocate memory for the new adjacent triangle vmi_mesh->edges[e].triangles = (GLuint *)realloc(vmi_mesh->edges[e].triangles, (vmi_mesh->edges[e].numTriangles + 1) * sizeof(GLuint)); // Adding triangle i adjacent to edge e VMI::addItem( (int *)vmi_mesh->edges[e].triangles, (int *)&vmi_mesh->edges[e].numTriangles, i); // Adding edge e adjacent to triangle i VMI::addItem((int *)vmi_mesh->triangles[i].edges, (int *)&t, e); } if ((e = findEdge(vmi_mesh->edges, n, v3, v1)) == -1) { vmi_mesh->edges[n].u = v3; vmi_mesh->edges[n].v = v1; vmi_mesh->edges[n].triangles = NULL; vmi_mesh->edges[n].numTriangles = 0; vmi_mesh->edges[n].enable = GL_TRUE; // Reallocate memory for the new adjacent triangle. vmi_mesh->edges[n].triangles = (GLuint *)realloc(vmi_mesh->edges[n].triangles, (vmi_mesh->edges[n].numTriangles + 1) * sizeof(GLuint)); // Adding triangle i adjacent to edge n VMI::addItem( (int *)vmi_mesh->edges[n].triangles, (int *)&vmi_mesh->edges[n].numTriangles, i); // Adding edge n adjacent to triangle i VMI::addItem((int *)vmi_mesh->triangles[i].edges, (int *)&t, n); n++; } else { // Reallocate memory for the new adjacent triangle vmi_mesh->edges[e].triangles = (GLuint *)realloc(vmi_mesh->edges[e].triangles, (vmi_mesh->edges[e].numTriangles + 1) * sizeof(GLuint)); // Adding triangle i adjacent to edge e VMI::addItem((int *)vmi_mesh->edges[e].triangles, (int *)&vmi_mesh->edges[e].numTriangles, i); // Adding edge e adjacent to triangle i VMI::addItem((int *)vmi_mesh->triangles[i].edges, (int *)&t, e); } } printf("Ok\n"); vmi_mesh->numEdges = n; // Creates vertex multimap. initVertexMultimap(vmi_mesh,mTexConserver->mVertices); return vmi_mesh; } //------------------------------------------------------------------------- // Gets the geometry mesh of a the vmi mesh given. //------------------------------------------------------------------------- void ViewPointDrivenSimplifier::loadMesh() { int num_indices; SubMesh *geosubmesh; VertexBuffer *vertex_buffer; // Gets old vertex buffer. vertex_buffer = mGeoMesh->mVertexBuffer; // Initialize auxiliar vertex buffer. mVB = new VertexBuffer(); mVB->mPosition = new Vector3[VMI::mesh->currentNumVertices]; mVB->mNormal = new Vector3[VMI::mesh->currentNumVertices]; mVB->mTexCoords = new Vector2[VMI::mesh->currentNumVertices]; mVB->mVertexInfo = vertex_buffer->mVertexInfo; // For each submesh. for (size_t submesh = 0; submesh < mGeoMesh->mSubMeshCount; submesh++) { geosubmesh = &mGeoMesh->mSubMesh[submesh]; delete []geosubmesh->mIndex; // Initialize submesh index count; num_indices = 0; // For each triangle. for (size_t i = 0; i < VMI::mesh->numTriangles; i++) { // If is enable and of the current submesh. if ((VMI::mesh->triangles[i].enable) && (VMI::mesh->triangles[i].submesh == submesh)) { // Increments submesh index count. num_indices += 3; } } geosubmesh->mIndexCount = num_indices; geosubmesh->mIndex = new Geometry::Index[geosubmesh->mIndexCount]; // Initialize number of indices. num_indices = 0; // Fill up indices. for (size_t i = 0; i < VMI::mesh->numTriangles; i++) { if ((VMI::mesh->triangles[i].enable) && (VMI::mesh->triangles[i].submesh == submesh)) { geosubmesh->mIndex[num_indices++] = VMI::mesh->triangles[i].indices[0]; geosubmesh->mIndex[num_indices++] = VMI::mesh->triangles[i].indices[1]; geosubmesh->mIndex[num_indices++] = VMI::mesh->triangles[i].indices[2]; } } // For each index. for (size_t i = 0; i < geosubmesh->mIndexCount; i++) { findVertex(submesh,i); } geosubmesh->mVertexBuffer = mVB; } delete vertex_buffer; mGeoMesh->mVertexBuffer = mVB; } //------------------------------------------------------------------------- // Find vertex in auxiliar vertex buffer. //------------------------------------------------------------------------- void ViewPointDrivenSimplifier::findVertex(size_t submesh, size_t elem) { bool found; int index; unsigned int i; int new_elem; VertexBuffer *vertex_buffer; map::iterator it; found = false; // Shared vertex buffer. vertex_buffer = mInitialMesh->mVertexBuffer; index = mGeoMesh->mSubMesh[submesh].mIndex[elem]; i = 0; if ((it = mIndexMap.find(index)) != mIndexMap.end()) { mGeoMesh->mSubMesh[submesh].mIndex[elem] = (*it).second; } else { mIndexMap[index] = int(mVB->mVertexCount); // Last element. new_elem = int(mVB->mVertexCount); mVB->mPosition[new_elem] = VMI::vPositions[index]; mVB->mNormal[new_elem] = VMI::vNormals[index]; mVB->mTexCoords[new_elem] = VMI::vTexCoords[index]; // Update index. mGeoMesh->mSubMesh[submesh].mIndex[elem] = new_elem; // Increments vertex count. mVB->mVertexCount++; } } //------------------------------------------------------------------------- // Reassigns bones. //------------------------------------------------------------------------- void ViewPointDrivenSimplifier::bonesReassignament() { size_t vertex_id; size_t bones_count; bool vertex_found; map::iterator im; VertexBoneAssignment bone; vector::iterator ib; // Copy new vertices. for (unsigned int i = 0; i < msimpsequence->mNewVertices.size(); i++) { vertex_id = msimpsequence->mNewVertices[i].id; // Initialize number of bones. bones_count = mInitialMesh->mBones.size(); // check if my twin-vertex-bone has a bone assignment // we check only the GeoMesh bones because the lodstrips // only works for sharedvertex bones. for (int j = 0; j < bones_count; j++) { ib = mInitialMesh->mBones.begin() + j; if (ib->vertexIndex == msimpsequence->mNewVertices[i].bonefrom) { bone.vertexIndex = vertex_id; bone.boneIndex = ib->boneIndex; bone.weight = ib->weight; mInitialMesh->mBones.push_back(bone); bones_count++; } } } // Clears bones. mGeoMesh->mBones.clear(); // For each bone assignment. for (unsigned int i = 0; i < mInitialMesh->mBones.size(); i++) { bone.vertexIndex = mInitialMesh->mBones[i].vertexIndex; bone.boneIndex = mInitialMesh->mBones[i].boneIndex; bone.weight = mInitialMesh->mBones[i].weight; vertex_found = false; // If the vertex is found in the simplification model. if ((im = mIndexMap.find(bone.vertexIndex)) != mIndexMap.end()) { bone.vertexIndex = (*im).second; mGeoMesh->mBones.push_back(bone); vertex_found = true; } } } //------------------------------------------------------------------------- // Fill up position, normal and texture coordinates. //------------------------------------------------------------------------- void ViewPointDrivenSimplifier::fillUpPosNorTC(Mesh *geoMesh) { VertexBuffer *vertex_buffer; Vector3 v3; Vector2 v2; vertex_buffer = geoMesh->mVertexBuffer; for (size_t i = 0; i < vertex_buffer->mVertexCount; i++) { v3 = vertex_buffer->mPosition[i]; vPositions.push_back(v3); v3 = vertex_buffer->mNormal[i]; vNormals.push_back(v3); v2 = vertex_buffer->mTexCoords[i]; vTexCoords.push_back(v2); } } //------------------------------------------------------------------------- // EdgesMultimap class //------------------------------------------------------------------------- //------------------------------------------------------------------------- // Constructor. //------------------------------------------------------------------------- EdgesMultimap::EdgesMultimap() { edges.clear(); } //------------------------------------------------------------------------- // Insert and edge. //------------------------------------------------------------------------- void EdgesMultimap::insert(int v1,int v2) { edges.insert(pair(v1,v2)); edges.insert(pair(v2,v1)); } //------------------------------------------------------------------------- // Remove edges with v1 and v2. //------------------------------------------------------------------------- void EdgesMultimap::remove(int v1,int v2) { multimap::iterator lb; multimap::iterator ub; if (edges.find(v1) != edges.end()) { lb = edges.lower_bound(v1); ub = edges.upper_bound(v1); while (lb != ub) { if ((*lb).second == v2) { // Remove edge. edges.erase(lb); lb = ub; } else { lb++; } } } if (edges.find(v2) != edges.end()) { lb = edges.lower_bound(v2); ub = edges.upper_bound(v2); while (lb != ub) { if ((*lb).second == v1) { // Remove edge. edges.erase(lb); lb = ub; } else { lb++; } } } } //------------------------------------------------------------------------- // Checks if the edge (v1,v2) exists. //------------------------------------------------------------------------- bool EdgesMultimap::exists(int v1,int v2) { bool found; multimap::iterator lb; multimap::iterator ub; found = false; // Find range. lb = edges.lower_bound(v1); ub = edges.upper_bound(v1); // Search for all v1 edges. while (lb != ub) { // If edge is found. if ((*lb).second = v2) { found = true; lb = ub; } else { // Next iteration. lb++; } } return found; } //------------------------------------------------------------------------- // Change vertex v1 to v2 in the map. //------------------------------------------------------------------------- void EdgesMultimap::contract(int v1,int v2) { multimap::iterator it; int v_aux; // Remove contracted edge. remove(v1,v2); // Modify all edges where appears v1 to v2. while ((it = edges.find(v1)) != edges.end()) { v_aux = (*it).second; // Remove current edge. remove(v1,v_aux); // Modify edge. insert(v2,v_aux); } } //------------------------------------------------------------------------- // TextureConserver class //------------------------------------------------------------------------- TextureConserver::TextureConserver() { mEdges = new EdgesMultimap(); mGeoMesh = new Mesh(); } TextureConserver::~TextureConserver() { delete mGeoMesh; } //------------------------------------------------------------------------- // Join twin vertices into a unique vertex. //------------------------------------------------------------------------- void TextureConserver::JoinVertices(Mesh *mesh) { map<_coord_, int> uniquevertices; map newindices; multimap::iterator it; map::iterator it_map; VertexBuffer *vertex_buffer; VertexBuffer *mGMVB; unsigned int vertex_count; unsigned int i; unsigned int aux_i; unsigned int submesh; SubMesh *geosubmesh; _coord_ vertex_aux; // Copy actual mesh. *mGeoMesh = *mesh; // Gets the shared vertex buffer. vertex_buffer = mGeoMesh->mVertexBuffer; // Initialize unique vertices count. vertex_count = 0; // Fill up vertices. for (i = 0; i < vertex_buffer->mVertexCount; i++) { vertex_aux.x = vertex_buffer->mPosition[i].x; vertex_aux.y = vertex_buffer->mPosition[i].y; vertex_aux.z = vertex_buffer->mPosition[i].z; // New index. if (uniquevertices.find(vertex_aux) == uniquevertices.end()) { uniquevertices[vertex_aux] = vertex_count; newindices[i] = vertex_count; mVertices.insert(pair(vertex_count,i)); // Increments unique vertices count. vertex_count++; } // The map of unique vertices already contains this vertex. else { int newindex = uniquevertices[vertex_aux]; newindices[i] = newindex; mVertices.insert(pair(newindex,i)); } } // Delete vertices. delete mesh->mVertexBuffer; mesh->mVertexBuffer = new VertexBuffer(); mesh->mVertexBuffer->mPosition = new Vector3[vertex_count]; mesh->mVertexBuffer->mNormal = new Vector3[vertex_count]; mesh->mVertexBuffer->mTexCoords = new Vector2[vertex_count]; mesh->mVertexBuffer->mVertexInfo = vertex_buffer->mVertexInfo; mesh->mVertexBuffer->mVertexCount = vertex_count; mGMVB = mesh->mVertexBuffer; // Fill up unique vertices. for (i = 0; i < vertex_count; i++) { // Find first ocurrence of unique vertex. it = mVertices.find(i); aux_i = (*it).second; mGMVB->mPosition[i].x = vertex_buffer->mPosition[aux_i].x; mGMVB->mPosition[i].y = vertex_buffer->mPosition[aux_i].y; mGMVB->mPosition[i].z = vertex_buffer->mPosition[aux_i].z; mGMVB->mNormal[i].x = vertex_buffer->mNormal[aux_i].x; mGMVB->mNormal[i].y = vertex_buffer->mNormal[aux_i].y; mGMVB->mNormal[i].z = vertex_buffer->mNormal[aux_i].z; mGMVB->mTexCoords[i].x = vertex_buffer->mTexCoords[aux_i].x; mGMVB->mTexCoords[i].y = vertex_buffer->mTexCoords[aux_i].y; } // Fill up indices to unique vertices. // For each submesh. for (submesh = 0; submesh < mesh->mSubMeshCount; submesh++) { geosubmesh = &mesh->mSubMesh[submesh]; // Change indices. for (i = 0; i < geosubmesh->mIndexCount; i++) { // Unique index asociated to the given one. it_map = newindices.find(geosubmesh->mIndex[i]); geosubmesh->mIndex[i] = (*it_map).second; } } } //------------------------------------------------------------------------- // Modify the joined vertices sequento to an split. //------------------------------------------------------------------------- MeshSimplificationSequence * TextureConserver::WriteRealSimpSeq(MeshSimplificationSequence *simpseq) { bool edge_found; size_t v0; size_t v1; size_t vertex_count; size_t i,j; VertexBuffer *mVB; GeoVertex new_vertex; multimap::iterator lb0; multimap::iterator ub0; multimap::iterator lb1; multimap::iterator ub1; multimap::iterator it0; MeshSimplificationSequence *real_seq; MeshSimplificationSequence::Step current_step; // Initialize vertex count. vertex_count = mGeoMesh->mVertexBuffer->mVertexCount; // Creates new simplification sequence. real_seq = new MeshSimplificationSequence(); // For each simplification step. for (i = 0; i < simpseq->mSteps.size(); i++) { lb0 = mVertices.lower_bound(simpseq->mSteps[i].mV0); ub0 = mVertices.upper_bound(simpseq->mSteps[i].mV0); lb1 = mVertices.lower_bound(simpseq->mSteps[i].mV1); ub1 = mVertices.upper_bound(simpseq->mSteps[i].mV1); // Removed vertex. while (lb1 != ub1) { // Real index. v1 = (*lb1).second; // Begin of iteration v0. it0 = lb0; edge_found = false; // Remaining vertex. while (it0 != ub0) { // Real index. v0 = (*it0).second; // If edge exists. if (mEdges->exists(v0,v1)) { mEdges->contract(v1,v0); // Simplification sequence. current_step.mV0 = v0; current_step.mV1 = v1; real_seq->mSteps.push_back(current_step); edge_found = true; } it0++; } // If not found a valid edge. if (!edge_found) { // Id new vertex. new_vertex.id = vertex_count; new_vertex.bonefrom = v0; // Simplification sequence. current_step.mV0 = new_vertex.id; current_step.mV1 = v1; real_seq->mSteps.push_back(current_step); // Contracts lonely vertex. mEdges->contract(v1,new_vertex.id); // New vertex adquires position of v0. new_vertex.position.x = mGeoMesh->mVertexBuffer->mPosition[v0].x; new_vertex.position.y = mGeoMesh->mVertexBuffer->mPosition[v0].y; new_vertex.position.z = mGeoMesh->mVertexBuffer->mPosition[v0].z; // New vertex adquires normal of lonely one. new_vertex.normal.x = mGeoMesh->mVertexBuffer->mNormal[v1].x; new_vertex.normal.y = mGeoMesh->mVertexBuffer->mNormal[v1].y; new_vertex.normal.z = mGeoMesh->mVertexBuffer->mNormal[v1].z; // New vertex adquires the texture cood of the lonely one. new_vertex.texcoord.x = mGeoMesh->mVertexBuffer->mTexCoords[v1].x; new_vertex.texcoord.y = mGeoMesh->mVertexBuffer->mTexCoords[v1].y; // New vertex stored. real_seq->mNewVertices.push_back(new_vertex); // New vertex added. vertex_count++; } lb1++; } } // Assigns new simplification sequence. delete simpseq; return real_seq; /* // New vertex buffer to add new vertices. mVB = new VertexBuffer(); mVB->mPosition = new Vector3[vertex_count]; mVB->mNormal = new Vector3[vertex_count]; mVB->mTexCoords = new Vector2[vertex_count]; mVB->mVertexInfo = mGeoMesh->mVertexBuffer->mVertexInfo; // Copy original vertices. for (i = 0; i < mGeoMesh->mVertexBuffer->mVertexCount; i++) { mVB->mPosition[i].x = mGeoMesh->mVertexBuffer->mPosition[i].x; mVB->mPosition[i].y = mGeoMesh->mVertexBuffer->mPosition[i].y; mVB->mPosition[i].z = mGeoMesh->mVertexBuffer->mPosition[i].z; mVB->mNormal[i].x = mGeoMesh->mVertexBuffer->mNormal[i].x; mVB->mNormal[i].y = mGeoMesh->mVertexBuffer->mNormal[i].y; mVB->mNormal[i].z = mGeoMesh->mVertexBuffer->mNormal[i].z; mVB->mTexCoords[i].x = mGeoMesh->mVertexBuffer->mTexCoords[i].x; mVB->mTexCoords[i].y = mGeoMesh->mVertexBuffer->mTexCoords[i].y; } // Add new vertices. j = mGeoMesh->mVertexBuffer->mVertexCount; for (i = 0; i < new_vertices.size(); i++) { mVB->mPosition[j].x = new_vertices[i].position.x; mVB->mPosition[j].y = new_vertices[i].position.y; mVB->mPosition[j].z = new_vertices[i].position.z; mVB->mNormal[j].x = new_vertices[i].normal.x; mVB->mNormal[j].y = new_vertices[i].normal.y; mVB->mNormal[j].z = new_vertices[i].normal.z; mVB->mTexCoords[j].x = new_vertices[i].texcoord.x; mVB->mTexCoords[j].y = new_vertices[i].texcoord.y; } // Free memory. delete []mGeoMesh->mVertexBuffer; // Reassigns main vertex buffer with new vertices. mGeoMesh->mVertexBuffer = mVB; // Reassign submesh vertex buffers. for (i = 0; i < mGeoMesh->mSubMeshCount; i++) { mGeoMesh->mSubMesh[i].mVertexBuffer = mVB; } */ } //------------------------------------------------------------------------- // Return mesh that may have repeated vertices for texture aparence. //------------------------------------------------------------------------- Mesh *TextureConserver::GetMesh() { return mGeoMesh; }