rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 Open Asset Import Library (assimp)
|
nuclear@0
|
3 ----------------------------------------------------------------------
|
nuclear@0
|
4
|
nuclear@0
|
5 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
6 All rights reserved.
|
nuclear@0
|
7
|
nuclear@0
|
8 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
9 with or without modification, are permitted provided that the
|
nuclear@0
|
10 following conditions are met:
|
nuclear@0
|
11
|
nuclear@0
|
12 * Redistributions of source code must retain the above
|
nuclear@0
|
13 copyright notice, this list of conditions and the
|
nuclear@0
|
14 following disclaimer.
|
nuclear@0
|
15
|
nuclear@0
|
16 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
17 copyright notice, this list of conditions and the
|
nuclear@0
|
18 following disclaimer in the documentation and/or other
|
nuclear@0
|
19 materials provided with the distribution.
|
nuclear@0
|
20
|
nuclear@0
|
21 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
22 contributors may be used to endorse or promote products
|
nuclear@0
|
23 derived from this software without specific prior
|
nuclear@0
|
24 written permission of the assimp team.
|
nuclear@0
|
25
|
nuclear@0
|
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
37
|
nuclear@0
|
38 ----------------------------------------------------------------------
|
nuclear@0
|
39 */
|
nuclear@0
|
40
|
nuclear@0
|
41 #include "AssimpPCH.h"
|
nuclear@0
|
42 #include "TargetAnimation.h"
|
nuclear@0
|
43 #include <algorithm>
|
nuclear@0
|
44
|
nuclear@0
|
45 using namespace Assimp;
|
nuclear@0
|
46
|
nuclear@0
|
47
|
nuclear@0
|
48 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
49 KeyIterator::KeyIterator(const std::vector<aiVectorKey>* _objPos,
|
nuclear@0
|
50 const std::vector<aiVectorKey>* _targetObjPos,
|
nuclear@0
|
51 const aiVector3D* defaultObjectPos /*= NULL*/,
|
nuclear@0
|
52 const aiVector3D* defaultTargetPos /*= NULL*/)
|
nuclear@0
|
53
|
nuclear@0
|
54 : reachedEnd (false)
|
nuclear@0
|
55 , curTime (-1.)
|
nuclear@0
|
56 , objPos (_objPos)
|
nuclear@0
|
57 , targetObjPos (_targetObjPos)
|
nuclear@0
|
58 , nextObjPos (0)
|
nuclear@0
|
59 , nextTargetObjPos(0)
|
nuclear@0
|
60 {
|
nuclear@0
|
61 // Generate default transformation tracks if necessary
|
nuclear@0
|
62 if (!objPos || objPos->empty())
|
nuclear@0
|
63 {
|
nuclear@0
|
64 defaultObjPos.resize(1);
|
nuclear@0
|
65 defaultObjPos.front().mTime = 10e10;
|
nuclear@0
|
66
|
nuclear@0
|
67 if (defaultObjectPos)
|
nuclear@0
|
68 defaultObjPos.front().mValue = *defaultObjectPos;
|
nuclear@0
|
69
|
nuclear@0
|
70 objPos = & defaultObjPos;
|
nuclear@0
|
71 }
|
nuclear@0
|
72 if (!targetObjPos || targetObjPos->empty())
|
nuclear@0
|
73 {
|
nuclear@0
|
74 defaultTargetObjPos.resize(1);
|
nuclear@0
|
75 defaultTargetObjPos.front().mTime = 10e10;
|
nuclear@0
|
76
|
nuclear@0
|
77 if (defaultTargetPos)
|
nuclear@0
|
78 defaultTargetObjPos.front().mValue = *defaultTargetPos;
|
nuclear@0
|
79
|
nuclear@0
|
80 targetObjPos = & defaultTargetObjPos;
|
nuclear@0
|
81 }
|
nuclear@0
|
82 }
|
nuclear@0
|
83
|
nuclear@0
|
84 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
85 template <class T>
|
nuclear@0
|
86 inline T Interpolate(const T& one, const T& two, float val)
|
nuclear@0
|
87 {
|
nuclear@0
|
88 return one + (two-one)*val;
|
nuclear@0
|
89 }
|
nuclear@0
|
90
|
nuclear@0
|
91 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
92 void KeyIterator::operator ++()
|
nuclear@0
|
93 {
|
nuclear@0
|
94 // If we are already at the end of all keyframes, return
|
nuclear@0
|
95 if (reachedEnd) {
|
nuclear@0
|
96 return;
|
nuclear@0
|
97 }
|
nuclear@0
|
98
|
nuclear@0
|
99 // Now search in all arrays for the time value closest
|
nuclear@0
|
100 // to our current position on the time line
|
nuclear@0
|
101 double d0,d1;
|
nuclear@0
|
102
|
nuclear@0
|
103 d0 = objPos->at ( std::min<unsigned int> ( nextObjPos, objPos->size()-1) ).mTime;
|
nuclear@0
|
104 d1 = targetObjPos->at( std::min<unsigned int> ( nextTargetObjPos, targetObjPos->size()-1) ).mTime;
|
nuclear@0
|
105
|
nuclear@0
|
106 // Easiest case - all are identical. In this
|
nuclear@0
|
107 // case we don't need to interpolate so we can
|
nuclear@0
|
108 // return earlier
|
nuclear@0
|
109 if ( d0 == d1 )
|
nuclear@0
|
110 {
|
nuclear@0
|
111 curTime = d0;
|
nuclear@0
|
112 curPosition = objPos->at(nextObjPos).mValue;
|
nuclear@0
|
113 curTargetPosition = targetObjPos->at(nextTargetObjPos).mValue;
|
nuclear@0
|
114
|
nuclear@0
|
115 // increment counters
|
nuclear@0
|
116 if (objPos->size() != nextObjPos-1)
|
nuclear@0
|
117 ++nextObjPos;
|
nuclear@0
|
118
|
nuclear@0
|
119 if (targetObjPos->size() != nextTargetObjPos-1)
|
nuclear@0
|
120 ++nextTargetObjPos;
|
nuclear@0
|
121 }
|
nuclear@0
|
122
|
nuclear@0
|
123 // An object position key is closest to us
|
nuclear@0
|
124 else if (d0 < d1)
|
nuclear@0
|
125 {
|
nuclear@0
|
126 curTime = d0;
|
nuclear@0
|
127
|
nuclear@0
|
128 // interpolate the other
|
nuclear@0
|
129 if (1 == targetObjPos->size() || !nextTargetObjPos) {
|
nuclear@0
|
130 curTargetPosition = targetObjPos->at(0).mValue;
|
nuclear@0
|
131 }
|
nuclear@0
|
132 else
|
nuclear@0
|
133 {
|
nuclear@0
|
134 const aiVectorKey& last = targetObjPos->at(nextTargetObjPos);
|
nuclear@0
|
135 const aiVectorKey& first = targetObjPos->at(nextTargetObjPos-1);
|
nuclear@0
|
136
|
nuclear@0
|
137 curTargetPosition = Interpolate(first.mValue, last.mValue, (float) (
|
nuclear@0
|
138 (curTime-first.mTime) / (last.mTime-first.mTime) ));
|
nuclear@0
|
139 }
|
nuclear@0
|
140
|
nuclear@0
|
141 if (objPos->size() != nextObjPos-1)
|
nuclear@0
|
142 ++nextObjPos;
|
nuclear@0
|
143 }
|
nuclear@0
|
144 // A target position key is closest to us
|
nuclear@0
|
145 else
|
nuclear@0
|
146 {
|
nuclear@0
|
147 curTime = d1;
|
nuclear@0
|
148
|
nuclear@0
|
149 // interpolate the other
|
nuclear@0
|
150 if (1 == objPos->size() || !nextObjPos) {
|
nuclear@0
|
151 curPosition = objPos->at(0).mValue;
|
nuclear@0
|
152 }
|
nuclear@0
|
153 else
|
nuclear@0
|
154 {
|
nuclear@0
|
155 const aiVectorKey& last = objPos->at(nextObjPos);
|
nuclear@0
|
156 const aiVectorKey& first = objPos->at(nextObjPos-1);
|
nuclear@0
|
157
|
nuclear@0
|
158 curPosition = Interpolate(first.mValue, last.mValue, (float) (
|
nuclear@0
|
159 (curTime-first.mTime) / (last.mTime-first.mTime)));
|
nuclear@0
|
160 }
|
nuclear@0
|
161
|
nuclear@0
|
162 if (targetObjPos->size() != nextTargetObjPos-1)
|
nuclear@0
|
163 ++nextTargetObjPos;
|
nuclear@0
|
164 }
|
nuclear@0
|
165
|
nuclear@0
|
166 if (nextObjPos >= objPos->size()-1 &&
|
nuclear@0
|
167 nextTargetObjPos >= targetObjPos->size()-1)
|
nuclear@0
|
168 {
|
nuclear@0
|
169 // We reached the very last keyframe
|
nuclear@0
|
170 reachedEnd = true;
|
nuclear@0
|
171 }
|
nuclear@0
|
172 }
|
nuclear@0
|
173
|
nuclear@0
|
174 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
175 void TargetAnimationHelper::SetTargetAnimationChannel (
|
nuclear@0
|
176 const std::vector<aiVectorKey>* _targetPositions)
|
nuclear@0
|
177 {
|
nuclear@0
|
178 ai_assert(NULL != _targetPositions);
|
nuclear@0
|
179 targetPositions = _targetPositions;
|
nuclear@0
|
180 }
|
nuclear@0
|
181
|
nuclear@0
|
182 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
183 void TargetAnimationHelper::SetMainAnimationChannel (
|
nuclear@0
|
184 const std::vector<aiVectorKey>* _objectPositions)
|
nuclear@0
|
185 {
|
nuclear@0
|
186 ai_assert(NULL != _objectPositions);
|
nuclear@0
|
187 objectPositions = _objectPositions;
|
nuclear@0
|
188 }
|
nuclear@0
|
189
|
nuclear@0
|
190 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
191 void TargetAnimationHelper::SetFixedMainAnimationChannel(
|
nuclear@0
|
192 const aiVector3D& fixed)
|
nuclear@0
|
193 {
|
nuclear@0
|
194 objectPositions = NULL; // just to avoid confusion
|
nuclear@0
|
195 fixedMain = fixed;
|
nuclear@0
|
196 }
|
nuclear@0
|
197
|
nuclear@0
|
198 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
199 void TargetAnimationHelper::Process(std::vector<aiVectorKey>* distanceTrack)
|
nuclear@0
|
200 {
|
nuclear@0
|
201 ai_assert(NULL != targetPositions && NULL != distanceTrack);
|
nuclear@0
|
202
|
nuclear@0
|
203 // TODO: in most cases we won't need the extra array
|
nuclear@0
|
204 std::vector<aiVectorKey> real;
|
nuclear@0
|
205
|
nuclear@0
|
206 std::vector<aiVectorKey>* fill = (distanceTrack == objectPositions ? &real : distanceTrack);
|
nuclear@0
|
207 fill->reserve(std::max( objectPositions->size(), targetPositions->size() ));
|
nuclear@0
|
208
|
nuclear@0
|
209 // Iterate through all object keys and interpolate their values if necessary.
|
nuclear@0
|
210 // Then get the corresponding target position, compute the difference
|
nuclear@0
|
211 // vector between object and target position. Then compute a rotation matrix
|
nuclear@0
|
212 // that rotates the base vector of the object coordinate system at that time
|
nuclear@0
|
213 // to match the diff vector.
|
nuclear@0
|
214
|
nuclear@0
|
215 KeyIterator iter(objectPositions,targetPositions,&fixedMain);
|
nuclear@0
|
216 for (;!iter.Finished();++iter)
|
nuclear@0
|
217 {
|
nuclear@0
|
218 const aiVector3D& position = iter.GetCurPosition();
|
nuclear@0
|
219 const aiVector3D& tposition = iter.GetCurTargetPosition();
|
nuclear@0
|
220
|
nuclear@0
|
221 // diff vector
|
nuclear@0
|
222 aiVector3D diff = tposition - position;
|
nuclear@0
|
223 float f = diff.Length();
|
nuclear@0
|
224
|
nuclear@0
|
225 // output distance vector
|
nuclear@0
|
226 if (f)
|
nuclear@0
|
227 {
|
nuclear@0
|
228 fill->push_back(aiVectorKey());
|
nuclear@0
|
229 aiVectorKey& v = fill->back();
|
nuclear@0
|
230 v.mTime = iter.GetCurTime();
|
nuclear@0
|
231 v.mValue = diff;
|
nuclear@0
|
232
|
nuclear@0
|
233 diff /= f;
|
nuclear@0
|
234 }
|
nuclear@0
|
235 else
|
nuclear@0
|
236 {
|
nuclear@0
|
237 // FIXME: handle this
|
nuclear@0
|
238 }
|
nuclear@0
|
239
|
nuclear@0
|
240 // diff is now the vector in which our camera is pointing
|
nuclear@0
|
241 }
|
nuclear@0
|
242
|
nuclear@0
|
243 if (real.size()) {
|
nuclear@0
|
244 *distanceTrack = real;
|
nuclear@0
|
245 }
|
nuclear@0
|
246 }
|