提交 d4d514a1 编写于 作者: M Mr.doob

Updated builds.

上级 ce31424c
......@@ -31480,168 +31480,69 @@
} );
/**
* @author tschw
*
* A Track that interpolates Strings
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
var AnimationUtils = {
// same as Array.prototype.slice, but also works on typed arrays
arraySlice: function ( array, from, to ) {
if ( AnimationUtils.isTypedArray( array ) ) {
// in ios9 array.subarray(from, undefined) will return empty array
// but array.subarray(from) or array.subarray(from, len) is correct
return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );
}
return array.slice( from, to );
},
// converts an array to a specific type
convertArray: function ( array, type, forceClone ) {
if ( ! array || // let 'undefined' and 'null' pass
! forceClone && array.constructor === type ) return array;
if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
return new type( array ); // create typed array
}
return Array.prototype.slice.call( array ); // create Array
},
isTypedArray: function ( object ) {
return ArrayBuffer.isView( object ) &&
! ( object instanceof DataView );
},
// returns an array by which times and values can be sorted
getKeyframeOrder: function ( times ) {
function compareTime( i, j ) {
return times[ i ] - times[ j ];
}
var n = times.length;
var result = new Array( n );
for ( var i = 0; i !== n; ++ i ) result[ i ] = i;
result.sort( compareTime );
return result;
},
// uses the array previously returned by 'getKeyframeOrder' to sort data
sortedArray: function ( values, stride, order ) {
var nValues = values.length;
var result = new values.constructor( nValues );
for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
var srcOffset = order[ i ] * stride;
for ( var j = 0; j !== stride; ++ j ) {
result[ dstOffset ++ ] = values[ srcOffset + j ];
}
}
return result;
},
// function for parsing AOS keyframe formats
flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {
var i = 1, key = jsonKeys[ 0 ];
while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
key = jsonKeys[ i ++ ];
}
if ( key === undefined ) return; // no data
var value = key[ valuePropertyName ];
if ( value === undefined ) return; // no data
if ( Array.isArray( value ) ) {
do {
value = key[ valuePropertyName ];
if ( value !== undefined ) {
times.push( key.time );
values.push.apply( values, value ); // push all elements
}
key = jsonKeys[ i ++ ];
} while ( key !== undefined );
} else if ( value.toArray !== undefined ) {
function StringKeyframeTrack( name, times, values, interpolation ) {
// ...assume THREE.Math-ish
KeyframeTrack.call( this, name, times, values, interpolation );
do {
}
value = key[ valuePropertyName ];
StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
if ( value !== undefined ) {
constructor: StringKeyframeTrack,
times.push( key.time );
value.toArray( values, values.length );
ValueTypeName: 'string',
ValueBufferType: Array,
}
DefaultInterpolation: InterpolateDiscrete,
key = jsonKeys[ i ++ ];
InterpolantFactoryMethodLinear: undefined,
} while ( key !== undefined );
InterpolantFactoryMethodSmooth: undefined
} else {
} );
// otherwise push as-is
/**
*
* A Track of Boolean keyframe values.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
do {
function BooleanKeyframeTrack( name, times, values ) {
value = key[ valuePropertyName ];
KeyframeTrack.call( this, name, times, values );
if ( value !== undefined ) {
}
times.push( key.time );
values.push( value );
BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
}
constructor: BooleanKeyframeTrack,
key = jsonKeys[ i ++ ];
ValueTypeName: 'bool',
ValueBufferType: Array,
} while ( key !== undefined );
DefaultInterpolation: InterpolateDiscrete,
}
InterpolantFactoryMethodLinear: undefined,
InterpolantFactoryMethodSmooth: undefined
}
// Note: Actually this track could have a optimized / compressed
// representation of a single value and a custom interpolant that
// computes "firstValue ^ isOdd( index )".
};
} );
/**
* Abstract base class of interpolants over parametric samples.
......@@ -31901,89 +31802,220 @@
} );
/**
* Fast and simple cubic spline interpolant.
*
* It was derived from a Hermitian construction setting the first derivative
* at each sample position to the linear slope between neighboring positions
* over their parameter interval.
* Spherical linear unit quaternion interpolant.
*
* @author tschw
*/
function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
this._weightPrev = - 0;
this._offsetPrev = - 0;
this._weightNext = - 0;
this._offsetNext = - 0;
}
CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
constructor: CubicInterpolant,
constructor: QuaternionLinearInterpolant,
DefaultSettings_: {
interpolate_: function ( i1, t0, t, t1 ) {
endingStart: ZeroCurvatureEnding,
endingEnd: ZeroCurvatureEnding
var result = this.resultBuffer,
values = this.sampleValues,
stride = this.valueSize,
},
offset = i1 * stride,
intervalChanged_: function ( i1, t0, t1 ) {
alpha = ( t - t0 ) / ( t1 - t0 );
var pp = this.parameterPositions,
iPrev = i1 - 2,
iNext = i1 + 1,
for ( var end = offset + stride; offset !== end; offset += 4 ) {
tPrev = pp[ iPrev ],
tNext = pp[ iNext ];
Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
if ( tPrev === undefined ) {
}
switch ( this.getSettings_().endingStart ) {
return result;
case ZeroSlopeEnding:
}
// f'(t0) = 0
iPrev = i1;
tPrev = 2 * t0 - t1;
} );
break;
/**
*
* A Track of quaternion keyframe values.
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
case WrapAroundEnding:
function QuaternionKeyframeTrack( name, times, values, interpolation ) {
// use the other end of the curve
iPrev = pp.length - 2;
tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
KeyframeTrack.call( this, name, times, values, interpolation );
break;
}
default: // ZeroCurvatureEnding
QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
// f''(t0) = 0 a.k.a. Natural Spline
iPrev = i1;
tPrev = t1;
constructor: QuaternionKeyframeTrack,
}
ValueTypeName: 'quaternion',
}
// ValueBufferType is inherited
if ( tNext === undefined ) {
DefaultInterpolation: InterpolateLinear,
switch ( this.getSettings_().endingEnd ) {
InterpolantFactoryMethodLinear: function ( result ) {
case ZeroSlopeEnding:
return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );
// f'(tN) = 0
iNext = i1;
tNext = 2 * t1 - t0;
},
break;
InterpolantFactoryMethodSmooth: undefined // not yet implemented
case WrapAroundEnding:
} );
/**
*
* A Track of keyframe values that represent color.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
function ColorKeyframeTrack( name, times, values, interpolation ) {
KeyframeTrack.call( this, name, times, values, interpolation );
}
ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
constructor: ColorKeyframeTrack,
ValueTypeName: 'color'
// ValueBufferType is inherited
// DefaultInterpolation is inherited
// Note: Very basic implementation and nothing special yet.
// However, this is the place for color space parameterization.
} );
/**
*
* A Track of numeric keyframe values.
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
function NumberKeyframeTrack( name, times, values, interpolation ) {
KeyframeTrack.call( this, name, times, values, interpolation );
}
NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
constructor: NumberKeyframeTrack,
ValueTypeName: 'number'
// ValueBufferType is inherited
// DefaultInterpolation is inherited
} );
/**
* Fast and simple cubic spline interpolant.
*
* It was derived from a Hermitian construction setting the first derivative
* at each sample position to the linear slope between neighboring positions
* over their parameter interval.
*
* @author tschw
*/
function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
this._weightPrev = - 0;
this._offsetPrev = - 0;
this._weightNext = - 0;
this._offsetNext = - 0;
}
CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
constructor: CubicInterpolant,
DefaultSettings_: {
endingStart: ZeroCurvatureEnding,
endingEnd: ZeroCurvatureEnding
},
intervalChanged_: function ( i1, t0, t1 ) {
var pp = this.parameterPositions,
iPrev = i1 - 2,
iNext = i1 + 1,
tPrev = pp[ iPrev ],
tNext = pp[ iNext ];
if ( tPrev === undefined ) {
switch ( this.getSettings_().endingStart ) {
case ZeroSlopeEnding:
// f'(t0) = 0
iPrev = i1;
tPrev = 2 * t0 - t1;
break;
case WrapAroundEnding:
// use the other end of the curve
iPrev = pp.length - 2;
tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
break;
default: // ZeroCurvatureEnding
// f''(t0) = 0 a.k.a. Natural Spline
iPrev = i1;
tPrev = t1;
}
}
if ( tNext === undefined ) {
switch ( this.getSettings_().endingEnd ) {
case ZeroSlopeEnding:
// f'(tN) = 0
iNext = i1;
tNext = 2 * t1 - t0;
break;
case WrapAroundEnding:
// use the other end of the curve
iNext = 1;
......@@ -32116,745 +32148,716 @@
} );
var KeyframeTrackPrototype;
KeyframeTrackPrototype = {
TimeBufferType: Float32Array,
ValueBufferType: Float32Array,
/**
* @author tschw
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
*/
DefaultInterpolation: InterpolateLinear,
var AnimationUtils = {
InterpolantFactoryMethodDiscrete: function ( result ) {
// same as Array.prototype.slice, but also works on typed arrays
arraySlice: function ( array, from, to ) {
return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );
if ( AnimationUtils.isTypedArray( array ) ) {
},
// in ios9 array.subarray(from, undefined) will return empty array
// but array.subarray(from) or array.subarray(from, len) is correct
return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );
InterpolantFactoryMethodLinear: function ( result ) {
}
return new LinearInterpolant( this.times, this.values, this.getValueSize(), result );
return array.slice( from, to );
},
InterpolantFactoryMethodSmooth: function ( result ) {
// converts an array to a specific type
convertArray: function ( array, type, forceClone ) {
return new CubicInterpolant( this.times, this.values, this.getValueSize(), result );
if ( ! array || // let 'undefined' and 'null' pass
! forceClone && array.constructor === type ) return array;
},
if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
setInterpolation: function ( interpolation ) {
return new type( array ); // create typed array
var factoryMethod;
}
switch ( interpolation ) {
return Array.prototype.slice.call( array ); // create Array
case InterpolateDiscrete:
},
factoryMethod = this.InterpolantFactoryMethodDiscrete;
isTypedArray: function ( object ) {
break;
return ArrayBuffer.isView( object ) &&
! ( object instanceof DataView );
case InterpolateLinear:
},
factoryMethod = this.InterpolantFactoryMethodLinear;
// returns an array by which times and values can be sorted
getKeyframeOrder: function ( times ) {
break;
function compareTime( i, j ) {
case InterpolateSmooth:
return times[ i ] - times[ j ];
factoryMethod = this.InterpolantFactoryMethodSmooth;
}
break;
var n = times.length;
var result = new Array( n );
for ( var i = 0; i !== n; ++ i ) result[ i ] = i;
}
result.sort( compareTime );
if ( factoryMethod === undefined ) {
return result;
var message = "unsupported interpolation for " +
this.ValueTypeName + " keyframe track named " + this.name;
},
if ( this.createInterpolant === undefined ) {
// uses the array previously returned by 'getKeyframeOrder' to sort data
sortedArray: function ( values, stride, order ) {
// fall back to default, unless the default itself is messed up
if ( interpolation !== this.DefaultInterpolation ) {
var nValues = values.length;
var result = new values.constructor( nValues );
this.setInterpolation( this.DefaultInterpolation );
for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
} else {
var srcOffset = order[ i ] * stride;
throw new Error( message ); // fatal, in this case
for ( var j = 0; j !== stride; ++ j ) {
}
result[ dstOffset ++ ] = values[ srcOffset + j ];
}
console.warn( 'THREE.KeyframeTrackPrototype:', message );
return;
}
this.createInterpolant = factoryMethod;
return result;
},
getInterpolation: function () {
// function for parsing AOS keyframe formats
flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {
switch ( this.createInterpolant ) {
var i = 1, key = jsonKeys[ 0 ];
case this.InterpolantFactoryMethodDiscrete:
while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
return InterpolateDiscrete;
key = jsonKeys[ i ++ ];
case this.InterpolantFactoryMethodLinear:
}
return InterpolateLinear;
if ( key === undefined ) return; // no data
case this.InterpolantFactoryMethodSmooth:
var value = key[ valuePropertyName ];
if ( value === undefined ) return; // no data
return InterpolateSmooth;
if ( Array.isArray( value ) ) {
}
do {
},
value = key[ valuePropertyName ];
getValueSize: function () {
if ( value !== undefined ) {
return this.values.length / this.times.length;
times.push( key.time );
values.push.apply( values, value ); // push all elements
},
}
// move all keyframes either forwards or backwards in time
shift: function ( timeOffset ) {
key = jsonKeys[ i ++ ];
if ( timeOffset !== 0.0 ) {
} while ( key !== undefined );
var times = this.times;
} else if ( value.toArray !== undefined ) {
for ( var i = 0, n = times.length; i !== n; ++ i ) {
// ...assume THREE.Math-ish
times[ i ] += timeOffset;
do {
}
value = key[ valuePropertyName ];
}
if ( value !== undefined ) {
return this;
times.push( key.time );
value.toArray( values, values.length );
},
}
// scale all keyframe times by a factor (useful for frame <-> seconds conversions)
scale: function ( timeScale ) {
key = jsonKeys[ i ++ ];
if ( timeScale !== 1.0 ) {
} while ( key !== undefined );
var times = this.times;
} else {
for ( var i = 0, n = times.length; i !== n; ++ i ) {
// otherwise push as-is
times[ i ] *= timeScale;
do {
}
value = key[ valuePropertyName ];
}
if ( value !== undefined ) {
return this;
times.push( key.time );
values.push( value );
},
}
// removes keyframes before and after animation without changing any values within the range [startTime, endTime].
// IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
trim: function ( startTime, endTime ) {
key = jsonKeys[ i ++ ];
var times = this.times,
nKeys = times.length,
from = 0,
to = nKeys - 1;
} while ( key !== undefined );
while ( from !== nKeys && times[ from ] < startTime ) ++ from;
while ( to !== - 1 && times[ to ] > endTime ) -- to;
}
++ to; // inclusive -> exclusive bound
}
if ( from !== 0 || to !== nKeys ) {
};
// empty tracks are forbidden, so keep at least one keyframe
if ( from >= to ) to = Math.max( to, 1 ), from = to - 1;
/**
*
* A timed sequence of keyframes for a specific property.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
var stride = this.getValueSize();
this.times = AnimationUtils.arraySlice( times, from, to );
this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride );
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 );
return this;
this.name = name;
},
this.times = AnimationUtils.convertArray( times, this.TimeBufferType );
this.values = AnimationUtils.convertArray( values, this.ValueBufferType );
// ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
validate: function () {
this.setInterpolation( interpolation || this.DefaultInterpolation );
var valid = true;
this.validate();
this.optimize();
var valueSize = this.getValueSize();
if ( valueSize - Math.floor( valueSize ) !== 0 ) {
}
console.error( 'THREE.KeyframeTrackPrototype: Invalid value size in track.', this );
valid = false;
// Static methods:
}
Object.assign( KeyframeTrack, {
var times = this.times,
values = this.values,
// Serialization (in static context, because of constructor invocation
// and automatic invocation of .toJSON):
nKeys = times.length;
parse: function ( json ) {
if ( nKeys === 0 ) {
if ( json.type === undefined ) {
console.error( 'THREE.KeyframeTrackPrototype: Track is empty.', this );
valid = false;
throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );
}
var prevTime = null;
var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type );
for ( var i = 0; i !== nKeys; i ++ ) {
if ( json.times === undefined ) {
var currTime = times[ i ];
var times = [], values = [];
if ( typeof currTime === 'number' && isNaN( currTime ) ) {
AnimationUtils.flattenJSON( json.keys, times, values, 'value' );
console.error( 'THREE.KeyframeTrackPrototype: Time is not a valid number.', this, i, currTime );
valid = false;
break;
json.times = times;
json.values = values;
}
}
if ( prevTime !== null && prevTime > currTime ) {
// derived classes can define a static parse method
if ( trackType.parse !== undefined ) {
console.error( 'THREE.KeyframeTrackPrototype: Out of order keys.', this, i, currTime, prevTime );
valid = false;
break;
return trackType.parse( json );
}
} else {
prevTime = currTime;
// by default, we assume a constructor compatible with the base
return new trackType( json.name, json.times, json.values, json.interpolation );
}
if ( values !== undefined ) {
},
if ( AnimationUtils.isTypedArray( values ) ) {
toJSON: function ( track ) {
for ( var i = 0, n = values.length; i !== n; ++ i ) {
var trackType = track.constructor;
var value = values[ i ];
var json;
if ( isNaN( value ) ) {
// derived classes can define a static toJSON method
if ( trackType.toJSON !== undefined ) {
console.error( 'THREE.KeyframeTrackPrototype: Value is not a valid number.', this, i, value );
valid = false;
break;
json = trackType.toJSON( track );
}
} else {
}
// by default, we assume the data can be serialized as-is
json = {
}
'name': track.name,
'times': AnimationUtils.convertArray( track.times, Array ),
'values': AnimationUtils.convertArray( track.values, Array )
}
};
return valid;
var interpolation = track.getInterpolation();
},
if ( interpolation !== track.DefaultInterpolation ) {
// removes equivalent sequential keys as common in morph target sequences
// (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
optimize: function () {
json.interpolation = interpolation;
var times = this.times,
values = this.values,
stride = this.getValueSize(),
}
smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
}
writeIndex = 1,
lastIndex = times.length - 1;
json.type = track.ValueTypeName; // mandatory
for ( var i = 1; i < lastIndex; ++ i ) {
return json;
var keep = false;
},
var time = times[ i ];
var timeNext = times[ i + 1 ];
_getTrackTypeForValueTypeName: function ( typeName ) {
// remove adjacent keyframes scheduled at the same time
switch ( typeName.toLowerCase() ) {
if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) {
case 'scalar':
case 'double':
case 'float':
case 'number':
case 'integer':
if ( ! smoothInterpolation ) {
return NumberKeyframeTrack;
// remove unnecessary keyframes same as their neighbors
case 'vector':
case 'vector2':
case 'vector3':
case 'vector4':
var offset = i * stride,
offsetP = offset - stride,
offsetN = offset + stride;
return VectorKeyframeTrack;
for ( var j = 0; j !== stride; ++ j ) {
case 'color':
var value = values[ offset + j ];
return ColorKeyframeTrack;
if ( value !== values[ offsetP + j ] ||
value !== values[ offsetN + j ] ) {
case 'quaternion':
keep = true;
break;
return QuaternionKeyframeTrack;
}
case 'bool':
case 'boolean':
}
return BooleanKeyframeTrack;
} else keep = true;
case 'string':
}
return StringKeyframeTrack;
// in-place compaction
}
if ( keep ) {
throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );
if ( i !== writeIndex ) {
}
times[ writeIndex ] = times[ i ];
} );
var readOffset = i * stride,
writeOffset = writeIndex * stride;
Object.assign( KeyframeTrack.prototype, {
for ( var j = 0; j !== stride; ++ j )
constructor: KeyframeTrack,
values[ writeOffset + j ] = values[ readOffset + j ];
TimeBufferType: Float32Array,
}
ValueBufferType: Float32Array,
++ writeIndex;
DefaultInterpolation: InterpolateLinear,
}
InterpolantFactoryMethodDiscrete: function ( result ) {
}
return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );
// flush last keyframe (compaction looks ahead)
},
if ( lastIndex > 0 ) {
InterpolantFactoryMethodLinear: function ( result ) {
times[ writeIndex ] = times[ lastIndex ];
return new LinearInterpolant( this.times, this.values, this.getValueSize(), result );
for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j )
},
values[ writeOffset + j ] = values[ readOffset + j ];
InterpolantFactoryMethodSmooth: function ( result ) {
++ writeIndex;
return new CubicInterpolant( this.times, this.values, this.getValueSize(), result );
}
},
if ( writeIndex !== times.length ) {
setInterpolation: function ( interpolation ) {
this.times = AnimationUtils.arraySlice( times, 0, writeIndex );
this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );
var factoryMethod;
}
switch ( interpolation ) {
return this;
case InterpolateDiscrete:
}
factoryMethod = this.InterpolantFactoryMethodDiscrete;
};
break;
function KeyframeTrackConstructor( name, times, values, interpolation ) {
case InterpolateLinear:
if ( name === undefined ) throw new Error( 'track name is undefined' );
factoryMethod = this.InterpolantFactoryMethodLinear;
if ( times === undefined || times.length === 0 ) {
break;
throw new Error( 'no keyframes in track named ' + name );
case InterpolateSmooth:
}
factoryMethod = this.InterpolantFactoryMethodSmooth;
this.name = name;
break;
this.times = AnimationUtils.convertArray( times, this.TimeBufferType );
this.values = AnimationUtils.convertArray( values, this.ValueBufferType );
}
this.setInterpolation( interpolation || this.DefaultInterpolation );
if ( factoryMethod === undefined ) {
this.validate();
this.optimize();
var message = "unsupported interpolation for " +
this.ValueTypeName + " keyframe track named " + this.name;
}
if ( this.createInterpolant === undefined ) {
/**
*
* A Track of vectored keyframe values.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
// fall back to default, unless the default itself is messed up
if ( interpolation !== this.DefaultInterpolation ) {
function VectorKeyframeTrack( name, times, values, interpolation ) {
this.setInterpolation( this.DefaultInterpolation );
KeyframeTrackConstructor.call( this, name, times, values, interpolation );
} else {
}
throw new Error( message ); // fatal, in this case
VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrackPrototype ), {
}
constructor: VectorKeyframeTrack,
}
ValueTypeName: 'vector'
console.warn( 'THREE.KeyframeTrack:', message );
return;
// ValueBufferType is inherited
}
// DefaultInterpolation is inherited
this.createInterpolant = factoryMethod;
} );
},
/**
* Spherical linear unit quaternion interpolant.
*
* @author tschw
*/
getInterpolation: function () {
function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
switch ( this.createInterpolant ) {
Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
case this.InterpolantFactoryMethodDiscrete:
}
return InterpolateDiscrete;
QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
case this.InterpolantFactoryMethodLinear:
constructor: QuaternionLinearInterpolant,
return InterpolateLinear;
interpolate_: function ( i1, t0, t, t1 ) {
case this.InterpolantFactoryMethodSmooth:
var result = this.resultBuffer,
values = this.sampleValues,
stride = this.valueSize,
return InterpolateSmooth;
offset = i1 * stride,
}
alpha = ( t - t0 ) / ( t1 - t0 );
},
for ( var end = offset + stride; offset !== end; offset += 4 ) {
getValueSize: function () {
Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
return this.values.length / this.times.length;
}
},
return result;
// move all keyframes either forwards or backwards in time
shift: function ( timeOffset ) {
}
if ( timeOffset !== 0.0 ) {
} );
var times = this.times;
/**
*
* A Track of quaternion keyframe values.
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
for ( var i = 0, n = times.length; i !== n; ++ i ) {
function QuaternionKeyframeTrack( name, times, values, interpolation ) {
times[ i ] += timeOffset;
KeyframeTrackConstructor.call( this, name, times, values, interpolation );
}
}
}
QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrackPrototype ), {
return this;
constructor: QuaternionKeyframeTrack,
},
ValueTypeName: 'quaternion',
// scale all keyframe times by a factor (useful for frame <-> seconds conversions)
scale: function ( timeScale ) {
// ValueBufferType is inherited
if ( timeScale !== 1.0 ) {
DefaultInterpolation: InterpolateLinear,
var times = this.times;
InterpolantFactoryMethodLinear: function ( result ) {
for ( var i = 0, n = times.length; i !== n; ++ i ) {
return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );
times[ i ] *= timeScale;
},
}
InterpolantFactoryMethodSmooth: undefined // not yet implemented
}
} );
return this;
/**
*
* A Track of numeric keyframe values.
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
},
function NumberKeyframeTrack( name, times, values, interpolation ) {
// removes keyframes before and after animation without changing any values within the range [startTime, endTime].
// IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
trim: function ( startTime, endTime ) {
KeyframeTrackConstructor.call( this, name, times, values, interpolation );
var times = this.times,
nKeys = times.length,
from = 0,
to = nKeys - 1;
}
while ( from !== nKeys && times[ from ] < startTime ) {
NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrackPrototype ), {
++ from;
constructor: NumberKeyframeTrack,
}
ValueTypeName: 'number'
while ( to !== - 1 && times[ to ] > endTime ) {
// ValueBufferType is inherited
-- to;
// DefaultInterpolation is inherited
}
} );
++ to; // inclusive -> exclusive bound
/**
*
* A Track that interpolates Strings
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
if ( from !== 0 || to !== nKeys ) {
function StringKeyframeTrack( name, times, values, interpolation ) {
// empty tracks are forbidden, so keep at least one keyframe
if ( from >= to ) to = Math.max( to, 1 ), from = to - 1;
KeyframeTrackConstructor.call( this, name, times, values, interpolation );
var stride = this.getValueSize();
this.times = AnimationUtils.arraySlice( times, from, to );
this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride );
}
}
StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrackPrototype ), {
return this;
constructor: StringKeyframeTrack,
},
ValueTypeName: 'string',
ValueBufferType: Array,
// ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
validate: function () {
DefaultInterpolation: InterpolateDiscrete,
var valid = true;
InterpolantFactoryMethodLinear: undefined,
var valueSize = this.getValueSize();
if ( valueSize - Math.floor( valueSize ) !== 0 ) {
InterpolantFactoryMethodSmooth: undefined
console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this );
valid = false;
} );
}
/**
*
* A Track of Boolean keyframe values.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
var times = this.times,
values = this.values,
function BooleanKeyframeTrack( name, times, values ) {
nKeys = times.length;
KeyframeTrackConstructor.call( this, name, times, values );
if ( nKeys === 0 ) {
}
console.error( 'THREE.KeyframeTrack: Track is empty.', this );
valid = false;
BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrackPrototype ), {
}
constructor: BooleanKeyframeTrack,
var prevTime = null;
ValueTypeName: 'bool',
ValueBufferType: Array,
for ( var i = 0; i !== nKeys; i ++ ) {
DefaultInterpolation: InterpolateDiscrete,
var currTime = times[ i ];
InterpolantFactoryMethodLinear: undefined,
InterpolantFactoryMethodSmooth: undefined
if ( typeof currTime === 'number' && isNaN( currTime ) ) {
// Note: Actually this track could have a optimized / compressed
// representation of a single value and a custom interpolant that
// computes "firstValue ^ isOdd( index )".
console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime );
valid = false;
break;
} );
}
/**
*
* A Track of keyframe values that represent color.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
if ( prevTime !== null && prevTime > currTime ) {
function ColorKeyframeTrack( name, times, values, interpolation ) {
console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime );
valid = false;
break;
KeyframeTrackConstructor.call( this, name, times, values, interpolation );
}
}
prevTime = currTime;
ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrackPrototype ), {
}
constructor: ColorKeyframeTrack,
if ( values !== undefined ) {
ValueTypeName: 'color'
if ( AnimationUtils.isTypedArray( values ) ) {
// ValueBufferType is inherited
for ( var i = 0, n = values.length; i !== n; ++ i ) {
// DefaultInterpolation is inherited
var value = values[ i ];
if ( isNaN( value ) ) {
// Note: Very basic implementation and nothing special yet.
// However, this is the place for color space parameterization.
console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value );
valid = false;
break;
} );
}
/**
*
* A timed sequence of keyframes for a specific property.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
}
function KeyframeTrack( name, times, values, interpolation ) {
}
KeyframeTrackConstructor.apply( this, name, times, values, interpolation );
}
}
return valid;
KeyframeTrack.prototype = KeyframeTrackPrototype;
KeyframeTrackPrototype.constructor = KeyframeTrack;
},
// Static methods:
// removes equivalent sequential keys as common in morph target sequences
// (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
optimize: function () {
Object.assign( KeyframeTrack, {
var times = this.times,
values = this.values,
stride = this.getValueSize(),
// Serialization (in static context, because of constructor invocation
// and automatic invocation of .toJSON):
smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
parse: function ( json ) {
writeIndex = 1,
lastIndex = times.length - 1;
if ( json.type === undefined ) {
for ( var i = 1; i < lastIndex; ++ i ) {
throw new Error( 'track type undefined, can not parse' );
var keep = false;
}
var time = times[ i ];
var timeNext = times[ i + 1 ];
var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type );
// remove adjacent keyframes scheduled at the same time
if ( json.times === undefined ) {
if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) {
var times = [], values = [];
if ( ! smoothInterpolation ) {
AnimationUtils.flattenJSON( json.keys, times, values, 'value' );
// remove unnecessary keyframes same as their neighbors
json.times = times;
json.values = values;
var offset = i * stride,
offsetP = offset - stride,
offsetN = offset + stride;
}
for ( var j = 0; j !== stride; ++ j ) {
// derived classes can define a static parse method
if ( trackType.parse !== undefined ) {
var value = values[ offset + j ];
return trackType.parse( json );
if ( value !== values[ offsetP + j ] ||
value !== values[ offsetN + j ] ) {
} else {
keep = true;
break;
// by default, we assume a constructor compatible with the base
return new trackType( json.name, json.times, json.values, json.interpolation );
}
}
}
},
} else {
toJSON: function ( track ) {
keep = true;
var trackType = track.constructor;
}
var json;
}
// derived classes can define a static toJSON method
if ( trackType.toJSON !== undefined ) {
// in-place compaction
json = trackType.toJSON( track );
if ( keep ) {
} else {
if ( i !== writeIndex ) {
// by default, we assume the data can be serialized as-is
json = {
times[ writeIndex ] = times[ i ];
'name': track.name,
'times': AnimationUtils.convertArray( track.times, Array ),
'values': AnimationUtils.convertArray( track.values, Array )
var readOffset = i * stride,
writeOffset = writeIndex * stride;
};
for ( var j = 0; j !== stride; ++ j ) {
var interpolation = track.getInterpolation();
values[ writeOffset + j ] = values[ readOffset + j ];
if ( interpolation !== track.DefaultInterpolation ) {
}
json.interpolation = interpolation;
}
++ writeIndex;
}
}
json.type = track.ValueTypeName; // mandatory
// flush last keyframe (compaction looks ahead)
return json;
if ( lastIndex > 0 ) {
},
times[ writeIndex ] = times[ lastIndex ];
_getTrackTypeForValueTypeName: function ( typeName ) {
for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {
switch ( typeName.toLowerCase() ) {
values[ writeOffset + j ] = values[ readOffset + j ];
case 'scalar':
case 'double':
case 'float':
case 'number':
case 'integer':
}
return NumberKeyframeTrack;
++ writeIndex;
case 'vector':
case 'vector2':
case 'vector3':
case 'vector4':
}
return VectorKeyframeTrack;
if ( writeIndex !== times.length ) {
case 'color':
this.times = AnimationUtils.arraySlice( times, 0, writeIndex );
this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );
return ColorKeyframeTrack;
}
case 'quaternion':
return this;
return QuaternionKeyframeTrack;
}
case 'bool':
case 'boolean':
} );
return BooleanKeyframeTrack;
/**
*
* A Track of vectored keyframe values.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
case 'string':
function VectorKeyframeTrack( name, times, values, interpolation ) {
return StringKeyframeTrack;
KeyframeTrack.call( this, name, times, values, interpolation );
}
}
throw new Error( 'Unsupported typeName: ' + typeName );
VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
}
constructor: VectorKeyframeTrack,
ValueTypeName: 'vector'
// ValueBufferType is inherited
// DefaultInterpolation is inherited
} );
因为 它太大了无法显示 source diff 。你可以改为 查看blob
......@@ -31474,168 +31474,69 @@ RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), {
} );
/**
* @author tschw
*
* A Track that interpolates Strings
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
var AnimationUtils = {
// same as Array.prototype.slice, but also works on typed arrays
arraySlice: function ( array, from, to ) {
if ( AnimationUtils.isTypedArray( array ) ) {
// in ios9 array.subarray(from, undefined) will return empty array
// but array.subarray(from) or array.subarray(from, len) is correct
return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );
}
return array.slice( from, to );
},
// converts an array to a specific type
convertArray: function ( array, type, forceClone ) {
if ( ! array || // let 'undefined' and 'null' pass
! forceClone && array.constructor === type ) return array;
if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
return new type( array ); // create typed array
}
return Array.prototype.slice.call( array ); // create Array
},
isTypedArray: function ( object ) {
return ArrayBuffer.isView( object ) &&
! ( object instanceof DataView );
},
// returns an array by which times and values can be sorted
getKeyframeOrder: function ( times ) {
function compareTime( i, j ) {
return times[ i ] - times[ j ];
}
var n = times.length;
var result = new Array( n );
for ( var i = 0; i !== n; ++ i ) result[ i ] = i;
result.sort( compareTime );
return result;
},
// uses the array previously returned by 'getKeyframeOrder' to sort data
sortedArray: function ( values, stride, order ) {
var nValues = values.length;
var result = new values.constructor( nValues );
for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
var srcOffset = order[ i ] * stride;
for ( var j = 0; j !== stride; ++ j ) {
result[ dstOffset ++ ] = values[ srcOffset + j ];
}
}
return result;
},
// function for parsing AOS keyframe formats
flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {
var i = 1, key = jsonKeys[ 0 ];
while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
key = jsonKeys[ i ++ ];
}
if ( key === undefined ) return; // no data
var value = key[ valuePropertyName ];
if ( value === undefined ) return; // no data
if ( Array.isArray( value ) ) {
do {
value = key[ valuePropertyName ];
if ( value !== undefined ) {
times.push( key.time );
values.push.apply( values, value ); // push all elements
}
key = jsonKeys[ i ++ ];
} while ( key !== undefined );
} else if ( value.toArray !== undefined ) {
function StringKeyframeTrack( name, times, values, interpolation ) {
// ...assume THREE.Math-ish
KeyframeTrack.call( this, name, times, values, interpolation );
do {
}
value = key[ valuePropertyName ];
StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
if ( value !== undefined ) {
constructor: StringKeyframeTrack,
times.push( key.time );
value.toArray( values, values.length );
ValueTypeName: 'string',
ValueBufferType: Array,
}
DefaultInterpolation: InterpolateDiscrete,
key = jsonKeys[ i ++ ];
InterpolantFactoryMethodLinear: undefined,
} while ( key !== undefined );
InterpolantFactoryMethodSmooth: undefined
} else {
} );
// otherwise push as-is
/**
*
* A Track of Boolean keyframe values.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
do {
function BooleanKeyframeTrack( name, times, values ) {
value = key[ valuePropertyName ];
KeyframeTrack.call( this, name, times, values );
if ( value !== undefined ) {
}
times.push( key.time );
values.push( value );
BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
}
constructor: BooleanKeyframeTrack,
key = jsonKeys[ i ++ ];
ValueTypeName: 'bool',
ValueBufferType: Array,
} while ( key !== undefined );
DefaultInterpolation: InterpolateDiscrete,
}
InterpolantFactoryMethodLinear: undefined,
InterpolantFactoryMethodSmooth: undefined
}
// Note: Actually this track could have a optimized / compressed
// representation of a single value and a custom interpolant that
// computes "firstValue ^ isOdd( index )".
};
} );
/**
* Abstract base class of interpolants over parametric samples.
......@@ -31895,89 +31796,220 @@ Object.assign( Interpolant.prototype, {
} );
/**
* Fast and simple cubic spline interpolant.
*
* It was derived from a Hermitian construction setting the first derivative
* at each sample position to the linear slope between neighboring positions
* over their parameter interval.
* Spherical linear unit quaternion interpolant.
*
* @author tschw
*/
function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
this._weightPrev = - 0;
this._offsetPrev = - 0;
this._weightNext = - 0;
this._offsetNext = - 0;
}
CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
constructor: CubicInterpolant,
constructor: QuaternionLinearInterpolant,
DefaultSettings_: {
interpolate_: function ( i1, t0, t, t1 ) {
endingStart: ZeroCurvatureEnding,
endingEnd: ZeroCurvatureEnding
var result = this.resultBuffer,
values = this.sampleValues,
stride = this.valueSize,
},
offset = i1 * stride,
intervalChanged_: function ( i1, t0, t1 ) {
alpha = ( t - t0 ) / ( t1 - t0 );
var pp = this.parameterPositions,
iPrev = i1 - 2,
iNext = i1 + 1,
for ( var end = offset + stride; offset !== end; offset += 4 ) {
tPrev = pp[ iPrev ],
tNext = pp[ iNext ];
Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
if ( tPrev === undefined ) {
}
switch ( this.getSettings_().endingStart ) {
return result;
case ZeroSlopeEnding:
}
// f'(t0) = 0
iPrev = i1;
tPrev = 2 * t0 - t1;
} );
break;
/**
*
* A Track of quaternion keyframe values.
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
case WrapAroundEnding:
function QuaternionKeyframeTrack( name, times, values, interpolation ) {
// use the other end of the curve
iPrev = pp.length - 2;
tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
KeyframeTrack.call( this, name, times, values, interpolation );
break;
}
default: // ZeroCurvatureEnding
QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
// f''(t0) = 0 a.k.a. Natural Spline
iPrev = i1;
tPrev = t1;
constructor: QuaternionKeyframeTrack,
}
ValueTypeName: 'quaternion',
}
// ValueBufferType is inherited
if ( tNext === undefined ) {
DefaultInterpolation: InterpolateLinear,
switch ( this.getSettings_().endingEnd ) {
InterpolantFactoryMethodLinear: function ( result ) {
case ZeroSlopeEnding:
return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );
// f'(tN) = 0
iNext = i1;
tNext = 2 * t1 - t0;
},
break;
InterpolantFactoryMethodSmooth: undefined // not yet implemented
case WrapAroundEnding:
} );
/**
*
* A Track of keyframe values that represent color.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
function ColorKeyframeTrack( name, times, values, interpolation ) {
KeyframeTrack.call( this, name, times, values, interpolation );
}
ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
constructor: ColorKeyframeTrack,
ValueTypeName: 'color'
// ValueBufferType is inherited
// DefaultInterpolation is inherited
// Note: Very basic implementation and nothing special yet.
// However, this is the place for color space parameterization.
} );
/**
*
* A Track of numeric keyframe values.
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
function NumberKeyframeTrack( name, times, values, interpolation ) {
KeyframeTrack.call( this, name, times, values, interpolation );
}
NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
constructor: NumberKeyframeTrack,
ValueTypeName: 'number'
// ValueBufferType is inherited
// DefaultInterpolation is inherited
} );
/**
* Fast and simple cubic spline interpolant.
*
* It was derived from a Hermitian construction setting the first derivative
* at each sample position to the linear slope between neighboring positions
* over their parameter interval.
*
* @author tschw
*/
function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
this._weightPrev = - 0;
this._offsetPrev = - 0;
this._weightNext = - 0;
this._offsetNext = - 0;
}
CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
constructor: CubicInterpolant,
DefaultSettings_: {
endingStart: ZeroCurvatureEnding,
endingEnd: ZeroCurvatureEnding
},
intervalChanged_: function ( i1, t0, t1 ) {
var pp = this.parameterPositions,
iPrev = i1 - 2,
iNext = i1 + 1,
tPrev = pp[ iPrev ],
tNext = pp[ iNext ];
if ( tPrev === undefined ) {
switch ( this.getSettings_().endingStart ) {
case ZeroSlopeEnding:
// f'(t0) = 0
iPrev = i1;
tPrev = 2 * t0 - t1;
break;
case WrapAroundEnding:
// use the other end of the curve
iPrev = pp.length - 2;
tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
break;
default: // ZeroCurvatureEnding
// f''(t0) = 0 a.k.a. Natural Spline
iPrev = i1;
tPrev = t1;
}
}
if ( tNext === undefined ) {
switch ( this.getSettings_().endingEnd ) {
case ZeroSlopeEnding:
// f'(tN) = 0
iNext = i1;
tNext = 2 * t1 - t0;
break;
case WrapAroundEnding:
// use the other end of the curve
iNext = 1;
......@@ -32110,745 +32142,716 @@ DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.protot
} );
var KeyframeTrackPrototype;
KeyframeTrackPrototype = {
TimeBufferType: Float32Array,
ValueBufferType: Float32Array,
/**
* @author tschw
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
*/
DefaultInterpolation: InterpolateLinear,
var AnimationUtils = {
InterpolantFactoryMethodDiscrete: function ( result ) {
// same as Array.prototype.slice, but also works on typed arrays
arraySlice: function ( array, from, to ) {
return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );
if ( AnimationUtils.isTypedArray( array ) ) {
},
// in ios9 array.subarray(from, undefined) will return empty array
// but array.subarray(from) or array.subarray(from, len) is correct
return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );
InterpolantFactoryMethodLinear: function ( result ) {
}
return new LinearInterpolant( this.times, this.values, this.getValueSize(), result );
return array.slice( from, to );
},
InterpolantFactoryMethodSmooth: function ( result ) {
// converts an array to a specific type
convertArray: function ( array, type, forceClone ) {
return new CubicInterpolant( this.times, this.values, this.getValueSize(), result );
if ( ! array || // let 'undefined' and 'null' pass
! forceClone && array.constructor === type ) return array;
},
if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
setInterpolation: function ( interpolation ) {
return new type( array ); // create typed array
var factoryMethod;
}
switch ( interpolation ) {
return Array.prototype.slice.call( array ); // create Array
case InterpolateDiscrete:
},
factoryMethod = this.InterpolantFactoryMethodDiscrete;
isTypedArray: function ( object ) {
break;
return ArrayBuffer.isView( object ) &&
! ( object instanceof DataView );
case InterpolateLinear:
},
factoryMethod = this.InterpolantFactoryMethodLinear;
// returns an array by which times and values can be sorted
getKeyframeOrder: function ( times ) {
break;
function compareTime( i, j ) {
case InterpolateSmooth:
return times[ i ] - times[ j ];
factoryMethod = this.InterpolantFactoryMethodSmooth;
}
break;
var n = times.length;
var result = new Array( n );
for ( var i = 0; i !== n; ++ i ) result[ i ] = i;
}
result.sort( compareTime );
if ( factoryMethod === undefined ) {
return result;
var message = "unsupported interpolation for " +
this.ValueTypeName + " keyframe track named " + this.name;
},
if ( this.createInterpolant === undefined ) {
// uses the array previously returned by 'getKeyframeOrder' to sort data
sortedArray: function ( values, stride, order ) {
// fall back to default, unless the default itself is messed up
if ( interpolation !== this.DefaultInterpolation ) {
var nValues = values.length;
var result = new values.constructor( nValues );
this.setInterpolation( this.DefaultInterpolation );
for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
} else {
var srcOffset = order[ i ] * stride;
throw new Error( message ); // fatal, in this case
for ( var j = 0; j !== stride; ++ j ) {
}
result[ dstOffset ++ ] = values[ srcOffset + j ];
}
console.warn( 'THREE.KeyframeTrackPrototype:', message );
return;
}
this.createInterpolant = factoryMethod;
return result;
},
getInterpolation: function () {
// function for parsing AOS keyframe formats
flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {
switch ( this.createInterpolant ) {
var i = 1, key = jsonKeys[ 0 ];
case this.InterpolantFactoryMethodDiscrete:
while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
return InterpolateDiscrete;
key = jsonKeys[ i ++ ];
case this.InterpolantFactoryMethodLinear:
}
return InterpolateLinear;
if ( key === undefined ) return; // no data
case this.InterpolantFactoryMethodSmooth:
var value = key[ valuePropertyName ];
if ( value === undefined ) return; // no data
return InterpolateSmooth;
if ( Array.isArray( value ) ) {
}
do {
},
value = key[ valuePropertyName ];
getValueSize: function () {
if ( value !== undefined ) {
return this.values.length / this.times.length;
times.push( key.time );
values.push.apply( values, value ); // push all elements
},
}
// move all keyframes either forwards or backwards in time
shift: function ( timeOffset ) {
key = jsonKeys[ i ++ ];
if ( timeOffset !== 0.0 ) {
} while ( key !== undefined );
var times = this.times;
} else if ( value.toArray !== undefined ) {
for ( var i = 0, n = times.length; i !== n; ++ i ) {
// ...assume THREE.Math-ish
times[ i ] += timeOffset;
do {
}
value = key[ valuePropertyName ];
}
if ( value !== undefined ) {
return this;
times.push( key.time );
value.toArray( values, values.length );
},
}
// scale all keyframe times by a factor (useful for frame <-> seconds conversions)
scale: function ( timeScale ) {
key = jsonKeys[ i ++ ];
if ( timeScale !== 1.0 ) {
} while ( key !== undefined );
var times = this.times;
} else {
for ( var i = 0, n = times.length; i !== n; ++ i ) {
// otherwise push as-is
times[ i ] *= timeScale;
do {
}
value = key[ valuePropertyName ];
}
if ( value !== undefined ) {
return this;
times.push( key.time );
values.push( value );
},
}
// removes keyframes before and after animation without changing any values within the range [startTime, endTime].
// IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
trim: function ( startTime, endTime ) {
key = jsonKeys[ i ++ ];
var times = this.times,
nKeys = times.length,
from = 0,
to = nKeys - 1;
} while ( key !== undefined );
while ( from !== nKeys && times[ from ] < startTime ) ++ from;
while ( to !== - 1 && times[ to ] > endTime ) -- to;
}
++ to; // inclusive -> exclusive bound
}
if ( from !== 0 || to !== nKeys ) {
};
// empty tracks are forbidden, so keep at least one keyframe
if ( from >= to ) to = Math.max( to, 1 ), from = to - 1;
/**
*
* A timed sequence of keyframes for a specific property.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
var stride = this.getValueSize();
this.times = AnimationUtils.arraySlice( times, from, to );
this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride );
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 );
return this;
this.name = name;
},
this.times = AnimationUtils.convertArray( times, this.TimeBufferType );
this.values = AnimationUtils.convertArray( values, this.ValueBufferType );
// ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
validate: function () {
this.setInterpolation( interpolation || this.DefaultInterpolation );
var valid = true;
this.validate();
this.optimize();
var valueSize = this.getValueSize();
if ( valueSize - Math.floor( valueSize ) !== 0 ) {
}
console.error( 'THREE.KeyframeTrackPrototype: Invalid value size in track.', this );
valid = false;
// Static methods:
}
Object.assign( KeyframeTrack, {
var times = this.times,
values = this.values,
// Serialization (in static context, because of constructor invocation
// and automatic invocation of .toJSON):
nKeys = times.length;
parse: function ( json ) {
if ( nKeys === 0 ) {
if ( json.type === undefined ) {
console.error( 'THREE.KeyframeTrackPrototype: Track is empty.', this );
valid = false;
throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );
}
var prevTime = null;
var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type );
for ( var i = 0; i !== nKeys; i ++ ) {
if ( json.times === undefined ) {
var currTime = times[ i ];
var times = [], values = [];
if ( typeof currTime === 'number' && isNaN( currTime ) ) {
AnimationUtils.flattenJSON( json.keys, times, values, 'value' );
console.error( 'THREE.KeyframeTrackPrototype: Time is not a valid number.', this, i, currTime );
valid = false;
break;
json.times = times;
json.values = values;
}
}
if ( prevTime !== null && prevTime > currTime ) {
// derived classes can define a static parse method
if ( trackType.parse !== undefined ) {
console.error( 'THREE.KeyframeTrackPrototype: Out of order keys.', this, i, currTime, prevTime );
valid = false;
break;
return trackType.parse( json );
}
} else {
prevTime = currTime;
// by default, we assume a constructor compatible with the base
return new trackType( json.name, json.times, json.values, json.interpolation );
}
if ( values !== undefined ) {
},
if ( AnimationUtils.isTypedArray( values ) ) {
toJSON: function ( track ) {
for ( var i = 0, n = values.length; i !== n; ++ i ) {
var trackType = track.constructor;
var value = values[ i ];
var json;
if ( isNaN( value ) ) {
// derived classes can define a static toJSON method
if ( trackType.toJSON !== undefined ) {
console.error( 'THREE.KeyframeTrackPrototype: Value is not a valid number.', this, i, value );
valid = false;
break;
json = trackType.toJSON( track );
}
} else {
}
// by default, we assume the data can be serialized as-is
json = {
}
'name': track.name,
'times': AnimationUtils.convertArray( track.times, Array ),
'values': AnimationUtils.convertArray( track.values, Array )
}
};
return valid;
var interpolation = track.getInterpolation();
},
if ( interpolation !== track.DefaultInterpolation ) {
// removes equivalent sequential keys as common in morph target sequences
// (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
optimize: function () {
json.interpolation = interpolation;
var times = this.times,
values = this.values,
stride = this.getValueSize(),
}
smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
}
writeIndex = 1,
lastIndex = times.length - 1;
json.type = track.ValueTypeName; // mandatory
for ( var i = 1; i < lastIndex; ++ i ) {
return json;
var keep = false;
},
var time = times[ i ];
var timeNext = times[ i + 1 ];
_getTrackTypeForValueTypeName: function ( typeName ) {
// remove adjacent keyframes scheduled at the same time
switch ( typeName.toLowerCase() ) {
if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) {
case 'scalar':
case 'double':
case 'float':
case 'number':
case 'integer':
if ( ! smoothInterpolation ) {
return NumberKeyframeTrack;
// remove unnecessary keyframes same as their neighbors
case 'vector':
case 'vector2':
case 'vector3':
case 'vector4':
var offset = i * stride,
offsetP = offset - stride,
offsetN = offset + stride;
return VectorKeyframeTrack;
for ( var j = 0; j !== stride; ++ j ) {
case 'color':
var value = values[ offset + j ];
return ColorKeyframeTrack;
if ( value !== values[ offsetP + j ] ||
value !== values[ offsetN + j ] ) {
case 'quaternion':
keep = true;
break;
return QuaternionKeyframeTrack;
}
case 'bool':
case 'boolean':
}
return BooleanKeyframeTrack;
} else keep = true;
case 'string':
}
return StringKeyframeTrack;
// in-place compaction
}
if ( keep ) {
throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );
if ( i !== writeIndex ) {
}
times[ writeIndex ] = times[ i ];
} );
var readOffset = i * stride,
writeOffset = writeIndex * stride;
Object.assign( KeyframeTrack.prototype, {
for ( var j = 0; j !== stride; ++ j )
constructor: KeyframeTrack,
values[ writeOffset + j ] = values[ readOffset + j ];
TimeBufferType: Float32Array,
}
ValueBufferType: Float32Array,
++ writeIndex;
DefaultInterpolation: InterpolateLinear,
}
InterpolantFactoryMethodDiscrete: function ( result ) {
}
return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );
// flush last keyframe (compaction looks ahead)
},
if ( lastIndex > 0 ) {
InterpolantFactoryMethodLinear: function ( result ) {
times[ writeIndex ] = times[ lastIndex ];
return new LinearInterpolant( this.times, this.values, this.getValueSize(), result );
for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j )
},
values[ writeOffset + j ] = values[ readOffset + j ];
InterpolantFactoryMethodSmooth: function ( result ) {
++ writeIndex;
return new CubicInterpolant( this.times, this.values, this.getValueSize(), result );
}
},
if ( writeIndex !== times.length ) {
setInterpolation: function ( interpolation ) {
this.times = AnimationUtils.arraySlice( times, 0, writeIndex );
this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );
var factoryMethod;
}
switch ( interpolation ) {
return this;
case InterpolateDiscrete:
}
factoryMethod = this.InterpolantFactoryMethodDiscrete;
};
break;
function KeyframeTrackConstructor( name, times, values, interpolation ) {
case InterpolateLinear:
if ( name === undefined ) throw new Error( 'track name is undefined' );
factoryMethod = this.InterpolantFactoryMethodLinear;
if ( times === undefined || times.length === 0 ) {
break;
throw new Error( 'no keyframes in track named ' + name );
case InterpolateSmooth:
}
factoryMethod = this.InterpolantFactoryMethodSmooth;
this.name = name;
break;
this.times = AnimationUtils.convertArray( times, this.TimeBufferType );
this.values = AnimationUtils.convertArray( values, this.ValueBufferType );
}
this.setInterpolation( interpolation || this.DefaultInterpolation );
if ( factoryMethod === undefined ) {
this.validate();
this.optimize();
var message = "unsupported interpolation for " +
this.ValueTypeName + " keyframe track named " + this.name;
}
if ( this.createInterpolant === undefined ) {
/**
*
* A Track of vectored keyframe values.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
// fall back to default, unless the default itself is messed up
if ( interpolation !== this.DefaultInterpolation ) {
function VectorKeyframeTrack( name, times, values, interpolation ) {
this.setInterpolation( this.DefaultInterpolation );
KeyframeTrackConstructor.call( this, name, times, values, interpolation );
} else {
}
throw new Error( message ); // fatal, in this case
VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrackPrototype ), {
}
constructor: VectorKeyframeTrack,
}
ValueTypeName: 'vector'
console.warn( 'THREE.KeyframeTrack:', message );
return;
// ValueBufferType is inherited
}
// DefaultInterpolation is inherited
this.createInterpolant = factoryMethod;
} );
},
/**
* Spherical linear unit quaternion interpolant.
*
* @author tschw
*/
getInterpolation: function () {
function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
switch ( this.createInterpolant ) {
Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
case this.InterpolantFactoryMethodDiscrete:
}
return InterpolateDiscrete;
QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
case this.InterpolantFactoryMethodLinear:
constructor: QuaternionLinearInterpolant,
return InterpolateLinear;
interpolate_: function ( i1, t0, t, t1 ) {
case this.InterpolantFactoryMethodSmooth:
var result = this.resultBuffer,
values = this.sampleValues,
stride = this.valueSize,
return InterpolateSmooth;
offset = i1 * stride,
}
alpha = ( t - t0 ) / ( t1 - t0 );
},
for ( var end = offset + stride; offset !== end; offset += 4 ) {
getValueSize: function () {
Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
return this.values.length / this.times.length;
}
},
return result;
// move all keyframes either forwards or backwards in time
shift: function ( timeOffset ) {
}
if ( timeOffset !== 0.0 ) {
} );
var times = this.times;
/**
*
* A Track of quaternion keyframe values.
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
for ( var i = 0, n = times.length; i !== n; ++ i ) {
function QuaternionKeyframeTrack( name, times, values, interpolation ) {
times[ i ] += timeOffset;
KeyframeTrackConstructor.call( this, name, times, values, interpolation );
}
}
}
QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrackPrototype ), {
return this;
constructor: QuaternionKeyframeTrack,
},
ValueTypeName: 'quaternion',
// scale all keyframe times by a factor (useful for frame <-> seconds conversions)
scale: function ( timeScale ) {
// ValueBufferType is inherited
if ( timeScale !== 1.0 ) {
DefaultInterpolation: InterpolateLinear,
var times = this.times;
InterpolantFactoryMethodLinear: function ( result ) {
for ( var i = 0, n = times.length; i !== n; ++ i ) {
return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );
times[ i ] *= timeScale;
},
}
InterpolantFactoryMethodSmooth: undefined // not yet implemented
}
} );
return this;
/**
*
* A Track of numeric keyframe values.
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
},
function NumberKeyframeTrack( name, times, values, interpolation ) {
// removes keyframes before and after animation without changing any values within the range [startTime, endTime].
// IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
trim: function ( startTime, endTime ) {
KeyframeTrackConstructor.call( this, name, times, values, interpolation );
var times = this.times,
nKeys = times.length,
from = 0,
to = nKeys - 1;
}
while ( from !== nKeys && times[ from ] < startTime ) {
NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrackPrototype ), {
++ from;
constructor: NumberKeyframeTrack,
}
ValueTypeName: 'number'
while ( to !== - 1 && times[ to ] > endTime ) {
// ValueBufferType is inherited
-- to;
// DefaultInterpolation is inherited
}
} );
++ to; // inclusive -> exclusive bound
/**
*
* A Track that interpolates Strings
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
if ( from !== 0 || to !== nKeys ) {
function StringKeyframeTrack( name, times, values, interpolation ) {
// empty tracks are forbidden, so keep at least one keyframe
if ( from >= to ) to = Math.max( to, 1 ), from = to - 1;
KeyframeTrackConstructor.call( this, name, times, values, interpolation );
var stride = this.getValueSize();
this.times = AnimationUtils.arraySlice( times, from, to );
this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride );
}
}
StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrackPrototype ), {
return this;
constructor: StringKeyframeTrack,
},
ValueTypeName: 'string',
ValueBufferType: Array,
// ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
validate: function () {
DefaultInterpolation: InterpolateDiscrete,
var valid = true;
InterpolantFactoryMethodLinear: undefined,
var valueSize = this.getValueSize();
if ( valueSize - Math.floor( valueSize ) !== 0 ) {
InterpolantFactoryMethodSmooth: undefined
console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this );
valid = false;
} );
}
/**
*
* A Track of Boolean keyframe values.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
var times = this.times,
values = this.values,
function BooleanKeyframeTrack( name, times, values ) {
nKeys = times.length;
KeyframeTrackConstructor.call( this, name, times, values );
if ( nKeys === 0 ) {
}
console.error( 'THREE.KeyframeTrack: Track is empty.', this );
valid = false;
BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrackPrototype ), {
}
constructor: BooleanKeyframeTrack,
var prevTime = null;
ValueTypeName: 'bool',
ValueBufferType: Array,
for ( var i = 0; i !== nKeys; i ++ ) {
DefaultInterpolation: InterpolateDiscrete,
var currTime = times[ i ];
InterpolantFactoryMethodLinear: undefined,
InterpolantFactoryMethodSmooth: undefined
if ( typeof currTime === 'number' && isNaN( currTime ) ) {
// Note: Actually this track could have a optimized / compressed
// representation of a single value and a custom interpolant that
// computes "firstValue ^ isOdd( index )".
console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime );
valid = false;
break;
} );
}
/**
*
* A Track of keyframe values that represent color.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
if ( prevTime !== null && prevTime > currTime ) {
function ColorKeyframeTrack( name, times, values, interpolation ) {
console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime );
valid = false;
break;
KeyframeTrackConstructor.call( this, name, times, values, interpolation );
}
}
prevTime = currTime;
ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrackPrototype ), {
}
constructor: ColorKeyframeTrack,
if ( values !== undefined ) {
ValueTypeName: 'color'
if ( AnimationUtils.isTypedArray( values ) ) {
// ValueBufferType is inherited
for ( var i = 0, n = values.length; i !== n; ++ i ) {
// DefaultInterpolation is inherited
var value = values[ i ];
if ( isNaN( value ) ) {
// Note: Very basic implementation and nothing special yet.
// However, this is the place for color space parameterization.
console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value );
valid = false;
break;
} );
}
/**
*
* A timed sequence of keyframes for a specific property.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
}
function KeyframeTrack( name, times, values, interpolation ) {
}
KeyframeTrackConstructor.apply( this, name, times, values, interpolation );
}
}
return valid;
KeyframeTrack.prototype = KeyframeTrackPrototype;
KeyframeTrackPrototype.constructor = KeyframeTrack;
},
// Static methods:
// removes equivalent sequential keys as common in morph target sequences
// (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
optimize: function () {
Object.assign( KeyframeTrack, {
var times = this.times,
values = this.values,
stride = this.getValueSize(),
// Serialization (in static context, because of constructor invocation
// and automatic invocation of .toJSON):
smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
parse: function ( json ) {
writeIndex = 1,
lastIndex = times.length - 1;
if ( json.type === undefined ) {
for ( var i = 1; i < lastIndex; ++ i ) {
throw new Error( 'track type undefined, can not parse' );
var keep = false;
}
var time = times[ i ];
var timeNext = times[ i + 1 ];
var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type );
// remove adjacent keyframes scheduled at the same time
if ( json.times === undefined ) {
if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) {
var times = [], values = [];
if ( ! smoothInterpolation ) {
AnimationUtils.flattenJSON( json.keys, times, values, 'value' );
// remove unnecessary keyframes same as their neighbors
json.times = times;
json.values = values;
var offset = i * stride,
offsetP = offset - stride,
offsetN = offset + stride;
}
for ( var j = 0; j !== stride; ++ j ) {
// derived classes can define a static parse method
if ( trackType.parse !== undefined ) {
var value = values[ offset + j ];
return trackType.parse( json );
if ( value !== values[ offsetP + j ] ||
value !== values[ offsetN + j ] ) {
} else {
keep = true;
break;
// by default, we assume a constructor compatible with the base
return new trackType( json.name, json.times, json.values, json.interpolation );
}
}
}
},
} else {
toJSON: function ( track ) {
keep = true;
var trackType = track.constructor;
}
var json;
}
// derived classes can define a static toJSON method
if ( trackType.toJSON !== undefined ) {
// in-place compaction
json = trackType.toJSON( track );
if ( keep ) {
} else {
if ( i !== writeIndex ) {
// by default, we assume the data can be serialized as-is
json = {
times[ writeIndex ] = times[ i ];
'name': track.name,
'times': AnimationUtils.convertArray( track.times, Array ),
'values': AnimationUtils.convertArray( track.values, Array )
var readOffset = i * stride,
writeOffset = writeIndex * stride;
};
for ( var j = 0; j !== stride; ++ j ) {
var interpolation = track.getInterpolation();
values[ writeOffset + j ] = values[ readOffset + j ];
if ( interpolation !== track.DefaultInterpolation ) {
}
json.interpolation = interpolation;
}
++ writeIndex;
}
}
json.type = track.ValueTypeName; // mandatory
// flush last keyframe (compaction looks ahead)
return json;
if ( lastIndex > 0 ) {
},
times[ writeIndex ] = times[ lastIndex ];
_getTrackTypeForValueTypeName: function ( typeName ) {
for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {
switch ( typeName.toLowerCase() ) {
values[ writeOffset + j ] = values[ readOffset + j ];
case 'scalar':
case 'double':
case 'float':
case 'number':
case 'integer':
}
return NumberKeyframeTrack;
++ writeIndex;
case 'vector':
case 'vector2':
case 'vector3':
case 'vector4':
}
return VectorKeyframeTrack;
if ( writeIndex !== times.length ) {
case 'color':
this.times = AnimationUtils.arraySlice( times, 0, writeIndex );
this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );
return ColorKeyframeTrack;
}
case 'quaternion':
return this;
return QuaternionKeyframeTrack;
}
case 'bool':
case 'boolean':
} );
return BooleanKeyframeTrack;
/**
*
* A Track of vectored keyframe values.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
* @author tschw
*/
case 'string':
function VectorKeyframeTrack( name, times, values, interpolation ) {
return StringKeyframeTrack;
KeyframeTrack.call( this, name, times, values, interpolation );
}
}
throw new Error( 'Unsupported typeName: ' + typeName );
VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
}
constructor: VectorKeyframeTrack,
ValueTypeName: 'vector'
// ValueBufferType is inherited
// DefaultInterpolation is inherited
} );
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册