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 /** @file LWOAnimation.cpp
|
nuclear@0
|
42 * @brief LWOAnimationResolver utility class
|
nuclear@0
|
43 *
|
nuclear@0
|
44 * It's a very generic implementation of LightWave's system of
|
nuclear@0
|
45 * componentwise-animated stuff. The one and only fully free
|
nuclear@0
|
46 * implementation of LightWave envelopes of which I know.
|
nuclear@0
|
47 */
|
nuclear@0
|
48
|
nuclear@0
|
49 #include "AssimpPCH.h"
|
nuclear@0
|
50 #if (!defined ASSIMP_BUILD_NO_LWO_IMPORTER) && (!defined ASSIMP_BUILD_NO_LWS_IMPORTER)
|
nuclear@0
|
51
|
nuclear@0
|
52 #include <functional>
|
nuclear@0
|
53
|
nuclear@0
|
54 // internal headers
|
nuclear@0
|
55 #include "LWOFileData.h"
|
nuclear@0
|
56
|
nuclear@0
|
57 using namespace Assimp;
|
nuclear@0
|
58 using namespace Assimp::LWO;
|
nuclear@0
|
59
|
nuclear@0
|
60 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
61 // Construct an animation resolver from a given list of envelopes
|
nuclear@0
|
62 AnimResolver::AnimResolver(std::list<Envelope>& _envelopes,double tick)
|
nuclear@0
|
63 : envelopes (_envelopes)
|
nuclear@0
|
64 , sample_rate (0.)
|
nuclear@0
|
65 {
|
nuclear@0
|
66 trans_x = trans_y = trans_z = NULL;
|
nuclear@0
|
67 rotat_x = rotat_y = rotat_z = NULL;
|
nuclear@0
|
68 scale_x = scale_y = scale_z = NULL;
|
nuclear@0
|
69
|
nuclear@0
|
70 first = last = 150392.;
|
nuclear@0
|
71
|
nuclear@0
|
72 // find transformation envelopes
|
nuclear@0
|
73 for (std::list<LWO::Envelope>::iterator it = envelopes.begin(); it != envelopes.end(); ++it) {
|
nuclear@0
|
74
|
nuclear@0
|
75 (*it).old_first = 0;
|
nuclear@0
|
76 (*it).old_last = (*it).keys.size()-1;
|
nuclear@0
|
77
|
nuclear@0
|
78 if ((*it).keys.empty()) continue;
|
nuclear@0
|
79 switch ((*it).type) {
|
nuclear@0
|
80
|
nuclear@0
|
81 // translation
|
nuclear@0
|
82 case LWO::EnvelopeType_Position_X:
|
nuclear@0
|
83 trans_x = &*it;break;
|
nuclear@0
|
84 case LWO::EnvelopeType_Position_Y:
|
nuclear@0
|
85 trans_y = &*it;break;
|
nuclear@0
|
86 case LWO::EnvelopeType_Position_Z:
|
nuclear@0
|
87 trans_z = &*it;break;
|
nuclear@0
|
88
|
nuclear@0
|
89 // rotation
|
nuclear@0
|
90 case LWO::EnvelopeType_Rotation_Heading:
|
nuclear@0
|
91 rotat_x = &*it;break;
|
nuclear@0
|
92 case LWO::EnvelopeType_Rotation_Pitch:
|
nuclear@0
|
93 rotat_y = &*it;break;
|
nuclear@0
|
94 case LWO::EnvelopeType_Rotation_Bank:
|
nuclear@0
|
95 rotat_z = &*it;break;
|
nuclear@0
|
96
|
nuclear@0
|
97 // scaling
|
nuclear@0
|
98 case LWO::EnvelopeType_Scaling_X:
|
nuclear@0
|
99 scale_x = &*it;break;
|
nuclear@0
|
100 case LWO::EnvelopeType_Scaling_Y:
|
nuclear@0
|
101 scale_y = &*it;break;
|
nuclear@0
|
102 case LWO::EnvelopeType_Scaling_Z:
|
nuclear@0
|
103 scale_z = &*it;break;
|
nuclear@0
|
104 default:
|
nuclear@0
|
105 continue;
|
nuclear@0
|
106 };
|
nuclear@0
|
107
|
nuclear@0
|
108 // convert from seconds to ticks
|
nuclear@0
|
109 for (std::vector<LWO::Key>::iterator d = (*it).keys.begin(); d != (*it).keys.end(); ++d)
|
nuclear@0
|
110 (*d).time *= tick;
|
nuclear@0
|
111
|
nuclear@0
|
112 // set default animation range (minimum and maximum time value for which we have a keyframe)
|
nuclear@0
|
113 first = std::min(first, (*it).keys.front().time );
|
nuclear@0
|
114 last = std::max(last, (*it).keys.back().time );
|
nuclear@0
|
115 }
|
nuclear@0
|
116
|
nuclear@0
|
117 // deferred setup of animation range to increase performance.
|
nuclear@0
|
118 // typically the application will want to specify its own.
|
nuclear@0
|
119 need_to_setup = true;
|
nuclear@0
|
120 }
|
nuclear@0
|
121
|
nuclear@0
|
122 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
123 // Reset all envelopes to their original contents
|
nuclear@0
|
124 void AnimResolver::ClearAnimRangeSetup()
|
nuclear@0
|
125 {
|
nuclear@0
|
126 for (std::list<LWO::Envelope>::iterator it = envelopes.begin(); it != envelopes.end(); ++it) {
|
nuclear@0
|
127
|
nuclear@0
|
128 (*it).keys.erase((*it).keys.begin(),(*it).keys.begin()+(*it).old_first);
|
nuclear@0
|
129 (*it).keys.erase((*it).keys.begin()+(*it).old_last+1,(*it).keys.end());
|
nuclear@0
|
130 }
|
nuclear@0
|
131 }
|
nuclear@0
|
132
|
nuclear@0
|
133 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
134 // Insert additional keys to match LWO's pre& post behaviours.
|
nuclear@0
|
135 void AnimResolver::UpdateAnimRangeSetup()
|
nuclear@0
|
136 {
|
nuclear@0
|
137 // XXX doesn't work yet (hangs if more than one envelope channels needs to be interpolated)
|
nuclear@0
|
138
|
nuclear@0
|
139 for (std::list<LWO::Envelope>::iterator it = envelopes.begin(); it != envelopes.end(); ++it) {
|
nuclear@0
|
140 if ((*it).keys.empty()) continue;
|
nuclear@0
|
141
|
nuclear@0
|
142 const double my_first = (*it).keys.front().time;
|
nuclear@0
|
143 const double my_last = (*it).keys.back().time;
|
nuclear@0
|
144
|
nuclear@0
|
145 const double delta = my_last-my_first;
|
nuclear@0
|
146 const size_t old_size = (*it).keys.size();
|
nuclear@0
|
147
|
nuclear@0
|
148 const float value_delta = (*it).keys.back().value - (*it).keys.front().value;
|
nuclear@0
|
149
|
nuclear@0
|
150 // NOTE: We won't handle reset, linear and constant here.
|
nuclear@0
|
151 // See DoInterpolation() for their implementation.
|
nuclear@0
|
152
|
nuclear@0
|
153 // process pre behaviour
|
nuclear@0
|
154 switch ((*it).pre) {
|
nuclear@0
|
155 case LWO::PrePostBehaviour_OffsetRepeat:
|
nuclear@0
|
156 case LWO::PrePostBehaviour_Repeat:
|
nuclear@0
|
157 case LWO::PrePostBehaviour_Oscillate:
|
nuclear@0
|
158 {
|
nuclear@0
|
159 const double start_time = delta - fmod(my_first-first,delta);
|
nuclear@0
|
160 std::vector<LWO::Key>::iterator n = std::find_if((*it).keys.begin(),(*it).keys.end(),
|
nuclear@0
|
161 std::bind1st(std::greater<double>(),start_time)),m;
|
nuclear@0
|
162
|
nuclear@0
|
163 size_t ofs = 0;
|
nuclear@0
|
164 if (n != (*it).keys.end()) {
|
nuclear@0
|
165 // copy from here - don't use iterators, insert() would invalidate them
|
nuclear@0
|
166 ofs = (*it).keys.end()-n;
|
nuclear@0
|
167 (*it).keys.insert((*it).keys.begin(),ofs,LWO::Key());
|
nuclear@0
|
168
|
nuclear@0
|
169 std::copy((*it).keys.end()-ofs,(*it).keys.end(),(*it).keys.begin());
|
nuclear@0
|
170 }
|
nuclear@0
|
171
|
nuclear@0
|
172 // do full copies. again, no iterators
|
nuclear@0
|
173 const unsigned int num = (unsigned int)((my_first-first) / delta);
|
nuclear@0
|
174 (*it).keys.resize((*it).keys.size() + num*old_size);
|
nuclear@0
|
175
|
nuclear@0
|
176 n = (*it).keys.begin()+ofs;
|
nuclear@0
|
177 bool reverse = false;
|
nuclear@0
|
178 for (unsigned int i = 0; i < num; ++i) {
|
nuclear@0
|
179 m = n+old_size*(i+1);
|
nuclear@0
|
180 std::copy(n,n+old_size,m);
|
nuclear@0
|
181
|
nuclear@0
|
182 if ((*it).pre == LWO::PrePostBehaviour_Oscillate && (reverse = !reverse))
|
nuclear@0
|
183 std::reverse(m,m+old_size-1);
|
nuclear@0
|
184 }
|
nuclear@0
|
185
|
nuclear@0
|
186 // update time values
|
nuclear@0
|
187 n = (*it).keys.end() - (old_size+1);
|
nuclear@0
|
188 double cur_minus = delta;
|
nuclear@0
|
189 unsigned int tt = 1;
|
nuclear@0
|
190 for (const double tmp = delta*(num+1);cur_minus <= tmp;cur_minus += delta,++tt) {
|
nuclear@0
|
191 m = (delta == tmp ? (*it).keys.begin() : n - (old_size+1));
|
nuclear@0
|
192 for (;m != n; --n) {
|
nuclear@0
|
193 (*n).time -= cur_minus;
|
nuclear@0
|
194
|
nuclear@0
|
195 // offset repeat? add delta offset to key value
|
nuclear@0
|
196 if ((*it).pre == LWO::PrePostBehaviour_OffsetRepeat) {
|
nuclear@0
|
197 (*n).value += tt * value_delta;
|
nuclear@0
|
198 }
|
nuclear@0
|
199 }
|
nuclear@0
|
200 }
|
nuclear@0
|
201 break;
|
nuclear@0
|
202 }
|
nuclear@0
|
203 default:
|
nuclear@0
|
204 // silence compiler warning
|
nuclear@0
|
205 break;
|
nuclear@0
|
206 }
|
nuclear@0
|
207
|
nuclear@0
|
208 // process post behaviour
|
nuclear@0
|
209 switch ((*it).post) {
|
nuclear@0
|
210
|
nuclear@0
|
211 case LWO::PrePostBehaviour_OffsetRepeat:
|
nuclear@0
|
212 case LWO::PrePostBehaviour_Repeat:
|
nuclear@0
|
213 case LWO::PrePostBehaviour_Oscillate:
|
nuclear@0
|
214
|
nuclear@0
|
215 break;
|
nuclear@0
|
216
|
nuclear@0
|
217 default:
|
nuclear@0
|
218 // silence compiler warning
|
nuclear@0
|
219 break;
|
nuclear@0
|
220 }
|
nuclear@0
|
221 }
|
nuclear@0
|
222 }
|
nuclear@0
|
223
|
nuclear@0
|
224 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
225 // Extract bind pose matrix
|
nuclear@0
|
226 void AnimResolver::ExtractBindPose(aiMatrix4x4& out)
|
nuclear@0
|
227 {
|
nuclear@0
|
228 // If we have no envelopes, return identity
|
nuclear@0
|
229 if (envelopes.empty()) {
|
nuclear@0
|
230 out = aiMatrix4x4();
|
nuclear@0
|
231 return;
|
nuclear@0
|
232 }
|
nuclear@0
|
233 aiVector3D angles, scaling(1.f,1.f,1.f), translation;
|
nuclear@0
|
234
|
nuclear@0
|
235 if (trans_x) translation.x = trans_x->keys[0].value;
|
nuclear@0
|
236 if (trans_y) translation.y = trans_y->keys[0].value;
|
nuclear@0
|
237 if (trans_z) translation.z = trans_z->keys[0].value;
|
nuclear@0
|
238
|
nuclear@0
|
239 if (rotat_x) angles.x = rotat_x->keys[0].value;
|
nuclear@0
|
240 if (rotat_y) angles.y = rotat_y->keys[0].value;
|
nuclear@0
|
241 if (rotat_z) angles.z = rotat_z->keys[0].value;
|
nuclear@0
|
242
|
nuclear@0
|
243 if (scale_x) scaling.x = scale_x->keys[0].value;
|
nuclear@0
|
244 if (scale_y) scaling.y = scale_y->keys[0].value;
|
nuclear@0
|
245 if (scale_z) scaling.z = scale_z->keys[0].value;
|
nuclear@0
|
246
|
nuclear@0
|
247 // build the final matrix
|
nuclear@0
|
248 aiMatrix4x4 s,rx,ry,rz,t;
|
nuclear@0
|
249 aiMatrix4x4::RotationZ(angles.z, rz);
|
nuclear@0
|
250 aiMatrix4x4::RotationX(angles.y, rx);
|
nuclear@0
|
251 aiMatrix4x4::RotationY(angles.x, ry);
|
nuclear@0
|
252 aiMatrix4x4::Translation(translation,t);
|
nuclear@0
|
253 aiMatrix4x4::Scaling(scaling,s);
|
nuclear@0
|
254 out = t*ry*rx*rz*s;
|
nuclear@0
|
255 }
|
nuclear@0
|
256
|
nuclear@0
|
257 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
258 // Do a single interpolation on a channel
|
nuclear@0
|
259 void AnimResolver::DoInterpolation(std::vector<LWO::Key>::const_iterator cur,
|
nuclear@0
|
260 LWO::Envelope* envl,double time, float& fill)
|
nuclear@0
|
261 {
|
nuclear@0
|
262 if (envl->keys.size() == 1) {
|
nuclear@0
|
263 fill = envl->keys[0].value;
|
nuclear@0
|
264 return;
|
nuclear@0
|
265 }
|
nuclear@0
|
266
|
nuclear@0
|
267 // check whether we're at the beginning of the animation track
|
nuclear@0
|
268 if (cur == envl->keys.begin()) {
|
nuclear@0
|
269
|
nuclear@0
|
270 // ok ... this depends on pre behaviour now
|
nuclear@0
|
271 // we don't need to handle repeat&offset repeat&oszillate here, see UpdateAnimRangeSetup()
|
nuclear@0
|
272 switch (envl->pre)
|
nuclear@0
|
273 {
|
nuclear@0
|
274 case LWO::PrePostBehaviour_Linear:
|
nuclear@0
|
275 DoInterpolation2(cur,cur+1,time,fill);
|
nuclear@0
|
276 return;
|
nuclear@0
|
277
|
nuclear@0
|
278 case LWO::PrePostBehaviour_Reset:
|
nuclear@0
|
279 fill = 0.f;
|
nuclear@0
|
280 return;
|
nuclear@0
|
281
|
nuclear@0
|
282 default : //case LWO::PrePostBehaviour_Constant:
|
nuclear@0
|
283 fill = (*cur).value;
|
nuclear@0
|
284 return;
|
nuclear@0
|
285 }
|
nuclear@0
|
286 }
|
nuclear@0
|
287 // check whether we're at the end of the animation track
|
nuclear@0
|
288 else if (cur == envl->keys.end()-1 && time > envl->keys.rbegin()->time) {
|
nuclear@0
|
289 // ok ... this depends on post behaviour now
|
nuclear@0
|
290 switch (envl->post)
|
nuclear@0
|
291 {
|
nuclear@0
|
292 case LWO::PrePostBehaviour_Linear:
|
nuclear@0
|
293 DoInterpolation2(cur,cur-1,time,fill);
|
nuclear@0
|
294 return;
|
nuclear@0
|
295
|
nuclear@0
|
296 case LWO::PrePostBehaviour_Reset:
|
nuclear@0
|
297 fill = 0.f;
|
nuclear@0
|
298 return;
|
nuclear@0
|
299
|
nuclear@0
|
300 default : //case LWO::PrePostBehaviour_Constant:
|
nuclear@0
|
301 fill = (*cur).value;
|
nuclear@0
|
302 return;
|
nuclear@0
|
303 }
|
nuclear@0
|
304 }
|
nuclear@0
|
305
|
nuclear@0
|
306 // Otherwise do a simple interpolation
|
nuclear@0
|
307 DoInterpolation2(cur-1,cur,time,fill);
|
nuclear@0
|
308 }
|
nuclear@0
|
309
|
nuclear@0
|
310 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
311 // Almost the same, except we won't handle pre/post conditions here
|
nuclear@0
|
312 void AnimResolver::DoInterpolation2(std::vector<LWO::Key>::const_iterator beg,
|
nuclear@0
|
313 std::vector<LWO::Key>::const_iterator end,double time, float& fill)
|
nuclear@0
|
314 {
|
nuclear@0
|
315 switch ((*end).inter) {
|
nuclear@0
|
316
|
nuclear@0
|
317 case LWO::IT_STEP:
|
nuclear@0
|
318 // no interpolation at all - take the value of the last key
|
nuclear@0
|
319 fill = (*beg).value;
|
nuclear@0
|
320 return;
|
nuclear@0
|
321 default:
|
nuclear@0
|
322
|
nuclear@0
|
323 // silence compiler warning
|
nuclear@0
|
324 break;
|
nuclear@0
|
325 }
|
nuclear@0
|
326 // linear interpolation - default
|
nuclear@0
|
327 fill = (*beg).value + ((*end).value - (*beg).value)*(float)(((time - (*beg).time) / ((*end).time - (*beg).time)));
|
nuclear@0
|
328 }
|
nuclear@0
|
329
|
nuclear@0
|
330 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
331 // Subsample animation track by given key values
|
nuclear@0
|
332 void AnimResolver::SubsampleAnimTrack(std::vector<aiVectorKey>& /*out*/,
|
nuclear@0
|
333 double /*time*/ ,double /*sample_delta*/ )
|
nuclear@0
|
334 {
|
nuclear@0
|
335 //ai_assert(out.empty() && sample_delta);
|
nuclear@0
|
336
|
nuclear@0
|
337 //const double time_start = out.back().mTime;
|
nuclear@0
|
338 // for ()
|
nuclear@0
|
339 }
|
nuclear@0
|
340
|
nuclear@0
|
341 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
342 // Track interpolation
|
nuclear@0
|
343 void AnimResolver::InterpolateTrack(std::vector<aiVectorKey>& out,aiVectorKey& fill,double time)
|
nuclear@0
|
344 {
|
nuclear@0
|
345 // subsample animation track?
|
nuclear@0
|
346 if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) {
|
nuclear@0
|
347 SubsampleAnimTrack(out,time, sample_delta);
|
nuclear@0
|
348 }
|
nuclear@0
|
349
|
nuclear@0
|
350 fill.mTime = time;
|
nuclear@0
|
351
|
nuclear@0
|
352 // get x
|
nuclear@0
|
353 if ((*cur_x).time == time) {
|
nuclear@0
|
354 fill.mValue.x = (*cur_x).value;
|
nuclear@0
|
355
|
nuclear@0
|
356 if (cur_x != envl_x->keys.end()-1) /* increment x */
|
nuclear@0
|
357 ++cur_x;
|
nuclear@0
|
358 else end_x = true;
|
nuclear@0
|
359 }
|
nuclear@0
|
360 else DoInterpolation(cur_x,envl_x,time,(float&)fill.mValue.x);
|
nuclear@0
|
361
|
nuclear@0
|
362 // get y
|
nuclear@0
|
363 if ((*cur_y).time == time) {
|
nuclear@0
|
364 fill.mValue.y = (*cur_y).value;
|
nuclear@0
|
365
|
nuclear@0
|
366 if (cur_y != envl_y->keys.end()-1) /* increment y */
|
nuclear@0
|
367 ++cur_y;
|
nuclear@0
|
368 else end_y = true;
|
nuclear@0
|
369 }
|
nuclear@0
|
370 else DoInterpolation(cur_y,envl_y,time,(float&)fill.mValue.y);
|
nuclear@0
|
371
|
nuclear@0
|
372 // get z
|
nuclear@0
|
373 if ((*cur_z).time == time) {
|
nuclear@0
|
374 fill.mValue.z = (*cur_z).value;
|
nuclear@0
|
375
|
nuclear@0
|
376 if (cur_z != envl_z->keys.end()-1) /* increment z */
|
nuclear@0
|
377 ++cur_z;
|
nuclear@0
|
378 else end_x = true;
|
nuclear@0
|
379 }
|
nuclear@0
|
380 else DoInterpolation(cur_z,envl_z,time,(float&)fill.mValue.z);
|
nuclear@0
|
381 }
|
nuclear@0
|
382
|
nuclear@0
|
383 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
384 // Build linearly subsampled keys from three single envelopes, one for each component (x,y,z)
|
nuclear@0
|
385 void AnimResolver::GetKeys(std::vector<aiVectorKey>& out,
|
nuclear@0
|
386 LWO::Envelope* _envl_x,
|
nuclear@0
|
387 LWO::Envelope* _envl_y,
|
nuclear@0
|
388 LWO::Envelope* _envl_z,
|
nuclear@0
|
389 unsigned int _flags)
|
nuclear@0
|
390 {
|
nuclear@0
|
391 envl_x = _envl_x;
|
nuclear@0
|
392 envl_y = _envl_y;
|
nuclear@0
|
393 envl_z = _envl_z;
|
nuclear@0
|
394 flags = _flags;
|
nuclear@0
|
395
|
nuclear@0
|
396 // generate default channels if none are given
|
nuclear@0
|
397 LWO::Envelope def_x, def_y, def_z;
|
nuclear@0
|
398 LWO::Key key_dummy;
|
nuclear@0
|
399 key_dummy.time = 0.f;
|
nuclear@0
|
400 if ((envl_x && envl_x->type == LWO::EnvelopeType_Scaling_X) ||
|
nuclear@0
|
401 (envl_y && envl_y->type == LWO::EnvelopeType_Scaling_Y) ||
|
nuclear@0
|
402 (envl_z && envl_z->type == LWO::EnvelopeType_Scaling_Z)) {
|
nuclear@0
|
403 key_dummy.value = 1.f;
|
nuclear@0
|
404 }
|
nuclear@0
|
405 else key_dummy.value = 0.f;
|
nuclear@0
|
406
|
nuclear@0
|
407 if (!envl_x) {
|
nuclear@0
|
408 envl_x = &def_x;
|
nuclear@0
|
409 envl_x->keys.push_back(key_dummy);
|
nuclear@0
|
410 }
|
nuclear@0
|
411 if (!envl_y) {
|
nuclear@0
|
412 envl_y = &def_y;
|
nuclear@0
|
413 envl_y->keys.push_back(key_dummy);
|
nuclear@0
|
414 }
|
nuclear@0
|
415 if (!envl_z) {
|
nuclear@0
|
416 envl_z = &def_z;
|
nuclear@0
|
417 envl_z->keys.push_back(key_dummy);
|
nuclear@0
|
418 }
|
nuclear@0
|
419
|
nuclear@0
|
420 // guess how many keys we'll get
|
nuclear@0
|
421 size_t reserve;
|
nuclear@0
|
422 double sr = 1.;
|
nuclear@0
|
423 if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) {
|
nuclear@0
|
424 if (!sample_rate)
|
nuclear@0
|
425 sr = 100.f;
|
nuclear@0
|
426 else sr = sample_rate;
|
nuclear@0
|
427 sample_delta = 1.f / sr;
|
nuclear@0
|
428
|
nuclear@0
|
429 reserve = (size_t)(
|
nuclear@0
|
430 std::max( envl_x->keys.rbegin()->time,
|
nuclear@0
|
431 std::max( envl_y->keys.rbegin()->time, envl_z->keys.rbegin()->time )) * sr);
|
nuclear@0
|
432 }
|
nuclear@0
|
433 else reserve = std::max(envl_x->keys.size(),std::max(envl_x->keys.size(),envl_z->keys.size()));
|
nuclear@0
|
434 out.reserve(reserve+(reserve>>1));
|
nuclear@0
|
435
|
nuclear@0
|
436 // Iterate through all three arrays at once - it's tricky, but
|
nuclear@0
|
437 // rather interesting to implement.
|
nuclear@0
|
438 double lasttime = std::min(envl_x->keys[0].time,std::min(envl_y->keys[0].time,envl_z->keys[0].time));
|
nuclear@0
|
439
|
nuclear@0
|
440 cur_x = envl_x->keys.begin();
|
nuclear@0
|
441 cur_y = envl_y->keys.begin();
|
nuclear@0
|
442 cur_z = envl_z->keys.begin();
|
nuclear@0
|
443
|
nuclear@0
|
444 end_x = end_y = end_z = false;
|
nuclear@0
|
445 while (1) {
|
nuclear@0
|
446
|
nuclear@0
|
447 aiVectorKey fill;
|
nuclear@0
|
448
|
nuclear@0
|
449 if ((*cur_x).time == (*cur_y).time && (*cur_x).time == (*cur_z).time ) {
|
nuclear@0
|
450
|
nuclear@0
|
451 // we have a keyframe for all of them defined .. this means
|
nuclear@0
|
452 // we don't need to interpolate here.
|
nuclear@0
|
453 fill.mTime = (*cur_x).time;
|
nuclear@0
|
454
|
nuclear@0
|
455 fill.mValue.x = (*cur_x).value;
|
nuclear@0
|
456 fill.mValue.y = (*cur_y).value;
|
nuclear@0
|
457 fill.mValue.z = (*cur_z).value;
|
nuclear@0
|
458
|
nuclear@0
|
459 // subsample animation track
|
nuclear@0
|
460 if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) {
|
nuclear@0
|
461 //SubsampleAnimTrack(out,cur_x, cur_y, cur_z, d, sample_delta);
|
nuclear@0
|
462 }
|
nuclear@0
|
463 }
|
nuclear@0
|
464
|
nuclear@0
|
465 // Find key with lowest time value
|
nuclear@0
|
466 else if ((*cur_x).time <= (*cur_y).time && !end_x) {
|
nuclear@0
|
467
|
nuclear@0
|
468 if ((*cur_z).time <= (*cur_x).time && !end_z) {
|
nuclear@0
|
469 InterpolateTrack(out,fill,(*cur_z).time);
|
nuclear@0
|
470 }
|
nuclear@0
|
471 else {
|
nuclear@0
|
472 InterpolateTrack(out,fill,(*cur_x).time);
|
nuclear@0
|
473 }
|
nuclear@0
|
474 }
|
nuclear@0
|
475 else if ((*cur_z).time <= (*cur_y).time && !end_y) {
|
nuclear@0
|
476 InterpolateTrack(out,fill,(*cur_y).time);
|
nuclear@0
|
477 }
|
nuclear@0
|
478 else if (!end_y) {
|
nuclear@0
|
479 // welcome on the server, y
|
nuclear@0
|
480 InterpolateTrack(out,fill,(*cur_y).time);
|
nuclear@0
|
481 }
|
nuclear@0
|
482 else {
|
nuclear@0
|
483 // we have reached the end of at least 2 channels,
|
nuclear@0
|
484 // only one is remaining. Extrapolate the 2.
|
nuclear@0
|
485 if (end_y) {
|
nuclear@0
|
486 InterpolateTrack(out,fill,(end_x ? (*cur_z) : (*cur_x)).time);
|
nuclear@0
|
487 }
|
nuclear@0
|
488 else if (end_x) {
|
nuclear@0
|
489 InterpolateTrack(out,fill,(end_z ? (*cur_y) : (*cur_z)).time);
|
nuclear@0
|
490 }
|
nuclear@0
|
491 else { // if (end_z)
|
nuclear@0
|
492 InterpolateTrack(out,fill,(end_y ? (*cur_x) : (*cur_y)).time);
|
nuclear@0
|
493 }
|
nuclear@0
|
494 }
|
nuclear@0
|
495 lasttime = fill.mTime;
|
nuclear@0
|
496 out.push_back(fill);
|
nuclear@0
|
497
|
nuclear@0
|
498 if (lasttime >= (*cur_x).time) {
|
nuclear@0
|
499 if (cur_x != envl_x->keys.end()-1)
|
nuclear@0
|
500 ++cur_x;
|
nuclear@0
|
501 else end_x = true;
|
nuclear@0
|
502 }
|
nuclear@0
|
503 if (lasttime >= (*cur_y).time) {
|
nuclear@0
|
504 if (cur_y != envl_y->keys.end()-1)
|
nuclear@0
|
505 ++cur_y;
|
nuclear@0
|
506 else end_y = true;
|
nuclear@0
|
507 }
|
nuclear@0
|
508 if (lasttime >= (*cur_z).time) {
|
nuclear@0
|
509 if (cur_z != envl_z->keys.end()-1)
|
nuclear@0
|
510 ++cur_z;
|
nuclear@0
|
511 else end_z = true;
|
nuclear@0
|
512 }
|
nuclear@0
|
513
|
nuclear@0
|
514 if( end_x && end_y && end_z ) /* finished? */
|
nuclear@0
|
515 break;
|
nuclear@0
|
516 }
|
nuclear@0
|
517
|
nuclear@0
|
518 if (flags & AI_LWO_ANIM_FLAG_START_AT_ZERO) {
|
nuclear@0
|
519 for (std::vector<aiVectorKey>::iterator it = out.begin(); it != out.end(); ++it)
|
nuclear@0
|
520 (*it).mTime -= first;
|
nuclear@0
|
521 }
|
nuclear@0
|
522 }
|
nuclear@0
|
523
|
nuclear@0
|
524 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
525 // Extract animation channel
|
nuclear@0
|
526 void AnimResolver::ExtractAnimChannel(aiNodeAnim** out, unsigned int flags /*= 0*/)
|
nuclear@0
|
527 {
|
nuclear@0
|
528 *out = NULL;
|
nuclear@0
|
529
|
nuclear@0
|
530
|
nuclear@0
|
531 //FIXME: crashes if more than one component is animated at different timings, to be resolved.
|
nuclear@0
|
532
|
nuclear@0
|
533 // If we have no envelopes, return NULL
|
nuclear@0
|
534 if (envelopes.empty()) {
|
nuclear@0
|
535 return;
|
nuclear@0
|
536 }
|
nuclear@0
|
537
|
nuclear@0
|
538 // We won't spawn an animation channel if we don't have at least one envelope with more than one keyframe defined.
|
nuclear@0
|
539 const bool trans = ((trans_x && trans_x->keys.size() > 1) || (trans_y && trans_y->keys.size() > 1) || (trans_z && trans_z->keys.size() > 1));
|
nuclear@0
|
540 const bool rotat = ((rotat_x && rotat_x->keys.size() > 1) || (rotat_y && rotat_y->keys.size() > 1) || (rotat_z && rotat_z->keys.size() > 1));
|
nuclear@0
|
541 const bool scale = ((scale_x && scale_x->keys.size() > 1) || (scale_y && scale_y->keys.size() > 1) || (scale_z && scale_z->keys.size() > 1));
|
nuclear@0
|
542 if (!trans && !rotat && !scale)
|
nuclear@0
|
543 return;
|
nuclear@0
|
544
|
nuclear@0
|
545 // Allocate the output animation
|
nuclear@0
|
546 aiNodeAnim* anim = *out = new aiNodeAnim();
|
nuclear@0
|
547
|
nuclear@0
|
548 // Setup default animation setup if necessary
|
nuclear@0
|
549 if (need_to_setup) {
|
nuclear@0
|
550 UpdateAnimRangeSetup();
|
nuclear@0
|
551 need_to_setup = false;
|
nuclear@0
|
552 }
|
nuclear@0
|
553
|
nuclear@0
|
554 // copy translation keys
|
nuclear@0
|
555 if (trans) {
|
nuclear@0
|
556 std::vector<aiVectorKey> keys;
|
nuclear@0
|
557 GetKeys(keys,trans_x,trans_y,trans_z,flags);
|
nuclear@0
|
558
|
nuclear@0
|
559 anim->mPositionKeys = new aiVectorKey[ anim->mNumPositionKeys = keys.size() ];
|
nuclear@0
|
560 std::copy(keys.begin(),keys.end(),anim->mPositionKeys);
|
nuclear@0
|
561 }
|
nuclear@0
|
562
|
nuclear@0
|
563 // copy rotation keys
|
nuclear@0
|
564 if (rotat) {
|
nuclear@0
|
565 std::vector<aiVectorKey> keys;
|
nuclear@0
|
566 GetKeys(keys,rotat_x,rotat_y,rotat_z,flags);
|
nuclear@0
|
567
|
nuclear@0
|
568 anim->mRotationKeys = new aiQuatKey[ anim->mNumRotationKeys = keys.size() ];
|
nuclear@0
|
569
|
nuclear@0
|
570 // convert heading, pitch, bank to quaternion
|
nuclear@0
|
571 // mValue.x=Heading=Rot(Y), mValue.y=Pitch=Rot(X), mValue.z=Bank=Rot(Z)
|
nuclear@0
|
572 // Lightwave's rotation order is ZXY
|
nuclear@0
|
573 aiVector3D X(1.0,0.0,0.0);
|
nuclear@0
|
574 aiVector3D Y(0.0,1.0,0.0);
|
nuclear@0
|
575 aiVector3D Z(0.0,0.0,1.0);
|
nuclear@0
|
576 for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
|
nuclear@0
|
577 aiQuatKey& qk = anim->mRotationKeys[i];
|
nuclear@0
|
578 qk.mTime = keys[i].mTime;
|
nuclear@0
|
579 qk.mValue = aiQuaternion(Y,keys[i].mValue.x)*aiQuaternion(X,keys[i].mValue.y)*aiQuaternion(Z,keys[i].mValue.z);
|
nuclear@0
|
580 }
|
nuclear@0
|
581 }
|
nuclear@0
|
582
|
nuclear@0
|
583 // copy scaling keys
|
nuclear@0
|
584 if (scale) {
|
nuclear@0
|
585 std::vector<aiVectorKey> keys;
|
nuclear@0
|
586 GetKeys(keys,scale_x,scale_y,scale_z,flags);
|
nuclear@0
|
587
|
nuclear@0
|
588 anim->mScalingKeys = new aiVectorKey[ anim->mNumScalingKeys = keys.size() ];
|
nuclear@0
|
589 std::copy(keys.begin(),keys.end(),anim->mScalingKeys);
|
nuclear@0
|
590 }
|
nuclear@0
|
591 }
|
nuclear@0
|
592
|
nuclear@0
|
593
|
nuclear@0
|
594 #endif // no lwo or no lws
|