mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 12:41:30 +11:00
shader: implement clip paths
Expand the the final kernel4 stage to maintain a per-pixel mask. Introduce two new path elements, FillMask and FillMaskInv, to fill the mask. FillMask acts like Fill, while FillMaskInv fills the area outside the path. SVG clipPaths is then representable by a FillMaskInv(0.0) for every nested path, preceded by a FillMask(1.0) to clear the mask. The bounding box for FillMaskInv elements is the entire screen; tightening of the bounding box is left for future work. Note that a fullscreen bounding box is not hopelessly inefficient because completely filling a tile with a mask is just a single CmdSolidMask per tile. Fixes #30 Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
parent
55cfd472a5
commit
8fab45544e
|
@ -7,6 +7,10 @@ piet_gpu! {
|
|||
rgba_color: u32,
|
||||
bbox: [f32; 4],
|
||||
}
|
||||
struct AnnoFillMask {
|
||||
mask: f32,
|
||||
bbox: [f32; 4],
|
||||
}
|
||||
struct AnnoStroke {
|
||||
rgba_color: u32,
|
||||
bbox: [f32; 4],
|
||||
|
@ -18,6 +22,8 @@ piet_gpu! {
|
|||
Nop,
|
||||
Stroke(AnnoStroke),
|
||||
Fill(AnnoFill),
|
||||
FillMask(AnnoFillMask),
|
||||
FillMaskInv(AnnoFillMask),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,9 +25,17 @@ piet_gpu! {
|
|||
backdrop: i32,
|
||||
rgba_color: u32,
|
||||
}
|
||||
struct CmdFillMask {
|
||||
tile_ref: u32,
|
||||
backdrop: i32,
|
||||
mask: f32,
|
||||
}
|
||||
struct CmdSolid {
|
||||
rgba_color: u32,
|
||||
}
|
||||
struct CmdSolidMask {
|
||||
mask: f32,
|
||||
}
|
||||
struct CmdJump {
|
||||
new_ref: u32,
|
||||
}
|
||||
|
@ -36,8 +44,11 @@ piet_gpu! {
|
|||
Circle(CmdCircle),
|
||||
Line(CmdLine),
|
||||
Fill(CmdFill),
|
||||
FillMask(CmdFillMask),
|
||||
FillMaskInv(CmdFillMask),
|
||||
Stroke(CmdStroke),
|
||||
Solid(CmdSolid),
|
||||
SolidMask(CmdSolidMask),
|
||||
Jump(CmdJump),
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,9 @@ piet_gpu! {
|
|||
struct Fill {
|
||||
rgba_color: u32,
|
||||
}
|
||||
struct FillMask {
|
||||
mask: f32,
|
||||
}
|
||||
struct Stroke {
|
||||
rgba_color: u32,
|
||||
}
|
||||
|
@ -50,6 +53,8 @@ piet_gpu! {
|
|||
Fill(Fill),
|
||||
SetLineWidth(SetLineWidth),
|
||||
Transform(Transform),
|
||||
FillMask(FillMask),
|
||||
FillMaskInv(FillMask),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,10 @@ struct AnnoFillRef {
|
|||
uint offset;
|
||||
};
|
||||
|
||||
struct AnnoFillMaskRef {
|
||||
uint offset;
|
||||
};
|
||||
|
||||
struct AnnoStrokeRef {
|
||||
uint offset;
|
||||
};
|
||||
|
@ -23,6 +27,17 @@ AnnoFillRef AnnoFill_index(AnnoFillRef ref, uint index) {
|
|||
return AnnoFillRef(ref.offset + index * AnnoFill_size);
|
||||
}
|
||||
|
||||
struct AnnoFillMask {
|
||||
float mask;
|
||||
vec4 bbox;
|
||||
};
|
||||
|
||||
#define AnnoFillMask_size 20
|
||||
|
||||
AnnoFillMaskRef AnnoFillMask_index(AnnoFillMaskRef ref, uint index) {
|
||||
return AnnoFillMaskRef(ref.offset + index * AnnoFillMask_size);
|
||||
}
|
||||
|
||||
struct AnnoStroke {
|
||||
uint rgba_color;
|
||||
vec4 bbox;
|
||||
|
@ -38,6 +53,8 @@ AnnoStrokeRef AnnoStroke_index(AnnoStrokeRef ref, uint index) {
|
|||
#define Annotated_Nop 0
|
||||
#define Annotated_Stroke 1
|
||||
#define Annotated_Fill 2
|
||||
#define Annotated_FillMask 3
|
||||
#define Annotated_FillMaskInv 4
|
||||
#define Annotated_size 28
|
||||
|
||||
AnnotatedRef Annotated_index(AnnotatedRef ref, uint index) {
|
||||
|
@ -66,6 +83,28 @@ void AnnoFill_write(AnnoFillRef ref, AnnoFill s) {
|
|||
annotated[ix + 4] = floatBitsToUint(s.bbox.w);
|
||||
}
|
||||
|
||||
AnnoFillMask AnnoFillMask_read(AnnoFillMaskRef ref) {
|
||||
uint ix = ref.offset >> 2;
|
||||
uint raw0 = annotated[ix + 0];
|
||||
uint raw1 = annotated[ix + 1];
|
||||
uint raw2 = annotated[ix + 2];
|
||||
uint raw3 = annotated[ix + 3];
|
||||
uint raw4 = annotated[ix + 4];
|
||||
AnnoFillMask s;
|
||||
s.mask = uintBitsToFloat(raw0);
|
||||
s.bbox = vec4(uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3), uintBitsToFloat(raw4));
|
||||
return s;
|
||||
}
|
||||
|
||||
void AnnoFillMask_write(AnnoFillMaskRef ref, AnnoFillMask s) {
|
||||
uint ix = ref.offset >> 2;
|
||||
annotated[ix + 0] = floatBitsToUint(s.mask);
|
||||
annotated[ix + 1] = floatBitsToUint(s.bbox.x);
|
||||
annotated[ix + 2] = floatBitsToUint(s.bbox.y);
|
||||
annotated[ix + 3] = floatBitsToUint(s.bbox.z);
|
||||
annotated[ix + 4] = floatBitsToUint(s.bbox.w);
|
||||
}
|
||||
|
||||
AnnoStroke AnnoStroke_read(AnnoStrokeRef ref) {
|
||||
uint ix = ref.offset >> 2;
|
||||
uint raw0 = annotated[ix + 0];
|
||||
|
@ -103,6 +142,14 @@ AnnoFill Annotated_Fill_read(AnnotatedRef ref) {
|
|||
return AnnoFill_read(AnnoFillRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
AnnoFillMask Annotated_FillMask_read(AnnotatedRef ref) {
|
||||
return AnnoFillMask_read(AnnoFillMaskRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
AnnoFillMask Annotated_FillMaskInv_read(AnnotatedRef ref) {
|
||||
return AnnoFillMask_read(AnnoFillMaskRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
void Annotated_Nop_write(AnnotatedRef ref) {
|
||||
annotated[ref.offset >> 2] = Annotated_Nop;
|
||||
}
|
||||
|
@ -117,3 +164,13 @@ void Annotated_Fill_write(AnnotatedRef ref, AnnoFill s) {
|
|||
AnnoFill_write(AnnoFillRef(ref.offset + 4), s);
|
||||
}
|
||||
|
||||
void Annotated_FillMask_write(AnnotatedRef ref, AnnoFillMask s) {
|
||||
annotated[ref.offset >> 2] = Annotated_FillMask;
|
||||
AnnoFillMask_write(AnnoFillMaskRef(ref.offset + 4), s);
|
||||
}
|
||||
|
||||
void Annotated_FillMaskInv_write(AnnotatedRef ref, AnnoFillMask s) {
|
||||
annotated[ref.offset >> 2] = Annotated_FillMaskInv;
|
||||
AnnoFillMask_write(AnnoFillMaskRef(ref.offset + 4), s);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,10 @@ void main() {
|
|||
uint row_count = 0;
|
||||
if (element_ix < n_elements) {
|
||||
uint tag = Annotated_tag(ref);
|
||||
if (tag == Annotated_Fill) {
|
||||
switch (tag) {
|
||||
case Annotated_Fill:
|
||||
case Annotated_FillMask:
|
||||
case Annotated_FillMaskInv:
|
||||
PathRef path_ref = PathRef(element_ix * Path_size);
|
||||
Path path = Path_read(path_ref);
|
||||
sh_row_width[th_ix] = path.bbox.z - path.bbox.x;
|
||||
|
|
Binary file not shown.
|
@ -60,6 +60,8 @@ void main() {
|
|||
float my_right_edge = INFINITY;
|
||||
switch (tag) {
|
||||
case Annotated_Fill:
|
||||
case Annotated_FillMask:
|
||||
case Annotated_FillMaskInv:
|
||||
case Annotated_Stroke:
|
||||
// Note: we take advantage of the fact that fills and strokes
|
||||
// have compatible layout.
|
||||
|
|
Binary file not shown.
|
@ -173,6 +173,8 @@ void main() {
|
|||
uint tile_count;
|
||||
switch (tag) {
|
||||
case Annotated_Fill:
|
||||
case Annotated_FillMask:
|
||||
case Annotated_FillMaskInv:
|
||||
case Annotated_Stroke:
|
||||
// Because the only elements we're processing right now are
|
||||
// paths, we can just use the element index as the path index.
|
||||
|
@ -222,12 +224,20 @@ void main() {
|
|||
el_ix = probe;
|
||||
}
|
||||
}
|
||||
AnnotatedRef ref = AnnotatedRef(el_ix * Annotated_size);
|
||||
uint tag = Annotated_tag(ref);
|
||||
uint seq_ix = ix - (el_ix > 0 ? sh_tile_count[el_ix - 1] : 0);
|
||||
uint width = sh_tile_width[el_ix];
|
||||
uint x = sh_tile_x0[el_ix] + seq_ix % width;
|
||||
uint y = sh_tile_y0[el_ix] + seq_ix / width;
|
||||
Tile tile = Tile_read(TileRef(sh_tile_base[el_ix] + (sh_tile_stride[el_ix] * y + x) * Tile_size));
|
||||
if (tile.tile.offset != 0 || tile.backdrop != 0) {
|
||||
// Include the path in the tile if
|
||||
// - the tile contains at least a segment (tile offset non-zero)
|
||||
// - the tile is completely covered (backdrop non-zero)
|
||||
// - the tile is not covered and we're filling everything outside the path (backdrop zero, inverse fills).
|
||||
bool inside = tile.backdrop != 0;
|
||||
bool fill = tag != Annotated_FillMaskInv;
|
||||
if (tile.tile.offset != 0 || inside == fill) {
|
||||
uint el_slice = el_ix / 32;
|
||||
uint el_mask = 1 << (el_ix & 31);
|
||||
atomicOr(sh_bitmaps[el_slice][y * N_TILE_X + x], el_mask);
|
||||
|
@ -281,6 +291,27 @@ void main() {
|
|||
}
|
||||
cmd_ref.offset += Cmd_size;
|
||||
break;
|
||||
case Annotated_FillMask:
|
||||
case Annotated_FillMaskInv:
|
||||
tile = Tile_read(TileRef(sh_tile_base[element_ref_ix]
|
||||
+ (sh_tile_stride[element_ref_ix] * tile_y + tile_x) * Tile_size));
|
||||
AnnoFillMask fill_mask = Annotated_FillMask_read(ref);
|
||||
alloc_cmd(cmd_ref, cmd_limit);
|
||||
if (tile.tile.offset != 0) {
|
||||
CmdFillMask cmd_fill;
|
||||
cmd_fill.tile_ref = tile.tile.offset;
|
||||
cmd_fill.backdrop = tile.backdrop;
|
||||
cmd_fill.mask = fill_mask.mask;
|
||||
if (tag == Annotated_FillMask) {
|
||||
Cmd_FillMask_write(cmd_ref, cmd_fill);
|
||||
} else {
|
||||
Cmd_FillMaskInv_write(cmd_ref, cmd_fill);
|
||||
}
|
||||
} else {
|
||||
Cmd_SolidMask_write(cmd_ref, CmdSolidMask(fill_mask.mask));
|
||||
}
|
||||
cmd_ref.offset += Cmd_size;
|
||||
break;
|
||||
case Annotated_Stroke:
|
||||
tile = Tile_read(TileRef(sh_tile_base[element_ref_ix]
|
||||
+ (sh_tile_stride[element_ref_ix] * tile_y + tile_x) * Tile_size));
|
||||
|
|
Binary file not shown.
|
@ -130,6 +130,8 @@ State map_element(ElementRef ref, inout bool is_fill) {
|
|||
c.pathseg_count = 1;
|
||||
break;
|
||||
case Element_Fill:
|
||||
case Element_FillMask:
|
||||
case Element_FillMaskInv:
|
||||
is_fill = true;
|
||||
// fall-through
|
||||
case Element_Stroke:
|
||||
|
@ -381,6 +383,23 @@ void main() {
|
|||
out_ref = AnnotatedRef((st.path_count - 1) * Annotated_size);
|
||||
Annotated_Fill_write(out_ref, anno_fill);
|
||||
break;
|
||||
case Element_FillMask:
|
||||
FillMask fill_mask = Element_FillMask_read(this_ref);
|
||||
AnnoFillMask anno_fill_mask;
|
||||
anno_fill_mask.mask = fill_mask.mask;
|
||||
anno_fill_mask.bbox = st.bbox;
|
||||
out_ref = AnnotatedRef((st.path_count - 1) * Annotated_size);
|
||||
Annotated_FillMask_write(out_ref, anno_fill_mask);
|
||||
break;
|
||||
case Element_FillMaskInv:
|
||||
fill_mask = Element_FillMaskInv_read(this_ref);
|
||||
anno_fill_mask.mask = fill_mask.mask;
|
||||
// The inverse fill conceptually takes up the entire screen.
|
||||
// TODO: Tighten bounds to contain only affected paths.
|
||||
anno_fill_mask.bbox = vec4(0, 0, 1e9, 1e9);
|
||||
out_ref = AnnotatedRef((st.path_count - 1) * Annotated_size);
|
||||
Annotated_FillMaskInv_write(out_ref, anno_fill_mask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -27,6 +27,40 @@ layout(rgba8, set = 0, binding = 2) uniform writeonly image2D image;
|
|||
#include "ptcl.h"
|
||||
#include "tile.h"
|
||||
|
||||
// Calculate coverage based on backdrop + coverage of each line segment
|
||||
float[CHUNK] computeArea(vec2 xy, int backdrop, uint tile_ref) {
|
||||
// Probably better to store as float, but conversion is no doubt cheap.
|
||||
float area[CHUNK];
|
||||
for (uint k = 0; k < CHUNK; k++) area[k] = float(backdrop);
|
||||
TileSegRef tile_seg_ref = TileSegRef(tile_ref);
|
||||
do {
|
||||
TileSeg seg = TileSeg_read(tile_seg_ref);
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
vec2 my_xy = vec2(xy.x, xy.y + float(k * CHUNK_DY));
|
||||
vec2 start = seg.start - my_xy;
|
||||
vec2 end = seg.end - my_xy;
|
||||
vec2 window = clamp(vec2(start.y, end.y), 0.0, 1.0);
|
||||
if (window.x != window.y) {
|
||||
vec2 t = (window - start.y) / (end.y - start.y);
|
||||
vec2 xs = vec2(mix(start.x, end.x, t.x), mix(start.x, end.x, t.y));
|
||||
float xmin = min(min(xs.x, xs.y), 1.0) - 1e-6;
|
||||
float xmax = max(xs.x, xs.y);
|
||||
float b = min(xmax, 1.0);
|
||||
float c = max(b, 0.0);
|
||||
float d = max(xmin, 0.0);
|
||||
float a = (b + 0.5 * (d * d - c * c) - xmin) / (xmax - xmin);
|
||||
area[k] += a * (window.x - window.y);
|
||||
}
|
||||
area[k] += sign(end.x - start.x) * clamp(my_xy.y - seg.y_edge + 1.0, 0.0, 1.0);
|
||||
}
|
||||
tile_seg_ref = seg.next;
|
||||
} while (tile_seg_ref.offset != 0);
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
area[k] = min(abs(area[k]), 1.0);
|
||||
}
|
||||
return area;
|
||||
}
|
||||
|
||||
void main() {
|
||||
uint tile_ix = gl_WorkGroupID.y * WIDTH_IN_TILES + gl_WorkGroupID.x;
|
||||
CmdRef cmd_ref = CmdRef(tile_ix * PTCL_INITIAL_ALLOC);
|
||||
|
@ -34,8 +68,10 @@ void main() {
|
|||
uvec2 xy_uint = uvec2(gl_GlobalInvocationID.x, gl_LocalInvocationID.y + TILE_HEIGHT_PX * gl_WorkGroupID.y);
|
||||
vec2 xy = vec2(xy_uint);
|
||||
vec3 rgb[CHUNK];
|
||||
float mask[CHUNK];
|
||||
for (uint i = 0; i < CHUNK; i++) {
|
||||
rgb[i] = vec3(0.5);
|
||||
mask[i] = 1.0;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
@ -52,7 +88,7 @@ void main() {
|
|||
float r = length(vec2(xy.x, xy.y + dy) + vec2(0.5, 0.5) - circle.center.xy);
|
||||
float alpha = clamp(0.5 + circle.radius - r, 0.0, 1.0);
|
||||
// TODO: sRGB
|
||||
rgb[i] = mix(rgb[i], fg_rgba.rgb, alpha * fg_rgba.a);
|
||||
rgb[i] = mix(rgb[i], fg_rgba.rgb, mask[i] * alpha * fg_rgba.a);
|
||||
}
|
||||
break;
|
||||
case Cmd_Stroke:
|
||||
|
@ -75,49 +111,43 @@ void main() {
|
|||
fg_rgba = unpackUnorm4x8(stroke.rgba_color).wzyx;
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
float alpha = clamp(stroke.half_width + 0.5 - df[k], 0.0, 1.0);
|
||||
rgb[k] = mix(rgb[k], fg_rgba.rgb, alpha * fg_rgba.a);
|
||||
rgb[k] = mix(rgb[k], fg_rgba.rgb, mask[k] * alpha * fg_rgba.a);
|
||||
}
|
||||
break;
|
||||
case Cmd_Fill:
|
||||
// Calculate coverage based on backdrop + coverage of each line segment
|
||||
CmdFill fill = Cmd_Fill_read(cmd_ref);
|
||||
// Probably better to store as float, but conversion is no doubt cheap.
|
||||
float area[CHUNK];
|
||||
for (uint k = 0; k < CHUNK; k++) area[k] = float(fill.backdrop);
|
||||
tile_seg_ref = TileSegRef(fill.tile_ref);
|
||||
do {
|
||||
TileSeg seg = TileSeg_read(tile_seg_ref);
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
vec2 my_xy = vec2(xy.x, xy.y + float(k * CHUNK_DY));
|
||||
vec2 start = seg.start - my_xy;
|
||||
vec2 end = seg.end - my_xy;
|
||||
vec2 window = clamp(vec2(start.y, end.y), 0.0, 1.0);
|
||||
if (window.x != window.y) {
|
||||
vec2 t = (window - start.y) / (end.y - start.y);
|
||||
vec2 xs = vec2(mix(start.x, end.x, t.x), mix(start.x, end.x, t.y));
|
||||
float xmin = min(min(xs.x, xs.y), 1.0) - 1e-6;
|
||||
float xmax = max(xs.x, xs.y);
|
||||
float b = min(xmax, 1.0);
|
||||
float c = max(b, 0.0);
|
||||
float d = max(xmin, 0.0);
|
||||
float a = (b + 0.5 * (d * d - c * c) - xmin) / (xmax - xmin);
|
||||
area[k] += a * (window.x - window.y);
|
||||
}
|
||||
area[k] += sign(end.x - start.x) * clamp(my_xy.y - seg.y_edge + 1.0, 0.0, 1.0);
|
||||
}
|
||||
tile_seg_ref = seg.next;
|
||||
} while (tile_seg_ref.offset != 0);
|
||||
area = computeArea(xy, fill.backdrop, fill.tile_ref);
|
||||
fg_rgba = unpackUnorm4x8(fill.rgba_color).wzyx;
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
float alpha = min(abs(area[k]), 1.0);
|
||||
rgb[k] = mix(rgb[k], fg_rgba.rgb, alpha * fg_rgba.a);
|
||||
rgb[k] = mix(rgb[k], fg_rgba.rgb, mask[k] * area[k] * fg_rgba.a);
|
||||
}
|
||||
break;
|
||||
case Cmd_FillMask:
|
||||
CmdFillMask fill_mask = Cmd_FillMask_read(cmd_ref);
|
||||
area = computeArea(xy, fill_mask.backdrop, fill_mask.tile_ref);
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
mask[k] = mix(mask[k], fill_mask.mask, area[k]);
|
||||
}
|
||||
break;
|
||||
case Cmd_FillMaskInv:
|
||||
fill_mask = Cmd_FillMask_read(cmd_ref);
|
||||
area = computeArea(xy, fill_mask.backdrop, fill_mask.tile_ref);
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
mask[k] = mix(mask[k], fill_mask.mask, 1.0 - area[k]);
|
||||
}
|
||||
break;
|
||||
case Cmd_Solid:
|
||||
CmdSolid solid = Cmd_Solid_read(cmd_ref);
|
||||
fg_rgba = unpackUnorm4x8(solid.rgba_color).wzyx;
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
rgb[k] = mix(rgb[k], fg_rgba.rgb, fg_rgba.a);
|
||||
rgb[k] = mix(rgb[k], fg_rgba.rgb, mask[k] * fg_rgba.a);
|
||||
}
|
||||
break;
|
||||
case Cmd_SolidMask:
|
||||
CmdSolidMask solid_mask = Cmd_SolidMask_read(cmd_ref);
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
mask[k] = solid_mask.mask;
|
||||
}
|
||||
break;
|
||||
case Cmd_Jump:
|
||||
|
|
Binary file not shown.
|
@ -16,10 +16,18 @@ struct CmdFillRef {
|
|||
uint offset;
|
||||
};
|
||||
|
||||
struct CmdFillMaskRef {
|
||||
uint offset;
|
||||
};
|
||||
|
||||
struct CmdSolidRef {
|
||||
uint offset;
|
||||
};
|
||||
|
||||
struct CmdSolidMaskRef {
|
||||
uint offset;
|
||||
};
|
||||
|
||||
struct CmdJumpRef {
|
||||
uint offset;
|
||||
};
|
||||
|
@ -83,6 +91,18 @@ CmdFillRef CmdFill_index(CmdFillRef ref, uint index) {
|
|||
return CmdFillRef(ref.offset + index * CmdFill_size);
|
||||
}
|
||||
|
||||
struct CmdFillMask {
|
||||
uint tile_ref;
|
||||
int backdrop;
|
||||
float mask;
|
||||
};
|
||||
|
||||
#define CmdFillMask_size 12
|
||||
|
||||
CmdFillMaskRef CmdFillMask_index(CmdFillMaskRef ref, uint index) {
|
||||
return CmdFillMaskRef(ref.offset + index * CmdFillMask_size);
|
||||
}
|
||||
|
||||
struct CmdSolid {
|
||||
uint rgba_color;
|
||||
};
|
||||
|
@ -93,6 +113,16 @@ CmdSolidRef CmdSolid_index(CmdSolidRef ref, uint index) {
|
|||
return CmdSolidRef(ref.offset + index * CmdSolid_size);
|
||||
}
|
||||
|
||||
struct CmdSolidMask {
|
||||
float mask;
|
||||
};
|
||||
|
||||
#define CmdSolidMask_size 4
|
||||
|
||||
CmdSolidMaskRef CmdSolidMask_index(CmdSolidMaskRef ref, uint index) {
|
||||
return CmdSolidMaskRef(ref.offset + index * CmdSolidMask_size);
|
||||
}
|
||||
|
||||
struct CmdJump {
|
||||
uint new_ref;
|
||||
};
|
||||
|
@ -107,9 +137,12 @@ CmdJumpRef CmdJump_index(CmdJumpRef ref, uint index) {
|
|||
#define Cmd_Circle 1
|
||||
#define Cmd_Line 2
|
||||
#define Cmd_Fill 3
|
||||
#define Cmd_Stroke 4
|
||||
#define Cmd_Solid 5
|
||||
#define Cmd_Jump 6
|
||||
#define Cmd_FillMask 4
|
||||
#define Cmd_FillMaskInv 5
|
||||
#define Cmd_Stroke 6
|
||||
#define Cmd_Solid 7
|
||||
#define Cmd_SolidMask 8
|
||||
#define Cmd_Jump 9
|
||||
#define Cmd_size 20
|
||||
|
||||
CmdRef Cmd_index(CmdRef ref, uint index) {
|
||||
|
@ -219,6 +252,25 @@ void CmdFill_write(CmdFillRef ref, CmdFill s) {
|
|||
ptcl[ix + 2] = s.rgba_color;
|
||||
}
|
||||
|
||||
CmdFillMask CmdFillMask_read(CmdFillMaskRef ref) {
|
||||
uint ix = ref.offset >> 2;
|
||||
uint raw0 = ptcl[ix + 0];
|
||||
uint raw1 = ptcl[ix + 1];
|
||||
uint raw2 = ptcl[ix + 2];
|
||||
CmdFillMask s;
|
||||
s.tile_ref = raw0;
|
||||
s.backdrop = int(raw1);
|
||||
s.mask = uintBitsToFloat(raw2);
|
||||
return s;
|
||||
}
|
||||
|
||||
void CmdFillMask_write(CmdFillMaskRef ref, CmdFillMask s) {
|
||||
uint ix = ref.offset >> 2;
|
||||
ptcl[ix + 0] = s.tile_ref;
|
||||
ptcl[ix + 1] = uint(s.backdrop);
|
||||
ptcl[ix + 2] = floatBitsToUint(s.mask);
|
||||
}
|
||||
|
||||
CmdSolid CmdSolid_read(CmdSolidRef ref) {
|
||||
uint ix = ref.offset >> 2;
|
||||
uint raw0 = ptcl[ix + 0];
|
||||
|
@ -232,6 +284,19 @@ void CmdSolid_write(CmdSolidRef ref, CmdSolid s) {
|
|||
ptcl[ix + 0] = s.rgba_color;
|
||||
}
|
||||
|
||||
CmdSolidMask CmdSolidMask_read(CmdSolidMaskRef ref) {
|
||||
uint ix = ref.offset >> 2;
|
||||
uint raw0 = ptcl[ix + 0];
|
||||
CmdSolidMask s;
|
||||
s.mask = uintBitsToFloat(raw0);
|
||||
return s;
|
||||
}
|
||||
|
||||
void CmdSolidMask_write(CmdSolidMaskRef ref, CmdSolidMask s) {
|
||||
uint ix = ref.offset >> 2;
|
||||
ptcl[ix + 0] = floatBitsToUint(s.mask);
|
||||
}
|
||||
|
||||
CmdJump CmdJump_read(CmdJumpRef ref) {
|
||||
uint ix = ref.offset >> 2;
|
||||
uint raw0 = ptcl[ix + 0];
|
||||
|
@ -261,6 +326,14 @@ CmdFill Cmd_Fill_read(CmdRef ref) {
|
|||
return CmdFill_read(CmdFillRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
CmdFillMask Cmd_FillMask_read(CmdRef ref) {
|
||||
return CmdFillMask_read(CmdFillMaskRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
CmdFillMask Cmd_FillMaskInv_read(CmdRef ref) {
|
||||
return CmdFillMask_read(CmdFillMaskRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
CmdStroke Cmd_Stroke_read(CmdRef ref) {
|
||||
return CmdStroke_read(CmdStrokeRef(ref.offset + 4));
|
||||
}
|
||||
|
@ -269,6 +342,10 @@ CmdSolid Cmd_Solid_read(CmdRef ref) {
|
|||
return CmdSolid_read(CmdSolidRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
CmdSolidMask Cmd_SolidMask_read(CmdRef ref) {
|
||||
return CmdSolidMask_read(CmdSolidMaskRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
CmdJump Cmd_Jump_read(CmdRef ref) {
|
||||
return CmdJump_read(CmdJumpRef(ref.offset + 4));
|
||||
}
|
||||
|
@ -292,6 +369,16 @@ void Cmd_Fill_write(CmdRef ref, CmdFill s) {
|
|||
CmdFill_write(CmdFillRef(ref.offset + 4), s);
|
||||
}
|
||||
|
||||
void Cmd_FillMask_write(CmdRef ref, CmdFillMask s) {
|
||||
ptcl[ref.offset >> 2] = Cmd_FillMask;
|
||||
CmdFillMask_write(CmdFillMaskRef(ref.offset + 4), s);
|
||||
}
|
||||
|
||||
void Cmd_FillMaskInv_write(CmdRef ref, CmdFillMask s) {
|
||||
ptcl[ref.offset >> 2] = Cmd_FillMaskInv;
|
||||
CmdFillMask_write(CmdFillMaskRef(ref.offset + 4), s);
|
||||
}
|
||||
|
||||
void Cmd_Stroke_write(CmdRef ref, CmdStroke s) {
|
||||
ptcl[ref.offset >> 2] = Cmd_Stroke;
|
||||
CmdStroke_write(CmdStrokeRef(ref.offset + 4), s);
|
||||
|
@ -302,6 +389,11 @@ void Cmd_Solid_write(CmdRef ref, CmdSolid s) {
|
|||
CmdSolid_write(CmdSolidRef(ref.offset + 4), s);
|
||||
}
|
||||
|
||||
void Cmd_SolidMask_write(CmdRef ref, CmdSolidMask s) {
|
||||
ptcl[ref.offset >> 2] = Cmd_SolidMask;
|
||||
CmdSolidMask_write(CmdSolidMaskRef(ref.offset + 4), s);
|
||||
}
|
||||
|
||||
void Cmd_Jump_write(CmdRef ref, CmdJump s) {
|
||||
ptcl[ref.offset >> 2] = Cmd_Jump;
|
||||
CmdJump_write(CmdJumpRef(ref.offset + 4), s);
|
||||
|
|
|
@ -16,6 +16,10 @@ struct FillRef {
|
|||
uint offset;
|
||||
};
|
||||
|
||||
struct FillMaskRef {
|
||||
uint offset;
|
||||
};
|
||||
|
||||
struct StrokeRef {
|
||||
uint offset;
|
||||
};
|
||||
|
@ -78,6 +82,16 @@ FillRef Fill_index(FillRef ref, uint index) {
|
|||
return FillRef(ref.offset + index * Fill_size);
|
||||
}
|
||||
|
||||
struct FillMask {
|
||||
float mask;
|
||||
};
|
||||
|
||||
#define FillMask_size 4
|
||||
|
||||
FillMaskRef FillMask_index(FillMaskRef ref, uint index) {
|
||||
return FillMaskRef(ref.offset + index * FillMask_size);
|
||||
}
|
||||
|
||||
struct Stroke {
|
||||
uint rgba_color;
|
||||
};
|
||||
|
@ -120,6 +134,8 @@ TransformRef Transform_index(TransformRef ref, uint index) {
|
|||
#define Element_Fill 8
|
||||
#define Element_SetLineWidth 9
|
||||
#define Element_Transform 10
|
||||
#define Element_FillMask 11
|
||||
#define Element_FillMaskInv 12
|
||||
#define Element_size 36
|
||||
|
||||
ElementRef Element_index(ElementRef ref, uint index) {
|
||||
|
@ -179,6 +195,14 @@ Fill Fill_read(FillRef ref) {
|
|||
return s;
|
||||
}
|
||||
|
||||
FillMask FillMask_read(FillMaskRef ref) {
|
||||
uint ix = ref.offset >> 2;
|
||||
uint raw0 = scene[ix + 0];
|
||||
FillMask s;
|
||||
s.mask = uintBitsToFloat(raw0);
|
||||
return s;
|
||||
}
|
||||
|
||||
Stroke Stroke_read(StrokeRef ref) {
|
||||
uint ix = ref.offset >> 2;
|
||||
uint raw0 = scene[ix + 0];
|
||||
|
@ -253,3 +277,11 @@ Transform Element_Transform_read(ElementRef ref) {
|
|||
return Transform_read(TransformRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
FillMask Element_FillMask_read(ElementRef ref) {
|
||||
return FillMask_read(FillMaskRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
FillMask Element_FillMaskInv_read(ElementRef ref) {
|
||||
return FillMask_read(FillMaskRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@ void main() {
|
|||
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
|
||||
switch (tag) {
|
||||
case Annotated_Fill:
|
||||
case Annotated_FillMask:
|
||||
case Annotated_FillMaskInv:
|
||||
case Annotated_Stroke:
|
||||
// Note: we take advantage of the fact that fills and strokes
|
||||
// have compatible layout.
|
||||
|
|
Binary file not shown.
Loading…
Reference in a new issue