| #include <rive/clip_result.hpp> |
| #include <rive/file.hpp> |
| #include <rive/node.hpp> |
| #include <rive/shapes/clipping_shape.hpp> |
| #include <rive/shapes/rectangle.hpp> |
| #include <rive/shapes/shape.hpp> |
| #include <utils/no_op_renderer.hpp> |
| #include "rive_file_reader.hpp" |
| #include <catch.hpp> |
| |
| TEST_CASE("clipping loads correctly", "[clipping]") |
| { |
| auto file = ReadRiveFile("../../test/assets/circle_clips.riv"); |
| |
| auto node = file->artboard()->find("TopEllipse"); |
| REQUIRE(node != nullptr); |
| REQUIRE(node->is<rive::Shape>()); |
| |
| auto shape = node->as<rive::Shape>(); |
| REQUIRE(shape->clippingShapes().size() == 2); |
| REQUIRE(shape->clippingShapes()[0]->source()->name() == "ClipRect2"); |
| REQUIRE(shape->clippingShapes()[1]->source()->name() == "BabyEllipse"); |
| |
| file->artboard()->updateComponents(); |
| |
| rive::NoOpRenderer renderer; |
| file->artboard()->draw(&renderer); |
| } |
| |
| class ClipTestRenderPath : public rive::RenderPath |
| { |
| public: |
| rive::RawPath rawPath; |
| ClipTestRenderPath(rive::RawPath& path) : rawPath(path) {} |
| |
| void rewind() override {} |
| |
| void fillRule(rive::FillRule value) override {} |
| void addPath(rive::CommandPath* path, const rive::Mat2D& transform) override {} |
| void addRenderPath(rive::RenderPath* path, const rive::Mat2D& transform) override {} |
| |
| void moveTo(float x, float y) override {} |
| void lineTo(float x, float y) override {} |
| void cubicTo(float ox, float oy, float ix, float iy, float x, float y) override {} |
| void close() override {} |
| }; |
| |
| class ClippingFactory : public rive::NoOpFactory |
| { |
| rive::rcp<rive::RenderPath> makeRenderPath(rive::RawPath& rawPath, rive::FillRule) override |
| { |
| return rive::make_rcp<ClipTestRenderPath>(rawPath); |
| } |
| }; |
| |
| TEST_CASE("artboard is clipped correctly", "[clipping]") |
| { |
| ClippingFactory factory; |
| auto file = ReadRiveFile("../../test/assets/artboardclipping.riv", &factory); |
| |
| auto artboard = file->artboard("Center"); |
| REQUIRE(artboard != nullptr); |
| artboard->advance(0.0f); |
| REQUIRE(artboard->originX() == 0.5); |
| REQUIRE(artboard->originY() == 0.5); |
| { |
| auto clipPath = static_cast<ClipTestRenderPath*>(artboard->clipPath()); |
| auto points = clipPath->rawPath.points(); |
| REQUIRE(points.size() == 4); |
| |
| REQUIRE(points[0] == rive::Vec2D(0.0f, 0.0f)); |
| REQUIRE(points[1] == rive::Vec2D(500.0f, 0.0f)); |
| REQUIRE(points[2] == rive::Vec2D(500.0f, 500.0f)); |
| REQUIRE(points[3] == rive::Vec2D(0.0f, 500.0f)); |
| } |
| // Now disable framing the origin so that the points are in origin space. |
| artboard->frameOrigin(false); |
| artboard->updateComponents(); |
| { |
| auto clipPath = static_cast<ClipTestRenderPath*>(artboard->clipPath()); |
| auto points = clipPath->rawPath.points(); |
| REQUIRE(points.size() == 4); |
| |
| REQUIRE(points[0] == rive::Vec2D(-250.0f, -250.0f)); |
| REQUIRE(points[1] == rive::Vec2D(250.0f, -250.0f)); |
| REQUIRE(points[2] == rive::Vec2D(250.0f, 250.0f)); |
| REQUIRE(points[3] == rive::Vec2D(-250.0f, 250.0f)); |
| } |
| } |
| |
| TEST_CASE("Shape does not have any clipping paths visible", "[clipping]") |
| { |
| ClippingFactory factory; |
| auto file = ReadRiveFile("../../test/assets/clip_tests.riv", &factory); |
| |
| auto artboard = file->artboard("Empty-Shape"); |
| REQUIRE(artboard != nullptr); |
| artboard->updateComponents(); |
| auto node = artboard->find("Ellipse-clipper"); |
| REQUIRE(node != nullptr); |
| REQUIRE(node->is<rive::Shape>()); |
| rive::Shape* shape = static_cast<rive::Shape*>(node); |
| REQUIRE(shape->isEmpty() == true); |
| auto clippedNode = artboard->find("Rectangle-clipped"); |
| REQUIRE(clippedNode != nullptr); |
| REQUIRE(clippedNode->is<rive::Shape>()); |
| rive::Shape* clippedShape = static_cast<rive::Shape*>(clippedNode); |
| rive::NoOpRenderer renderer; |
| auto clipResult = clippedShape->applyClip(&renderer); |
| REQUIRE(clipResult == rive::ClipResult::emptyClip); |
| } |
| |
| TEST_CASE("Shape has at least a clipping path visible", "[clipping]") |
| { |
| ClippingFactory factory; |
| auto file = ReadRiveFile("../../test/assets/clip_tests.riv", &factory); |
| |
| auto artboard = file->artboard("Hidden-Path-Visible-Path"); |
| REQUIRE(artboard != nullptr); |
| artboard->updateComponents(); |
| auto node = artboard->find("Ellipse-clipper"); |
| REQUIRE(node != nullptr); |
| REQUIRE(node->is<rive::Shape>()); |
| rive::Shape* shape = static_cast<rive::Shape*>(node); |
| REQUIRE(shape->isEmpty() == false); |
| auto clippedNode = artboard->find("Rectangle-clipped"); |
| REQUIRE(clippedNode != nullptr); |
| REQUIRE(clippedNode->is<rive::Shape>()); |
| rive::Shape* clippedShape = static_cast<rive::Shape*>(clippedNode); |
| rive::NoOpRenderer renderer; |
| auto clipResult = clippedShape->applyClip(&renderer); |
| REQUIRE(clipResult == rive::ClipResult::clip); |
| } |
| |
| TEST_CASE("Shape returns an empty clip when one clipping shape is empty", "[clipping]") |
| { |
| ClippingFactory factory; |
| auto file = ReadRiveFile("../../test/assets/clip_tests.riv", &factory); |
| |
| auto artboard = file->artboard("One-Clipping-Shape-Visible-One-Hidden"); |
| REQUIRE(artboard != nullptr); |
| artboard->updateComponents(); |
| auto node = artboard->find("Rectangle-clipped"); |
| REQUIRE(node != nullptr); |
| REQUIRE(node->is<rive::Shape>()); |
| rive::Shape* shape = static_cast<rive::Shape*>(node); |
| |
| rive::NoOpRenderer renderer; |
| auto clipResult = shape->applyClip(&renderer); |
| REQUIRE(clipResult == rive::ClipResult::emptyClip); |
| } |