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