/* * Copyright 2007 (c) Tim Knip, ascollada.org. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ package org.ascollada.core { import org.ascollada.core.DaeEntity; /** * */ public class student_ar_org_ascollada_core_DaeAnimationCurve extends DaeEntity { public static const INTERPOLATION_STEP:uint = 0; //equivalent to no interpolation public static const INTERPOLATION_LINEAR:uint = 1; public static const INTERPOLATION_BEZIER:uint = 2; public static const INTERPOLATION_TCB:uint = 3; public static const INTERPOLATION_UNKNOWN:uint = 4; public static const INTERPOLATION_DEFAULT:uint = 0; public static const INFINITY_CONSTANT:uint = 0; public static const INFINITY_LINEAR:uint = 1; public static const INFINITY_CYCLE:uint = 2; public static const INFINITY_CYCLE_RELATIVE:uint = 3; public static const INFINITY_OSCILLATE:uint = 4; public static const INFINITY_UNKNOWN:uint = 5; public static const INFINITY_DEFAULT:uint = 0; public var keys:Array; public var keyValues:Array; public var interpolations:Array; public var inTangents:Array; public var outTangents:Array; public var tcbParameters:Array; public var easeInOuts:Array; public var preInfinity:uint = 0; public var postInfinity:uint = 0; public var interpolationType:uint = 1; /** * * @param keys * @param keyValues */ public function student_ar_org_ascollada_core_DaeAnimationCurve( keys:Array = null, keyValues:Array = null ):void { this.keys = keys || new Array(); this.keyValues = keyValues || new Array(); this.interpolations = new Array(); } /** * main workhorse for the animation system. * * @param time * * @return */ public function evaluate( dt:Number ):Number { // Check for empty curves and poses (curves with 1 key). if( !this.keys.length ) return 0.0; if( this.keys.length == 1 ) return this.keyValues[0]; var i:int; var outputStart:Number = this.keyValues[0]; var outputEnd:Number = this.keyValues[this.keyValues.length-1]; var inputStart:Number = this.keys[0]; var inputEnd:Number = this.keys[this.keys.length-1]; var inputSpan:Number = inputEnd - inputStart; var cycleCount:Number; dt = dt % inputEnd; // Account for pre-infinity mode var outputOffset:Number = 0.0; if( dt <= inputStart ) { switch( preInfinity ) { case INFINITY_CONSTANT: return outputStart; case INFINITY_LINEAR: return outputStart + (dt - inputStart) * (keyValues[1] - outputStart) / (keys[1] - inputStart); case INFINITY_CYCLE: { cycleCount = Math.ceil((inputStart - dt) / inputSpan); dt += cycleCount * inputSpan; break; } case INFINITY_CYCLE_RELATIVE: { cycleCount = Math.ceil((inputStart - dt) / inputSpan); dt += cycleCount * inputSpan; outputOffset -= cycleCount * (outputEnd - outputStart); break; } case INFINITY_OSCILLATE: { cycleCount = Math.ceil((inputStart - dt) / (2.0 * inputSpan)); dt += cycleCount * 2.0 * inputSpan; dt = inputEnd - Math.abs(dt - inputEnd); break; } case INFINITY_UNKNOWN: default: return outputStart; } } else if (dt >= inputEnd) { // Account for post-infinity mode switch (postInfinity) { case INFINITY_CONSTANT: return outputEnd; case INFINITY_LINEAR: return outputEnd + (dt - inputEnd) * (keyValues[keys.length - 2] - outputEnd) / (keys[keys.length - 2] - inputEnd); case INFINITY_CYCLE: { cycleCount = Math.ceil((dt - inputEnd) / inputSpan); dt -= cycleCount * inputSpan; break; } case INFINITY_CYCLE_RELATIVE: { cycleCount = Math.ceil((dt - inputEnd) / inputSpan); dt -= cycleCount * inputSpan; outputOffset += cycleCount * (outputEnd - outputStart); break; } case INFINITY_OSCILLATE: { cycleCount = Math.ceil((dt - inputEnd) / (2.0 * inputSpan)); dt -= cycleCount * 2.0 * inputSpan; dt = inputStart + Math.abs(dt - inputStart); break; } case INFINITY_UNKNOWN: default: return outputEnd; } } // speed up interval search var approxi:int = Math.ceil((dt/inputEnd) * this.keys.length); // Find the current interval for( i = approxi; i < this.keys.length; ++i ) if( this.keys[i] > dt ) break; var index:int = i; // Get the keys and values for this interval var endKey:Number = this.keys[index]; var startKey:Number = this.keys[index - 1]; var endValue:Number = this.keyValues[index]; var startValue:Number = this.keyValues[index - 1]; var output:Number; switch( interpolationType ) { case INTERPOLATION_LINEAR: output = (dt - startKey) / (endKey - startKey) * (endValue - startValue) + startValue; break; case INTERPOLATION_STEP: default: output = startValue; break; } return outputOffset + output; } } }