blob: 57993b95ad4d99d5389bb36fd12ec1e710b82019 [file] [log] [blame]
/*
* Copyright 2022 Rive
*/
#include "rive/pls/pls_factory.hpp"
#include "pls_paint.hpp"
#include "pls_path.hpp"
#include "rive/math/math_types.hpp"
#include "rive/math/simd.hpp"
#include "rive/pls/pls_renderer.hpp"
namespace rive::pls
{
rcp<RenderBuffer> PLSFactory::makeBufferU16(Span<const uint16_t> data) { return nullptr; }
rcp<RenderBuffer> PLSFactory::makeBufferU32(Span<const uint32_t> data) { return nullptr; }
rcp<RenderBuffer> PLSFactory::makeBufferF32(Span<const float> data) { return nullptr; }
rcp<RenderShader> PLSFactory::makeLinearGradient(float sx,
float sy,
float ex,
float ey,
const ColorInt colors[], // [count]
const float stops[], // [count]
size_t count)
{
float2 start = {sx, sy};
float2 end = {ex, ey};
PLSGradDataArray<ColorInt> newColors(colors, count);
PLSGradDataArray<float> newStops(stops, count);
// If the stops don't begin and end on 0 and 1, transform the gradient so they do. This allows
// us to take full advantage of the gradient's range of pixels in the texture.
float firstStop = stops[0];
float lastStop = stops[count - 1];
if (firstStop != 0 || lastStop != 1)
{
// Tighten the endpoints to align with the mininum and maximum gradient stops.
float4 newEndpoints = simd::precise_mix(start.xyxy,
end.xyxy,
float4{firstStop, firstStop, lastStop, lastStop});
start = newEndpoints.xy;
end = newEndpoints.zw;
// Transform the stops into the range defined by the new endpoints.
newStops[0] = 0;
if (count > 2)
{
float m = 1.f / (lastStop - firstStop);
float a = -firstStop * m;
for (size_t i = 1; i < count - 1; ++i)
{
newStops[i] = std::clamp(stops[i] * m + a, newStops[i - 1], 1.f);
}
}
newStops[count - 1] = 1;
}
return PLSGradient::MakeLinear(std::move(newColors),
std::move(newStops),
count,
math::bit_cast<Vec2D>(start),
math::bit_cast<Vec2D>(end));
}
rcp<RenderShader> PLSFactory::makeRadialGradient(float cx,
float cy,
float radius,
const ColorInt colors[], // [count]
const float stops[], // [count]
size_t count)
{
PLSGradDataArray<ColorInt> newColors(colors, count);
PLSGradDataArray<float> newStops(stops, count);
// If the stops don't end on 1, scale gradient so they do. This allows us to take better
// advantage of the gradient's full range of pixels in the texture.
//
// TODO: If we want to take full advantage of the gradient texture pixels, we could add an inner
// radius that specifies where t=0 begins (instead of assuming it begins at the center).
float lastStop = stops[count - 1];
if (lastStop != 1)
{
// Scale the radius to align with the final stop.
radius *= lastStop;
// Scale the stops into the range defined by the new radius.
float inverseLastStop = 1.f / lastStop;
for (size_t i = 0; i < count - 1; ++i)
{
newStops[i] = stops[i] * inverseLastStop;
}
newStops[count - 1] = 1;
}
return PLSGradient::MakeRadial(std::move(newColors),
std::move(newStops),
count,
{cx, cy},
radius);
}
std::unique_ptr<RenderPath> PLSFactory::makeRenderPath(RawPath& rawPath, FillRule fillRule)
{
return std::make_unique<PLSPath>(fillRule, rawPath);
}
std::unique_ptr<RenderPath> PLSFactory::makeEmptyRenderPath()
{
return std::make_unique<PLSPath>();
}
std::unique_ptr<RenderPaint> PLSFactory::makeRenderPaint() { return std::make_unique<PLSPaint>(); }
std::unique_ptr<RenderImage> PLSFactory::decodeImage(Span<const uint8_t>) { return nullptr; }
} // namespace rive::pls