diff --git a/stepmania/src/Model.cpp b/stepmania/src/Model.cpp index 3a2d9f86ba..b056f26cd7 100644 --- a/stepmania/src/Model.cpp +++ b/stepmania/src/Model.cpp @@ -111,7 +111,22 @@ void Model::LoadPieces( CString sMeshesPath, CString sMaterialsPath, CString sBo // // Setup temp vertices (if necessary) // - m_bUseTempVertices = m_mapNameToAnimation[DEFAULT_ANIMATION_NAME].Bones.size() > 0; // if there are no bones, then there's no reason to use temp vertices + bool bHasAnyPerVertexBones = false; + for (int i = 0; i < (int)m_pGeometry->m_Meshes.size(); i++) + { + msMesh& mesh = m_pGeometry->m_Meshes[i]; + for (int j = 0; j < (int)mesh.Vertices.size(); j++) + { + RageModelVertex &vert = mesh.Vertices[j]; + if( vert.boneIndex != -1 ) + { + bHasAnyPerVertexBones = true; + break; + } + } + } + + m_bUseTempVertices = bHasAnyPerVertexBones; if( m_bUseTempVertices ) { m_vTempVerticesByMesh.resize( m_pGeometry->m_Meshes.size() ); @@ -476,9 +491,6 @@ void Model::DrawPrimitives() // UGLY: This overrides the Actor's BlendMode DISPLAY->SetTextureModeAdd(); } - - DISPLAY->DrawIndexedTriangles( &TempVertices[0], pMesh->Vertices.size(), (Uint16*)&pMesh->Triangles[0], pMesh->Triangles.size()*3 ); - DISPLAY->SetSphereEnironmentMapping( false ); } else { @@ -495,7 +507,23 @@ void Model::DrawPrimitives() shininess ); DISPLAY->ClearAllTextures(); DISPLAY->SetSphereEnironmentMapping( false ); - DISPLAY->DrawIndexedTriangles( &TempVertices[0], pMesh->Vertices.size(), (Uint16*)&pMesh->Triangles[0], pMesh->Triangles.size()*3 ); + } + + // apply mesh-specific bone (if any) + if( pMesh->nBoneIndex != -1 ) + { + DISPLAY->PushMatrix(); + + RageMatrix &mat = m_vpBones[pMesh->nBoneIndex].mFinal; + DISPLAY->PreMultMatrix( mat ); + } + + DISPLAY->DrawIndexedTriangles( &TempVertices[0], pMesh->Vertices.size(), (Uint16*)&pMesh->Triangles[0], pMesh->Triangles.size()*3 ); + DISPLAY->SetSphereEnironmentMapping( false ); + + if( pMesh->nBoneIndex != -1 ) + { + DISPLAY->PopMatrix(); } } } @@ -611,12 +639,14 @@ void Model::PlayAnimation( CString sAniName, float fPlayRate ) } } + // subtract out the bone's resting position for (i = 0; i < (int)m_pGeometry->m_Meshes.size(); i++) { msMesh *pMesh = &m_pGeometry->m_Meshes[i]; for (j = 0; j < (int)pMesh->Vertices.size(); j++) { RageModelVertex *pVertex = &pMesh->Vertices[j]; + int nBoneIndex = (pMesh->nBoneIndex!=-1) ? pMesh->nBoneIndex : pVertex->boneIndex; if (pVertex->boneIndex != -1) { pVertex->p[0] -= m_vpBones[pVertex->boneIndex].mAbsolute.m[3][0]; @@ -785,9 +815,9 @@ void Model::Update( float fDelta ) } // - // process vertices + // process per-vertex bones // - if( m_bUseTempVertices && m_pGeometry ) + if( m_pGeometry && m_bUseTempVertices ) { for (int i = 0; i < (int)m_pGeometry->m_Meshes.size(); i++) { diff --git a/stepmania/src/ModelManager.h b/stepmania/src/ModelManager.h index 9e55bf7b2d..36b02ac24c 100644 --- a/stepmania/src/ModelManager.h +++ b/stepmania/src/ModelManager.h @@ -11,7 +11,7 @@ Chris Danford ----------------------------------------------------------------------------- */ -#include "Model.h" +#include "RageModelGeometry.h" #include diff --git a/stepmania/src/ModelTypes.h b/stepmania/src/ModelTypes.h index 27a3069687..360e7196cf 100644 --- a/stepmania/src/ModelTypes.h +++ b/stepmania/src/ModelTypes.h @@ -78,6 +78,11 @@ typedef struct msMesh // vector Normals; // each vertex holds its own normal + // OPTIMIZATION: If all verts in a mesh are transformed by the same bone, + // then send the transform to the graphics card for the whole mesh instead + // of transforming each vertex on the CPU; + char nBoneIndex; // -1 = no bone + vector Triangles; } msMesh; diff --git a/stepmania/src/RageModelGeometry.cpp b/stepmania/src/RageModelGeometry.cpp index fa47505b0a..0a132ff85b 100644 --- a/stepmania/src/RageModelGeometry.cpp +++ b/stepmania/src/RageModelGeometry.cpp @@ -24,6 +24,41 @@ RageModelGeometry::~RageModelGeometry () { } +void RageModelGeometry::OptimizeBones() +{ + for (unsigned i = 0; i < m_Meshes.size(); i++) + { + msMesh& mesh = m_Meshes[i]; + + // check to see if all vertices have the same bone index + bool bAllVertsUseSameBone = true; + char nBoneIndex = !mesh.Vertices.empty() ? mesh.Vertices[0].boneIndex : -1; + if( nBoneIndex != -1 ) + { + for (unsigned j = 1; j < mesh.Vertices.size(); j++) + { + RageModelVertex& vertex = mesh.Vertices[j]; + if( vertex.boneIndex != nBoneIndex ) + { + bAllVertsUseSameBone = false; + break; + } + } + } + if( bAllVertsUseSameBone ) + { + mesh.nBoneIndex = nBoneIndex; + + // clear all vertex/bone associations; + for (unsigned j = 0; j < mesh.Vertices.size(); j++) + { + RageModelVertex& vertex = mesh.Vertices[j]; + vertex.boneIndex = -1; + } + } + } +} + #define THROW RageException::Throw( "Parse at line %d: '%s'", sLine.c_str() ); void RageModelGeometry::LoadMilkshapeAscii( CString sPath ) @@ -81,6 +116,8 @@ void RageModelGeometry::LoadMilkshapeAscii( CString sPath ) // mesh.nFlags = nFlags; mesh.nMaterialIndex = (byte)nIndex; + mesh.nBoneIndex = -1; + // // vertices // @@ -119,7 +156,6 @@ void RageModelGeometry::LoadMilkshapeAscii( CString sPath ) } - // // normals // @@ -193,6 +229,8 @@ void RageModelGeometry::LoadMilkshapeAscii( CString sPath ) } } + OptimizeBones(); + f.Close(); } diff --git a/stepmania/src/RageModelGeometry.h b/stepmania/src/RageModelGeometry.h index 75b22f0e7a..e12a98ad01 100644 --- a/stepmania/src/RageModelGeometry.h +++ b/stepmania/src/RageModelGeometry.h @@ -28,6 +28,7 @@ public: public: void LoadMilkshapeAscii( CString sMilkshapeAsciiFile ); + void OptimizeBones(); int m_iRefCount;