| #include <rive/animation/loop.hpp> | |
| #include <rive/animation/linear_animation.hpp> | |
| #include <rive/animation/linear_animation_instance.hpp> | |
| #include "no_op_factory.hpp" | |
| #include <catch.hpp> | |
| #include <cstdio> | |
| TEST_CASE("LinearAnimationInstance oneShot", "[animation]") { | |
| rive::NoOpFactory emptyFactory; | |
| // For each of these tests, we cons up a dummy artboard/instance | |
| // just to make the animations happy. | |
| rive::Artboard ab(&emptyFactory); | |
| auto abi = ab.instance(); | |
| rive::LinearAnimation* linearAnimation = new rive::LinearAnimation(); | |
| // duration in seconds is 5 | |
| linearAnimation->duration(10); | |
| linearAnimation->fps(2); | |
| linearAnimation->loopValue(static_cast<int>(rive::Loop::oneShot)); | |
| rive::LinearAnimationInstance* linearAnimationInstance = | |
| new rive::LinearAnimationInstance(linearAnimation, abi.get()); | |
| // play from beginning. | |
| bool continuePlaying = linearAnimationInstance->advance(2.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->time() == 2.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 2.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == false); | |
| // get stuck at end | |
| continuePlaying = linearAnimationInstance->advance(10.0); | |
| REQUIRE(linearAnimationInstance->time() == 5.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 12.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == true); | |
| REQUIRE(continuePlaying == false); | |
| delete linearAnimationInstance; | |
| delete linearAnimation; | |
| } | |
| TEST_CASE("LinearAnimationInstance oneShot <-", "[animation]") { | |
| rive::NoOpFactory emptyFactory; | |
| rive::Artboard ab(&emptyFactory); | |
| auto abi = ab.instance(); | |
| rive::LinearAnimation* linearAnimation = new rive::LinearAnimation(); | |
| // duration in seconds is 5 | |
| linearAnimation->duration(10); | |
| linearAnimation->fps(2); | |
| linearAnimation->loopValue(static_cast<int>(rive::Loop::oneShot)); | |
| rive::LinearAnimationInstance* linearAnimationInstance = | |
| new rive::LinearAnimationInstance(linearAnimation, abi.get()); | |
| linearAnimationInstance->direction(-1); | |
| REQUIRE(linearAnimationInstance->time() == 0.0); | |
| // Advancing 2 seconds backwards will keep the "animation" time at 0 | |
| bool continuePlaying = linearAnimationInstance->advance(2.0); | |
| REQUIRE(continuePlaying == false); | |
| REQUIRE(linearAnimationInstance->time() == 0.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 2.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == true); | |
| // set time to end.. | |
| // TODO: this also "resets" the total time. is that sensible? | |
| linearAnimationInstance->time(5.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 5.0); | |
| // TODO: get rid if we stop killing m_Direction | |
| linearAnimationInstance->direction(-1); | |
| // play from end to beginning | |
| continuePlaying = linearAnimationInstance->advance(2.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->time() == 3.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 7.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == false); | |
| // get stuck at beginning | |
| continuePlaying = linearAnimationInstance->advance(4.0); | |
| REQUIRE(continuePlaying == false); | |
| REQUIRE(linearAnimationInstance->time() == 0.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 11.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == true); | |
| delete linearAnimationInstance; | |
| delete linearAnimation; | |
| } | |
| TEST_CASE("LinearAnimationInstance loop ->", "[animation]") { | |
| rive::NoOpFactory emptyFactory; | |
| rive::Artboard ab(&emptyFactory); | |
| auto abi = ab.instance(); | |
| rive::LinearAnimation* linearAnimation = new rive::LinearAnimation(); | |
| // duration in seconds is 5 | |
| linearAnimation->duration(10); | |
| linearAnimation->fps(2); | |
| linearAnimation->loopValue(static_cast<int>(rive::Loop::loop)); | |
| rive::LinearAnimationInstance* linearAnimationInstance = | |
| new rive::LinearAnimationInstance(linearAnimation, abi.get()); | |
| // play from beginning. | |
| bool continuePlaying = linearAnimationInstance->advance(2.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->time() == 2.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 2.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == false); | |
| // loop around a couple of times, back to the same spot | |
| continuePlaying = linearAnimationInstance->advance(10.0); | |
| REQUIRE(linearAnimationInstance->time() == 2.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 12.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == true); | |
| REQUIRE(continuePlaying == true); | |
| delete linearAnimationInstance; | |
| delete linearAnimation; | |
| } | |
| TEST_CASE("LinearAnimationInstance loop <-", "[animation]") { | |
| rive::NoOpFactory emptyFactory; | |
| rive::Artboard ab(&emptyFactory); | |
| auto abi = ab.instance(); | |
| rive::LinearAnimation* linearAnimation = new rive::LinearAnimation(); | |
| // duration in seconds is 5 | |
| linearAnimation->duration(10); | |
| linearAnimation->fps(2); | |
| linearAnimation->loopValue(static_cast<int>(rive::Loop::loop)); | |
| rive::LinearAnimationInstance* linearAnimationInstance = | |
| new rive::LinearAnimationInstance(linearAnimation, abi.get()); | |
| linearAnimationInstance->direction(-1); | |
| REQUIRE(linearAnimationInstance->time() == 0.0); | |
| // Advancing 2 seconds backwards will get the "animation" time to 3 | |
| bool continuePlaying = linearAnimationInstance->advance(2.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->direction() == -1); | |
| REQUIRE(linearAnimationInstance->time() == 3.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 2.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == true); | |
| // play without looping past the beginning. | |
| continuePlaying = linearAnimationInstance->advance(2.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->time() == 1.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 4.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == false); | |
| // loop past beginning again | |
| continuePlaying = linearAnimationInstance->advance(4.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->time() == 2.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 8.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == true); | |
| delete linearAnimationInstance; | |
| delete linearAnimation; | |
| } | |
| TEST_CASE("LinearAnimationInstance loop <- work area", "[animation]") { | |
| rive::NoOpFactory emptyFactory; | |
| rive::Artboard ab(&emptyFactory); | |
| auto abi = ab.instance(); | |
| rive::LinearAnimation* linearAnimation = new rive::LinearAnimation(); | |
| // duration in seconds is 50 | |
| linearAnimation->workStart(4); | |
| linearAnimation->enableWorkArea(true); | |
| linearAnimation->workEnd(10); | |
| linearAnimation->duration(100); | |
| linearAnimation->fps(2); | |
| linearAnimation->loopValue(static_cast<int>(rive::Loop::loop)); | |
| rive::LinearAnimationInstance* linearAnimationInstance = | |
| new rive::LinearAnimationInstance(linearAnimation, abi.get()); | |
| linearAnimationInstance->direction(-1); | |
| REQUIRE(linearAnimationInstance->time() == 2.0); | |
| // kick off, we're at the lower bound, will move to 5s. | |
| bool continuePlaying = linearAnimationInstance->advance(0.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->direction() == -1); | |
| REQUIRE(linearAnimationInstance->time() == 5.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 0.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == true); | |
| // 2 more secs , 5s -> 3s | |
| continuePlaying = linearAnimationInstance->advance(2.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->direction() == -1); | |
| REQUIRE(linearAnimationInstance->time() == 3.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 2.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == false); | |
| // 2 more secs , 3s -> 1s, thats before start, so loops to 4s | |
| continuePlaying = linearAnimationInstance->advance(2.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->direction() == -1); | |
| REQUIRE(linearAnimationInstance->time() == 4.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 4.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == true); | |
| // another hit, 4->2s, thats at the start, loops to 5s | |
| continuePlaying = linearAnimationInstance->advance(2.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->time() == 5.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 6.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == true); | |
| delete linearAnimationInstance; | |
| delete linearAnimation; | |
| } | |
| TEST_CASE("LinearAnimationInstance pingpong ->", "[animation]") { | |
| rive::NoOpFactory emptyFactory; | |
| rive::Artboard ab(&emptyFactory); | |
| auto abi = ab.instance(); | |
| rive::LinearAnimation* linearAnimation = new rive::LinearAnimation(); | |
| // duration in seconds is 5 | |
| linearAnimation->duration(10); | |
| linearAnimation->fps(2); | |
| linearAnimation->loopValue(static_cast<int>(rive::Loop::pingPong)); | |
| rive::LinearAnimationInstance* linearAnimationInstance = | |
| new rive::LinearAnimationInstance(linearAnimation, abi.get()); | |
| // play from beginning. | |
| bool continuePlaying = linearAnimationInstance->advance(2.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->time() == 2.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 2.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == false); | |
| // pingpong at the end and come back to 3. | |
| continuePlaying = linearAnimationInstance->advance(5.0); | |
| REQUIRE(linearAnimationInstance->time() == 3.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 7.0); | |
| REQUIRE(linearAnimationInstance->direction() == -1); | |
| REQUIRE(linearAnimationInstance->didLoop() == true); | |
| REQUIRE(continuePlaying == true); | |
| delete linearAnimationInstance; | |
| delete linearAnimation; | |
| } | |
| TEST_CASE("LinearAnimationInstance pingpong <-", "[animation]") { | |
| rive::NoOpFactory emptyFactory; | |
| rive::Artboard ab(&emptyFactory); | |
| auto abi = ab.instance(); | |
| rive::LinearAnimation* linearAnimation = new rive::LinearAnimation(); | |
| // duration in seconds is 5 | |
| linearAnimation->duration(10); | |
| linearAnimation->fps(2); | |
| linearAnimation->loopValue(static_cast<int>(rive::Loop::pingPong)); | |
| rive::LinearAnimationInstance* linearAnimationInstance = | |
| new rive::LinearAnimationInstance(linearAnimation, abi.get()); | |
| linearAnimationInstance->direction(-1); | |
| REQUIRE(linearAnimationInstance->time() == 0.0); | |
| // Advancing 2 seconds backwards, pongs immediately (and is acutally just | |
| // like playing forwards) | |
| bool continuePlaying = linearAnimationInstance->advance(2.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->direction() == 1); | |
| REQUIRE(linearAnimationInstance->time() == 2.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 2.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == true); | |
| // pingpong at the end | |
| continuePlaying = linearAnimationInstance->advance(4.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->direction() == -1); | |
| REQUIRE(linearAnimationInstance->time() == 4.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 6.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == true); | |
| // just a normal advance, no loop | |
| continuePlaying = linearAnimationInstance->advance(2.0); | |
| REQUIRE(continuePlaying == true); | |
| REQUIRE(linearAnimationInstance->direction() == -1); | |
| REQUIRE(linearAnimationInstance->time() == 2.0); | |
| REQUIRE(linearAnimationInstance->totalTime() == 8.0); | |
| REQUIRE(linearAnimationInstance->didLoop() == false); | |
| delete linearAnimationInstance; | |
| delete linearAnimation; | |
| } | |
| TEST_CASE("LinearAnimationInstance override loop", "[animation]") { | |
| rive::NoOpFactory emptyFactory; | |
| rive::Artboard ab(&emptyFactory); | |
| auto abi = ab.instance(); | |
| rive::LinearAnimation* linearAnimation = new rive::LinearAnimation(); | |
| // duration in seconds is 5 | |
| linearAnimation->duration(10); | |
| linearAnimation->fps(2); | |
| linearAnimation->loopValue(static_cast<int>(rive::Loop::oneShot)); | |
| rive::LinearAnimationInstance* linearAnimationInstance = | |
| new rive::LinearAnimationInstance(linearAnimation, abi.get()); | |
| // Check the loop value is same as the animation's | |
| REQUIRE(linearAnimationInstance->loopValue() == linearAnimation->loopValue()); | |
| // Override the loop type | |
| linearAnimationInstance->loopValue(static_cast<int>(rive::Loop::pingPong)); | |
| REQUIRE(linearAnimationInstance->loopValue() != linearAnimation->loopValue()); | |
| REQUIRE(linearAnimationInstance->loopValue() == static_cast<int>(rive::Loop::pingPong)); | |
| REQUIRE(linearAnimationInstance->loop() == rive::Loop::pingPong); | |
| delete linearAnimationInstance; | |
| delete linearAnimation; | |
| } |