Merge pull request #34 from eliasnaur/master

implement clip paths
This commit is contained in:
Elias Naur 2020-10-16 11:34:52 +02:00 committed by GitHub
commit 61810b1bff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 326 additions and 40 deletions

View file

@ -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),
}
}
}

View file

@ -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),
}

View file

@ -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),
}
}
}

View file

@ -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);
}

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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:
@ -289,10 +291,6 @@ void main() {
for (uint i = 0; i < N_ROWS; i++) {
State st = combine_state(row, th_state[i]);
// We write the state now for development purposes, but the
// actual goal is to write transformed and annotated elements.
//State_write(StateRef((ix + i) * State_size), st);
// Here we read again from the original scene. There may be
// gains to be had from stashing in shared memory or possibly
// registers (though register pressure is an issue).
@ -385,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.

View file

@ -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.

View file

@ -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);

View file

@ -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));
}

View file

@ -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.