00001 /* 00002 File: PLYFile.cc 00003 00004 Function: 00005 00006 Authors: Greg Turk, Andrew Willmott 00007 00008 Notes: 00009 */ 00010 00011 #include "ply.h" 00012 #include "gcl/SceneLang.h" 00013 #include "gcl/VecUtil.h" 00014 00015 /* 00016 00017 Based on example programs by: 00018 00019 Greg Turk 00020 00021 ----------------------------------------------------------------------- 00022 00023 Copyright (c) 1998 Georgia Institute of Technology. All rights reserved. 00024 00025 Permission to use, copy, modify and distribute this software and its 00026 documentation for any purpose is hereby granted without fee, provided 00027 that the above copyright notice and this permission notice appear in 00028 all copies of this software and that you do not sell the software. 00029 00030 THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, 00031 EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 00032 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 00033 00034 */ 00035 00036 /* user's vertex and face definitions for a polygonal object */ 00037 00038 struct Vertex 00039 { 00040 float x, y, z; 00041 float nx, ny, nz; 00042 unsigned char r, g, b; 00043 void *other_props; /* other properties */ 00044 }; 00045 00046 struct Face 00047 { 00048 unsigned char nverts; /* number of vertex indices in list */ 00049 int *verts; /* vertex index list */ 00050 void *other_props; /* other properties */ 00051 }; 00052 00053 struct TriStrips 00054 { 00055 int nverts; /* number of vertex indices in list */ 00056 int *verts; /* vertex index list */ 00057 void *other_props; /* other properties */ 00058 }; 00059 00060 char *elem_names[] = { /* list of the kinds of elements in the user's object */ 00061 "vertex", "face", "tristrips" 00062 }; 00063 00064 PlyProperty vert_props[] = { /* list of property information for a vertex */ 00065 {"x", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex, x), 0, 0, 0, 0}, 00066 {"y", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex, y), 0, 0, 0, 0}, 00067 {"z", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex, z), 0, 0, 0, 0}, 00068 {"nx", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex, nx), 0, 0, 0, 0}, 00069 {"ny", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex, ny), 0, 0, 0, 0}, 00070 {"nz", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex, nz), 0, 0, 0, 0}, 00071 {"red", PLY_UCHAR, PLY_UCHAR, offsetof(Vertex, r), 0, 0, 0, 0}, 00072 {"green", PLY_UCHAR, PLY_UCHAR, offsetof(Vertex, g), 0, 0, 0, 0}, 00073 {"blue", PLY_UCHAR, PLY_UCHAR, offsetof(Vertex, b), 0, 0, 0, 0}, 00074 }; 00075 00076 PlyProperty face_props[] = { /* list of property information for a vertex */ 00077 {"vertex_indices", PLY_INT, PLY_INT, offsetof(Face, verts), 00078 1, PLY_UCHAR, PLY_UCHAR, offsetof(Face, nverts)}, 00079 }; 00080 00081 PlyProperty tristrip_props[] = { /* list of property information for a vertex */ 00082 {"vertex_indices", PLY_INT, PLY_INT, offsetof(TriStrips, verts), 00083 1, PLY_INT, PLY_INT, offsetof(TriStrips, nverts)}, 00084 }; 00085 00086 /*** the PLY object ***/ 00087 00088 static int nverts, nfaces, ntristrips; 00089 static Vertex *vlist; 00090 static Face *flist; 00091 static TriStrips *tslist; 00092 static PlyOtherElems *other_elements = NULL; 00093 static PlyOtherProp *vert_other, *face_other, *tristrip_other; 00094 static int nelems; 00095 static char **elist; 00096 static int num_comments; 00097 static char **comments; 00098 static int num_obj_info; 00099 static char **obj_info; 00100 static int file_type; 00101 00102 static int has_normals, has_rgb; /* are normals in PLY file? */ 00103 00104 00105 /****************************************************************************** 00106 Read in the PLY file from standard in. 00107 ******************************************************************************/ 00108 00109 void read_file(FILE *file) 00110 { 00111 int i, j, k; 00112 PlyFile *ply; 00113 int nprops; 00114 int num_elems; 00115 PlyProperty **plist; 00116 char *elem_name; 00117 float version; 00118 00119 00120 /*** Read in the original PLY object ***/ 00121 00122 00123 ply = ply_read (file, &nelems, &elist); 00124 ply_get_info (ply, &version, &file_type); 00125 00126 for (i = 0; i < nelems; i++) 00127 { 00128 00129 /* get the description of the first element */ 00130 elem_name = elist[i]; 00131 plist = ply_get_element_description (ply, elem_name, &num_elems, &nprops); 00132 00133 if (equal_strings ("vertex", elem_name)) 00134 { 00135 00136 /* see if vertex holds any normal information */ 00137 has_normals = has_rgb = 0; 00138 for (j = 0; j < nprops; j++) 00139 { 00140 if (equal_strings ("nx", plist[j]->name)) has_normals = 1; 00141 if (equal_strings ("red", plist[j]->name)) has_rgb = 1; 00142 } 00143 00144 /* create a vertex list to hold all the vertices */ 00145 vlist = (Vertex *) malloc (sizeof (Vertex) * num_elems); 00146 nverts = num_elems; 00147 00148 /* set up for getting vertex elements */ 00149 00150 ply_get_property (ply, elem_name, &vert_props[0]); 00151 ply_get_property (ply, elem_name, &vert_props[1]); 00152 ply_get_property (ply, elem_name, &vert_props[2]); 00153 if (has_normals) 00154 { 00155 ply_get_property (ply, elem_name, &vert_props[3]); 00156 ply_get_property (ply, elem_name, &vert_props[4]); 00157 ply_get_property (ply, elem_name, &vert_props[5]); 00158 } 00159 if (has_rgb) 00160 { 00161 ply_get_property (ply, elem_name, &vert_props[6]); 00162 ply_get_property (ply, elem_name, &vert_props[7]); 00163 ply_get_property (ply, elem_name, &vert_props[8]); 00164 } 00165 vert_other = ply_get_other_properties (ply, elem_name, 00166 offsetof(Vertex, other_props)); 00167 00168 /* grab all the vertex elements */ 00169 for (j = 0; j < num_elems; j++) 00170 ply_get_element (ply, (void *) (vlist + j)); 00171 } 00172 else if (equal_strings ("face", elem_name)) 00173 { 00174 00175 /* create a list to hold all the face elements */ 00176 flist = (Face *) malloc (sizeof(Face) * num_elems); 00177 nfaces = num_elems; 00178 00179 /* set up for getting face elements */ 00180 00181 ply_get_property (ply, elem_name, &face_props[0]); 00182 face_other = ply_get_other_properties (ply, elem_name, 00183 offsetof(Face, other_props)); 00184 00185 /* grab all the face elements */ 00186 for (j = 0; j < num_elems; j++) 00187 ply_get_element (ply, (void *) (flist + j)); 00188 } 00189 else if (equal_strings ("tristrips", elem_name)) 00190 { 00191 00192 /* create a list to hold all the tristrip elements */ 00193 tslist = (TriStrips *) malloc (sizeof(TriStrips) * num_elems); 00194 ntristrips = num_elems; 00195 00196 /* set up for getting tristrip elements */ 00197 00198 ply_get_property (ply, elem_name, &tristrip_props[0]); 00199 tristrip_other = ply_get_other_properties (ply, elem_name, 00200 offsetof(TriStrips, other_props)); 00201 00202 /* grab all the tristrip elements */ 00203 for (j = 0; j < num_elems; j++) 00204 ply_get_element (ply, (void *) (tslist + j)); 00205 } 00206 else 00207 other_elements = ply_get_other_element (ply, elem_name, num_elems); 00208 } 00209 00210 comments = ply_get_comments (ply, &num_comments); 00211 obj_info = ply_get_obj_info (ply, &num_obj_info); 00212 00213 ply_close (ply); 00214 } 00215 00216 00217 /****************************************************************************** 00218 Write out the PLY file to standard out. 00219 ******************************************************************************/ 00220 00221 write_file() 00222 { 00223 int i, j, k; 00224 PlyFile *ply; 00225 int num_elems; 00226 char *elem_name; 00227 00228 /*** Write out the final PLY object ***/ 00229 00230 00231 ply = ply_write (stdout, 3, elem_names, file_type); 00232 00233 00234 /* describe what properties go into the vertex and face elements */ 00235 00236 ply_element_count (ply, "vertex", nverts); 00237 ply_describe_property (ply, "vertex", &vert_props[0]); 00238 ply_describe_property (ply, "vertex", &vert_props[1]); 00239 ply_describe_property (ply, "vertex", &vert_props[2]); 00240 if (has_normals) 00241 { 00242 ply_describe_property (ply, "vertex", &vert_props[3]); 00243 ply_describe_property (ply, "vertex", &vert_props[4]); 00244 ply_describe_property (ply, "vertex", &vert_props[5]); 00245 } 00246 ply_describe_other_properties (ply, vert_other, offsetof(Vertex, other_props)); 00247 00248 ply_element_count (ply, "face", nfaces); 00249 ply_describe_property (ply, "face", &face_props[0]); 00250 ply_describe_other_properties (ply, face_other, offsetof(Face, other_props)); 00251 00252 ply_describe_other_elements (ply, other_elements); 00253 00254 for (i = 0; i < num_comments; i++) 00255 ply_put_comment (ply, comments[i]); 00256 00257 for (i = 0; i < num_obj_info; i++) 00258 ply_put_obj_info (ply, obj_info[i]); 00259 00260 ply_header_complete (ply); 00261 00262 /* set up and write the vertex elements */ 00263 ply_put_element_setup (ply, "vertex"); 00264 for (i = 0; i < nverts; i++) 00265 ply_put_element (ply, (void *) (vlist + i)); 00266 00267 /* set up and write the face elements */ 00268 ply_put_element_setup (ply, "face"); 00269 for (i = 0; i < nfaces; i++) 00270 ply_put_element (ply, (void *) (flist + i)); 00271 00272 ply_put_other_elements (ply); 00273 00274 /* close the PLY file */ 00275 ply_close (ply); 00276 } 00277 00278 00279 00280 // --- GCL stuff ------------------------------- 00281 00282 Void AccumNormals( 00283 Int tri[3], 00284 PointList &points, 00285 NormalList &normals, 00286 ScalarList &areas 00287 ) 00288 { 00289 Vector normal; 00290 GCLReal normalLen; 00291 00292 CalcTriAreaNormal( 00293 points[tri[0]], 00294 points[tri[1]], 00295 points[tri[2]], 00296 normal 00297 ); 00298 00299 normal *= 0.5; 00300 normalLen = len(normal); 00301 00302 normals[tri[0]] += normal; 00303 normals[tri[1]] += normal; 00304 normals[tri[2]] += normal; 00305 areas[tri[0]] += normalLen; 00306 areas[tri[1]] += normalLen; 00307 areas[tri[2]] += normalLen; 00308 } 00309 00310 Void MakeNormals() 00311 { 00312 scPoints *sp = SL_GET(Points); 00313 scNormals *sn = new scNormals; 00314 NormalList &normals = *sn; 00315 PointList &points = *sp; 00316 ScalarList areas(nverts); 00317 Int i, j; 00318 Int tri[3], triStripLen; 00319 00320 normals.SetSize(nverts); 00321 normals.ClearTo(vl_0); 00322 areas.ClearTo(0.0); 00323 00324 if (nfaces > 0) 00325 for (i = 0; i < nfaces; i++) 00326 { 00327 Face *face = flist + i; 00328 00329 tri[0] = face->verts[face->nverts - 2]; 00330 tri[1] = face->verts[face->nverts - 1]; 00331 for (j = 0; j < face->nverts; j++) 00332 { 00333 tri[2] = face->verts[j]; 00334 AccumNormals(tri, points, normals, areas); 00335 tri[0] = tri[1]; 00336 tri[1] = tri[2]; 00337 } 00338 } 00339 00340 if (ntristrips > 0) 00341 { 00342 for (i = 0; i < ntristrips; i++) 00343 { 00344 TriStrips *tristrip = tslist + i; 00345 00346 triStripLen = 0; 00347 00348 for (j = 0; j < tristrip->nverts; j++) 00349 if (tristrip->verts[j] == -1) 00350 triStripLen = 0; 00351 else 00352 { 00353 triStripLen++; 00354 if (triStripLen < 3) 00355 continue; 00356 else if (triStripLen % 2) 00357 { 00358 tri[0] = tristrip->verts[j - 2]; 00359 tri[1] = tristrip->verts[j - 1]; 00360 } 00361 else 00362 { 00363 tri[0] = tristrip->verts[j - 1]; 00364 tri[1] = tristrip->verts[j - 2]; 00365 } 00366 tri[2] = tristrip->verts[j]; 00367 00368 AccumNormals(tri, points, normals, areas); 00369 } 00370 } 00371 } 00372 00373 for (i = 0; i < normals.NumItems(); i++) 00374 { 00375 if (areas[i] > 0.0) 00376 normals[i] /= areas[i]; 00377 } 00378 00379 slAttribute(sn); 00380 } 00381 00382 scScenePtr ParsePLYFile(const Char *filename) 00383 { 00384 FILE *plyFile; 00385 scScenePtr result; 00386 Int i, j; 00387 00388 plyFile = fopen(filename, "r"); 00389 read_file(plyFile); 00390 // ply does the close??? hard to tell 00391 00392 cerr << nfaces << " faces" << endl; 00393 cerr << ntristrips << " triangle strips" << endl; 00394 cerr << nverts << " vertices" << endl; 00395 cerr << "converting..." << endl; 00396 00397 result = slBeginObject(filename); 00398 00399 cerr << "making point list" << endl; 00400 slPointList(); 00401 SL_GET(Points)->PreAllocate(nverts); 00402 for (i = 0; i < nverts; i++) 00403 { 00404 Vertex *v = vlist + i; 00405 slPoint(Point(v->x, v->y, v->z)); 00406 } 00407 00408 if (has_normals) 00409 { 00410 cerr << "making normals list" << endl; 00411 slNormalList(); 00412 SL_GET(Normals)->PreAllocate(nverts); 00413 00414 for (i = 0; i < nverts; i++) 00415 { 00416 Vertex *v = vlist + i; 00417 slNormal(Vector(v->nx, v->ny, v->nz)); 00418 } 00419 } 00420 else 00421 { 00422 cerr << "creating a normals list" << endl; 00423 MakeNormals(); 00424 } 00425 00426 if (has_rgb) 00427 { 00428 cerr << "making colours list" << endl; 00429 slColourList(); 00430 SL_GET(Colours)->PreAllocate(nverts); 00431 00432 for (i = 0; i < nverts; i++) 00433 { 00434 Vertex *v = vlist + i; 00435 slColour(Colour(v->r, v->g, v->b) / 255.0); 00436 } 00437 } 00438 00439 free(vlist); 00440 00441 if (nfaces > 0) 00442 { 00443 cerr << "making faces list" << endl; 00444 slBeginFaces(); 00445 for (i = 0; i < nfaces; i++) 00446 { 00447 Face *face = flist + i; 00448 00449 for (j = 0; j < face->nverts; j++) 00450 slPointIndex(face->verts[j]); 00451 00452 slFace(); 00453 free(face->verts); 00454 } 00455 slEndFaces(); 00456 } 00457 free(flist); 00458 00459 if (ntristrips > 0) 00460 { 00461 Int strips = 0; 00462 00463 cerr << "making tristrips list" << endl; 00464 00465 slMeshType(renTriStrip); 00466 slBeginFaces(); 00467 00468 for (i = 0; i < ntristrips; i++) 00469 { 00470 TriStrips *tristrip = tslist + i; 00471 00472 for (j = 0; j < tristrip->nverts; j++) 00473 if (tristrip->verts[j] == -1) 00474 { 00475 strips++; 00476 slFace(); 00477 } 00478 else 00479 slPointIndex(tristrip->verts[j]); 00480 00481 strips++; 00482 free(tristrip->verts); 00483 } 00484 00485 slEndFaces(); 00486 slEndAttribute(aMeshType); 00487 } 00488 free(tslist); 00489 00490 slEndObject(); 00491 00492 cerr << "done." << endl; 00493 00494 return (result); 00495 } 00496 00497 #include "plyfile.c" 00498