You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

234 lines
6.3 KiB
JavaScript

import defaultValue from "../Core/defaultValue.js";
import Event from "../Core/Event.js";
import JulianDate from "../Core/JulianDate.js";
import ModelAnimationLoop from "./ModelAnimationLoop.js";
import ModelAnimationState from "./ModelAnimationState.js";
/**
* An active glTF animation. A glTF asset can contain animations. An active animation
* is an animation that is currently playing or scheduled to be played because it was
* added to a model's {@link ModelAnimationCollection}. An active animation is an
* instance of an animation; for example, there can be multiple active animations
* for the same glTF animation, each with a different start time.
* <p>
* Create this by calling {@link ModelAnimationCollection#add}.
* </p>
*
* @alias ModelAnimation
* @internalConstructor
* @class
*
* @see ModelAnimationCollection#add
*/
function ModelAnimation(options, model, runtimeAnimation) {
this._name = runtimeAnimation.name;
this._startTime = JulianDate.clone(options.startTime);
this._delay = defaultValue(options.delay, 0.0); // in seconds
this._stopTime = options.stopTime;
/**
* When <code>true</code>, the animation is removed after it stops playing.
* This is slightly more efficient that not removing it, but if, for example,
* time is reversed, the animation is not played again.
*
* @type {Boolean}
* @default false
*/
this.removeOnStop = defaultValue(options.removeOnStop, false);
this._multiplier = defaultValue(options.multiplier, 1.0);
this._reverse = defaultValue(options.reverse, false);
this._loop = defaultValue(options.loop, ModelAnimationLoop.NONE);
/**
* The event fired when this animation is started. This can be used, for
* example, to play a sound or start a particle system, when the animation starts.
* <p>
* This event is fired at the end of the frame after the scene is rendered.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* animation.start.addEventListener(function(model, animation) {
* console.log('Animation started: ' + animation.name);
* });
*/
this.start = new Event();
/**
* The event fired when on each frame when this animation is updated. The
* current time of the animation, relative to the glTF animation time span, is
* passed to the event, which allows, for example, starting new animations at a
* specific time relative to a playing animation.
* <p>
* This event is fired at the end of the frame after the scene is rendered.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* animation.update.addEventListener(function(model, animation, time) {
* console.log('Animation updated: ' + animation.name + '. glTF animation time: ' + time);
* });
*/
this.update = new Event();
/**
* The event fired when this animation is stopped. This can be used, for
* example, to play a sound or start a particle system, when the animation stops.
* <p>
* This event is fired at the end of the frame after the scene is rendered.
* </p>
*
* @type {Event}
* @default new Event()
*
* @example
* animation.stop.addEventListener(function(model, animation) {
* console.log('Animation stopped: ' + animation.name);
* });
*/
this.stop = new Event();
this._state = ModelAnimationState.STOPPED;
this._runtimeAnimation = runtimeAnimation;
// Set during animation update
this._computedStartTime = undefined;
this._duration = undefined;
// To avoid allocations in ModelAnimationCollection.update
var that = this;
this._raiseStartEvent = function () {
that.start.raiseEvent(model, that);
};
this._updateEventTime = 0.0;
this._raiseUpdateEvent = function () {
that.update.raiseEvent(model, that, that._updateEventTime);
};
this._raiseStopEvent = function () {
that.stop.raiseEvent(model, that);
};
}
Object.defineProperties(ModelAnimation.prototype, {
/**
* The glTF animation name that identifies this animation.
*
* @memberof ModelAnimation.prototype
*
* @type {String}
* @readonly
*/
name: {
get: function () {
return this._name;
},
},
/**
* The scene time to start playing this animation. When this is <code>undefined</code>,
* the animation starts at the next frame.
*
* @memberof ModelAnimation.prototype
*
* @type {JulianDate}
* @readonly
*
* @default undefined
*/
startTime: {
get: function () {
return this._startTime;
},
},
/**
* The delay, in seconds, from {@link ModelAnimation#startTime} to start playing.
*
* @memberof ModelAnimation.prototype
*
* @type {Number}
* @readonly
*
* @default undefined
*/
delay: {
get: function () {
return this._delay;
},
},
/**
* The scene time to stop playing this animation. When this is <code>undefined</code>,
* the animation is played for its full duration and perhaps repeated depending on
* {@link ModelAnimation#loop}.
*
* @memberof ModelAnimation.prototype
*
* @type {JulianDate}
* @readonly
*
* @default undefined
*/
stopTime: {
get: function () {
return this._stopTime;
},
},
/**
* Values greater than <code>1.0</code> increase the speed that the animation is played relative
* to the scene clock speed; values less than <code>1.0</code> decrease the speed. A value of
* <code>1.0</code> plays the animation at the speed in the glTF animation mapped to the scene
* clock speed. For example, if the scene is played at 2x real-time, a two-second glTF animation
* will play in one second even if <code>multiplier</code> is <code>1.0</code>.
*
* @memberof ModelAnimation.prototype
*
* @type {Number}
* @readonly
*
* @default 1.0
*/
multiplier: {
get: function () {
return this._multiplier;
},
},
/**
* When <code>true</code>, the animation is played in reverse.
*
* @memberof ModelAnimation.prototype
*
* @type {Boolean}
* @readonly
*
* @default false
*/
reverse: {
get: function () {
return this._reverse;
},
},
/**
* Determines if and how the animation is looped.
*
* @memberof ModelAnimation.prototype
*
* @type {ModelAnimationLoop}
* @readonly
*
* @default {@link ModelAnimationLoop.NONE}
*/
loop: {
get: function () {
return this._loop;
},
},
});
export default ModelAnimation;