Code:
/*
* Mesh class
*/
#include <stdio.h>
#include <vector>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "SDL.h"
#include "mesh.h"
#include "types.h"
using namespace std;
#define BUFFER_OFFSET(i) (((char *)NULL + (i)))
// Determines the type of face being loaded from an OBJ file
int GetFaceType(const char *buffer) {
int count = 0;
for (int index = 0; index < strlen(buffer); index++) {
if (buffer[index] == '/') {
if (buffer[index + 1] == '/')
return VERTEX_NORMAL;
else
count++;
}
}
switch (count) {
case 3:
return VERTEX_TEXTURE;
case 6:
return VERTEX_NORMAL_TEXTURE;
}
return VERTEX_ONLY;
};
Mesh::Mesh() {
// Enable vertex arrays
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
};
Mesh::~Mesh() {
// Delete the VBOs, if needed
if (bufferID) glDeleteBuffers(1, &bufferID);
};
int Mesh::LoadOBJ(const char *filename) {
// Create vector buffers to hold vertex, normal, and texture data
vector <Float3> vertexBuffer;
vector <Float3> normalBuffer;
vector <Float3> textureBuffer;
vector <Face> faceBuffer;
// Try opening the desired file
FILE *OBJFile = fopen(filename, "r");
if (!OBJFile) {
fprintf(stderr, "[MESH] Unable to load mesh named %s.\n", filename);
return 1;
}
// Read in the object file
char buffer[255];
int facetype;
Float3 tempFloat;
Face tempFace;
while (fgets(buffer, 255, OBJFile) != NULL) {
switch (buffer[0]) {
case 'v':
switch (buffer[1]) {
case 'n': // Vertex normal
sscanf(buffer, "vn %f %f %f", &tempFloat.X, &tempFloat.Y, &tempFloat.Z);
normalBuffer.push_back(tempFloat);
break;
case 't': // Vertex texture
sscanf(buffer, "vt %f %f %f", &tempFloat.X, &tempFloat.Y, &tempFloat.Z);
textureBuffer.push_back(tempFloat);
break;
default: // Vertex
sscanf(buffer, "v %f %f %f", &tempFloat.X, &tempFloat.Y, &tempFloat.Z);
vertexBuffer.push_back(tempFloat);
break;
}
break;
case 'f': // Face
facetype = GetFaceType(buffer);
switch (facetype) {
case VERTEX_ONLY:
sscanf(buffer, "f %d %d %d", &tempFace.Vertex.X, &tempFace.Vertex.Y, &tempFace.Vertex.Z);
tempFace.FaceType = facetype;
faceBuffer.push_back(tempFace);
break;
case VERTEX_NORMAL:
sscanf(buffer, "f %d//%d %d//%d %d//%d", &tempFace.Vertex.X, &tempFace.Normal.X,
&tempFace.Vertex.Y, &tempFace.Normal.Y,
&tempFace.Vertex.Z, &tempFace.Normal.Z);
tempFace.FaceType = facetype;
faceBuffer.push_back(tempFace);
break;
case VERTEX_TEXTURE:
sscanf(buffer, "f %d/%d %d/%d %d/%d", &tempFace.Vertex.X, &tempFace.Texture.X,
&tempFace.Vertex.Y, &tempFace.Texture.Y,
&tempFace.Vertex.Z, &tempFace.Texture.Z);
tempFace.FaceType = facetype;
faceBuffer.push_back(tempFace);
break;
case VERTEX_NORMAL_TEXTURE:
sscanf(buffer, "f %d/%d/%d %d/%d/%d %d/%d/%d", &tempFace.Vertex.X, &tempFace.Texture.X, &tempFace.Normal.X,
&tempFace.Vertex.Y, &tempFace.Texture.Y, &tempFace.Normal.Y,
&tempFace.Vertex.Z, &tempFace.Texture.Z, &tempFace.Normal.Z);
tempFace.FaceType = facetype;
faceBuffer.push_back(tempFace);
break;
default:
break;
}
break;
default:
break;
}
}
// Close the file
fclose(OBJFile);
// Process the data into arrays
GLuint vertexArraySize = 0;
GLuint normalArraySize = 0;
GLuint textureArraySize = 0;
GLfloat vertexArray[faceBuffer.size() * 3];
GLfloat normalArray[faceBuffer.size() * 3];
GLfloat textureArray[faceBuffer.size() * 3];
for (int index = 0; index < faceBuffer.size(); index++) {
vertexArray[index] = faceBuffer.at(index).Vertex.X;
vertexArray[index + 1] = faceBuffer.at(index).Vertex.Y;
vertexArray[index + 2] = faceBuffer.at(index).Vertex.Z;
vertexArraySize++;
switch (faceBuffer.at(index).FaceType) {
case VERTEX_NORMAL:
normalArray[index] = faceBuffer.at(index).Normal.X;
normalArray[index + 1] = faceBuffer.at(index).Normal.Y;
normalArray[index + 2] = faceBuffer.at(index).Normal.Z;
normalArraySize++;
break;
case VERTEX_TEXTURE:
textureArray[index] = faceBuffer.at(index).Texture.X;
textureArray[index + 1] = faceBuffer.at(index).Texture.Y;
textureArray[index + 2] = faceBuffer.at(index).Texture.Z;
textureArraySize++;
break;
case VERTEX_NORMAL_TEXTURE:
normalArray[index] = faceBuffer.at(index).Normal.X;
normalArray[index + 1] = faceBuffer.at(index).Normal.Y;
normalArray[index + 2] = faceBuffer.at(index).Normal.Z;
textureArray[index] = faceBuffer.at(index).Texture.X;
textureArray[index + 1] = faceBuffer.at(index).Texture.Y;
textureArray[index + 2] = faceBuffer.at(index).Texture.Z;
normalArraySize++;
textureArraySize++;
break;
}
}
bufferSize = faceBuffer.size();
normalOffset = vertexArraySize;
textureOffset = vertexArraySize + normalArraySize;
// Generate and feed the data into the VBO
glGenBuffers(1, &bufferID);
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
glBufferData(GL_ARRAY_BUFFER, bufferSize * sizeof(GLfloat) * 3, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexArraySize * sizeof(GLfloat), vertexArray);
glBufferSubData(GL_ARRAY_BUFFER, normalOffset, normalArraySize * sizeof(GLfloat), normalArray);
glBufferSubData(GL_ARRAY_BUFFER, textureOffset, textureArraySize * sizeof(GLfloat), textureArray);
};
void Mesh::Render() {
// Render the contents of the VBO
glBindBufferARB(GL_ARRAY_BUFFER, bufferID);
glVertexPointer(3, GL_FLOAT, 0, 0);
glNormalPointer(GL_FLOAT, normalOffset, 0);
glTexCoordPointer(3, GL_FLOAT, textureOffset, 0);
glDrawArrays(GL_TRIANGLES, 0, bufferSize);
};