Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/Tools/3dsmaxExport/LEXIExporter/LexiExport/Sources/LexiIntermediateBuilderSkeleton.cpp @ 6

Last change on this file since 6 was 6, checked in by anonymous, 17 years ago

=…

File size: 13.8 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of LEXIExporter
4
5Copyright 2006 NDS Limited
6
7Author(s):
8Mark Folkenberg
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25
26#include "LexiStdAfx.h"
27#include "LexiIntermediateAPI.h"
28
29CIntermediateBuilderSkeleton::CIntermediateBuilderSkeleton()
30{
31        //
32        m_iBoneIndex = 0;
33        m_pMaxNode = NULL;
34        m_pISkel = NULL;
35        m_pProgressDlg = NULL;
36
37}
38
39CIntermediateBuilderSkeleton::~CIntermediateBuilderSkeleton()
40{
41        //
42}
43
44bool CIntermediateBuilderSkeleton::BuildIntermediateSkeleton( INode* pMaxNode )
45{
46        m_pMaxNode = pMaxNode;
47
48        //LOGDEBUG "CIntermediate::CreateMesh() - Tjeck for skin modifier.");
49        if(FindSkinModifier( m_pMaxNode ))
50        {
51                LOGDEBUG "Creating intermediate skeleton.");
52
53                if(m_pISkel != NULL)
54                        delete m_pISkel;
55
56                m_pISkel = new CIntermediateSkeleton();
57                //pIMesh->SetSkeleton(m_pISkel); // Needed for ReIndexing!
58
59                CreateBonePool();
60                m_pISkel->PopulateBoneHandleMap();
61                AssembleBones();
62                ConnectLinkedBones();
63
64                SetBoneIndexes();
65
66                m_pISkel->BuildIndexedBoneList();
67
68                SetBindingPose(0);
69
70                //LOGDEBUG "%s", m_pISkel->ToString().c_str() );
71
72
73                return true;
74        }
75       
76        return false;
77}
78
79void CIntermediateBuilderSkeleton::Finalize( void )
80{
81        if(m_pISkel!=NULL)
82        {
83                m_pISkel->TrimVertexAssignments(4);
84                m_pISkel->NormalizeVertexAssignments();
85                m_pISkel->SetFPS( GetFrameRate() );
86        }
87}
88
89// Index the bones according to a depth first search. This way we can add them to the ogre skeleton in the right order.
90void CIntermediateBuilderSkeleton::SetBoneIndexes( void )
91{
92        std::vector< CIntermediateBone* > lRootBones = m_pISkel->GetRootBones();
93        std::vector< CIntermediateBone* >::iterator rootIter = lRootBones.begin();
94
95        while(rootIter != lRootBones.end())
96        {
97                CIntermediateBone* pCurBone = (*rootIter);
98                pCurBone->SetIndex(m_iBoneIndex++);
99
100                for(int i=0; i < pCurBone->GetBoneCount(); i++)
101                {
102                        SetBoneIndexesRecursive(pCurBone->GetBone(i));
103                }
104
105                rootIter++;
106        }
107}
108
109void CIntermediateBuilderSkeleton::SetBoneIndexesRecursive( CIntermediateBone* pIBone)
110{
111        pIBone->SetIndex(m_iBoneIndex++);
112
113        for(int i=0; i < pIBone->GetBoneCount(); i++)
114        {
115                SetBoneIndexesRecursive(pIBone->GetBone(i));
116        }
117}
118
119void CIntermediateBuilderSkeleton::CreateAnimation( CDDObject* pDDConfig, CExportProgressDlg *pProgressDlg )
120{
121        assert(pDDConfig);
122        if(pProgressDlg != NULL)
123                m_pProgressDlg = pProgressDlg;
124
125        CAnimationSetting curAnim;
126        curAnim.m_iStartFrame = pDDConfig->GetInt("AnimationStartID", 0);
127        curAnim.m_iEndFrame = pDDConfig->GetInt("AnimationEndID", 1);
128        curAnim.m_fSampleRate = pDDConfig->GetFloat("AnimationSampleRateID", 1.0);
129        curAnim.m_sAnimName = pDDConfig->GetString("Name", "Anim1");
130
131        AddFrame( curAnim );
132}
133
134
135void CIntermediateBuilderSkeleton::CreateBonePool( void )
136{
137        int iBoneCount = m_pSkin->GetNumBones();
138        for (int i=0; i < iBoneCount; i++)
139        {
140                INode* pBone = m_pSkin->GetBone(i);
141                CIntermediateBone* pIBone = new CIntermediateBone( pBone->GetName() );
142                pIBone->SetHandle( pBone->GetHandle() );
143
144                INode* pParent = pBone->GetParentNode();
145                if(pParent)
146                        pIBone->SetParentHandle( pParent->GetHandle() );
147
148                //pIBone->SetIndex( m_iBoneIndex++ );
149               
150                m_pISkel->AddBone( pIBone, pIBone->GetName().c_str() );
151        }
152}
153
154void CIntermediateBuilderSkeleton::ConnectLinkedBones( void )
155{
156        static int i = 0;
157
158        std::vector<CIntermediateBone*>::const_iterator iter = m_pISkel->GetRootBones().begin();
159
160        while(iter != m_pISkel->GetRootBones().end())
161        {
162                CIntermediateBone* pIBone = *iter;
163                ULONG handle = pIBone->GetHandle();
164                INode* pNode = GetNodeFromID(handle);
165
166                INode* pParentNode = pNode->GetParentNode();
167                if(pParentNode)
168                        if(pParentNode->SuperClassID() == HELPER_CLASS_ID)
169                        {
170                                CIntermediateBone* pParentIBone = m_pISkel->FindBone( pParentNode->GetParentNode()->GetHandle() );
171                                if(pParentIBone)
172                                {
173                                        Ogre::StringUtil::StrStreamType strID;
174                                        strID << "Connecting_Bone_" << i++ ;
175                                        CIntermediateBone* pConnectBone = new CIntermediateBone(strID.str().c_str());
176
177                                        pConnectBone->SetHandle( pParentNode->GetHandle());
178                                        //pConnectBone->SetIndex(m_iBoneIndex++);
179                                        pConnectBone->AddBone( pIBone );
180                                        pParentIBone->AddBone( pIBone );
181                                }
182                        }
183                iter++;
184        }
185}
186
187bool CIntermediateBuilderSkeleton::FindSkinModifier( INode* pMaxNode )
188{       
189        // Get object from node. Abort if no object.
190        Object* ObjectPtr = pMaxNode->GetObjectRef();                   
191
192        if (!ObjectPtr) return false;
193
194        // Is derived object ?
195        while (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID && ObjectPtr)
196        {
197                // Yes -> Cast.
198                IDerivedObject *DerivedObjectPtr = (IDerivedObject *)(ObjectPtr);
199
200                // Iterate over all entries of the modifier stack.
201                int ModStackIndex = 0;
202                while (ModStackIndex < DerivedObjectPtr->NumModifiers())
203                {
204                        // Get current modifier.
205                        Modifier* ModifierPtr = DerivedObjectPtr->GetModifier(ModStackIndex);
206
207                        // Is this Physique ?
208                        if (ModifierPtr->ClassID() == SKIN_CLASSID)
209                        {
210                                // Yes -> Exit.
211                                m_pSkinMod = ModifierPtr;
212                                m_pSkin=(ISkin*)(m_pSkinMod)->GetInterface(I_SKIN);
213
214                                //get the node's initial transformation matrix and store it in a matrix3
215                                Matrix3 initTM;
216                                int msg = (m_pSkin)->GetBoneInitTM(pMaxNode, initTM);
217
218                                //get a pointer to the export context interface
219                                m_pSkinContext = (ISkinContextData*)(m_pSkin)->GetContextInterface(pMaxNode);
220                                return true;
221                        }
222
223                        // Next modifier stack entry.
224                        ModStackIndex++;
225                }
226                ObjectPtr = DerivedObjectPtr->GetObjRef();
227        }
228
229        // Not found.
230        return false;
231}
232
233bool CIntermediateBuilderSkeleton::QuerySkinModifier( INode* pMaxNode )
234{       
235        // Get object from node. Abort if no object.
236        Object* ObjectPtr = pMaxNode->GetObjectRef();                   
237
238        if (!ObjectPtr) return false;
239
240        Modifier*                       pSkinMod = NULL;
241        ISkin*                          pSkin = NULL;
242        ISkinContextData*       pSkinContext = NULL;
243
244        // Is derived object ?
245        while (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID && ObjectPtr)
246        {
247                // Yes -> Cast.
248                IDerivedObject *DerivedObjectPtr = (IDerivedObject *)(ObjectPtr);
249
250                // Iterate over all entries of the modifier stack.
251                int ModStackIndex = 0;
252                while (ModStackIndex < DerivedObjectPtr->NumModifiers())
253                {
254                        // Get current modifier.
255                        Modifier* ModifierPtr = DerivedObjectPtr->GetModifier(ModStackIndex);
256
257                        // Is this Physique ?
258                        if (ModifierPtr->ClassID() == SKIN_CLASSID)
259                        {
260                                // Yes -> Exit.
261                                pSkinMod = ModifierPtr;
262                                pSkin=(ISkin*)(pSkinMod)->GetInterface(I_SKIN);
263
264                                //get the node's initial transformation matrix and store it in a matrix3
265                                Matrix3 initTM;
266                                int msg = (pSkin)->GetBoneInitTM(pMaxNode, initTM);
267
268                                //get a pointer to the export context interface
269                                pSkinContext = (ISkinContextData*)(pSkin)->GetContextInterface(pMaxNode);
270                                return true;
271                        }
272
273                        // Next modifier stack entry.
274                        ModStackIndex++;
275                }
276                ObjectPtr = DerivedObjectPtr->GetObjRef();
277        }
278
279        // Not found.
280        return false;
281}
282
283
284
285void CIntermediateBuilderSkeleton::AddFrame( CAnimationSetting animationSettings )
286{
287        if(m_pProgressDlg != NULL)
288                m_pProgressDlg->InitLocal(m_pISkel->GetBoneCount());
289
290        for (int i=0; i < m_pISkel->GetBoneCount(); i++)
291        {
292                if(m_pProgressDlg != NULL)
293                        m_pProgressDlg->LocalStep("Exporting Bones");
294
295                CAnimationSetting animSetting = animationSettings;
296
297                CIntermediateBone* pIBone = m_pISkel->GetBone(i);
298                INode* pMaxNode = GetNodeFromID(pIBone->GetHandle());
299                if(!pMaxNode) return;
300
301                INode* pParentBone = pMaxNode->GetParentNode();
302
303                // binding pose:
304                Ogre::Vector3 pos;
305                Ogre::Vector3 scale;
306                Ogre::Quaternion oriet;
307                pIBone->GetBindingPose(pos,oriet,scale);
308
309                Point3 basePos(pos.x, pos.y, pos.z);
310                Point3 baseScale(scale.x, scale.y, scale.z);
311                Quat baseOriet(oriet.x, oriet.y, oriet.z, oriet.w);
312
313                //If bone is root in the modifier we must not make it relative to its parent
314                bool bModifierRoot = false;
315                std::vector<CIntermediateBone*> lRoots = m_pISkel->GetRootBones();
316                for(int i=0; i<lRoots.size(); i++)
317                {
318                        if(lRoots[i] == pIBone)
319                                bModifierRoot = true;
320                }
321
322
323                int tpf = GetTicksPerFrame();
324                float fps = 1.0 / float(GetFrameRate());
325
326                bool animCreated = pIBone->CreateAnimation(animSetting);
327
328                if(animCreated)
329                {
330                        float x = animSetting.m_iStartFrame;
331                        int frameCount = 0;
332                        while(x <= animSetting.m_iEndFrame)
333                        {
334                                TimeValue t = x*tpf;
335                                float time = (x- animSetting.m_iStartFrame)*fps;
336
337                                // adjust for next sample according to sampleRate
338                                x = x + animSetting.m_fSampleRate;
339
340                                Matrix3 nodeTM = pMaxNode->GetNodeTM(t);
341                                Matrix3 parentTM = pParentBone->GetNodeTM(t);
342                                Matrix3 relativeTM = nodeTM;
343
344                                if( pParentBone->IsRootNode() || bModifierRoot )
345                                {
346                                        INode* pMeshNode = m_pMaxNode; //GetNodeFromID(meshNodeID);
347                                        parentTM = pMeshNode->GetObjTMAfterWSM(t);
348                                }
349       
350                                //if(!bModifierRoot)
351                                relativeTM = nodeTM * Inverse(parentTM);
352
353                                Point3 nodePos;
354                                Point3 nodeScale;
355                                Quat nodeOriet;
356
357                                DecomposeMatrix(relativeTM, nodePos, nodeOriet, nodeScale);
358
359                                Ogre::Quaternion oquat;
360                                oquat.x = nodeOriet.x;
361                                oquat.y = nodeOriet.z;
362                                oquat.z = -nodeOriet.y;
363                                oquat.w = nodeOriet.w;
364
365                                Ogre::Vector3 axis;
366                                Ogre::Radian w;
367                                oquat.ToAngleAxis(w, axis);
368                                oquat.FromAngleAxis(-w, axis);
369
370                                //CIntermediateBuilder::Rotate90DegreesAroundX(nodeOriet);
371                                //Ogre::Quaternion oquat;
372                                //oquat.x = nodeOriet.x;
373                                //oquat.y = nodeOriet.y;
374                                //oquat.z = nodeOriet.z;
375                                //oquat.w = nodeOriet.w;
376
377                                CIntermediateBuilder::Rotate90DegreesAroundX(nodePos);
378
379
380                                Point3 relPos = basePos;
381                                Point3 relScale = baseScale;
382                                Ogre::Quaternion relOriet = baseOriet;
383
384                                // relative transformation
385                                relPos = nodePos - basePos;
386                                relScale = (nodeScale + baseScale) / 2;
387                                relOriet = oriet.Inverse() * oquat;
388                                //relOriet =  oquat * oriet.Inverse();
389
390                                relScale = Point3(1,1,1);
391
392                                //Clamp(relPos, 0.0001);
393
394                               
395                                pIBone->AddFrame( 
396                                        animSetting.m_sAnimName,
397                                        frameCount++, // frame nr relative to this animation
398                                        time,
399                                        Ogre::Vector3(relPos.x, relPos.y, relPos.z), // already rotated..
400                                        relOriet, 
401                                        Ogre::Vector3(relScale.x, relScale.z, relScale.y)
402                                        );
403
404                                //if(m_fAnimTotalLength < time)
405                                //      m_fAnimTotalLength = time;
406                        }
407                }
408        }
409        //LOGDEBUG "CIntermediate::AddFrame() - End");
410}
411
412
413void CIntermediateBuilderSkeleton::SetBindingPose( unsigned int frame )
414{
415        for (int i=0; i < m_pISkel->GetBoneCount(); i++)
416        {
417                CIntermediateBone* pIBone = m_pISkel->GetBone(i);
418                INode* pMaxNode = GetNodeFromID(pIBone->GetHandle());
419                if(!pMaxNode) return;
420
421                // binding pose:
422                INode* pParentBone = pMaxNode->GetParentNode();
423                Matrix3 baseParentTM = pParentBone->GetNodeTM(frame);
424                Matrix3 baseTM = pMaxNode->GetNodeTM(frame);
425
426                //If bone is root in the modifier we must not make it relative to its parent
427                bool bModifierRoot = false;
428                std::vector<CIntermediateBone*> lRoots = m_pISkel->GetRootBones();
429                for(int i=0; i<lRoots.size(); i++)
430                {
431                        if(lRoots[i] == pIBone)
432                                bModifierRoot = true;
433                }
434
435                if( pParentBone->IsRootNode() ||  bModifierRoot)
436                {
437                        // NOTICE! Double tjeck this seciton! Are Root bones handled correctly?
438                        Matrix3 meshTM = m_pMaxNode->GetObjTMAfterWSM(frame);
439                        baseTM = baseTM * Inverse(meshTM);
440                }
441                else
442                {
443                        baseTM = baseTM * Inverse(baseParentTM); // binding pose initial local space transformation matrix
444                }
445               
446                Point3 basePos;
447                Point3 baseScale;
448                Quat baseOriet;
449
450                DecomposeMatrix(baseTM, basePos, baseOriet, baseScale);
451
452                Ogre::Quaternion oquat;
453                oquat.x = baseOriet.x;
454                oquat.y = baseOriet.z;
455                oquat.z = -baseOriet.y;
456                oquat.w = baseOriet.w;
457
458                Ogre::Vector3 axis;
459                Ogre::Radian w;
460                oquat.ToAngleAxis(w, axis);
461                oquat.FromAngleAxis(-w, axis);
462
463                //CIntermediateBuilder::Rotate90DegreesAroundX(baseOriet);
464                //Ogre::Quaternion oquat;
465                //oquat.x = baseOriet.x;
466                //oquat.y = baseOriet.y;
467                //oquat.z = baseOriet.z;
468                //oquat.w = baseOriet.w;
469
470                CIntermediateBuilder::Rotate90DegreesAroundX(basePos);
471
472                Ogre::Vector3 scale = Ogre::Vector3(baseScale.x, baseScale.z, baseScale.y);
473
474                pIBone->SetBindingPose(Ogre::Vector3(basePos.x, basePos.y, basePos.z), oquat, scale);
475        }
476}
477
478void CIntermediateBuilderSkeleton::AssembleBones( void )
479{
480        //m_iBoneIndex = 0;
481        for (int i=0; i < m_pISkel->GetBoneCount(); i++)
482        {
483                CIntermediateBone* pIBone = m_pISkel->GetBone(i);
484                INode* pMaxNode = GetNodeFromID(pIBone->GetHandle());
485                if(!pMaxNode) return;
486
487                ULONG parentHandle = pIBone->GetParentHandle();
488                CIntermediateBone* parent = m_pISkel->FindBone( parentHandle );
489                if(parent)
490                        parent->AddBone( pIBone );
491                else
492                {
493                        m_pISkel->MarkBoneAsRoot( pIBone );
494                }
495        }
496}
497
498// Set the vertex data from the max vertex with index maxIdx to Intermediate Mesh vertex with intermediateIdx.
499void CIntermediateBuilderSkeleton::SetVertexData( unsigned int maxIdx, unsigned int intermediateIdx )
500{
501        if(m_pISkel==NULL)
502                return;
503        SVertexBoneData vd;
504        int nrBones = m_pSkinContext->GetNumAssignedBones(maxIdx);
505        for (int i=0; i < nrBones; i++)
506        {
507                int iBoneIdx = m_pSkinContext->GetAssignedBone(maxIdx,i);
508                INode* pMaxBone = m_pSkin->GetBone(iBoneIdx);
509                if(pMaxBone)
510                {
511                        CIntermediateBone* pIBone = m_pISkel->FindBone( pMaxBone->GetHandle() );
512
513                        vd.boneIndex = pIBone->GetIndex();
514                        vd.weight = m_pSkinContext->GetBoneWeight(maxIdx, i);//iBoneIdx);
515
516                        if(vd.weight < 0.001f) 
517                                continue;
518
519                        m_pISkel->AddVertexData( intermediateIdx, vd );
520                }
521        }
522}
523
524CIntermediateSkeleton* CIntermediateBuilderSkeleton::GetSkeleton( void )
525{
526        return m_pISkel;
527}
Note: See TracBrowser for help on using the repository browser.