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