bluecore/engine/MeshManager.cpp
2008-01-24 22:16:53 +00:00

495 lines
14 KiB
C++

#include "MeshManager.h"
#include "Utilities/format.h"
#include "Utilities/Log.h"
#include "physfs.h"
#include "trimeshloader.h"
#include <iostream>
#include <vector>
using namespace std;
namespace BlueCore
{
Mesh::Mesh(RenderDevice* device) :
_Device(device)
{
}
Mesh::~Mesh()
{
clog << ">>> Mesh destructed ..."<< endline;
}
void Mesh::render()
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer( 3, GL_FLOAT, sizeof(Vertex), &VertexBuffer[0].point.x);
glTexCoordPointer( 2, GL_FLOAT, sizeof(Vertex), &VertexBuffer[0].u);
glNormalPointer(GL_FLOAT, sizeof(Vertex), &VertexBuffer[0].normal.x);
glDrawElements(GL_TRIANGLES, IndexBuffer.count() * 3, GL_UNSIGNED_SHORT,
IndexBuffer.data() );
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
}
#if 0
//--------------------------------------------------------------------------
void Mesh::createVBO()
{
if ( GLEW_ARB_vertex_buffer_object && !vbo )
{
glGenBuffersARB ( 1, &vbo );
glBindBufferARB ( GL_ARRAY_BUFFER_ARB, vbo );
glBufferDataARB (
GL_ARRAY_BUFFER_ARB,
size(),
data(),
GL_STATIC_DRAW_ARB );
}
}
//--------------------------------------------------------------------------
void Mesh::releaseVBO()
{
if ( GLEW_ARB_vertex_buffer_object && vbo )
{
glDeleteBuffersARB ( 1, &vbo );
vbo = 0;
}
}
//--------------------------------------------------------------------------
void Mesh::bind()
{
if ( GLEW_ARB_vertex_buffer_object && vbo )
{
glBindBufferARB ( GL_ARRAY_BUFFER_ARB, vbo );
// hardcoded offset and stride
glVertexPointer ( 3, GL_FLOAT, sizeof ( Vertex ), 0 );
glTexCoordPointer ( 2, GL_FLOAT, sizeof ( Vertex ), ( const GLvoid* ) ( sizeof ( float ) * 3 ) );
glNormalPointer ( GL_FLOAT, sizeof ( Vertex ), ( const GLvoid* ) ( sizeof ( float ) * 5 ) );
}
else
{
// hardcoded offset and stride
glVertexPointer ( 3, GL_FLOAT, sizeof ( Vertex ), data() );
glTexCoordPointer ( 2, GL_FLOAT, sizeof ( Vertex ), data() + sizeof ( float ) * 3 );
glNormalPointer ( GL_FLOAT, sizeof ( Vertex ), data() + sizeof ( float ) * 5 );
}
}
#endif
MeshManager::MeshManager(RenderDevice* device) :
_Device(device)
{
BlueCore::clog << ">>> MeshManager constructed..." << endlog;
}
MeshManager::~MeshManager()
{
clog << ">>> MeshManager destructed ..." << endlog;
}
bool loadTrimesh(const char* filename, Mesh *mesh)
{
PHYSFS_file* file = PHYSFS_openRead(filename);
if (file != 0)
{
char buffer[1024];
unsigned int size = 0;
if (tlObjCheckFileExtension(filename) == 0)
{
tlObjState *state = tlObjCreateState();
while (PHYSFS_eof(file) == 0)
{
size = (unsigned int) PHYSFS_read(file, buffer, 1,
sizeof(buffer));
tlObjParse(state, buffer, size, size < sizeof(buffer) ? 1 : 0);
}
mesh->VertexBuffer.create(tlObjVertexCount(state));
for (unsigned int i = 0; i < mesh->VertexBuffer.count(); i++)
tlObjGetVertex(state, i, &mesh->VertexBuffer[i].point.x,
&mesh->VertexBuffer[i].point.y,
&mesh->VertexBuffer[i].point.z,
&mesh->VertexBuffer[i].u, &mesh->VertexBuffer[i].v,
&mesh->VertexBuffer[i].normal.x,
&mesh->VertexBuffer[i].normal.y,
&mesh->VertexBuffer[i].normal.z);
mesh->IndexBuffer.create(tlObjFaceCount(state));
for (unsigned int i = 0; i < mesh->IndexBuffer.count(); i++)
tlObjGetFace(state, i, &mesh->IndexBuffer[i].a,
&mesh->IndexBuffer[i].b, &mesh->IndexBuffer[i].c);
mesh->SubsetBuffer.create(tlObjObjectCount(state));
for (unsigned int i = 0; i < mesh->SubsetBuffer.count(); i++)
{
mesh->SubsetBuffer[i].first = tlObjObjectFaceIndex(state, i);
mesh->SubsetBuffer[i].count = tlObjObjectFaceCount(state, i);
}
tlObjDestroyState(state);
}
else if (tl3dsCheckFileExtension(filename) == 0)
{
tl3dsState *state = tl3dsCreateState();
while (PHYSFS_eof(file) == 0)
{
size = (unsigned int) PHYSFS_read(file, buffer, 1,
sizeof(buffer));
tl3dsParse(state, buffer, size, size < sizeof(buffer) ? 1 : 0);
}
mesh->VertexBuffer.create(tl3dsVertexCount(state));
for (unsigned int i = 0; i < mesh->VertexBuffer.count(); i++)
tl3dsGetVertex(state, i, &mesh->VertexBuffer[i].point.x,
&mesh->VertexBuffer[i].point.y,
&mesh->VertexBuffer[i].point.z,
&mesh->VertexBuffer[i].u, &mesh->VertexBuffer[i].v,
&mesh->VertexBuffer[i].normal.x,
&mesh->VertexBuffer[i].normal.y,
&mesh->VertexBuffer[i].normal.z);
mesh->IndexBuffer.create(tl3dsFaceCount(state));
for (unsigned int i = 0; i < mesh->IndexBuffer.count(); i++)
tl3dsGetFace(state, i, &mesh->IndexBuffer[i].a,
&mesh->IndexBuffer[i].b, &mesh->IndexBuffer[i].c);
mesh->SubsetBuffer.create(tl3dsObjectCount(state));
for (unsigned int i = 0; i < mesh->SubsetBuffer.count(); i++)
{
mesh->SubsetBuffer[i].first = tl3dsObjectFaceIndex(state, i);
mesh->SubsetBuffer[i].count = tl3dsObjectFaceCount(state, i);
}
tl3dsDestroyState(state);
}
PHYSFS_close(file);
// create normlas, tangents, and binomials
clog << " create normlas..." << endline;
for (unsigned int i = 0; i < mesh->VertexBuffer.count(); i++)
{
mesh->VertexBuffer[i].normal.zero();
}
for (unsigned int i = 0; i < mesh->IndexBuffer.count(); i++)
{
const TriangleIndices& triangle = mesh->IndexBuffer[i];
Vector3Template<float> ab = mesh->VertexBuffer[ triangle.a ].point
- mesh->VertexBuffer[ triangle.b ].point;
Vector3Template<float> ac = mesh->VertexBuffer[ triangle.a ].point
- mesh->VertexBuffer[ triangle.c ].point;
Vector3Template<float> n = ab.cross(ac);
mesh->VertexBuffer[ triangle.a ].normal += n;
mesh->VertexBuffer[ triangle.a ].normal += n;
mesh->VertexBuffer[ triangle.a ].normal += n;
}
for (unsigned int i = 0; i < mesh->VertexBuffer.count(); i ++)
{
mesh->VertexBuffer[i].normal.normalize();
}
clog << " create tangents..." << endline;
mesh->TangentBuffer.create(mesh->VertexBuffer.count());
mesh->BitangentBuffer.create(mesh->VertexBuffer.count());
for (unsigned int i = 0; i < mesh->TangentBuffer.count(); i ++)
{
mesh->TangentBuffer[i].zero();
mesh->BitangentBuffer[i].zero();
}
for (unsigned int i = 0; i < mesh->IndexBuffer.count(); i ++)
{
const TriangleIndices& triangle = mesh->IndexBuffer[i];
const Vertex& v1 = mesh->VertexBuffer[triangle.a];
const Vertex& v2 = mesh->VertexBuffer[triangle.b];
const Vertex& v3 = mesh->VertexBuffer[triangle.c];
float x1 = v2.point.x - v1.point.x;
float x2 = v3.point.x - v1.point.x;
float y1 = v2.point.y - v1.point.y;
float y2 = v3.point.y - v1.point.y;
float z1 = v2.point.z - v1.point.z;
float z2 = v3.point.z - v1.point.z;
float s1 = v2.u - v1.u;
float s2 = v3.u - v1.u;
float t1 = v2.v - v1.v;
float t2 = v3.v - v1.v;
float r = 1.0f / (s1 * t2 - s2 * t1 );
Vector3Float sdir( (t2 * x1 - t1 * x2 ) * r, (t2 * y1 - t1 * y2 )
* r, (t2 * z1 - t1 * z2 ) * r);
Vector3Float tdir( (s1 * x2 - s2 * x1 ) * r, (s1 * y2 - s2 * y1 )
* r, (s1 * z2 - s2 * z1 ) * r);
mesh->TangentBuffer[triangle.a] += sdir;
mesh->TangentBuffer[triangle.b] += sdir;
mesh->TangentBuffer[triangle.c] += sdir;
mesh->BitangentBuffer[triangle.a] += tdir;
mesh->BitangentBuffer[triangle.b] += tdir;
mesh->BitangentBuffer[triangle.c] += tdir;
}
for (unsigned int i = 0; i < mesh->TangentBuffer.count(); i ++)
{
mesh->TangentBuffer[i].normalize();
mesh->BitangentBuffer[i].normalize();
}
return 0;
}
return 1;
}
Mesh *MeshManager::loadMesh(const string &filename)
{
// check if this mesh is already loaded
std::map<std::string, weak_ptr<Mesh> >::const_iterator result;
result = _Meshes.find(filename);
if (result != _Meshes.end() && result->second.valid())
{
return result->second.pointer();
}
Mesh *mesh = new Mesh (_Device);
// check cache
PHYSFS_sint64 mod_file = PHYSFS_getLastModTime(filename.c_str());
std::string cachename = filename + ".msc";
PHYSFS_sint64 mod_cache = PHYSFS_getLastModTime(cachename.c_str());
if ( (mod_cache > mod_file) && loadFromCache(mesh, filename) )
{
clog << ">>> Mesh '" << filename << "' loaded from cache." << endline;
_Meshes[filename] = mesh;
return mesh;
}
clog << ">>> Mesh '" << filename << "': loading from file..." << endlog;
if (loadTrimesh(filename.c_str(), mesh) != 0)
{
mesh->removeReference();
clog << "!!! Mesh not found!" << endline;
return 0;
}
#if 0
mesh->buildShadowFaceBuffer();
mesh->buildTangentBuffer();
unsigned int counter;
// calculate bounding sphere
clog << " calculate bounding sphere";
mesh->bounding_sphere.center().zero();
for ( counter = 0; counter < mesh->vertex_buffer.count(); counter++ )
{
mesh->bounding_sphere.center() += mesh->vertex_buffer[counter].point;
}
mesh->bounding_sphere.center() /= mesh->vertex_buffer.size();
mesh->bounding_sphere.radius() = 0.;
for ( counter = 0; counter < mesh->vertex_buffer.count(); counter++ )
{
Scalar distance = ( mesh->vertex_buffer[counter].point - mesh->bounding_sphere.center() ).length();
if ( distance > mesh->bounding_sphere.radius() )
mesh->bounding_sphere.radius() = distance;
}
clog << ": " << mesh->bounding_sphere.radius() << endline;
// create normlas, tangents, and binomials
clog << " create normlas, tangents, and binomials" << endline;
for ( counter = 0; counter < mesh->vertex_buffer.count(); counter += 1 )
{
mesh->vertex_buffer[counter].normal.zero();
}
for ( counter = 0; counter < mesh->index_buffer.count(); counter += 3 )
{
Index a = mesh->index_buffer[counter];
Index b = mesh->index_buffer[counter+1];
Index c = mesh->index_buffer[counter+2];
Vector3Template<float> ab = mesh->vertex_buffer[ a ].point - mesh->vertex_buffer[ b ].point;
Vector3Template<float> ac = mesh->vertex_buffer[ a ].point - mesh->vertex_buffer[ c ].point;
Vector3Template<float> n = ab.cross ( ac );
mesh->vertex_buffer[ a ].normal += n;
mesh->vertex_buffer[ b ].normal += n;
mesh->vertex_buffer[ c ].normal += n;
}
for ( counter = 0; counter < mesh->vertex_buffer.count(); counter += 1 )
{
mesh->vertex_buffer[counter].normal.normalize();
}
clog << " create vbos" << endline;
mesh->vertex_buffer.createVBO();
mesh->index_buffer.createVBO();
mesh->tangent_buffer.createVBO();
mesh->bitangent_buffer.createVBO();
#endif
_Meshes[filename] = mesh;
saveToCache(mesh, filename);
return mesh;
}
bool MeshManager::loadFromCache(Mesh *mesh, const std::string &name)
{
std::string filename = name + ".msc";
PHYSFS_file *file = PHYSFS_openRead(filename.c_str());
if (file == 0)
return false;
unsigned int size;
// read vertex_buffer
PHYSFS_read(file, &size, sizeof (size ), 1);
mesh->VertexBuffer.create(size);
PHYSFS_read(file, mesh->VertexBuffer.data(), mesh->VertexBuffer.size(), 1);
// read index buffer
PHYSFS_read(file, &size, sizeof (size ), 1);
mesh->IndexBuffer.create(size);
PHYSFS_read(file, mesh->IndexBuffer.data(), mesh->IndexBuffer.size(), 1);
// read subsets
PHYSFS_read(file, &size, sizeof (size ), 1);
mesh->SubsetBuffer.create(size);
PHYSFS_read(file, mesh->SubsetBuffer.data(), mesh->SubsetBuffer.size(), 1);
// read tangent buffer
PHYSFS_read(file, &size, sizeof (size ), 1);
mesh->TangentBuffer.create(size);
PHYSFS_read(file, mesh->TangentBuffer.data(), mesh->TangentBuffer.size(), 1);
// read bitangent buffer
PHYSFS_read(file, &size, sizeof (size ), 1);
mesh->BitangentBuffer.create(size);
PHYSFS_read(file, mesh->BitangentBuffer.data(),
mesh->BitangentBuffer.size(), 1);
#if 0
// read bounding sphere
PHYSFS_read ( file, &mesh->bounding_sphere, sizeof ( mesh->bounding_sphere ), 1 );
#endif
#if 0
// read bitangent buffer
PHYSFS_read ( file, &size, sizeof ( size ), 1 );
mesh->shadowface_buffer.create ( size );
PHYSFS_read ( file, mesh->shadowface_buffer.data(), mesh->shadowface_buffer.size(), 1 );
#endif
PHYSFS_close(file);
return true;
}
bool MeshManager::saveToCache(Mesh *mesh, const std::string &name)
{
std::string filename = name + ".msc";
PHYSFS_file *file = PHYSFS_openWrite(filename.c_str() );
if (file == 0)
{
clog << ">>> cannot open cache file for mesh: " << name << endline;
return false;
}
// write vertex_buffer
unsigned int size = mesh->VertexBuffer.count();
PHYSFS_write(file, &size, sizeof (size ), 1);
PHYSFS_write(file, mesh->VertexBuffer.data(), mesh->VertexBuffer.size(), 1);
// write index_buffer
size = mesh->IndexBuffer.count();
PHYSFS_write(file, &size, sizeof (size ), 1);
PHYSFS_write(file, mesh->IndexBuffer.data(), mesh->IndexBuffer.size(), 1);
// write subsets
size = mesh->SubsetBuffer.count();
PHYSFS_write(file, &size, sizeof (size ), 1);
PHYSFS_write(file, mesh->SubsetBuffer.data(), mesh->SubsetBuffer.size(), 1);
// write tangent_buffer
size = mesh->TangentBuffer.count();
PHYSFS_write(file, &size, sizeof (size ), 1);
PHYSFS_write(file, mesh->TangentBuffer.data(), mesh->TangentBuffer.size(),
1);
// write bitangent_buffer
size = mesh->BitangentBuffer.count();
PHYSFS_write(file, &size, sizeof (size ), 1);
PHYSFS_write(file, mesh->BitangentBuffer.data(),
mesh->BitangentBuffer.size(), 1);
#if 0
// write bounding sphere
PHYSFS_write ( file, &mesh->bounding_sphere, sizeof ( mesh->bounding_sphere ), 1 );
// write shadowfaces
size = mesh->shadowface_buffer.count();
PHYSFS_write ( file, &size, sizeof ( size ), 1 );
PHYSFS_write ( file, mesh->shadowface_buffer.data(), mesh->shadowface_buffer.size(), 1 );
#endif
PHYSFS_close(file);
return true;
}
} // namespace BlueCore