#include #include #include #include #include #include #include "typedefs.h" #include "C_3DObject.h" #include "bitmap.h" C_3DObject::C_3DObject() : m_Pos(0.0, 0.0, 0.0), m_Rot(0.0, 0.0, 0.0), m_Scale(1.0, 1.0, 1.0), m_bOwnTexture(false), m_bDispListValid(false) { //std::cout << "C_3DObject:: default constructor\n"; } C_3DObject::C_3DObject(const char* f_strFileName, char* f_strColorTexName, MatProps_t f_Material) : m_Pos(0.0, 0.0, 0.0), m_Rot(0.0, 0.0, 0.0), m_Scale(1.0, 1.0, 1.0), m_bOwnTexture(false), m_bDispListValid(false), m_Mat(f_Material) { BitmapStruct l_bmp; //load 3d model m_bDispListValid = CreateObject(f_strFileName); //load textures if (m_bDispListValid) { if (f_strColorTexName != NULL) { std::cout << "Loading " << f_strColorTexName << std::endl; l_bmp = BitmapLoad(f_strColorTexName); m_uiColorTex = (GLuint)l_bmp.m_iImageId; m_bOwnTexture = true; } } } C_3DObject::C_3DObject(const char* f_strFileName, GLuint f_uiTexture, MatProps_t f_Material) : m_Pos(0.0, 0.0, 0.0), m_Rot(0.0, 0.0, 0.0), m_Scale(1.0, 1.0, 1.0), m_bOwnTexture(false), m_bDispListValid(false), m_uiColorTex(f_uiTexture), m_Mat(f_Material) { //load 3d model m_bDispListValid = CreateObject(f_strFileName); } C_3DObject::~C_3DObject() { if (glIsList(m_uiListIndex)) glDeleteLists(m_uiListIndex, 1); if (glIsTexture(m_uiColorTex) && m_bOwnTexture) glDeleteTextures(1, &m_uiColorTex); } void C_3DObject::TransRotateScale() { glTranslated(m_Pos.x, m_Pos.y, m_Pos.z); glRotated(m_Rot.z, 0.0, 0.0, 1.0); glRotated(m_Rot.x, 1.0, 0.0, 0.0); glRotated(m_Rot.y, 0.0, 1.0, 0.0); glScaled(m_Scale.x, m_Scale.y, m_Scale.z); } void C_3DObject::Render(GLint f_iTexLocation) { //apply OpenGL settings for rendering this Object glPushAttrib(GL_TEXTURE_BIT); glEnable(GL_TEXTURE_2D); //modulate the texture color with the computed material //colors glActiveTexture(GL_TEXTURE0); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glBindTexture(GL_TEXTURE_2D, m_uiColorTex); if (f_iTexLocation != 0) { glUniform1i(f_iTexLocation, 0); } //set material properties glMaterialfv(GL_FRONT, GL_AMBIENT, m_Mat.m_fAmb); glMaterialfv(GL_FRONT, GL_DIFFUSE, m_Mat.m_fDif); glMaterialfv(GL_FRONT, GL_SPECULAR, m_Mat.m_fSpec); glMaterialfv(GL_FRONT, GL_EMISSION, m_Mat.m_fEmi); glMaterialf(GL_FRONT, GL_SHININESS, m_Mat.m_fShin); //render by calling the display list if(m_bDispListValid) { glCallList(m_uiListIndex); } else { //or render a LARGE cube when we failed to load the //geometry glutSolidCube(1.0); } glPopAttrib(); } bool C_3DObject::CreateObject(const char *f_pFilePath) { Geometry_t l_Geom; bool l_bParseOk; Vect3D_t l_DummyVect; //the triangle indices are 1-based so we insert dummy Vect3D_t //to fill the 0 positions in the vertex, normals and texcoords //vector containers. l_Geom.m_verts.push_back(l_DummyVect); l_Geom.m_norms.push_back(l_DummyVect); l_Geom.m_texs.push_back(l_DummyVect); l_bParseOk = LoadGeometryData(f_pFilePath, l_Geom); ////output statistics //std::cout << "C_3DObject: file " << f_pFilePath // << "\nParse: " << (l_bParseOk? "SUCCESS" : "FAILURE") // << "\nVertices: " << l_Geom.m_verts.size()-1 // << "\nNormals: " << l_Geom.m_norms.size()-1 // << "\nTexCrds: " << l_Geom.m_texs.size()-1 // << "\nTriangles: " << l_Geom.m_triangles.size() // << "\nBoundBox: x(" << m_BBox.m_Min.x << "," << m_BBox.m_Max.x << ")" // << "\n y(" << m_BBox.m_Min.y << "," << m_BBox.m_Max.y << ")" // << "\n z(" << m_BBox.m_Min.z << "," << m_BBox.m_Max.z << ")" // << std::endl; if(!l_bParseOk) { std::cout << "C_3DObject Error: failed to parse file " << f_pFilePath << std::endl; //set bounding box to the size of a unit cube m_BBox.m_Max = Vect3D_t(0.5, 0.5, 0.5); m_BBox.m_Min = Vect3D_t(-0.5, -0.5, -0.5); return false; } //create display list m_uiListIndex = glGenLists(1); glNewList(m_uiListIndex, GL_COMPILE); glBegin(GL_TRIANGLES); //iterate through the triangles std::vector::iterator it = l_Geom.m_triangles.begin(); for(; it != l_Geom.m_triangles.end(); it++) { //vertex1 Vect3D_t v = l_Geom.m_verts[it->v1], t = l_Geom.m_texs[it->t1], n = l_Geom.m_norms[it->n1]; glNormal3d(n.x, n.y, n.z); glTexCoord3d(t.x, t.y, t.z); glVertex3d(v.x, v.y, v.z); //vertex2 v = l_Geom.m_verts[it->v2], t = l_Geom.m_texs[it->t2], n = l_Geom.m_norms[it->n2]; glNormal3d(n.x, n.y, n.z); glTexCoord3d(t.x, t.y, t.z); glVertex3d(v.x, v.y, v.z); //vertex3 v = l_Geom.m_verts[it->v3], t = l_Geom.m_texs[it->t3], n = l_Geom.m_norms[it->n3]; glNormal3d(n.x, n.y, n.z); glTexCoord3d(t.x, t.y, t.z); glVertex3d(v.x, v.y, v.z);} glEnd(); glEndList(); return true; } bool C_3DObject::LoadGeometryData(const char *f_pFilePath, Geometry_t &f_Geom) { std::ifstream l_infile(f_pFilePath); char l_inbuffer[256]; bool l_bParseOk = true; Vect3D_t l_v3; Triangle_t l_tri; if (l_infile.fail()) { std::cout << "C_3DObject Error: could not open file " << f_pFilePath << std::endl; return false; } //load data while(!l_infile.eof() && l_bParseOk) { //read the next line l_infile.getline(l_inbuffer, 256); //check if reading succeeded if (l_infile.eof() || l_infile.fail() || l_infile.bad()) { break; } //try to parse the first string of the line as one of the keywords: //v -> vertex coordinate //vt -> texture coordinate //vn -> vertex normal //f -> face record switch (l_inbuffer[0]) { case 'v' : //posibilities 'v' 'vt' 'vn' switch (l_inbuffer[1]) { case ' ': //vertex if (l_bParseOk = ParseVect3D(&l_inbuffer[2], l_v3)) { f_Geom.m_verts.push_back(l_v3); //update boundingbox m_BBox << l_v3; } break; case 't': if (l_inbuffer[2] == ' ') { //texture coordinates if (l_bParseOk = ParseVect3D(&l_inbuffer[3], l_v3)) { f_Geom.m_texs.push_back(l_v3); } } break; case 'n': if (l_inbuffer[2] == ' ') { //normal if (l_bParseOk = ParseVect3D(&l_inbuffer[3], l_v3)) { f_Geom.m_norms.push_back(l_v3); } } break; } break; case 'f': if (l_inbuffer[1] == ' ') { //face (triangle) if (l_bParseOk = ParseTriangle(&l_inbuffer[2], l_tri)) { f_Geom.m_triangles.push_back(l_tri); } } break; case 'm' : // 'mtllib'? break; case 'u' : // 'usemtl' ? break; } } l_infile.close(); if (!l_bParseOk) { std::cout << "Parse error in: \"" << l_inbuffer << "\"\n"; } return l_bParseOk; } bool C_3DObject::ParseVect3D(const char *f_pInBuffer, Vect3D_t &f_V3) { //format: " x y z " std::stringstream l_inbuffer(f_pInBuffer); l_inbuffer >> std::skipws >> f_V3.x >> f_V3.y >> f_V3.z; //std::cout << "Read values: " << f_V3.x << ", " << f_V3.y << ", " << f_V3.z << "\n"; return !l_inbuffer.fail(); } bool C_3DObject::ParseTriangle(const char *f_pInBuffer, Triangle_t &f_triangle) { //format v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 std::stringstream l_inbuffer(f_pInBuffer); char l_slash; l_inbuffer >> std::skipws >> f_triangle.v1 >> l_slash >> f_triangle.t1 >> l_slash >> f_triangle.n1; l_inbuffer >> std::skipws >> f_triangle.v2 >> l_slash >> f_triangle.t2 >> l_slash >> f_triangle.n2; l_inbuffer >> std::skipws >> f_triangle.v3 >> l_slash >> f_triangle.t3 >> l_slash >> f_triangle.n3; return !l_inbuffer.fail(); }