vrshoot

annotate libs/assimp/LWOAnimation.cpp @ 1:e7ca128b8713

looks nice :)
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 02 Feb 2014 00:35:22 +0200
parents
children
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