| #include <rive/node.hpp> |
| #include <rive/bones/bone.hpp> |
| #include <rive/shapes/shape.hpp> |
| #include <utils/no_op_renderer.hpp> |
| #include "rive_file_reader.hpp" |
| #include "rive_testing.hpp" |
| #include <cstdio> |
| |
| TEST_CASE("two bone ik places bones correctly", "[file]") |
| { |
| auto file = ReadRiveFile("../../test/assets/two_bone_ik.riv"); |
| auto artboard = file->artboard(); |
| |
| REQUIRE(artboard->find<rive::Shape>("circle a") != nullptr); |
| auto circleA = artboard->find<rive::Shape>("circle a"); |
| |
| REQUIRE(artboard->find<rive::Shape>("circle b") != nullptr); |
| auto circleB = artboard->find<rive::Shape>("circle b"); |
| |
| REQUIRE(artboard->find<rive::Bone>("a") != nullptr); |
| auto boneA = artboard->find<rive::Bone>("a"); |
| |
| REQUIRE(artboard->find<rive::Bone>("b") != nullptr); |
| auto boneB = artboard->find<rive::Bone>("b"); |
| |
| REQUIRE(artboard->find<rive::Node>("target") != nullptr); |
| auto target = artboard->find<rive::Node>("target"); |
| |
| REQUIRE(artboard->animation("Animation 1") != nullptr); |
| auto animation = artboard->animation("Animation 1"); |
| |
| // Make sure dependency structure is correct. Important thing here is to |
| // ensure that circle a is dependent upon the tip of the ik chain (bone b). |
| // circle b is a child of bone b so it'll be there anyway, but may as well |
| // validate. |
| REQUIRE(std::find(boneB->dependents().begin(), boneB->dependents().end(), circleA) != |
| boneB->dependents().end()); |
| REQUIRE(std::find(boneB->dependents().begin(), boneB->dependents().end(), circleB) != |
| boneB->dependents().end()); |
| |
| animation->apply(artboard, 0.0f, 1.0f); |
| artboard->advance(0.0f); |
| REQUIRE(target->x() == 296.0f); |
| REQUIRE(target->y() == 202.0f); |
| REQUIRE(aboutEqual(boneA->worldTransform(), |
| rive::Mat2D(0.11632211506366729736328125f, |
| -0.993211567401885986328125f, |
| 0.993211567401885986328125f, |
| 0.11632211506366729736328125f, |
| 26.015254974365234375f, |
| 475.2149658203125f))); |
| |
| REQUIRE(aboutEqual(boneB->worldTransform(), |
| rive::Mat2D(0.974071562290191650390625f, |
| 0.2262403070926666259765625f, |
| -0.2262403070926666259765625f, |
| 0.974071562290191650390625f, |
| 64.31568145751953125f, |
| 148.1883544921875f))); |
| |
| animation->apply(artboard, 1.0f, 1.0f); |
| artboard->advance(0.0f); |
| REQUIRE(target->x() == 450.0f); |
| REQUIRE(target->y() == 337.0f); |
| REQUIRE(aboutEqual(boneA->worldTransform(), |
| rive::Mat2D(0.650279819965362548828125f, |
| -0.7596948146820068359375f, |
| 0.7596948146820068359375f, |
| 0.650279819965362548828125f, |
| 26.015254974365234375f, |
| 475.2149658203125f))); |
| |
| REQUIRE(aboutEqual(boneB->worldTransform(), |
| rive::Mat2D(0.8823678493499755859375f, |
| 0.470560371875762939453125f, |
| -0.47056043148040771484375f, |
| 0.882367908954620361328125f, |
| 240.1275634765625f, |
| 225.07647705078125f))); |
| } |
| |
| TEST_CASE("ik keeps working after a lot of iterations", "[file]") |
| { |
| auto file = ReadRiveFile("../../test/assets/two_bone_ik.riv"); |
| auto artboard = file->artboard(); |
| |
| REQUIRE(artboard->find<rive::Shape>("circle a") != nullptr); |
| auto circleA = artboard->find<rive::Shape>("circle a"); |
| |
| REQUIRE(artboard->find<rive::Shape>("circle b") != nullptr); |
| auto circleB = artboard->find<rive::Shape>("circle b"); |
| |
| REQUIRE(artboard->find<rive::Bone>("a") != nullptr); |
| auto boneA = artboard->find<rive::Bone>("a"); |
| |
| REQUIRE(artboard->find<rive::Bone>("b") != nullptr); |
| auto boneB = artboard->find<rive::Bone>("b"); |
| |
| REQUIRE(artboard->find<rive::Node>("target") != nullptr); |
| auto target = artboard->find<rive::Node>("target"); |
| |
| REQUIRE(artboard->animation("Animation 1") != nullptr); |
| auto animation = artboard->animation("Animation 1"); |
| |
| // Make sure dependency structure is correct. Important thing here is to |
| // ensure that circle a is dependent upon the tip of the ik chain (bone b). |
| // circle b is a child of bone b so it'll be there anyway, but may as well |
| // validate. |
| REQUIRE(std::find(boneB->dependents().begin(), boneB->dependents().end(), circleA) != |
| boneB->dependents().end()); |
| REQUIRE(std::find(boneB->dependents().begin(), boneB->dependents().end(), circleB) != |
| boneB->dependents().end()); |
| |
| for (int i = 0; i < 1000; i++) |
| { |
| animation->apply(artboard, 0.0f, 1.0f); |
| artboard->advance(0.0f); |
| REQUIRE(target->x() == 296.0f); |
| REQUIRE(target->y() == 202.0f); |
| REQUIRE(aboutEqual(boneA->worldTransform(), |
| rive::Mat2D(0.11632211506366729736328125f, |
| -0.993211567401885986328125f, |
| 0.993211567401885986328125f, |
| 0.11632211506366729736328125f, |
| 26.015254974365234375f, |
| 475.2149658203125f))); |
| |
| REQUIRE(aboutEqual(boneB->worldTransform(), |
| rive::Mat2D(0.974071562290191650390625f, |
| 0.2262403070926666259765625f, |
| -0.2262403070926666259765625f, |
| 0.974071562290191650390625f, |
| 64.31568145751953125f, |
| 148.1883544921875f))); |
| |
| animation->apply(artboard, 1.0f, 1.0f); |
| artboard->advance(0.0f); |
| REQUIRE(target->x() == 450.0f); |
| REQUIRE(target->y() == 337.0f); |
| REQUIRE(aboutEqual(boneA->worldTransform(), |
| rive::Mat2D(0.650279819965362548828125f, |
| -0.7596948146820068359375f, |
| 0.7596948146820068359375f, |
| 0.650279819965362548828125f, |
| 26.015254974365234375f, |
| 475.2149658203125f))); |
| |
| REQUIRE(aboutEqual(boneB->worldTransform(), |
| rive::Mat2D(0.8823678493499755859375f, |
| 0.470560371875762939453125f, |
| -0.47056043148040771484375f, |
| 0.882367908954620361328125f, |
| 240.1275634765625f, |
| 225.07647705078125f))); |
| } |
| } |