From f0743d593be2424b96bc88323281f9e9c8859674 Mon Sep 17 00:00:00 2001 From: manuelk Date: Thu, 22 Jan 2015 11:08:13 -0800 Subject: [PATCH] Add parsing ability for OBJ material format to regression/shape_utils - add simple parsing function to the Shape class - only a small portion of the MTL format is supported (no textures) - the feature is disabled by default - this work is incomplete : we still need to add piping to the GPU --- regression/common/shape_utils.cpp | 161 ++++++++++++++++++++++-------- regression/common/shape_utils.h | 61 ++++++++--- 2 files changed, 169 insertions(+), 53 deletions(-) diff --git a/regression/common/shape_utils.cpp b/regression/common/shape_utils.cpp index 87ba850e..dc593331 100644 --- a/regression/common/shape_utils.cpp +++ b/regression/common/shape_utils.cpp @@ -25,9 +25,11 @@ #include "shape_utils.h" +#include #include #include #include +#include #include //------------------------------------------------------------------------------ @@ -53,66 +55,83 @@ static char const * sgets( char * s, int size, char ** stream ) { Shape::~Shape() { for (int i=0; i<(int)tags.size(); ++i) delete tags[i]; + + for (int i=0; i<(int)mtls.size(); ++i) + delete mtls[i]; } //------------------------------------------------------------------------------ -Shape * Shape::parseObj(char const * shapestr, Scheme shapescheme, int axis ) { +Shape * Shape::parseObj(char const * shapestr, Scheme shapescheme, int axis, bool parsemtl) { Shape * s = new Shape; s->scheme = shapescheme; - char * str=const_cast(shapestr), line[256]; + char * str=const_cast(shapestr), line[256], buf[256], usemtl=-1; bool done = false; - while( not done ) - { done = sgets(line, sizeof(line), &str)==0; + while (not done) { + done = sgets(line, sizeof(line), &str)==0; char* end = &line[strlen(line)-1]; if (*end == '\n') *end = '\0'; // strip trailing nl float x, y, z, u, v; switch (line[0]) { - case 'v': switch (line[1]) - { case ' ': if(sscanf(line, "v %f %f %f", &x, &y, &z) == 3) { - s->verts.push_back(x); - switch( axis ) { - case 0 : s->verts.push_back(-z); - s->verts.push_back(y); break; - case 1 : s->verts.push_back(y); - s->verts.push_back(z); break; - } - } break; - case 't': if(sscanf(line, "vt %f %f", &u, &v) == 2) { - s->uvs.push_back(u); - s->uvs.push_back(v); - } break; - case 'n' : if(sscanf(line, "vn %f %f %f", &x, &y, &z) == 3) { - s->normals.push_back(x); - s->normals.push_back(y); - s->normals.push_back(z); + case 'v': switch (line[1]) { + case ' ': if (sscanf(line, "v %f %f %f", &x, &y, &z) == 3) { + s->verts.push_back(x); + switch( axis ) { + case 0 : s->verts.push_back(-z); + s->verts.push_back(y); break; + case 1 : s->verts.push_back(y); + s->verts.push_back(z); break; } - break; // skip normals for now - } - break; - case 'f': if(line[1] == ' ') { - int vi, ti, ni; - const char* cp = &line[2]; + } break; + case 't': if (sscanf(line, "vt %f %f", &u, &v) == 2) { + s->uvs.push_back(u); + s->uvs.push_back(v); + } break; + case 'n' : if (sscanf(line, "vn %f %f %f", &x, &y, &z) == 3) { + s->normals.push_back(x); + s->normals.push_back(y); + s->normals.push_back(z); + } break; // skip normals for now + } break; + case 'f': if (line[1] == ' ') { + int vi, ti, ni; + const char* cp = &line[2]; + while (*cp == ' ') cp++; + int nverts = 0, nitems=0; + while( (nitems=sscanf(cp, "%d/%d/%d", &vi, &ti, &ni))>0) { + nverts++; + s->faceverts.push_back(vi-1); + if(nitems >= 1) s->faceuvs.push_back(ti-1); + if(nitems >= 2) s->facenormals.push_back(ni-1); + while (*cp && *cp != ' ') cp++; while (*cp == ' ') cp++; - int nverts = 0, nitems=0; - while( (nitems=sscanf(cp, "%d/%d/%d", &vi, &ti, &ni))>0) { - nverts++; - s->faceverts.push_back(vi-1); - if(nitems >= 1) s->faceuvs.push_back(ti-1); - if(nitems >= 2) s->facenormals.push_back(ni-1); - while (*cp && *cp != ' ') cp++; - while (*cp == ' ') cp++; - } - s->nvertsPerFace.push_back(nverts); } - break; - case 't' : if(line[1] == ' ') { + s->nvertsPerFace.push_back(nverts); + if (not s->mtls.empty()) { + s->mtlbind.push_back(usemtl); + } + } break; + case 't' : if (line[1] == ' ') { Shape::tag * t = tag::parseTag( line ); if (t) s->tags.push_back(t); } break; + case 'u' : if (parsemtl and sscanf(line, "usemtl %s", buf)==1) { + usemtl = s->FindMaterial(buf); + } break; + case 'm' : if (parsemtl and sscanf(line, "mtllib %s", buf)==1) { + std::ifstream ifs(buf); + if (ifs) { + std::stringstream ss; + ss << ifs.rdbuf(); + ifs.close(); + std::string str = ss.str(); + s->parseMtllib(str.c_str()); + s->mtllib = buf; + } + } break; } } return s; @@ -170,6 +189,68 @@ Shape::tag * Shape::tag::parseTag(char const * line) { return t; } +//------------------------------------------------------------------------------ +Shape::material::material() { + memset(ka, 0, sizeof(float)*3); + memset(kd, 0, sizeof(float)*3); + memset(ks, 0, sizeof(float)*3); + memset(tf, 0, sizeof(float)*3); + ns = ni = d = 0.0f; + illum=0; +} + +//------------------------------------------------------------------------------ +void Shape::parseMtllib(char const * mtlstr) { + + char * str=const_cast(mtlstr), line[256]; + + material * mtl=0; + + bool done = false; + float r, g, b, a; + while (not done) { + done = sgets(line, sizeof(line), &str)==0; + char* end = &line[strlen(line)-1]; + if (*end == '\n') *end = '\0'; // strip trailing nl + switch (line[0]) { + case 'n': char name[256]; + if (sscanf(line, "newmtl %s", name) == 1) { + mtl = new material; + mtl->name = name; + mtls.push_back(mtl); + } break; + case 'K': if (sscanf(line+2, " %f %f %f", &r, &g, &b) == 3) { + switch (line[1]) { + case 'a': mtl->ka[0]=r; mtl->ka[1]=g; mtl->ka[2]=b; break; + case 'd': mtl->kd[0]=r; mtl->kd[1]=g; mtl->kd[2]=b; break; + case 's': mtl->ks[0]=r; mtl->ks[1]=g; mtl->ks[2]=b; break; + } + } break; + case 'N': if (sscanf(line+2, " %f", &a) == 1) { + switch (line[1]) { + case 's' : mtl->ns = a; break; + case 'i' : mtl->ni = a; break; + } + } break; + case 'd': if (sscanf(line, "d %f", &a) == 1) { + mtl->d = a; + } break; + case 'T': if (line[1]=='f') { + if (sscanf(line, "Tf %f %f %f", &r, &g, &b) == 3) { + mtl->tf[0]=r; mtl->tf[1]=g; mtl->tf[2]=b; + } break; + } break; + case 'i': int illum; + if (sscanf(line, "illum %d", &illum) == 1) { + mtl->illum = illum; + } break; + case 's': if (sscanf(line, "sharpness %f", &a) == 1) { + mtl->sharpness = a; + } break; + } + } +} + //------------------------------------------------------------------------------ std::string Shape::tag::genTag() const { std::stringstream t; diff --git a/regression/common/shape_utils.h b/regression/common/shape_utils.h index ad0df0c3..57b6a8b0 100644 --- a/regression/common/shape_utils.h +++ b/regression/common/shape_utils.h @@ -27,6 +27,7 @@ #include #include +#include //------------------------------------------------------------------------------ enum Scheme { @@ -38,10 +39,28 @@ enum Scheme { //------------------------------------------------------------------------------ struct Shape { + // full(er) spec here: http://paulbourke.net/dataformats/mtl/ + struct material { + + material(); + + std::string name; + + float ka[3], // ambient + kd[3], // diffuse + ks[3], // specular + ns, // specular exponent + ni, // optical density (1.0=no refraction, glass=1.5) + sharpness, // reflection sharpness + tf[3], // transimission filter + d; // dissolve factor (1.0 = opaque) + + int illum; + }; struct tag { - static tag * parseTag( char const * stream ); + static tag * parseTag(char const * stream); std::string genTag() const; @@ -51,7 +70,10 @@ struct Shape { std::vector stringargs; }; - static Shape * parseObj(char const * Shapestr, Scheme schme, int axis=1); + static Shape * parseObj(char const * Shapestr, Scheme schme, + int axis=1, bool parsemtl=false); + + void parseMtllib(char const * stream); std::string genShape(char const * name) const; @@ -64,20 +86,33 @@ struct Shape { int GetNumVertices() const { return (int)verts.size()/3; } int GetNumFaces() const { return (int)nvertsPerFace.size(); } - + bool HasUV() const { return not (uvs.empty() or faceuvs.empty()); } - + int GetFVarWidth() const { return HasUV() ? 2 : 0; } - std::vector verts; - std::vector uvs; - std::vector normals; - std::vector nvertsPerFace; - std::vector faceverts; - std::vector faceuvs; - std::vector facenormals; - std::vector tags; - Scheme scheme; + std::vector verts; + std::vector uvs; + std::vector normals; + std::vector nvertsPerFace; + std::vector faceverts; + std::vector faceuvs; + std::vector facenormals; + std::vector tags; + Scheme scheme; + + char FindMaterial(char const * name) { + for (int i=0; i<(int)mtls.size(); ++i) { + if (mtls[i]->name==name) { + return i; + } + } + return -1; + } + + std::string mtllib; + std::vector mtlbind; + std::vector mtls; }; //------------------------------------------------------------------------------