mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-09 20:31:29 +11:00
Address review feedback.
* remove area clamp in fine (now in #241) * make DrawTag::info_size() const fn * document DrawColor rgba field * change Monoid type parameter to an associated type and describe the additional Default constraint * consistent parens in PathTag::is_subpath_end * add comments for 32-bit path segment types in PathTag * also adds low level encoding functions for the three currently supported brushes
This commit is contained in:
parent
dbe7f27768
commit
520f6d0d41
|
@ -138,7 +138,7 @@ fn fill_path(tile: Tile, xy: vec2<f32>) -> array<f32, PIXELS_PER_THREAD> {
|
|||
}
|
||||
// nonzero winding rule
|
||||
for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) {
|
||||
area[i] = min(abs(area[i]), 1.0);
|
||||
area[i] = abs(area[i]);
|
||||
}
|
||||
return area;
|
||||
}
|
||||
|
|
|
@ -48,8 +48,8 @@ impl DrawTag {
|
|||
}
|
||||
|
||||
impl DrawTag {
|
||||
/// Returns the size of the info buffer used by this tag.
|
||||
pub fn info_size(self) -> u32 {
|
||||
/// Returns the size of the info buffer (in u32s) used by this tag.
|
||||
pub const fn info_size(self) -> u32 {
|
||||
(self.0 >> 6) & 0xf
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,8 @@ impl DrawTag {
|
|||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct DrawColor {
|
||||
/// Packed RGBA color.
|
||||
/// Packed little endian RGBA premultiplied color with the alpha component
|
||||
/// in the low byte.
|
||||
pub rgba: u32,
|
||||
}
|
||||
|
||||
|
@ -143,7 +144,9 @@ pub struct DrawMonoid {
|
|||
pub info_offset: u32,
|
||||
}
|
||||
|
||||
impl Monoid<DrawTag> for DrawMonoid {
|
||||
impl Monoid for DrawMonoid {
|
||||
type SourceValue = DrawTag;
|
||||
|
||||
fn new(tag: DrawTag) -> Self {
|
||||
Self {
|
||||
path_ix: (tag != DrawTag::NOP) as u32,
|
||||
|
|
|
@ -15,9 +15,11 @@
|
|||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
use super::resource::Patch;
|
||||
use super::{DrawTag, PathEncoder, PathTag, Transform};
|
||||
use super::{
|
||||
DrawColor, DrawLinearGradient, DrawRadialGradient, DrawTag, PathEncoder, PathTag, Transform,
|
||||
};
|
||||
|
||||
use peniko::{kurbo::Shape, BlendMode, BrushRef, Color, ColorStop};
|
||||
use peniko::{kurbo::Shape, BlendMode, BrushRef, Color, ColorStop, Extend};
|
||||
|
||||
/// Encoded data streams for a scene.
|
||||
#[derive(Default)]
|
||||
|
@ -148,44 +150,79 @@ impl Encoding {
|
|||
/// Encodes a brush with an optional alpha modifier.
|
||||
pub fn encode_brush<'b>(&mut self, brush: impl Into<BrushRef<'b>>, alpha: f32) {
|
||||
use super::math::point_to_f32;
|
||||
use super::{DrawColor, DrawLinearGradient, DrawRadialGradient};
|
||||
match brush.into() {
|
||||
BrushRef::Solid(color) => {
|
||||
self.draw_tags.push(DrawTag::COLOR);
|
||||
let color = if alpha != 1.0 {
|
||||
color_with_alpha(color, alpha)
|
||||
} else {
|
||||
color
|
||||
};
|
||||
self.draw_data
|
||||
.extend_from_slice(bytemuck::bytes_of(&DrawColor::new(color)));
|
||||
self.encode_color(DrawColor::new(color));
|
||||
}
|
||||
BrushRef::LinearGradient(gradient) => {
|
||||
self.add_ramp(&gradient.stops, alpha);
|
||||
self.draw_tags.push(DrawTag::LINEAR_GRADIENT);
|
||||
self.draw_data
|
||||
.extend_from_slice(bytemuck::bytes_of(&DrawLinearGradient {
|
||||
self.encode_linear_gradient(
|
||||
DrawLinearGradient {
|
||||
index: 0,
|
||||
p0: point_to_f32(gradient.start),
|
||||
p1: point_to_f32(gradient.end),
|
||||
}));
|
||||
},
|
||||
gradient.stops.iter().copied(),
|
||||
alpha,
|
||||
gradient.extend,
|
||||
);
|
||||
}
|
||||
BrushRef::RadialGradient(gradient) => {
|
||||
self.add_ramp(&gradient.stops, alpha);
|
||||
self.draw_tags.push(DrawTag::RADIAL_GRADIENT);
|
||||
self.draw_data
|
||||
.extend_from_slice(bytemuck::bytes_of(&DrawRadialGradient {
|
||||
self.encode_radial_gradient(
|
||||
DrawRadialGradient {
|
||||
index: 0,
|
||||
p0: point_to_f32(gradient.start_center),
|
||||
p1: point_to_f32(gradient.end_center),
|
||||
r0: gradient.start_radius,
|
||||
r1: gradient.end_radius,
|
||||
}));
|
||||
},
|
||||
gradient.stops.iter().copied(),
|
||||
alpha,
|
||||
gradient.extend,
|
||||
);
|
||||
}
|
||||
BrushRef::SweepGradient(_gradient) => todo!("sweep gradients aren't done yet!"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes a solid color brush.
|
||||
pub fn encode_color(&mut self, color: DrawColor) {
|
||||
self.draw_tags.push(DrawTag::COLOR);
|
||||
self.draw_data.extend_from_slice(bytemuck::bytes_of(&color));
|
||||
}
|
||||
|
||||
/// Encodes a linear gradient brush.
|
||||
pub fn encode_linear_gradient(
|
||||
&mut self,
|
||||
gradient: DrawLinearGradient,
|
||||
color_stops: impl Iterator<Item = ColorStop>,
|
||||
alpha: f32,
|
||||
_extend: Extend,
|
||||
) {
|
||||
self.add_ramp(color_stops, alpha);
|
||||
self.draw_tags.push(DrawTag::LINEAR_GRADIENT);
|
||||
self.draw_data
|
||||
.extend_from_slice(bytemuck::bytes_of(&gradient));
|
||||
}
|
||||
|
||||
/// Encodes a radial gradient brush.
|
||||
pub fn encode_radial_gradient(
|
||||
&mut self,
|
||||
gradient: DrawRadialGradient,
|
||||
color_stops: impl Iterator<Item = ColorStop>,
|
||||
alpha: f32,
|
||||
_extend: Extend,
|
||||
) {
|
||||
self.add_ramp(color_stops, alpha);
|
||||
self.draw_tags.push(DrawTag::RADIAL_GRADIENT);
|
||||
self.draw_data
|
||||
.extend_from_slice(bytemuck::bytes_of(&gradient));
|
||||
}
|
||||
|
||||
/// Encodes a begin clip command.
|
||||
pub fn encode_begin_clip(&mut self, blend_mode: BlendMode, alpha: f32) {
|
||||
use super::DrawBeginClip;
|
||||
|
@ -211,16 +248,16 @@ impl Encoding {
|
|||
self.path_tags.swap(len - 1, len - 2);
|
||||
}
|
||||
|
||||
fn add_ramp(&mut self, stops: &[ColorStop], alpha: f32) {
|
||||
fn add_ramp(&mut self, color_stops: impl Iterator<Item = ColorStop>, alpha: f32) {
|
||||
let offset = self.draw_data.len();
|
||||
let stops_start = self.color_stops.len();
|
||||
if alpha != 1.0 {
|
||||
self.color_stops.extend(stops.iter().map(|s| ColorStop {
|
||||
self.color_stops.extend(color_stops.map(|s| ColorStop {
|
||||
offset: s.offset,
|
||||
color: color_with_alpha(s.color, alpha),
|
||||
}));
|
||||
} else {
|
||||
self.color_stops.extend_from_slice(stops);
|
||||
self.color_stops.extend(color_stops);
|
||||
}
|
||||
self.patches.push(Patch::Ramp {
|
||||
offset,
|
||||
|
|
|
@ -14,10 +14,15 @@
|
|||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
/// Interface for a monoid.
|
||||
pub trait Monoid<T>: Default {
|
||||
/// Interface for a monoid. The default value must be the identity of
|
||||
/// the monoid.
|
||||
pub trait Monoid: Default {
|
||||
/// The source value for constructing the monoid.
|
||||
type SourceValue;
|
||||
|
||||
/// Creates a monoid from a given value.
|
||||
fn new(value: T) -> Self;
|
||||
fn new(value: Self::SourceValue) -> Self;
|
||||
|
||||
/// Combines two monoids. This operation must be associative.
|
||||
fn combine(&self, other: &Self) -> Self;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@ pub struct PathSegment {
|
|||
}
|
||||
|
||||
/// Path segment type.
|
||||
///
|
||||
/// The values of the segment types are equivalent to the number of associated
|
||||
/// points for each segment in the path data stream.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Pod, Zeroable)]
|
||||
#[repr(C)]
|
||||
pub struct PathSegmentType(pub u8);
|
||||
|
@ -52,12 +55,18 @@ pub struct PathTag(pub u8);
|
|||
|
||||
impl PathTag {
|
||||
/// 32-bit floating point line segment.
|
||||
///
|
||||
/// This is equivalent to (PathSegmentType::LINE_TO | PathTag::F32_BIT).
|
||||
pub const LINE_TO_F32: Self = Self(0x9);
|
||||
|
||||
/// 32-bit floating point quadratic segment.
|
||||
///
|
||||
/// This is equivalent to (PathSegmentType::QUAD_TO | PathTag::F32_BIT).
|
||||
pub const QUAD_TO_F32: Self = Self(0xa);
|
||||
|
||||
/// 32-bit floating point cubic segment.
|
||||
///
|
||||
/// This is equivalent to (PathSegmentType::CUBIC_TO | PathTag::F32_BIT).
|
||||
pub const CUBIC_TO_F32: Self = Self(0xb);
|
||||
|
||||
/// 16-bit integral line segment.
|
||||
|
@ -78,8 +87,14 @@ impl PathTag {
|
|||
/// Line width setting.
|
||||
pub const LINEWIDTH: Self = Self(0x40);
|
||||
|
||||
/// Bit for path segments that are represented as f32 values. If unset
|
||||
/// they are represented as i16.
|
||||
const F32_BIT: u8 = 0x8;
|
||||
|
||||
/// Bit that marks a segment that is the end of a subpath.
|
||||
const SUBPATH_END_BIT: u8 = 0x4;
|
||||
|
||||
/// Mask for bottom 3 bits that contain the [PathSegmentType].
|
||||
const SEGMENT_MASK: u8 = 0x3;
|
||||
|
||||
/// Returns true if the tag is a segment.
|
||||
|
@ -94,7 +109,7 @@ impl PathTag {
|
|||
|
||||
/// Returns true if this segment ends a subpath.
|
||||
pub fn is_subpath_end(self) -> bool {
|
||||
(self.0 & Self::SUBPATH_END_BIT) != 0
|
||||
self.0 & Self::SUBPATH_END_BIT != 0
|
||||
}
|
||||
|
||||
/// Sets the subpath end bit.
|
||||
|
@ -124,7 +139,9 @@ pub struct PathMonoid {
|
|||
pub path_ix: u32,
|
||||
}
|
||||
|
||||
impl Monoid<u32> for PathMonoid {
|
||||
impl Monoid for PathMonoid {
|
||||
type SourceValue = u32;
|
||||
|
||||
/// Reduces a packed 32-bit word containing 4 tags.
|
||||
fn new(tag_word: u32) -> Self {
|
||||
let mut c = Self::default();
|
||||
|
|
Loading…
Reference in a new issue