| /* |
| * 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 |