Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
236 changes: 116 additions & 120 deletions src/animation/AnimationClip.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,104 +9,28 @@ import { VectorKeyframeTrack } from './tracks/VectorKeyframeTrack.js';
import { MathUtils } from '../math/MathUtils.js';
import { NormalAnimationBlendMode } from '../constants.js';

function AnimationClip( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) {
class AnimationClip {

this.name = name;
this.tracks = tracks;
this.duration = duration;
this.blendMode = blendMode;
constructor( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) {

this.uuid = MathUtils.generateUUID();

// this means it should figure out its duration by scanning the tracks
if ( this.duration < 0 ) {

this.resetDuration();

}

}

function getTrackTypeForValueTypeName( typeName ) {

switch ( typeName.toLowerCase() ) {

case 'scalar':
case 'double':
case 'float':
case 'number':
case 'integer':

return NumberKeyframeTrack;

case 'vector':
case 'vector2':
case 'vector3':
case 'vector4':

return VectorKeyframeTrack;

case 'color':

return ColorKeyframeTrack;

case 'quaternion':

return QuaternionKeyframeTrack;

case 'bool':
case 'boolean':

return BooleanKeyframeTrack;

case 'string':

return StringKeyframeTrack;

}

throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );

}

function parseKeyframeTrack( json ) {

if ( json.type === undefined ) {

throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );

}

const trackType = getTrackTypeForValueTypeName( json.type );

if ( json.times === undefined ) {

const times = [], values = [];

AnimationUtils.flattenJSON( json.keys, times, values, 'value' );

json.times = times;
json.values = values;

}
this.name = name;
this.tracks = tracks;
this.duration = duration;
this.blendMode = blendMode;

// derived classes can define a static parse method
if ( trackType.parse !== undefined ) {
this.uuid = MathUtils.generateUUID();

return trackType.parse( json );
// this means it should figure out its duration by scanning the tracks
if ( this.duration < 0 ) {

} else {
this.resetDuration();

// by default, we assume a constructor compatible with the base
return new trackType( json.name, json.times, json.values, json.interpolation );
}

}

}

Object.assign( AnimationClip, {

parse: function ( json ) {
static parse( json ) {

const tracks = [],
jsonTracks = json.tracks,
Expand All @@ -118,14 +42,14 @@ Object.assign( AnimationClip, {

}

const clip = new AnimationClip( json.name, json.duration, tracks, json.blendMode );
const clip = new this( json.name, json.duration, tracks, json.blendMode );
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah! I didn't know you could do new this() 🤓

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, I see you do new this.constructor a bit further down the file. What's the difference?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah! If you are constructing from a static method you can use this(), otherwise you have to use this.constructor()

class Foo {

  constructor(attributes) {
    Object.assign(this, attributes);
  }

  static create(attributes) {
    return new this(attributes);
  }

  clone() {
    return new this.constructor(this) ;
  }
}

class Bar extends Foo { }


const objects = [
 new Foo({ name: 'foo1' }),
 Foo.create({ name: 'foo2' }),
 new Foo({ name: 'foo3' }).clone(),
 new Bar({ name: 'bar1' }),
 Bar.create({ name: 'bar2' }),
 new Bar({ name: 'bar3' }).clone(),
]

for (const obj of objects) {
  console.log(obj);
}

Outputs -->

Foo { name: 'foo1' }
Foo { name: 'foo2' }
Foo { name: 'foo3' }
Bar { name: 'bar1' }
Bar { name: 'bar2' }
Bar { name: 'bar3' }

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dang. You know your stuff! 🙏

clip.uuid = json.uuid;

return clip;

},
}

toJSON: function ( clip ) {
static toJSON( clip ) {

const tracks = [],
clipTracks = clip.tracks;
Expand All @@ -148,9 +72,9 @@ Object.assign( AnimationClip, {

return json;

},
}

CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) {
static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) {

const numMorphTargets = morphTargetSequence.length;
const tracks = [];
Expand Down Expand Up @@ -188,11 +112,11 @@ Object.assign( AnimationClip, {

}

return new AnimationClip( name, - 1, tracks );
return new this( name, - 1, tracks );

},
}

findByName: function ( objectOrClipArray, name ) {
static findByName( objectOrClipArray, name ) {

let clipArray = objectOrClipArray;

Expand All @@ -215,9 +139,9 @@ Object.assign( AnimationClip, {

return null;

},
}

CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) {
static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) {

const animationToMorphTargets = {};

Expand Down Expand Up @@ -254,16 +178,16 @@ Object.assign( AnimationClip, {

for ( const name in animationToMorphTargets ) {

clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );
clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );

}

return clips;

},
}

// parse the animation.hierarchy format
parseAnimation: function ( animation, bones ) {
static parseAnimation( animation, bones ) {

if ( ! animation ) {

Expand Down Expand Up @@ -384,17 +308,13 @@ Object.assign( AnimationClip, {

}

const clip = new AnimationClip( clipName, duration, tracks, blendMode );
const clip = new this( clipName, duration, tracks, blendMode );

return clip;

}

} );

Object.assign( AnimationClip.prototype, {

resetDuration: function () {
resetDuration() {

const tracks = this.tracks;
let duration = 0;
Expand All @@ -411,9 +331,9 @@ Object.assign( AnimationClip.prototype, {

return this;

},
}

trim: function () {
trim() {

for ( let i = 0; i < this.tracks.length; i ++ ) {

Expand All @@ -423,9 +343,9 @@ Object.assign( AnimationClip.prototype, {

return this;

},
}

validate: function () {
validate() {

let valid = true;

Expand All @@ -437,9 +357,9 @@ Object.assign( AnimationClip.prototype, {

return valid;

},
}

optimize: function () {
optimize() {

for ( let i = 0; i < this.tracks.length; i ++ ) {

Expand All @@ -449,9 +369,9 @@ Object.assign( AnimationClip.prototype, {

return this;

},
}

clone: function () {
clone() {

const tracks = [];

Expand All @@ -461,17 +381,93 @@ Object.assign( AnimationClip.prototype, {

}

return new AnimationClip( this.name, this.duration, tracks, this.blendMode );
return new this.constructor( this.name, this.duration, tracks, this.blendMode );

}

toJSON() {

return this.constructor.toJSON( this );

}

}

function getTrackTypeForValueTypeName( typeName ) {

switch ( typeName.toLowerCase() ) {

case 'scalar':
case 'double':
case 'float':
case 'number':
case 'integer':

return NumberKeyframeTrack;

case 'vector':
case 'vector2':
case 'vector3':
case 'vector4':

return VectorKeyframeTrack;

case 'color':

return ColorKeyframeTrack;

case 'quaternion':

return QuaternionKeyframeTrack;

case 'bool':
case 'boolean':

return BooleanKeyframeTrack;

case 'string':

return StringKeyframeTrack;

}

throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );

}

function parseKeyframeTrack( json ) {

if ( json.type === undefined ) {

throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );

}

const trackType = getTrackTypeForValueTypeName( json.type );

},
if ( json.times === undefined ) {

toJSON: function () {
const times = [], values = [];

return AnimationClip.toJSON( this );
AnimationUtils.flattenJSON( json.keys, times, values, 'value' );

json.times = times;
json.values = values;

}

} );
// derived classes can define a static parse method
if ( trackType.parse !== undefined ) {

return trackType.parse( json );

} else {

// by default, we assume a constructor compatible with the base
return new trackType( json.name, json.times, json.values, json.interpolation );

}

}

export { AnimationClip };
Loading