00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <string.h>
00012 #include "Common/Assert.h"
00013 #include "Common/File.h"
00014 #include "Common/Error.h"
00015 #include "Common/Parser.h"
00016 #include "Model/MdlMesh.h"
00017 #include "Model/MdlAnim.h"
00018 #include "Model/MdlLoader.h"
00019
00020 #define HEADER_MDLMAGIC "3DMODEL"
00021 #define HEADER_ANMMAGIC "ANIM"
00022
00023 u32 KMdlLoader::m_MDLVersion = 104;
00024 u32 KMdlLoader::m_ANMVersion = 100;
00025
00026
00027 KMdlLoader::KMdlLoader()
00028 {
00029 m_StartFrame = 0;
00030 m_EndFrame = 0;
00031 }
00032
00033
00034 KMdlLoader::~KMdlLoader()
00035 {
00036 Flush();
00037 }
00038
00039
00040 void KMdlLoader::Flush()
00041 {
00042 for( u32 m = 0; m < m_Meshes.GetSize(); m ++ )
00043 Deletep( m_Meshes[m] );
00044 for( u32 a = 0; a < m_Anims.GetSize(); a ++ )
00045 Deletep( m_Anims[a] );
00046 for( u32 t = 0; t < m_Shaders.GetSize(); t ++ )
00047 Freep( m_Shaders[t] );
00048
00049 m_Meshes.Clear();
00050 m_Anims.Clear();
00051 m_Shaders.Clear();
00052 }
00053
00054
00055 bool KMdlLoader::LoadMDL( char* pFileName )
00056 {
00057 KFile File;
00058 char pMagic[] = { HEADER_MDLMAGIC };
00059 u32 Version;
00060
00061
00062 for( u32 m = 0; m < m_Meshes.GetSize(); m ++ )
00063 Deletep( m_Meshes[m] );
00064 m_Meshes.Clear();
00065
00066 for( u32 t = 0; t < m_Shaders.GetSize(); t ++ )
00067 Freep( m_Shaders[t] );
00068 m_Shaders.Clear();
00069
00070
00071
00072 memset( pMagic, 0, sizeof( pMagic ) );
00073
00074 if( !File.Open( pFileName ) )
00075 {
00076 KError::Warning( NULL, "Cannot open model file : %s", pFileName );
00077 return false;
00078 }
00079
00080
00081 File >> pMagic;
00082 if( strncmp( pMagic, HEADER_MDLMAGIC, strlen( HEADER_MDLMAGIC ) ) != 0 )
00083 {
00084 KError::Error( NULL, "Bad model header in file : %s", pFileName );
00085 return false;
00086 }
00087
00088
00089 File >> Version;
00090 if( Version != m_MDLVersion )
00091 {
00092 KError::Error( NULL, "Bad model version in file : %s\nFile version : %i, Expected version %i", pFileName, Version, m_MDLVersion );
00093 return false;
00094 }
00095
00096
00097 u32 ShaderId;
00098 u32 Length;
00099 u32 nTextures;
00100 char* pTextureName;
00101
00102 File >> nTextures;
00103 for( ShaderId = 0; ShaderId < nTextures; ShaderId ++ )
00104 {
00105 File >> Length;
00106 pTextureName = (char*)malloc(Length + 1);
00107 File.Read( (u8*)pTextureName, Length );
00108 pTextureName[Length] = '\0';
00109 m_Shaders.Add( pTextureName );
00110 }
00111
00112
00113 File >> m_StartFrame >> m_EndFrame;
00114
00115
00116 u32 MeshId;
00117 u32 nMeshes;
00118 KMdlMesh* pMesh = NULL;
00119
00120 File >> nMeshes;
00121 for( MeshId = 0; MeshId < nMeshes; MeshId ++ )
00122 {
00123 pMesh = new KMdlMesh();
00124 pMesh->Load( File, m_EndFrame );
00125 m_Meshes.Add( pMesh );
00126 }
00127
00128 File.Close();
00129
00130
00131 GenerateHierarchy();
00132
00133
00134 GenerateBones();
00135
00136
00137 ComputeFirstWorldMatrix();
00138
00139 return true;
00140 }
00141
00142
00143 #define FINDTOKEN Parser.FindToken()
00144 #define TOKEN Parser.GetToken()
00145 #define NEWLINETOKEN Parser.IsNewLine()
00146 #define CMPTOKEN(__s) (stricmp(__s,Parser.GetToken()) == 0)
00147
00148
00149 bool KMdlLoader::LoadANM( char* pFileName )
00150 {
00151 KParser Parser;
00152
00153
00154 for( u32 a = 0; a < m_Anims.GetSize(); a ++ )
00155 Deletep( m_Anims[a] );
00156 m_Anims.Clear();
00157
00158
00159 if( !Parser.LoadASE( pFileName ) )
00160 {
00161 KError::Warning( NULL, "Cannot open anim file : %s\nThe model will not be animated.", pFileName );
00162 return true;
00163 }
00164
00165
00166 FINDTOKEN;
00167 if( !CMPTOKEN( HEADER_ANMMAGIC ) )
00168 {
00169 KError::Error( NULL, "Bad anim header in file : %s", pFileName );
00170 return false;
00171 }
00172
00173
00174 FINDTOKEN;
00175 if( atoi( TOKEN ) != m_ANMVersion )
00176 {
00177 KError::Error( NULL, "Bad anim version in file : %s\nFile version : %i, Expected version %i", pFileName, atoi( TOKEN ), m_ANMVersion );
00178 return false;
00179 }
00180
00181
00182 while( !Parser.IsEOF() )
00183 {
00184 #define TEST_TOKEN_THROW( x ) if( !CMPTOKEN( x ) ) throw x
00185
00186 KMdlAnim* pAnim = new KMdlAnim();
00187
00188 try
00189 {
00190
00191 FINDTOKEN;
00192 if( !CMPTOKEN( "ANIM_NAME" ) )
00193 continue;
00194
00195 FINDTOKEN;
00196 pAnim->SetName( KStr( TOKEN ) );
00197
00198
00199 FINDTOKEN;
00200 TEST_TOKEN_THROW( "{" );
00201
00202
00203 FINDTOKEN;
00204 TEST_TOKEN_THROW( "FRAME_COUNT" );
00205 FINDTOKEN;
00206 if( atoi( TOKEN ) < 1 )
00207 {
00208 KError::Error( NULL, "Error in anim file [%s]\nFRAME_COUNT should be greater than 1 [%i]", pFileName, atoi( TOKEN ) );
00209 return false;
00210 }
00211 pAnim->SetMaxFrame( atoi( TOKEN ) - 1 );
00212
00213
00214 FINDTOKEN;
00215 TEST_TOKEN_THROW( "FPS" );
00216 FINDTOKEN;
00217 if( atoi( TOKEN ) < 1 )
00218 {
00219 KError::Error( NULL, "Error in anim file [%s]\nFPS should be greater than 1 [%i]", pFileName, atoi( TOKEN ) );
00220 return false;
00221 }
00222 pAnim->SetFPS( atoi( TOKEN ) );
00223
00224
00225 FINDTOKEN;
00226 while( !CMPTOKEN( "}" ) )
00227 {
00228 KMdlMeshAnim* pMeshAnim = new KMdlMeshAnim();
00229
00230
00231 TEST_TOKEN_THROW( "MESHANIM_NAME" );
00232 FINDTOKEN;
00233 pMeshAnim->SetpMesh( GetpMeshByName( TOKEN ) );
00234 if( !pMeshAnim->GetpMesh() )
00235 {
00236 KError::Error( NULL, "Error in anim file [%s]\nUnknown mesh name [%s]", pFileName, TOKEN );
00237 return false;
00238 }
00239
00240
00241 FINDTOKEN;
00242 TEST_TOKEN_THROW( "{" );
00243
00244
00245 FINDTOKEN;
00246 TEST_TOKEN_THROW( "MESHANIM_INHERITFRAME" );
00247 FINDTOKEN;
00248 pMeshAnim->SetInheritFrame( atoi( TOKEN ) ? true : false );
00249
00250
00251 FINDTOKEN;
00252 TEST_TOKEN_THROW( "MESHANIM_FRAMESTART" );
00253 FINDTOKEN;
00254 pMeshAnim->SetFrameStart( atoi( TOKEN ) );
00255
00256
00257 FINDTOKEN;
00258 TEST_TOKEN_THROW( "MESHANIM_FRAMEEND" );
00259 FINDTOKEN;
00260 pMeshAnim->SetFrameEnd( atoi( TOKEN ) );
00261
00262
00263 FINDTOKEN;
00264 TEST_TOKEN_THROW( "MESHANIM_MESHFRAMESTART" );
00265 FINDTOKEN;
00266 pMeshAnim->SetMeshFrameStart( atoi( TOKEN ) );
00267
00268
00269 FINDTOKEN;
00270 TEST_TOKEN_THROW( "MESHANIM_MESHFRAMEEND" );
00271 FINDTOKEN;
00272 pMeshAnim->SetMeshFrameEnd( atoi( TOKEN ) );
00273
00274 pAnim->AddMeshAnim( pMeshAnim );
00275
00276
00277 FINDTOKEN;
00278 TEST_TOKEN_THROW( "}" );
00279
00280 FINDTOKEN;
00281 }
00282 }
00283 catch( char* pToken )
00284 {
00285 KError::Error( NULL, "Error in anim file [%s] line %i\nToken %s not found", pFileName, Parser.GetCurrentLine(), pToken );
00286 return false;
00287 }
00288
00289 AddAnim( pAnim );
00290 }
00291
00292 return true;
00293 }
00294
00295
00296 bool KMdlLoader::SaveMDL( char* pFileName )
00297 {
00298 KFile File;
00299
00300 if( !File.Create( pFileName ) )
00301 return false;
00302
00303
00304 File << HEADER_MDLMAGIC;
00305
00306 File << m_MDLVersion;
00307
00308
00309 u32 ShaderId;
00310 u32 Length;
00311 u32 nShaders = m_Shaders.GetSize();
00312
00313 File << nShaders;
00314 for( ShaderId = 0; ShaderId < m_Shaders.GetSize(); ShaderId ++ )
00315 {
00316 Length = (u32)strlen( m_Shaders[ShaderId] );
00317 File << Length;
00318 File.Write( (u8*)m_Shaders[ShaderId], Length );
00319 }
00320
00321
00322 File << m_StartFrame << m_EndFrame;
00323
00324
00325 u32 MeshId;
00326 u32 nMeshes = m_Meshes.GetSize();
00327
00328 File << nMeshes;
00329 for( MeshId = 0; MeshId < m_Meshes.GetSize(); MeshId ++ )
00330 m_Meshes[MeshId]->Save( File );
00331
00332 File.Close();
00333
00334 return true;
00335 }
00336
00337
00338 bool KMdlLoader::SaveANM( char* pFileName )
00339 {
00340 KFile File;
00341 KStr sText;
00342
00343 if( !File.Create( pFileName ) )
00344 return false;
00345
00346
00347 sText = "// Magic\r\n";
00348 sText += HEADER_ANMMAGIC;
00349 sText += "\r\n";
00350 File.WriteText( sText );
00351
00352
00353 sText = "// File version\r\n";
00354 sText += (s32)KMdlLoader::m_ANMVersion;
00355 sText += "\r\n\r\n";
00356 File.WriteText( sText );
00357
00358
00359 for( u32 AnimId = 0; AnimId < m_Anims.GetSize(); AnimId ++ )
00360 {
00361 KMdlAnim* pAnim = m_Anims[AnimId];
00362
00363 sText = "ANIM_NAME ";
00364 sText += pAnim->GetName();
00365 sText += "\r\n";
00366 File.WriteText( sText );
00367
00368 File.WriteText( KStr( "{\r\n" ) );
00369
00370 sText = " FRAME_COUNT ";
00371 sText += (s32)(pAnim->GetMaxFrame() + 1);
00372 sText += "\r\n";
00373 File.WriteText( sText );
00374
00375 sText = " FPS ";
00376 sText += (s32)pAnim->GetFPS();
00377 sText += "\r\n\r\n";
00378 File.WriteText( sText );
00379
00380
00381 for( u32 MeshAnimId = 0; MeshAnimId < pAnim->GetnMeshAnims(); MeshAnimId ++ )
00382 {
00383 KMdlMeshAnim* pMeshAnim = pAnim->GetpMeshAnims( MeshAnimId );
00384 sText = " MESHANIM_NAME ";
00385 sText += pMeshAnim->GetpMesh()->m_Name;
00386 sText += "\r\n";
00387 File.WriteText( sText );
00388
00389 File.WriteText( KStr( " {\r\n" ) );
00390
00391 sText = " MESHANIM_INHERITFRAME ";
00392 sText += (s32)pMeshAnim->IsInheritFrame();
00393 sText += "\r\n";
00394 File.WriteText( sText );
00395
00396 sText = " MESHANIM_FRAMESTART ";
00397 sText += (s32)pMeshAnim->GetFrameStart();
00398 sText += "\r\n";
00399 File.WriteText( sText );
00400
00401 sText = " MESHANIM_FRAMEEND ";
00402 sText += (s32)pMeshAnim->GetFrameEnd();
00403 sText += "\r\n";
00404 File.WriteText( sText );
00405
00406 sText = " MESHANIM_MESHFRAMESTART ";
00407 sText += (s32)pMeshAnim->GetMeshFrameStart();
00408 sText += "\r\n";
00409 File.WriteText( sText );
00410
00411 sText = " MESHANIM_MESHFRAMEEND ";
00412 sText += (s32)pMeshAnim->GetMeshFrameEnd();
00413 sText += "\r\n";
00414 File.WriteText( sText );
00415
00416 File.WriteText( KStr( " }\r\n\r\n" ) );
00417 }
00418 File.WriteText( KStr( "}\r\n\r\n" ) );
00419 }
00420
00421 File.Close();
00422
00423 return true;
00424 }
00425
00426
00427 u32 KMdlLoader::AddMesh( KMdlMesh* pMesh )
00428 {
00429 m_Meshes.Add( pMesh );
00430 return m_Meshes.GetSize() - 1;
00431 }
00432
00433
00434 u32 KMdlLoader::AddAnim( KMdlAnim* pAnim )
00435 {
00436 m_Anims.Add( pAnim );
00437 return m_Anims.GetSize() - 1;
00438 }
00439
00440
00441 u32 KMdlLoader::AddShader( char* pShaderName )
00442 {
00443 m_Shaders.Add( strdup( pShaderName ) );
00444 return m_Shaders.GetSize() - 1;
00445 }
00446
00447
00448 u32 KMdlLoader::RemoveAnim( KMdlAnim* pAnim )
00449 {
00450 for( u32 i = 0; i < m_Anims.GetSize(); i++ )
00451 {
00452 if( m_Anims[i] == pAnim )
00453 {
00454 m_Anims.Erase( i );
00455 break;
00456 }
00457 }
00458 return m_Anims.GetSize() - 1;
00459 }
00460
00461
00462 void KMdlLoader::GenerateHierarchy()
00463 {
00464
00465 FlushHierarchy();
00466
00467
00468 for( u32 m = 0; m < m_Meshes.GetSize(); m ++ )
00469 {
00470 if( m_Meshes[m]->m_FatherName.GetLength() )
00471 {
00472
00473 for( u32 f = 0; f < m_Meshes.GetSize(); f ++ )
00474 {
00475 if( m_Meshes[f]->m_Name == m_Meshes[m]->m_FatherName )
00476 {
00477 m_Meshes[f]->AddpChild( m_Meshes[m] );
00478 m_Meshes[m]->m_pFather = m_Meshes[f];
00479 break;
00480 }
00481 }
00482 }
00483 }
00484 }
00485
00486
00487 void KMdlLoader::FlushHierarchy()
00488 {
00489 for( u32 m = 0; m < m_Meshes.GetSize(); m ++ )
00490 {
00491 m_Meshes[m]->m_pFather = NULL;
00492 m_Meshes[m]->ClearChilds();
00493 }
00494 }
00495
00496
00497 void KMdlLoader::GenerateBones()
00498 {
00499
00500 for( u32 m = 0; m < m_Meshes.GetSize(); m ++ )
00501 {
00502 KMdlMesh* pMesh = m_Meshes[m];
00503
00504 for( u32 b = 0; b < pMesh->GetnBones(); b ++ )
00505 {
00506 KMdlBone* pBone = pMesh->GetpBone( b );
00507
00508
00509 for(u32 bm = 0; bm < m_Meshes.GetSize(); bm ++ )
00510 {
00511 if( m_Meshes[bm]->m_Name == pBone->m_Name )
00512 {
00513 pBone->m_pBone = m_Meshes[bm];
00514 break;
00515 }
00516 }
00517 }
00518 }
00519 }
00520
00521
00522 void KMdlLoader::ComputeFirstWorldMatrix()
00523 {
00524
00525 KMdlMesh* pMesh;
00526 KMatrix CurrentMatrix;
00527
00528 CurrentMatrix.LoadIdentity();
00529
00530
00531 for( u32 MeshId = 0; MeshId < m_Meshes.GetSize(); MeshId ++ )
00532 {
00533 pMesh = m_Meshes[MeshId];
00534 if( !pMesh->m_pFather )
00535 {
00536 ComputeFirstMeshWorldMatrix( pMesh, CurrentMatrix );
00537 }
00538 }
00539 }
00540
00541
00542 void KMdlLoader::ComputeFirstMeshWorldMatrix( KMdlMesh* pMesh, KMatrix CurrentMatrix )
00543 {
00544 KMdlFrameMatrix* pFrameMatrix = pMesh->GetFrameMatrix( 0 );
00545
00546 KASSERT( pFrameMatrix );
00547
00548 KMatrix WorldMatrix = pFrameMatrix->m_Matrix * CurrentMatrix;
00549
00550 pMesh->m_FirstWorldMatrix = WorldMatrix;
00551
00552 KMdlMesh* pChild;
00553 for( pChild = pMesh->GetpFirstChild(); pChild; pChild = pMesh->GetpNextChild( pChild ) )
00554 {
00555 ComputeFirstMeshWorldMatrix( pChild, WorldMatrix );
00556 }
00557 }
00558
00559
00560 void KMdlLoader::ComputeWorldMatrix()
00561 {
00562
00563 KMdlMesh* pMesh;
00564 KMatrix CurrentMatrix;
00565
00566 CurrentMatrix.LoadIdentity();
00567
00568
00569 for( u32 MeshId = 0; MeshId < m_Meshes.GetSize(); MeshId ++ )
00570 {
00571 pMesh = m_Meshes[MeshId];
00572 if( !pMesh->m_pFather )
00573 {
00574 ComputeMeshWorldMatrix( pMesh, CurrentMatrix );
00575 }
00576 }
00577 }
00578
00579
00580 void KMdlLoader::ComputeMeshWorldMatrix( KMdlMesh* pMesh, KMatrix CurrentMatrix )
00581 {
00582 KMdlFrameMatrix* pFrameMatrix = pMesh->GetFrameMatrix( pMesh->m_CurrentFrame );
00583
00584 KASSERT( pFrameMatrix );
00585
00586 KMatrix WorldMatrix = pFrameMatrix->m_Matrix * CurrentMatrix;
00587
00588
00589 pMesh->m_CurrentWorldMatrix = WorldMatrix;
00590
00591
00592 KMatrix FirstPostureMat = pMesh->m_FirstWorldMatrix;
00593 FirstPostureMat.Inverse();
00594 pMesh->m_BlendMatrix = FirstPostureMat * pMesh->m_CurrentWorldMatrix;
00595
00596 KMdlMesh* pChild;
00597 for( pChild = pMesh->GetpFirstChild(); pChild; pChild = pMesh->GetpNextChild( pChild ) )
00598 {
00599 ComputeMeshWorldMatrix( pChild, WorldMatrix );
00600 }
00601 }
00602
00603
00604 KMdlMesh* KMdlLoader::GetpMeshByName( KStr MeshName )
00605 {
00606 for( u32 m = 0; m < m_Meshes.GetSize(); m ++ )
00607 {
00608 if( m_Meshes[m]->m_Name == MeshName )
00609 return m_Meshes[m];
00610 }
00611 return NULL;
00612 }
00613