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;
75 static Ply *read_header(FILE *fp);
76 static Element *seek_elem(Ply *ply, ElementType elem_type);
78 static const char *ply_filename = 0; // for error reports
87 bool file_is_ply(FILE *file) {
90 fseek(file, 0, SEEK_SET);
93 return !strcmp(sig, "ply\n");
97 error("ply(%s): " m, fname);\
103 TriMesh *load_mesh_ply(const char *fname) {
104 const char *sep = " \t\n";
105 char buf[BUFFER_SIZE];
107 FILE *fp = fopen(fname, "r");
108 if(!fp || !file_is_ply(fp)) {
113 ply_filename = fname;
115 Ply *ply = read_header(fp);
122 vector<Vertex> verts;
123 vector<Triangle> tris;
127 // -- read the vertices
128 if(!(elem = seek_elem(ply, ELEM_VERTEX))) {
129 FAIL("failed to locate vertex data");
132 if(elem->prop[0].type != PROP_FLOAT || elem->prop[1].type != PROP_FLOAT || elem->prop[2].type != PROP_FLOAT) {
133 FAIL("weird vertex format, didn't find 3 floats");
136 for(unsigned long i=0; i<elem->count; i++) {
138 if(ply->fmt == PLY_ASCII) {
139 fgets(buf, BUFFER_SIZE, fp);
141 char *x_str = strtok(buf, sep);
142 char *y_str = strtok(0, sep);
143 char *z_str = strtok(0, sep);
145 if(!x_str || !y_str || !z_str) {
146 FAIL("vertex data loading failed, format inconsistent");
148 v.pos.x = atof(x_str);
149 v.pos.y = atof(y_str);
150 v.pos.z = -atof(z_str);
153 FAIL("sorry binary ply loading not implemented yet");
159 // -- read the face list
160 if(!(elem = seek_elem(ply, ELEM_FACE))) {
161 FAIL("failed to locate face data");
164 if(elem->prop[0].type != PROP_LIST) {
165 FAIL("weird face format, didn't find an index list");
168 for(unsigned long i=0; i<elem->count; i++) {
170 unsigned long indices[4];
172 if(ply->fmt == PLY_ASCII) {
173 fgets(buf, BUFFER_SIZE, fp);
175 count = atoi(strtok(buf, sep));
176 if(count < 3 || count > 4) {
177 FAIL("only triangles and quads are supported");
180 for(int j=0; j<count; j++) {
181 char *substr = strtok(0, sep);
183 FAIL("inconsistent face list data");
185 indices[j] = atol(substr);
189 FAIL("sorry binary ply loading not implemented yet");
192 Triangle tri(indices[0], indices[1], indices[2]);
196 Triangle tri2(indices[0], indices[2], indices[3]);
197 tris.push_back(tri2);
204 // ok now we have the vertex/triangle vectors, let's create the mesh and return it
205 TriMesh *mesh = new TriMesh(&verts[0], verts.size(), &tris[0], tris.size());
206 mesh->calculate_normals();
210 static Ply *read_header(FILE *fp) {
211 const char *sep = " \t\n";
212 char buf[BUFFER_SIZE];
214 fseek(fp, 0, SEEK_SET);
218 bool vertex_ok = false, face_ok = false;
220 while(fgets(buf, BUFFER_SIZE, fp)) {
221 char *field = strtok(buf, sep);
224 if(!strcmp(field, "format")) {
225 char *fmt = strtok(0, sep);
227 error("ply(%s): invalid format field", ply_filename);
232 if(!strcmp(fmt, "ascii")) {
233 ply->fmt = PLY_ASCII;
234 } else if(!strcmp(fmt, "binary_little_endian")) {
235 ply->fmt = PLY_LITTLE_ENDIAN;
236 } else if(!strcmp(fmt, "binary_big_endian")) {
237 ply->fmt = PLY_BIG_ENDIAN;
239 error("ply(%s): invalid format field", ply_filename);
244 } else if(!strcmp(field, "element")) {
245 char *elem_name = strtok(0, sep);
247 warning("ply(%s): invalid element definition", ply_filename);
251 char *count_str = strtok(0, sep);
252 if(!count_str || !isdigit(*count_str)) {
253 error("ply(%s): element not followed by a count", ply_filename);
258 unsigned long count = atol(count_str);
261 elem.type = ELEM_UNKNOWN;
264 if(!strcmp(elem_name, "vertex")) {
265 elem.type = ELEM_VERTEX;
269 if(!strcmp(elem_name, "face")) {
270 elem.type = ELEM_FACE;
274 // determine element properties
275 while((buf[0] = fgetc(fp)) == 'p') {
276 if(!fgets(buf + 1, BUFFER_SIZE - 1, fp)) {
277 error("ply(%s): unexpected end of file while reading element properties", ply_filename);
281 char *ptr = strtok(buf, sep);
282 if(!ptr || strcmp(ptr, "property")) {
283 error("ply(%s): looking for \"propery\", got \"%s\"", ply_filename, ptr ? ptr : "NULL");
292 char *name = strtok(0, sep);
294 error("ply(%s): invalid property entry, no name specified", ply_filename);
301 char *type = strtok(0, sep);
303 error("ply(%s): invalid property entry, no type specified", ply_filename);
308 PropTypeMatch *mptr = prop_match;
310 if(!strcmp(type, mptr->symb)) {
311 prop.type = mptr->type;
312 prop.size = prop_size[prop.type];
318 if(prop.type == PROP_LIST) {
319 type = strtok(0, sep);
321 error("ply(%s): invalid property entry, no list subtype specified", ply_filename);
328 if(!strcmp(type, mptr->symb)) {
329 prop.list_type = mptr->type;
330 prop.size = prop_size[prop.list_type];
338 error("ply(%s): unknown property type \"%s\"", ply_filename, type);
343 elem.prop.push_back(prop);
348 ply->elem.push_back(elem);
350 } else if(!strcmp(field, "end_header")) {
351 if(!vertex_ok || !face_ok) {
352 error("ply(%s): some important element is unspecified (vertex or face list)", ply_filename);
356 ply->header_skip = ftell(fp);
364 static Element *seek_elem(Ply *ply, ElementType elem_type) {
365 fseek(ply->fp, ply->header_skip, SEEK_SET);
367 if(ply->fmt == PLY_ASCII) {
368 char buf[BUFFER_SIZE];
370 for(size_t i=0; i<ply->elem.size(); i++) {
371 if(ply->elem[i].type == elem_type) {
372 return &ply->elem[i];
375 // it's not the one we want, skip it.
376 for(size_t j=0; j<ply->elem[i].count; j++) {
377 fgets(buf, BUFFER_SIZE, ply->fp);
383 error("ply(%s): seek failed, binary ply loading not implemented yet", ply_filename);