Skip to content

Commit af9063b

Browse files
authored
Add ability to set speed of animations (#464)
1 parent e8f6fbf commit af9063b

File tree

1 file changed

+51
-8
lines changed
  • sceneview/src/main/java/io/github/sceneview/node

1 file changed

+51
-8
lines changed

sceneview/src/main/java/io/github/sceneview/node/ModelNode.kt

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import io.github.sceneview.model.lightEntities
2525
import io.github.sceneview.model.model
2626
import io.github.sceneview.model.renderableEntities
2727
import io.github.sceneview.utils.intervalSeconds
28+
import kotlin.math.abs
2829

2930
/**
3031
* Create the ModelNode from a loaded model instance.
@@ -110,7 +111,11 @@ open class ModelNode(
110111
override var name = super<ChildNode>.name
111112
}
112113

113-
data class PlayingAnimation(val startTime: Long = System.nanoTime(), val loop: Boolean = true)
114+
data class PlayingAnimation(
115+
val startTime: Long = System.nanoTime(),
116+
var speed: Float = 1f,
117+
val loop: Boolean = true
118+
)
114119

115120
val renderableNodes = modelInstance.renderableEntities.map {
116121
RenderableNode(modelInstance, it)
@@ -233,21 +238,46 @@ open class ModelNode(
233238
* animation definition. Uses `TransformManager`.
234239
*
235240
* @param animationIndex Zero-based index for the `animation` of interest.
241+
* @param speed The rate at which the `animation` plays. Reverses the `animation` if negative.
242+
* Pauses the `animation` if zero.
243+
* @param loop Specifies if the `animation` should repeat forever.
236244
*
237245
* @see Animator.getAnimationCount
238246
*/
239-
fun playAnimation(animationIndex: Int, loop: Boolean = true) {
247+
fun playAnimation(animationIndex: Int, speed: Float = 1f, loop: Boolean = true) {
240248
if (animationIndex < animationCount) {
241-
playingAnimations[animationIndex] = PlayingAnimation(loop = loop)
249+
playingAnimations[animationIndex] = PlayingAnimation(speed = speed, loop = loop)
242250
}
243251
}
244252

245253
/**
246254
* @see playAnimation
247255
* @see Animator.getAnimationName
248256
*/
249-
fun playAnimation(animationName: String, loop: Boolean = true) {
250-
animator.getAnimationIndex(animationName)?.let { playAnimation(it, loop) }
257+
fun playAnimation(animationName: String, speed: Float = 1f, loop: Boolean = true) {
258+
animator.getAnimationIndex(animationName)?.let { playAnimation(it, speed, loop) }
259+
}
260+
261+
/**
262+
* Sets the rate at which the `animation` is played.
263+
*
264+
* @param animationIndex Zero-based index for the `animation` of interest.
265+
* @param speed The rate at which the `animation` plays. Reverses the `animation` if negative.
266+
* Pauses the `animation` if zero.
267+
* @see playAnimation
268+
*/
269+
fun setAnimationSpeed(animationIndex: Int, speed: Float) {
270+
if (animationIndex < animationCount) {
271+
playingAnimations[animationIndex]?.speed = speed
272+
}
273+
}
274+
275+
/**
276+
* @see setAnimationSpeed
277+
* @see Animator.getAnimationName
278+
*/
279+
fun setAnimationSpeed(animationName: String, speed: Float) {
280+
animator.getAnimationIndex(animationName)?.let { setAnimationSpeed(it, speed) }
251281
}
252282

253283
fun stopAnimation(animationIndex: Int) {
@@ -383,18 +413,31 @@ open class ModelNode(
383413
super.onFrame(frameTimeNanos)
384414

385415
model.popRenderable()
416+
applyAnimations(frameTimeNanos)
417+
animator.updateBoneMatrices()
418+
}
386419

420+
private fun applyAnimations(frameTimeNanos: Long) {
387421
playingAnimations.forEach { (index, animation) ->
422+
if (animation.speed == 0f) return@forEach
423+
388424
animator.let { animator ->
389425
val elapsedTimeSeconds = frameTimeNanos.intervalSeconds(animation.startTime)
390-
animator.applyAnimation(index, elapsedTimeSeconds.toFloat())
426+
val adjustedTimeSeconds = elapsedTimeSeconds.toFloat() * abs(animation.speed)
427+
val animationDuration = animator.getAnimationDuration(index)
428+
val animationTime: Float = if (animation.speed > 0) {
429+
adjustedTimeSeconds
430+
} else {
431+
animationDuration - adjustedTimeSeconds
432+
}
391433

392-
if (!animation.loop && elapsedTimeSeconds >= animator.getAnimationDuration(index)) {
434+
animator.applyAnimation(index, animationTime)
435+
436+
if (!animation.loop && adjustedTimeSeconds >= animationDuration) {
393437
playingAnimations.remove(index)
394438
}
395439
}
396440
}
397-
animator.updateBoneMatrices()
398441
}
399442
}
400443

0 commit comments

Comments
 (0)