From dde601e416e4090b1b502f34aa89254c27fcc236 Mon Sep 17 00:00:00 2001 From: Mark Vejvoda Date: Thu, 20 Jun 2013 07:24:09 +0000 Subject: [PATCH] attempt to implement will's mesh merging for better render performance --- source/shared_lib/include/graphics/model.h | 12 + .../sources/graphics/gl/model_renderer_gl.cpp | 10 + source/shared_lib/sources/graphics/model.cpp | 344 +++++++++++++++++- 3 files changed, 364 insertions(+), 2 deletions(-) diff --git a/source/shared_lib/include/graphics/model.h b/source/shared_lib/include/graphics/model.h index 097e61c58..57b695921 100644 --- a/source/shared_lib/include/graphics/model.h +++ b/source/shared_lib/include/graphics/model.h @@ -92,6 +92,8 @@ public: void init(); void end(); + void copyInto(Mesh *dest, bool ignoreInterpolationData, bool destinationOwnsTextures); + //maps const Texture2D *getTexture(int i) const {return textures[i];} @@ -116,6 +118,11 @@ public: const Vec3f *getTangents() const {return tangents;} const uint32 *getIndices() const {return indices;} + void setVertices(Vec3f *data, uint32 count); + void setNormals(Vec3f *data, uint32 count); + void setTexCoords(Vec2f *data, uint32 count); + void setIndices(uint32 *data, uint32 count); + //material const Vec3f &getDiffuseColor() const {return diffuseColor;} const Vec3f &getSpecularColor() const {return specularColor;} @@ -127,11 +134,15 @@ public: bool getCustomTexture() const {return customColor;} bool getNoSelect() const {return noSelect;} + uint32 getTextureFlags() const { return textureFlags; } + //external data const InterpolationData *getInterpolationData() const {return interpolationData;} //interpolation void buildInterpolationData(); + void cleanupInterpolationData(); + void updateInterpolationData(float t, bool cycle); void updateInterpolationVertices(float t, bool cycle); @@ -225,6 +236,7 @@ public: private: void buildInterpolationData() const; + void autoJoinMeshFrames(); }; class PixelBufferWrapper { diff --git a/source/shared_lib/sources/graphics/gl/model_renderer_gl.cpp b/source/shared_lib/sources/graphics/gl/model_renderer_gl.cpp index 6ae03eabf..41107f601 100644 --- a/source/shared_lib/sources/graphics/gl/model_renderer_gl.cpp +++ b/source/shared_lib/sources/graphics/gl/model_renderer_gl.cpp @@ -237,6 +237,8 @@ void ModelRendererGl::renderMesh(Mesh *mesh,int renderMode) { glDisableClientState(GL_NORMAL_ARRAY); } + assertGl(); + //tex coords if(renderTextures && mesh->getTexture(mtDiffuse) != NULL ) { if(duplicateTexCoords) { @@ -279,6 +281,8 @@ void ModelRendererGl::renderMesh(Mesh *mesh,int renderMode) { glDisableClientState(GL_NORMAL_ARRAY); } + assertGl(); + //tex coords if(renderTextures && mesh->getTexture(mtDiffuse)!=NULL ) { if(duplicateTexCoords) { @@ -302,15 +306,21 @@ void ModelRendererGl::renderMesh(Mesh *mesh,int renderMode) { } if(getVBOSupported() == true && mesh->getFrameCount() == 1) { + assertGl(); + glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, mesh->getVBOIndexes() ); glDrawRangeElements(GL_TRIANGLES, 0, vertexCount-1, indexCount, GL_UNSIGNED_INT, (char *)NULL); glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); //glDrawRangeElements(GL_TRIANGLES, 0, vertexCount-1, indexCount, GL_UNSIGNED_INT, mesh->getIndices()); + + assertGl(); } else { //draw model + assertGl(); + glDrawRangeElements(GL_TRIANGLES, 0, vertexCount-1, indexCount, GL_UNSIGNED_INT, mesh->getIndices()); } diff --git a/source/shared_lib/sources/graphics/model.cpp b/source/shared_lib/sources/graphics/model.cpp index f73817a9b..92ceff3ad 100644 --- a/source/shared_lib/sources/graphics/model.cpp +++ b/source/shared_lib/sources/graphics/model.cpp @@ -22,6 +22,8 @@ #include "opengl.h" #include "platform_util.h" #include +#include +#include #include "leak_dumper.h" using namespace Shared::Platform; @@ -287,8 +289,7 @@ void Mesh::end() { delete [] indices; indices=NULL; - delete interpolationData; - interpolationData=NULL; + cleanupInterpolationData(); if(textureManager != NULL) { for(int i = 0; i < meshTextureCount; ++i) { @@ -311,6 +312,11 @@ void Mesh::buildInterpolationData(){ interpolationData= new InterpolationData(this); } +void Mesh::cleanupInterpolationData() { + delete interpolationData; + interpolationData=NULL; +} + void Mesh::updateInterpolationData(float t, bool cycle) { if(interpolationData != NULL) { interpolationData->update(t, cycle); @@ -1292,6 +1298,8 @@ void Model::loadG3d(const string &path, bool deletePixMapAfterLoad, } fclose(f); + + autoJoinMeshFrames(); } catch(megaglest_runtime_error& ex) { //printf("1111111 ex.wantStackTrace() = %d\n",ex.wantStackTrace()); @@ -1369,6 +1377,338 @@ void Model::deletePixels() { } } +class MeshContainer { +protected: + int indexValue; + std::vector meshes; + +public: + + MeshContainer() { + this->indexValue = -1; + } + void add(int index, Mesh *mesh) { + if(this->indexValue < 0) { + this->indexValue = index; + } + meshes.push_back(mesh); + } + int index() { + return indexValue; + } + int size() { + return meshes.size(); + } + std::vector get() { + return meshes; + } +}; + +void Mesh::setVertices(Vec3f *data, uint32 count) { + delete [] this->vertices; + this->vertices = data; + + this->vertexCount = count; +} +void Mesh::setNormals(Vec3f *data, uint32 count) { + delete [] this->normals; + this->normals = data; + + this->vertexCount = count; +} + +void Mesh::setTexCoords(Vec2f *data, uint32 count) { + delete [] this->texCoords; + this->texCoords = data; + + this->vertexCount = count; +} + +void Mesh::setIndices(uint32 *data, uint32 count) { + delete [] this->indices; + this->indices = data; + + this->indexCount = count; +} + +void Mesh::copyInto(Mesh *dest, bool ignoreInterpolationData, + bool destinationOwnsTextures) { + + for(int index = 0; index < meshTextureCount; ++index){ + dest->textures[index] = this->textures[index]; + dest->texturesOwned[index] = this->texturesOwned[index]; + dest->texturePaths[index] = this->texturePaths[index]; + + if(destinationOwnsTextures == true) { + this->texturesOwned[index] = false; + } + } + + dest->name = this->name; + //vertex data counts + dest->frameCount = this->frameCount; + dest->vertexCount = this->vertexCount; + dest->indexCount = this->indexCount; + dest->texCoordFrameCount = this->texCoordFrameCount; + + //vertex data + if(dest->vertices != NULL) { + delete [] dest->vertices; + dest->vertices = NULL; + } + if(this->vertices != NULL) { + dest->vertices = new Vec3f[this->frameCount * this->vertexCount]; + memcpy(&dest->vertices[0],&this->vertices[0],this->frameCount * this->vertexCount * sizeof(Vec3f)); + } + + if(dest->normals != NULL) { + delete [] dest->normals; + dest->normals = NULL; + } + if(this->normals != NULL) { + dest->normals = new Vec3f[this->frameCount * this->vertexCount]; + memcpy(&dest->normals[0],&this->normals[0],this->frameCount * this->vertexCount * sizeof(Vec3f)); + } + + if(dest->texCoords != NULL) { + delete [] dest->texCoords; + dest->texCoords = NULL; + } + if(this->texCoords != NULL) { + dest->texCoords = new Vec2f[this->vertexCount]; + memcpy(&dest->texCoords[0],&this->texCoords[0],this->vertexCount * sizeof(Vec2f)); + } + + if(dest->tangents != NULL) { + delete [] dest->tangents; + dest->tangents = NULL; + } + if(this->tangents != NULL) { + dest->tangents = new Vec3f[this->vertexCount]; + memcpy(&dest->tangents[0],&this->tangents[0],this->vertexCount * sizeof(Vec3f)); + } + + if(dest->indices != NULL) { + delete [] dest->indices; + dest->indices = NULL; + } + if(this->indices != NULL) { + dest->indices = new uint32[this->indexCount]; + memcpy(&dest->indices[0],&this->indices[0],this->indexCount * sizeof(uint32)); + } + + //material data + dest->diffuseColor = this->diffuseColor; + dest->specularColor = this->specularColor; + dest->specularPower = this->specularPower; + dest->opacity = this->opacity; + + //properties + dest->twoSided = this->twoSided; + dest->customColor = this->customColor; + dest->noSelect = this->noSelect; + + dest->textureFlags = this->textureFlags; + + if(ignoreInterpolationData == false) { + dest->interpolationData = this->interpolationData; + } + dest->textureManager = this->textureManager; + + // Vertex Buffer Object Names + dest->hasBuiltVBOs = this->hasBuiltVBOs; + dest->m_nVBOVertices = this-> m_nVBOVertices; + dest->m_nVBOTexCoords = this->m_nVBOTexCoords; + dest->m_nVBONormals = this->m_nVBONormals; + dest->m_nVBOIndexes = this->m_nVBOIndexes; +} + +void Model::autoJoinMeshFrames() { + +/* + print "auto-joining compatible meshes..." + meshes = {} + for mesh in self.meshes: + key = (mesh.texture,mesh.frame_count,mesh.twoSided|mesh.customColour) + if key in meshes: + meshes[key].append(mesh) + else: + meshes[key] = [mesh] + for joinable in meshes.values(): + if len(joinable) < 2: continue + base = joinable[0] + print "\tjoining to",base + for mesh in joinable[1:]: + if base.index_count+mesh.index_count > 0xffff: + base = mesh + print "\tjoining to",base + continue + print "\t\t",mesh + for a,b in zip(base.frames,mesh.frames): + a.vertices.extend(b.vertices) + a.normals.extend(b.normals) + if base.texture: + base.textures.extend(mesh.textures) + base.indices.extend(index+base.vertex_count for index in mesh.indices) + base.vertex_count += mesh.vertex_count + base.index_count += mesh.index_count + self.meshes.remove(mesh) +*/ + + + + bool haveJoinedMeshes = false; + + // First looks for meshes with same texture in the same frame + std::map joinedMeshes; + for(uint32 index = 0; index < meshCount; ++index) { + Mesh &mesh = meshes[index]; + + // Duplicate mesh vertices are considered to be those with the same + // 1. texture 2. framecount 3. twosided flag value 4. same custom texture color + string mesh_key = (mesh.getTextureFlags() & 1 ? mesh.getTexture(0)->getPath() : "none"); + mesh_key += string("_") + intToStr(mesh.getFrameCount()) + + string("_") + intToStr(mesh.getTwoSided()) + + string("_") + intToStr(mesh.getCustomTexture()); + + joinedMeshes[mesh_key].add(index,&mesh); + if(haveJoinedMeshes == false && joinedMeshes[mesh_key].size() > 1) { + haveJoinedMeshes = true; + } + } + + if(haveJoinedMeshes == true) { + //printf("*** Detected Joined meshes for model [%s]\n",fileName.c_str()); + + // We have mesh data to join we now create a list in the same order + // as the original meshes but each index will have 1 or more meshes + // This is done to maintain original mesh ordering + std::map > orderedMeshes; + for(std::map::iterator iterMap = joinedMeshes.begin(); + iterMap != joinedMeshes.end(); ++iterMap) { + orderedMeshes[iterMap->second.index()] = iterMap->second.get(); + + //if(iterMap->second.size() > 1) { + // printf("Key [%s] joined meshes: %d\n",iterMap->first.c_str(),iterMap->second.size()); + //} + } + + // Now the real work of creating a new list of joined mesh data + Mesh *joinedMeshList = new Mesh[joinedMeshes.size()]; + + int index = 0; + for(std::map >::iterator iterMap = orderedMeshes.begin(); + iterMap != orderedMeshes.end(); ++iterMap) { + //printf("Join index: %d joincount: %d\n",index,iterMap->second.size()); + + Mesh *base = &joinedMeshList[index]; + + // Deep copy mesh data + iterMap->second[0]->copyInto(base, true, true); + + if(iterMap->second.size() > 1) { + // Time to join mesh data for this mesh + for(int joinIndex = 1; + joinIndex < iterMap->second.size(); ++joinIndex) { + Mesh *mesh = iterMap->second[joinIndex]; + if(base->getIndexCount() + mesh->getIndexCount() > 0xffff) { + printf("Not exactly sure what this IF statement is for?\n"); + mesh->copyInto(base, true, true); + } + else { + // Need to add verticies for each from from mesh to base + uint32 originalBaseVertexCount = base->getVertexCount(); + + uint32 newVertexCount = + base->getVertexCount() + mesh->getVertexCount(); + + uint32 newVertexFrameCount = + (base->getFrameCount() * newVertexCount); + + Vec3f *joined_vertices = new Vec3f[newVertexFrameCount]; + Vec3f *joined_normals = new Vec3f[newVertexFrameCount]; + uint32 join_index = 0; + + // Join mesh vertices and normals + for(int frameIndex = 0; + frameIndex < base->getFrameCount(); ++frameIndex) { + uint32 baseIndex = frameIndex * originalBaseVertexCount; + uint32 meshIndex = frameIndex * mesh->getVertexCount(); + //uint32 appendBaseJoinIndex = frameIndex * newVertexCount; + + // first original mesh values get copied + memcpy(&joined_vertices[join_index], + &base->getVertices()[baseIndex], + originalBaseVertexCount * sizeof(Vec3f)); + memcpy(&joined_normals[join_index], + &base->getNormals()[baseIndex], + originalBaseVertexCount * sizeof(Vec3f)); + join_index += originalBaseVertexCount; + + // second joined mesh values get copied + memcpy(&joined_vertices[join_index], + &mesh->getVertices()[meshIndex], + mesh->getVertexCount() * sizeof(Vec3f)); + memcpy(&joined_normals[join_index], + &mesh->getNormals()[meshIndex], + mesh->getVertexCount() * sizeof(Vec3f)); + join_index += mesh->getVertexCount(); + } + + // update vertex and normal buffers with joined mesh data + base->setVertices(joined_vertices, newVertexCount); + base->setNormals(joined_normals, newVertexCount); + + // If we have texture coords join them + if(base->getTextureFlags() & 1) { + Vec2f *joined_texCoords = new Vec2f[newVertexCount]; + + // update texture coord buffers with joined mesh data + memcpy(&joined_texCoords[0], + &base->getTexCoords()[0], + originalBaseVertexCount * sizeof(Vec2f)); + memcpy(&joined_texCoords[originalBaseVertexCount], + &mesh->getTexCoords()[0], + mesh->getVertexCount() * sizeof(Vec2f)); + + base->setTexCoords(joined_texCoords, newVertexCount); + } + + // update index buffers with joined mesh data + uint32 newindexCount = base->getIndexCount() + mesh->getIndexCount(); + uint32 *joined_indexes = new uint32[newindexCount]; + + uint32 join_index_index = 0; + memcpy(&joined_indexes[join_index_index], + &base->getIndices()[0], + base->getIndexCount() * sizeof(uint32)); + join_index_index += base->getIndexCount(); + + for(int meshIndex = 0; + meshIndex < mesh->getIndexCount(); ++meshIndex) { + uint32 index_value = mesh->getIndices()[meshIndex]; + + // join index values + joined_indexes[join_index_index] = index_value + originalBaseVertexCount; + join_index_index++; + } + base->setIndices(joined_indexes, newindexCount); + } + } + } + base->buildInterpolationData(); + + index++; + } + + delete [] meshes; + meshes = joinedMeshList; + meshCount = joinedMeshes.size(); + } +} + +// ---------------------------------------------------------------------------- + bool PixelBufferWrapper::isPBOEnabled = false; int PixelBufferWrapper::index = 0; vector PixelBufferWrapper::pboIds;