Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 3 of 3

Thread: C++ opengl sfml obj loader help

  1. #1
    Junior Member Newbie
    Join Date
    Apr 2012
    Posts
    2

    C++ opengl sfml obj loader help

    Hi Guys,

    I'm building and object loader in the above language and libraries, I have a basic single file loaded in my loader and showing on the screen.

    Now part of the assignment is to make the model of a robotic arm move, pivot etc.

    In order to do this i guess i have to load every part of the arm model separately?

    If so how would i do that?
    My code is below

    If you need any more info please ask

    thanks

    Main
    Code :
    ////////////////////////////////////////////////////////////
    // Headers
    ////////////////////////////////////////////////////////////
    #include <SFML/Window.hpp>
    #include <SFML/Graphics.hpp>
    #include "model.h"  //Model header
     
     
    #define REFRESH_RATE 0.0167f  //60th of a sec
     
    int modelId; //The model id
    model obj; //The model object 
     
     
    //Initialise OpenGL stuff, load the model and return the model's id
    int init()
    {
     
    	glClearColor(0.0,0.0,0.0,1.0);
    	glMatrixMode(GL_PROJECTION);
    	glLoadIdentity();
    	gluPerspective(150.f, 800.0/600.0, 1.f, 20.f);
    	glMatrixMode(GL_MODELVIEW);
     
    	glEnable(GL_DEPTH_TEST);
     
    	modelId=obj.loadModel("testPUMA.obj");	//load the torus.obj file
     
    	glEnable(GL_LIGHTING);	//we enable lighting, to make the 3D object to 3D
    	glEnable(GL_LIGHT0);
    	float diffuse[]={1.0f,1.0f,1.0f,1.0f};	//light color is white
    	glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuse);
    	float ambient[]={0.2f,0.2f,0.2f,1.0f};	//light color is white
    	glLightfv(GL_LIGHT0,GL_AMBIENT,ambient);
     
    	return modelId;
    }
     
    //Display the model given its id and an incremental angle of rotation
    void display(int modelId, float angle)
    {
    	glLoadIdentity();
     
    	glTranslatef(0.0,0.0,-5.0);
    	//glRotatef(angle,1.0,1.0,1.0);
     
    	glCallList(modelId);	//draw the 3D mesh
    }
     
     
     
    ////////////////////////////////////////////////////////////
    /// Entry point of application
    ///
    /// \return Application exit code
    ///
    ////////////////////////////////////////////////////////////
    int main()
    {
        // Create the main window
        //sf::Window App(sf::VideoMode(600, 600, 32), "SFML OpenGL");
    	//
     
     
    	sf::WindowSettings Settings;
    	Settings.DepthBits         = 24; // Request a 24 bits depth buffer
    	Settings.StencilBits       = 8;  // Request a 8 bits stencil buffer
    	Settings.AntialiasingLevel = 2;  // Request 2 levels of antialiasing
    	sf::Window App(sf::VideoMode(800, 600, 32), "OBJ Model Viewer", sf::Style::Close, Settings);
     
    	  // Create a clock for measuring time elapsed
        sf::Clock Clock;
    	// declare a struct to get the system time 
    	SYSTEMTIME st;
     
    	float angle=0.0;
     
    	modelId=init(); 
     
            // Start game loop
        while (App.IsOpened())
        {
            // Process events
            sf::Event Event;
            while (App.GetEvent(Event))
            {
                // Close window : exit
                if (Event.Type == sf::Event::Closed)
                    App.Close();
     
                // Escape key : exit
                if ((Event.Type == sf::Event::KeyPressed) &amp;&amp; (Event.Key.Code == sf::Key::Escape))
                    App.Close();
     
                // Resize event : adjust viewport
                if (Event.Type == sf::Event::Resized)
                    glViewport(0, 0, Event.Size.Width, Event.Size.Height);
     
    			if ((Event.Type == sf::Event::KeyPressed) ){
    				switch (Event.Key.Code){
    				case sf::Key::T: waist_rotate += MOVE_INCREMENT; break;
    				case sf::Key::G: waist_rotate -= MOVE_INCREMENT; break;
    // other key bindings
    }
    }
     
            }
     
            // Set the active window before using OpenGL commands
            // It's useless here because active window is always the same,
            // but don't forget it if you use multiple windows or controls
            App.SetActive();
     
    		float elapsedTime=Clock.GetElapsedTime();
    		if(elapsedTime>REFRESH_RATE){
    			// get current system time
    			GetSystemTime(&amp;st);
     
    			Clock.Reset();
     
    			angle+=0.5; //Incremental angle
     
    			if (angle>360)
    				angle-=360;
    			display(modelId,angle);		
    		}
     
            // Finally, display rendered frame on screen
            App.Display();
        }
     
     
        return EXIT_SUCCESS;
    }

    model.cpp
    Code :
    /////////////////////////////////////////////////////////
    ////												/////
    ////												/////
    ////	Basic model class implementation			/////
    ////												/////
    ////	Eric Tatham									/////
    ////												/////
    ////												/////
    /////////////////////////////////////////////////////////
     
    #include "model.h"
     
    //Constructor
    model::model()
    {
    	//Initialise id to 0
    	modelId=0;
    }
     
     
    //Load a model using given filename and return the model id
    int model::loadModel(const char* filename)
    {
    	ifstream in(filename);  //Open the model file
    	if(!in.is_open())	//if not opened, exit with -1
    	{
    		cout << "File not opened" << std::endl;
    		return -1;
    	}
     
    	//Set up an array to act as a buffer for text read from the input file
    	char buf[256];
     
    	//Read input file text to end of file and push onto lines list
    	while(!in.eof())
    	{
    		in.getline(buf,256);
    		lines.push_back(new std::string(buf));
    	}
     
    	in.close();
     
    	//Now the file contents are in memory, parse the file's lines
    	ParseOBJFile();
     
    	//Check if the OBJ file has a linked material file
    	if (hasMaterialFile())
    	{
    		//Open the file
    		string name=GetMatFileName();
     
    		ifstream in(name);  //Open the model file
     
    		if(!in.is_open())	//if not opened, exit with -1
    		{
    			std::cout << "File not opened" << std::endl;
    			return -1;
    		}
     
    		//Set up an array to act as a buffer for text read from the input file
    		char buf2[256];
     
    		//Read input file text to end of file and push onto matLines list
    		while(!in.eof())
    		{
    			in.getline(buf2,256);
    			matLines.push_back(new std::string(buf2));
    		}
     
    		in.close();
     
    		//Now we have a material file in memory, parse the lines of the file
    		ParseMTLFile();
    	}
     
    	//Now build the OpenGL List and get a model id
    	GLuint modelId=BuildOpenGL();
     
    	return modelId;
    }
     
     
     
    //Destructor
    model::~model()
    {
    		//delete everything to avoid memory leaks
    	for(int i=0;i<(int)lines.size();i++)
    		delete lines[i];
    	for(int i=0;i<(int)matLines.size();i++)
    		delete matLines[i];
    	lines.clear();
    	matLines.clear();
    	faces.clear();
    }
     
     
    //Parse the OBJ file once it has been opened and loaded into memory
    void model::ParseOBJFile()
    {
    	//There may be a material file name: mtllib 
    	//and each face may have a usemtl proceeding it
     
    	char matFileName[32];
    	char usemtlName[32];
    	hasMaterialFile(false);
    	bool usemtl=false; //No valid usemtl name
     
    	size_t found_mtllib, found_usemtl;
     
     
    	//Go through each of the input text lines in the lines list, and decide what kind of element it is
    	for(int i=0;i<(int)lines.size();i++)
    	{
     
    		found_mtllib= lines[i]->find("mtllib");
    		found_usemtl= lines[i]->find("usemtl");
     
     
    		//Check for material file and, if found, get its file name
    		if (found_mtllib!=string::npos)
    		{
    			sscanf_s(lines[i]->c_str(),"mtllib %s",matFileName,32);
    			hasMaterialFile(true);
    			SetMatFileName( string(matFileName));
    		}
     
    		//Check for use material
    		else if (found_usemtl!=string::npos)	
    		{
    			sscanf_s(lines[i]->c_str(),"usemtl %s",usemtlName,32);
    			usemtl=true;
    		}
     
    		//if first character is 'v' and second is ' ' then we have a vertex 
    		//so get it and add it to the vertManager list
    		else if(lines[i]->c_str()[0]=='v' &amp;&amp; lines[i]->c_str()[1]==' ')	
    		{
    			float tmpx,tmpy,tmpz;
    			//read in the 3 float coordinates to tmpx,tmpy,tmpz
    			sscanf_s(lines[i]->c_str(),"v %f %f %f",&amp;tmpx,&amp;tmpy,&amp;tmpz);	
    			//and then make a point3D and push onto the model's vertices list
    			Point3D pt=Point3D(tmpx,tmpy,tmpz);
    			vertManager.AddVertex(pt);
     
    		//else if first character is 'v' and second is 'n' then we have a normal 
    		//so get it and add it to the normManager list
    		}else if(lines[i]->c_str()[0]=='v' &amp;&amp; lines[i]->c_str()[1]=='n')	
    		{
    			float tmpx,tmpy,tmpz;	
    			//read in the 3 float coordinates to tmpx,tmpy,tmpz
    			sscanf_s(lines[i]->c_str(),"vn %f %f %f",&amp;tmpx,&amp;tmpy,&amp;tmpz);
    			//and then make a point3D to represent the normal vector and push onto the model's normals list
    			Normal norm=Normal(tmpx,tmpy,tmpz);
    			normManager.AddNormal(norm);
     
    		//else if first character is 'v' and second is 't' then we have a UV 
    		//so get it and add it to the uvManager list
    		}else if(lines[i]->c_str()[0]=='v' &amp;&amp; lines[i]->c_str()[1]=='t')	
    		{
    			float tmpx,tmpy;	
    			//read in the 2 float coordinates to tmpx,tmpy
    			sscanf_s(lines[i]->c_str(),"vt %f %f",&amp;tmpx,&amp;tmpy);
    			//and then make a UV and push onto the model's texCoords list
    			UV uv=UV(tmpx,tmpy);
    			uvManager.AddUV(uv);	
     
    		//else if first character is 'f' then we have a face
    		}else if(lines[i]->c_str()[0]=='f')	
    		{
    			//Create temporary variable to hold the indices from the face input line
    			int v1,t1,n1,v2,t2,n2,v3,t3,n3,v4,t4,n4;
     
    			//Count the number of spaces in the input line
    			//If there are 3 spaces then we have a triangular face
    			//else we have a quad face
    			if(count(lines[i]->begin(),lines[i]->end(),' ')==3)
    			{
    				//Read the vertex, texture UV and normal indices from the input line
    				sscanf_s(lines[i]->c_str(),"f %d/%d/%d %d/%d/%d %d/%d/%d",&amp;v1,&amp;t1,&amp;n1,&amp;v2,&amp;t2,&amp;n2,&amp;v3,&amp;t3,&amp;n3);				//Push the vertex and normal indices onto the faces list
     
    				int vert[4];
    				int norm[4];
    				int tex[4];
     
    				vert[0]=v1;
    				vert[1]=v2;
    				vert[2]=v3;
    				vert[3]=0;
     
    				norm[0]=n1;
    				norm[1]=n2;
    				norm[2]=n3;
    				norm[3]=0;
     
    				tex[0]=t1;
    				tex[1]=t2;
    				tex[2]=t3;
    				tex[3]=0;
     
    				Face face= Face(false,usemtl, string(usemtlName), vert, norm, tex);
    				faces.push_back(face);
     
    			}else  //Must be a quad so there are 4 sets of data to read
    			{
    				//Read the vertex, texture UV and normal indices from the input line
    				sscanf_s(lines[i]->c_str(),"f %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d",&amp;v1,&amp;t1,&amp;n1,&amp;v2,&amp;t2,&amp;n2,&amp;v3,&amp;t3,&amp;n3,&amp;v4,&amp;t4,&amp;n4);
    				//Push the vertex and normal indices onto the faces list
    				int vert[4];
    				int norm[4];
    				int tex[4];
     
    				vert[0]=v1;
    				vert[1]=v2;
    				vert[2]=v3;
    				vert[3]=v4;
     
    				norm[0]=n1;
    				norm[1]=n2;
    				norm[2]=n3;
    				norm[3]=n4;
     
    				tex[0]=t1;
    				tex[1]=t2;
    				tex[2]=t3;
    				tex[3]=t4;
     
    				Face face= Face(true,usemtl, string(usemtlName), vert, norm, tex);
    				faces.push_back(face);
     
    			}
    		}
    	}
    }
     
     
     
     
    //Parse the MTL file
    void model:: ParseMTLFile()
    {
    	size_t found_newmtl, found_Kd, found_mapKd,found_Ka,found_Ks;
     
    	//Loop through each line of the file looking for relevant strings
    	for(int i=0;i<(int)matLines.size();i++)
    	{
    		//In each of the following, the found_*** variable is set to the position of the string if found
    		found_newmtl = matLines[i]->find("newmtl");
    		//look for map_Kd BEFORE looking for Kd 
    		//to ensure that map_Kd line is not accepted as Kd because Kd characters are found within it
    		found_mapKd = matLines[i]->find("map_Kd");
    		found_Kd = matLines[i]->find("Kd");
    		found_Ks = matLines[i]->find("Ks");
    		found_Ka = matLines[i]->find("Ka");
     
    		/*
     
    		TO DO 1
     
    		Code is needed here to parse through the MTL file 
     
    		You can check whether certain string is found as follows:
     
    			if (found_newmtl!=string::npos)
     
    		This, of course, checks for the newmtl string.
     
    		string::npos has a value representing the end of line position. 
    		Thus the above check is true only if the string has been found.
     
    		If a newmtl line is found:
    		Create a new Material and add it to the materialManager
     
    		i.e.
    			Material material = Material();
    			material.SetName(string(newmtlName));
    			materialManager.AddMaterial(string(newmtlName),material);
     
    		If Kd line is found:
    		Set the materials diffuse colour via the materialManager
     
    		i.e.
    			kd.SetRed(tmpr);kd.SetGreen(tmpg);kd.SetBlue(tmpb);
    			//Set it for the current named material through the material manager
    			materialManager.SetDiffuse(newmtlName,kd);
     
    		To start with, I recommend just dealing with diffuse material colour
    		You can always come back later to add Ambient, Specular, Shininess, etc..
     
    		If map_Kd line is found:
    		Get the texture file name and set up the texture via the materialManager
     
    		i.e.
    			materialManager.SetUpTexture(newmtlName, textureFilename);
     
    		Note that SetUpTexture uses TextureManager to load the texture and provide a reference ID for it.
    		It also sets the Material textureId to the OpenGl texture ID which the TextureManager provides.
    		It can be used later to reference this texture after recovery via the materialManager GetTextureId() method
     
     
    		*/
     
    	}
     
     
    }
     
     
     
    //Build the OpenGL for the model
    GLuint model::BuildOpenGL()
    {
    	GLuint modId=glGenLists(1);	
     
    	//Create the OpenGL list
    	glNewList(modId,GL_COMPILE);	
     
    	//Set up some temporary variables
    	//float ambient[4];
    	//float diffuse[4];
    	//float specular[4];
    	//float shininess;
     
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
     
    	//for each face in the model
    	for(int i=0;i<(int)faces.size();i++)	
    	{
     
    		/*
     
     
    		TO DO 2
     
    		Code is needed here to check whether the current face has a material defined
     
    		If so, then:
     
    		get its name and use the materialManager to check if it has a texture defined
     
    		If it does have a texture then get the texture ID through the materialManager, bind and enable the texture
    		else get the material data through the materialManager and set up glMaterialfv(****) calls.
     
     
    		*/
     
    		//if the face is a quad then there are 4 vertices and 4 normals to deal with
    		if(faces[i].IsQuad())	
    		{
    			glBegin(GL_QUADS);
     
     
    				//Recover the vertex, normal and UV from the respective Managers 
    				//For Vertex 1
    				int vertId = faces[i].GetVertexIndex1();
    				int normId = faces[i].GetNormalIndex1();
    				int texId = faces[i].GetUVIndex1();
     
    				Point3D vert = vertManager.GetVertex(vertId);
    				Normal norm = normManager.GetNormal(normId);
    				UV tex = uvManager.GetUV(texId);
     
    				glNormal3f(norm.GetX(),norm.GetY(),norm.GetZ());
    				glTexCoord2f(tex.GetU(),tex.GetV());
    				glVertex3f(vert.GetX(),vert.GetY(),vert.GetZ());
     
     
    				//For Vertex 2
    				vertId = faces[i].GetVertexIndex2();
    				normId = faces[i].GetNormalIndex2();
    				texId = faces[i].GetUVIndex2();
     
    				vert = vertManager.GetVertex(vertId);
    				norm = normManager.GetNormal(normId);
    				tex = uvManager.GetUV(texId);
     
    				glNormal3f(norm.GetX(),norm.GetY(),norm.GetZ());
    				glTexCoord2f(tex.GetU(),tex.GetV());
    				glVertex3f(vert.GetX(),vert.GetY(),vert.GetZ());
     
     
    				//For Vertex 3
    				vertId = faces[i].GetVertexIndex3();
    				normId = faces[i].GetNormalIndex3();
    				texId = faces[i].GetUVIndex3();
     
    				vert = vertManager.GetVertex(vertId);
    				norm = normManager.GetNormal(normId);
    				tex = uvManager.GetUV(texId);
     
    				glNormal3f(norm.GetX(),norm.GetY(),norm.GetZ());
    				glTexCoord2f(tex.GetU(),tex.GetV());
    				glVertex3f(vert.GetX(),vert.GetY(),vert.GetZ());
     
     
    				//For Vertex 4
    				vertId = faces[i].GetVertexIndex4();
    				normId = faces[i].GetNormalIndex4();
    				texId = faces[i].GetUVIndex4();
     
    				vert = vertManager.GetVertex(vertId);
    				norm = normManager.GetNormal(normId);
    				tex = uvManager.GetUV(texId);
     
    				glNormal3f(norm.GetX(),norm.GetY(),norm.GetZ());
    				glTexCoord2f(tex.GetU(),tex.GetV());
    				glVertex3f(vert.GetX(),vert.GetY(),vert.GetZ());
     
     
    			glEnd();
    		}
    		//else there must be 3 vertices and 3 normals to deal with
    		else
    		{
    			glBegin(GL_TRIANGLES);
    				//Recover the vertex, normal and UV from the respective Managers 
    				//For Vertex 1
    				int vertId = faces[i].GetVertexIndex1();
    				int normId = faces[i].GetNormalIndex1();
    				int texId = faces[i].GetUVIndex1();
     
    				Point3D vert = vertManager.GetVertex(vertId);
    				Normal norm = normManager.GetNormal(normId);
    				UV tex = uvManager.GetUV(texId);
     
    				glNormal3f(norm.GetX(),norm.GetY(),norm.GetZ());
    				glTexCoord2f(tex.GetU(),tex.GetV());
    				glVertex3f(vert.GetX(),vert.GetY(),vert.GetZ());
     
     
    				//For Vertex 2
    				vertId = faces[i].GetVertexIndex2();
    				normId = faces[i].GetNormalIndex2();
    				texId = faces[i].GetUVIndex2();
     
    				vert = vertManager.GetVertex(vertId);
    				norm = normManager.GetNormal(normId);
    				tex = uvManager.GetUV(texId);
     
    				glNormal3f(norm.GetX(),norm.GetY(),norm.GetZ());
    				glTexCoord2f(tex.GetU(),tex.GetV());
    				glVertex3f(vert.GetX(),vert.GetY(),vert.GetZ());
     
     
    				//For Vertex 3
    				vertId = faces[i].GetVertexIndex3();
    				normId = faces[i].GetNormalIndex3();
    				texId = faces[i].GetUVIndex3();
     
    				vert = vertManager.GetVertex(vertId);
    				norm = normManager.GetNormal(normId);
    				tex = uvManager.GetUV(texId);
     
    				glNormal3f(norm.GetX(),norm.GetY(),norm.GetZ());
    				glTexCoord2f(tex.GetU(),tex.GetV());
    				glVertex3f(vert.GetX(),vert.GetY(),vert.GetZ());
     
    			glEnd();
    		}
    	}
    	glEndList();
     
    	return modId;
     
    }

  2. #2
    Advanced Member Frequent Contributor
    Join Date
    Jan 2012
    Location
    Australia
    Posts
    728

    Re: C++ opengl sfml obj loader help

    you could either split the model into several separate objs or colour code different parts of the models and create a separate mesh per material in the obj

  3. #3
    Junior Member Newbie
    Join Date
    Apr 2012
    Posts
    2

    Re: C++ opengl sfml obj loader help

    Thanks,

    Ok so if i split the model into several separate objs in maya and export them separately, how would i get the loader to load them individually?

    Thankyou very much

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •