fillConvexTriangles
Generates triangles to fill path (must be convex).
Vertexes will have unset uv and color is alpha multiplied opts.color fading to transparent at the edge if fade is > 0.
Parameters
- path:Path
- Path
- allocator:std.mem.Allocator
- std.mem.Allocator
- opts:FillConvexOptions
- FillConvexOptions
Source
Implementation
pub fn fillConvexTriangles(path: Path, allocator: std.mem.Allocator, opts: FillConvexOptions) std.mem.Allocator.Error!Triangles {
if (path.points.len < 3) {
return .empty;
}
var vtx_count = path.points.len;
var idx_count = (path.points.len - 2) * 3;
if (opts.fade > 0) {
vtx_count *= 2;
idx_count += path.points.len * 6;
}
if (opts.center) |_| {
vtx_count += 1;
idx_count += 6;
}
var builder = try Triangles.Builder.init(allocator, vtx_count, idx_count);
errdefer comptime unreachable; // No errors from this point on
const col: Color.PMA = .fromColor(opts.color);
var i: usize = 0;
while (i < path.points.len) : (i += 1) {
const ai: u16 = @intCast((i + path.points.len - 1) % path.points.len);
const bi: u16 = @intCast(i % path.points.len);
const ci: u16 = @intCast((i + 1) % path.points.len);
const aa = path.points[ai];
const bb = path.points[bi];
const cc = path.points[ci];
const diffab = aa.diff(bb).normalize();
const diffbc = bb.diff(cc).normalize();
// average of normals on each side
var norm: Point.Physical = .{ .x = (diffab.y + diffbc.y) / 2, .y = (-diffab.x - diffbc.x) / 2 };
// inner vertex
const inside_len = @min(0.5, opts.fade / 2);
builder.appendVertex(.{
.pos = .{
.x = bb.x - norm.x * inside_len,
.y = bb.y - norm.y * inside_len,
},
.col = col,
});
const idx_ai = if (opts.fade > 0) ai * 2 else ai;
const idx_bi = if (opts.fade > 0) bi * 2 else bi;
// indexes for fill
// triangles must be counter-clockwise (y going down) to avoid backface culling
if (opts.center) |_| {
builder.appendTriangles(&.{ @intCast(vtx_count - 1), idx_ai, idx_bi });
} else if (i > 1) {
builder.appendTriangles(&.{ 0, idx_ai, idx_bi });
}
if (opts.fade > 0) {
// scale averaged normal by angle between which happens to be the same as
// dividing by the length^2
const d2 = norm.x * norm.x + norm.y * norm.y;
if (d2 > 0.000001) {
norm = norm.scale(1.0 / d2, Point.Physical);
}
// limit distance our vertexes can be from the point to 2 so
// very small angles don't produce huge geometries
const l = norm.length();
if (l > 2.0) {
norm = norm.scale(2.0 / l, Point.Physical);
}
// outer vertex
const outside_len = if (opts.fade <= 1) opts.fade / 2 else opts.fade - 0.5;
builder.appendVertex(.{
.pos = .{
.x = bb.x + norm.x * outside_len,
.y = bb.y + norm.y * outside_len,
},
.col = .transparent,
});
// indexes for aa fade from inner to outer
// triangles must be counter-clockwise (y going down) to avoid backface culling
builder.appendTriangles(&.{
idx_ai, idx_ai + 1, idx_bi,
idx_ai + 1, idx_bi + 1, idx_bi,
});
}
}
if (opts.center) |center| {
builder.appendVertex(.{
.pos = center,
.col = col,
});
}
return builder.build();
}