X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2F3dengfx%2Fsrc%2F3dengfx%2Fply.cpp;fp=src%2F3dengfx%2Fsrc%2F3dengfx%2Fply.cpp;h=78bdc53524b93c1f65a362dd5c25627d3e60bc58;hb=6e23259dbabaeb1711a2a5ca25b9cb421f693759;hp=0000000000000000000000000000000000000000;hpb=fe068fa879814784c45e0cb2e65dac489e8f5594;p=summerhack diff --git a/src/3dengfx/src/3dengfx/ply.cpp b/src/3dengfx/src/3dengfx/ply.cpp new file mode 100644 index 0000000..78bdc53 --- /dev/null +++ b/src/3dengfx/src/3dengfx/ply.cpp @@ -0,0 +1,378 @@ +#include +#include +#include +#include +#include +#include "gfx/3dgeom.hpp" +#include "common/err_msg.h" + +#define BUFFER_SIZE 256 + +using std::vector; +using std::string; + +enum PlyFormat { + PLY_ASCII, + PLY_LITTLE_ENDIAN, + PLY_BIG_ENDIAN +}; + +enum PropType { + PROP_FLOAT, + PROP_INT8, + PROP_INT16, + PROP_INT32, + PROP_LIST +}; + +const size_t prop_size[] = {32, 8, 16, 32, 0}; + +struct PropTypeMatch { + char *symb; + PropType type; +} prop_match[] = { + {"float", PROP_FLOAT}, + {"float32", PROP_FLOAT}, + {"int", PROP_INT32}, + {"int32", PROP_INT32}, + {"uint", PROP_INT32}, + {"uint32", PROP_INT32}, + {"int16", PROP_INT16}, + {"uint16", PROP_INT16}, + {"char", PROP_INT8}, + {"uchar", PROP_INT8}, + {"int8", PROP_INT8}, + {"uint8", PROP_INT8}, + {"list", PROP_LIST}, + {0, (PropType)0} +}; + +struct Property { + string name; + PropType type; + PropType list_type; // list elements type, if type == PROP_LIST + size_t size; +}; + +enum ElementType {ELEM_UNKNOWN, ELEM_VERTEX, ELEM_FACE}; + +struct Element { + ElementType type; + unsigned long count; + vector prop; + long offset; +}; + +struct Ply { + PlyFormat fmt; + vector elem; + FILE *fp; + unsigned long header_skip; +}; + +static Ply *read_header(FILE *fp); +static Element *seek_elem(Ply *ply, ElementType elem_type); + +static const char *ply_filename = 0; // for error reports + +bool file_is_ply(FILE *file) { + char sig[5] = {0}; + + fseek(file, 0, SEEK_SET); + fgets(sig, 5, file); + + return !strcmp(sig, "ply\n"); +} + +#define FAIL(m) {\ + error("ply(%s): " m, fname);\ + fclose(fp);\ + delete ply;\ + return 0;\ +} + +TriMesh *load_mesh_ply(const char *fname) { + const char *sep = " \t\n"; + char buf[BUFFER_SIZE]; + + FILE *fp = fopen(fname, "r"); + if(!fp || !file_is_ply(fp)) { + if(fp) fclose(fp); + return 0; + } + + ply_filename = fname; + + Ply *ply = read_header(fp); + if(!ply) { + fclose(fp); + return 0; + } + ply->fp = fp; + + vector verts; + vector tris; + + Element *elem; + + // -- read the vertices + if(!(elem = seek_elem(ply, ELEM_VERTEX))) { + FAIL("failed to locate vertex data"); + } + + if(elem->prop[0].type != PROP_FLOAT || elem->prop[1].type != PROP_FLOAT || elem->prop[2].type != PROP_FLOAT) { + FAIL("weird vertex format, didn't find 3 floats"); + } + + for(unsigned long i=0; icount; i++) { + Vertex v; + if(ply->fmt == PLY_ASCII) { + fgets(buf, BUFFER_SIZE, fp); + + char *x_str = strtok(buf, sep); + char *y_str = strtok(0, sep); + char *z_str = strtok(0, sep); + + if(!x_str || !y_str || !z_str) { + FAIL("vertex data loading failed, format inconsistent"); + } + v.pos.x = atof(x_str); + v.pos.y = atof(y_str); + v.pos.z = -atof(z_str); + + } else { + FAIL("sorry binary ply loading not implemented yet"); + } + + verts.push_back(v); + } + + // -- read the face list + if(!(elem = seek_elem(ply, ELEM_FACE))) { + FAIL("failed to locate face data"); + } + + if(elem->prop[0].type != PROP_LIST) { + FAIL("weird face format, didn't find an index list"); + } + + for(unsigned long i=0; icount; i++) { + int count; + unsigned long indices[4]; + + if(ply->fmt == PLY_ASCII) { + fgets(buf, BUFFER_SIZE, fp); + + count = atoi(strtok(buf, sep)); + if(count < 3 || count > 4) { + FAIL("only triangles and quads are supported"); + } + + for(int j=0; jcalculate_normals(); + return mesh; +} + +static Ply *read_header(FILE *fp) { + const char *sep = " \t\n"; + char buf[BUFFER_SIZE]; + + fseek(fp, 0, SEEK_SET); + + Ply *ply = new Ply; + memset(ply, 0, sizeof(Ply)); + + bool vertex_ok = false, face_ok = false; + + while(fgets(buf, BUFFER_SIZE, fp)) { + char *field = strtok(buf, sep); + if(!field) continue; + + if(!strcmp(field, "format")) { + char *fmt = strtok(0, sep); + if(!fmt) { + error("ply(%s): invalid format field", ply_filename); + delete ply; + return 0; + } + + if(!strcmp(fmt, "ascii")) { + ply->fmt = PLY_ASCII; + } else if(!strcmp(fmt, "binary_little_endian")) { + ply->fmt = PLY_LITTLE_ENDIAN; + } else if(!strcmp(fmt, "binary_big_endian")) { + ply->fmt = PLY_BIG_ENDIAN; + } else { + error("ply(%s): invalid format field", ply_filename); + delete ply; + return 0; + } + + } else if(!strcmp(field, "element")) { + char *elem_name = strtok(0, sep); + if(!elem_name) { + warning("ply(%s): invalid element definition", ply_filename); + continue; + } + + char *count_str = strtok(0, sep); + if(!count_str || !isdigit(*count_str)) { + error("ply(%s): element not followed by a count", ply_filename); + delete ply; + return 0; + } + + unsigned long count = atol(count_str); + + Element elem; + elem.type = ELEM_UNKNOWN; + elem.count = count; + + if(!strcmp(elem_name, "vertex")) { + elem.type = ELEM_VERTEX; + vertex_ok = true; + } + + if(!strcmp(elem_name, "face")) { + elem.type = ELEM_FACE; + face_ok = true; + } + + // determine element properties + while((buf[0] = fgetc(fp)) == 'p') { + if(!fgets(buf + 1, BUFFER_SIZE - 1, fp)) { + error("ply(%s): unexpected end of file while reading element properties", ply_filename); + delete ply; + return 0; + } + char *ptr = strtok(buf, sep); + if(!ptr || strcmp(ptr, "property")) { + error("ply(%s): looking for \"propery\", got \"%s\"", ply_filename, ptr ? ptr : "NULL"); + delete ply; + return 0; + } + + Property prop; + prop.size = 0; + + /* + char *name = strtok(0, sep); + if(!name) { + error("ply(%s): invalid property entry, no name specified", ply_filename); + delete ply; + return 0; + } + prop.name = name; + */ + + char *type = strtok(0, sep); + if(!type) { + error("ply(%s): invalid property entry, no type specified", ply_filename); + delete ply; + return 0; + } + + PropTypeMatch *mptr = prop_match; + while(mptr->symb) { + if(!strcmp(type, mptr->symb)) { + prop.type = mptr->type; + prop.size = prop_size[prop.type]; + break; + } + mptr++; + } + + if(prop.type == PROP_LIST) { + type = strtok(0, sep); + if(!type) { + error("ply(%s): invalid property entry, no list subtype specified", ply_filename); + delete ply; + return 0; + } + + mptr = prop_match; + while(mptr->symb) { + if(!strcmp(type, mptr->symb)) { + prop.list_type = mptr->type; + prop.size = prop_size[prop.list_type]; + break; + } + mptr++; + } + } + + if(!prop.size) { + error("ply(%s): unknown property type \"%s\"", ply_filename, type); + delete ply; + return 0; + } + + elem.prop.push_back(prop); + } + + ungetc(buf[0], fp); + + ply->elem.push_back(elem); + + } else if(!strcmp(field, "end_header")) { + if(!vertex_ok || !face_ok) { + error("ply(%s): some important element is unspecified (vertex or face list)", ply_filename); + delete ply; + return 0; + } + ply->header_skip = ftell(fp); + break; + } + } + + return ply; +} + +static Element *seek_elem(Ply *ply, ElementType elem_type) { + fseek(ply->fp, ply->header_skip, SEEK_SET); + + if(ply->fmt == PLY_ASCII) { + char buf[BUFFER_SIZE]; + + for(size_t i=0; ielem.size(); i++) { + if(ply->elem[i].type == elem_type) { + return &ply->elem[i]; + } + + // it's not the one we want, skip it. + for(size_t j=0; jelem[i].count; j++) { + fgets(buf, BUFFER_SIZE, ply->fp); + } + } + return 0; + + } else { + error("ply(%s): seek failed, binary ply loading not implemented yet", ply_filename); + return 0; + } +}