#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) { objmesh = m; mGeoMesh = NULL; msimpsequence = NULL; indexMeshLeaves = -1; // Sets the actual progress bar function. mUPB = upb; } //--------------------------------------------------------------------------- // MeshSimplifier destroyer. //--------------------------------------------------------------------------- MeshSimplifier::~MeshSimplifier() { delete msimpsequence; } //--------------------------------------------------------------------------- // Returns the simplified mesh. //--------------------------------------------------------------------------- Mesh * MeshSimplifier::GetMesh() { return mGeoMesh; } //--------------------------------------------------------------------------- // Set submesh leaves //--------------------------------------------------------------------------- void MeshSimplifier::setMeshLeaves(Index index) { indexMeshLeaves = index; } //--------------------------------------------------------------------------- // Returns the simplification sequence for general meshes. //--------------------------------------------------------------------------- MeshSimplificationSequence *MeshSimplifier::GetSimplificationSequence() { return msimpsequence; } //////////////////////////////////////////////////////////////////////////// // // // GeometryBasedSimplifier class // // // //////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- GeometryBasedSimplifier::GeometryBasedSimplifier( const Mesh *m, TIPOFUNC upb) :MeshSimplifier(m,upb) { } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- 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(); 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(); delete m_qslim; } //////////////////////////////////////////////////////////////////////////// // // // ViewPointDrivenSimplifier class // // // //////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- /// Class constructor. Will call Simplifier class constructor. //--------------------------------------------------------------------------- ViewPointDrivenSimplifier::ViewPointDrivenSimplifier( const Mesh *m, TIPOFUNC upb) :MeshSimplifier(m,upb) { //char s[MAX_CHAR]; // 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::cameraType = 2; 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); mGeoMesh = new Mesh(); *mGeoMesh = *m; // Transform NoSV Mesh to a SV Mesh. mGeoMesh = mGeoMesh->toSharedVertex(); // Loads the vmi mesh structure for a geometry mesh given. VMI::mesh = initMeshStructure(mGeoMesh); //VMI::printMesh(mesh); //getchar(); // Get a filename without extension //strncpy(VMI::filename, argv[argc - 1], strlen(argv[argc - 1]) - 4); //glutInit(&argc, argv); // RGB and Alpha. glutInitDisplayMode(GLUT_DEPTH | GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA); glutInitWindowSize(VMI::width, VMI::height); glutInitWindowPosition(100, 100); //#ifdef KL // Kullback-Leibler // sprintf(s, "VKL - [%s]", argv[argc-1]); //#endif //#ifdef MI // Mutual Information // sprintf(s, "VMI - [%s]", argv[argc-1]); //#endif //#ifdef HE // Hellinger // sprintf(s, "VHE - [%s]", argv[argc-1]); //#endif //#ifdef CS // Chi-Square // sprintf(s, "VCS - [%s]", argv[argc-1]); //#endif VMI::vmiWin = glutCreateWindow("VMI"/*s*/); glewInit(); VMI::init(); if (VMI::bLoadCamerasFromFile == GL_FALSE) { switch (VMI::cameraType) { case 0: VMI::cameras = VMI::setCameras(VMI::radius, OCTAHEDRON, &VMI::numCameras); printf("Number of cameras: %d\n", OCTAHEDRON); break; case 1: VMI:: cameras = VMI::setCameras(VMI::radius, ICOSAHEDRON, &VMI::numCameras); printf("Number of cameras: %d\n", ICOSAHEDRON); break; case 2: VMI::cameras = VMI::setCameras(VMI::radius, DODECAHEDRON, &VMI::numCameras); printf("Number of cameras: %d\n", DODECAHEDRON); break; default: break; } } else { // Loads a cameras file //sprintf(s,"%s.cam", VMI::filename); //VMI::cameras = VMI::loadCameras(VMI::radius, s, &VMI::numCameras); //getchar(); } VMI::histogram = VMI::initHistogram( VMI::mesh->currentNumTriangles, VMI::numCameras); VMI::initialIs = VMI::initIs(VMI::numCameras); } //--------------------------------------------------------------------------- /// Class destructor. //--------------------------------------------------------------------------- ViewPointDrivenSimplifier::~ViewPointDrivenSimplifier(void) { // Free memory VMI::freeMemory(); } /// Copy constructor //ViewPointDrivenSimplifier(const ViewPointDrivenSimplifier&); /// Assignment operator //ViewPointDrivenSimplifier& operator =(const ViewPointDrivenSimplifier&); /// 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) { // TODO: parametros libreria globales VMI::numDemandedTriangles = (int)(VMI::mesh->numTriangles * percent); if ((VMI::numDemandedTriangles == 0) || (VMI::numDemandedTriangles >= VMI::mesh->currentNumTriangles)) { printf("Illegal number of triangles.\n"); } VMI::display(); // Load a geometry mesh for vmi mesh. loadMesh(); GetMeshSimpSequence(); } //--------------------------------------------------------------------------- /// 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(); // Load a geometry mesh for vmi mesh. loadMesh(); GetMeshSimpSequence(); } // Returns the simplified mesh. //Mesh * ViewPointDrivenSimplifier::GetMesh() //{ // return mGeoMesh; //} //--------------------------------------------------------------------------- // Gets the VMI mesh simplification sequence. //--------------------------------------------------------------------------- void ViewPointDrivenSimplifier::GetMeshSimpSequence() { unsigned int j = 0; MeshSimplificationSequence::Step current_step; msimpsequence = new MeshSimplificationSequence(); // Debug. cout << "GetMeshsimpSequence VMI" << endl; // For each simplification step. for (unsigned int i = 0; i < VMI::mVMISteps.size(); i++) { current_step.mV0 = VMI::mVMISteps[i].mV0; current_step.mV1 = VMI::mVMISteps[i].mV1; current_step.mT0 = VMI::mVMISteps[i].mT0; current_step.mT1 = VMI::mVMISteps[i].mT1; current_step.x = VMI::mVMISteps[i].x; current_step.y = VMI::mVMISteps[i].y; current_step.z = VMI::mVMISteps[i].z; current_step.obligatorio = VMI::mVMISteps[i].obligatory; // For each face modificated. while (j < VMI::mVMISteps[i].mModfaces.size()) { current_step.mModfaces.push_back(VMI::mVMISteps[i].mModfaces[j]); j++; } // Debug. cout << "Step " << i << " added." << endl; msimpsequence->mSteps.push_back(current_step); } } //--------------------------------------------------------------------------- // Init vmi mesh structure for a geometry mesh given. //--------------------------------------------------------------------------- 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 < mGeoMesh->mSubMeshCount; submesh++) { mesh_index_count += int(mGeoMesh->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; } printf("Ok\n"); vmi_mesh->numVertices = int(vertex_buffer->mVertexCount); vmi_mesh->currentNumVertices = int(vertex_buffer->mVertexCount); // Fill up triangles. printf("Adding triangles..."); // Initialize index of triangle. index = 0; // For each submesh. for (unsigned int submesh = 0; submesh < mGeoMesh->mSubMeshCount; submesh++) { // Gets actual submesh. geosubmesh = &mGeoMesh->mSubMesh[submesh]; 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]); //printf("\n%d a: %f",index , vmi_mesh->triangles[index].area); 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("\n"); 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); } // Init edges for (i=0; inumTriangles * 3; i++) { vmi_mesh->edges[i].triangles = NULL; vmi_mesh->edges[i].numTriangles = 0; } printf("Adding edges..."); n = 0; for (i=0; inumTriangles; 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].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); //printf("n:%d i:%d\n", n, 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); //printf("n:%d i:%d\n", e, 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].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); //printf("n:%d i:%d\n", n, 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); //printf("n:%d i:%d\n", e, 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].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); //printf("n:%d i:%d\n", n, 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); //printf("n:%d i:%d\n", e, 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; 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 (unsigned int submesh = 0; submesh < mGeoMesh->mSubMeshCount; submesh++) { geosubmesh = &mGeoMesh->mSubMesh[submesh]; delete []geosubmesh->mIndex; // Initialize submesh index count; num_indices = 0; // For each triangle. for (unsigned int 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 Index[geosubmesh->mIndexCount]; // Initialize number of indices. num_indices = 0; // Fill up indices. for (unsigned int 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 (unsigned int 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; found = false; // Shared vertex buffer. vertex_buffer = mGeoMesh->mVertexBuffer; index = mGeoMesh->mSubMesh[submesh].mIndex[elem]; i = 0; while (!found && (i < mVB->mVertexCount)) { if ((VMI::mesh->vertices[index].x == mVB->mPosition[i].x) && (VMI::mesh->vertices[index].y == mVB->mPosition[i].y) && (VMI::mesh->vertices[index].z == mVB->mPosition[i].z)) { found = true; // Update index. mGeoMesh->mSubMesh[submesh].mIndex[elem] = i; } // Increments index. i++; } if (!found) { // Last element. new_elem = int(mVB->mVertexCount); // Add to last. mVB->mPosition[new_elem].x = VMI::mesh->vertices[index].x; mVB->mPosition[new_elem].y = VMI::mesh->vertices[index].y; mVB->mPosition[new_elem].z = VMI::mesh->vertices[index].z; mVB->mNormal[new_elem].x = vertex_buffer->mNormal[index].x; mVB->mNormal[new_elem].y = vertex_buffer->mNormal[index].y; mVB->mNormal[new_elem].z = vertex_buffer->mNormal[index].z; mVB->mTexCoords[new_elem].x = vertex_buffer->mTexCoords[index].x; mVB->mTexCoords[new_elem].y = vertex_buffer->mTexCoords[index].y; // Update index. mGeoMesh->mSubMesh[submesh].mIndex[elem] = new_elem; // Increments vertex count. mVB->mVertexCount++; } }