6 #include "gfx/3dgeom.hpp"
7 #include "common/err_msg.h"
9 #define BUFFER_SIZE 256
28 const size_t prop_size[] = {32, 8, 16, 32, 0};
30 struct PropTypeMatch {
34 {"float", PROP_FLOAT},
35 {"float32", PROP_FLOAT},
37 {"int32", PROP_INT32},
39 {"uint32", PROP_INT32},
40 {"int16", PROP_INT16},
41 {"uint16", PROP_INT16},
53 PropType list_type; // list elements type, if type == PROP_LIST
57 enum ElementType {ELEM_UNKNOWN, ELEM_VERTEX, ELEM_FACE};
62 vector<Property> prop;
70 unsigned long header_skip;
73 static Ply *read_header(FILE *fp);
74 static Element *seek_elem(Ply *ply, ElementType elem_type);
76 static const char *ply_filename = 0; // for error reports
78 bool file_is_ply(FILE *file) {
81 fseek(file, 0, SEEK_SET);
84 return !strcmp(sig, "ply\n");
88 error("ply(%s): " m, fname);\
94 TriMesh *load_mesh_ply(const char *fname) {
95 const char *sep = " \t\n";
96 char buf[BUFFER_SIZE];
98 FILE *fp = fopen(fname, "r");
99 if(!fp || !file_is_ply(fp)) {
104 ply_filename = fname;
106 Ply *ply = read_header(fp);
113 vector<Vertex> verts;
114 vector<Triangle> tris;
118 // -- read the vertices
119 if(!(elem = seek_elem(ply, ELEM_VERTEX))) {
120 FAIL("failed to locate vertex data");
123 if(elem->prop[0].type != PROP_FLOAT || elem->prop[1].type != PROP_FLOAT || elem->prop[2].type != PROP_FLOAT) {
124 FAIL("weird vertex format, didn't find 3 floats");
127 for(unsigned long i=0; i<elem->count; i++) {
129 if(ply->fmt == PLY_ASCII) {
130 fgets(buf, BUFFER_SIZE, fp);
132 char *x_str = strtok(buf, sep);
133 char *y_str = strtok(0, sep);
134 char *z_str = strtok(0, sep);
136 if(!x_str || !y_str || !z_str) {
137 FAIL("vertex data loading failed, format inconsistent");
139 v.pos.x = atof(x_str);
140 v.pos.y = atof(y_str);
141 v.pos.z = -atof(z_str);
144 FAIL("sorry binary ply loading not implemented yet");
150 // -- read the face list
151 if(!(elem = seek_elem(ply, ELEM_FACE))) {
152 FAIL("failed to locate face data");
155 if(elem->prop[0].type != PROP_LIST) {
156 FAIL("weird face format, didn't find an index list");
159 for(unsigned long i=0; i<elem->count; i++) {
161 unsigned long indices[4];
163 if(ply->fmt == PLY_ASCII) {
164 fgets(buf, BUFFER_SIZE, fp);
166 count = atoi(strtok(buf, sep));
167 if(count < 3 || count > 4) {
168 FAIL("only triangles and quads are supported");
171 for(int j=0; j<count; j++) {
172 char *substr = strtok(0, sep);
174 FAIL("inconsistent face list data");
176 indices[j] = atol(substr);
180 FAIL("sorry binary ply loading not implemented yet");
183 Triangle tri(indices[0], indices[1], indices[2]);
187 Triangle tri2(indices[0], indices[2], indices[3]);
188 tris.push_back(tri2);
195 // ok now we have the vertex/triangle vectors, let's create the mesh and return it
196 TriMesh *mesh = new TriMesh(&verts[0], verts.size(), &tris[0], tris.size());
197 mesh->calculate_normals();
201 static Ply *read_header(FILE *fp) {
202 const char *sep = " \t\n";
203 char buf[BUFFER_SIZE];
205 fseek(fp, 0, SEEK_SET);
208 memset(ply, 0, sizeof(Ply));
210 bool vertex_ok = false, face_ok = false;
212 while(fgets(buf, BUFFER_SIZE, fp)) {
213 char *field = strtok(buf, sep);
216 if(!strcmp(field, "format")) {
217 char *fmt = strtok(0, sep);
219 error("ply(%s): invalid format field", ply_filename);
224 if(!strcmp(fmt, "ascii")) {
225 ply->fmt = PLY_ASCII;
226 } else if(!strcmp(fmt, "binary_little_endian")) {
227 ply->fmt = PLY_LITTLE_ENDIAN;
228 } else if(!strcmp(fmt, "binary_big_endian")) {
229 ply->fmt = PLY_BIG_ENDIAN;
231 error("ply(%s): invalid format field", ply_filename);
236 } else if(!strcmp(field, "element")) {
237 char *elem_name = strtok(0, sep);
239 warning("ply(%s): invalid element definition", ply_filename);
243 char *count_str = strtok(0, sep);
244 if(!count_str || !isdigit(*count_str)) {
245 error("ply(%s): element not followed by a count", ply_filename);
250 unsigned long count = atol(count_str);
253 elem.type = ELEM_UNKNOWN;
256 if(!strcmp(elem_name, "vertex")) {
257 elem.type = ELEM_VERTEX;
261 if(!strcmp(elem_name, "face")) {
262 elem.type = ELEM_FACE;
266 // determine element properties
267 while((buf[0] = fgetc(fp)) == 'p') {
268 if(!fgets(buf + 1, BUFFER_SIZE - 1, fp)) {
269 error("ply(%s): unexpected end of file while reading element properties", ply_filename);
273 char *ptr = strtok(buf, sep);
274 if(!ptr || strcmp(ptr, "property")) {
275 error("ply(%s): looking for \"propery\", got \"%s\"", ply_filename, ptr ? ptr : "NULL");
284 char *name = strtok(0, sep);
286 error("ply(%s): invalid property entry, no name specified", ply_filename);
293 char *type = strtok(0, sep);
295 error("ply(%s): invalid property entry, no type specified", ply_filename);
300 PropTypeMatch *mptr = prop_match;
302 if(!strcmp(type, mptr->symb)) {
303 prop.type = mptr->type;
304 prop.size = prop_size[prop.type];
310 if(prop.type == PROP_LIST) {
311 type = strtok(0, sep);
313 error("ply(%s): invalid property entry, no list subtype specified", ply_filename);
320 if(!strcmp(type, mptr->symb)) {
321 prop.list_type = mptr->type;
322 prop.size = prop_size[prop.list_type];
330 error("ply(%s): unknown property type \"%s\"", ply_filename, type);
335 elem.prop.push_back(prop);
340 ply->elem.push_back(elem);
342 } else if(!strcmp(field, "end_header")) {
343 if(!vertex_ok || !face_ok) {
344 error("ply(%s): some important element is unspecified (vertex or face list)", ply_filename);
348 ply->header_skip = ftell(fp);
356 static Element *seek_elem(Ply *ply, ElementType elem_type) {
357 fseek(ply->fp, ply->header_skip, SEEK_SET);
359 if(ply->fmt == PLY_ASCII) {
360 char buf[BUFFER_SIZE];
362 for(size_t i=0; i<ply->elem.size(); i++) {
363 if(ply->elem[i].type == elem_type) {
364 return &ply->elem[i];
367 // it's not the one we want, skip it.
368 for(size_t j=0; j<ply->elem[i].count; j++) {
369 fgets(buf, BUFFER_SIZE, ply->fp);
375 error("ply(%s): seek failed, binary ply loading not implemented yet", ply_filename);