00001 #include "MercuryShapes.h"
00002 #include "MercuryLoadableModel.h"
00003 #include "MercuryPoly.h"
00004 #include "MercuryLog.h"
00005
00006
00007 void MercuryLoadableModel::Update( const float dTime )
00008 {
00009 static MQuaternion NoRot( 1,0,0,0 );
00010 unsigned i;
00011
00012
00013 for ( i = 0; i < m_vAnimationInfos.size(); ++i )
00014 m_vAnimationInfos[i].fPlace += dTime * m_vAnimationInfos[i].fRate;
00015
00016 for ( i = 0; i < m_vBones.size(); ++i )
00017 {
00018 if ( m_vAnimationInfos.empty() )
00019 ResetBoneMatrix( i );
00020 else
00021 {
00022
00023 MercuryPoint Pos;
00024 MQuaternion Rot;
00025
00026 Pos = m_vBones[i].Pos;
00027 Rot = m_vBones[i].Rot;
00028
00029 float fTotalPercent = 0;
00030
00031 for ( unsigned j = 0; j < m_vAnimationInfos.size(); ++j )
00032 {
00033 float fPercent = m_vAnimationInfos[j].fPercent;
00034 fTotalPercent += fPercent;
00035 float fPlace = m_vAnimationInfos[j].fPlace;
00036 float fStart, fEnd;
00037 bool bHadToForceExit = false;
00038
00039 MLBoneAnimation * pMLP = m_vBones[i].m_mAnimations.get( m_vAnimationInfos[j].sAnimationName );
00040
00041 if( !pMLP )
00042 continue;
00043
00044 bool bDoTween = false;
00045 float fTweenLocation;
00046 MVector<MLAnimationKey> * pAnim = &pMLP->vKeys;
00047
00048 int iStartPlace = pMLP->iCurrentPlace;
00049 int iEndPlace;
00050
00051
00052
00053
00054
00055
00056
00057 float fDuration = pMLP->fAnimationLength;
00058 if ( pMLP->vKeys.size() != 0 && m_vAnimationInfos[j].bRunning )
00059 {
00060 while( fDuration < fPlace )
00061 {
00062 fPlace = fPlace - fDuration;
00063 if( !m_vAnimationInfos[j].bLoop )
00064 m_vAnimationInfos[j].bRunning = false;
00065 }
00066 }
00067
00068
00069 if ( pMLP->vKeys.size() != 0 && m_vAnimationInfos[j].bRunning )
00070 {
00071
00072
00073 int iKeyMax = pMLP->vKeys.size();
00074
00075
00076 int iOriginalStart = iStartPlace;
00077
00078
00079 iEndPlace = ( iStartPlace + 1 )%iKeyMax;
00080
00081 while (!( (*pAnim)[iStartPlace].fSeconds < fPlace && (*pAnim)[iEndPlace].fSeconds >= fPlace ))
00082 {
00083 iStartPlace = ( iStartPlace + 1 )%iKeyMax;
00084 iEndPlace = ( iStartPlace + 1 )%iKeyMax;
00085
00086
00087 if ( iStartPlace == iOriginalStart )
00088 {
00089 bHadToForceExit = true;
00090 break;
00091 }
00092 }
00093
00094 if ( !bHadToForceExit )
00095 {
00096
00097 iEndPlace = ( iStartPlace + 1 )%iKeyMax;
00098 pMLP->iCurrentPlace = iStartPlace;
00099
00100
00101 fStart = (*pAnim)[iStartPlace].fSeconds;
00102 fEnd = (*pAnim)[iEndPlace].fSeconds;
00103
00104 if ( fEnd < fStart )
00105 fEnd+=fDuration;
00106
00107 fTweenLocation = ( fPlace-fStart ) / ( fEnd-fStart );
00108 } else
00109 fTweenLocation = 0;
00110
00111 m_vAnimationInfos[j].fPlace = fPlace;
00112 bDoTween = true;
00113 }
00114
00115 if ( bDoTween )
00116 {
00117 if ( !m_vAnimationInfos[j].bLoop )
00118 {
00119
00120
00121 if ( iStartPlace == 0 )
00122 fPercent = fTweenLocation;
00123 if ( iEndPlace == (int)pMLP->vKeys.size() - 1 )
00124 fPercent = ( 1-fTweenLocation );
00125 }
00126
00127 Pos += (*pAnim)[iStartPlace].Pos * fPercent * (1-fTweenLocation);
00128 Pos += (*pAnim)[iEndPlace].Pos * fPercent * fTweenLocation;
00129 Rot = Rot * SLERP(
00130 NoRot,
00131 SLERP( (*pAnim)[iStartPlace].Rot, (*pAnim)[iEndPlace].Rot, fTweenLocation ),
00132 fPercent );
00133 }
00134 }
00135
00136 MakeBoneMatrix( i, Pos, Rot );
00137 }
00138
00139 MercuryPoint out;
00140 VectorMultiply( m_vBones[i].mXF, gpZero, out );
00141
00142 for ( unsigned int iVert = 0; iVert < m_vBones[i].m_vDissassembledVerts.size(); iVert++ )
00143 {
00144
00145
00146
00147 if ( m_vBones[i].mXF, m_vBones[i].m_vDissassembledVerts[iVert].fPercent > 0.5 )
00148 VectorMultiply( m_vBones[i].mXF, m_vBones[i].m_vDissassembledVerts[iVert].pos,
00149 m_meshes[ m_vBones[i].m_vDissassembledVerts[iVert].iMappedMesh ]->
00150 GetVertex(m_vBones[i].m_vDissassembledVerts[iVert].iMappedVert)->GetPointHandle() );
00151 }
00152
00153
00154
00155 if ( m_vBones[i].iExclusiveMesh != -1 )
00156 {
00157 m_meshes[m_vBones[i].iExclusiveMesh]->SetRotationMode( RM_MATRIX );
00158 m_meshes[m_vBones[i].iExclusiveMesh]->SetPosition( MercuryPoint( 0,0,0 ) );
00159 m_meshes[m_vBones[i].iExclusiveMesh]->SetAfterMatrix( m_vBones[i].mXF.Ptr() );
00160 }
00161 }
00162
00163 for ( i = 0; i < m_meshes.size(); ++i )
00164 if ( m_meshes[i]->IsAnimated() )
00165 m_meshes[i]->CalculateVertexNormals();
00166
00167 MercuryModel::Update( dTime );
00168 }
00169
00170 void MercuryLoadableModel::LoadModel()
00171 {
00172 int sType;
00173 unsigned int i;
00174 unsigned int iVersion;
00175 unsigned int iNumMeshes;
00176 unsigned int iNumBones;
00177 unsigned int iNumAnimations;
00178 unsigned int iNumMaterials;
00179
00180 m_file->Read( &sType, 4 );
00181 TO_ENDIAN(sType);
00182 if (sType != 0x464d424d)
00183 {
00184 LOG.Warn(ssprintf( "%s is not a valid HGMDL file. It has headder %08X", m_file->GetName().c_str(),sType));
00185 return;
00186 }
00187
00188 m_file->Read( &iVersion, 4 );
00189 TO_ENDIAN(iVersion);
00190
00191 m_file->Read( &iNumMeshes, 4 );
00192 TO_ENDIAN(iNumMeshes);
00193
00194 m_meshes.resize( 0 );
00195 m_vMeshMaterialAssignments.resize( iNumMeshes );
00196 for ( i = 0; i < iNumMeshes; ++i )
00197 {
00198 LoadMesh( i );
00199 m_meshes[i]->CalculateVertexNormals();
00200 m_meshes[i]->BuildVBO();
00201 }
00202
00203 m_file->Read( &iNumBones, 4 );
00204 TO_ENDIAN(iNumBones);
00205
00206 m_vBones.resize( iNumBones );
00207 for ( i = 0; i < iNumBones; ++i )
00208 LoadBone( i );
00209
00210 m_file->Read( &iNumAnimations, 4 );
00211 TO_ENDIAN(iNumAnimations);
00212 for ( i = 0; i < iNumAnimations; ++i )
00213 LoadAnimation( i );
00214
00215 m_file->Read( &iNumMaterials, 4 );
00216 TO_ENDIAN(iNumMaterials);
00217 m_materials.resize( iNumMaterials );
00218 for ( i = 0; i < iNumMaterials; ++i )
00219 LoadMaterial( i );
00220
00221
00222 for( i = 0; i < iNumMeshes; ++i )
00223 if( m_vMeshMaterialAssignments[i] >= 0 )
00224 m_meshes[i]->SetMaterial( m_materials[m_vMeshMaterialAssignments[i]] );
00225
00226 m_vMeshMaterialAssignments.resize(0);
00227 SAFE_DELETE( m_file );
00228 }
00229
00230 bool MercuryLoadableModel::LoadMesh( int iMesh )
00231 {
00232 unsigned int iNameLen;
00233 char * sName;
00234 unsigned int iNumVerts;
00235 unsigned int iNumStrips;
00236 unsigned int iNumFans;
00237 unsigned int iNumTriangles;
00238 bool bCache;
00239 unsigned int i;
00240
00241 m_file->Read( &iNameLen, 4 );
00242 TO_ENDIAN(iNameLen);
00243 sName = new char[iNameLen+1];
00244 m_file->Read( sName, iNameLen );
00245 sName[iNameLen] = 0;
00246
00247 MString sFullName = GetName() + sName + ssprintf("%d", iMesh);
00248 SAFE_DELETE(sName);
00249
00250 m_file->Read( &iNumVerts, 4 );
00251 TO_ENDIAN(iNumVerts);
00252 m_file->Read( &iNumStrips, 4 );
00253 TO_ENDIAN(iNumStrips);
00254 m_file->Read( &iNumFans, 4 );
00255 TO_ENDIAN(iNumFans);
00256 m_file->Read( &iNumTriangles, 4 );
00257 TO_ENDIAN(iNumTriangles);
00258 m_file->Read( &m_vMeshMaterialAssignments[iMesh], 4 );
00259 TO_ENDIAN(m_vMeshMaterialAssignments[iMesh]);
00260 m_file->Read( &bCache, 1 );
00261
00262 MercuryMesh * m = new MercuryMesh;
00263 if( MESHMAN.RegMesh( m, sFullName, bCache ) )
00264 {
00265
00266
00267 }
00268
00269 m->SetIsAnimated( !( bCache || m_vMeshMaterialAssignments[iMesh] == 0 ));
00270 m->ToggleUseVBOs( bCache );
00271
00272 m->SetNumVertices(iNumVerts);
00273
00274
00275
00276 m_file->Read( m->GetVerticePtr(), iNumVerts * 32 );
00277
00278 for( i = 0; i < m->NumVertices(); ++i )
00279 {
00280 TO_ENDIAN( *( (unsigned*) & (*m)[i].x ) );
00281 TO_ENDIAN( *( (unsigned*) & (*m)[i].y ) );
00282 TO_ENDIAN( *( (unsigned*) & (*m)[i].z ) );
00283 TO_ENDIAN( *( (unsigned*) & (*m)[i].m_uv[0] ) );
00284 TO_ENDIAN( *( (unsigned*) & (*m)[i].m_uv[1] ) );
00285
00286 if( m_fVisRadius < (*m)[i].GetPointHandle().Magnitude() )
00287 m_fVisRadius = (*m)[i].GetPointHandle().Magnitude();
00288 }
00289
00290 for ( i = 0; i < iNumStrips; ++i)
00291 {
00292 unsigned int length;
00293 m_file->Read( &length, 4 );
00294 TO_ENDIAN( length );
00295 m->SetDrawType(MGL_STRIP);
00296 m->SetNumIndices( length );
00297 m_file->Read( m->GetIndicesPtr(), length*4 );
00298 for( unsigned j = 0; j < length; j++ )
00299 TO_ENDIAN( m->GetIndicesPtr()[j] );
00300 }
00301
00302 for ( i = 0; i < iNumFans; ++i)
00303 {
00304 unsigned int length;
00305 m_file->Read( &length, 4 );
00306 TO_ENDIAN( length );
00307 m->SetDrawType(MGL_FAN);
00308 m->SetNumIndices( length );
00309 m_file->Read( m->GetIndicesPtr(), length*4 );
00310 for( unsigned j = 0; j < length; j++ )
00311 TO_ENDIAN( m->GetIndicesPtr()[j] );
00312 }
00313
00314 if ( iNumTriangles > 0)
00315 {
00316 m->SetDrawType(MGL_TRIANGLE);
00317 m->SetNumIndices( iNumTriangles*3 );
00318 m_file->Read( m->GetIndicesPtr(), m->NumIndices()*4 );
00319 for( unsigned j = 0; j < m->NumIndices(); j++ )
00320 TO_ENDIAN( m->GetIndicesPtr()[j] );
00321 }
00322
00323 if ( iNumStrips != 0 || iNumFans != 0 )
00324 LOG.Warn( "Cannot load model. Model has fans and strips. They are not yet supported." );
00325
00326
00327 AddMesh( m );
00328 return true;
00329 }
00330
00331 void MercuryLoadableModel::LoadBone( int iBone )
00332 {
00333
00334 unsigned int iTmp;
00335 unsigned i;
00336 m_file->Read( &iTmp, 4 );
00337 TO_ENDIAN( iTmp );
00338 char * sName = new char[iTmp+1];
00339 m_file->Read( sName, iTmp );
00340 sName[iTmp] = 0;
00341
00342 m_file->Read( &m_vBones[iBone].iParent, 4 );
00343 TO_ENDIAN( m_vBones[iBone].iParent );
00344 m_file->Read( &m_vBones[iBone].iExclusiveMesh, 4 );
00345 TO_ENDIAN( m_vBones[iBone].iExclusiveMesh );
00346 m_file->Read( &m_vBones[iBone].Pos, 4 * 3 );
00347 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].Pos.x ) );
00348 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].Pos.y ) );
00349 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].Pos.z ) );
00350 m_file->Read( &m_vBones[iBone].Rot, 4 * 4 );
00351 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].Rot.w ) );
00352 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].Rot.x ) );
00353 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].Rot.y ) );
00354 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].Rot.z ) );
00355 m_file->Read( &iTmp, 4 );
00356 TO_ENDIAN( iTmp );
00357
00358 ResetBoneMatrix( iBone );
00359
00360
00361
00362 m_vBones[iBone].m_vDissassembledVerts.resize( iTmp );
00363
00364 for ( i = 0; i < iTmp; i++ )
00365 {
00366 MLQVert * tVert = &m_vBones[iBone].m_vDissassembledVerts[i];
00367 m_file->Read( &tVert->iMappedMesh, 4 );
00368 TO_ENDIAN( tVert->iMappedMesh );
00369 m_file->Read( &tVert->iMappedVert, 4 );
00370 TO_ENDIAN( tVert->iMappedVert );
00371 m_file->Read( &tVert->fPercent, 4 );
00372 TO_ENDIAN( *( (unsigned*) & (tVert->fPercent) ) );
00373
00374 MercuryPoint G = m_meshes[tVert->iMappedMesh]->GetVertex(tVert->iMappedVert)->GetPointHandle();
00375 MercuryMatrix P;
00376 InvertMatrix( m_vBones[iBone].mXF, P );
00377
00378 VectorMultiply( P, G, tVert->pos );
00379 }
00380
00381 SAFE_DELETE(sName);
00382
00383
00384
00385
00386
00387
00388
00389 }
00390
00391 void MercuryLoadableModel::LoadAnimation( int iAnimation )
00392 {
00393 unsigned int iTmp = 0;
00394 unsigned int iNumBones = 0;
00395 char * sAnimationName;
00396 float fDuration = 0.0f;
00397 m_file->Read( &iTmp, 4 );
00398 TO_ENDIAN( iTmp );
00399 sAnimationName = new char [iTmp + 1];
00400 m_file->Read( sAnimationName, iTmp );
00401 sAnimationName[iTmp] = '\0';
00402
00403 m_file->Read( &fDuration,4);
00404 TO_ENDIAN( *( (unsigned*) & (fDuration) ) );
00405 m_file->Read( &iNumBones, 4 );
00406 TO_ENDIAN( iNumBones );
00407
00408 for ( unsigned int i = 0; i < iNumBones; ++i )
00409 {
00410 int iBone;
00411 int iNumKeys;
00412 m_file->Read( &iBone, 4 );
00413 TO_ENDIAN( iBone );
00414 m_file->Read( &iNumKeys, 4 );
00415 TO_ENDIAN( iNumKeys );
00416
00417 m_vBones[iBone].m_mAnimations[sAnimationName].fAnimationLength = fDuration;
00418 m_vBones[iBone].m_mAnimations[sAnimationName].vKeys.resize( iNumKeys );
00419 m_vBones[iBone].m_mAnimations[sAnimationName].iCurrentPlace = 0;
00420
00421 for ( int j = 0; j < iNumKeys; ++j )
00422 {
00423 m_file->Read( &m_vBones[iBone].m_mAnimations[sAnimationName].vKeys[j].fSeconds, 4 );
00424 m_file->Read( &m_vBones[iBone].m_mAnimations[sAnimationName].vKeys[j].Pos, 4 * 3 );
00425 m_file->Read( &m_vBones[iBone].m_mAnimations[sAnimationName].vKeys[j].Rot, 4 * 4 );
00426 TO_ENDIAN( *( (unsigned*) & (m_vBones[iBone].m_mAnimations[sAnimationName].vKeys[j].fSeconds) ) );
00427 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].m_mAnimations[sAnimationName].vKeys[j].Pos.x ) );
00428 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].m_mAnimations[sAnimationName].vKeys[j].Pos.y ) );
00429 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].m_mAnimations[sAnimationName].vKeys[j].Pos.z ) );
00430 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].m_mAnimations[sAnimationName].vKeys[j].Rot.w ) );
00431 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].m_mAnimations[sAnimationName].vKeys[j].Rot.x ) );
00432 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].m_mAnimations[sAnimationName].vKeys[j].Rot.y ) );
00433 TO_ENDIAN( *( (unsigned*) & m_vBones[iBone].m_mAnimations[sAnimationName].vKeys[j].Rot.z ) );
00434 }
00435 }
00436
00437 SAFE_DELETE( sAnimationName );
00438 }
00439
00440 void MercuryLoadableModel::LoadMaterial( int iMaterial )
00441 {
00442 unsigned int iNameLen;
00443 char * sName;
00444 m_file->Read( &iNameLen, 4 );
00445 TO_ENDIAN( iNameLen );
00446 sName = new char[iNameLen+1];
00447 m_file->Read( sName, iNameLen );
00448 sName[iNameLen] = 0;
00449 MercuryMaterial * m = new MercuryMaterial;
00450 m->LoadMaterial( MString( sName, iNameLen ), m_path );
00451 SAFE_DELETE(sName);
00452 m_materials[iMaterial] = m;
00453 }
00454
00455
00456
00457
00458
00459 void MercuryLoadableModel::ResetBoneMatrix( int iBone )
00460 {
00461 MercuryMatrix m,n,o;
00462 MLBone * thisbone = &m_vBones[iBone];
00463
00464 (thisbone->Rot).toMatrix4( o );
00465 o[0][3] = thisbone->Pos.x;
00466 o[1][3] = thisbone->Pos.y;
00467 o[2][3] = thisbone->Pos.z;
00468
00469 if ( thisbone->iParent >= 0 )
00470 {
00471 m = m_vBones[m_vBones[iBone].iParent].mXF * o;
00472 Copy16f( &thisbone->mXF, &m);
00473 }
00474 else
00475 Copy16f(&thisbone->mXF, &o);
00476 }
00477
00478 void MercuryLoadableModel::MakeBoneMatrix( int iBone, const MercuryPoint & Pos, const MQuaternion & Rot )
00479 {
00480 MercuryMatrix m,n,o;
00481 MLBone * thisbone = &m_vBones[iBone];
00482
00483 Rot.toMatrix4( o );
00484 o[0][3] = Pos.x;
00485 o[1][3] = Pos.y;
00486 o[2][3] = Pos.z;
00487
00488 if ( thisbone->iParent >= 0 )
00489 {
00490 m = m_vBones[m_vBones[iBone].iParent].mXF * o;
00491 Copy16f( &thisbone->mXF, &m );
00492 }
00493 else
00494 Copy16f( &thisbone->mXF, &o );
00495 }
00496
00497 #include "MercuryObjectFactory.h"
00498 REGISTER_OBJECT_TYPE( MercuryLoadableModel );
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527