Changeset 472 for cafu/trunk

Show
Ignore:
Timestamp:
01/27/12 15:01:08 (4 months ago)
Author:
Carsten
Message:

Model Editor: Add ability to import animation sequences into existing model files.

This feature is, at the moment, implemented for md5anim files only.

References #80.

Location:
cafu/trunk
Files:
11 modified

Legend:

Unmodified
Added
Removed
  • cafu/trunk/CaWE/ModelEditor/ChildFrame.cpp

    r455 r472  
    4141 
    4242#include "MaterialSystem/Material.hpp" 
     43#include "Models/Loader_md5.hpp" 
    4344#include "Models/Model_cmdl.hpp" 
    4445 
     
    172173    ModelMenu->Append(ID_MENU_MODEL_SKIN_ADD, "Add skin", "Adds a new skin to the model"); 
    173174    ModelMenu->Append(ID_MENU_MODEL_GUIFIXTURE_ADD, "Add GUI fixture", "Adds a new GUI fixture to the model"); 
     175    ModelMenu->Append(ID_MENU_MODEL_ANIM_IMPORT, "Import anim sequences", "Imports additional animation sequences into the model"); 
    174176    ModelMenu->Append(ID_MENU_MODEL_CHANNEL_ADD, "Add channel", "Adds a new animation channel to the model"); 
    175177    ModelMenu->Append(-1, "Run benchmark", "Move the camera along a predefined path and determine the time taken")->Enable(false); 
     
    314316 // AnimToolbar->AddTool(ID_MENU_MODEL_SKIN_ADD,       "Add skin",        wxArtProvider::GetBitmap("window-new", wxART_TOOLBAR), "Add skin"); 
    315317    AnimToolbar->AddTool(ID_MENU_MODEL_GUIFIXTURE_ADD, "Add GUI fixture", wxArtProvider::GetBitmap("window-new", wxART_TOOLBAR), "Add GUI fixture"); 
     318 // AnimToolbar->AddTool(ID_MENU_MODEL_ANIM_IMPORT,    "Import anim",     wxArtProvider::GetBitmap("window-new", wxART_TOOLBAR), "Import anim"); 
    316319 // AnimToolbar->AddTool(ID_MENU_MODEL_CHANNEL_ADD,    "Add channel",     wxArtProvider::GetBitmap("window-new", wxART_TOOLBAR), "Add channel"); 
    317320    AnimToolbar->Realize(); 
     
    380383 
    381384    return SubmitCommand(new CommandAddT(m_ModelDoc, GuiFixtures)); 
     385} 
     386 
     387 
     388bool ModelEditor::ChildFrameT::SubmitImportAnims() 
     389{ 
     390    wxFileDialog FileDialog(this,                           // The window parent. 
     391                            "Import animation sequence",    // Message. 
     392                            "",                             // The default directory. 
     393                            "*.md5anim",                    // The default file name. 
     394                            "All files (*.*)|*.*"           // The wildcard. 
     395                            "|md5anim files|*.md5anim", 
     396                            wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE); 
     397 
     398    if (FileDialog.ShowModal()!=wxID_OK) 
     399        return false; 
     400 
     401    wxArrayString     Paths; 
     402    ArrayT<CommandT*> SubCommands; 
     403    wxString          Errors; 
     404 
     405    FileDialog.GetPaths(Paths); 
     406 
     407    for (size_t PathNr=0; PathNr<Paths.GetCount(); PathNr++) 
     408    { 
     409        try 
     410        { 
     411            ImporterMd5AnimT          Importer(Paths[PathNr].ToStdString()); 
     412            ArrayT<CafuModelT::AnimT> Anims=Importer.Import(m_ModelDoc->GetModel()->GetJoints(), m_ModelDoc->GetModel()->GetMeshes()); 
     413 
     414            SubCommands.PushBack(new CommandAddT(m_ModelDoc, Anims)); 
     415        } 
     416        catch (const ModelLoaderT::LoadErrorT& LE) 
     417        { 
     418            Errors += "\n" + Paths[PathNr] + "\n" + LE.what() + "\n"; 
     419        } 
     420    } 
     421 
     422    if (Errors!="") 
     423    { 
     424        wxMessageBox(Errors, "Couldn't import animation sequences"); 
     425    } 
     426 
     427    if (SubCommands.Size()==1) 
     428    { 
     429        return SubmitCommand(SubCommands[0]); 
     430    } 
     431    else if (SubCommands.Size()>1) 
     432    { 
     433        return SubmitCommand(new CommandMacroT(SubCommands, "Import anim sequences")); 
     434    } 
     435 
     436    return false; 
    382437} 
    383438 
     
    922977        } 
    923978 
     979        case ID_MENU_MODEL_ANIM_IMPORT: 
     980        { 
     981            SubmitImportAnims(); 
     982            break; 
     983        } 
     984 
    924985        case ID_MENU_MODEL_CHANNEL_ADD: 
    925986        { 
  • cafu/trunk/CaWE/ModelEditor/ChildFrame.hpp

    r457 r472  
    7272        /// Creates a new GUI fixture, calls SubmitCommand() accordingly and returns its result. 
    7373        bool SubmitNewGuiFixture(); 
     74 
     75        /// Imports animation sequences from a user selected file, calls SubmitCommand() accordingly and returns its result. 
     76        bool SubmitImportAnims(); 
    7477 
    7578        /// Creates a new animation channel, calls SubmitCommand() accordingly and returns its result. 
     
    171174            ID_MENU_MODEL_SKIN_ADD, 
    172175            ID_MENU_MODEL_GUIFIXTURE_ADD, 
     176            ID_MENU_MODEL_ANIM_IMPORT, 
    173177            ID_MENU_MODEL_CHANNEL_ADD, 
    174178            ID_MENU_MODEL_LOAD_SUBMODEL, 
  • cafu/trunk/CaWE/ModelEditor/Commands/Add.cpp

    r455 r472  
    4747 
    4848 
     49CommandAddT::CommandAddT(ModelDocumentT* ModelDoc, const ArrayT<CafuModelT::AnimT>& Anims) 
     50    : m_ModelDoc(ModelDoc), 
     51      m_Type(ANIM), 
     52      m_Anims(Anims) 
     53{ 
     54} 
     55 
     56 
    4957CommandAddT::CommandAddT(ModelDocumentT* ModelDoc, const CafuModelT::ChannelT& Channel) 
    5058    : m_ModelDoc(ModelDoc), 
     
    9098            break; 
    9199 
     100        case ANIM: 
     101            for (unsigned long AnimNr=0; AnimNr<m_Anims.Size(); AnimNr++) 
     102            { 
     103                Indices.PushBack(m_ModelDoc->GetModel()->m_Anims.Size()); 
     104                m_ModelDoc->GetModel()->m_Anims.PushBack(m_Anims[AnimNr]); 
     105            } 
     106            break; 
     107 
    92108        case CHAN: 
    93109            for (unsigned long ChannelNr=0; ChannelNr<m_Channels.Size(); ChannelNr++) 
     
    96112                m_ModelDoc->GetModel()->m_Channels.PushBack(m_Channels[ChannelNr]); 
    97113            } 
    98             break; 
    99  
    100         default: 
    101114            break; 
    102115    } 
     
    146159            break; 
    147160 
     161        case ANIM: 
     162            for (unsigned long AnimNr=0; AnimNr<m_Anims.Size(); AnimNr++) 
     163            { 
     164                m_ModelDoc->GetModel()->m_Anims.DeleteBack(); 
     165                Indices.InsertAt(0, m_ModelDoc->GetModel()->m_Anims.Size()); 
     166            } 
     167            break; 
     168 
    148169        case CHAN: 
    149170            for (unsigned long ChannelNr=0; ChannelNr<m_Channels.Size(); ChannelNr++) 
     
    152173                Indices.InsertAt(0, m_ModelDoc->GetModel()->m_Channels.Size()); 
    153174            } 
    154             break; 
    155  
    156         default: 
    157175            break; 
    158176    } 
     
    175193        case JOINT: break; 
    176194        case MESH:  break; 
    177         case ANIM:  break; 
    178195 
    179196        case SKIN: 
     
    191208        } 
    192209 
     210        case ANIM: 
     211        { 
     212            Name=(m_Anims.Size()==1) ? wxString("Add anim sequence") : wxString::Format("Add %lu anim sequences", m_Anims.Size()); 
     213            break; 
     214        } 
     215 
    193216        case CHAN: 
    194217        { 
  • cafu/trunk/CaWE/ModelEditor/Commands/Add.hpp

    r457 r472  
    4040        CommandAddT(ModelDocumentT* ModelDoc, const CafuModelT::SkinT& Skin); 
    4141        CommandAddT(ModelDocumentT* ModelDoc, const ArrayT<CafuModelT::GuiFixtureT>& GuiFixtures); 
     42        CommandAddT(ModelDocumentT* ModelDoc, const ArrayT<CafuModelT::AnimT>& Anims); 
    4243        CommandAddT(ModelDocumentT* ModelDoc, const CafuModelT::ChannelT& Channel); 
    4344 
     
    5253        ModelDocumentT*                 m_ModelDoc; 
    5354        const ModelElementTypeT         m_Type; 
    54      // ArrayT<CafuModelT::JointT>      m_Joints;       ///< The added joints (if m_Type==JOINT). 
    55      // ArrayT<CafuModelT::MeshT>       m_Meshes;       ///< The added meshes (if m_Type==MESH). 
     55     // ArrayT<CafuModelT::JointT>      m_Joints;       ///< The added joints       (if m_Type==JOINT). 
     56     // ArrayT<CafuModelT::MeshT>       m_Meshes;       ///< The added meshes       (if m_Type==MESH). 
    5657     // ArrayT<MatSys::MeshT>           m_DrawMs;       ///< The draw meshes related to m_Meshes. 
    57         ArrayT<CafuModelT::SkinT>       m_Skins;        ///< The added skins (if m_Type==SKIN). 
     58        ArrayT<CafuModelT::SkinT>       m_Skins;        ///< The added skins        (if m_Type==SKIN). 
    5859        ArrayT<CafuModelT::GuiFixtureT> m_GuiFixtures;  ///< The added GUI fixtures (if m_Type==GFIX). 
    59      // ArrayT<CafuModelT::AnimT>       m_Anims;        ///< The added anims (if m_Type==ANIM). 
    60         ArrayT<CafuModelT::ChannelT>    m_Channels;     ///< The added channels (if m_Type==CHAN). 
     60        ArrayT<CafuModelT::AnimT>       m_Anims;        ///< The added anims        (if m_Type==ANIM). 
     61        ArrayT<CafuModelT::ChannelT>    m_Channels;     ///< The added channels     (if m_Type==CHAN). 
    6162    }; 
    6263} 
  • cafu/trunk/CaWE/ModelEditor/ElementsList.cpp

    r455 r472  
    305305    Menu.Append(ID_MENU_RENAME, "Rename\tF2"); 
    306306    if (m_TYPE==GFIX || m_TYPE==SKIN || m_TYPE==CHAN) Menu.Append(ID_MENU_ADD_NEW, "Add/create new"); 
     307    if (m_TYPE==ANIM) Menu.Append(ID_MENU_ADD_NEW, "Import more..."); 
    307308 
    308309    if (m_TYPE==MESH) 
     
    336337                case SKIN: m_MainFrame->SubmitNewSkin();       break; 
    337338                case GFIX: m_MainFrame->SubmitNewGuiFixture(); break; 
     339                case ANIM: m_MainFrame->SubmitImportAnims();   break; 
    338340                case CHAN: m_MainFrame->SubmitNewChannel();    break; 
    339341                default: break; 
     
    493495                case SKIN: m_MainFrame->SubmitNewSkin();       break; 
    494496                case GFIX: m_MainFrame->SubmitNewGuiFixture(); break; 
     497                case ANIM: m_MainFrame->SubmitImportAnims();   break; 
    495498                case CHAN: m_MainFrame->SubmitNewChannel();    break; 
    496499                default: break; 
     
    518521        case ID_BUTTON_ADD: 
    519522        { 
    520             UE.Enable(m_TYPE==SKIN || m_TYPE==GFIX || m_TYPE==CHAN); 
     523            UE.Enable(m_TYPE==SKIN || m_TYPE==GFIX || m_TYPE==ANIM || m_TYPE==CHAN); 
    521524            break; 
    522525        } 
  • cafu/trunk/Libs/Models/Loader.cpp

    r455 r472  
    159159    return Mat; 
    160160} 
     161 
     162 
     163AnimImporterT::AnimImporterT(const std::string& FileName) 
     164    : m_FileName(FileName) 
     165{ 
     166} 
  • cafu/trunk/Libs/Models/Loader.hpp

    r457 r472  
    129129}; 
    130130 
     131 
     132/// The base class for importing additional animations into an existing CafuModelT. 
     133class AnimImporterT 
     134{ 
     135    public: 
     136 
     137    /// The constructor. 
     138    AnimImporterT(const std::string& FileName); 
     139 
     140    /// Returns the name of the file the animations are imported from. 
     141    virtual const std::string& GetFileName() const { return m_FileName; } 
     142 
     143    /// Imports and returns the animation sequences from the file, optionally referring to the joints and meshes of the related model. 
     144    /// It is up to the caller to actually add the imported sequences to the related model instance. 
     145    virtual ArrayT<CafuModelT::AnimT> Import(const ArrayT<CafuModelT::JointT>& Joints, const ArrayT<CafuModelT::MeshT>& Meshes)=0; 
     146 
     147 
     148    protected: 
     149 
     150    const std::string m_FileName; 
     151}; 
     152 
    131153#endif 
  • cafu/trunk/Libs/Models/Loader_md5.cpp

    r455 r472  
    229229    for (unsigned long FileNr=1; FileNr<ComponentFiles.Size(); FileNr++) 
    230230    { 
    231         TextParserT TP(ComponentFiles[FileNr].c_str()); 
    232  
    233231        try 
    234232        { 
    235             CafuModelT::AnimT Anim; 
    236  
    237             Anim.Name="Anim"; 
    238             Anim.FPS =24.0f; 
    239             Anim.Next=-1; 
    240  
    241             while (!TP.IsAtEOF()) 
    242             { 
    243                 const std::string Token=TP.GetNextToken(); 
    244  
    245                      if (Token=="MD5Version" ) { if (TP.GetNextToken()!="10") throw LoadErrorT("MD5Version is not 10."); } 
    246                 else if (Token=="commandline") TP.GetNextToken();       // Ignore the command line. 
    247                 else if (Token=="frameRate"  ) Anim.FPS=TP.GetNextTokenAsFloat(); 
    248                 else if (Token=="numFrames"  ) 
    249                 { 
    250                     // Be stricter with numFrames than with some num* variables in the md5mesh file. 
    251                     // This is required because for example there must be as many bounding boxes as frames. 
    252                     if (Anim.Frames.Size()>0) throw LoadErrorT("Anim.Frames.Size() > 0"); 
    253  
    254                     Anim.Frames.PushBackEmpty(TP.GetNextTokenAsInt()); 
    255                 } 
    256                 else if (Token=="numJoints") 
    257                 { 
    258                     // The numJoints here MUST match the numJoints in the md5mesh file! 
    259                     const unsigned long numJoints=TP.GetNextTokenAsInt(); 
    260  
    261                     if (numJoints!=Joints.Size()) { printf("%lu joints in md5anim file, %lu joints in md5mesh.\n", numJoints, Joints.Size()); throw LoadErrorT("Number of joints in the md5anim file does not match number of bones in the md5mesh."); } 
    262                     if (Anim.AnimJoints.Size()>0) { printf("Anim.AnimJoints.Size()==%lu\n", Anim.AnimJoints.Size()); throw LoadErrorT("Anim.AnimJoints.Size() > 0"); } 
    263  
    264                     Anim.AnimJoints.PushBackEmpty(numJoints); 
    265                 } 
    266                 else if (Token=="numAnimatedComponents") 
    267                 { 
    268                     const unsigned long numAnimatedComponents=TP.GetNextTokenAsInt(); 
    269  
    270                     // This is the number of components that is animated in the frames (and thus so many values are stored with each frame). 
    271                     // Therefore, the number of frames must have been specified already, so we can allocate all the memory here. 
    272                     if (Anim.Frames.Size()==0) throw LoadErrorT("Anim.Frames.Size() == 0"); 
    273  
    274                     for (unsigned long FrameNr=0; FrameNr<Anim.Frames.Size(); FrameNr++) 
    275                         Anim.Frames[FrameNr].AnimData.PushBackEmpty(numAnimatedComponents); 
    276                 } 
    277                 else if (Token=="hierarchy") 
    278                 { 
    279                     TP.AssertAndSkipToken("{"); 
    280  
    281                     for (unsigned long JointNr=0; JointNr<Anim.AnimJoints.Size(); JointNr++) 
    282                     { 
    283                         // Make sure that the name and parent are identical with the joint from the md5mesh file. 
    284                         if (Joints[JointNr].Name  !=TP.GetNextToken()) throw LoadErrorT("Mismatching joint name."); 
    285                         if (Joints[JointNr].Parent!=TP.GetNextTokenAsInt()) throw LoadErrorT("Mismatching joint parent."); 
    286  
    287                         Anim.AnimJoints[JointNr].Flags       =TP.GetNextTokenAsInt(); 
    288                         Anim.AnimJoints[JointNr].FirstDataIdx=TP.GetNextTokenAsInt(); 
    289                     } 
    290  
    291                     TP.AssertAndSkipToken("}"); 
    292                 } 
    293                 else if (Token=="bounds") 
    294                 { 
    295                     TP.AssertAndSkipToken("{"); 
    296  
    297                     for (unsigned long FrameNr=0; FrameNr<Anim.Frames.Size(); FrameNr++) 
    298                     { 
    299                         TP.AssertAndSkipToken("("); 
    300                         Anim.Frames[FrameNr].BB.Min.x=TP.GetNextTokenAsFloat(); 
    301                         Anim.Frames[FrameNr].BB.Min.y=TP.GetNextTokenAsFloat(); 
    302                         Anim.Frames[FrameNr].BB.Min.z=TP.GetNextTokenAsFloat(); 
    303                         TP.AssertAndSkipToken(")"); 
    304                         TP.AssertAndSkipToken("("); 
    305                         Anim.Frames[FrameNr].BB.Max.x=TP.GetNextTokenAsFloat(); 
    306                         Anim.Frames[FrameNr].BB.Max.y=TP.GetNextTokenAsFloat(); 
    307                         Anim.Frames[FrameNr].BB.Max.z=TP.GetNextTokenAsFloat(); 
    308                         TP.AssertAndSkipToken(")"); 
    309                     } 
    310  
    311                     TP.AssertAndSkipToken("}"); 
    312                 } 
    313                 else if (Token=="baseframe") 
    314                 { 
    315                     TP.AssertAndSkipToken("{"); 
    316  
    317                     for (unsigned long JointNr=0; JointNr<Anim.AnimJoints.Size(); JointNr++) 
    318                     { 
    319                         TP.AssertAndSkipToken("("); 
    320                         Anim.AnimJoints[JointNr].DefaultPos.x=TP.GetNextTokenAsFloat(); 
    321                         Anim.AnimJoints[JointNr].DefaultPos.y=TP.GetNextTokenAsFloat(); 
    322                         Anim.AnimJoints[JointNr].DefaultPos.z=TP.GetNextTokenAsFloat(); 
    323                         TP.AssertAndSkipToken(")"); 
    324                         TP.AssertAndSkipToken("("); 
    325                         Anim.AnimJoints[JointNr].DefaultQtr.x=TP.GetNextTokenAsFloat(); 
    326                         Anim.AnimJoints[JointNr].DefaultQtr.y=TP.GetNextTokenAsFloat(); 
    327                         Anim.AnimJoints[JointNr].DefaultQtr.z=TP.GetNextTokenAsFloat(); 
    328                         TP.AssertAndSkipToken(")"); 
    329                         Anim.AnimJoints[JointNr].DefaultScale=Vector3fT(1.0f, 1.0f, 1.0f); 
    330                     } 
    331  
    332                     TP.AssertAndSkipToken("}"); 
    333                 } 
    334                 else if (Token=="frame") 
    335                 { 
    336                     const unsigned long FrameNr=TP.GetNextTokenAsInt(); 
    337  
    338                     TP.AssertAndSkipToken("{"); 
    339  
    340                     for (unsigned long ComponentNr=0; ComponentNr<Anim.Frames[FrameNr].AnimData.Size(); ComponentNr++) 
    341                         Anim.Frames[FrameNr].AnimData[ComponentNr]=TP.GetNextTokenAsFloat(); 
    342  
    343                     TP.AssertAndSkipToken("}"); 
    344                 } 
    345                 else 
    346                 { 
    347                     // Unknown token! 
    348                     // If the next token is a block start, skip the block. 
    349                     // Otherwise it was something else that we just throw away. 
    350                     printf("Unknown token \"%s\", skipping...\n", Token.c_str()); 
    351                     if (TP.GetNextToken()=="{") TP.SkipBlock("{", "}", true); 
    352                 } 
    353             } 
    354  
    355             Anims.PushBack(Anim); 
    356         } 
    357         catch (const TextParserT::ParseError&) 
    358         { 
    359             // Loading this animation sequence failed, but as the base mesh (the md5mesh file) 
    360             // loaded properly, that is not reason enough to abort loading the entire model. 
    361             CafuModelT::AnimT InvalidAnim; 
    362  
    363             InvalidAnim.FPS=-1.0f;          // Use a negative FPS to flags this animation as invalid. 
    364             Anims.PushBack(InvalidAnim);    // Note that InvalidAnim.Frames.Size()==0, too. 
    365  
    366             printf("WARNING: Loading animation sequence file %s failed just before input byte %lu!\n", ComponentFiles[FileNr].c_str(), TP.GetReadPosByte()); 
     233            ImporterMd5AnimT Importer(ComponentFiles[FileNr]); 
     234 
     235            Anims.PushBack(Importer.Import(Joints, Meshes)); 
    367236        } 
    368237        catch (const LoadErrorT& LE) 
     
    372241            CafuModelT::AnimT InvalidAnim; 
    373242 
    374             InvalidAnim.FPS=-1.0f;          // Use a negative FPS to flags this animation as invalid. 
     243            InvalidAnim.FPS=-1.0f;          // Use a negative FPS to flag this animation as invalid. 
    375244            Anims.PushBack(InvalidAnim);    // Note that InvalidAnim.Frames.Size()==0, too. 
    376245 
    377             printf("WARNING: Loading animation sequence file %s failed just before input byte %lu:\n", ComponentFiles[FileNr].c_str(), TP.GetReadPosByte()); 
    378             printf("%s", LE.what()); 
     246            printf("WARNING: Loading animation sequence file %s failed:\n", ComponentFiles[FileNr].c_str()); 
     247            printf("%s\n", LE.what()); 
    379248        } 
    380249    } 
    381250} 
     251 
     252 
     253ImporterMd5AnimT::ImporterMd5AnimT(const std::string& FileName) 
     254    : AnimImporterT(FileName) 
     255{ 
     256} 
     257 
     258 
     259ArrayT<CafuModelT::AnimT> ImporterMd5AnimT::Import(const ArrayT<CafuModelT::JointT>& Joints, const ArrayT<CafuModelT::MeshT>& Meshes) 
     260{ 
     261    TextParserT TP(m_FileName.c_str()); 
     262 
     263    try 
     264    { 
     265        CafuModelT::AnimT Anim; 
     266 
     267        Anim.Name="Anim"; 
     268        Anim.FPS =24.0f; 
     269        Anim.Next=-1; 
     270 
     271        bool GotHierarchy=false; 
     272        bool GotBounds   =false; 
     273        bool GotBaseframe=false; 
     274        ArrayT<bool> GotFrames; 
     275 
     276        while (!TP.IsAtEOF()) 
     277        { 
     278            const std::string Token=TP.GetNextToken(); 
     279 
     280                 if (Token=="MD5Version" ) { if (TP.GetNextToken()!="10") throw ModelLoaderT::LoadErrorT("MD5Version is not 10."); } 
     281            else if (Token=="commandline") TP.GetNextToken();       // Ignore the command line. 
     282            else if (Token=="frameRate"  ) Anim.FPS=TP.GetNextTokenAsFloat(); 
     283            else if (Token=="numFrames"  ) 
     284            { 
     285                // Be stricter with numFrames than with some num* variables in the md5mesh file. 
     286                // This is required because for example there must be as many bounding boxes as frames. 
     287                if (Anim.Frames.Size()>0) throw ModelLoaderT::LoadErrorT("Anim.Frames.Size() > 0"); 
     288 
     289                Anim.Frames.PushBackEmpty(TP.GetNextTokenAsInt()); 
     290 
     291                for (unsigned long FrameNr=0; FrameNr<Anim.Frames.Size(); FrameNr++) 
     292                    GotFrames.PushBack(false); 
     293            } 
     294            else if (Token=="numJoints") 
     295            { 
     296                // The numJoints here MUST match the numJoints in the md5mesh file! 
     297                const unsigned long numJoints=TP.GetNextTokenAsInt(); 
     298 
     299                if (numJoints!=Joints.Size()) { printf("%lu joints in md5anim file, %lu joints in the model.\n", numJoints, Joints.Size()); throw ModelLoaderT::LoadErrorT("The number of joints in the md5anim file does not match number of bones in the model."); } 
     300                if (Anim.AnimJoints.Size()>0) { printf("Anim.AnimJoints.Size()==%lu\n", Anim.AnimJoints.Size()); throw ModelLoaderT::LoadErrorT("Anim.AnimJoints.Size() > 0"); } 
     301 
     302                Anim.AnimJoints.PushBackEmpty(numJoints); 
     303            } 
     304            else if (Token=="numAnimatedComponents") 
     305            { 
     306                const unsigned long numAnimatedComponents=TP.GetNextTokenAsInt(); 
     307 
     308                // This is the number of components that is animated in the frames (and thus so many values are stored with each frame). 
     309                // Therefore, the number of frames must have been specified already, so we can allocate all the memory here. 
     310                if (Anim.Frames.Size()==0) throw ModelLoaderT::LoadErrorT("Anim.Frames.Size() == 0"); 
     311 
     312                for (unsigned long FrameNr=0; FrameNr<Anim.Frames.Size(); FrameNr++) 
     313                    Anim.Frames[FrameNr].AnimData.PushBackEmpty(numAnimatedComponents); 
     314            } 
     315            else if (Token=="hierarchy") 
     316            { 
     317                TP.AssertAndSkipToken("{"); 
     318 
     319                for (unsigned long JointNr=0; JointNr<Anim.AnimJoints.Size(); JointNr++) 
     320                { 
     321                    // Make sure that the name and parent are identical with the joint from the md5mesh file. 
     322                    if (Joints[JointNr].Name  !=TP.GetNextToken()) throw ModelLoaderT::LoadErrorT("Mismatching joint name."); 
     323                    if (Joints[JointNr].Parent!=TP.GetNextTokenAsInt()) throw ModelLoaderT::LoadErrorT("Mismatching joint parent."); 
     324 
     325                    Anim.AnimJoints[JointNr].Flags       =TP.GetNextTokenAsInt(); 
     326                    Anim.AnimJoints[JointNr].FirstDataIdx=TP.GetNextTokenAsInt(); 
     327                } 
     328 
     329                TP.AssertAndSkipToken("}"); 
     330                GotHierarchy=true; 
     331            } 
     332            else if (Token=="bounds") 
     333            { 
     334                TP.AssertAndSkipToken("{"); 
     335 
     336                for (unsigned long FrameNr=0; FrameNr<Anim.Frames.Size(); FrameNr++) 
     337                { 
     338                    TP.AssertAndSkipToken("("); 
     339                    Anim.Frames[FrameNr].BB.Min.x=TP.GetNextTokenAsFloat(); 
     340                    Anim.Frames[FrameNr].BB.Min.y=TP.GetNextTokenAsFloat(); 
     341                    Anim.Frames[FrameNr].BB.Min.z=TP.GetNextTokenAsFloat(); 
     342                    TP.AssertAndSkipToken(")"); 
     343                    TP.AssertAndSkipToken("("); 
     344                    Anim.Frames[FrameNr].BB.Max.x=TP.GetNextTokenAsFloat(); 
     345                    Anim.Frames[FrameNr].BB.Max.y=TP.GetNextTokenAsFloat(); 
     346                    Anim.Frames[FrameNr].BB.Max.z=TP.GetNextTokenAsFloat(); 
     347                    TP.AssertAndSkipToken(")"); 
     348                } 
     349 
     350                TP.AssertAndSkipToken("}"); 
     351                GotBounds=true; 
     352            } 
     353            else if (Token=="baseframe") 
     354            { 
     355                TP.AssertAndSkipToken("{"); 
     356 
     357                for (unsigned long JointNr=0; JointNr<Anim.AnimJoints.Size(); JointNr++) 
     358                { 
     359                    TP.AssertAndSkipToken("("); 
     360                    Anim.AnimJoints[JointNr].DefaultPos.x=TP.GetNextTokenAsFloat(); 
     361                    Anim.AnimJoints[JointNr].DefaultPos.y=TP.GetNextTokenAsFloat(); 
     362                    Anim.AnimJoints[JointNr].DefaultPos.z=TP.GetNextTokenAsFloat(); 
     363                    TP.AssertAndSkipToken(")"); 
     364                    TP.AssertAndSkipToken("("); 
     365                    Anim.AnimJoints[JointNr].DefaultQtr.x=TP.GetNextTokenAsFloat(); 
     366                    Anim.AnimJoints[JointNr].DefaultQtr.y=TP.GetNextTokenAsFloat(); 
     367                    Anim.AnimJoints[JointNr].DefaultQtr.z=TP.GetNextTokenAsFloat(); 
     368                    TP.AssertAndSkipToken(")"); 
     369                    Anim.AnimJoints[JointNr].DefaultScale=Vector3fT(1.0f, 1.0f, 1.0f); 
     370                } 
     371 
     372                TP.AssertAndSkipToken("}"); 
     373                GotBaseframe=true; 
     374            } 
     375            else if (Token=="frame") 
     376            { 
     377                const unsigned long FrameNr=TP.GetNextTokenAsInt(); 
     378 
     379                TP.AssertAndSkipToken("{"); 
     380 
     381                for (unsigned long ComponentNr=0; ComponentNr<Anim.Frames[FrameNr].AnimData.Size(); ComponentNr++) 
     382                    Anim.Frames[FrameNr].AnimData[ComponentNr]=TP.GetNextTokenAsFloat(); 
     383 
     384                TP.AssertAndSkipToken("}"); 
     385                GotFrames[FrameNr]=true; 
     386            } 
     387            else 
     388            { 
     389                // Unknown token! 
     390                // If the next token is a block start, skip the block. 
     391                // Otherwise it was something else that we just throw away. 
     392                printf("Unknown token \"%s\", skipping...\n", Token.c_str()); 
     393                if (TP.GetNextToken()=="{") TP.SkipBlock("{", "}", true); 
     394            } 
     395        } 
     396 
     397 
     398        // Make sure that the imported animation sequence is valid. 
     399        if (Anim.AnimJoints.Size()!=Joints.Size()) throw ModelLoaderT::LoadErrorT("The number of joints in the md5anim file does not match number of bones in the model."); 
     400        if (!GotHierarchy) throw ModelLoaderT::LoadErrorT("There seems to be no joints hierarchy defined in this file."); 
     401        if (!GotBounds) throw ModelLoaderT::LoadErrorT("There seem to be no bounds in this file."); 
     402        if (!GotBaseframe) throw ModelLoaderT::LoadErrorT("There seems to be no baseframe data in this file."); 
     403        if (Anim.Frames.Size()==0) throw ModelLoaderT::LoadErrorT("The animation sequence in this file has no frames."); 
     404 
     405        for (unsigned long FrameNr=0; FrameNr<Anim.Frames.Size(); FrameNr++) 
     406            if (!GotFrames[FrameNr]) 
     407                throw ModelLoaderT::LoadErrorT("Some frames in the sequence are not defined."); 
     408 
     409 
     410        // The animation seems ok, return it. 
     411        ArrayT<CafuModelT::AnimT> Anims; 
     412        Anims.PushBack(Anim); 
     413        return Anims; 
     414    } 
     415    catch (const TextParserT::ParseError&) 
     416    { 
     417        printf("WARNING: Loading animation sequence file %s failed just before input byte %lu!\n", m_FileName.c_str(), TP.GetReadPosByte()); 
     418 
     419        throw ModelLoaderT::LoadErrorT("Could not parse the file."); 
     420    } 
     421} 
  • cafu/trunk/Libs/Models/Loader_md5.hpp

    r457 r472  
    4646}; 
    4747 
     48 
     49/// This class imports animations from Doom3 .md5anim files for addition to an existing CafuModelT. 
     50class ImporterMd5AnimT : public AnimImporterT 
     51{ 
     52    public: 
     53 
     54    ImporterMd5AnimT(const std::string& FileName); 
     55 
     56    ArrayT<CafuModelT::AnimT> Import(const ArrayT<CafuModelT::JointT>& Joints, const ArrayT<CafuModelT::MeshT>& Meshes); 
     57}; 
     58 
    4859#endif 
  • cafu/trunk/Libs/Models/Model_cmdl.cpp

    r469 r472  
    354354    for (unsigned long MeshNr=0; MeshNr<m_Meshes.Size(); MeshNr++) 
    355355        MatSys::Renderer->FreeMaterial(m_Meshes[MeshNr].RenderMaterial); 
     356} 
     357 
     358 
     359void CafuModelT::Import(AnimImporterT& Importer) 
     360{ 
     361    m_Anims.PushBack(Importer.Import(m_Joints, m_Meshes)); 
    356362} 
    357363 
  • cafu/trunk/Libs/Models/Model_cmdl.hpp

    r469 r472  
    3737 
    3838 
     39class AnimImporterT; 
    3940class MaterialT; 
    4041class ModelLoaderT; 
     
    253254    ~CafuModelT(); 
    254255 
     256    /// Imports animations into this model using the given AnimImporterT. 
     257    /// At this time, this method is actually unused, because in the Model Editor, 
     258    /// the related command is a friend and thus accesses the m_Anims member directly. 
     259    void Import(AnimImporterT& Importer); 
     260 
    255261    /// Saves the model into the given stream. 
    256262    void Save(std::ostream& OutStream) const;