| import { |
| InterpolateLinear, |
| InterpolateSmooth, |
| InterpolateDiscrete |
| } from '../constants.js'; |
| import { CubicInterpolant } from '../math/interpolants/CubicInterpolant.js'; |
| import { LinearInterpolant } from '../math/interpolants/LinearInterpolant.js'; |
| import { DiscreteInterpolant } from '../math/interpolants/DiscreteInterpolant.js'; |
| import { AnimationUtils } from './AnimationUtils.js'; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| function KeyframeTrack( name, times, values, interpolation ) { |
|
|
| if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); |
| if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); |
|
|
| this.name = name; |
|
|
| this.times = AnimationUtils.convertArray( times, this.TimeBufferType ); |
| this.values = AnimationUtils.convertArray( values, this.ValueBufferType ); |
|
|
| this.setInterpolation( interpolation || this.DefaultInterpolation ); |
|
|
| } |
|
|
| |
|
|
| Object.assign( KeyframeTrack, { |
|
|
| |
| |
|
|
| toJSON: function ( track ) { |
|
|
| var trackType = track.constructor; |
|
|
| var json; |
|
|
| |
| if ( trackType.toJSON !== undefined ) { |
|
|
| json = trackType.toJSON( track ); |
|
|
| } else { |
|
|
| |
| json = { |
|
|
| 'name': track.name, |
| 'times': AnimationUtils.convertArray( track.times, Array ), |
| 'values': AnimationUtils.convertArray( track.values, Array ) |
|
|
| }; |
|
|
| var interpolation = track.getInterpolation(); |
|
|
| if ( interpolation !== track.DefaultInterpolation ) { |
|
|
| json.interpolation = interpolation; |
|
|
| } |
|
|
| } |
|
|
| json.type = track.ValueTypeName; |
|
|
| return json; |
|
|
| } |
|
|
| } ); |
|
|
| Object.assign( KeyframeTrack.prototype, { |
|
|
| constructor: KeyframeTrack, |
|
|
| TimeBufferType: Float32Array, |
|
|
| ValueBufferType: Float32Array, |
|
|
| DefaultInterpolation: InterpolateLinear, |
|
|
| InterpolantFactoryMethodDiscrete: function ( result ) { |
|
|
| return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); |
|
|
| }, |
|
|
| InterpolantFactoryMethodLinear: function ( result ) { |
|
|
| return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); |
|
|
| }, |
|
|
| InterpolantFactoryMethodSmooth: function ( result ) { |
|
|
| return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); |
|
|
| }, |
|
|
| setInterpolation: function ( interpolation ) { |
|
|
| var factoryMethod; |
|
|
| switch ( interpolation ) { |
|
|
| case InterpolateDiscrete: |
|
|
| factoryMethod = this.InterpolantFactoryMethodDiscrete; |
|
|
| break; |
|
|
| case InterpolateLinear: |
|
|
| factoryMethod = this.InterpolantFactoryMethodLinear; |
|
|
| break; |
|
|
| case InterpolateSmooth: |
|
|
| factoryMethod = this.InterpolantFactoryMethodSmooth; |
|
|
| break; |
|
|
| } |
|
|
| if ( factoryMethod === undefined ) { |
|
|
| var message = "unsupported interpolation for " + |
| this.ValueTypeName + " keyframe track named " + this.name; |
|
|
| if ( this.createInterpolant === undefined ) { |
|
|
| |
| if ( interpolation !== this.DefaultInterpolation ) { |
|
|
| this.setInterpolation( this.DefaultInterpolation ); |
|
|
| } else { |
|
|
| throw new Error( message ); |
|
|
| } |
|
|
| } |
|
|
| console.warn( 'THREE.KeyframeTrack:', message ); |
| return this; |
|
|
| } |
|
|
| this.createInterpolant = factoryMethod; |
|
|
| return this; |
|
|
| }, |
|
|
| getInterpolation: function () { |
|
|
| switch ( this.createInterpolant ) { |
|
|
| case this.InterpolantFactoryMethodDiscrete: |
|
|
| return InterpolateDiscrete; |
|
|
| case this.InterpolantFactoryMethodLinear: |
|
|
| return InterpolateLinear; |
|
|
| case this.InterpolantFactoryMethodSmooth: |
|
|
| return InterpolateSmooth; |
|
|
| } |
|
|
| }, |
|
|
| getValueSize: function () { |
|
|
| return this.values.length / this.times.length; |
|
|
| }, |
|
|
| |
| shift: function ( timeOffset ) { |
|
|
| if ( timeOffset !== 0.0 ) { |
|
|
| var times = this.times; |
|
|
| for ( var i = 0, n = times.length; i !== n; ++ i ) { |
|
|
| times[ i ] += timeOffset; |
|
|
| } |
|
|
| } |
|
|
| return this; |
|
|
| }, |
|
|
| |
| scale: function ( timeScale ) { |
|
|
| if ( timeScale !== 1.0 ) { |
|
|
| var times = this.times; |
|
|
| for ( var i = 0, n = times.length; i !== n; ++ i ) { |
|
|
| times[ i ] *= timeScale; |
|
|
| } |
|
|
| } |
|
|
| return this; |
|
|
| }, |
|
|
| |
| |
| trim: function ( startTime, endTime ) { |
|
|
| var times = this.times, |
| nKeys = times.length, |
| from = 0, |
| to = nKeys - 1; |
|
|
| while ( from !== nKeys && times[ from ] < startTime ) { |
|
|
| ++ from; |
|
|
| } |
|
|
| while ( to !== - 1 && times[ to ] > endTime ) { |
|
|
| -- to; |
|
|
| } |
|
|
| ++ to; |
|
|
| if ( from !== 0 || to !== nKeys ) { |
|
|
| |
| if ( from >= to ) to = Math.max( to, 1 ), from = to - 1; |
|
|
| var stride = this.getValueSize(); |
| this.times = AnimationUtils.arraySlice( times, from, to ); |
| this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride ); |
|
|
| } |
|
|
| return this; |
|
|
| }, |
|
|
| |
| validate: function () { |
|
|
| var valid = true; |
|
|
| var valueSize = this.getValueSize(); |
| if ( valueSize - Math.floor( valueSize ) !== 0 ) { |
|
|
| console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); |
| valid = false; |
|
|
| } |
|
|
| var times = this.times, |
| values = this.values, |
|
|
| nKeys = times.length; |
|
|
| if ( nKeys === 0 ) { |
|
|
| console.error( 'THREE.KeyframeTrack: Track is empty.', this ); |
| valid = false; |
|
|
| } |
|
|
| var prevTime = null; |
|
|
| for ( var i = 0; i !== nKeys; i ++ ) { |
|
|
| var currTime = times[ i ]; |
|
|
| if ( typeof currTime === 'number' && isNaN( currTime ) ) { |
|
|
| console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); |
| valid = false; |
| break; |
|
|
| } |
|
|
| if ( prevTime !== null && prevTime > currTime ) { |
|
|
| console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); |
| valid = false; |
| break; |
|
|
| } |
|
|
| prevTime = currTime; |
|
|
| } |
|
|
| if ( values !== undefined ) { |
|
|
| if ( AnimationUtils.isTypedArray( values ) ) { |
|
|
| for ( var i = 0, n = values.length; i !== n; ++ i ) { |
|
|
| var value = values[ i ]; |
|
|
| if ( isNaN( value ) ) { |
|
|
| console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); |
| valid = false; |
| break; |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| return valid; |
|
|
| }, |
|
|
| |
| |
| optimize: function () { |
|
|
| var times = this.times, |
| values = this.values, |
| stride = this.getValueSize(), |
|
|
| smoothInterpolation = this.getInterpolation() === InterpolateSmooth, |
|
|
| writeIndex = 1, |
| lastIndex = times.length - 1; |
|
|
| for ( var i = 1; i < lastIndex; ++ i ) { |
|
|
| var keep = false; |
|
|
| var time = times[ i ]; |
| var timeNext = times[ i + 1 ]; |
|
|
| |
|
|
| if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) { |
|
|
| if ( ! smoothInterpolation ) { |
|
|
| |
|
|
| var offset = i * stride, |
| offsetP = offset - stride, |
| offsetN = offset + stride; |
|
|
| for ( var j = 0; j !== stride; ++ j ) { |
|
|
| var value = values[ offset + j ]; |
|
|
| if ( value !== values[ offsetP + j ] || |
| value !== values[ offsetN + j ] ) { |
|
|
| keep = true; |
| break; |
|
|
| } |
|
|
| } |
|
|
| } else { |
|
|
| keep = true; |
|
|
| } |
|
|
| } |
|
|
| |
|
|
| if ( keep ) { |
|
|
| if ( i !== writeIndex ) { |
|
|
| times[ writeIndex ] = times[ i ]; |
|
|
| var readOffset = i * stride, |
| writeOffset = writeIndex * stride; |
|
|
| for ( var j = 0; j !== stride; ++ j ) { |
|
|
| values[ writeOffset + j ] = values[ readOffset + j ]; |
|
|
| } |
|
|
| } |
|
|
| ++ writeIndex; |
|
|
| } |
|
|
| } |
|
|
| |
|
|
| if ( lastIndex > 0 ) { |
|
|
| times[ writeIndex ] = times[ lastIndex ]; |
|
|
| for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { |
|
|
| values[ writeOffset + j ] = values[ readOffset + j ]; |
|
|
| } |
|
|
| ++ writeIndex; |
|
|
| } |
|
|
| if ( writeIndex !== times.length ) { |
|
|
| this.times = AnimationUtils.arraySlice( times, 0, writeIndex ); |
| this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride ); |
|
|
| } |
|
|
| return this; |
|
|
| }, |
|
|
| clone: function () { |
|
|
| var times = AnimationUtils.arraySlice( this.times, 0 ); |
| var values = AnimationUtils.arraySlice( this.values, 0 ); |
|
|
| var TypedKeyframeTrack = this.constructor; |
| var track = new TypedKeyframeTrack( this.name, times, values ); |
|
|
| |
| track.createInterpolant = this.createInterpolant; |
|
|
| return track; |
|
|
| } |
|
|
| } ); |
|
|
| export { KeyframeTrack }; |
|
|