vrshoot
diff libs/assimp/LWOAnimation.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/LWOAnimation.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,594 @@ 1.4 +/* 1.5 +Open Asset Import Library (assimp) 1.6 +---------------------------------------------------------------------- 1.7 + 1.8 +Copyright (c) 2006-2012, assimp team 1.9 +All rights reserved. 1.10 + 1.11 +Redistribution and use of this software in source and binary forms, 1.12 +with or without modification, are permitted provided that the 1.13 +following conditions are met: 1.14 + 1.15 +* Redistributions of source code must retain the above 1.16 + copyright notice, this list of conditions and the 1.17 + following disclaimer. 1.18 + 1.19 +* Redistributions in binary form must reproduce the above 1.20 + copyright notice, this list of conditions and the 1.21 + following disclaimer in the documentation and/or other 1.22 + materials provided with the distribution. 1.23 + 1.24 +* Neither the name of the assimp team, nor the names of its 1.25 + contributors may be used to endorse or promote products 1.26 + derived from this software without specific prior 1.27 + written permission of the assimp team. 1.28 + 1.29 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.30 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.31 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.32 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.33 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.34 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.35 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.36 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.37 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.38 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.39 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.40 + 1.41 +---------------------------------------------------------------------- 1.42 +*/ 1.43 + 1.44 +/** @file LWOAnimation.cpp 1.45 + * @brief LWOAnimationResolver utility class 1.46 + * 1.47 + * It's a very generic implementation of LightWave's system of 1.48 + * componentwise-animated stuff. The one and only fully free 1.49 + * implementation of LightWave envelopes of which I know. 1.50 +*/ 1.51 + 1.52 +#include "AssimpPCH.h" 1.53 +#if (!defined ASSIMP_BUILD_NO_LWO_IMPORTER) && (!defined ASSIMP_BUILD_NO_LWS_IMPORTER) 1.54 + 1.55 +#include <functional> 1.56 + 1.57 +// internal headers 1.58 +#include "LWOFileData.h" 1.59 + 1.60 +using namespace Assimp; 1.61 +using namespace Assimp::LWO; 1.62 + 1.63 +// ------------------------------------------------------------------------------------------------ 1.64 +// Construct an animation resolver from a given list of envelopes 1.65 +AnimResolver::AnimResolver(std::list<Envelope>& _envelopes,double tick) 1.66 + : envelopes (_envelopes) 1.67 + , sample_rate (0.) 1.68 +{ 1.69 + trans_x = trans_y = trans_z = NULL; 1.70 + rotat_x = rotat_y = rotat_z = NULL; 1.71 + scale_x = scale_y = scale_z = NULL; 1.72 + 1.73 + first = last = 150392.; 1.74 + 1.75 + // find transformation envelopes 1.76 + for (std::list<LWO::Envelope>::iterator it = envelopes.begin(); it != envelopes.end(); ++it) { 1.77 + 1.78 + (*it).old_first = 0; 1.79 + (*it).old_last = (*it).keys.size()-1; 1.80 + 1.81 + if ((*it).keys.empty()) continue; 1.82 + switch ((*it).type) { 1.83 + 1.84 + // translation 1.85 + case LWO::EnvelopeType_Position_X: 1.86 + trans_x = &*it;break; 1.87 + case LWO::EnvelopeType_Position_Y: 1.88 + trans_y = &*it;break; 1.89 + case LWO::EnvelopeType_Position_Z: 1.90 + trans_z = &*it;break; 1.91 + 1.92 + // rotation 1.93 + case LWO::EnvelopeType_Rotation_Heading: 1.94 + rotat_x = &*it;break; 1.95 + case LWO::EnvelopeType_Rotation_Pitch: 1.96 + rotat_y = &*it;break; 1.97 + case LWO::EnvelopeType_Rotation_Bank: 1.98 + rotat_z = &*it;break; 1.99 + 1.100 + // scaling 1.101 + case LWO::EnvelopeType_Scaling_X: 1.102 + scale_x = &*it;break; 1.103 + case LWO::EnvelopeType_Scaling_Y: 1.104 + scale_y = &*it;break; 1.105 + case LWO::EnvelopeType_Scaling_Z: 1.106 + scale_z = &*it;break; 1.107 + default: 1.108 + continue; 1.109 + }; 1.110 + 1.111 + // convert from seconds to ticks 1.112 + for (std::vector<LWO::Key>::iterator d = (*it).keys.begin(); d != (*it).keys.end(); ++d) 1.113 + (*d).time *= tick; 1.114 + 1.115 + // set default animation range (minimum and maximum time value for which we have a keyframe) 1.116 + first = std::min(first, (*it).keys.front().time ); 1.117 + last = std::max(last, (*it).keys.back().time ); 1.118 + } 1.119 + 1.120 + // deferred setup of animation range to increase performance. 1.121 + // typically the application will want to specify its own. 1.122 + need_to_setup = true; 1.123 +} 1.124 + 1.125 +// ------------------------------------------------------------------------------------------------ 1.126 +// Reset all envelopes to their original contents 1.127 +void AnimResolver::ClearAnimRangeSetup() 1.128 +{ 1.129 + for (std::list<LWO::Envelope>::iterator it = envelopes.begin(); it != envelopes.end(); ++it) { 1.130 + 1.131 + (*it).keys.erase((*it).keys.begin(),(*it).keys.begin()+(*it).old_first); 1.132 + (*it).keys.erase((*it).keys.begin()+(*it).old_last+1,(*it).keys.end()); 1.133 + } 1.134 +} 1.135 + 1.136 +// ------------------------------------------------------------------------------------------------ 1.137 +// Insert additional keys to match LWO's pre& post behaviours. 1.138 +void AnimResolver::UpdateAnimRangeSetup() 1.139 +{ 1.140 + // XXX doesn't work yet (hangs if more than one envelope channels needs to be interpolated) 1.141 + 1.142 + for (std::list<LWO::Envelope>::iterator it = envelopes.begin(); it != envelopes.end(); ++it) { 1.143 + if ((*it).keys.empty()) continue; 1.144 + 1.145 + const double my_first = (*it).keys.front().time; 1.146 + const double my_last = (*it).keys.back().time; 1.147 + 1.148 + const double delta = my_last-my_first; 1.149 + const size_t old_size = (*it).keys.size(); 1.150 + 1.151 + const float value_delta = (*it).keys.back().value - (*it).keys.front().value; 1.152 + 1.153 + // NOTE: We won't handle reset, linear and constant here. 1.154 + // See DoInterpolation() for their implementation. 1.155 + 1.156 + // process pre behaviour 1.157 + switch ((*it).pre) { 1.158 + case LWO::PrePostBehaviour_OffsetRepeat: 1.159 + case LWO::PrePostBehaviour_Repeat: 1.160 + case LWO::PrePostBehaviour_Oscillate: 1.161 + { 1.162 + const double start_time = delta - fmod(my_first-first,delta); 1.163 + std::vector<LWO::Key>::iterator n = std::find_if((*it).keys.begin(),(*it).keys.end(), 1.164 + std::bind1st(std::greater<double>(),start_time)),m; 1.165 + 1.166 + size_t ofs = 0; 1.167 + if (n != (*it).keys.end()) { 1.168 + // copy from here - don't use iterators, insert() would invalidate them 1.169 + ofs = (*it).keys.end()-n; 1.170 + (*it).keys.insert((*it).keys.begin(),ofs,LWO::Key()); 1.171 + 1.172 + std::copy((*it).keys.end()-ofs,(*it).keys.end(),(*it).keys.begin()); 1.173 + } 1.174 + 1.175 + // do full copies. again, no iterators 1.176 + const unsigned int num = (unsigned int)((my_first-first) / delta); 1.177 + (*it).keys.resize((*it).keys.size() + num*old_size); 1.178 + 1.179 + n = (*it).keys.begin()+ofs; 1.180 + bool reverse = false; 1.181 + for (unsigned int i = 0; i < num; ++i) { 1.182 + m = n+old_size*(i+1); 1.183 + std::copy(n,n+old_size,m); 1.184 + 1.185 + if ((*it).pre == LWO::PrePostBehaviour_Oscillate && (reverse = !reverse)) 1.186 + std::reverse(m,m+old_size-1); 1.187 + } 1.188 + 1.189 + // update time values 1.190 + n = (*it).keys.end() - (old_size+1); 1.191 + double cur_minus = delta; 1.192 + unsigned int tt = 1; 1.193 + for (const double tmp = delta*(num+1);cur_minus <= tmp;cur_minus += delta,++tt) { 1.194 + m = (delta == tmp ? (*it).keys.begin() : n - (old_size+1)); 1.195 + for (;m != n; --n) { 1.196 + (*n).time -= cur_minus; 1.197 + 1.198 + // offset repeat? add delta offset to key value 1.199 + if ((*it).pre == LWO::PrePostBehaviour_OffsetRepeat) { 1.200 + (*n).value += tt * value_delta; 1.201 + } 1.202 + } 1.203 + } 1.204 + break; 1.205 + } 1.206 + default: 1.207 + // silence compiler warning 1.208 + break; 1.209 + } 1.210 + 1.211 + // process post behaviour 1.212 + switch ((*it).post) { 1.213 + 1.214 + case LWO::PrePostBehaviour_OffsetRepeat: 1.215 + case LWO::PrePostBehaviour_Repeat: 1.216 + case LWO::PrePostBehaviour_Oscillate: 1.217 + 1.218 + break; 1.219 + 1.220 + default: 1.221 + // silence compiler warning 1.222 + break; 1.223 + } 1.224 + } 1.225 +} 1.226 + 1.227 +// ------------------------------------------------------------------------------------------------ 1.228 +// Extract bind pose matrix 1.229 +void AnimResolver::ExtractBindPose(aiMatrix4x4& out) 1.230 +{ 1.231 + // If we have no envelopes, return identity 1.232 + if (envelopes.empty()) { 1.233 + out = aiMatrix4x4(); 1.234 + return; 1.235 + } 1.236 + aiVector3D angles, scaling(1.f,1.f,1.f), translation; 1.237 + 1.238 + if (trans_x) translation.x = trans_x->keys[0].value; 1.239 + if (trans_y) translation.y = trans_y->keys[0].value; 1.240 + if (trans_z) translation.z = trans_z->keys[0].value; 1.241 + 1.242 + if (rotat_x) angles.x = rotat_x->keys[0].value; 1.243 + if (rotat_y) angles.y = rotat_y->keys[0].value; 1.244 + if (rotat_z) angles.z = rotat_z->keys[0].value; 1.245 + 1.246 + if (scale_x) scaling.x = scale_x->keys[0].value; 1.247 + if (scale_y) scaling.y = scale_y->keys[0].value; 1.248 + if (scale_z) scaling.z = scale_z->keys[0].value; 1.249 + 1.250 + // build the final matrix 1.251 + aiMatrix4x4 s,rx,ry,rz,t; 1.252 + aiMatrix4x4::RotationZ(angles.z, rz); 1.253 + aiMatrix4x4::RotationX(angles.y, rx); 1.254 + aiMatrix4x4::RotationY(angles.x, ry); 1.255 + aiMatrix4x4::Translation(translation,t); 1.256 + aiMatrix4x4::Scaling(scaling,s); 1.257 + out = t*ry*rx*rz*s; 1.258 +} 1.259 + 1.260 +// ------------------------------------------------------------------------------------------------ 1.261 +// Do a single interpolation on a channel 1.262 +void AnimResolver::DoInterpolation(std::vector<LWO::Key>::const_iterator cur, 1.263 + LWO::Envelope* envl,double time, float& fill) 1.264 +{ 1.265 + if (envl->keys.size() == 1) { 1.266 + fill = envl->keys[0].value; 1.267 + return; 1.268 + } 1.269 + 1.270 + // check whether we're at the beginning of the animation track 1.271 + if (cur == envl->keys.begin()) { 1.272 + 1.273 + // ok ... this depends on pre behaviour now 1.274 + // we don't need to handle repeat&offset repeat&oszillate here, see UpdateAnimRangeSetup() 1.275 + switch (envl->pre) 1.276 + { 1.277 + case LWO::PrePostBehaviour_Linear: 1.278 + DoInterpolation2(cur,cur+1,time,fill); 1.279 + return; 1.280 + 1.281 + case LWO::PrePostBehaviour_Reset: 1.282 + fill = 0.f; 1.283 + return; 1.284 + 1.285 + default : //case LWO::PrePostBehaviour_Constant: 1.286 + fill = (*cur).value; 1.287 + return; 1.288 + } 1.289 + } 1.290 + // check whether we're at the end of the animation track 1.291 + else if (cur == envl->keys.end()-1 && time > envl->keys.rbegin()->time) { 1.292 + // ok ... this depends on post behaviour now 1.293 + switch (envl->post) 1.294 + { 1.295 + case LWO::PrePostBehaviour_Linear: 1.296 + DoInterpolation2(cur,cur-1,time,fill); 1.297 + return; 1.298 + 1.299 + case LWO::PrePostBehaviour_Reset: 1.300 + fill = 0.f; 1.301 + return; 1.302 + 1.303 + default : //case LWO::PrePostBehaviour_Constant: 1.304 + fill = (*cur).value; 1.305 + return; 1.306 + } 1.307 + } 1.308 + 1.309 + // Otherwise do a simple interpolation 1.310 + DoInterpolation2(cur-1,cur,time,fill); 1.311 +} 1.312 + 1.313 +// ------------------------------------------------------------------------------------------------ 1.314 +// Almost the same, except we won't handle pre/post conditions here 1.315 +void AnimResolver::DoInterpolation2(std::vector<LWO::Key>::const_iterator beg, 1.316 + std::vector<LWO::Key>::const_iterator end,double time, float& fill) 1.317 +{ 1.318 + switch ((*end).inter) { 1.319 + 1.320 + case LWO::IT_STEP: 1.321 + // no interpolation at all - take the value of the last key 1.322 + fill = (*beg).value; 1.323 + return; 1.324 + default: 1.325 + 1.326 + // silence compiler warning 1.327 + break; 1.328 + } 1.329 + // linear interpolation - default 1.330 + fill = (*beg).value + ((*end).value - (*beg).value)*(float)(((time - (*beg).time) / ((*end).time - (*beg).time))); 1.331 +} 1.332 + 1.333 +// ------------------------------------------------------------------------------------------------ 1.334 +// Subsample animation track by given key values 1.335 +void AnimResolver::SubsampleAnimTrack(std::vector<aiVectorKey>& /*out*/, 1.336 + double /*time*/ ,double /*sample_delta*/ ) 1.337 +{ 1.338 + //ai_assert(out.empty() && sample_delta); 1.339 + 1.340 + //const double time_start = out.back().mTime; 1.341 +// for () 1.342 +} 1.343 + 1.344 +// ------------------------------------------------------------------------------------------------ 1.345 +// Track interpolation 1.346 +void AnimResolver::InterpolateTrack(std::vector<aiVectorKey>& out,aiVectorKey& fill,double time) 1.347 +{ 1.348 + // subsample animation track? 1.349 + if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) { 1.350 + SubsampleAnimTrack(out,time, sample_delta); 1.351 + } 1.352 + 1.353 + fill.mTime = time; 1.354 + 1.355 + // get x 1.356 + if ((*cur_x).time == time) { 1.357 + fill.mValue.x = (*cur_x).value; 1.358 + 1.359 + if (cur_x != envl_x->keys.end()-1) /* increment x */ 1.360 + ++cur_x; 1.361 + else end_x = true; 1.362 + } 1.363 + else DoInterpolation(cur_x,envl_x,time,(float&)fill.mValue.x); 1.364 + 1.365 + // get y 1.366 + if ((*cur_y).time == time) { 1.367 + fill.mValue.y = (*cur_y).value; 1.368 + 1.369 + if (cur_y != envl_y->keys.end()-1) /* increment y */ 1.370 + ++cur_y; 1.371 + else end_y = true; 1.372 + } 1.373 + else DoInterpolation(cur_y,envl_y,time,(float&)fill.mValue.y); 1.374 + 1.375 + // get z 1.376 + if ((*cur_z).time == time) { 1.377 + fill.mValue.z = (*cur_z).value; 1.378 + 1.379 + if (cur_z != envl_z->keys.end()-1) /* increment z */ 1.380 + ++cur_z; 1.381 + else end_x = true; 1.382 + } 1.383 + else DoInterpolation(cur_z,envl_z,time,(float&)fill.mValue.z); 1.384 +} 1.385 + 1.386 +// ------------------------------------------------------------------------------------------------ 1.387 +// Build linearly subsampled keys from three single envelopes, one for each component (x,y,z) 1.388 +void AnimResolver::GetKeys(std::vector<aiVectorKey>& out, 1.389 + LWO::Envelope* _envl_x, 1.390 + LWO::Envelope* _envl_y, 1.391 + LWO::Envelope* _envl_z, 1.392 + unsigned int _flags) 1.393 +{ 1.394 + envl_x = _envl_x; 1.395 + envl_y = _envl_y; 1.396 + envl_z = _envl_z; 1.397 + flags = _flags; 1.398 + 1.399 + // generate default channels if none are given 1.400 + LWO::Envelope def_x, def_y, def_z; 1.401 + LWO::Key key_dummy; 1.402 + key_dummy.time = 0.f; 1.403 + if ((envl_x && envl_x->type == LWO::EnvelopeType_Scaling_X) || 1.404 + (envl_y && envl_y->type == LWO::EnvelopeType_Scaling_Y) || 1.405 + (envl_z && envl_z->type == LWO::EnvelopeType_Scaling_Z)) { 1.406 + key_dummy.value = 1.f; 1.407 + } 1.408 + else key_dummy.value = 0.f; 1.409 + 1.410 + if (!envl_x) { 1.411 + envl_x = &def_x; 1.412 + envl_x->keys.push_back(key_dummy); 1.413 + } 1.414 + if (!envl_y) { 1.415 + envl_y = &def_y; 1.416 + envl_y->keys.push_back(key_dummy); 1.417 + } 1.418 + if (!envl_z) { 1.419 + envl_z = &def_z; 1.420 + envl_z->keys.push_back(key_dummy); 1.421 + } 1.422 + 1.423 + // guess how many keys we'll get 1.424 + size_t reserve; 1.425 + double sr = 1.; 1.426 + if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) { 1.427 + if (!sample_rate) 1.428 + sr = 100.f; 1.429 + else sr = sample_rate; 1.430 + sample_delta = 1.f / sr; 1.431 + 1.432 + reserve = (size_t)( 1.433 + std::max( envl_x->keys.rbegin()->time, 1.434 + std::max( envl_y->keys.rbegin()->time, envl_z->keys.rbegin()->time )) * sr); 1.435 + } 1.436 + else reserve = std::max(envl_x->keys.size(),std::max(envl_x->keys.size(),envl_z->keys.size())); 1.437 + out.reserve(reserve+(reserve>>1)); 1.438 + 1.439 + // Iterate through all three arrays at once - it's tricky, but 1.440 + // rather interesting to implement. 1.441 + double lasttime = std::min(envl_x->keys[0].time,std::min(envl_y->keys[0].time,envl_z->keys[0].time)); 1.442 + 1.443 + cur_x = envl_x->keys.begin(); 1.444 + cur_y = envl_y->keys.begin(); 1.445 + cur_z = envl_z->keys.begin(); 1.446 + 1.447 + end_x = end_y = end_z = false; 1.448 + while (1) { 1.449 + 1.450 + aiVectorKey fill; 1.451 + 1.452 + if ((*cur_x).time == (*cur_y).time && (*cur_x).time == (*cur_z).time ) { 1.453 + 1.454 + // we have a keyframe for all of them defined .. this means 1.455 + // we don't need to interpolate here. 1.456 + fill.mTime = (*cur_x).time; 1.457 + 1.458 + fill.mValue.x = (*cur_x).value; 1.459 + fill.mValue.y = (*cur_y).value; 1.460 + fill.mValue.z = (*cur_z).value; 1.461 + 1.462 + // subsample animation track 1.463 + if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) { 1.464 + //SubsampleAnimTrack(out,cur_x, cur_y, cur_z, d, sample_delta); 1.465 + } 1.466 + } 1.467 + 1.468 + // Find key with lowest time value 1.469 + else if ((*cur_x).time <= (*cur_y).time && !end_x) { 1.470 + 1.471 + if ((*cur_z).time <= (*cur_x).time && !end_z) { 1.472 + InterpolateTrack(out,fill,(*cur_z).time); 1.473 + } 1.474 + else { 1.475 + InterpolateTrack(out,fill,(*cur_x).time); 1.476 + } 1.477 + } 1.478 + else if ((*cur_z).time <= (*cur_y).time && !end_y) { 1.479 + InterpolateTrack(out,fill,(*cur_y).time); 1.480 + } 1.481 + else if (!end_y) { 1.482 + // welcome on the server, y 1.483 + InterpolateTrack(out,fill,(*cur_y).time); 1.484 + } 1.485 + else { 1.486 + // we have reached the end of at least 2 channels, 1.487 + // only one is remaining. Extrapolate the 2. 1.488 + if (end_y) { 1.489 + InterpolateTrack(out,fill,(end_x ? (*cur_z) : (*cur_x)).time); 1.490 + } 1.491 + else if (end_x) { 1.492 + InterpolateTrack(out,fill,(end_z ? (*cur_y) : (*cur_z)).time); 1.493 + } 1.494 + else { // if (end_z) 1.495 + InterpolateTrack(out,fill,(end_y ? (*cur_x) : (*cur_y)).time); 1.496 + } 1.497 + } 1.498 + lasttime = fill.mTime; 1.499 + out.push_back(fill); 1.500 + 1.501 + if (lasttime >= (*cur_x).time) { 1.502 + if (cur_x != envl_x->keys.end()-1) 1.503 + ++cur_x; 1.504 + else end_x = true; 1.505 + } 1.506 + if (lasttime >= (*cur_y).time) { 1.507 + if (cur_y != envl_y->keys.end()-1) 1.508 + ++cur_y; 1.509 + else end_y = true; 1.510 + } 1.511 + if (lasttime >= (*cur_z).time) { 1.512 + if (cur_z != envl_z->keys.end()-1) 1.513 + ++cur_z; 1.514 + else end_z = true; 1.515 + } 1.516 + 1.517 + if( end_x && end_y && end_z ) /* finished? */ 1.518 + break; 1.519 + } 1.520 + 1.521 + if (flags & AI_LWO_ANIM_FLAG_START_AT_ZERO) { 1.522 + for (std::vector<aiVectorKey>::iterator it = out.begin(); it != out.end(); ++it) 1.523 + (*it).mTime -= first; 1.524 + } 1.525 +} 1.526 + 1.527 +// ------------------------------------------------------------------------------------------------ 1.528 +// Extract animation channel 1.529 +void AnimResolver::ExtractAnimChannel(aiNodeAnim** out, unsigned int flags /*= 0*/) 1.530 +{ 1.531 + *out = NULL; 1.532 + 1.533 + 1.534 + //FIXME: crashes if more than one component is animated at different timings, to be resolved. 1.535 + 1.536 + // If we have no envelopes, return NULL 1.537 + if (envelopes.empty()) { 1.538 + return; 1.539 + } 1.540 + 1.541 + // We won't spawn an animation channel if we don't have at least one envelope with more than one keyframe defined. 1.542 + const bool trans = ((trans_x && trans_x->keys.size() > 1) || (trans_y && trans_y->keys.size() > 1) || (trans_z && trans_z->keys.size() > 1)); 1.543 + const bool rotat = ((rotat_x && rotat_x->keys.size() > 1) || (rotat_y && rotat_y->keys.size() > 1) || (rotat_z && rotat_z->keys.size() > 1)); 1.544 + const bool scale = ((scale_x && scale_x->keys.size() > 1) || (scale_y && scale_y->keys.size() > 1) || (scale_z && scale_z->keys.size() > 1)); 1.545 + if (!trans && !rotat && !scale) 1.546 + return; 1.547 + 1.548 + // Allocate the output animation 1.549 + aiNodeAnim* anim = *out = new aiNodeAnim(); 1.550 + 1.551 + // Setup default animation setup if necessary 1.552 + if (need_to_setup) { 1.553 + UpdateAnimRangeSetup(); 1.554 + need_to_setup = false; 1.555 + } 1.556 + 1.557 + // copy translation keys 1.558 + if (trans) { 1.559 + std::vector<aiVectorKey> keys; 1.560 + GetKeys(keys,trans_x,trans_y,trans_z,flags); 1.561 + 1.562 + anim->mPositionKeys = new aiVectorKey[ anim->mNumPositionKeys = keys.size() ]; 1.563 + std::copy(keys.begin(),keys.end(),anim->mPositionKeys); 1.564 + } 1.565 + 1.566 + // copy rotation keys 1.567 + if (rotat) { 1.568 + std::vector<aiVectorKey> keys; 1.569 + GetKeys(keys,rotat_x,rotat_y,rotat_z,flags); 1.570 + 1.571 + anim->mRotationKeys = new aiQuatKey[ anim->mNumRotationKeys = keys.size() ]; 1.572 + 1.573 + // convert heading, pitch, bank to quaternion 1.574 + // mValue.x=Heading=Rot(Y), mValue.y=Pitch=Rot(X), mValue.z=Bank=Rot(Z) 1.575 + // Lightwave's rotation order is ZXY 1.576 + aiVector3D X(1.0,0.0,0.0); 1.577 + aiVector3D Y(0.0,1.0,0.0); 1.578 + aiVector3D Z(0.0,0.0,1.0); 1.579 + for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) { 1.580 + aiQuatKey& qk = anim->mRotationKeys[i]; 1.581 + qk.mTime = keys[i].mTime; 1.582 + qk.mValue = aiQuaternion(Y,keys[i].mValue.x)*aiQuaternion(X,keys[i].mValue.y)*aiQuaternion(Z,keys[i].mValue.z); 1.583 + } 1.584 + } 1.585 + 1.586 + // copy scaling keys 1.587 + if (scale) { 1.588 + std::vector<aiVectorKey> keys; 1.589 + GetKeys(keys,scale_x,scale_y,scale_z,flags); 1.590 + 1.591 + anim->mScalingKeys = new aiVectorKey[ anim->mNumScalingKeys = keys.size() ]; 1.592 + std::copy(keys.begin(),keys.end(),anim->mScalingKeys); 1.593 + } 1.594 +} 1.595 + 1.596 + 1.597 +#endif // no lwo or no lws