#include "MeshManager.h" #include "Utilities/format.h" #include "Utilities/Log.h" #include "physfs.h" #include "trimeshloader.h" #include #include 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 ab = mesh->VertexBuffer[ triangle.a ].point - mesh->VertexBuffer[ triangle.b ].point; Vector3Template ac = mesh->VertexBuffer[ triangle.a ].point - mesh->VertexBuffer[ triangle.c ].point; Vector3Template 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 >::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 ab = mesh->vertex_buffer[ a ].point - mesh->vertex_buffer[ b ].point; Vector3Template ac = mesh->vertex_buffer[ a ].point - mesh->vertex_buffer[ c ].point; Vector3Template 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