blob: 27cd3de71682d3e3147af105576ae6e1f64fac41 [file]
/*
* Copyright 2022 Rive
*/
#include "rive/pls/pls.hpp"
namespace rive::pls
{
constexpr static int32_t pack_params(int32_t patchSegmentSpan, int32_t vertexType)
{
return (patchSegmentSpan << 2) | vertexType;
}
static void generate_buffer_data_for_patch_type(PatchType patchType,
PatchVertex vertices[],
uint16_t indices[],
uint16_t baseVertex)
{
// AA border vertices. "Inner tessellation curves" have one more segment without a fan triangle
// whose purpose is to fill the join.
size_t patchSegmentSpan = patchType == PatchType::midpointFan ? kMidpointFanPatchSegmentSpan
: kOuterCurvePatchSegmentSpan;
size_t vertexCount = 0;
for (int i = 0; i <= patchSegmentSpan; ++i)
{
if (patchType == PatchType::outerCurves)
{
vertices[vertexCount++] = {static_cast<float>(i),
1,
0,
pack_params(patchSegmentSpan, flags::kStrokeVertex)};
vertices[vertexCount++] = {static_cast<float>(i),
0,
.5f,
pack_params(patchSegmentSpan, flags::kStrokeVertex)};
vertices[vertexCount++] = {static_cast<float>(i),
-1,
0,
pack_params(patchSegmentSpan, flags::kStrokeVertex)};
}
else
{
assert(patchType == PatchType::midpointFan);
vertices[vertexCount++] = {static_cast<float>(i),
-1,
1,
pack_params(patchSegmentSpan, flags::kStrokeVertex)};
vertices[vertexCount++] = {static_cast<float>(i),
1,
0,
pack_params(patchSegmentSpan, flags::kStrokeVertex)};
}
}
// Triangle fan vertices. (These only touch the first "fanSegmentSpan" segments on inner
// tessellation curves.
size_t fanSegmentSpan =
patchType == PatchType::midpointFan ? patchSegmentSpan : patchSegmentSpan - 1;
assert((fanSegmentSpan & (fanSegmentSpan - 1)) == 0); // The fan must be a power of two.
size_t fanVerticesIdx = vertexCount;
for (int i = 0; i <= fanSegmentSpan; ++i)
{
vertices[vertexCount++] = {static_cast<float>(i),
patchType == PatchType::outerCurves ? 0.f : -1.f,
1,
pack_params(patchSegmentSpan, flags::kFanVertex)};
}
// The midpoint vertex is only included on midpoint fan patches.
size_t midpointIdx = vertexCount;
if (patchType == PatchType::midpointFan)
{
vertices[vertexCount++] = {0,
0,
1,
pack_params(patchSegmentSpan, flags::kFanMidpointVertex)};
}
assert(vertexCount == (patchType == PatchType::outerCurves ? kOuterCurvePatchVertexCount
: kMidpointFanPatchVertexCount));
// AA border indices.
constexpr static size_t kCenterBorderPatternSize = 12;
constexpr static uint16_t kCenterBorderPattern[kCenterBorderPatternSize] =
{3, 4, 0, 0, 4, 1, 5, 4, 2, 2, 4, 1};
constexpr static size_t kOuterBorderPatternSize = 6;
constexpr static uint16_t kOuterBorderPattern[kOuterBorderPatternSize] = {0, 1, 2, 2, 1, 3};
size_t borderPatternSize =
patchType == PatchType::outerCurves ? kCenterBorderPatternSize : kOuterBorderPatternSize;
const uint16_t* borderPattern =
patchType == PatchType::outerCurves ? kCenterBorderPattern : kOuterBorderPattern;
size_t verticesPerNormal = patchType == PatchType::outerCurves ? 3 : 2;
size_t indexCount = 0;
for (int i = 0; i < borderPatternSize * patchSegmentSpan; ++i)
{
indices[indexCount++] = borderPattern[i % borderPatternSize] +
i / borderPatternSize * verticesPerNormal + baseVertex;
}
// Triangle fan indices, in a middle-out topology.
// Don't include the final bowtie join if this is an "outerStroke" patch. (i.e., use
// fanSegmentSpan and not "patchSegmentSpan".)
for (int step = 1; step < fanSegmentSpan; step <<= 1)
{
for (int i = 0; i < fanSegmentSpan; i += step * 2)
{
indices[indexCount++] = fanVerticesIdx + i + baseVertex;
indices[indexCount++] = fanVerticesIdx + i + step + baseVertex;
indices[indexCount++] = fanVerticesIdx + i + step * 2 + baseVertex;
}
}
if (patchType == PatchType::midpointFan)
{
// Triangle to the contour midpoint.
indices[indexCount++] = fanVerticesIdx + baseVertex;
indices[indexCount++] = fanVerticesIdx + fanSegmentSpan + baseVertex;
indices[indexCount++] = midpointIdx + baseVertex;
assert(indexCount == kMidpointFanPatchIndexCount);
}
else
{
assert(patchType == PatchType::outerCurves);
assert(indexCount == kOuterCurvePatchIndexCount);
}
}
void GeneratePatchBufferData(PatchVertex vertices[kPatchVertexBufferCount],
uint16_t indices[kPatchIndexBufferCount])
{
generate_buffer_data_for_patch_type(PatchType::midpointFan, vertices, indices, 0);
generate_buffer_data_for_patch_type(PatchType::outerCurves,
vertices + kMidpointFanPatchVertexCount,
indices + kMidpointFanPatchIndexCount,
kMidpointFanPatchVertexCount);
}
float FindTransformedArea(const AABB& bounds, const Mat2D& matrix)
{
Vec2D pts[4] = {{bounds.left(), bounds.top()},
{bounds.right(), bounds.top()},
{bounds.right(), bounds.bottom()},
{bounds.left(), bounds.bottom()}};
Vec2D screenSpacePts[4];
matrix.mapPoints(screenSpacePts, pts, 4);
Vec2D v[3] = {screenSpacePts[1] - screenSpacePts[0],
screenSpacePts[2] - screenSpacePts[0],
screenSpacePts[3] - screenSpacePts[0]};
return (fabsf(Vec2D::cross(v[0], v[1])) + fabsf(Vec2D::cross(v[1], v[2]))) * .5f;
}
} // namespace rive::pls