blob: 9e09e4439b916c524730d8efc3a709ebf53027c9 [file]
/*
* Copyright 2024 Rive
*/
#include "gm.hpp"
#include "gmutils.hpp"
#include "common/testing_window.hpp"
#include "rive/renderer/render_context.hpp"
#include "assets/nomoon.png.hpp"
#include <iterator>
using namespace rive;
using namespace rivegm;
// Grid of squares filled and stroked with linear and radial gradients, each
// under a translated, scaled or rotated shader transform.
DEF_SIMPLE_GM_WITH_CLEAR_COLOR(
gradienttransform,
0xff000000,
1600,
800,
renderer)
{
gpu::RenderContext* renderContext = TestingWindow::Get()->renderContext();
gpu::RenderContext::FrameDescriptor frameDescriptor;
if (renderContext != nullptr)
{
frameDescriptor = renderContext->frameDescriptor();
frameDescriptor.loadAction = gpu::LoadAction::preserveRenderTarget;
}
// This also tests addRenderPath's transform
Path doubleSquare;
doubleSquare->addRect(0.0f, 0.0f, 2.0f, 2.0f);
Path rect;
rect->addRenderPath(doubleSquare.get(), Mat2D::fromScale(0.5f, 0.5f));
ColorInt colors[] = {0xffff0000, 0xff00ff00};
float stops[] = {0.0f, 1.0f};
Paint horizPaint;
horizPaint->shader(
TestingWindow::Get()
->factory()
->makeLinearGradient(0.0f, 0.0f, 1.0f, 0.0f, colors, stops, 2));
Paint vertPaint;
vertPaint->shader(
TestingWindow::Get()
->factory()
->makeLinearGradient(0.0f, 0.0f, 0.0f, 1.0f, colors, stops, 2));
Paint radialPaint;
radialPaint->shader(
TestingWindow::Get()
->factory()
->makeRadialGradient(0.5f, 0.5f, 0.5f, colors, stops, 2));
Paint angularPaint;
angularPaint->shader(
TestingWindow::Get()->factory()->makeAngularGradient(colors, stops, 2));
// The rect is a unit square that the renderer scales up, so stroke
// thickness is in unit-square space.
constexpr float strokeThickness = 0.2f;
horizPaint->thickness(strokeThickness);
vertPaint->thickness(strokeThickness);
radialPaint->thickness(strokeThickness);
angularPaint->thickness(strokeThickness);
std::tuple<const Paint&, Mat2D> iterations[] = {
{horizPaint, Mat2D::fromTranslate(0.25f, 0.0f)},
{horizPaint, Mat2D::fromTranslate(-0.25f, 0.0f)},
{horizPaint, Mat2D::fromScale(1.5f, 1.0f)},
{horizPaint, Mat2D::fromScale(0.5f, 1.0f)},
{horizPaint, Mat2D::fromRotation(math::PI * 0.125f)},
{horizPaint, Mat2D::fromRotation(-math::PI * 0.125f)},
{vertPaint, Mat2D::fromTranslate(0.0f, 0.25f)},
{vertPaint, Mat2D::fromTranslate(0.0f, -0.25f)},
{vertPaint, Mat2D::fromScale(1.0f, 1.5f)},
{vertPaint, Mat2D::fromScale(1.0f, 0.5f)},
{vertPaint, Mat2D::fromRotation(math::PI * 0.125f)},
{vertPaint, Mat2D::fromRotation(-math::PI * 0.125f)},
{radialPaint, Mat2D::fromTranslate(0.25f, 0.0f)},
{radialPaint, Mat2D::fromTranslate(-0.25f, 0.0f)},
{radialPaint, Mat2D::fromTranslate(0.0f, 0.25f)},
{radialPaint, Mat2D::fromTranslate(0.0f, -0.25f)},
{radialPaint, Mat2D::fromScale(1.5f, 1.0f)},
{radialPaint, Mat2D::fromScale(0.5f, 1.0f)},
{radialPaint, Mat2D::fromScale(1.0f, 1.5f)},
{radialPaint, Mat2D::fromScale(1.0f, 0.5f)},
{radialPaint, Mat2D::fromRotation(math::PI * 0.125f)},
{radialPaint, Mat2D::fromRotation(-math::PI * 0.125f)},
{angularPaint,
Mat2D::fromTranslate(0.5f, 0.5f) * Mat2D::fromTranslate(0.25f, 0.25f)},
{angularPaint,
Mat2D::fromTranslate(0.5f, 0.5f) * Mat2D::fromScale(1.0f, 1.5f)},
{angularPaint,
Mat2D::fromTranslate(0.5f, 0.5f) * Mat2D::fromScale(1.0f, 0.5f)},
{angularPaint,
Mat2D::fromTranslate(0.5f, 0.5f) *
Mat2D::fromRotation(-math::PI * 0.125f)},
{angularPaint,
Mat2D::fromTranslate(0.5f, 0.5f) *
Mat2D::fromRotation(-math::PI * 0.125f)},
};
// Each iteration is drawn twice: filled, then stroked.
int count = sizeof(iterations) / sizeof(iterations[0]) * 2;
// Grid dimensions that keep the cells roughly square.
double aspectRatio = double(width()) / double(height());
int xCount = int(std::ceil(std::sqrt(double(count) * aspectRatio)));
int yCount = (count + xCount - 1) / xCount;
float rectSpaceWidth = float(width()) / float(xCount);
float rectSpaceHeight = float(height()) / float(yCount);
float rectWidth = rectSpaceWidth * 0.75f;
float rectHeight = rectSpaceHeight * 0.75f;
for (int i = 0; i < count; i++)
{
int x = i % xCount;
int y = i / xCount;
TestingWindow::Get()->flushPLSContext();
if (renderContext != nullptr)
{
renderContext->beginFrame(frameDescriptor);
}
renderer->save();
renderer->translate(
(float(x) + 0.5f) * rectSpaceWidth - rectWidth * 0.5f,
(float(y) + 0.5f) * rectSpaceHeight - rectHeight * 0.5f);
renderer->scale(rectWidth, rectHeight);
auto& [paint, transform] = iterations[i / 2];
paint->style(
(i % 2) == 0 ? RenderPaintStyle::fill : RenderPaintStyle::stroke);
paint->shaderTransform(transform);
renderer->drawPath(rect, paint);
renderer->restore();
}
}
DEF_SIMPLE_GM_WITH_CLEAR_COLOR(gradienttypes, 0xff404040, 2048, 1536, renderer)
{
auto factory = TestingWindow::Get()->factory();
ColorInt colors2[] = {
0xff881177,
0xff22ccbb,
};
float stops2[] = {0.0f, 1.0f};
static_assert(std::size(colors2) == std::size(stops2));
ColorInt colors5[] = {
0xff99dd55,
0xff00bbcc,
0xff881177,
0xffcc6666,
0xffeedd00,
};
float stops5[] = {0.0f, 0.25f, 0.5f, 0.75f, 1.0f};
static_assert(std::size(colors5) == std::size(stops5));
rcp<RenderShader> gradients[] = {
factory->makeLinearGradient(
-100.0f,
-100.0f,
100.0f,
100.0f,
colors2,
stops2,
std::size(colors2)),
factory->makeRadialGradient(
0.0f,
0.0,
100.0f,
colors2,
stops2,
std::size(colors2)),
factory->makeAngularGradient(colors2, stops2, std::size(colors2)),
factory->makeLinearGradient(
-100.0f,
-100.0f,
100.0f,
100.0f,
colors5,
stops5,
std::size(colors5)),
factory->makeRadialGradient(
0.0f,
0.0,
100.0f,
colors5,
stops5,
std::size(colors5)),
factory->makeAngularGradient(colors5, stops5, std::size(colors5)),
};
auto box = AABB{-110.0f, -110.0f, 110.0f, 110.0f};
auto path = PathBuilder::RRect(box, float(40.0f), float(40.0f));
path->fillRule(FillRule::clockwise);
auto img = LoadImage(assets::nomoon_png());
for (auto drawTypeIndex = 0; drawTypeIndex < 8; drawTypeIndex++)
{
auto useImage = (drawTypeIndex & 1) != 0;
bool isStroke = (drawTypeIndex & 2) != 0;
bool isFeather = (drawTypeIndex & 4) != 0;
for (auto gradientIndex = 0; gradientIndex < std::size(gradients);
gradientIndex++)
{
renderer->save();
renderer->transform(Mat2D::fromTranslate(
float(drawTypeIndex) * 256.0f + 128.0f,
float(gradientIndex) * 256.0f + 128.0f));
Paint paint;
paint->shader(gradients[gradientIndex]);
if (isStroke)
{
paint->stroke({.thickness = 10.0f});
}
if (isFeather)
{
paint->feather(20.0f);
}
if (useImage)
{
paint->modulatedImage(
img.get(),
ImageSampler{},
Mat2D::fromTranslate(-110.0f, -110.0f) *
Mat2D::fromScale(220.0f, 220.0f));
}
renderer->drawPath(path, paint);
renderer->restore();
}
}
}