mirror of
https://github.com/rive-app/rive-cpp.git
synced 2026-01-18 13:11:19 +01:00
fix(scripting): search first parent transform component to build script node feature: modulate opacity (#11427) 128d9d61e0 * feature: modulate opacity * fix: clang-format * fix: rust renderer has a no-op modulateOpacity * fix: no-op modulateOpacity for canvas android * feature: modulate opacity on android canvas * fix: rcp ref * fix: missing override * fix: gms * fix: make flutter_renderer match cg one * fix: josh pr feedback * fix: remove CG transparency layer * fix: save modulated gradient up-front * fix: store only one gradient ref * fix: remove specific constructor * fix: use GradDataArray! * fix: expose currentModulatedOpacity * fix: cg_factory modulated opacity value * fix: modulate negative opacity test * fix: verify double modulate negative also clamps Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com> Co-authored-by: hernan <hernan@rive.app>
194 lines
6.8 KiB
C++
194 lines
6.8 KiB
C++
/*
|
|
* Copyright 2023 Rive
|
|
*/
|
|
|
|
#include "gm.hpp"
|
|
#include "gr_inner_fan_triangulator.hpp"
|
|
#include "common/testing_window.hpp"
|
|
#include "rive/renderer.hpp"
|
|
#include "rive/renderer/draw.hpp"
|
|
#include "rive/renderer/render_context.hpp"
|
|
#include "../src/rive_render_paint.hpp"
|
|
#include "../src/rive_render_path.hpp"
|
|
#include "../src/shaders/constants.glsl"
|
|
|
|
using namespace rivegm;
|
|
using namespace rive;
|
|
using namespace rive::gpu;
|
|
|
|
constexpr static std::array<Vec2D, 3> kTris[] = {
|
|
{Vec2D{10, 10}, Vec2D{50, 10}, Vec2D{10, 120}},
|
|
{Vec2D{10, 290}, Vec2D{290, 10}, Vec2D{270, 280}},
|
|
{Vec2D{60, 60}, Vec2D{30, 190}, Vec2D{250, 20}},
|
|
};
|
|
constexpr static size_t kNumTriangles = sizeof(kTris) / sizeof(kTris[0]);
|
|
|
|
rcp<RiveRenderPath> make_nonempty_placeholder_path()
|
|
{
|
|
auto path = make_rcp<RiveRenderPath>();
|
|
path->moveTo(0, 0);
|
|
return path;
|
|
}
|
|
|
|
class PushRetrofittedTrianglesGMDraw : public PathDraw
|
|
{
|
|
public:
|
|
PushRetrofittedTrianglesGMDraw(RenderContext* context,
|
|
const RiveRenderPaint* paint) :
|
|
PathDraw(FULLSCREEN_PIXEL_BOUNDS,
|
|
Mat2D(),
|
|
make_nonempty_placeholder_path(),
|
|
context->frameDescriptor().clockwiseFillOverride
|
|
? FillRule::clockwise
|
|
: FillRule::nonZero,
|
|
paint,
|
|
1.0f, // modulatedOpacity
|
|
SelectCoverageType(paint,
|
|
1,
|
|
context->platformFeatures(),
|
|
context->frameInterlockMode()),
|
|
context->frameDescriptor())
|
|
{
|
|
m_resourceCounts.pathCount = 1;
|
|
m_resourceCounts.contourCount = 1;
|
|
m_resourceCounts.maxTessellatedSegmentCount = kNumTriangles;
|
|
m_resourceCounts.outerCubicTessVertexCount =
|
|
context->frameInterlockMode() != gpu::InterlockMode::msaa
|
|
? gpu::kOuterCurvePatchSegmentSpan * kNumTriangles * 2
|
|
: gpu::kOuterCurvePatchSegmentSpan * kNumTriangles;
|
|
m_triangulator = context->make<GrInnerFanTriangulator>(
|
|
RawPath(),
|
|
Mat2D(),
|
|
GrTriangulator::Comparator::Direction::kHorizontal,
|
|
FillRule::nonZero,
|
|
&context->perFrameAllocator());
|
|
}
|
|
|
|
void countSubpasses() override
|
|
{
|
|
assert(m_prepassCount == 0);
|
|
assert(m_subpassCount == 1);
|
|
}
|
|
|
|
bool allocateResources(RenderContext::LogicalFlush* flush) override
|
|
{
|
|
if (!PathDraw::allocateResources(flush))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void pushToRenderContext(RenderContext::LogicalFlush* flush,
|
|
int subpassIndex) override
|
|
{
|
|
// Make sure the rawPath in our path reference hasn't changed since we
|
|
// began holding!
|
|
assert(m_rawPathMutationID == m_pathRef->getRawPathMutationID());
|
|
assert(!m_pathRef->getRawPath().empty());
|
|
assert(subpassIndex == 0);
|
|
|
|
uint32_t tessVertexCount = math::lossless_numeric_cast<uint32_t>(
|
|
m_resourceCounts.outerCubicTessVertexCount);
|
|
if (tessVertexCount > 0)
|
|
{
|
|
m_pathID = flush->pushPath(this);
|
|
|
|
uint32_t tessLocation =
|
|
flush->allocateOuterCubicTessVertices(tessVertexCount);
|
|
|
|
uint32_t forwardTessVertexCount, forwardTessLocation,
|
|
mirroredTessVertexCount, mirroredTessLocation;
|
|
if (m_contourDirections ==
|
|
gpu::ContourDirections::reverseThenForward)
|
|
{
|
|
forwardTessVertexCount = mirroredTessVertexCount =
|
|
tessVertexCount / 2;
|
|
forwardTessLocation = mirroredTessLocation =
|
|
tessLocation + tessVertexCount / 2;
|
|
}
|
|
else
|
|
{
|
|
assert(m_contourDirections == gpu::ContourDirections::forward);
|
|
forwardTessVertexCount = tessVertexCount;
|
|
forwardTessLocation = tessLocation;
|
|
mirroredTessVertexCount = mirroredTessLocation = 0;
|
|
}
|
|
|
|
RenderContext::TessellationWriter tessWriter(
|
|
flush,
|
|
m_pathID,
|
|
m_contourDirections,
|
|
forwardTessVertexCount,
|
|
forwardTessLocation,
|
|
mirroredTessVertexCount,
|
|
mirroredTessLocation);
|
|
|
|
uint32_t contourID = tessWriter.pushContour(
|
|
{0, 0},
|
|
/*isStroke=*/false,
|
|
/*closed=*/true,
|
|
0 /* gpu::kOuterCurvePatchSegmentSpan - 2 */);
|
|
for (const auto& pts : kTris)
|
|
{
|
|
Vec2D tri[4] = {pts[0], pts[1], {0, 0}, pts[2]};
|
|
tessWriter.pushCubic(tri,
|
|
m_contourDirections,
|
|
{0, 0},
|
|
gpu::kOuterCurvePatchSegmentSpan - 1,
|
|
1,
|
|
1,
|
|
contourID |
|
|
RETROFITTED_TRIANGLE_CONTOUR_FLAG);
|
|
}
|
|
|
|
if (flush->frameDescriptor().clockwiseFillOverride)
|
|
{
|
|
m_drawContents |= gpu::DrawContents::clockwiseFill;
|
|
}
|
|
|
|
flush->pushOuterCubicsDraw(this,
|
|
m_coverageType == CoverageType::msaa
|
|
? gpu::DrawType::msaaOuterCubics
|
|
: gpu::DrawType::outerCurvePatches,
|
|
tessVertexCount,
|
|
tessLocation,
|
|
gpu::ShaderMiscFlags::none);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Checks that RenderContext properly draws single triangles when using the
|
|
// "kRetrofittedTriangle" flag.
|
|
class RetrofittedCubicTrianglesGM : public GM
|
|
{
|
|
public:
|
|
RetrofittedCubicTrianglesGM() : GM(300, 300) {}
|
|
|
|
protected:
|
|
void onDraw(Renderer* renderer) override
|
|
{
|
|
TestingWindow::Get()->endFrame(nullptr);
|
|
gpu::RenderContext* renderContext =
|
|
TestingWindow::Get()->renderContext();
|
|
if (!renderContext)
|
|
{
|
|
TestingWindow::Get()->beginFrame({.clearColor = 0xffff0000});
|
|
}
|
|
else
|
|
{
|
|
TestingWindow::Get()->beginFrame({.clearColor = 0xff000000});
|
|
RiveRenderPaint paint;
|
|
paint.color(0xffffffff);
|
|
DrawUniquePtr draw(
|
|
renderContext->make<PushRetrofittedTrianglesGMDraw>(
|
|
renderContext,
|
|
&paint));
|
|
bool success RIVE_MAYBE_UNUSED = renderContext->pushDraws(&draw, 1);
|
|
assert(success);
|
|
}
|
|
}
|
|
};
|
|
|
|
GMREGISTER(retrofittedcubictriangles, return new RetrofittedCubicTrianglesGM;)
|