D:/Zythum/DinoKod/Model/MdlLoader.cpp

00001 //---------------------------------------------------------------------------------------------
00002 //      This file is a part of "DinoKod".
00003 //      Copyright © 2003 Dino Productions. All Rights Reserved.
00004 //      
00005 //      File                    : MdlLoader.cpp
00006 //      Author                  : Sebastien LEIX        sebastien.leix@wanadoo.fr
00007 //      Date                    : 09/09/2002
00008 //      Modification    :
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;     // 1.04
00024 u32 KMdlLoader::m_ANMVersion = 100;     // 1.00
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         // Flush shaders & meshes
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         // Ouvre le fichier
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         // Header
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         // Version
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         // Shader
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         // Anim intervalle
00113         File >> m_StartFrame >> m_EndFrame;
00114 
00115         // Meshes
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         // Hierarchy
00131         GenerateHierarchy();
00132         
00133         // Bones
00134         GenerateBones();
00135 
00136         // World matrices
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         // Flush les anims
00154         for( u32 a = 0; a < m_Anims.GetSize(); a ++ )
00155                 Deletep( m_Anims[a] );
00156         m_Anims.Clear();
00157 
00158         // Parse le fichier
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         // Header
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         // Version
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         // Anims
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                         // ANIM_NAME
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                         // FRAME_COUNT
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                         // FPS
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                                 // MESHANIM_NAME
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                                 // MESHANIM_INHERITFRAME
00245                                 FINDTOKEN;
00246                                 TEST_TOKEN_THROW( "MESHANIM_INHERITFRAME" );
00247                                 FINDTOKEN;
00248                                 pMeshAnim->SetInheritFrame( atoi( TOKEN ) ? true : false );
00249 
00250                                 // MESHANIM_FRAMESTART
00251                                 FINDTOKEN;
00252                                 TEST_TOKEN_THROW( "MESHANIM_FRAMESTART" );
00253                                 FINDTOKEN;
00254                                 pMeshAnim->SetFrameStart( atoi( TOKEN ) );
00255 
00256                                 // MESHANIM_FRAMEEND
00257                                 FINDTOKEN;
00258                                 TEST_TOKEN_THROW( "MESHANIM_FRAMEEND" );
00259                                 FINDTOKEN;
00260                                 pMeshAnim->SetFrameEnd( atoi( TOKEN ) );
00261 
00262                                 // MESHANIM_MESHFRAMESTART
00263                                 FINDTOKEN;
00264                                 TEST_TOKEN_THROW( "MESHANIM_MESHFRAMESTART" );
00265                                 FINDTOKEN;
00266                                 pMeshAnim->SetMeshFrameStart( atoi( TOKEN ) );
00267 
00268                                 // MESHANIM_MESHFRAMEEND
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         // Header
00304         File << HEADER_MDLMAGIC;
00305         // Version
00306         File << m_MDLVersion;
00307         
00308         // Shader
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         // Anim intervalle
00322         File << m_StartFrame << m_EndFrame;
00323 
00324         // Meshes
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         // MAGIC
00347         sText = "// Magic\r\n";
00348         sText += HEADER_ANMMAGIC;
00349         sText += "\r\n";
00350         File.WriteText( sText );
00351 
00352         // VERSION
00353         sText = "// File version\r\n";
00354         sText += (s32)KMdlLoader::m_ANMVersion;
00355         sText += "\r\n\r\n";
00356         File.WriteText( sText );
00357 
00358         // ANIM
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                 // MESHANIM
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         // Flush
00465         FlushHierarchy();
00466 
00467         // Generation de la hierarchie
00468         for( u32 m = 0; m < m_Meshes.GetSize(); m ++ )
00469         {
00470                 if( m_Meshes[m]->m_FatherName.GetLength() )
00471                 {
00472                         // Recherche le pere
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         // Associe les KMdlBones au KMdlMesh de bone correspondant
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                         // Recherche le KMdlMesh qui correspond au bone
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         // Calcule la matrice monde de chaque mesh pour la 1ere frame
00525         KMdlMesh*               pMesh;
00526         KMatrix                 CurrentMatrix;
00527 
00528         CurrentMatrix.LoadIdentity();
00529 
00530         // Affiche les meshes
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         // Calcule la matrice monde de chaque mesh pour la frame courante
00563         KMdlMesh*               pMesh;
00564         KMatrix                 CurrentMatrix;
00565 
00566         CurrentMatrix.LoadIdentity();
00567 
00568         // Affiche les meshes
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         // World Matrix
00589         pMesh->m_CurrentWorldMatrix = WorldMatrix;
00590 
00591         // Blend Matrix
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 

Generated on Sun Mar 25 20:02:15 2007 for Zythum Project by  doxygen 1.5.1-p1