1 //****************************************************************************//
2 // morphtargetmixer.cpp                                                       //
3 // Copyright (C) 2001, 2002 Bruno 'Beosil' Heidelberger                       //
4 //****************************************************************************//
5 // This library is free software; you can redistribute it and/or modify it    //
6 // under the terms of the GNU Lesser General Public License as published by   //
7 // the Free Software Foundation; either version 2.1 of the License, or (at    //
8 // your option) any later version.                                            //
9 //****************************************************************************//
10 
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14 
15 //****************************************************************************//
16 // Includes                                                                   //
17 //****************************************************************************//
18 
19 #include "cal3d/error.h"
20 #include "cal3d/morphtargetmixer.h"
21 #include "cal3d/model.h"
22 #include "cal3d/mesh.h"
23 #include "cal3d/submesh.h"
24 #include "cal3d/coremorphanimation.h"
25 #include "cal3d/coremodel.h"
26 #include "cal3d/coremesh.h"
27 #include "cal3d/coresubmesh.h"
28 
29  /*****************************************************************************/
30 /** Constructs the morph target mixer instance.
31   *
32   * This function is the default constructor of the morph target mixer instance.
33   *****************************************************************************/
34 
CalMorphTargetMixer(CalModel * pModel)35 CalMorphTargetMixer::CalMorphTargetMixer(CalModel* pModel)
36 {
37   assert(pModel);
38   m_pModel = pModel;
39 
40   if(pModel->getCoreModel()->getCoreMorphAnimationCount() != 0)
41   {
42     int morphAnimationCount = pModel->getCoreModel()->getCoreMorphAnimationCount();
43     // reserve the space needed in all the vectors
44     m_vectorCurrentWeight.resize(morphAnimationCount);
45     m_vectorEndWeight.resize(morphAnimationCount);
46     m_vectorDuration.resize(morphAnimationCount);
47     std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
48     std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
49     std::vector<float>::iterator iteratorDuration = m_vectorDuration.begin();
50     while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
51     {
52       (*iteratorCurrentWeight) = 0.0f;
53       (*iteratorEndWeight) = 0.0f;
54       (*iteratorDuration) = 0.0f;
55       ++iteratorCurrentWeight;
56       ++iteratorEndWeight;
57       ++iteratorDuration;
58     }
59   }
60 }
61 
62 
63 /*****************************************************************************/
64 /** Interpolates the weight of a morph target.
65   *
66   * This function interpolates the weight of a morph target a new value
67   * in a given amount of time.
68   *
69   * @param id The ID of the morph target that should be blended.
70   * @param weight The weight to interpolate the morph target to.
71   * @param delay The time in seconds until the new weight should be reached.
72   *
73   * @return One of the following values:
74   *         \li \b true if successful
75   *         \li \b false if an error happend
76   *****************************************************************************/
blend(int id,float weight,float delay)77 bool CalMorphTargetMixer::blend(int id, float weight, float delay)
78 {
79   if((id < 0) || (id >= (int)m_vectorCurrentWeight.size()))
80   {
81     CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__);
82     return false;
83   }
84   m_vectorEndWeight[id] = weight;
85   m_vectorDuration[id] = delay;
86   return true;
87 }
88 
89  /*****************************************************************************/
90 /** Fades a morph target out.
91   *
92   * This function fades a morph target out in a given amount of time.
93   *
94   * @param id The ID of the morph target that should be faded out.
95   * @param delay The time in seconds until the the morph target is
96   *              completely removed.
97   *
98   * @return One of the following values:
99   *         \li \b true if successful
100   *         \li \b false if an error happend
101   *****************************************************************************/
102 
clear(int id,float delay)103 bool CalMorphTargetMixer::clear(int id, float delay)
104 {
105   if((id < 0) || (id >= (int)m_vectorCurrentWeight.size()))
106   {
107     CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__);
108     return false;
109   }
110   m_vectorEndWeight[id] = 0.0f;
111   m_vectorDuration[id] = delay;
112   return true;
113 }
114 
115  /*****************************************************************************/
116 /** Get the weight of a morph target.
117   *
118   * @param id The id of the morph target which weight you want.
119   *
120   * @return The weight of the morph target with the given id.
121   *****************************************************************************/
getCurrentWeight(int id) const122 float CalMorphTargetMixer::getCurrentWeight(int id) const
123 {
124   if((id < 0) || (id >= (int)m_vectorCurrentWeight.size()))
125   {
126     CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__);
127     return false;
128   }
129   return m_vectorCurrentWeight[id];
130 }
131 
132  /*****************************************************************************/
133 /** Get the weight of the base vertices.
134   *
135   * @return The weight of the base vertices.
136   *****************************************************************************/
getCurrentWeightBase()137 float CalMorphTargetMixer::getCurrentWeightBase()
138 {
139   float currentWeight = 1.0f;
140   std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
141   while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
142   {
143     currentWeight -=(*iteratorCurrentWeight);
144     ++iteratorCurrentWeight;
145   }
146   return currentWeight;
147 }
148 
149  /*****************************************************************************/
150 /** Updates all morph targets.
151   *
152   * This function updates all morph targets of the mixer instance for a
153   * given amount of time.
154   *
155   * @param deltaTime The elapsed time in seconds since the last update.
156   *****************************************************************************/
157 
update(float deltaTime)158 void CalMorphTargetMixer::update(float deltaTime)
159 {
160   std::vector<float>::iterator iteratorCurrentWeight = m_vectorCurrentWeight.begin();
161   std::vector<float>::iterator iteratorEndWeight = m_vectorEndWeight.begin();
162   std::vector<float>::iterator iteratorDuration = m_vectorDuration.begin();
163   while(iteratorCurrentWeight!=m_vectorCurrentWeight.end())
164   {
165     if(deltaTime >= (*iteratorDuration))
166     {
167       (*iteratorCurrentWeight) = (*iteratorEndWeight);
168       (*iteratorDuration) = 0.0f;
169     }
170     else
171     {
172       (*iteratorCurrentWeight) += ((*iteratorEndWeight)-(*iteratorCurrentWeight)) *
173                                   deltaTime/(*iteratorDuration);
174       (*iteratorDuration) -= deltaTime;
175     }
176     ++iteratorCurrentWeight;
177     ++iteratorEndWeight;
178     ++iteratorDuration;
179   }
180   int morphAnimationID = 0;
181   while(morphAnimationID<getMorphTargetCount())
182   {
183     CalCoreMorphAnimation* pCoreMorphAnimation =
184                    m_pModel->getCoreModel()->getCoreMorphAnimation(morphAnimationID);
185     std::vector<int>& vectorCoreMeshID = pCoreMorphAnimation->getVectorCoreMeshID();
186     std::vector<int>& vectorMorphTargetID = pCoreMorphAnimation->getVectorMorphTargetID();
187     size_t meshIterator = 0;
188     while(meshIterator<vectorCoreMeshID.size())
189     {
190        std::vector<CalSubmesh *> &vectorSubmesh =
191              m_pModel->getMesh(vectorCoreMeshID[meshIterator])->getVectorSubmesh();
192        int submeshCount = vectorSubmesh.size();
193        int submeshId;
194        for(submeshId=0;submeshId<submeshCount;++submeshId)
195        {
196          vectorSubmesh[submeshId]->setMorphTargetWeight
197                   (vectorMorphTargetID[meshIterator],m_vectorCurrentWeight[morphAnimationID]);
198        }
199        ++meshIterator;
200     }
201     ++morphAnimationID;
202   }
203 }
204 
205  /*****************************************************************************/
206 /** Returns the number of morph targets this morph target mixer mixes.
207   *
208   * @return The number of morph targets this morph target mixer mixes.
209   *****************************************************************************/
210 
getMorphTargetCount() const211 int CalMorphTargetMixer::getMorphTargetCount() const
212 {
213   return m_vectorCurrentWeight.size();
214 }
215 
216 //****************************************************************************//
217