495 lines
14 KiB
C++
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
|