#ifndef OBJJEDI_H #define OBJJEDI_H /*OBJ reader and writer. One aspect of the writer is based on OpenGL output commands. You can send OpenGL commands (replacing "gl" and "GL" with "obj" and "OBJ" respectively to render to an Wavefront OBJ file */ //#include "rtsMath.h" #include "rtsLinearAlgebra.h" #include #include #include #include #include using namespace std; //masks for valid vertex components #define OBJ_V_X 0x1 #define OBJ_V_Y 0x2 #define OBJ_V_Z 0x4 #define OBJ_V_W 0x8 #define OBJ_VT_U 0x1 #define OBJ_VT_V 0x2 #define OBJ_VT_W 0x4 #define OBJ_VN_I 0x1 #define OBJ_VN_J 0x2 #define OBJ_VN_K 0x4 #define OBJ_V 0x1 #define OBJ_VT 0x2 #define OBJ_VN 0x4 //primitive types typedef unsigned char primitive_type; #define OBJ_END 0x0 #define OBJ_POINTS 0x1 #define OBJ_LINES 0x2 #define OBJ_FACE 0x3 #define OBJ_INVALID ULONG_MAX //define the point structures struct vertex_position{float x,y,z,w; unsigned char mask;}; struct vertex_texture{float u,v,w; unsigned char mask;}; struct vertex_normal{float i,j,k; unsigned char mask;}; //the point structure contains indices to the relative 3-vectors in the lists struct vertex { unsigned int v; unsigned int vt; unsigned int vn; }; struct primitive { vector p; //indices to the point unsigned char mask; //mask describing which features (v, vt, vn) are used primitive_type type; //the type of primitive (points, lines, face) }; //axis-aligned bounding box struct AABB { vertex_position min; vertex_position max; }; //create variable types typedef unsigned int OBJint; //define the OBJ data class class rtsOBJ { private: /*Current state variables. These variables are committed to the OBJ object when a vertex is added. However, we are careful to only add them once (if they don't change with every vertex. */ vertex_texture current_vt; vertex_normal current_vn; bool vt_changed; //true if a new vt or vn was inserted since the last vertex bool vn_changed; unsigned char current_primitive_mask; //defines what coordinates are being used by the current primitive //global variable storing the current render mode OBJint g_CurrentMode; //output file stream ofstream g_objFile; //obj file object //objData g_OBJ; //number of vertices since the last BEGIN unsigned int g_NumVertices; /*Attribute mask. This indicates what attributes are stored for each vertex. Only a single mask applies to each vertex between objBegin() and objEnd(). The attribute mask is flipped the first time an attribute is set but it is fixed after the first vertex is passed.*/ unsigned char g_AttributeMask; /*Attribute reset mask. This indicates whether or not an attribute has been reset since the last vertex was rendered. This applies to OBJ_VT and OBJ_VN*/ unsigned char g_AttributeResetMask; //latest texture coordinate sent unsigned int g_LatestVT; //latest vertex normal sent unsigned int g_LatestVN; //extents of the points in the OBJ file AABB m_bounds; OBJint f_InsertPointVertex(); OBJint f_InsertLineVertex(); OBJint f_InsertLineLoopVertex(); OBJint f_InsertLineStripVertex(); OBJint f_InsertTriangleVertex(); OBJint f_InsertTriangleStripVertex(); OBJint f_InsertTriangleFanVertex(); OBJint f_InsertQuadVertex(); OBJint f_InsertQuadStripVertex(); OBJint f_InsertPolygonVertex(); OBJint f_InsertPreviousFaceVertex(unsigned int v_index); OBJint f_InsertFirstFaceVertex(unsigned int v_index); OBJint f_InsertNewFaceVertex(); OBJint f_InsertNewLineVertex(); OBJint f_CreateNewFace(); OBJint f_CreateNewLine(); OBJint f_TerminateLineLoop(); OBJint f_LoadOBJ(const char* filename); OBJint f_LoadSWC(const char* filename); //insert coordinate commands //these are used to handle coordinates of different dimensions (and are called by the associated public function) OBJint f_InsertVertexf(float x, float y, float z, float w, unsigned char mask); OBJint f_InsertTexCoordf(float u, float v, float w, unsigned char mask); OBJint f_InsertNormalf(float i, float j, float k, unsigned char mask); //output functions void f_OutputVertices(); void f_OutputPoints(); void f_OutputLines(); void f_OutputFaces(); void f_OutputVertexNormals(); void f_OutputTextureCoordinates(); void f_ClearAll(); //methods for reading from a file OBJint f_ReadPosition(ifstream &infile); OBJint f_ReadNormal(ifstream &infile); OBJint f_ReadTexCoord(ifstream &infile); OBJint f_ReadVertex(ifstream &infile, vertex &new_point, unsigned char &mask); OBJint f_ReadPrimitive(ifstream &infile, primitive_type type); OBJint f_AdjustExtents(vertex_position v); public: /*These vectors store the vertex and primitive data from the obj file. All vertices, texture coordinates, and normals are stored in m_v, m_vt, m_vn respectively. The vectors for each primitive store an index into m_v, m_vt, and m_vn identifying the associated coordinate. Basically, the data is stored in a structure very similar to the OBJ file itself. */ vector v_list; vector vt_list; vector vn_list; vector primitives; vector points; vector lines; vector faces; public: OBJint objOpen(const char* filename); OBJint objBegin(OBJint obj_mode); OBJint objEnd(); OBJint objClose(); OBJint objNormal3f(float i, float j, float k); OBJint objNormal2f(float i, float j); OBJint objNormal1f(float i); OBJint objTexCoord3f(float u, float v, float w); OBJint objTexCoord2f(float u, float v); OBJint objTexCoord1f(float u); OBJint objVertex1f(float x); OBJint objVertex2f(float x, float y); OBJint objVertex3f(float x, float y, float z); OBJint objVertex4f(float x, float y, float z, float w); OBJint LoadFile(const char* filename); OBJint SaveFile(const char* filename); //direct insertion methods void insertVertexPosition(float x, float y, float z, unsigned char mask = OBJ_V_X | OBJ_V_Y | OBJ_V_Z); void insertLine(unsigned int num_points, unsigned int* pointlist, unsigned int* normallist, unsigned int* texturelist); //get methods unsigned int getNumVertices(); unsigned int getNumLines(); unsigned int getNumFaces(); unsigned int getNumPointLists(); unsigned int getNumTexCoords(); unsigned int getNumNormals(); //these functions return the coordinate index as well as the value unsigned int getNumFaceVertices(unsigned int face); unsigned int getFaceVertex(unsigned int face, unsigned int vertex); unsigned int getFaceNormal(unsigned int face, unsigned int normal); unsigned int getFaceTexCoord(unsigned int face, unsigned int texcoord); unsigned int getNumLineVertices(unsigned int line); unsigned int getLineVertex(unsigned int line, unsigned int vertex); unsigned int getLineTexCoord(unsigned int line, unsigned int texcoord); point3D getVertex3d(unsigned int index); point3D getTexCoord3d(unsigned int index); point3D getNormal3d(unsigned int index); vertex_position getVertex(unsigned int index); vertex_texture getTexCoord(unsigned int index); vertex_normal getNormal(unsigned int index); AABB getBoundingBox(){return m_bounds;} void Scale(float scale_x, float scale_y, float scale_z); void Translate(float trans_x, float trans_y, float trans_z); float GetDistance(float x, float y, float z); //return data about primitives unsigned int getPrimitiveType(unsigned int primitive); //constructors rtsOBJ(); void CopyOBJ(const rtsOBJ& obj); //assignment rtsOBJ& operator=(const rtsOBJ& obj) { CopyOBJ(obj); return *this; } //copy rtsOBJ(const rtsOBJ& obj) { CopyOBJ(obj); //return *this; } //Iterator stuff class iterator { friend class rtsOBJ; private: rtsOBJ* obj; bool end_primitive; bool end_object; unsigned int primitive_index; public: unsigned int operator*(); void operator++(); bool operator==(rtsOBJ::iterator operand); bool operator!=(rtsOBJ::iterator operand); unsigned int size(){return obj->primitives[primitive_index].p.size();}; void print(); }; iterator begin(); iterator end(); }; //define error codes #define OBJ_OK 0x0100 #define OBJ_ERROR 0x0101 //define the different modes #define OBJ_NONE 0x0 #define OBJ_POINTS 0x1 #define OBJ_LINES 0x2 #define OBJ_LINE_STRIP 0x3 #define OBJ_LINE_LOOP 0x4 #define OBJ_TRIANGLES 0x5 #define OBJ_TRIANGLE_STRIP 0x6 #define OBJ_TRIANGLE_FAN 0x7 #define OBJ_QUADS 0x8 #define OBJ_QUAD_STRIP 0x9 #define OBJ_POLYGON 0x10 //initialize the OBJ file OBJint objOpen(char* filename); //close the obj file OBJint objClose(); //start rendering in a certain mode OBJint objBegin(OBJint mode); //stop the current rendering sequence OBJint objEnd(void); //render a vertex to the file OBJint objVertex1f(float x); OBJint objVertex2f(float x, float y); OBJint objVertex3f(float x, float y, float z); OBJint objVertex4f(float x, float y, float z, float w); //set a normal vector for a vertex OBJint objNormal3f(float i, float j, float k); OBJint objNormal2f(float i, float j); OBJint objNormal1f(float i); //set a texture coordinate for a vertex OBJint objTexCoord3f(float u, float v, float w); OBJint objTexCoord2f(float u, float v); OBJint objTexCoord1f(float u); //global variable for global functions extern rtsOBJ g_OBJ; /*BUG NOTES The standard function calls for inserting vertices don't work anymore. I've fixed points but everything beyond that has to be updated. */ #include "objJedi.h" #include "rtsVector3d.h" #include "rtsPoint3d.h" #include //variable for use in global functions rtsOBJ g_OBJ; /********UTILITY METHODS*******************************/ void rtsOBJ::Scale(float scale_x, float scale_y, float scale_z) { vector::iterator i; for(i = v_list.begin(); i!= v_list.end(); i++) { (*i).x *= scale_x; (*i).y *= scale_y; (*i).z *= scale_z; } } void rtsOBJ::Translate(float trans_x, float trans_y, float trans_z) { vector::iterator i; for(i = v_list.begin(); i!= v_list.end(); i++) { (*i).x += trans_x; (*i).y += trans_y; (*i).z += trans_z; } } float rtsOBJ::GetDistance(float x, float y, float z) { //gets the distance between the specified point and the nearest surface of the OBJ //currently only works for lines //cout<<"Primitives: "< p0, p1, p2; float min_dist = 255; float dist; unsigned int p, l; vector3D v, w; float c1, c2, b; point3D Pb; //for each line for(l=0; l OBJ_POLYGON) return OBJ_ERROR; //otherwise, go ahead and set the mode g_CurrentMode = mode; //set the number of vertices to zero g_NumVertices = 0; //reset the current state primitive state current_primitive_mask = 0x0; return OBJ_OK; } OBJint rtsOBJ::objEnd() { OBJint error = OBJ_OK; //check to make sure the number of rendered vertices is valid for the current mode switch(g_CurrentMode) { case OBJ_NONE: //can't quit if we haven't started error = OBJ_ERROR; break; case OBJ_LINES: //if less than two vertices or an odd number of vertices if(g_NumVertices < 2 || g_NumVertices%2 != 0) { //if there wasn't a vertex at all if(g_NumVertices == 0) error = OBJ_ERROR; //if there was at least one vertex else { //pop the last line off the list primitives.pop_back(); lines.pop_back(); error = OBJ_ERROR; } } break; case OBJ_LINE_STRIP: //if less than two vertices if(g_NumVertices < 2) { //if there wasn't a vertex at all if(g_NumVertices == 0) error = OBJ_ERROR; //if there was at least one vertex else { //pop the last line off the list primitives.pop_back(); lines.pop_back(); error = OBJ_ERROR; } } break; case OBJ_LINE_LOOP: //if less than three vertices if(g_NumVertices < 3) { //pop the last line off the list primitives.pop_back(); lines.pop_back(); error = OBJ_ERROR; } //connect the first and last points else { error = f_TerminateLineLoop(); } break; case OBJ_TRIANGLES: //if less than three vertices or not a power of three if(g_NumVertices < 3 || g_NumVertices%3 !=0) { primitives.pop_back(); faces.pop_back(); error = OBJ_ERROR; } break; case OBJ_TRIANGLE_STRIP: //if less than three vertices if(g_NumVertices < 3) { primitives.pop_back(); faces.pop_back(); error = OBJ_ERROR; } break; case OBJ_TRIANGLE_FAN: //if less than three vertices if(g_NumVertices < 3) { primitives.pop_back(); faces.pop_back(); error = OBJ_ERROR; } break; case OBJ_QUADS: if(g_NumVertices < 4 || g_NumVertices%4 != 0) { primitives.pop_back(); faces.pop_back(); error = OBJ_ERROR; } break; case OBJ_QUAD_STRIP: //has to be at least 4 vertices and an even number if(g_NumVertices < 4 || g_NumVertices%2 != 0) { primitives.pop_back(); faces.pop_back(); error = OBJ_ERROR; } break; case OBJ_POLYGON: //has to be at least three vertices if(g_NumVertices < 3) { primitives.pop_back(); faces.pop_back(); error = OBJ_ERROR; } break; } //reset the attribute mask g_AttributeMask = 0x0; //just for closure, reset the attribute reset mask g_AttributeResetMask = 0x0; //stop rendering g_CurrentMode = OBJ_NONE; return error; } OBJint rtsOBJ::f_InsertVertexf(float x, float y, float z, float w, unsigned char mask) { //make sure we're rendering if(g_CurrentMode == OBJ_NONE) return OBJ_ERROR; //insert the vertex into the vertex vector vertex_position v; v.x = x; v.y = y; v.z=z; v.w=w; v.mask = mask; v_list.push_back(v); f_AdjustExtents(v); //set the bounding box //insert texture coordinate and normal if specified for this primitive if((current_primitive_mask & OBJ_VT) && (vt_changed)) vt_list.push_back(current_vt); if((current_primitive_mask & OBJ_VN) && (vn_changed)) vn_list.push_back(current_vn); //increment the number of vertices inserted g_NumVertices++; //handle each case of the vertex creation individually OBJint error = OBJ_OK; switch(g_CurrentMode) { case OBJ_POINTS: error = f_InsertPointVertex(); break; case OBJ_LINES: error = f_InsertLineVertex(); break; case OBJ_LINE_LOOP: error = f_InsertLineLoopVertex(); break; case OBJ_LINE_STRIP: error = f_InsertLineStripVertex(); break; case OBJ_TRIANGLES: error = f_InsertTriangleVertex(); break; case OBJ_TRIANGLE_STRIP: error = f_InsertTriangleStripVertex(); break; case OBJ_TRIANGLE_FAN: error = f_InsertTriangleFanVertex(); break; case OBJ_QUADS: error = f_InsertQuadVertex(); break; case OBJ_QUAD_STRIP: error = f_InsertQuadStripVertex(); break; case OBJ_POLYGON: error = f_InsertPolygonVertex(); break; } //set the reset mask to zero g_AttributeResetMask = 0x0; //set the attribute mask to include vertex position g_AttributeMask = g_AttributeMask | OBJ_V; //return the result of the insertion return error; } OBJint rtsOBJ::objVertex1f(float x) { return f_InsertVertexf(x, 0.0, 0.0, 0.0, OBJ_V_X); } OBJint rtsOBJ::objVertex2f(float x, float y) { return f_InsertVertexf(x, y, 0.0, 0.0, OBJ_V_X | OBJ_V_Y); } OBJint rtsOBJ::objVertex3f(float x, float y, float z) { return f_InsertVertexf(x, y, z, 0.0, OBJ_V_X | OBJ_V_Y | OBJ_V_Z); } OBJint rtsOBJ::objVertex4f(float x, float y, float z, float w) { return f_InsertVertexf(x, y, z, w, OBJ_V_X | OBJ_V_Y | OBJ_V_Z | OBJ_V_W); } OBJint rtsOBJ::objNormal3f(float i, float j, float k) { return f_InsertNormalf(i, j, k, OBJ_VN_I | OBJ_VN_J | OBJ_VN_K); } OBJint rtsOBJ::objNormal2f(float i, float j) { return f_InsertNormalf(i, j, 0.0, OBJ_VN_I | OBJ_VN_J); } OBJint rtsOBJ::objNormal1f(float i) { return f_InsertNormalf(i, 0.0, 0.0, OBJ_VN_I); } OBJint rtsOBJ::f_InsertNormalf(float i, float j, float k, unsigned char mask) { /*DEPRECATED //if the mode is not rendering faces, there is an error if(g_CurrentMode < OBJ_TRIANGLES) return OBJ_ERROR; //if the normal attribute flag is not set, set it (as long as a vertex hasn't been written) if(!(g_AttributeMask & OBJ_VN)) { //if a vertex has been rendered, then we can't change the attribute, so exit if(g_NumVertices > 0) return OBJ_ERROR; else //otherwise, just set the attribute flag g_AttributeMask = g_AttributeMask | OBJ_VN; } //insert the new normal into the normal list for the file vertex_normal new_vn; new_vn.i = i; new_vn.j = j; new_vn.k = k; new_vn.mask = mask; vn_list.push_back(new_vn); */ current_vn.i = i; //set the current texture state to the given coordinates current_vn.j = j; current_vn.k = k; current_vn.mask = mask; //set the mask as appropriate vn_changed = true; //the texture coordinate state has changed current_primitive_mask = current_primitive_mask | OBJ_VN; //the current primitive now uses texture coordinates (if it didn't previously) return OBJ_OK; } OBJint rtsOBJ::objTexCoord3f(float u, float v, float w) { return f_InsertTexCoordf(u, v, w, OBJ_VT_U | OBJ_VT_V | OBJ_VT_W); } OBJint rtsOBJ::objTexCoord2f(float u, float v) { return f_InsertTexCoordf(u, v, 0.0, OBJ_VT_U | OBJ_VT_V); } OBJint rtsOBJ::objTexCoord1f(float u) { return f_InsertTexCoordf(u, 0.0, 0.0, OBJ_VT_U); } OBJint rtsOBJ::f_InsertTexCoordf(float u, float v, float w, unsigned char mask) { /* DEPRECATED //if the normal attribute flag is not set, set it (as long as a vertex hasn't been written) if(!(g_AttributeMask & OBJ_VT)) { //if a vertex has been rendered, then we can't change the attribute, so exit if(g_NumVertices > 0) return OBJ_ERROR; else //otherwise, just set the attribute flag g_AttributeMask = g_AttributeMask | OBJ_VT; } //insert the new texture coordinate into the list for the file vertex_texture new_vt; new_vt.u = u; new_vt.v = v; new_vt.w = w; new_vt.mask = mask; vt_list.push_back(new_vt); */ current_vt.u = u; //set the current texture state to the given coordinates current_vt.v = v; current_vt.w = w; current_vt.mask = mask; //set the mask as appropriate vt_changed = true; //the texture coordinate state has changed current_primitive_mask = current_primitive_mask | OBJ_VT; //the current primitive now uses texture coordinates (if it didn't previously) return OBJ_OK; } void rtsOBJ::insertVertexPosition(float x, float y, float z, unsigned char mask) { vertex_position v; v.x = x; v.y = y; v.z = z; v.mask = mask; v_list.push_back(v); } void rtsOBJ::insertLine(unsigned int num_points, unsigned int* pointlist, unsigned int* normallist, unsigned int* texturelist) { //create the new primitive primitive line; line.type = OBJ_LINES; line.mask = 0; //set the mask based on the passed data if(pointlist != NULL) line.mask = line.mask | OBJ_V; if(normallist != NULL) line.mask = line.mask | OBJ_VN; if(texturelist != NULL) line.mask = line.mask | OBJ_VT; //insert the line unsigned int v; vertex new_vert; for(v=0; v 1) points.push_back(p_index); return OBJ_OK; } OBJint rtsOBJ::f_InsertLineVertex() { //if this is an odd vertex, create a new line if(g_NumVertices%2 == 1) { f_CreateNewLine(); } f_InsertNewLineVertex(); return OBJ_OK; } OBJint rtsOBJ::f_InsertLineLoopVertex() { //technically, this is the same as inserting a line strip vertex f_InsertLineStripVertex(); return OBJ_OK; } OBJint rtsOBJ::f_InsertLineStripVertex() { if(g_NumVertices == 1) { f_CreateNewLine(); } f_InsertNewLineVertex(); return OBJ_OK; } OBJint rtsOBJ::f_InsertTriangleVertex() { //if this is the first vertex in a triangle, create a new triangle if(g_NumVertices%3 == 1) { f_CreateNewFace(); } f_InsertNewFaceVertex(); return OBJ_OK; } OBJint rtsOBJ::f_InsertTriangleStripVertex() { //in the special case of the first three vertices, just create a triangle if(g_NumVertices < 4) f_InsertTriangleVertex(); else { //create a new face for the new triangle f_CreateNewFace(); //make sure to get the ordering right: // Even vertices provide the previous two vertices "in order": (v2, v3, v4) // Odd vertices provide the previous two vertices in reverse order: (v1, v3, v2) if(g_NumVertices % 2 == 1) { f_InsertPreviousFaceVertex(2); f_InsertPreviousFaceVertex(1); f_InsertNewFaceVertex(); } else { f_InsertPreviousFaceVertex(1); f_InsertNewFaceVertex(); f_InsertPreviousFaceVertex(2); } } return OBJ_OK; } OBJint rtsOBJ::f_InsertTriangleFanVertex() { //in the special case of the first three vertices, just create a triangle if(g_NumVertices <4) f_InsertTriangleVertex(); else { //create a new face for the new triangle f_CreateNewFace(); //add the previous vertices to the face f_InsertFirstFaceVertex(0); f_InsertPreviousFaceVertex(2); //insert the current vertex f_InsertNewFaceVertex(); } return OBJ_OK; } OBJint rtsOBJ::f_InsertQuadVertex() { //if this is the first vertex in a quad, create a new quad if(g_NumVertices%4 == 1) { f_CreateNewFace(); } f_InsertNewFaceVertex(); return OBJ_OK; } OBJint rtsOBJ::f_InsertQuadStripVertex() { //in the case of one of the first four vertices, just create a quad if(g_NumVertices < 5) f_InsertQuadVertex(); //if the vertex is odd (it will be the third vertex of a quad) else if(g_NumVertices%2 == 1) { //create a new face for the new quad f_CreateNewFace(); //add the previous two vertices f_InsertPreviousFaceVertex(2); f_InsertPreviousFaceVertex(3); //add the current vertex f_InsertNewFaceVertex(); } else { //if this is the last vertex of the quad, just add it f_InsertNewFaceVertex(); } return OBJ_OK; } OBJint rtsOBJ::f_InsertPolygonVertex() { //if this is the first vertex, create the quad if(g_NumVertices == 1) { f_CreateNewFace(); } f_InsertNewFaceVertex(); return OBJ_OK; } OBJint rtsOBJ::f_InsertPreviousFaceVertex(unsigned int v_index) { /*Finds the vertex used in the previous face with the given index and inserts it into the current face. This limits the redundancy in the file for re-used vertices (in strips and fans). This also transfers texture and normal information.*/ //find the index of the previous face unsigned int prev_f_index = primitives.size() - 2; //find the index of the current face unsigned int f_index = prev_f_index +1; //add the vertex information from the previous face to this face primitives[f_index].p.push_back(primitives[prev_f_index].p[v_index]); return OBJ_OK; } OBJint rtsOBJ::f_InsertFirstFaceVertex(unsigned int v_index) { /*Finds the vertex used in the first face (since the last objBegin()) with the given index and inserts it at the end of the current face. This includes texture and normal information.*/ //The result depends on the type of face being rendered //So far, this function only applies to triangle fans if(g_CurrentMode != OBJ_TRIANGLE_FAN) return OBJ_ERROR; //calculate the number of faces that have been rendered unsigned int num_faces = g_NumVertices - 2; //find the index of the first face unsigned int first_f_index = primitives.size() - num_faces; //find the index of the current face unsigned int f_index = primitives.size() - 1; //transfer the vertex information from the first face to this one primitives[f_index].p.push_back(primitives[first_f_index].p[v_index]); return OBJ_OK; } OBJint rtsOBJ::f_InsertNewFaceVertex() { /*This inserts information about the current vertex into the current face*/ //find the new vertex index vertex p; p.v = v_list.size() -1; p.vt = vt_list.size() - 1; p.vn = vn_list.size() -1; //find the face index unsigned int f_index = primitives.size() -1; //INSERT VERTEX AND ATTRIBUTE DATA //just add the vertex to the face primitives[f_index].p.push_back(p); return OBJ_OK; } OBJint rtsOBJ::f_InsertNewLineVertex() { /*This inserts information about the current vertex into the current line*/ //find the new vertex index vertex p; p.v = v_list.size() -1; p.vt = vt_list.size() - 1; //find the line index unsigned int l_index = primitives.size() -1; //ADD VERTEX AND ATTRIBUTE INFORMATION //add the vertex to the line primitives[l_index].p.push_back(p); return OBJ_OK; } OBJint rtsOBJ::f_CreateNewFace() { primitive new_f; new_f.type = OBJ_FACE; new_f.mask = g_AttributeMask; faces.push_back(primitives.size()); primitives.push_back(new_f); return OBJ_OK; } OBJint rtsOBJ::f_CreateNewLine() { primitive new_l; new_l.type = OBJ_LINES; new_l.mask = g_AttributeMask; lines.push_back(primitives.size()); primitives.push_back(new_l); return OBJ_OK; } OBJint rtsOBJ::f_TerminateLineLoop() { /*This function just terminates the line loop by setting the last vertex to the first vertex.*/ if(g_CurrentMode != OBJ_LINE_LOOP) return OBJ_ERROR; //find the index for the current line unsigned int l_index = lines.size() -1; //insert the first vertex as the last vertex primitives[l_index].p.push_back(primitives[l_index].p[0]); return OBJ_OK; } void rtsOBJ::f_OutputVertices() { //get the number of vertices in the object unsigned int v_num = v_list.size(); for(unsigned int i=0; i>new_vertex.x; new_vertex.mask = OBJ_V_X; if(infile.peek() == ' ') { infile>>new_vertex.y; new_vertex.mask = new_vertex.mask | OBJ_V_Y; } if(infile.peek() == ' ') { infile>>new_vertex.z; new_vertex.mask = new_vertex.mask | OBJ_V_Z; } if(infile.peek() == ' ') { infile>>new_vertex.w; new_vertex.mask = new_vertex.mask | OBJ_V_W; } int c = infile.peek(); //ignore the rest of the line infile.ignore(1000, '\n'); c = infile.peek(); //cout<<"vertex read: "<>new_normal.i; new_normal.mask = OBJ_VN_I; //get every other component if(infile.peek() == ' ') { infile>>new_normal.j; new_normal.mask = new_normal.mask | OBJ_VN_J; } if(infile.peek() == ' ') { infile>>new_normal.k; new_normal.mask = new_normal.mask | OBJ_VN_K; } //ignore the rest of the line infile.ignore(1000, '\n'); //insert the normal vn_list.push_back(new_normal); return OBJ_OK; } OBJint rtsOBJ::f_ReadTexCoord(ifstream &infile) { vertex_texture new_texcoord; infile>>new_texcoord.u; new_texcoord.mask = OBJ_VT_U; //get every other component if(infile.peek() == ' ') { infile>>new_texcoord.v; new_texcoord.mask = new_texcoord.mask | OBJ_VT_V; } if(infile.peek() == ' ') { infile>>new_texcoord.w; new_texcoord.mask = new_texcoord.mask | OBJ_VT_W; } //ignore the rest of the line infile.ignore(1000, '\n'); //insert the texture coordinate vt_list.push_back(new_texcoord); return OBJ_OK; } OBJint rtsOBJ::f_ReadVertex(ifstream &infile, vertex &new_point, unsigned char &mask) { //store the line vertex infile>>new_point.v; new_point.v--; mask = OBJ_V; //new_face.v.push_back(new_v - 1); if(infile.peek() == '/') { infile.get(); //if there actually is a texcoord if(infile.peek() != '/') { infile>>new_point.vt; //get the index new_point.vt--; mask = mask | OBJ_VT; //update the mask //new_face.vt.push_back(new_vt - 1); } } //check for a normal if(infile.peek() == '/') { infile.get(); infile>>new_point.vn; //get the index new_point.vn--; mask = mask | OBJ_VN; //update the mask } return OBJ_OK; } OBJint rtsOBJ::f_ReadPrimitive(ifstream &infile, primitive_type type) { //create a new point list primitive new_primitive; new_primitive.type = type; //until the end of the line while(infile.peek() != '\n') { //read each point if(infile.peek() == ' ') infile.get(); else { vertex new_point; f_ReadVertex(infile, new_point, new_primitive.mask); new_primitive.p.push_back(new_point); } } //ignore the rest of the line infile.ignore(1000, '\n'); //push the id of the primitive into the new list //:DEBUG: if(type == OBJ_POINTS) points.push_back(primitives.size()); else if(type == OBJ_LINES) lines.push_back(primitives.size()); else if(type == OBJ_FACE) faces.push_back(primitives.size()); primitives.push_back(new_primitive); //push the new primitive return OBJ_OK; } OBJint rtsOBJ::f_AdjustExtents(vertex_position v) { if(v.x < m_bounds.min.x) m_bounds.min.x = v.x; if(v.y < m_bounds.min.y) m_bounds.min.y = v.y; if(v.z < m_bounds.min.z) m_bounds.min.z = v.z; if(v.x > m_bounds.max.x) m_bounds.max.x = v.x; if(v.y > m_bounds.max.y) m_bounds.max.y = v.y; if(v.z > m_bounds.max.z) m_bounds.max.z = v.z; return OBJ_OK; } OBJint rtsOBJ::f_LoadOBJ(const char* filename) { f_ClearAll(); //open the file as a stream ifstream infile; infile.open(filename); if(!infile) exit(1); unsigned int vertices = 0; string token; infile>>token; while(!infile.eof()) { //if the token is some vertex property if(token == "v") f_ReadPosition(infile); else if(token == "vn") f_ReadNormal(infile); else if(token == "vt") f_ReadTexCoord(infile); else if(token == "p") f_ReadPrimitive(infile, OBJ_POINTS); else if(token == "l") f_ReadPrimitive(infile, OBJ_LINES); else if(token == "f") f_ReadPrimitive(infile, OBJ_FACE); else infile.ignore(9999, '\n'); //vertices++; infile>>token; } } OBJint rtsOBJ::f_LoadSWC(const char* filename) { f_ClearAll(); //open the file as a stream ifstream infile; infile.open(filename); if(!infile.is_open()) return OBJ_ERROR; vector swcVertices; float token; objBegin(OBJ_LINES); while(!infile.eof()) { vertex_position v; infile>>token; //get the id infile>>token; //get the fiber type infile>>v.x; //get the node position infile>>v.y; infile>>v.z; infile>>token; //get the radius infile>>token; //get the parent //insert the node into the swc vector swcVertices.push_back(v); //now draw the line from the parent to the current node if(token != -1) { unsigned int i = (unsigned int)token - 1; objVertex3f(swcVertices[i].x, swcVertices[i].y, swcVertices[i].z); objVertex3f(v.x, v.y, v.z); } } objEnd(); return OBJ_OK; } OBJint rtsOBJ::LoadFile(const char* filename) { string strFilename = filename; int length = strFilename.length(); string extension = strFilename.substr(strFilename.length() - 3, 3); if(!extension.compare(string("obj"))) return f_LoadOBJ(filename); else if(!extension.compare(string("swc"))) return f_LoadSWC(filename); else return f_LoadOBJ(filename); } OBJint rtsOBJ::SaveFile(const char* filename) { //open the file as a stream ofstream outfile; outfile.open(filename); if(!outfile.is_open()) return OBJ_ERROR; //output vertex positions vector::iterator v; for(v=v_list.begin(); v!= v_list.end(); v++) { outfile<<"v"; if((*v).mask & OBJ_V_X) { outfile<<' '<<(*v).x; if((*v).mask & OBJ_V_Y) { outfile<<' '<<(*v).y; if((*v).mask & OBJ_V_Z) { outfile<<' '<<(*v).z; if((*v).mask & OBJ_V_W) outfile<<' '<<(*v).w; } } } outfile<<'\n'; } //output vertex texture coordinates vector::iterator vt; for(vt=vt_list.begin(); vt!= vt_list.end(); vt++) { outfile<<"vt"; if((*vt).mask & OBJ_VT_U) { outfile<<' '<<(*vt).u; if((*vt).mask & OBJ_VT_V) { outfile<<' '<<(*vt).v; if((*vt).mask & OBJ_VT_W) outfile<<' '<<(*vt).w; } } outfile<<'\n'; } //output vertex normal coordinates vector::iterator vn; for(vn=vn_list.begin(); vn!= vn_list.end(); vn++) { outfile<<"vn"; if((*vn).mask & OBJ_VN_I) { outfile<<' '<<(*vn).i; if((*vn).mask & OBJ_VN_J) { outfile<<' '<<(*vn).j; if((*vn).mask & OBJ_VN_K) outfile<<' '<<(*vn).k; } } outfile<<'\n'; } //output each primitive vector::iterator p; vector::iterator vert; for(p=primitives.begin(); p!= primitives.end(); p++) { switch((*p).type) { case OBJ_POINTS: outfile<<"p"; //output the points token break; case OBJ_LINES: outfile<<"l"; //output the lines token break; case OBJ_FACE: outfile<<"f"; //output the face token break; } //for each vertex in the list for the primitive for(vert = (*p).p.begin(); vert != (*p).p.end(); vert++) { outfile<<' '<<(*vert).v + 1; if((*p).mask & OBJ_VT) outfile<<'/'<<(*vert).vt + 1; if((*p).mask & OBJ_VN) { if(!((*p).mask & OBJ_VT)) outfile<<'/'; outfile<<'/'<<(*vert).vn + 1; } } outfile<<'\n'; } } //get methods unsigned int rtsOBJ::getNumVertices(){return v_list.size();} unsigned int rtsOBJ::getNumLines(){return lines.size();} unsigned int rtsOBJ::getNumFaces(){return faces.size();} unsigned int rtsOBJ::getNumPointLists(){return points.size();} unsigned int rtsOBJ::getNumTexCoords(){return vt_list.size();} unsigned int rtsOBJ::getNumNormals(){return vn_list.size();} //these functions return the coordinate index as well as the value unsigned int rtsOBJ::getNumFaceVertices(unsigned int face){return primitives[face].p.size();} unsigned int rtsOBJ::getFaceVertex(unsigned int face, unsigned int vertex){return primitives[face].p[vertex].v;} unsigned int rtsOBJ::getFaceNormal(unsigned int face, unsigned int normal){return primitives[face].p[normal].vn;} unsigned int rtsOBJ::getFaceTexCoord(unsigned int face, unsigned int texcoord){return primitives[face].p[texcoord].vt;} unsigned int rtsOBJ::getNumLineVertices(unsigned int line){return primitives[line].p.size();} unsigned int rtsOBJ::getLineVertex(unsigned int line, unsigned int vertex){return primitives[line].p[vertex].v;} unsigned int rtsOBJ::getLineTexCoord(unsigned int line, unsigned int texcoord){return primitives[line].p[texcoord].vt;} point3D rtsOBJ::getVertex3d(unsigned int index) { return point3D(v_list[index].x, v_list[index].y, v_list[index].z); } point3D rtsOBJ::getTexCoord3d(unsigned int index) { return point3D(vt_list[index].u, vt_list[index].v, vt_list[index].w); } point3D rtsOBJ::getNormal3d(unsigned int index) { return point3D(vn_list[index].i, vn_list[index].j, vn_list[index].k); } vertex_position rtsOBJ::getVertex(unsigned int index){return v_list[index];} vertex_texture rtsOBJ::getTexCoord(unsigned int index){return vt_list[index];} vertex_normal rtsOBJ::getNormal(unsigned int index){return vn_list[index];} unsigned int rtsOBJ::getPrimitiveType(unsigned int primitive) { /* switch(primitives[i].type) { case OBJ_POINTS: return OBJ_POINTS; break; case OBJ_LINES: return OBJ_LINES; break; case OBJ_FACE: f_RenderFace(i); break; }*/ return 0; } /****************************************************/ /*******Iterator Methods*****************************/ /****************************************************/ rtsOBJ::iterator rtsOBJ::begin() { //create an iterator that will be returned and assign it to this OBJ iterator result; result.obj = this; result.end_object = false; result.end_primitive = false; //if there are no primitives, return the end iterator if(primitives.size() == 0) return end(); //start at the beginning of the primitive array result.primitive_index = 0; return result; } rtsOBJ::iterator rtsOBJ::end() { //create an end iterator to return iterator result; result.obj = this; result.end_primitive = true; result.primitive_index = result.obj->primitives.size(); return result; } void rtsOBJ::iterator::operator++() { primitive_index++; if(primitive_index >= obj->primitives.size()) (*this) = obj->end(); } bool rtsOBJ::iterator::operator ==(rtsOBJ::iterator operand) { if(operand.primitive_index == primitive_index) return true; else return false; } bool rtsOBJ::iterator::operator !=(rtsOBJ::iterator operand) { if(operand.primitive_index != primitive_index) return true; else return false; } unsigned int rtsOBJ::iterator::operator*() { return primitive_index; } void rtsOBJ::iterator::print() { cout<<"This is a test"<