mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-08 20:01:30 +11:00
Merge pull request #242 from linebender/evenodd
Support even-odd fill rule
This commit is contained in:
commit
a9aa3f9cab
|
@ -271,7 +271,16 @@ fn blend_square(blend: BlendMode) -> SceneFragment {
|
|||
|
||||
#[allow(unused)]
|
||||
pub fn render_anim_frame(sb: &mut SceneBuilder, text: &mut SimpleText, i: usize) {
|
||||
use PathEl::*;
|
||||
let rect = Rect::from_origin_size(Point::new(0.0, 0.0), (1000.0, 1000.0));
|
||||
let star = [
|
||||
MoveTo((50.0, 0.0).into()),
|
||||
LineTo((21.0, 90.0).into()),
|
||||
LineTo((98.0, 35.0).into()),
|
||||
LineTo((2.0, 35.0).into()),
|
||||
LineTo((79.0, 90.0).into()),
|
||||
ClosePath,
|
||||
];
|
||||
sb.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
|
@ -333,6 +342,20 @@ pub fn render_anim_frame(sb: &mut SceneBuilder, text: &mut SimpleText, i: usize)
|
|||
&rect,
|
||||
);
|
||||
sb.pop_layer();
|
||||
sb.fill(
|
||||
Fill::NonZero,
|
||||
Affine::translate((400.0, 100.0)),
|
||||
Color::PURPLE,
|
||||
None,
|
||||
&star,
|
||||
);
|
||||
sb.fill(
|
||||
Fill::EvenOdd,
|
||||
Affine::translate((500.0, 100.0)),
|
||||
Color::PURPLE,
|
||||
None,
|
||||
&star,
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
|
|
|
@ -79,17 +79,22 @@ fn alloc_cmd(size: u32) {
|
|||
}
|
||||
}
|
||||
|
||||
fn write_path(tile: Tile, linewidth: f32) {
|
||||
fn write_path(tile: Tile, linewidth: f32) -> bool {
|
||||
// TODO: take flags
|
||||
alloc_cmd(3u);
|
||||
if linewidth < 0.0 {
|
||||
let even_odd = linewidth < -1.0;
|
||||
if tile.segments != 0u {
|
||||
let fill = CmdFill(tile.segments, tile.backdrop);
|
||||
ptcl[cmd_offset] = CMD_FILL;
|
||||
ptcl[cmd_offset + 1u] = fill.tile;
|
||||
let segments_and_rule = select(fill.tile << 1u, (fill.tile << 1u) | 1u, even_odd);
|
||||
ptcl[cmd_offset + 1u] = segments_and_rule;
|
||||
ptcl[cmd_offset + 2u] = u32(fill.backdrop);
|
||||
cmd_offset += 3u;
|
||||
} else {
|
||||
if even_odd && (abs(tile.backdrop) & 1) == 0 {
|
||||
return false;
|
||||
}
|
||||
ptcl[cmd_offset] = CMD_SOLID;
|
||||
cmd_offset += 1u;
|
||||
}
|
||||
|
@ -100,6 +105,7 @@ fn write_path(tile: Tile, linewidth: f32) {
|
|||
ptcl[cmd_offset + 2u] = bitcast<u32>(stroke.half_width);
|
||||
cmd_offset += 3u;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn write_color(color: CmdColor) {
|
||||
|
@ -323,25 +329,28 @@ fn main(
|
|||
// DRAWTAG_FILL_COLOR
|
||||
case 0x44u: {
|
||||
let linewidth = bitcast<f32>(info_bin_data[di]);
|
||||
write_path(tile, linewidth);
|
||||
let rgba_color = scene[dd];
|
||||
write_color(CmdColor(rgba_color));
|
||||
if write_path(tile, linewidth) {
|
||||
let rgba_color = scene[dd];
|
||||
write_color(CmdColor(rgba_color));
|
||||
}
|
||||
}
|
||||
// DRAWTAG_FILL_LIN_GRADIENT
|
||||
case 0x114u: {
|
||||
let linewidth = bitcast<f32>(info_bin_data[di]);
|
||||
write_path(tile, linewidth);
|
||||
let index = scene[dd];
|
||||
let info_offset = di + 1u;
|
||||
write_grad(CMD_LIN_GRAD, index, info_offset);
|
||||
if write_path(tile, linewidth) {
|
||||
let index = scene[dd];
|
||||
let info_offset = di + 1u;
|
||||
write_grad(CMD_LIN_GRAD, index, info_offset);
|
||||
}
|
||||
}
|
||||
// DRAWTAG_FILL_RAD_GRADIENT
|
||||
case 0x2dcu: {
|
||||
let linewidth = bitcast<f32>(info_bin_data[di]);
|
||||
write_path(tile, linewidth);
|
||||
let index = scene[dd];
|
||||
let info_offset = di + 1u;
|
||||
write_grad(CMD_RAD_GRAD, index, info_offset);
|
||||
if write_path(tile, linewidth) {
|
||||
let index = scene[dd];
|
||||
let info_offset = di + 1u;
|
||||
write_grad(CMD_RAD_GRAD, index, info_offset);
|
||||
}
|
||||
}
|
||||
// DRAWTAG_BEGIN_CLIP
|
||||
case 0x9u: {
|
||||
|
|
|
@ -97,7 +97,7 @@ var output: texture_storage_2d<r8, write>;
|
|||
|
||||
let PIXELS_PER_THREAD = 4u;
|
||||
|
||||
fn fill_path(tile: Tile, xy: vec2<f32>) -> array<f32, PIXELS_PER_THREAD> {
|
||||
fn fill_path(tile: Tile, xy: vec2<f32>, even_odd: bool) -> array<f32, PIXELS_PER_THREAD> {
|
||||
var area: array<f32, PIXELS_PER_THREAD>;
|
||||
let backdrop_f = f32(tile.backdrop);
|
||||
for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) {
|
||||
|
@ -136,9 +136,17 @@ fn fill_path(tile: Tile, xy: vec2<f32>) -> array<f32, PIXELS_PER_THREAD> {
|
|||
}
|
||||
segment_ix = segment.next;
|
||||
}
|
||||
// nonzero winding rule
|
||||
for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) {
|
||||
area[i] = min(abs(area[i]), 1.0);
|
||||
if even_odd {
|
||||
// even-odd winding rule
|
||||
for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) {
|
||||
let a = abs(area[i]);
|
||||
area[i] = select(a, 2.0 - min(a, 2.0), a > 1.0);
|
||||
}
|
||||
} else {
|
||||
// non-zero winding rule
|
||||
for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) {
|
||||
area[i] = min(abs(area[i]), 1.0);
|
||||
}
|
||||
}
|
||||
return area;
|
||||
}
|
||||
|
@ -195,8 +203,10 @@ fn main(
|
|||
// CMD_FILL
|
||||
case 1u: {
|
||||
let fill = read_fill(cmd_ix);
|
||||
let tile = Tile(fill.backdrop, fill.tile);
|
||||
area = fill_path(tile, xy);
|
||||
let segments = fill.tile >> 1u;
|
||||
let even_odd = (fill.tile & 1u) != 0u;
|
||||
let tile = Tile(fill.backdrop, segments);
|
||||
area = fill_path(tile, xy, even_odd);
|
||||
cmd_ix += 3u;
|
||||
}
|
||||
// CMD_STROKE
|
||||
|
|
|
@ -126,7 +126,7 @@ impl<'a> SceneBuilder<'a> {
|
|||
/// Fills a shape using the specified style and brush.
|
||||
pub fn fill<'b>(
|
||||
&mut self,
|
||||
_style: Fill,
|
||||
style: Fill,
|
||||
transform: Affine,
|
||||
brush: impl Into<BrushRef<'b>>,
|
||||
brush_transform: Option<Affine>,
|
||||
|
@ -134,7 +134,10 @@ impl<'a> SceneBuilder<'a> {
|
|||
) {
|
||||
self.scene
|
||||
.encode_transform(Transform::from_kurbo(&transform));
|
||||
self.scene.encode_linewidth(-1.0);
|
||||
self.scene.encode_linewidth(match style {
|
||||
Fill::NonZero => -1.0,
|
||||
Fill::EvenOdd => -2.0,
|
||||
});
|
||||
if self.scene.encode_shape(shape, true) {
|
||||
if let Some(brush_transform) = brush_transform {
|
||||
self.scene
|
||||
|
|
Loading…
Reference in a new issue