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