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

////////////////////////////////////////////////////////////
// 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) && (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(&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

/////////////////////////////////////////////////////////
////												/////
////												/////
////	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' && 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",&tmpx,&tmpy,&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' && 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",&tmpx,&tmpy,&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' && 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",&tmpx,&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",&v1,&t1,&n1,&v2,&t2,&n2,&v3,&t3,&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",&v1,&t1,&n1,&v2,&t2,&n2,&v3,&t3,&n3,&v4,&t4,&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;

}


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

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