Here is my code for the static Mesh:
//StaticMesh.h - this class uses assimp to load models and is used to represent all the data in a mesh
//through assimp's supported classes it can store many kinds of file type
//last updata 24/07/2012
#pragma once
#include "Includes.h"
#include "ObjectData.h"
struct aiScene;
struct aiNode;
struct aiMatrix4x4;
namespace OpenGL_3_3Engine
{
class StaticMesh
{
public:
StaticMesh(){};
~StaticMesh();
bool Init(const char* filename);
void Render();
glm::mat4x4 m_transform,m_scale;
std::vector<ObjectData*> m_meshData;
float m_scaleFactor;
glm::vec3 m_boundingBoxMin,m_boundingBoxMax;
private:
//support functions for use by Init();
void GetBoundingBox(glm::vec3& min,glm::vec3& max,const aiScene* scene);
void GetBoundingBoxForNode(const aiNode* node,glm::vec3& min,glm::vec3& max,aiMatrix4x4& trafo,
const aiScene* scene);
};
};
//StaticMesh.cpp - implementation of loading meshes, initialising vertex buffer data etc
// http://www.lighthouse3d.com/cg-topics/code-samples/importing-3d-models-with-assimp/ was a great reference in building
//this
//last update 24/07/2012
#include "StaticMesh.h"
#include <Assimp/aiScene.h>
#include <Assimp/aiPostProcess.h>
#include <Assimp/aiMesh.h>
#include <Assimp/assimp.hpp>
#include <Assimp/assimp.h>
namespace OpenGL_3_3Engine
{
StaticMesh::~StaticMesh()
{
for(std::vector<ObjectData*>::iterator meshData = m_meshData.begin(); meshData != m_meshData.end(); meshData++)
{
delete *meshData;
}
m_meshData.clear();
}
bool StaticMesh::Init(const char* filename)
{
//check if file exists
std::ifstream fin(filename);
if(!fin.fail())
{
fin.close();
}
else
{
std::cout << "Couldn't open file "<< filename <<" it doesn't exist!" << std::endl;
return false;
}
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(filename,aiProcessPreset_TargetRealtime_Quality);
if(!scene)
{
std::cout <<"couldn't load scene! Reason: "<< importer.GetErrorString() <<std::endl;
return false;
}
GetBoundingBox(m_boundingBoxMin,m_boundingBoxMax,scene);
float biggestDifferenceAxis = 0.0f;
biggestDifferenceAxis = m_boundingBoxMax.x - m_boundingBoxMin.x;
if(m_boundingBoxMax.y - m_boundingBoxMin.y > biggestDifferenceAxis )
biggestDifferenceAxis = m_boundingBoxMax.y - m_boundingBoxMin.y;
if(m_boundingBoxMax.z - m_boundingBoxMin.z > biggestDifferenceAxis )
biggestDifferenceAxis = m_boundingBoxMax.z - m_boundingBoxMin.z;
m_scaleFactor = 1.0f/biggestDifferenceAxis;
m_scale = glm::scale(m_scaleFactor,m_scaleFactor,m_scaleFactor);
//now init vaos and buffers...
//find out if this mesh has positions, normals, textures
for(unsigned int mesh = 0; mesh < scene->mNumMeshes; mesh++)
{
int numAttribs = 0;
const aiMesh* thisMesh = scene->mMeshes[mesh];
if(thisMesh->HasPositions())
numAttribs++;
/*if(thisMesh->HasNormals())
numAttribs++;*/
/*if(thisMesh->HasTextureCoords(0))
numAttribs++;*/
unsigned int numFaces = thisMesh->mNumFaces;
//create a new objectdata to store the mesh data on the gfx card
ObjectData* newObject = new ObjectData(numAttribs,numFaces);
//copy the mesh's face data
unsigned int *indices = new unsigned int[numFaces * 3];
for(unsigned int face = 0, vertexIndex = 0; face < numFaces; face++, vertexIndex += 3)
{
const struct aiFace* meshFace = &thisMesh->mFaces[face];
memcpy(&indices[vertexIndex],meshFace->mIndices,sizeof(unsigned int) * 3);
}
//for debugging
/*std::cout <<"Mesh number "<<mesh<<std::endl;
std::cout <<"number of vertices: "<<thisMesh->mNumVertices<<std::endl;
std::cout <<"number of faces: "<<thisMesh->mNumFaces<<std::endl;*/
//generate vertex array for this mesh using objectData
newObject->Init(indices,thisMesh->mNumVertices,thisMesh->mVertices,3);
//push this info into a vector of objectdatas for rendering later
m_meshData.push_back(newObject);
delete [] indices;
}
return true;
}
void StaticMesh::GetBoundingBox(glm::vec3& min,glm::vec3& max,const aiScene* scene)
{
aiMatrix4x4 trafo;
aiIdentityMatrix4(&trafo);
min.x = min.y = min.z = 1e10f;
max.x = max.y = max.z = -1e10f;
GetBoundingBoxForNode(scene->mRootNode,min,max,trafo,scene);
}
void StaticMesh::GetBoundingBoxForNode(const aiNode* node,glm::vec3& min,glm::vec3& max,aiMatrix4x4& trafo,
const aiScene* scene)
{
aiMatrix4x4 prev;
prev = trafo;
aiMultiplyMatrix4(&trafo,&node->mTransformation);
for (unsigned int n = 0; n < node->mNumMeshes; ++n)
{
const struct aiMesh* mesh = scene->mMeshes[node->mMeshes[n]];
for (unsigned int t = 0; t < mesh->mNumVertices; ++t)
{
struct aiVector3D tmp = mesh->mVertices[t];
aiTransformVecByMatrix4(&tmp,&trafo);
min.x = glm::min(min.x,tmp.x);
min.y = glm::min(min.y,tmp.y);
min.z = glm::min(min.z,tmp.z);
max.x = glm::max(max.x,tmp.x);
max.y = glm::max(max.y,tmp.y);
max.z = glm::max(max.z,tmp.z);
}
}
for (unsigned int n = 0; n < node->mNumChildren; n++)
{
GetBoundingBoxForNode(node->mChildren[n],min,max,trafo,scene);
}
trafo = prev;
}
void StaticMesh::Render()
{
for(std::vector<ObjectData*>::iterator mesh = m_meshData.begin(); mesh != m_meshData.end(); mesh++)
{
glBindVertexArray((*mesh)->GetVAO());
glDrawElements(GL_TRIANGLES,(*mesh)->GetNumFaces(),GL_UNSIGNED_INT,0);
}
}
};
and Here is my code for my 'objectData' class. I use this class a lot in other projects for simple shapes, planes etc...
//ObjectInfo.h
//last updated 24/07/2012
#pragma once
#include "Includes.h"
namespace OpenGL_3_3Engine
{
class ObjectData
{
public:
//ObjectData constructor - takes the number of VBO objects needed, eg 3 for vertices, normals
//and texture co ordintates, and a number of triangle faces to render
ObjectData(int numVBObjects,int numFaces) : m_numVbos(numVBObjects), m_numFaces(numFaces){};
~ObjectData();
//bool Init(int numVertices,...) takes a number of vertices for the objectdata to hold
//and a variable number of arguments that should be passed in the format data, components
//where data is the pointer to the data and components represents the number of elems in each
//vertex, e.g 3 for a normal, 4 for a normalised vertex, x for number of bones etc
//so a call like Init(indices,30,vertices,3) creates an index buffer and uses the data in vertices
//and knows there are 30 vertices and 3 components in each vertex
bool Init(const unsigned int* indices,int numVertices,...);
GLuint GetVAO()const {return m_vao;}
GLuint GetNumFaces()const {return m_numFaces;}
private:
bool BindData(GLuint buffer,int numComponents,int numVertices,float* data);
bool BindVAO();
GLuint* m_vbos;
GLint* m_numComponents;
GLuint m_vao;
GLuint m_indexBuff;
GLuint m_numVbos;
GLuint m_numFaces;
};
};
//ObjectData.cpp
//last updated 24/07/2012
#include "ObjectData.h"
namespace OpenGL_3_3Engine
{
ObjectData::~ObjectData()
{
glDeleteBuffers(m_numVbos,m_vbos);
glDeleteVertexArrays(1,&m_vao);
delete [] m_vbos;
delete [] m_numComponents;
}
bool ObjectData::Init(const unsigned int* indices,int numVertices,...)
{
m_vbos = new GLuint[m_numVbos];
m_numComponents = new GLint[m_numVbos];
//due to variable num of args, need to use va_list and va_arg to access the data
va_list attribList;
va_start(attribList,numVertices);
//generate an index buffer
glGenBuffers(1,&m_indexBuff);
//get info for num of faces and the index data
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_indexBuff);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * m_numFaces * 3, indices, GL_STATIC_DRAW);
//generate info for the buffers
glGenBuffers(m_numVbos,m_vbos);
for(int buffer = 0; buffer < m_numVbos; buffer++)
{
float* data = va_arg(attribList,float*);
int numComponents = va_arg(attribList,int);
m_numComponents[buffer] = numComponents;
BindData(m_vbos[buffer],numComponents,numVertices,data);
}
BindVAO();
return true;
}
bool ObjectData::BindData(GLuint buffer,int numComponents,int numVertices, float* data)
{
glBindBuffer(GL_ARRAY_BUFFER,buffer);
glBufferData(GL_ARRAY_BUFFER,numVertices * sizeof(float) * numComponents,data,GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,0);
return true;
}
bool ObjectData::BindVAO()
{
glGenVertexArrays(1,&m_vao);
glBindVertexArray(m_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_indexBuff);
for(int buffer = 0; buffer < m_numVbos; buffer++)
{
glEnableVertexAttribArray(buffer);
glBindBuffer(GL_ARRAY_BUFFER,m_vbos[buffer]);
glVertexAttribPointer(buffer,m_numComponents[buffer],GL_FLOAT,GL_FALSE,0,(GLubyte*)NULL);
}
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
return true;
}
};
At the moment some lines are commented out as I merely want the vertex data to render a flat shaded 'solid' mesh first before trying any lighting or textures.
Here is how the model renders currently, and you can dload the model HERE for free! http://www.turbosquid.com/3d-models/fantasy-creature-3d-model/129639:






