$search
00001 /* 00002 Szymon Rusinkiewicz 00003 Stanford Graphics Lab 00004 00005 trimesh_plyio.cc 00006 Code for trimesh I/O to/from .ply files. 00007 This does not read and write generalized .ply files - only a very restricted 00008 subset. If you want more generalized ply I/O routines, look in 00009 http://graphics.stanford.edu/software/zippack/ 00010 (look for the link to download the original ply libraries) 00011 00012 On the other hand, the routines here are quite a bit more efficient in space 00013 and time for reading the most often-used variants of ply files. 00014 */ 00015 00016 #include <stdio.h> 00017 #include "trimesh.h" 00018 #include "trimesh_endian.h" 00019 00020 #ifdef WIN32 00021 #define strncasecmp strnicmp 00022 #endif 00023 00024 namespace trimesh { 00025 00026 // Is this (possibly) a ply file? 00027 bool TriMesh::IsPlyFile(const char *plyfile) 00028 { 00029 FILE *f = fopen(plyfile, "rb"); 00030 if (!f) 00031 return false; 00032 00033 char buf[4]; 00034 fgets(buf, 4, f); 00035 fclose(f); 00036 00037 return !strncmp(buf, "ply", 3); 00038 } 00039 00040 00041 // Read a triangle mesh from a plyfile. 00042 // 00043 // Note that only a few kinds of ply files are supported. 00044 // The particular conditions are: 00045 // 1. The ply files must be format binary_big_endian 1.0 00046 // or binary_little_endian 1.0 00047 // 2. "comment" and "obj_info" lines are allowed, but ignored 00048 // 3. There must be exactly one "element vertex" 00049 // 3a. The vertices must have x, y, and z (as floats) 00050 // 3b. The vertices may contain diffuse_{red,green,blue} (as uchar) 00051 // 3c. The vertices may contain confidence (as float) 00052 // 3d. Other vertex properties will be allowed if they are scalars (char, 00053 // uchar, int, uint, float). They will be silently ignored. 00054 // 4. There must be exactly one "element face" or "element tristrips" 00055 // 4a. If there are faces, the only property allowed is 00056 // property list uchar int vertex_indices, and all faces must be triangles 00057 // 4b. If there are tristrips, the only recognized syntax is 00058 // element tristrips 1 00059 // property list int int vertex_indices 00060 // and the tristrips are separated by an index of -1 00061 // 5. No other elements are allowed. 00062 // 00063 TriMesh *TriMesh::ReadPly(const char *plyfile) 00064 { 00065 TriMesh *newmesh = NULL; 00066 00067 bool need_swap; 00068 int numvertices = 0, numfaces = 0; 00069 00070 bool have_colors = false, have_conf = false; 00071 bool have_faces = false, have_tstrips = false; 00072 int other_prop_len, color_offset, conf_offset; 00073 00074 char buf[255]; 00075 int result; 00076 00077 00078 FILE *f = fopen(plyfile, "rb"); 00079 if (!f) { 00080 perror("fopen"); 00081 fprintf(stderr, "Can't open plyfile [%s]\n", plyfile); 00082 return NULL; 00083 } 00084 printf("Reading %s...\n", plyfile); 00085 00086 00087 // Read header 00088 if (!fgets(buf, 255, f) || strncmp(buf, "ply", 3)) { 00089 fprintf(stderr, "Not a ply file.\n"); 00090 return NULL; 00091 } 00092 00093 #define GET_LINE() if (!fgets(buf, 255, f)) goto plyreaderror 00094 #define LINE_IS(text) !strncasecmp(buf, text, strlen(text)) 00095 00096 GET_LINE(); 00097 if (LINE_IS("format binary_big_endian 1.0")) { 00098 need_swap = we_are_little_endian(); 00099 } else if (LINE_IS("format binary_little_endian 1.0")) { 00100 need_swap = we_are_big_endian(); 00101 } else { 00102 fprintf(stderr, "Can only read binary ply files.\n"); 00103 goto plyreaderror; 00104 } 00105 00106 GET_LINE(); 00107 while (LINE_IS("obj_info") || LINE_IS("comment")) 00108 GET_LINE(); 00109 00110 result = sscanf(buf, "element vertex %d\n", &numvertices); 00111 if (result != 1) { 00112 fprintf(stderr, "Expected \"element vertex\"\n"); 00113 goto plyreaderror; 00114 } 00115 00116 GET_LINE(); 00117 if (!LINE_IS("property float x") && !LINE_IS("property float32 x")) { 00118 fprintf(stderr, "Expected \"property float x\"\n"); 00119 goto plyreaderror; 00120 } 00121 00122 GET_LINE(); 00123 if (!LINE_IS("property float y") && !LINE_IS("property float32 y")) { 00124 fprintf(stderr, "Expected \"property float y\"\n"); 00125 goto plyreaderror; 00126 } 00127 00128 GET_LINE(); 00129 if (!LINE_IS("property float z") && !LINE_IS("property float32 z")) { 00130 fprintf(stderr, "Expected \"property float z\"\n"); 00131 goto plyreaderror; 00132 } 00133 00134 other_prop_len = 0; 00135 GET_LINE(); 00136 while (LINE_IS("property")) { 00137 if (LINE_IS("property char") || 00138 LINE_IS("property uchar") || 00139 LINE_IS("property int8") || 00140 LINE_IS("property uint8")) { 00141 other_prop_len += 1; 00142 } else if (LINE_IS("property short") || 00143 LINE_IS("property ushort") || 00144 LINE_IS("property int16") || 00145 LINE_IS("property uint16")) { 00146 other_prop_len += 2; 00147 } else if (LINE_IS("property int") || 00148 LINE_IS("property uint") || 00149 LINE_IS("property float") || 00150 LINE_IS("property int32") || 00151 LINE_IS("property uint32") || 00152 LINE_IS("property float32")) { 00153 other_prop_len += 4; 00154 } else if (LINE_IS("property double") || 00155 LINE_IS("property float64")) { 00156 other_prop_len += 8; 00157 } else { 00158 fprintf(stderr, "Unsupported vertex property: %s\n", buf); 00159 goto plyreaderror; 00160 } 00161 00162 if (LINE_IS("property uchar diffuse_red") || 00163 LINE_IS("property uint8 diffuse_red")) { 00164 have_colors = true; 00165 color_offset = other_prop_len - 1; 00166 } else if (LINE_IS("property float confidence") || 00167 LINE_IS("property float32 confidence")) { 00168 have_conf = true; 00169 conf_offset = other_prop_len - 4; 00170 } 00171 00172 GET_LINE(); 00173 } 00174 00175 00176 result = sscanf(buf, "element face %d", &numfaces); 00177 if (result == 1) { 00178 have_faces = true; 00179 GET_LINE(); 00180 if (!LINE_IS("property list uchar int vertex_indices") && 00181 !LINE_IS("property list uint8 int32 vertex_indices")) 00182 goto plyreaderror; 00183 GET_LINE(); 00184 } else if (LINE_IS("element tristrips 1")) { 00185 have_tstrips = true; 00186 GET_LINE(); 00187 if (!LINE_IS("property list int int vertex_indices") && 00188 !LINE_IS("property list int32 int32 vertex_indices")) 00189 goto plyreaderror; 00190 GET_LINE(); 00191 } 00192 00193 if (!LINE_IS("end_header")) { 00194 fprintf(stderr, "Expected \"end_header\"\n"); 00195 goto plyreaderror; 00196 } 00197 00198 00199 // OK, we think we've parsed the header. Slurp in the actual data... 00200 newmesh = new TriMesh(numvertices, numfaces); 00201 if (have_colors) 00202 newmesh->colors = new color[numvertices]; 00203 if (have_conf) 00204 newmesh->confidences = new conf[numvertices]; 00205 00206 printf(" Reading %d vertices... ", numvertices); fflush(stdout); 00207 for (int i=0; i<numvertices; i++) { 00208 if (!fread((void *)(newmesh->vertices[i]), 12, 1, f)) 00209 goto plyreaderror; 00210 if (need_swap) { 00211 swap_float(newmesh->vertices[i][0]); 00212 swap_float(newmesh->vertices[i][1]); 00213 swap_float(newmesh->vertices[i][2]); 00214 } 00215 00216 if (other_prop_len && !fread((void *)buf, other_prop_len, 1, f)) 00217 goto plyreaderror; 00218 00219 if (have_colors) { 00220 memcpy(&newmesh->colors[i][0], 00221 buf + color_offset, 00222 sizeof(color)); 00223 } 00224 if (have_conf) { 00225 memcpy(&newmesh->confidences[i], 00226 buf + conf_offset, 00227 sizeof(conf)); 00228 if (need_swap) 00229 swap_float(newmesh->confidences[i]); 00230 } 00231 } 00232 printf("Done.\n"); 00233 00234 if (have_tstrips) { 00235 printf(" Reading triangle strips... "); fflush(stdout); 00236 00237 if (!fread((void *)&newmesh->tstripdatalen, 4, 1, f)) 00238 goto plyreaderror; 00239 if (need_swap) 00240 swap_4(newmesh->tstripdatalen); 00241 00242 newmesh->tstrips = new int[newmesh->tstripdatalen]; 00243 if (!fread((void *)newmesh->tstrips, 4*newmesh->tstripdatalen, 1, f)) 00244 goto plyreaderror; 00245 if (need_swap) 00246 for (int t=0; t < newmesh->tstripdatalen; t++) 00247 swap_4(newmesh->tstrips[t]); 00248 } else if (have_faces) { 00249 printf(" Reading %d faces... ", numfaces); fflush(stdout); 00250 for (int i=0; i<numfaces; i++) { 00251 if (!fread((void *)buf, 1, 1, f)) 00252 goto plyreaderror; 00253 if (buf[0] != 3) { 00254 fprintf(stderr, "Non-triangle found in mesh.\n"); 00255 } 00256 if (!fread((void *)(newmesh->faces[i]), 12, 1, f)) 00257 goto plyreaderror; 00258 if (need_swap) { 00259 swap_4(newmesh->faces[i][0]); 00260 swap_4(newmesh->faces[i][1]); 00261 swap_4(newmesh->faces[i][2]); 00262 } 00263 } 00264 } 00265 printf("Done.\n"); 00266 00267 fgets(buf, 2, f); 00268 if (!feof(f)) { 00269 fprintf(stderr, "Warning: ignoring excess garbage at end of ply file.\n"); 00270 } 00271 00272 fclose(f); 00273 return newmesh; 00274 00275 plyreaderror: 00276 fclose(f); 00277 if (newmesh) 00278 delete newmesh; 00279 fprintf(stderr, "Error reading plyfile.\n"); 00280 return NULL; 00281 } 00282 00283 00284 // Write mesh to a ply file. Writes vertices, tstrips (if present), faces (if 00285 // no tstrips), colors, and confidences 00286 void TriMesh::WritePly(const char *plyfile) 00287 { 00288 bool need_swap = we_are_big_endian(); // Always write big-endian 00289 if (!vertices) { 00290 fprintf(stderr, "Empty mesh - nothing to write!\n"); 00291 return; 00292 } 00293 bool writetstrips = !!tstrips; 00294 bool writetriangles = (!writetstrips && !!vertices); 00295 00296 FILE *f = fopen(plyfile, "wb"); 00297 00298 if (!f) { 00299 fprintf(stderr, "Error: Can't open %s for writing.\n", plyfile); 00300 return; 00301 } 00302 00303 printf("Writing %s... ", plyfile); fflush(stdout); 00304 00305 // Write header 00306 fprintf(f, "ply\n" 00307 "format binary_big_endian 1.0\n"); 00308 00309 fprintf(f, "element vertex %d\n", numvertices); 00310 fprintf(f, "property float x\n" 00311 "property float y\n" 00312 "property float z\n"); 00313 if (colors) { 00314 fprintf(f, "property uchar diffuse_red\n" 00315 "property uchar diffuse_green\n" 00316 "property uchar diffuse_blue\n"); 00317 } 00318 if (confidences) { 00319 fprintf(f, "property float confidence\n"); 00320 } 00321 00322 if (writetstrips) { 00323 fprintf(f, "element tristrips 1\n"); 00324 fprintf(f, "property list int int vertex_indices\n"); 00325 } else if (writetriangles) { 00326 fprintf(f, "element face %d\n", numfaces); 00327 fprintf(f, "property list uchar int vertex_indices\n"); 00328 } 00329 fprintf(f, "end_header\n"); 00330 fflush(f); 00331 00332 // Write vertices 00333 for (int i=0; i<numvertices; i++) { 00334 if (need_swap) { 00335 float vv[3] = { vertices[i][0], 00336 vertices[i][1], 00337 vertices[i][2] }; 00338 swap_float(vv[0]); 00339 swap_float(vv[1]); 00340 swap_float(vv[2]); 00341 fwrite((void *)(vv), (sizeof(float)), 3, f); 00342 } else { 00343 fwrite((void *)(vertices[i]), sizeof(point), 1, f); 00344 } 00345 00346 if (colors) 00347 fwrite((void *)(colors[i]), sizeof(color), 1, f); 00348 if (confidences) { 00349 if (need_swap) { 00350 float c = confidences[i]; 00351 swap_float(c); 00352 fwrite((void *)&c, sizeof(float), 1, f); 00353 } else { 00354 fwrite((void *)&confidences[i], sizeof(float), 1, f); 00355 } 00356 } 00357 } 00358 00359 if (writetstrips) { 00360 if (need_swap) { 00361 int tmp = tstripdatalen; 00362 swap_4(tmp); 00363 fwrite((void *)&tmp, sizeof(int), 1, f); 00364 for (int i=0; i < tstripdatalen; i++) { 00365 tmp = tstrips[i]; 00366 swap_4(tmp); 00367 fwrite((void *)&tmp, sizeof(int), 1, f); 00368 } 00369 } else { 00370 fwrite((void *)&tstripdatalen, sizeof(int), 1, f); 00371 fwrite((void *)tstrips, 4*tstripdatalen, 1, f); 00372 } 00373 } else if (writetriangles) { 00374 char vertsperface = { 3 }; 00375 for (int i=0; i < numfaces; i++) { 00376 fwrite((void *)&vertsperface, 1, 1, f); 00377 if (need_swap) { 00378 int ff[3] = { faces[i][0], faces[i][1], faces[i][2] }; 00379 swap_4(ff[0]); 00380 swap_4(ff[1]); 00381 swap_4(ff[2]); 00382 fwrite((void *)ff, sizeof(face), 1, f); 00383 } else { 00384 fwrite((void *)(faces[i]), sizeof(face), 1, f); 00385 } 00386 } 00387 } 00388 00389 fclose(f); 00390 printf("Done.\n"); 00391 } 00392 00393 } // namespace trimesh 00394