I've written a basic .obj loader. It works with a cube and some other basic stuff. Once I give it a complex model it fails.
Here is some basic code:
Functions.h
#pragma once
#include <string>
struct face {
bool triangle;
int faceNumber;
int faces[4];
face(int faceNumber2,int f1,int f2, int f3, int f4) {
triangle = false;
faceNumber = faceNumber2;
faces[0] = f1;
faces[1] = f2;
faces[2] = f3;
faces[3] = f4;
}
face(int faceNumber2,int f1,int f2, int f3) {
triangle = true;
faceNumber = faceNumber2;
faces[0] = f1;
faces[1] = f2;
faces[2] = f3;
}
};
struct position {
float x, y, z;
position(float X,float Y, float Z) {
x = X;
y = Y;
z = Z;
}
};
class Functions
{
public:
Functions(void);
~Functions(void);
int loadObject(std::string fileName);
void drawCube(float size);
unsigned int loadTexture(const char* fileName);
};
Functions.cpp
int Functions::loadObject(string fileName) {
ifstream file(fileName);
vector<string*> line;
vector<position*> normals;
vector<face*> faces;
vector<position*> vertices;
if (file.is_open()) {
char buffer[256];
while (!file.eof()) {
file.getline(buffer,256);
line.push_back(new string(buffer));
}
for (int i = 0; i<line.size(); i++) {
if ((*line[i])[0] == 'v' && (*line[i])[1] == ' ') { //Vertice
float x,y,z;
sscanf_s((*line[i]).c_str(),"v %f %f %f",&x,&y,&z);
vertices.push_back(new position(x,y,z));
}else if ((*line[i])[0] == 'v' && (*line[i])[1] == 'n') { //Normals
float x,y,z;
sscanf_s((*line[i]).c_str(),"vn %f %f %f",&x,&y,&z);
normals.push_back(new position(x,y,z));
} else if ((*line[i])[0] == 'f') {
if (count((*line[i]).begin(),(*line[i]).end(),' ') == 4) {
float a,b,c,d,e;
sscanf_s((*line[i]).c_str(),"f %f//%f %f//%f %f//%f %f//%f",&a,&e,&b,&e,&c,&e,&d,&e);
faces.push_back(new face(e,a,b,c,d));
} else {
float a,b,c,e;
sscanf_s((*line[i]).c_str(),"f %f//%f %f//%f %f//%f",&a,&e,&b,&e,&c,&e);
faces.push_back(new face(e,a,b,c));
}
}
}
file.close();
} else {
file.close();
throw exception("Fail to load file");
return -1;
}
int num;
num = glGenLists(1);
glNewList(num,GL_COMPILE);
for (int i = 0; i<faces.size(); i++) {
face tempFace = (*faces[i]);
if (tempFace.triangle) {
glBegin(GL_TRIANGLES);
glNormal3f((*normals[tempFace.faceNumber-1]).x, (*normals[tempFace.faceNumber-1]).y, (*normals[tempFace.faceNumber-1]).z);
glVertex3f((*vertices[tempFace.faces[0]-1]).x, (*vertices[tempFace.faces[0]-1]).y, (*vertices[tempFace.faces[0]-1]).z);
**//Errors below.**
glVertex3f((*vertices[tempFace.faces[1]-1]).x, (*vertices[tempFace.faces[1]-1]).y, (*vertices[tempFace.faces[1]-1]).z);
glVertex3f((*vertices[tempFace.faces[2]-1]).x, (*vertices[tempFace.faces[2]-1]).y, (*vertices[tempFace.faces[2]-1]).z);
glEnd();
} else {
//glNormal3f((*normals[tempFace.faceNumber-1]).x,(*normals[tempFace.faceNumber-1]).y,(*normals[tempFace.faceNumber-1]).z)
glBegin(GL_QUADS);
glNormal3f((*normals[tempFace.faceNumber-1]).x, (*normals[tempFace.faceNumber-1]).y, (*normals[tempFace.faceNumber-1]).z);
glVertex3f((*vertices[tempFace.faces[0]-1]).x, (*vertices[tempFace.faces[0]-1]).y, (*vertices[tempFace.faces[0]-1]).z);
glVertex3f((*vertices[tempFace.faces[1]-1]).x, (*vertices[tempFace.faces[1]-1]).y, (*vertices[tempFace.faces[1]-1]).z);
glVertex3f((*vertices[tempFace.faces[2]-1]).x, (*vertices[tempFace.faces[2]-1]).y, (*vertices[tempFace.faces[2]-1]).z);
glVertex3f((*vertices[tempFace.faces[3]-1]).x, (*vertices[tempFace.faces[3]-1]).y, (*vertices[tempFace.faces[3]-1]).z);
glEnd();
}
}
glEndList();
for (int i = 0; i<line.size(); i++) {
delete line[i];
}
for (int i = 0; i<normals.size(); i++) {
delete normals[i];
}
for (int i = 0; i<vertices.size(); i++) {
delete vertices[i];
}
for (int i = 0; i<faces.size(); i++) {
delete faces[i];
}
return 1;
}
I've been trying this for like two days. Like I said it works with a few things just not complex models.
There are several problems with the code, each technically calling for a separate answer. But oh well, here it goes. If you want to use C++, then do it right. First of all we want our objects RAII capable. Which means we need a copy constructor and an assignment operator.
Now how do we draw this? Well, we use vertex arrays for this. In the old and dusted fixed function pipeline, they're accessed through the client state and gl…Pointer functions.