#include #include #include #include using namespace std; #include // delimiters for parsing the obj file: #define OBJDELIMS " \t" struct Vertex { float x, y, z; }; struct Normal { float nx, ny, nz; }; struct TextureCoord { float s, t, p; }; struct face { int v, n, t; }; char * ObjName; char * RibName; FILE * ObjFp; FILE * RibFp; float Dot( float[3], float[3] ); void Cross( float[3], float[3], float[3] ); float Unit( float[3] ); float Unit( float[3], float[3] ); int main( int argc, char *argv[] ) { char line[256]; // the command line char *cmd; // the command string char *str; // argument string int i; // counter int c; // char read char *cp; // pointer into line char dummy1[4]; // to skip past the slashes char dummy2[4]; // to skip past the slashes vector Vertices(10000); vector Normals(10000); vector TextureCoords(10000); struct Vertex sv; struct Normal sn; struct TextureCoord st; ObjFp = stdin; RibFp = stdout; for( int i = 1, n = 0; i < argc; i++ ) { if( argv[i][0] != '-' ) { switch( n ) { case 0: ObjName = argv[i]; ObjFp = fopen( ObjName, "r" ); if( ObjFp == NULL ) { fprintf( stderr, "Cannot open Obj file '%s'\n", ObjName ); exit( 1 ); } n++; break; case 1: RibName = argv[i]; RibFp = fopen( RibName, "w" ); if( RibFp == NULL ) { fprintf( stderr, "Cannot create Rib file '%s'\n", RibName ); exit( 1 ); } n++; break; } } else { } } Vertices.clear(); Normals.clear(); TextureCoords.clear(); for( ; ; ) { for( i = 0, cp = line; i < 256; i++, cp++ ) { *cp = c = fgetc( ObjFp ); if( c == EOF ) { goto done; } if( c == '\n' ) { *cp = '\0'; break; } } // get the command string: cmd = strtok( line, OBJDELIMS ); // skip this line if it is empty: if( cmd == NULL ) continue; // skip this line if it is a comment: if( strcmp( cmd, "#" ) == 0 ) continue; if( strcmp( cmd, "v" ) == 0 ) { str = strtok( NULL, OBJDELIMS ); sv.x = atof(str); str = strtok( NULL, OBJDELIMS ); sv.y = atof(str); str = strtok( NULL, OBJDELIMS ); sv.z = atof(str); Vertices.push_back( sv ); continue; } if( strcmp( cmd, "vn" ) == 0 ) { str = strtok( NULL, OBJDELIMS ); sn.nx = atof( str ); str = strtok( NULL, OBJDELIMS ); sn.ny = atof( str ); str = strtok( NULL, OBJDELIMS ); sn.nz = atof( str ); Normals.push_back( sn ); continue; } if( strcmp( cmd, "vt" ) == 0 ) { st.s = st.t = st.p = 0.; str = strtok( NULL, OBJDELIMS ); st.s = atof( str ); str = strtok( NULL, OBJDELIMS ); if( str != NULL ) st.t = atof( str ); str = strtok( NULL, OBJDELIMS ); if( str != NULL ) st.p = atof( str ); TextureCoords.push_back( st ); continue; } if( strcmp( cmd, "f" ) == 0 ) { struct face vertices[10]; int sizev = (int)Vertices.size(); int sizen = (int)Normals.size(); int sizet = (int)TextureCoords.size(); int v, n, t; int numVertices = 0; bool valid = true; for( int vtx = 0; vtx < 10; vtx++ ) { v = 0; n = 0; t = 0; str = strtok( NULL, OBJDELIMS ); if( str == NULL ) break; sscanf( str, "%d%[/]%d%[/]%d", &v, dummy1, &t, dummy2, &n ); // if v, n, or t are negative, they are wrt the end of their respective list: if( v < 0 ) v += ( sizev + 1 ); if( n < 0 ) n += ( sizen + 1 ); if( t < 0 ) t += (sizet + 1 ); // be sure we are not out-of-bounds ( will abort): if( t > sizet ) { fprintf( stderr, "Read texture coord %d, but only have %d so far\n", vertices[vtx].t, sizet ); t = 0; } if( n > sizen ) { fprintf( stderr, "Read normal %d, but only have %d so far\n", vertices[vtx].n, sizen ); n = 0; } if( v > sizev ) { fprintf( stderr, "Read vertex coord %d, but only have %d so far\n", vertices[vtx].v, sizev ); v = 0; valid = false; } vertices[vtx].v = v; vertices[vtx].n = n; vertices[vtx].t = t; numVertices++; } // if vertices are invalid, don't draw anything this time: if( ! valid ) continue; if( numVertices < 3 ) continue; fprintf( RibFp, "Polygon " ); // list the vertices: fprintf( RibFp, "\"P\" [ " ); for( int vtx = 0; vtx < numVertices; vtx++ ) { struct Vertex *vp = &Vertices[ vertices[vtx].v - 1 ]; fprintf( RibFp, "%8.2f %8.2f %8.2f ", vp->x, vp->y, vp->z ); } fprintf( RibFp, " ] " ); // get the planar normal, in case vertex normals are not defined: struct Vertex *v0 = &Vertices[ vertices[0].v - 1 ]; struct Vertex *v1 = &Vertices[ vertices[1].v - 1 ]; struct Vertex *v2 = &Vertices[ vertices[2].v - 1 ]; float v01[3], v02[3], norm[3]; v01[0] = v1->x - v0->x; v01[1] = v1->y - v0->y; v01[2] = v1->z - v0->z; v02[0] = v2->x - v0->x; v02[1] = v2->y - v0->y; v02[2] = v2->z - v0->z; Cross( v01, v02, norm ); Unit( norm, norm ); // list the normals: fprintf( RibFp, "\"N\" [ " ); for( int vtx = 0; vtx < numVertices; vtx++ ) { if( vertices[vtx].n != 0 ) { struct Normal *np = &Normals[ vertices[vtx].n - 1 ]; fprintf( RibFp, "%5.2f %5.2f %5.2f ", np->nx, np->ny, np->nz ); } else { fprintf( RibFp, "%5.2f %5.2f %5.2f ", norm[0], norm[1], norm[2] ); } } fprintf( RibFp, " ] " ); // list the texture coords: fprintf( RibFp, "\"st\" [ " ); for( int vtx = 0; vtx < numVertices; vtx++ ) { if( vertices[vtx].t != 0 ) { struct TextureCoord *tp = &TextureCoords[ vertices[vtx].t - 1 ]; fprintf( RibFp, "%5.2f %5.2f ", tp->s, tp->t ); } } fprintf( RibFp, " ] " ); fprintf( RibFp, "\n" ); continue; } if( strcmp( cmd, "s" ) == 0 ) { continue; } } done:; fclose( ObjFp ); fclose( RibFp ); return 0; } float Dot( float v1[3], float v2[3] ) { return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; } void Cross( float v1[3], float v2[3], float vout[3] ) { float tmp[3]; tmp[0] = v1[1]*v2[2] - v2[1]*v1[2]; tmp[1] = v2[0]*v1[2] - v1[0]*v2[2]; tmp[2] = v1[0]*v2[1] - v2[0]*v1[1]; vout[0] = tmp[0]; vout[1] = tmp[1]; vout[2] = tmp[2]; } float Unit( float v[3] ) { float dist; dist = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; if( dist > 0.0 ) { dist = sqrt( dist ); v[0] /= dist; v[1] /= dist; v[2] /= dist; } return dist; } float Unit( float vin[3], float vout[3] ) { float dist; dist = vin[0]*vin[0] + vin[1]*vin[1] + vin[2]*vin[2]; if( dist > 0.0 ) { dist = sqrt( dist ); vout[0] = vin[0] / dist; vout[1] = vin[1] / dist; vout[2] = vin[2] / dist; } else { vout[0] = vin[0]; vout[1] = vin[1]; vout[2] = vin[2]; } return dist; }