|
@@ -1,500 +0,0 @@
|
|
|
-# Copyright 2012 United States Government, as represented by the Secretary of Defense, Under
|
|
|
-# Secretary of Defense (Personnel & Readiness).
|
|
|
-#
|
|
|
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
|
-# in compliance with the License. You may obtain a copy of the License at
|
|
|
-#
|
|
|
-# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
-#
|
|
|
-# Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
|
-# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
|
-# or implied. See the License for the specific language governing permissions and limitations under
|
|
|
-# the License.
|
|
|
-
|
|
|
-## `animation.vwf` adds standard animation functions to a node.
|
|
|
-##
|
|
|
-## Animations play over a given `animationDuration` and at a given `animationRate` with respect to
|
|
|
-## simulation time. `animationTime` tracks time as the animation plays. Setting `animationTime`
|
|
|
-## moves the animation. The animation plays once to the end, or with `animationLoop` repeats
|
|
|
-## indefinitely.
|
|
|
-##
|
|
|
-## Events are sent to indicate `animationStarted`, `animationStopped` and `animationLooped`. Changes
|
|
|
-## to the animation time are announced with `animationTimeChanged.`
|
|
|
-##
|
|
|
-## A node may provide an `animationUpdate` method to calculate its own animation state, or it may
|
|
|
-## use a specialized behavior that implements a standard animation.
|
|
|
-##
|
|
|
-## @name animation.vwf
|
|
|
-## @namespace
|
|
|
-
|
|
|
-# The duration must be a non-negative number, times are always in the range [ `0`, `duration` ], and
|
|
|
-# the rate may be any number (although there is little protection against rates very near zero).
|
|
|
-#
|
|
|
-# 0 <= animationDuration
|
|
|
-# 0 <= animationTime <= animationDuration
|
|
|
-# -Infinity < animationRate < Infinity
|
|
|
-#
|
|
|
-# The animation play state and time index are maintained in `animationStart$` and
|
|
|
-# `animationPause$`. `animationPause$` is `null` while the animation is playing. The
|
|
|
-# distance from `animationStart$` to the current time (when playing) or `animationPause$`
|
|
|
-# (when paused) gives the time index, after accounting for the play rate.
|
|
|
-#
|
|
|
-# animationTime = ( ( animationPause$ || time ) - ( animationStart$ || time ) ) *
|
|
|
-# animationRate (positive rates)
|
|
|
-# animationTime = ( ( animationPause$ || time ) - ( animationStart$ || time ) ) *
|
|
|
-# animationRate + animationDuration (negative rates)
|
|
|
-#
|
|
|
-# animationPlaying = this.animationStart$ != null && this.animationPause$ == null
|
|
|
-#
|
|
|
-# `animationStart$` and `animationPause$` are `null` before the animation is first played.
|
|
|
-# This state is interpreted as `animationPlaying` == `false` and `animationTime` == `0`.
|
|
|
-#
|
|
|
-# animationStart$ == null => animationPause$ == null
|
|
|
-# animationStart$ == null => animationStop$ == null
|
|
|
-#
|
|
|
-# animationStart$ != null => animationStart$ <= time
|
|
|
-# animationPause$ != null => animationStart$ <= animationPause$ <= time
|
|
|
-# animationStop$ != null => animationStart$ + animationDuration$ == animationStop$
|
|
|
-#
|
|
|
-# animationDuration$ == animationDuration / animationRate (positive rates)
|
|
|
-# animationDuration$ == -animationDuration / animationRate (negative rates)
|
|
|
-#
|
|
|
-# Properties named with a`$` suffix refer to times or durations on the simulation timeline. All
|
|
|
-# other time-related properties refer to the animation timeline.
|
|
|
-
|
|
|
----
|
|
|
-
|
|
|
-properties:
|
|
|
-
|
|
|
- ## The current animation position in seconds.
|
|
|
- ##
|
|
|
- ## `animationTime` automatically moves with the simulation time while the animation is playing,
|
|
|
- ## tracking the change in time multiplied by `animationRate`. A negative `animationRate` will
|
|
|
- ## cause `animationTime` to move backwards. Setting `animationTime` updates the postion whether or
|
|
|
- ## not the animation is currently playing.
|
|
|
-
|
|
|
- animationTime:
|
|
|
-
|
|
|
- set: |
|
|
|
- if(this.animationStartTime == null) {
|
|
|
- this.animationStartTime = 0;
|
|
|
- }
|
|
|
- if(this.animationStopTime == null) {
|
|
|
- this.animationStopTime = this.animationDuration;
|
|
|
- }
|
|
|
- // Save copies to avoid repeated reads.
|
|
|
- var duration = this.animationStopTime - this.animationStartTime,
|
|
|
- rate = this.animationRate;
|
|
|
- // Range limit the incoming value.
|
|
|
- value = Math.min( Math.max( this.animationStartTime, value ), this.animationStopTime );
|
|
|
- // Keep paused if updating start/pause from null/null. Use t=0 instead of `this.time` so that
|
|
|
- // setting `node.animationTime` during initialization is consistent across multiple clients.
|
|
|
- if ( this.animationStart$ == null ) {
|
|
|
- this.animationPause$ = 0;
|
|
|
- }
|
|
|
- // Calculate the start and stop times that makes the new time work.
|
|
|
- this.animationStart$ =
|
|
|
- ( this.animationPause$ != null ? this.animationPause$ : this.time ) -
|
|
|
- ( rate >= 0 ? value - this.animationStartTime : value - duration ) / rate;
|
|
|
- this.animationStop$ =
|
|
|
- this.animationStart$ +
|
|
|
- ( rate >= 0 ? duration : -duration ) / rate;
|
|
|
- // Update the node and fire the changed event.
|
|
|
- if ( value !== this.animationTimeUpdated ) {
|
|
|
- this.animationTimeUpdated = value;
|
|
|
- this.animationUpdate( value, this.animationDuration );
|
|
|
- this.animationTimeChanged( value );
|
|
|
- } //@ sourceURL=animation.animationTime.set.vwf
|
|
|
-
|
|
|
- get: |
|
|
|
- // Save copies to avoid repeated reads.
|
|
|
- var startTime = this.animationStartTime;
|
|
|
- var stopTime = this.animationStopTime;
|
|
|
- var rate = this.animationRate;
|
|
|
- var animationPause$ = this.animationPause$;
|
|
|
- var animationStart$ = this.animationStart$;
|
|
|
- var time = this.time;
|
|
|
- // Calculate the time from the start and current/pause times.
|
|
|
- var value = (
|
|
|
- ( animationPause$ != null ? animationPause$ : time ) -
|
|
|
- ( animationStart$ != null ? animationStart$ : time )
|
|
|
- ) * rate + ( rate >= 0 ? startTime : stopTime );
|
|
|
- // Range limit the value.
|
|
|
- value = Math.min( Math.max( startTime, value ), stopTime );
|
|
|
- // If changed since last seen, update and fire the changed event.
|
|
|
- if ( value !== this.animationTimeUpdated ) {
|
|
|
- this.animationTimeUpdated = value;
|
|
|
- this.animationUpdate( value, this.animationDuration );
|
|
|
- this.animationTimeChanged( value );
|
|
|
- }
|
|
|
- return value; //@ sourceURL=animation.animationTime.get.vwf
|
|
|
-
|
|
|
- ## The length of the animation in seconds.
|
|
|
- ##
|
|
|
- ## `animationTime` will always be within the range [ `0`, `animationDuration` ]. Animations
|
|
|
- ## automatically stop playing once `animationTime` reaches `animationDuration` unless
|
|
|
- ## `animationLoop` is set. Animations with a negative `animationRate` start at
|
|
|
- ## `animationDuration` and stop at `0`.
|
|
|
-
|
|
|
- animationDuration: # TODO: allow changes while playing
|
|
|
- set: |
|
|
|
- var duration = value, rate = this.animationRate;
|
|
|
- this.animationDuration = duration;
|
|
|
- this.animationDuration$ = ( rate >= 0 ? duration : -duration ) / rate;
|
|
|
- value: 1
|
|
|
-
|
|
|
- ## The animation playback rate.
|
|
|
- ##
|
|
|
- ## Set `animationRate` to a value greater than `1` to increase the rate. Set a value between `0`
|
|
|
- ## and `1` to decrease it. Negative rates will cause the animation to play backwards.
|
|
|
-
|
|
|
- animationRate: # TODO: allow changes while playing
|
|
|
- set: |
|
|
|
- var duration = this.animationDuration, rate = value;
|
|
|
- this.animationRate = rate;
|
|
|
- this.animationDuration$ = ( rate >= 0 ? duration : -duration ) / rate;
|
|
|
- value: 1
|
|
|
-
|
|
|
- ## Automatically replay the animation from the start after reaching the end.
|
|
|
-
|
|
|
- animationLoop: false
|
|
|
-
|
|
|
- ## The animation's play/pause control.
|
|
|
-
|
|
|
- animationPlaying:
|
|
|
-
|
|
|
- set: |
|
|
|
- if(this.animationStartTime == null) {
|
|
|
- this.animationStartTime = 0;
|
|
|
- }
|
|
|
- if(this.animationStopTime == null) {
|
|
|
- this.animationStopTime = this.animationDuration;
|
|
|
- }
|
|
|
- if ( this.animationStart$ != null && this.animationPause$ == null ) {
|
|
|
- if ( ! value ) {
|
|
|
- // Mark as paused at the current time.
|
|
|
- this.animationPause$ = this.time;
|
|
|
- // Send the `animationStopped` event if stopping at the end.
|
|
|
- if ( this.time == this.animationStop$ ) {
|
|
|
- this.animationStopped();
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- if ( value ) {
|
|
|
- // Save copies to avoid repeated reads.
|
|
|
- var duration = this.animationStopTime - this.animationStartTime,
|
|
|
- rate = this.animationRate;
|
|
|
- // Start from the beginning if resuming from the end.
|
|
|
- if ( this.animationPause$ == this.animationStop$ ) {
|
|
|
- this.animationPause$ = this.animationStart$;
|
|
|
- }
|
|
|
- // Recalculate the start and stop times to keep paused time unchanged, then resume.
|
|
|
- this.animationStart$ =
|
|
|
- ( this.animationStart$ != null ? this.animationStart$ : this.time ) -
|
|
|
- ( this.animationPause$ != null ? this.animationPause$ : this.time ) +
|
|
|
- this.time;
|
|
|
- this.animationStop$ =
|
|
|
- this.animationStart$ +
|
|
|
- ( rate >= 0 ? duration : -duration ) / rate;
|
|
|
- this.animationPause$ = null;
|
|
|
- // Send the `animationStarted` event if starting from the beginning.
|
|
|
- if ( this.time == this.animationStart$ ) {
|
|
|
- this.animationStarted();
|
|
|
- }
|
|
|
- // Start the animation worker.
|
|
|
- this.logger.debug( "scheduling animationTick" );
|
|
|
- this.animationTick();
|
|
|
- }
|
|
|
- } //@ sourceURL=animation.animationPlaying.set.vwf
|
|
|
-
|
|
|
- get: |
|
|
|
- return this.animationStart$ != null && this.animationPause$ == null;
|
|
|
-
|
|
|
- ## The most recent value of `animationTime` recognized by this behavior.
|
|
|
- ##
|
|
|
- ## Each `animationTime` change causes `animationUpdate` to be called. `animationTimeUpdated`
|
|
|
- ## records the value of `animationTime` from the last time this occurred.
|
|
|
- ##
|
|
|
- ## `animationTimeUpdated` is for internal use. Do not set this property.
|
|
|
-
|
|
|
- animationTimeUpdated: null
|
|
|
-
|
|
|
- ## The simulation time corresponding to the start of the animation.
|
|
|
- ##
|
|
|
- ## `animationStart$` is `null` until the animation is first played. `animationPlaying` is
|
|
|
- ## `false` and `animationTime` is `0` while `animationStart$` is `null`.
|
|
|
- ##
|
|
|
- ## `animationStart$` is for internal use. Do not set this property.
|
|
|
-
|
|
|
- animationStart$: null
|
|
|
-
|
|
|
- ## The simulation time corresponding to the animation's pause position.
|
|
|
- ##
|
|
|
- ## `animationPause$` is `null` while the animation is playing and before the animation is
|
|
|
- ## first played.
|
|
|
- ##
|
|
|
- ## `animationPause$` is for internal use. Do not set this property.
|
|
|
-
|
|
|
- animationPause$: null
|
|
|
-
|
|
|
- ## The simulation time corresponding to the end of the animation. The animation worker function
|
|
|
- ## loops or stops the animation when `time` reaches this value.
|
|
|
- ##
|
|
|
- ## `animationStop$` is for internal use. Do not set this property.
|
|
|
-
|
|
|
- animationStop$: null
|
|
|
-
|
|
|
- ## The animation's duration in simulation time, after considering `animationRate`.
|
|
|
- ##
|
|
|
- ## `animationDuration$` is for internal use. Do not set this property.
|
|
|
-
|
|
|
- animationDuration$: null
|
|
|
-
|
|
|
- ## The time that the animation should start at. Used with animationStopTime to play
|
|
|
- ## a subsection of the animation. Defaults to 0 when the animation starts to play
|
|
|
- ## if it is not assigned another value. 'animationStartTime' will always be within
|
|
|
- ## the range [ `0`, `animationDuration` ]
|
|
|
-
|
|
|
- animationStartTime:
|
|
|
- set: |
|
|
|
- this.animationStartTime = value ? Math.min( Math.max( 0, value ), this.animationDuration ) : value;
|
|
|
- value: null
|
|
|
-
|
|
|
- ## The time that the animation should stop at. Used with animationStartTime to play
|
|
|
- ## a subsection of the animation. Defaults to 'animationDuration' when the animation
|
|
|
- ## starts to play if it is not assigned another value. 'animationStopTime' will always
|
|
|
- ## be within the range [ `0`, `animationDuration` ]
|
|
|
-
|
|
|
- animationStopTime:
|
|
|
- set: |
|
|
|
- this.animationStopTime = value ? Math.min( Math.max( 0, value ), this.animationDuration ) : value;
|
|
|
- value: null
|
|
|
-
|
|
|
- ## The frame that the animation should start at. Setting this value automatically updates the "animationStartTime"
|
|
|
- ## to the "animationStartFrame" / "fps"
|
|
|
-
|
|
|
- animationStartFrame:
|
|
|
- set: |
|
|
|
- this.animationStartTime = value / this.animationFPS;
|
|
|
- get: |
|
|
|
- return Math.floor(this.animationStartTime * this.animationFPS);
|
|
|
-
|
|
|
- ## The frame that the animation should stop at. Setting this value automatically updates the "animationStopTime"
|
|
|
- ## to the "animationStopFrame" / "fps"
|
|
|
-
|
|
|
- animationStopFrame:
|
|
|
- set: |
|
|
|
- this.animationStopTime = value / this.animationFPS;
|
|
|
- get: |
|
|
|
- return Math.floor(this.animationStopTime * this.animationFPS);
|
|
|
-
|
|
|
- ## The frames per second of the animation loaded from the source model.
|
|
|
-
|
|
|
- animationFPS: 30
|
|
|
-
|
|
|
- ## The number of frames of the animation loaded from the source model.
|
|
|
- animationFrames:
|
|
|
- set: |
|
|
|
- this.animationDuration = value / this.animationFPS;
|
|
|
- get: |
|
|
|
- return Math.ceil(this.animationFPS * this.animationDuration);
|
|
|
-
|
|
|
- ## The current frame the animation is on. Equivalent to animationTime.
|
|
|
- animationFrame:
|
|
|
- set: |
|
|
|
- if(this.animationFPS) {
|
|
|
- this.animationTime = value / this.animationFPS;
|
|
|
- }
|
|
|
- get: |
|
|
|
- if(this.animationFPS) {
|
|
|
- return Math.floor(this.animationTime * this.animationFPS);
|
|
|
- }
|
|
|
-
|
|
|
- ## The animation update rate in ticks per second of simulation time.
|
|
|
-
|
|
|
- animationTPS: 60
|
|
|
-
|
|
|
-methods:
|
|
|
-
|
|
|
- # Play the animation from the start.
|
|
|
-
|
|
|
- animationPlay:
|
|
|
- parameters:
|
|
|
- - startTime
|
|
|
- - stopTime
|
|
|
- body: |
|
|
|
- if(!isNaN(stopTime)) {
|
|
|
- this.animationStopTime = stopTime;
|
|
|
- }
|
|
|
- if(!isNaN(startTime)) {
|
|
|
- this.animationStartTime = startTime;
|
|
|
- }
|
|
|
- this.animationPlaying = true;
|
|
|
-
|
|
|
- # Pause the animation at the current position.
|
|
|
-
|
|
|
- animationPause: |
|
|
|
- this.animationPlaying = false;
|
|
|
-
|
|
|
- # Resume the animation from the current position.
|
|
|
-
|
|
|
- animationResume: |
|
|
|
- this.animationPlaying = true;
|
|
|
-
|
|
|
- # Stop the animation and reset the position to the start.
|
|
|
-
|
|
|
- animationStop: |
|
|
|
- this.animationPlaying = false;
|
|
|
- this.animationTime = 0;
|
|
|
-
|
|
|
- ## Update the animation. If `animationTime` has reached the end, stop or loop depending on the
|
|
|
- ## `animationLoop` setting. Schedule the next tick if the animation did not stop.
|
|
|
- ##
|
|
|
- ## `animationTick` is for internal use. Do not call this method directly.
|
|
|
-
|
|
|
- animationTick: |
|
|
|
- if ( this.animationPlaying ) {
|
|
|
- // Read the time to recognize the current time and update.
|
|
|
- // TODO: move side effects out of the getter!!! (says Kevin)
|
|
|
- this.animationTime;
|
|
|
- // Loop or stop after reaching the end.
|
|
|
- if ( this.time === this.animationStop$ ) {
|
|
|
- if ( this.animationLoop ) {
|
|
|
- this.animationLooped();
|
|
|
- this.animationTime = this.animationRate >= 0 ?
|
|
|
- this.animationStartTime : this.animationStopTime;
|
|
|
- } else {
|
|
|
- this.animationPlaying = false;
|
|
|
- }
|
|
|
- }
|
|
|
- // Schedule the next tick if still playing.
|
|
|
- if ( this.animationPlaying ) {
|
|
|
- if ( this.animationStop$ - this.time > 1 / this.animationTPS ) {
|
|
|
- this.in( 1 / this.animationTPS ).animationTick(); // next interval
|
|
|
- } else {
|
|
|
-
|
|
|
- // TODO: When animationStop$ is 0 (usually when a model does not actually have an
|
|
|
- // animation on it), we schedule a method call for a time in the past (at time 0).
|
|
|
- // That immediately calls animationTick again, but this.time does not equal
|
|
|
- // animationStop$ as we would expect. So, it doesn't stop the animation and we get
|
|
|
- // caught in an infinite loop.
|
|
|
- // Ideally we should catch the case where animationStop$ is 0 before this point.
|
|
|
- // But for now, we catch it here.
|
|
|
- if ( this.animationStop$ > 0 ) {
|
|
|
- this.at( this.animationStop$ ).animationTick(); // exactly at end
|
|
|
- } else {
|
|
|
- this.animationPlaying = false;
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- this.logger.debug( "canceling animationTick" );
|
|
|
- }
|
|
|
- } //@ sourceURL=animation.animationTick.vwf
|
|
|
-
|
|
|
- ## `animation.vwf` calls `animationUpdate` each time `animationTime` changes. Nodes that
|
|
|
- ## implement `animation.vwf` should provide an `animationUpdate` method to calculate the animation
|
|
|
- ## state appropriate for the node.
|
|
|
- ##
|
|
|
- ## Since this event is sent within the `animationTime` getter function, references to
|
|
|
- ## `this.animationTime` will return `undefined` due to reentrancy protections. Use the provided
|
|
|
- ## `time` parameter instead.
|
|
|
- ##
|
|
|
- ## @param {Number} time
|
|
|
- ## The animation's `animationTime`.
|
|
|
- ## @param {Number} duration
|
|
|
- ## The animation's `animationDuration`.
|
|
|
-
|
|
|
- animationUpdate:
|
|
|
- parameters:
|
|
|
- - time
|
|
|
- - duration
|
|
|
-
|
|
|
-events:
|
|
|
-
|
|
|
- # Sent when the animation starts playing from the beginning.
|
|
|
-
|
|
|
- animationStarted:
|
|
|
-
|
|
|
- # Sent when the animation reaches the end and `animationLoop` is not set.
|
|
|
-
|
|
|
- animationStopped:
|
|
|
-
|
|
|
- # Sent when the animation reaches the end and `animationLoop` is set.
|
|
|
-
|
|
|
- animationLooped:
|
|
|
-
|
|
|
- ## Sent each time `animationTime` changes.
|
|
|
- ##
|
|
|
- ## Since this event is sent within the `animationTime` getter function, references to
|
|
|
- ## `this.animationTime` will return `undefined` due to reentrancy protections. Use the provided
|
|
|
- ## `time` parameter instead.
|
|
|
- ##
|
|
|
- ## @param {Number} time
|
|
|
- ## The animation's `animationTime`.
|
|
|
-
|
|
|
- animationTimeChanged:
|
|
|
- parameters:
|
|
|
- - time
|
|
|
-scripts:
|
|
|
-- |
|
|
|
- this.initialize = function() {
|
|
|
-
|
|
|
- // Locate child nodes that extend or implement "http://vwf.example.com/animation/position.vwf"
|
|
|
- // to identify themselves as animation key positions.
|
|
|
-
|
|
|
- var positions = this.find( "./element(*,'http://vwf.example.com/animation/position.vwf')" );
|
|
|
-
|
|
|
- // Fill in missing `animationTime` properties, distributing evenly between the left and right
|
|
|
- // positions that define `animationTime`.
|
|
|
-
|
|
|
- // 1: [ - ] => [ 0 ]
|
|
|
- // 1: [ 0, - ] => [ 0, 1 ]
|
|
|
- // 1: [ -, 1 ] => [ 0, 1 ]
|
|
|
- // 1: [ 0, -, - ] => [ 0, 1/2, 1 ]
|
|
|
- // 1: [ -, -, 1 ] => [ 0, 1/2, 1 ]
|
|
|
- // 1: [ 0, - , -, 1 ] => [ 0, 1/3 , 2/3, 1 ]
|
|
|
-
|
|
|
- var leftTime, leftIndex;
|
|
|
- var rightTime, rightIndex = -Infinity;
|
|
|
-
|
|
|
- if ( positions.length > 0 ) {
|
|
|
-
|
|
|
- positions.sort(function(a, b) {
|
|
|
- return a.sequence - b.sequence;
|
|
|
- });
|
|
|
-
|
|
|
- if ( positions[0].animationTime === null ) {
|
|
|
- positions[0].animationTime = 0;
|
|
|
- }
|
|
|
-
|
|
|
- if ( positions[positions.length-1].animationTime === null ) {
|
|
|
- positions[positions.length-1].animationTime = this.animationDuration;
|
|
|
- }
|
|
|
-
|
|
|
- positions.forEach( function( position, index ) {
|
|
|
-
|
|
|
- if ( position.animationTime !== null ) {
|
|
|
-
|
|
|
- leftTime = position.animationTime;
|
|
|
- leftIndex = index;
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- if ( index > rightIndex ) {
|
|
|
- for ( rightIndex = index + 1; rightIndex < positions.length; rightIndex++ ) {
|
|
|
- if ( ( rightTime = /* assignment! */ positions[rightIndex].animationTime ) !== null ) {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- position.animationTime = leftTime + ( rightTime - leftTime ) *
|
|
|
- ( index - leftIndex ) / ( rightIndex - leftIndex );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }, this );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- } //@ sourceURL=http://vwf.example.com/animation.vwf/scripts~initialize
|