OFX_OBJLOADER_BEGIN_NAMESPACE void load(string path, ofMesh& mesh, bool generateNormals, bool flipFace) { path = ofToDataPath(path); mesh.clear(); GLMmodel* m; m = glmReadOBJ((char*)path.c_str()); if (generateNormals) { glmFacetNormals(m); glmVertexNormals(m, 90); } if (flipFace) { glmReverseWinding(m); } for (int j = 0; j < m->numtriangles; j++) { const GLMtriangle &tri = m->triangles[j]; for (int k = 0; k < 3; k++) { GLfloat *v = m->vertices + (tri.vindices[k] * 3); mesh.addVertex(ofVec3f(v[0], v[1], v[2])); if (m->colors) { GLfloat *c = m->colors + (tri.vindices[k] * 3); mesh.addColor(ofFloatColor(c[0], c[1], c[2])); } if (m->normals && ofInRange(tri.nindices[k], 0, m->numnormals)) { GLfloat *n = m->normals + (tri.nindices[k] * 3); mesh.addNormal(ofVec3f(n[0], n[1], n[2])); } if (m->texcoords && ofInRange(tri.tindices[k], 0, m->numtexcoords)) { GLfloat *c = m->texcoords + (tri.tindices[k] * 2); mesh.addTexCoord(ofVec2f(c[0], c[1])); } } } glmDelete(m); }
void loadGroup(string path, map<string, ofMesh>& groups, bool generateNormals) { path = ofToDataPath(path); groups.clear(); GLMmodel* m; m = glmReadOBJ((char*)path.c_str()); if (generateNormals) { glmFacetNormals(m); } glmReverseWinding(m); GLMgroup *g = m->groups; while (g) { string name = g->name; ofMesh t; GLMtriangle *p = m->triangles; for (int j = 0; j < g->numtriangles; j++) { GLMtriangle tri = p[g->triangles[j]]; for (int k = 0; k < 3; k++) { GLfloat *v = m->vertices + (tri.vindices[k] * 3); t.addVertex(ofVec3f(v[0], v[1], v[2])); if (m->colors) { GLfloat *c = m->colors + (tri.vindices[k] * 3); t.addColor(ofFloatColor(c[0], c[1], c[2])); } if (m->normals && ofInRange(tri.nindices[k], 0, m->numnormals)) { GLfloat *n = m->normals + (tri.nindices[k] * 3); t.addNormal(ofVec3f(n[0], n[1], n[2])); } if (m->texcoords && ofInRange(tri.tindices[k], 0, m->numtexcoords)) { GLfloat *c = m->texcoords + (tri.tindices[k] * 2); t.addTexCoord(ofVec2f(c[0], c[1])); } } } groups[name] = t; g = g->next; } glmDelete(m); }
void saveGroup(string path, const vector<ofMesh> & meshGroup, bool flipFace, bool flipNormals) { path = ofToDataPath(path); ofFilePath::createEnclosingDirectory(path); GLuint writeMode = GLM_NONE; GLMmodel * m = new GLMmodel(); GLMgroup * group = NULL; int numOfVerticesTotal = 0; int numOfNormalsTotal = 0; int numOfTexCoordsTotal = 0; int numOfIndicesTotal = 0; int numOfTrianglesTotal = 0; for(int i=0; i<meshGroup.size(); i++) { const ofMesh & mesh = meshGroup[i]; numOfVerticesTotal += mesh.getNumVertices(); numOfNormalsTotal += mesh.getNumNormals(); numOfTexCoordsTotal += mesh.getNumTexCoords(); if(mesh.getNumIndices() > 0) { numOfIndicesTotal += mesh.getNumIndices(); } else { numOfIndicesTotal += mesh.getNumVertices(); } } // glm skips the first array element when exporting. // not sure why? // but it means everything needs to be padded by 1. numOfVerticesTotal += 1; numOfNormalsTotal += 1; numOfTexCoordsTotal += 1; if(numOfVerticesTotal > 0) { m->numvertices = numOfVerticesTotal; m->vertices = new GLfloat[m->numvertices * 3]; } if(numOfNormalsTotal > 0) { m->numnormals = numOfNormalsTotal; m->normals = new GLfloat[m->numnormals * 3]; } if(numOfTexCoordsTotal > 0) { m->numtexcoords = numOfTexCoordsTotal; m->texcoords = new GLfloat[m->numtexcoords * 2]; } if(numOfIndicesTotal > 0) { numOfTrianglesTotal = numOfIndicesTotal / 3; m->numtriangles = numOfTrianglesTotal; m->triangles = new GLMtriangle[m->numtriangles]; } int numOfVertices = 0; int numOfNormals = 0; int numOfTexCoords = 0; int numOfIndices = 0; int numOfTriangles = 0; int indexVertices = 1; int indexNormals = 1; int indexTexCoords = 1; int indexIndices = 0; int indexTriangles = 0; for(int k=0; k<meshGroup.size(); k++) { const ofMesh & mesh = meshGroup[k]; if(numOfVerticesTotal > 0) { numOfVertices = mesh.getNumVertices(); memcpy(&m->vertices[indexVertices * 3], &mesh.getVertices()[0].x, sizeof(ofVec3f) * numOfVertices); indexVertices += numOfVertices; } else { ofLogError("ofxObjLoader::save -- No vertices to save!"); return; } if(numOfNormalsTotal > 0) { numOfNormals = mesh.getNumNormals(); vector<ofVec3f> normals = mesh.getNormals(); if(flipNormals) { for(int i = 0; i < normals.size(); i++) { normals[i] *= -1; } } memcpy(&m->normals[indexNormals * 3], &normals[0].x, sizeof(ofVec3f) * numOfNormals); indexNormals += numOfNormals; writeMode |= GLM_SMOOTH; } if(numOfTexCoordsTotal > 0) { numOfTexCoords = mesh.getNumTexCoords(); memcpy(&m->texcoords[indexTexCoords * 2], &mesh.getTexCoords()[0].x, sizeof(ofVec2f) * numOfTexCoords); indexTexCoords += numOfTexCoords; writeMode |= GLM_TEXTURE; } numOfIndices = mesh.getNumIndices(); if(numOfIndices > 0) { numOfTriangles = numOfIndices / 3; } else { numOfTriangles = numOfVertices / 3; } GLMgroup * groupPrev = group; group = new GLMgroup(); group->next = NULL; group->material = NULL; if(m->groups == NULL) { m->groups = group; m->numgroups = 1; } if(groupPrev != NULL) { groupPrev->next = group; m->numgroups += 1; } string name = "ofMesh_" + ofToString(k); group->name = (char*)malloc(sizeof(char) * name.length() + 1); strcpy(group->name, name.c_str()); group->numtriangles = numOfTriangles; group->triangles = new GLuint[group->numtriangles]; const vector<ofIndexType> & indices = mesh.getIndices(); int index = 0; for(int i=0; i<numOfTriangles; i++) { int t = i + indexTriangles; for(int j=0; j<3; j++) { int idx = i * 3 + j; if(numOfIndices > 0) { index = indices[idx]; } else { index = idx; } index += (indexIndices + 1); m->triangles[t].vindices[j] = index; m->triangles[t].nindices[j] = index; m->triangles[t].tindices[j] = index; } group->triangles[i] = t; } indexIndices += numOfVertices; indexTriangles += numOfTriangles; } if(flipFace == true) { glmReverseWinding(m); } glmWriteOBJ(m, (char*)path.c_str(), writeMode); glmDelete(m); }
void save(string path, const ofMesh& mesh_, bool flipFace, bool flipNormals, bool export_vertexcolor_to_texture) { ofMesh mesh = mesh_; path = ofToDataPath(path); ofFilePath::createEnclosingDirectory(path); GLuint writeMode = GLM_NONE; GLMmodel* m = new GLMmodel(); if (export_vertexcolor_to_texture) { if (mesh.getMode() != OF_PRIMITIVE_TRIANGLES) { ofLogError("ofxObjLoader::save") << "vertex color to texture supported only triangle primitive"; } else { ofImage image; vertexColorToFaceColor(mesh); faceColorToTexture(mesh, image); ofFile file(path); string base_path = file.getEnclosingDirectory(); string material_name = file.getBaseName(); string image_name = material_name + ".png"; ofPixels pix = image.getPixelsRef(); // flip save texture pix.mirror(true, false); ofSaveImage(pix, ofFilePath::join(base_path, image_name)); string mtl_filename = material_name + ".mtl"; writeMode |= GLM_MATERIAL; m->mtllibname = (char*)malloc(mtl_filename.size()); strcpy(m->mtllibname, mtl_filename.c_str()); m->nummaterials = 1; m->materials = (GLMmaterial*)malloc(sizeof(GLMmaterial)); GLMmaterial *mat = &m->materials[0]; memset(mat, 0, sizeof(GLMmaterial)); for (int i = 0; i < 4; i++) { mat->diffuse[i] = 1; mat->ambient[i] = 1; mat->specular[i] = 1; mat->emmissive[i] = 1; } mat->shininess = 1; mat->name = (char*)malloc(material_name.size()); strcpy(mat->name, material_name.c_str()); mat->texture_path = (char*)malloc(image_name.size()); strcpy(mat->texture_path, image_name.c_str()); } } if (mesh.getNumVertices() > 0) { m->numvertices = mesh.getNumVertices(); m->vertices = new GLfloat[(m->numvertices + 1) * 3]; memcpy(&m->vertices[3], &mesh.getVertices()[0].x, sizeof(ofVec3f) * mesh.getNumVertices()); } else { ofLogError("ofxObjLoader::save -- No vertices to save!"); return; } if (mesh.getNumNormals() > 0) { m->numnormals = mesh.getNumNormals(); m->normals = new GLfloat[(m->numnormals + 1) * 3]; vector<ofVec3f> normals = mesh.getNormals(); if (flipNormals) for (int i = 0; i < normals.size(); i++) normals[i] *= -1; memcpy(&m->normals[3], &normals[0].x, sizeof(ofVec3f) * normals.size()); writeMode |= GLM_SMOOTH; } if (mesh.getNumTexCoords() > 0) { m->numtexcoords = mesh.getNumTexCoords(); m->texcoords = new GLfloat[(m->numtexcoords + 1) * 2]; memcpy(&m->texcoords[2], &mesh.getTexCoords()[0].x, sizeof(ofVec2f) * mesh.getNumTexCoords()); writeMode |= GLM_TEXTURE; } if (mesh.getNumIndices() > 0) { m->numtriangles = mesh.getNumIndices() / 3; m->triangles = new GLMtriangle[m->numtriangles]; m->groups = new GLMgroup(); m->groups->next = NULL; m->groups->material = NULL; string name = "ofMesh"; m->groups->name = (char*)malloc(sizeof(char) * name.length() + 1); strcpy(m->groups->name, name.c_str()); m->groups->numtriangles = mesh.getNumIndices() / 3; m->groups->triangles = new GLuint[m->groups->numtriangles]; m->numgroups = 1; for (int i = 0; i < mesh.getNumIndices(); i += 3) { int idx = i / 3; for (int j = 0; j < 3; j++) { m->triangles[idx].vindices[j] = mesh.getIndices()[i + j] + 1; m->triangles[idx].nindices[j] = mesh.getIndices()[i + j] + 1; m->triangles[idx].tindices[j] = mesh.getIndices()[i + j] + 1; } m->groups->triangles[idx] = idx; } } else { m->numtriangles = mesh.getNumVertices() / 3; m->triangles = new GLMtriangle[m->numtriangles]; m->groups = new GLMgroup(); m->groups->next = NULL; m->groups->material = NULL; string name = "ofMesh"; m->groups->name = (char*)malloc(sizeof(char) * name.length() + 1); strcpy(m->groups->name, name.c_str()); m->groups->numtriangles = mesh.getNumVertices() / 3; m->groups->triangles = new GLuint[m->groups->numtriangles]; m->numgroups = 1; for (int i = 0; i < mesh.getNumVertices(); i += 3) { int idx = i / 3; for (int j = 0; j < 3; j++) { m->triangles[idx].vindices[j] = i + j + 1; m->triangles[idx].nindices[j] = i + j + 1; m->triangles[idx].tindices[j] = i + j + 1; } m->groups->triangles[idx] = idx; } } if (flipFace) glmReverseWinding(m); glmWriteOBJ(m, (char*)path.c_str(), writeMode); glmDelete(m); }
void keyboard(unsigned char key, int x, int y) { GLint params[2]; switch (key) { case 'h': printf("help\n\n"); printf("w - Toggle wireframe/filled\n"); printf("c - Toggle culling\n"); printf("n - Toggle facet/smooth normal\n"); printf("b - Toggle bounding box\n"); printf("r - Reverse polygon winding\n"); printf("m - Toggle color/material/none mode\n"); printf("p - Toggle performance indicator\n"); printf("s/S - Scale model smaller/larger\n"); printf("t - Show model stats\n"); printf("o - Weld vertices in model\n"); printf("+/- - Increase/decrease smoothing angle\n"); printf("W - Write model to file (out.obj)\n"); printf("q/escape - Quit\n\n"); break; case 't': stats = !stats; break; case 'p': performance = !performance; break; case 'm': material_mode++; if (material_mode > 2) material_mode = 0; printf("material_mode = %d\n", material_mode); lists(); break; case 'd': glmDelete(model); init(); lists(); break; case 'w': glGetIntegerv(GL_POLYGON_MODE, params); if (params[0] == GL_FILL) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break; case 'c': if (glIsEnabled(GL_CULL_FACE)) glDisable(GL_CULL_FACE); else glEnable(GL_CULL_FACE); break; case 'b': bounding_box = !bounding_box; break; case 'n': facet_normal = !facet_normal; lists(); break; case 'r': glmReverseWinding(model); lists(); break; case 's': glmScale(model, 0.8); lists(); break; case 'S': glmScale(model, 1.25); lists(); break; case 'o': //printf("Welded %d\n", glmWeld(model, weld_distance)); glmVertexNormals(model, smoothing_angle); lists(); break; case 'O': weld_distance += 0.01; printf("Weld distance: %.2f\n", weld_distance); glmWeld(model, weld_distance); glmFacetNormals(model); glmVertexNormals(model, smoothing_angle); lists(); break; case '-': smoothing_angle -= 1.0; printf("Smoothing angle: %.1f\n", smoothing_angle); glmVertexNormals(model, smoothing_angle); lists(); break; case '+': smoothing_angle += 1.0; printf("Smoothing angle: %.1f\n", smoothing_angle); glmVertexNormals(model, smoothing_angle); lists(); break; case 'W': glmScale(model, 1.0/scale); glmWriteOBJ(model, "out.obj", GLM_SMOOTH | GLM_MATERIAL); break; case 'R': { GLuint i; GLfloat swap; for (i = 1; i <= model->numvertices; i++) { swap = model->vertices[3 * i + 1]; model->vertices[3 * i + 1] = model->vertices[3 * i + 2]; model->vertices[3 * i + 2] = -swap; } glmFacetNormals(model); lists(); break; } case 27: exit(0); break; } glutPostRedisplay(); }