From 16d45f5c5b7ef7ce7758dfccfc5b454627f9b903 Mon Sep 17 00:00:00 2001 From: tschw Date: Sun, 1 May 2016 02:53:29 +0200 Subject: [PATCH] Reintroduced AnimationAction (separate file). (#8774) - See #8749 --- src/animation/AnimationAction.js | 665 +++++++++++++++++++++++++++++++ src/animation/AnimationMixer.js | 649 +----------------------------- utils/build/includes/common.json | 1 + 3 files changed, 668 insertions(+), 647 deletions(-) create mode 100644 src/animation/AnimationAction.js diff --git a/src/animation/AnimationAction.js b/src/animation/AnimationAction.js new file mode 100644 index 0000000000..036328c68e --- /dev/null +++ b/src/animation/AnimationAction.js @@ -0,0 +1,665 @@ +/** + * + * Action provided by AnimationMixer for scheduling clip playback on specific + * objects. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + * + */ + +THREE.AnimationAction = function() { + + throw new Error( "THREE.AnimationAction: " + + "Use mixer.clipAction for construction." ); + +}; + +THREE.AnimationAction._new = + function AnimationAction( mixer, clip, localRoot ) { + + this._mixer = mixer; + this._clip = clip; + this._localRoot = localRoot || null; + + var tracks = clip.tracks, + nTracks = tracks.length, + interpolants = new Array( nTracks ); + + var interpolantSettings = { + endingStart: THREE.ZeroCurvatureEnding, + endingEnd: THREE.ZeroCurvatureEnding + }; + + for ( var i = 0; i !== nTracks; ++ i ) { + + var interpolant = tracks[ i ].createInterpolant( null ); + interpolants[ i ] = interpolant; + interpolant.settings = interpolantSettings; + + } + + this._interpolantSettings = interpolantSettings; + + this._interpolants = interpolants; // bound by the mixer + + // inside: PropertyMixer (managed by the mixer) + this._propertyBindings = new Array( nTracks ); + + this._cacheIndex = null; // for the memory manager + this._byClipCacheIndex = null; // for the memory manager + + this._timeScaleInterpolant = null; + this._weightInterpolant = null; + + this.loop = THREE.LoopRepeat; + this._loopCount = -1; + + // global mixer time when the action is to be started + // it's set back to 'null' upon start of the action + this._startTime = null; + + // scaled local time of the action + // gets clamped or wrapped to 0..clip.duration according to loop + this.time = 0; + + this.timeScale = 1; + this._effectiveTimeScale = 1; + + this.weight = 1; + this._effectiveWeight = 1; + + this.repetitions = Infinity; // no. of repetitions when looping + + this.paused = false; // false -> zero effective time scale + this.enabled = true; // true -> zero effective weight + + this.clampWhenFinished = false; // keep feeding the last frame? + + this.zeroSlopeAtStart = true; // for smooth interpolation w/o separate + this.zeroSlopeAtEnd = true; // clips for start, loop and end + +}; + +THREE.AnimationAction._new.prototype = { + + constructor: THREE.AnimationAction._new, + + // State & Scheduling + + play: function() { + + this._mixer._activateAction( this ); + + return this; + + }, + + stop: function() { + + this._mixer._deactivateAction( this ); + + return this.reset(); + + }, + + reset: function() { + + this.paused = false; + this.enabled = true; + + this.time = 0; // restart clip + this._loopCount = -1; // forget previous loops + this._startTime = null; // forget scheduling + + return this.stopFading().stopWarping(); + + }, + + isRunning: function() { + + var start = this._startTime; + + return this.enabled && ! this.paused && this.timeScale !== 0 && + this._startTime === null && this._mixer._isActiveAction( this ); + + }, + + // return true when play has been called + isScheduled: function() { + + return this._mixer._isActiveAction( this ); + + }, + + startAt: function( time ) { + + this._startTime = time; + + return this; + + }, + + setLoop: function( mode, repetitions ) { + + this.loop = mode; + this.repetitions = repetitions; + + return this; + + }, + + // Weight + + // set the weight stopping any scheduled fading + // although .enabled = false yields an effective weight of zero, this + // method does *not* change .enabled, because it would be confusing + setEffectiveWeight: function( weight ) { + + this.weight = weight; + + // note: same logic as when updated at runtime + this._effectiveWeight = this.enabled ? weight : 0; + + return this.stopFading(); + + }, + + // return the weight considering fading and .enabled + getEffectiveWeight: function() { + + return this._effectiveWeight; + + }, + + fadeIn: function( duration ) { + + return this._scheduleFading( duration, 0, 1 ); + + }, + + fadeOut: function( duration ) { + + return this._scheduleFading( duration, 1, 0 ); + + }, + + crossFadeFrom: function( fadeOutAction, duration, warp ) { + + var mixer = this._mixer; + + fadeOutAction.fadeOut( duration ); + this.fadeIn( duration ); + + if( warp ) { + + var fadeInDuration = this._clip.duration, + fadeOutDuration = fadeOutAction._clip.duration, + + startEndRatio = fadeOutDuration / fadeInDuration, + endStartRatio = fadeInDuration / fadeOutDuration; + + fadeOutAction.warp( 1.0, startEndRatio, duration ); + this.warp( endStartRatio, 1.0, duration ); + + } + + return this; + + }, + + crossFadeTo: function( fadeInAction, duration, warp ) { + + return fadeInAction.crossFadeFrom( this, duration, warp ); + + }, + + stopFading: function() { + + var weightInterpolant = this._weightInterpolant; + + if ( weightInterpolant !== null ) { + + this._weightInterpolant = null; + this._mixer._takeBackControlInterpolant( weightInterpolant ); + + } + + return this; + + }, + + // Time Scale Control + + // set the weight stopping any scheduled warping + // although .paused = true yields an effective time scale of zero, this + // method does *not* change .paused, because it would be confusing + setEffectiveTimeScale: function( timeScale ) { + + this.timeScale = timeScale; + this._effectiveTimeScale = this.paused ? 0 :timeScale; + + return this.stopWarping(); + + }, + + // return the time scale considering warping and .paused + getEffectiveTimeScale: function() { + + return this._effectiveTimeScale; + + }, + + setDuration: function( duration ) { + + this.timeScale = this._clip.duration / duration; + + return this.stopWarping(); + + }, + + syncWith: function( action ) { + + this.time = action.time; + this.timeScale = action.timeScale; + + return this.stopWarping(); + + }, + + halt: function( duration ) { + + return this.warp( this._currentTimeScale, 0, duration ); + + }, + + warp: function( startTimeScale, endTimeScale, duration ) { + + var mixer = this._mixer, now = mixer.time, + interpolant = this._timeScaleInterpolant, + + timeScale = this.timeScale; + + if ( interpolant === null ) { + + interpolant = mixer._lendControlInterpolant(), + this._timeScaleInterpolant = interpolant; + + } + + var times = interpolant.parameterPositions, + values = interpolant.sampleValues; + + times[ 0 ] = now; + times[ 1 ] = now + duration; + + values[ 0 ] = startTimeScale / timeScale; + values[ 1 ] = endTimeScale / timeScale; + + return this; + + }, + + stopWarping: function() { + + var timeScaleInterpolant = this._timeScaleInterpolant; + + if ( timeScaleInterpolant !== null ) { + + this._timeScaleInterpolant = null; + this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); + + } + + return this; + + }, + + // Object Accessors + + getMixer: function() { + + return this._mixer; + + }, + + getClip: function() { + + return this._clip; + + }, + + getRoot: function() { + + return this._localRoot || this._mixer._root; + + }, + + // Interna + + _update: function( time, deltaTime, timeDirection, accuIndex ) { + // called by the mixer + + var startTime = this._startTime; + + if ( startTime !== null ) { + + // check for scheduled start of action + + var timeRunning = ( time - startTime ) * timeDirection; + if ( timeRunning < 0 || timeDirection === 0 ) { + + return; // yet to come / don't decide when delta = 0 + + } + + // start + + this._startTime = null; // unschedule + deltaTime = timeDirection * timeRunning; + + } + + // apply time scale and advance time + + deltaTime *= this._updateTimeScale( time ); + var clipTime = this._updateTime( deltaTime ); + + // note: _updateTime may disable the action resulting in + // an effective weight of 0 + + var weight = this._updateWeight( time ); + + if ( weight > 0 ) { + + var interpolants = this._interpolants; + var propertyMixers = this._propertyBindings; + + for ( var j = 0, m = interpolants.length; j !== m; ++ j ) { + + interpolants[ j ].evaluate( clipTime ); + propertyMixers[ j ].accumulate( accuIndex, weight ); + + } + + } + + }, + + _updateWeight: function( time ) { + + var weight = 0; + + if ( this.enabled ) { + + weight = this.weight; + var interpolant = this._weightInterpolant; + + if ( interpolant !== null ) { + + var interpolantValue = interpolant.evaluate( time )[ 0 ]; + + weight *= interpolantValue; + + if ( time > interpolant.parameterPositions[ 1 ] ) { + + this.stopFading(); + + if ( interpolantValue === 0 ) { + + // faded out, disable + this.enabled = false; + + } + + } + + } + + } + + this._effectiveWeight = weight; + return weight; + + }, + + _updateTimeScale: function( time ) { + + var timeScale = 0; + + if ( ! this.paused ) { + + timeScale = this.timeScale; + + var interpolant = this._timeScaleInterpolant; + + if ( interpolant !== null ) { + + var interpolantValue = interpolant.evaluate( time )[ 0 ]; + + timeScale *= interpolantValue; + + if ( time > interpolant.parameterPositions[ 1 ] ) { + + this.stopWarping(); + + if ( timeScale === 0 ) { + + // motion has halted, pause + this.pause = true; + + } else { + + // warp done - apply final time scale + this.timeScale = timeScale; + + } + + } + + } + + } + + this._effectiveTimeScale = timeScale; + return timeScale; + + }, + + _updateTime: function( deltaTime ) { + + var time = this.time + deltaTime; + + if ( deltaTime === 0 ) return time; + + var duration = this._clip.duration, + + loop = this.loop, + loopCount = this._loopCount; + + if ( loop === THREE.LoopOnce ) { + + if ( loopCount === -1 ) { + // just started + + this.loopCount = 0; + this._setEndings( true, true, false ); + + } + + handle_stop: { + + if ( time >= duration ) { + + time = duration; + + } else if ( time < 0 ) { + + time = 0; + + } else break handle_stop; + + if ( this.clampWhenFinished ) this.pause = true; + else this.enabled = false; + + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime < 0 ? -1 : 1 + } ); + + } + + } else { // repetitive Repeat or PingPong + + var pingPong = ( loop === THREE.LoopPingPong ); + + if ( loopCount === -1 ) { + // just started + + if ( deltaTime >= 0 ) { + + loopCount = 0; + + this._setEndings( + true, this.repetitions === 0, pingPong ); + + } else { + + // when looping in reverse direction, the initial + // transition through zero counts as a repetition, + // so leave loopCount at -1 + + this._setEndings( + this.repetitions === 0, true, pingPong ); + + } + + } + + if ( time >= duration || time < 0 ) { + // wrap around + + var loopDelta = Math.floor( time / duration ); // signed + time -= duration * loopDelta; + + loopCount += Math.abs( loopDelta ); + + var pending = this.repetitions - loopCount; + + if ( pending < 0 ) { + // have to stop (switch state, clamp time, fire event) + + if ( this.clampWhenFinished ) this.paused = true; + else this.enabled = false; + + time = deltaTime > 0 ? duration : 0; + + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime > 0 ? 1 : -1 + } ); + + } else { + // keep running + + if ( pending === 0 ) { + // entering the last round + + var atStart = deltaTime < 0; + this._setEndings( atStart, ! atStart, pingPong ); + + } else { + + this._setEndings( false, false, pingPong ); + + } + + this._loopCount = loopCount; + + this._mixer.dispatchEvent( { + type: 'loop', action: this, loopDelta: loopDelta + } ); + + } + + } + + if ( pingPong && ( loopCount & 1 ) === 1 ) { + // invert time for the "pong round" + + this.time = time; + return duration - time; + + } + + } + + this.time = time; + return time; + + }, + + _setEndings: function( atStart, atEnd, pingPong ) { + + var settings = this._interpolantSettings; + + if ( pingPong ) { + + settings.endingStart = THREE.ZeroSlopeEnding; + settings.endingEnd = THREE.ZeroSlopeEnding; + + } else { + + // assuming for LoopOnce atStart == atEnd == true + + if ( atStart ) { + + settings.endingStart = this.zeroSlopeAtStart ? + THREE.ZeroSlopeEnding : THREE.ZeroCurvatureEnding; + + } else { + + settings.endingStart = THREE.WrapAroundEnding; + + } + + if ( atEnd ) { + + settings.endingEnd = this.zeroSlopeAtEnd ? + THREE.ZeroSlopeEnding : THREE.ZeroCurvatureEnding; + + } else { + + settings.endingEnd = THREE.WrapAroundEnding; + + } + + } + + }, + + _scheduleFading: function( duration, weightNow, weightThen ) { + + var mixer = this._mixer, now = mixer.time, + interpolant = this._weightInterpolant; + + if ( interpolant === null ) { + + interpolant = mixer._lendControlInterpolant(), + this._weightInterpolant = interpolant; + + } + + var times = interpolant.parameterPositions, + values = interpolant.sampleValues; + + times[ 0 ] = now; values[ 0 ] = weightNow; + times[ 1 ] = now + duration; values[ 1 ] = weightThen; + + return this; + + } + +}; + diff --git a/src/animation/AnimationMixer.js b/src/animation/AnimationMixer.js index 8129af408f..50cd06e8b2 100644 --- a/src/animation/AnimationMixer.js +++ b/src/animation/AnimationMixer.js @@ -269,654 +269,9 @@ THREE.AnimationMixer.prototype = { }; -THREE.EventDispatcher.prototype.apply( THREE.AnimationMixer.prototype ); - -THREE.AnimationMixer._Action = - function( mixer, clip, localRoot ) { - - this._mixer = mixer; - this._clip = clip; - this._localRoot = localRoot || null; - - var tracks = clip.tracks, - nTracks = tracks.length, - interpolants = new Array( nTracks ); - - var interpolantSettings = { - endingStart: THREE.ZeroCurvatureEnding, - endingEnd: THREE.ZeroCurvatureEnding - }; - - for ( var i = 0; i !== nTracks; ++ i ) { - - var interpolant = tracks[ i ].createInterpolant( null ); - interpolants[ i ] = interpolant; - interpolant.settings = interpolantSettings; - - } - - this._interpolantSettings = interpolantSettings; - - this._interpolants = interpolants; // bound by the mixer - - // inside: PropertyMixer (managed by the mixer) - this._propertyBindings = new Array( nTracks ); - - this._cacheIndex = null; // for the memory manager - this._byClipCacheIndex = null; // for the memory manager - - this._timeScaleInterpolant = null; - this._weightInterpolant = null; - - this.loop = THREE.LoopRepeat; - this._loopCount = -1; - - // global mixer time when the action is to be started - // it's set back to 'null' upon start of the action - this._startTime = null; - - // scaled local time of the action - // gets clamped or wrapped to 0..clip.duration according to loop - this.time = 0; - - this.timeScale = 1; - this._effectiveTimeScale = 1; - - this.weight = 1; - this._effectiveWeight = 1; - - this.repetitions = Infinity; // no. of repetitions when looping - - this.paused = false; // false -> zero effective time scale - this.enabled = true; // true -> zero effective weight - - this.clampWhenFinished = false; // keep feeding the last frame? - - this.zeroSlopeAtStart = true; // for smooth interpolation w/o separate - this.zeroSlopeAtEnd = true; // clips for start, loop and end - -}; - -THREE.AnimationMixer._Action.prototype = { - - constructor: THREE.AnimationMixer._Action, - - // State & Scheduling - - play: function() { - - this._mixer._activateAction( this ); - - return this; - - }, - - stop: function() { - - this._mixer._deactivateAction( this ); - - return this.reset(); - - }, - - reset: function() { - - this.paused = false; - this.enabled = true; - - this.time = 0; // restart clip - this._loopCount = -1; // forget previous loops - this._startTime = null; // forget scheduling - - return this.stopFading().stopWarping(); - - }, - - isRunning: function() { - - var start = this._startTime; - - return this.enabled && ! this.paused && this.timeScale !== 0 && - this._startTime === null && this._mixer._isActiveAction( this ); - - }, - - // return true when play has been called - isScheduled: function() { - - return this._mixer._isActiveAction( this ); - - }, - - startAt: function( time ) { - - this._startTime = time; - - return this; - - }, - - setLoop: function( mode, repetitions ) { - - this.loop = mode; - this.repetitions = repetitions; - - return this; - - }, - - // Weight - - // set the weight stopping any scheduled fading - // although .enabled = false yields an effective weight of zero, this - // method does *not* change .enabled, because it would be confusing - setEffectiveWeight: function( weight ) { - - this.weight = weight; - - // note: same logic as when updated at runtime - this._effectiveWeight = this.enabled ? weight : 0; - - return this.stopFading(); - - }, - - // return the weight considering fading and .enabled - getEffectiveWeight: function() { - - return this._effectiveWeight; - - }, - - fadeIn: function( duration ) { - - return this._scheduleFading( duration, 0, 1 ); - - }, - - fadeOut: function( duration ) { - - return this._scheduleFading( duration, 1, 0 ); - - }, - - crossFadeFrom: function( fadeOutAction, duration, warp ) { - - var mixer = this._mixer; - - fadeOutAction.fadeOut( duration ); - this.fadeIn( duration ); - - if( warp ) { - - var fadeInDuration = this._clip.duration, - fadeOutDuration = fadeOutAction._clip.duration, - - startEndRatio = fadeOutDuration / fadeInDuration, - endStartRatio = fadeInDuration / fadeOutDuration; - - fadeOutAction.warp( 1.0, startEndRatio, duration ); - this.warp( endStartRatio, 1.0, duration ); - - } - - return this; - - }, - - crossFadeTo: function( fadeInAction, duration, warp ) { - - return fadeInAction.crossFadeFrom( this, duration, warp ); - - }, - - stopFading: function() { - - var weightInterpolant = this._weightInterpolant; - - if ( weightInterpolant !== null ) { - - this._weightInterpolant = null; - this._mixer._takeBackControlInterpolant( weightInterpolant ); - - } - - return this; - - }, - - // Time Scale Control - - // set the weight stopping any scheduled warping - // although .paused = true yields an effective time scale of zero, this - // method does *not* change .paused, because it would be confusing - setEffectiveTimeScale: function( timeScale ) { - - this.timeScale = timeScale; - this._effectiveTimeScale = this.paused ? 0 :timeScale; - - return this.stopWarping(); - - }, - - // return the time scale considering warping and .paused - getEffectiveTimeScale: function() { - - return this._effectiveTimeScale; - - }, - - setDuration: function( duration ) { - - this.timeScale = this._clip.duration / duration; - - return this.stopWarping(); - - }, - - syncWith: function( action ) { - - this.time = action.time; - this.timeScale = action.timeScale; - - return this.stopWarping(); - - }, - - halt: function( duration ) { - - return this.warp( this._currentTimeScale, 0, duration ); - - }, - - warp: function( startTimeScale, endTimeScale, duration ) { - - var mixer = this._mixer, now = mixer.time, - interpolant = this._timeScaleInterpolant, - - timeScale = this.timeScale; - - if ( interpolant === null ) { - - interpolant = mixer._lendControlInterpolant(), - this._timeScaleInterpolant = interpolant; - - } - - var times = interpolant.parameterPositions, - values = interpolant.sampleValues; - - times[ 0 ] = now; - times[ 1 ] = now + duration; - - values[ 0 ] = startTimeScale / timeScale; - values[ 1 ] = endTimeScale / timeScale; - - return this; - - }, - - stopWarping: function() { - - var timeScaleInterpolant = this._timeScaleInterpolant; - - if ( timeScaleInterpolant !== null ) { - - this._timeScaleInterpolant = null; - this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); - - } - - return this; - - }, - - // Object Accessors - - getMixer: function() { - - return this._mixer; - - }, - - getClip: function() { - - return this._clip; - - }, - - getRoot: function() { - - return this._localRoot || this._mixer._root; - - }, - - // Interna +THREE.AnimationMixer._Action = THREE.AnimationAction._new; - _update: function( time, deltaTime, timeDirection, accuIndex ) { - // called by the mixer - - var startTime = this._startTime; - - if ( startTime !== null ) { - - // check for scheduled start of action - - var timeRunning = ( time - startTime ) * timeDirection; - if ( timeRunning < 0 || timeDirection === 0 ) { - - return; // yet to come / don't decide when delta = 0 - - } - - // start - - this._startTime = null; // unschedule - deltaTime = timeDirection * timeRunning; - - } - - // apply time scale and advance time - - deltaTime *= this._updateTimeScale( time ); - var clipTime = this._updateTime( deltaTime ); - - // note: _updateTime may disable the action resulting in - // an effective weight of 0 - - var weight = this._updateWeight( time ); - - if ( weight > 0 ) { - - var interpolants = this._interpolants; - var propertyMixers = this._propertyBindings; - - for ( var j = 0, m = interpolants.length; j !== m; ++ j ) { - - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulate( accuIndex, weight ); - - } - - } - - }, - - _updateWeight: function( time ) { - - var weight = 0; - - if ( this.enabled ) { - - weight = this.weight; - var interpolant = this._weightInterpolant; - - if ( interpolant !== null ) { - - var interpolantValue = interpolant.evaluate( time )[ 0 ]; - - weight *= interpolantValue; - - if ( time > interpolant.parameterPositions[ 1 ] ) { - - this.stopFading(); - - if ( interpolantValue === 0 ) { - - // faded out, disable - this.enabled = false; - - } - - } - - } - - } - - this._effectiveWeight = weight; - return weight; - - }, - - _updateTimeScale: function( time ) { - - var timeScale = 0; - - if ( ! this.paused ) { - - timeScale = this.timeScale; - - var interpolant = this._timeScaleInterpolant; - - if ( interpolant !== null ) { - - var interpolantValue = interpolant.evaluate( time )[ 0 ]; - - timeScale *= interpolantValue; - - if ( time > interpolant.parameterPositions[ 1 ] ) { - - this.stopWarping(); - - if ( timeScale === 0 ) { - - // motion has halted, pause - this.pause = true; - - } else { - - // warp done - apply final time scale - this.timeScale = timeScale; - - } - - } - - } - - } - - this._effectiveTimeScale = timeScale; - return timeScale; - - }, - - _updateTime: function( deltaTime ) { - - var time = this.time + deltaTime; - - if ( deltaTime === 0 ) return time; - - var duration = this._clip.duration, - - loop = this.loop, - loopCount = this._loopCount; - - if ( loop === THREE.LoopOnce ) { - - if ( loopCount === -1 ) { - // just started - - this.loopCount = 0; - this._setEndings( true, true, false ); - - } - - handle_stop: { - - if ( time >= duration ) { - - time = duration; - - } else if ( time < 0 ) { - - time = 0; - - } else break handle_stop; - - if ( this.clampWhenFinished ) this.pause = true; - else this.enabled = false; - - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime < 0 ? -1 : 1 - } ); - - } - - } else { // repetitive Repeat or PingPong - - var pingPong = ( loop === THREE.LoopPingPong ); - - if ( loopCount === -1 ) { - // just started - - if ( deltaTime >= 0 ) { - - loopCount = 0; - - this._setEndings( - true, this.repetitions === 0, pingPong ); - - } else { - - // when looping in reverse direction, the initial - // transition through zero counts as a repetition, - // so leave loopCount at -1 - - this._setEndings( - this.repetitions === 0, true, pingPong ); - - } - - } - - if ( time >= duration || time < 0 ) { - // wrap around - - var loopDelta = Math.floor( time / duration ); // signed - time -= duration * loopDelta; - - loopCount += Math.abs( loopDelta ); - - var pending = this.repetitions - loopCount; - - if ( pending < 0 ) { - // have to stop (switch state, clamp time, fire event) - - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; - - time = deltaTime > 0 ? duration : 0; - - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime > 0 ? 1 : -1 - } ); - - } else { - // keep running - - if ( pending === 0 ) { - // entering the last round - - var atStart = deltaTime < 0; - this._setEndings( atStart, ! atStart, pingPong ); - - } else { - - this._setEndings( false, false, pingPong ); - - } - - this._loopCount = loopCount; - - this._mixer.dispatchEvent( { - type: 'loop', action: this, loopDelta: loopDelta - } ); - - } - - } - - if ( pingPong && ( loopCount & 1 ) === 1 ) { - // invert time for the "pong round" - - this.time = time; - return duration - time; - - } - - } - - this.time = time; - return time; - - }, - - _setEndings: function( atStart, atEnd, pingPong ) { - - var settings = this._interpolantSettings; - - if ( pingPong ) { - - settings.endingStart = THREE.ZeroSlopeEnding; - settings.endingEnd = THREE.ZeroSlopeEnding; - - } else { - - // assuming for LoopOnce atStart == atEnd == true - - if ( atStart ) { - - settings.endingStart = this.zeroSlopeAtStart ? - THREE.ZeroSlopeEnding : THREE.ZeroCurvatureEnding; - - } else { - - settings.endingStart = THREE.WrapAroundEnding; - - } - - if ( atEnd ) { - - settings.endingEnd = this.zeroSlopeAtEnd ? - THREE.ZeroSlopeEnding : THREE.ZeroCurvatureEnding; - - } else { - - settings.endingEnd = THREE.WrapAroundEnding; - - } - - } - - }, - - _scheduleFading: function( duration, weightNow, weightThen ) { - - var mixer = this._mixer, now = mixer.time, - interpolant = this._weightInterpolant; - - if ( interpolant === null ) { - - interpolant = mixer._lendControlInterpolant(), - this._weightInterpolant = interpolant; - - } - - var times = interpolant.parameterPositions, - values = interpolant.sampleValues; - - times[ 0 ] = now; values[ 0 ] = weightNow; - times[ 1 ] = now + duration; values[ 1 ] = weightThen; - - return this; - - } - -}; +THREE.EventDispatcher.prototype.apply( THREE.AnimationMixer.prototype ); // Implementation details: diff --git a/utils/build/includes/common.json b/utils/build/includes/common.json index e98e66d8a7..e4b0cce7df 100644 --- a/utils/build/includes/common.json +++ b/utils/build/includes/common.json @@ -40,6 +40,7 @@ "src/core/BufferGeometry.js", "src/core/InstancedBufferGeometry.js", "src/core/Uniform.js", + "src/animation/AnimationAction.js", "src/animation/AnimationClip.js", "src/animation/AnimationMixer.js", "src/animation/AnimationObjectGroup.js", -- GitLab