mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 12:41:30 +11:00
commit
61810b1bff
|
@ -7,6 +7,10 @@ piet_gpu! {
|
||||||
rgba_color: u32,
|
rgba_color: u32,
|
||||||
bbox: [f32; 4],
|
bbox: [f32; 4],
|
||||||
}
|
}
|
||||||
|
struct AnnoFillMask {
|
||||||
|
mask: f32,
|
||||||
|
bbox: [f32; 4],
|
||||||
|
}
|
||||||
struct AnnoStroke {
|
struct AnnoStroke {
|
||||||
rgba_color: u32,
|
rgba_color: u32,
|
||||||
bbox: [f32; 4],
|
bbox: [f32; 4],
|
||||||
|
@ -18,6 +22,8 @@ piet_gpu! {
|
||||||
Nop,
|
Nop,
|
||||||
Stroke(AnnoStroke),
|
Stroke(AnnoStroke),
|
||||||
Fill(AnnoFill),
|
Fill(AnnoFill),
|
||||||
|
FillMask(AnnoFillMask),
|
||||||
|
FillMaskInv(AnnoFillMask),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,17 @@ piet_gpu! {
|
||||||
backdrop: i32,
|
backdrop: i32,
|
||||||
rgba_color: u32,
|
rgba_color: u32,
|
||||||
}
|
}
|
||||||
|
struct CmdFillMask {
|
||||||
|
tile_ref: u32,
|
||||||
|
backdrop: i32,
|
||||||
|
mask: f32,
|
||||||
|
}
|
||||||
struct CmdSolid {
|
struct CmdSolid {
|
||||||
rgba_color: u32,
|
rgba_color: u32,
|
||||||
}
|
}
|
||||||
|
struct CmdSolidMask {
|
||||||
|
mask: f32,
|
||||||
|
}
|
||||||
struct CmdJump {
|
struct CmdJump {
|
||||||
new_ref: u32,
|
new_ref: u32,
|
||||||
}
|
}
|
||||||
|
@ -36,8 +44,11 @@ piet_gpu! {
|
||||||
Circle(CmdCircle),
|
Circle(CmdCircle),
|
||||||
Line(CmdLine),
|
Line(CmdLine),
|
||||||
Fill(CmdFill),
|
Fill(CmdFill),
|
||||||
|
FillMask(CmdFillMask),
|
||||||
|
FillMaskInv(CmdFillMask),
|
||||||
Stroke(CmdStroke),
|
Stroke(CmdStroke),
|
||||||
Solid(CmdSolid),
|
Solid(CmdSolid),
|
||||||
|
SolidMask(CmdSolidMask),
|
||||||
Jump(CmdJump),
|
Jump(CmdJump),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@ piet_gpu! {
|
||||||
struct Fill {
|
struct Fill {
|
||||||
rgba_color: u32,
|
rgba_color: u32,
|
||||||
}
|
}
|
||||||
|
struct FillMask {
|
||||||
|
mask: f32,
|
||||||
|
}
|
||||||
struct Stroke {
|
struct Stroke {
|
||||||
rgba_color: u32,
|
rgba_color: u32,
|
||||||
}
|
}
|
||||||
|
@ -50,6 +53,8 @@ piet_gpu! {
|
||||||
Fill(Fill),
|
Fill(Fill),
|
||||||
SetLineWidth(SetLineWidth),
|
SetLineWidth(SetLineWidth),
|
||||||
Transform(Transform),
|
Transform(Transform),
|
||||||
|
FillMask(FillMask),
|
||||||
|
FillMaskInv(FillMask),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,10 @@ struct AnnoFillRef {
|
||||||
uint offset;
|
uint offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AnnoFillMaskRef {
|
||||||
|
uint offset;
|
||||||
|
};
|
||||||
|
|
||||||
struct AnnoStrokeRef {
|
struct AnnoStrokeRef {
|
||||||
uint offset;
|
uint offset;
|
||||||
};
|
};
|
||||||
|
@ -23,6 +27,17 @@ AnnoFillRef AnnoFill_index(AnnoFillRef ref, uint index) {
|
||||||
return AnnoFillRef(ref.offset + index * AnnoFill_size);
|
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 {
|
struct AnnoStroke {
|
||||||
uint rgba_color;
|
uint rgba_color;
|
||||||
vec4 bbox;
|
vec4 bbox;
|
||||||
|
@ -38,6 +53,8 @@ AnnoStrokeRef AnnoStroke_index(AnnoStrokeRef ref, uint index) {
|
||||||
#define Annotated_Nop 0
|
#define Annotated_Nop 0
|
||||||
#define Annotated_Stroke 1
|
#define Annotated_Stroke 1
|
||||||
#define Annotated_Fill 2
|
#define Annotated_Fill 2
|
||||||
|
#define Annotated_FillMask 3
|
||||||
|
#define Annotated_FillMaskInv 4
|
||||||
#define Annotated_size 28
|
#define Annotated_size 28
|
||||||
|
|
||||||
AnnotatedRef Annotated_index(AnnotatedRef ref, uint index) {
|
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);
|
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) {
|
AnnoStroke AnnoStroke_read(AnnoStrokeRef ref) {
|
||||||
uint ix = ref.offset >> 2;
|
uint ix = ref.offset >> 2;
|
||||||
uint raw0 = annotated[ix + 0];
|
uint raw0 = annotated[ix + 0];
|
||||||
|
@ -103,6 +142,14 @@ AnnoFill Annotated_Fill_read(AnnotatedRef ref) {
|
||||||
return AnnoFill_read(AnnoFillRef(ref.offset + 4));
|
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) {
|
void Annotated_Nop_write(AnnotatedRef ref) {
|
||||||
annotated[ref.offset >> 2] = Annotated_Nop;
|
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);
|
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;
|
uint row_count = 0;
|
||||||
if (element_ix < n_elements) {
|
if (element_ix < n_elements) {
|
||||||
uint tag = Annotated_tag(ref);
|
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);
|
PathRef path_ref = PathRef(element_ix * Path_size);
|
||||||
Path path = Path_read(path_ref);
|
Path path = Path_read(path_ref);
|
||||||
sh_row_width[th_ix] = path.bbox.z - path.bbox.x;
|
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;
|
float my_right_edge = INFINITY;
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case Annotated_Fill:
|
case Annotated_Fill:
|
||||||
|
case Annotated_FillMask:
|
||||||
|
case Annotated_FillMaskInv:
|
||||||
case Annotated_Stroke:
|
case Annotated_Stroke:
|
||||||
// Note: we take advantage of the fact that fills and strokes
|
// Note: we take advantage of the fact that fills and strokes
|
||||||
// have compatible layout.
|
// have compatible layout.
|
||||||
|
|
Binary file not shown.
|
@ -173,6 +173,8 @@ void main() {
|
||||||
uint tile_count;
|
uint tile_count;
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case Annotated_Fill:
|
case Annotated_Fill:
|
||||||
|
case Annotated_FillMask:
|
||||||
|
case Annotated_FillMaskInv:
|
||||||
case Annotated_Stroke:
|
case Annotated_Stroke:
|
||||||
// Because the only elements we're processing right now are
|
// Because the only elements we're processing right now are
|
||||||
// paths, we can just use the element index as the path index.
|
// paths, we can just use the element index as the path index.
|
||||||
|
@ -222,12 +224,20 @@ void main() {
|
||||||
el_ix = probe;
|
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 seq_ix = ix - (el_ix > 0 ? sh_tile_count[el_ix - 1] : 0);
|
||||||
uint width = sh_tile_width[el_ix];
|
uint width = sh_tile_width[el_ix];
|
||||||
uint x = sh_tile_x0[el_ix] + seq_ix % width;
|
uint x = sh_tile_x0[el_ix] + seq_ix % width;
|
||||||
uint y = sh_tile_y0[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));
|
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_slice = el_ix / 32;
|
||||||
uint el_mask = 1 << (el_ix & 31);
|
uint el_mask = 1 << (el_ix & 31);
|
||||||
atomicOr(sh_bitmaps[el_slice][y * N_TILE_X + x], el_mask);
|
atomicOr(sh_bitmaps[el_slice][y * N_TILE_X + x], el_mask);
|
||||||
|
@ -281,6 +291,27 @@ void main() {
|
||||||
}
|
}
|
||||||
cmd_ref.offset += Cmd_size;
|
cmd_ref.offset += Cmd_size;
|
||||||
break;
|
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:
|
case Annotated_Stroke:
|
||||||
tile = Tile_read(TileRef(sh_tile_base[element_ref_ix]
|
tile = Tile_read(TileRef(sh_tile_base[element_ref_ix]
|
||||||
+ (sh_tile_stride[element_ref_ix] * tile_y + tile_x) * Tile_size));
|
+ (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;
|
c.pathseg_count = 1;
|
||||||
break;
|
break;
|
||||||
case Element_Fill:
|
case Element_Fill:
|
||||||
|
case Element_FillMask:
|
||||||
|
case Element_FillMaskInv:
|
||||||
is_fill = true;
|
is_fill = true;
|
||||||
// fall-through
|
// fall-through
|
||||||
case Element_Stroke:
|
case Element_Stroke:
|
||||||
|
@ -289,10 +291,6 @@ void main() {
|
||||||
for (uint i = 0; i < N_ROWS; i++) {
|
for (uint i = 0; i < N_ROWS; i++) {
|
||||||
State st = combine_state(row, th_state[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
|
// Here we read again from the original scene. There may be
|
||||||
// gains to be had from stashing in shared memory or possibly
|
// gains to be had from stashing in shared memory or possibly
|
||||||
// registers (though register pressure is an issue).
|
// registers (though register pressure is an issue).
|
||||||
|
@ -385,6 +383,23 @@ void main() {
|
||||||
out_ref = AnnotatedRef((st.path_count - 1) * Annotated_size);
|
out_ref = AnnotatedRef((st.path_count - 1) * Annotated_size);
|
||||||
Annotated_Fill_write(out_ref, anno_fill);
|
Annotated_Fill_write(out_ref, anno_fill);
|
||||||
break;
|
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 "ptcl.h"
|
||||||
#include "tile.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() {
|
void main() {
|
||||||
uint tile_ix = gl_WorkGroupID.y * WIDTH_IN_TILES + gl_WorkGroupID.x;
|
uint tile_ix = gl_WorkGroupID.y * WIDTH_IN_TILES + gl_WorkGroupID.x;
|
||||||
CmdRef cmd_ref = CmdRef(tile_ix * PTCL_INITIAL_ALLOC);
|
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);
|
uvec2 xy_uint = uvec2(gl_GlobalInvocationID.x, gl_LocalInvocationID.y + TILE_HEIGHT_PX * gl_WorkGroupID.y);
|
||||||
vec2 xy = vec2(xy_uint);
|
vec2 xy = vec2(xy_uint);
|
||||||
vec3 rgb[CHUNK];
|
vec3 rgb[CHUNK];
|
||||||
|
float mask[CHUNK];
|
||||||
for (uint i = 0; i < CHUNK; i++) {
|
for (uint i = 0; i < CHUNK; i++) {
|
||||||
rgb[i] = vec3(0.5);
|
rgb[i] = vec3(0.5);
|
||||||
|
mask[i] = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
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 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);
|
float alpha = clamp(0.5 + circle.radius - r, 0.0, 1.0);
|
||||||
// TODO: sRGB
|
// 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;
|
break;
|
||||||
case Cmd_Stroke:
|
case Cmd_Stroke:
|
||||||
|
@ -75,49 +111,43 @@ void main() {
|
||||||
fg_rgba = unpackUnorm4x8(stroke.rgba_color).wzyx;
|
fg_rgba = unpackUnorm4x8(stroke.rgba_color).wzyx;
|
||||||
for (uint k = 0; k < CHUNK; k++) {
|
for (uint k = 0; k < CHUNK; k++) {
|
||||||
float alpha = clamp(stroke.half_width + 0.5 - df[k], 0.0, 1.0);
|
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;
|
break;
|
||||||
case Cmd_Fill:
|
case Cmd_Fill:
|
||||||
// Calculate coverage based on backdrop + coverage of each line segment
|
|
||||||
CmdFill fill = Cmd_Fill_read(cmd_ref);
|
CmdFill fill = Cmd_Fill_read(cmd_ref);
|
||||||
// Probably better to store as float, but conversion is no doubt cheap.
|
|
||||||
float area[CHUNK];
|
float area[CHUNK];
|
||||||
for (uint k = 0; k < CHUNK; k++) area[k] = float(fill.backdrop);
|
area = computeArea(xy, fill.backdrop, fill.tile_ref);
|
||||||
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);
|
|
||||||
fg_rgba = unpackUnorm4x8(fill.rgba_color).wzyx;
|
fg_rgba = unpackUnorm4x8(fill.rgba_color).wzyx;
|
||||||
for (uint k = 0; k < CHUNK; k++) {
|
for (uint k = 0; k < CHUNK; k++) {
|
||||||
float alpha = min(abs(area[k]), 1.0);
|
rgb[k] = mix(rgb[k], fg_rgba.rgb, mask[k] * area[k] * fg_rgba.a);
|
||||||
rgb[k] = mix(rgb[k], fg_rgba.rgb, alpha * 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;
|
break;
|
||||||
case Cmd_Solid:
|
case Cmd_Solid:
|
||||||
CmdSolid solid = Cmd_Solid_read(cmd_ref);
|
CmdSolid solid = Cmd_Solid_read(cmd_ref);
|
||||||
fg_rgba = unpackUnorm4x8(solid.rgba_color).wzyx;
|
fg_rgba = unpackUnorm4x8(solid.rgba_color).wzyx;
|
||||||
for (uint k = 0; k < CHUNK; k++) {
|
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;
|
break;
|
||||||
case Cmd_Jump:
|
case Cmd_Jump:
|
||||||
|
|
Binary file not shown.
|
@ -16,10 +16,18 @@ struct CmdFillRef {
|
||||||
uint offset;
|
uint offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CmdFillMaskRef {
|
||||||
|
uint offset;
|
||||||
|
};
|
||||||
|
|
||||||
struct CmdSolidRef {
|
struct CmdSolidRef {
|
||||||
uint offset;
|
uint offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CmdSolidMaskRef {
|
||||||
|
uint offset;
|
||||||
|
};
|
||||||
|
|
||||||
struct CmdJumpRef {
|
struct CmdJumpRef {
|
||||||
uint offset;
|
uint offset;
|
||||||
};
|
};
|
||||||
|
@ -83,6 +91,18 @@ CmdFillRef CmdFill_index(CmdFillRef ref, uint index) {
|
||||||
return CmdFillRef(ref.offset + index * CmdFill_size);
|
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 {
|
struct CmdSolid {
|
||||||
uint rgba_color;
|
uint rgba_color;
|
||||||
};
|
};
|
||||||
|
@ -93,6 +113,16 @@ CmdSolidRef CmdSolid_index(CmdSolidRef ref, uint index) {
|
||||||
return CmdSolidRef(ref.offset + index * CmdSolid_size);
|
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 {
|
struct CmdJump {
|
||||||
uint new_ref;
|
uint new_ref;
|
||||||
};
|
};
|
||||||
|
@ -107,9 +137,12 @@ CmdJumpRef CmdJump_index(CmdJumpRef ref, uint index) {
|
||||||
#define Cmd_Circle 1
|
#define Cmd_Circle 1
|
||||||
#define Cmd_Line 2
|
#define Cmd_Line 2
|
||||||
#define Cmd_Fill 3
|
#define Cmd_Fill 3
|
||||||
#define Cmd_Stroke 4
|
#define Cmd_FillMask 4
|
||||||
#define Cmd_Solid 5
|
#define Cmd_FillMaskInv 5
|
||||||
#define Cmd_Jump 6
|
#define Cmd_Stroke 6
|
||||||
|
#define Cmd_Solid 7
|
||||||
|
#define Cmd_SolidMask 8
|
||||||
|
#define Cmd_Jump 9
|
||||||
#define Cmd_size 20
|
#define Cmd_size 20
|
||||||
|
|
||||||
CmdRef Cmd_index(CmdRef ref, uint index) {
|
CmdRef Cmd_index(CmdRef ref, uint index) {
|
||||||
|
@ -219,6 +252,25 @@ void CmdFill_write(CmdFillRef ref, CmdFill s) {
|
||||||
ptcl[ix + 2] = s.rgba_color;
|
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) {
|
CmdSolid CmdSolid_read(CmdSolidRef ref) {
|
||||||
uint ix = ref.offset >> 2;
|
uint ix = ref.offset >> 2;
|
||||||
uint raw0 = ptcl[ix + 0];
|
uint raw0 = ptcl[ix + 0];
|
||||||
|
@ -232,6 +284,19 @@ void CmdSolid_write(CmdSolidRef ref, CmdSolid s) {
|
||||||
ptcl[ix + 0] = s.rgba_color;
|
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) {
|
CmdJump CmdJump_read(CmdJumpRef ref) {
|
||||||
uint ix = ref.offset >> 2;
|
uint ix = ref.offset >> 2;
|
||||||
uint raw0 = ptcl[ix + 0];
|
uint raw0 = ptcl[ix + 0];
|
||||||
|
@ -261,6 +326,14 @@ CmdFill Cmd_Fill_read(CmdRef ref) {
|
||||||
return CmdFill_read(CmdFillRef(ref.offset + 4));
|
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) {
|
CmdStroke Cmd_Stroke_read(CmdRef ref) {
|
||||||
return CmdStroke_read(CmdStrokeRef(ref.offset + 4));
|
return CmdStroke_read(CmdStrokeRef(ref.offset + 4));
|
||||||
}
|
}
|
||||||
|
@ -269,6 +342,10 @@ CmdSolid Cmd_Solid_read(CmdRef ref) {
|
||||||
return CmdSolid_read(CmdSolidRef(ref.offset + 4));
|
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) {
|
CmdJump Cmd_Jump_read(CmdRef ref) {
|
||||||
return CmdJump_read(CmdJumpRef(ref.offset + 4));
|
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);
|
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) {
|
void Cmd_Stroke_write(CmdRef ref, CmdStroke s) {
|
||||||
ptcl[ref.offset >> 2] = Cmd_Stroke;
|
ptcl[ref.offset >> 2] = Cmd_Stroke;
|
||||||
CmdStroke_write(CmdStrokeRef(ref.offset + 4), s);
|
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);
|
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) {
|
void Cmd_Jump_write(CmdRef ref, CmdJump s) {
|
||||||
ptcl[ref.offset >> 2] = Cmd_Jump;
|
ptcl[ref.offset >> 2] = Cmd_Jump;
|
||||||
CmdJump_write(CmdJumpRef(ref.offset + 4), s);
|
CmdJump_write(CmdJumpRef(ref.offset + 4), s);
|
||||||
|
|
|
@ -16,6 +16,10 @@ struct FillRef {
|
||||||
uint offset;
|
uint offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FillMaskRef {
|
||||||
|
uint offset;
|
||||||
|
};
|
||||||
|
|
||||||
struct StrokeRef {
|
struct StrokeRef {
|
||||||
uint offset;
|
uint offset;
|
||||||
};
|
};
|
||||||
|
@ -78,6 +82,16 @@ FillRef Fill_index(FillRef ref, uint index) {
|
||||||
return FillRef(ref.offset + index * Fill_size);
|
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 {
|
struct Stroke {
|
||||||
uint rgba_color;
|
uint rgba_color;
|
||||||
};
|
};
|
||||||
|
@ -120,6 +134,8 @@ TransformRef Transform_index(TransformRef ref, uint index) {
|
||||||
#define Element_Fill 8
|
#define Element_Fill 8
|
||||||
#define Element_SetLineWidth 9
|
#define Element_SetLineWidth 9
|
||||||
#define Element_Transform 10
|
#define Element_Transform 10
|
||||||
|
#define Element_FillMask 11
|
||||||
|
#define Element_FillMaskInv 12
|
||||||
#define Element_size 36
|
#define Element_size 36
|
||||||
|
|
||||||
ElementRef Element_index(ElementRef ref, uint index) {
|
ElementRef Element_index(ElementRef ref, uint index) {
|
||||||
|
@ -179,6 +195,14 @@ Fill Fill_read(FillRef ref) {
|
||||||
return s;
|
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) {
|
Stroke Stroke_read(StrokeRef ref) {
|
||||||
uint ix = ref.offset >> 2;
|
uint ix = ref.offset >> 2;
|
||||||
uint raw0 = scene[ix + 0];
|
uint raw0 = scene[ix + 0];
|
||||||
|
@ -253,3 +277,11 @@ Transform Element_Transform_read(ElementRef ref) {
|
||||||
return Transform_read(TransformRef(ref.offset + 4));
|
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;
|
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case Annotated_Fill:
|
case Annotated_Fill:
|
||||||
|
case Annotated_FillMask:
|
||||||
|
case Annotated_FillMaskInv:
|
||||||
case Annotated_Stroke:
|
case Annotated_Stroke:
|
||||||
// Note: we take advantage of the fact that fills and strokes
|
// Note: we take advantage of the fact that fills and strokes
|
||||||
// have compatible layout.
|
// have compatible layout.
|
||||||
|
|
Binary file not shown.
Loading…
Reference in a new issue