/* * PLY.cpp * PointProcessing * * Created by Renato Pajarola on Wed Nov 05 2003. * Copyright (c) 2003 __MyCompanyName__. All rights reserved. * */ #include #include #include #include #ifdef __APPLE__ #include #else #include #endif #include #include #include "PLY.h" #include "geometry.h" extern int box; extern int wire; extern int flat; extern int triangles; extern Vector3f light_pos, viewer_pos; extern Vector4f light_color, ambient_light; GLfloat diffuse[4] = {0.7, 0.7, 1.0, 1.0}; GLfloat specular[4] = {0.5, 0.5, 0.5, 1.0}; GLfloat shininess[1] = {5.0}; GLfloat white[4] = {1.0, 1.0, 1.0, 1.0}; PLYObject::PLYObject(FILE *in) { int i; nproperties = 0; hasnormal = hascolor = hastexture = hasedges = false; nv = nf = ne = 0; vertices = NULL; normals = NULL; colors = NULL; texcoords = NULL; faces = NULL; // init bounding box for (i = 0; i < 3; i++) { min[i] = FLT_MAX; max[i] = -FLT_MAX; } // default order for (i = 0; i < 11; i++) order[i] = -1; if (!checkHeader(in)) { fprintf(stderr, "Error: could not read PLY file.\n"); return; } vertices = (Vector3f*)calloc(nv, sizeof(Vector3f)); normals = (Vector3f*)calloc(nv, sizeof(Vector3f)); if (hascolor) colors = (Color3u*)calloc(nv, sizeof(Color3u)); if (hastexture) texcoords = (Texture2f*)calloc(nv, sizeof(Texture2f)); faces = (Index3i*)calloc(nf, sizeof(Index3i)); edges = (Index2i*)calloc(3*nf, sizeof(Index3i)); nodes = (Index3i*)calloc(nf, sizeof(Index3i)); fnormals = (Vector3f*)calloc(nf, sizeof(Vector3f)); readVertices(in); readFaces(in); findConnectivity(); invertNormals(); printf("#vertices: %d\n", nv); printf("#faces: %d\n", nf); printf("#edges: %d\n", ne); } PLYObject::~PLYObject() { // delete all allocated arrays if (vertices) free(vertices); if (normals) free(normals); if (colors) free(colors); if (texcoords) free(texcoords); if (faces) free(faces); } bool PLYObject::checkHeader(FILE *in) { char buf[128], type[128], c[32]; int i; // read ply file header fscanf(in, "%s\n", buf); if (strcmp(buf, "ply") != 0) { fprintf(stderr, "Error: Input file is not of .ply type.\n"); return false; } fgets(buf, 128, in); if (strncmp(buf, "format ascii", 12) != 0) { fprintf(stderr, "Error: Input file is not in ASCII format.\n"); //return false; } fgets(buf, 128, in); while (strncmp(buf, "comment", 7) == 0) fgets(buf, 128, in); // read number of vertices if (strncmp(buf, "element vertex", 14) == 0) sscanf(buf, "element vertex %d\n", &nv); else { fprintf(stderr, "Error: number of vertices expected.\n"); return false; } // read vertex properties order i = 0; fgets(buf, 128, in); while (strncmp(buf, "property", 8) == 0) { sscanf(buf, "property %s %s\n", type, c); if (strncmp(c, "x", 1) == 0) order[0] = i; else if (strncmp(c, "y", 1) == 0) order[1] = i; else if (strncmp(c, "z", 1) == 0) order[2] = i; else if (strncmp(c, "nx", 2) == 0) order[3] = i; else if (strncmp(c, "ny", 2) == 0) order[4] = i; else if (strncmp(c, "nz", 2) == 0) order[5] = i; else if (strncmp(c, "red", 3) == 0) order[6] = i; else if (strncmp(c, "green", 5) == 0) order[7] = i; else if (strncmp(c, "blue", 4) == 0) order[8] = i; else if (strncmp(c, "tu", 2) == 0) order[9] = i; else if (strncmp(c, "tv", 2) == 0) order[10] = i; i++; fgets(buf, 128, in); } nproperties = i; for (i = 0; i < 3; i++) { if (order[i] < 0) { fprintf(stderr, "Error: not enough vertex coordinate fields (nx, ny, nz).\n"); return false; } } hasnormal = true; for (i = 3; i < 6; i++) if (order[i] < 0) hasnormal = false; hascolor = true; for (i = 6; i < 9; i++) if (order[i] < 0) hascolor = false; hastexture = true; for (i = 9; i < 11; i++) if (order[i] < 0) hastexture = false; if (!hasnormal) fprintf(stderr, "Warning: no normal coordinates used from file.\n"); if (!hascolor) fprintf(stderr, "Warning: no color used from file.\n"); if (!hastexture) fprintf(stderr, "Warning: no texture coordinates used from file.\n"); // number of faces and face properties if (strncmp(buf, "element face", 12) == 0) sscanf(buf, "element face %d\n", &nf); else { fprintf(stderr, "Error: number of faces expected.\n"); return false; } /* Only for MAnifolds Beware */ /* Though is the maximum for boundary too.. */ ne = 3 * nf /2; fgets(buf, 128, in); if (strncmp(buf, "property list", 13) != 0) { fprintf(stderr, "Error: property list expected.\n"); return false; } fgets(buf, 128, in); while (strncmp(buf, "end_header", 10) != 0) fgets(buf, 128, in); return true; } void PLYObject::readVertices(FILE *in) { char buf[128]; int i, j; float values[32]; // read in vertex attributes for (i = 0; i < nv; i++) { fgets(buf, 128, in); sscanf(buf,"%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f", &values[0], &values[1], &values[2], &values[3], &values[4], &values[5], &values[6], &values[7], &values[8], &values[9], &values[10], &values[11], &values[12], &values[13], &values[14], &values[15]); for (j = 0; j < 3; j++) vertices[i][j] = values[order[j]]; if (hasnormal) for (j = 0; j < 3; j++) normals[i][j] = values[order[3+j]]; if (hascolor) for (j = 0; j < 3; j++) colors[i][j] = (unsigned char)values[order[6+j]]; if (hastexture) for (j = 0; j < 2; j++) texcoords[i][j] = values[order[9+j]]; for (j = 0; j < 3; j++) { if (vertices[i][j] < min[j]) min[j] = vertices[i][j]; if (vertices[i][j] > max[j]) max[j] = vertices[i][j]; } } } void PLYObject::readFaces(FILE *in) { char buf[128]; int i, j, k; // read in face connectivity for (i = 0; i < nf; i++) { fgets(buf, 128, in); sscanf(buf, "%d %d %d %d", &k, &faces[i][0], &faces[i][1], &faces[i][2]); if (k != 3) { fprintf(stderr, "Error: not a triangular face : %d.\n",k); exit(1); } // set up face normal normal(fnormals[i], vertices[faces[i][0]], vertices[faces[i][1]], vertices[faces[i][2]]); // accumulate normal information of each vertex if (!hasnormal) for (j = 0; j < 3; j++) for (k = 0; k < 3; k++) normals[faces[i][j]][k] += fnormals[i][k]; } if (!hasnormal) for (i = 0; i < nv; i++) normalize(normals[i]); hasnormal = true; } void PLYObject::resize() { int i; float size, scale; Vector3f tmin, tmax; // rescale vertex coordinates to be in [-1,1] size = 0.0; if (size < max[0]-min[0]) size = max[0]-min[0]; if (size < max[1]-min[1]) size = max[1]-min[1]; if (size < max[2]-min[2]) size = max[2]-min[2]; scale = 2.0 / size; for (i = 0; i < nv; i++) { vertices[i][0] = scale * (vertices[i][0] - 0.5*(max[0]+min[0])); vertices[i][1] = scale * (vertices[i][1] - 0.5*(max[1]+min[1])); vertices[i][2] = scale * (vertices[i][2] - 0.5*(max[2]+min[2])); } for (i = 0; i < 3; i++) { tmin[i] = scale * 0.5 * (min[i]-max[i]); tmax[i] = scale * 0.5 * (max[i]-min[i]); } for (i = 0; i < 3; i++) { min[i] = tmin[i]; max[i] = tmax[i]; } } Geometry::Vector3Df PLYObject::faceCenter(int f) { Geometry::Vector3Df sum; for (int v=0 ; v<3 ; v++) sum += Geometry::Vector3Df(vertices[ faces[f][v] ]) / 3; return sum; } bool PLYObject::areAdjacent(int f1, int f2) { if (f1 == f2) return false; int commonVertices = 0; for (int i=0 ; i<3 ; i++) for (int j=0 ; j<3 ; j++) { if (faces[f1][i] == faces[f2][j]) commonVertices++; } if (2 == commonVertices) return true; else return false; } bool PLYObject::alreadyConnected(int f1, int f2) { for (int e=0 ; e<3 ; e++) { if (-1 == nodes[f1][e]) break; // Check for edges connecting (f1,f2) if (f1 == edges[nodes[f1][e]][0] && f2 == edges[nodes[f1][e]][1]) return true; if (f2 == edges[nodes[f1][e]][0] && f1 == edges[nodes[f1][e]][1]) return true; } return false; } // Appends void PLYObject::appendEdge(int face, int edge) { // printf("edge %4d (%4d,%4d) -> face %d\n", edge, edges[edge][0], edges[edge][1], face); for (int e=0 ; e<3 ; e++) { if (-1 == nodes[face][e]) { nodes[face][e] = edge; return; } } fprintf(stderr, "ERROR: Face %d has more than 3 edges, when assigning edge %d\n", face, edge); exit(-1); } // Finds the connectivity between faces in the model void PLYObject::findConnectivity() { // Initialize the 'nodes' array to being empty for (int f=0 ; f > facesPerVertex(nv); for (int f=0 ; f::iterator it, it2; for (it=facesPerVertex[v].begin() ; it !=facesPerVertex[v].end() ; it++) for (it2=it ; it2 != facesPerVertex[v].end() ; it2++) if (areAdjacent(*it, *it2) ) { if ( alreadyConnected(*it, *it2) ) continue; edges[edgeCount][0] = *it; edges[edgeCount][1] = *it2; appendEdge(*it, edgeCount); appendEdge(*it2, edgeCount); edgeCount++; } } printf("edgeCount = %d, ne = %d\n", edgeCount, ne); ne = edgeCount; // assert (edgeCount == ne); hasedges = true; } void PLYObject::invertNormals() { int i, tmp; for (i = 0; i < nv; i++) scale(normals[i], -1.0); for (i = 0; i < nf; i++) { scale(fnormals[i], -1.0); tmp = faces[i][0]; faces[i][0] = faces[i][2]; faces[i][2] = tmp; } } void PLYObject::draw() { int i, j; if (box) { glDisable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); glColor3f(1.0, 0.0, 0.0); glPointSize(5.0); glBegin(GL_LINE_LOOP); glVertex3f(min[0], min[1], min[2]); glVertex3f(min[0], min[1], max[2]); glVertex3f(min[0], max[1], max[2]); glVertex3f(min[0], max[1], min[2]); glEnd(); glBegin(GL_LINE_LOOP); glVertex3f(max[0], max[1], max[2]); glVertex3f(max[0], max[1], min[2]); glVertex3f(max[0], min[1], min[2]); glVertex3f(max[0], min[1], max[2]); glEnd(); glBegin(GL_LINES); glVertex3f(min[0], min[1], min[2]); glVertex3f(max[0], min[1], min[2]); glVertex3f(min[0], min[1], max[2]); glVertex3f(max[0], min[1], max[2]); glVertex3f(min[0], max[1], max[2]); glVertex3f(max[0], max[1], max[2]); glVertex3f(min[0], max[1], min[2]); glVertex3f(max[0], max[1], min[2]); glEnd(); } // setup default material glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, diffuse); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular); glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess); glColor3fv(diffuse); // setup per-point color mode if (hascolor) { glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); } // render wireframe model if (wire) { glDisable(GL_LIGHTING); // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glColor3f(0.0, 0.0, 0.0); glLineWidth(2.5); for (i = 0; i < nf; i++) { glBegin(GL_LINE_LOOP); for (j = 0; j < 3; j++) glVertex3fv(vertices[faces[i][j]]); // vertex coordinates glEnd(); } glLineWidth(1); // glEnable(GL_POLYGON_OFFSET_FILL); // glPolygonOffset(0.5, 1.0); } // setup texture mode if (hastexture) { glEnable(GL_TEXTURE_2D); // setup white object color for use with texture modulation glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, white); } // set lighting if enabled glEnable(GL_LIGHTING); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); if (triangles) { glBegin(GL_TRIANGLES); for (i = 0; i < nf; i++) { if (flat) glNormal3fv(fnormals[i]); // face normal for (j = 0; j < 3; j++) { if (hascolor) glColor3ubv((GLubyte*)colors[faces[i][j]]); if (hastexture) glTexCoord2fv(texcoords[faces[i][j]]); // set texture coordinates if (!flat) glNormal3fv(normals[faces[i][j]]); // vertex normal glVertex3fv(vertices[faces[i][j]]); // vertex coordinates } } glEnd(); } glDisable(GL_POLYGON_OFFSET_FILL); if (hascolor) glDisable(GL_COLOR_MATERIAL); if (hastexture) glDisable(GL_TEXTURE_2D); }