mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 12:41:30 +11:00
Add layer encoding
This commit is contained in:
parent
753b97c342
commit
f8f91e4207
|
@ -115,6 +115,26 @@ impl Affine {
|
|||
y: point.y * self.yy + point.y * self.xy + self.dy,
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the determinant of this transform.
|
||||
pub fn determinant(self) -> f32 {
|
||||
self.xx * self.yy - self.yx * self.xy
|
||||
}
|
||||
|
||||
/// Compute the inverse transform.
|
||||
///
|
||||
/// Produces NaN values when the determinant is zero.
|
||||
pub fn inverse(self) -> Self {
|
||||
let inv_det = self.determinant().recip();
|
||||
Self::new(&[
|
||||
inv_det * self.yy,
|
||||
-inv_det * self.yx,
|
||||
-inv_det * self.xy,
|
||||
inv_det * self.xx,
|
||||
inv_det * (self.xy * self.dy - self.yy * self.dx),
|
||||
inv_det * (self.yx * self.dx - self.xx * self.dy),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Mul for Affine {
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
mod ramp_cache;
|
||||
mod gradient;
|
||||
|
||||
use crate::brush::{Brush, Stop};
|
||||
use ramp_cache::RampCache;
|
||||
use gradient::RampCache;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Context for caching resources across rendering operations.
|
||||
#[derive(Default)]
|
||||
pub struct ResourceContext {
|
||||
ramp_cache: RampCache,
|
||||
ramps: RampCache,
|
||||
persistent_map: HashMap<u64, PersistentBrushData>,
|
||||
}
|
||||
|
||||
impl ResourceContext {
|
||||
|
@ -15,14 +17,23 @@ impl ResourceContext {
|
|||
}
|
||||
|
||||
pub fn advance(&mut self) {
|
||||
self.ramp_cache.advance();
|
||||
self.ramps.advance();
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.ramps.clear();
|
||||
self.persistent_map.clear();
|
||||
}
|
||||
|
||||
pub fn add_ramp(&mut self, stops: &[Stop]) -> u32 {
|
||||
self.ramp_cache.add(stops)
|
||||
self.ramps.add(stops)
|
||||
}
|
||||
|
||||
pub fn create_brush(&mut self, brush: &Brush) -> PersistentBrush {
|
||||
match brush {
|
||||
Brush::Persistent(dup) => return *dup,
|
||||
_ => {}
|
||||
}
|
||||
PersistentBrush { kind: 0, id: 0 }
|
||||
}
|
||||
|
||||
|
@ -35,3 +46,8 @@ pub struct PersistentBrush {
|
|||
kind: u8,
|
||||
id: u64,
|
||||
}
|
||||
|
||||
struct PersistentBrushData {
|
||||
brush: Brush,
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ use crate::resource::ResourceContext;
|
|||
use bytemuck::{Pod, Zeroable};
|
||||
use core::borrow::Borrow;
|
||||
|
||||
const MAX_BLEND_STACK: usize = 256;
|
||||
|
||||
/// Creates a new builder for constructing a scene.
|
||||
pub fn build_scene<'a>(scene: &'a mut Scene, resources: &'a mut ResourceContext) -> Builder<'a> {
|
||||
Builder::new(&mut scene.data, ResourceData::Scene(resources))
|
||||
|
@ -38,12 +40,15 @@ pub fn build_fragment<'a>(fragment: &'a mut Fragment) -> Builder<'a> {
|
|||
pub struct Builder<'a> {
|
||||
scene: &'a mut SceneData,
|
||||
resources: ResourceData<'a>,
|
||||
layers: Vec<Blend>,
|
||||
}
|
||||
|
||||
impl<'a> Builder<'a> {
|
||||
/// Creates a new builder for constructing a scene.
|
||||
fn new(scene: &'a mut SceneData, resources: ResourceData<'a>) -> Self {
|
||||
Self { scene, resources }
|
||||
scene.clear();
|
||||
resources.clear();
|
||||
Self { scene, resources, layers: vec![] }
|
||||
}
|
||||
|
||||
/// Pushes a transform matrix onto the stack.
|
||||
|
@ -60,12 +65,22 @@ impl<'a> Builder<'a> {
|
|||
E::IntoIter: Clone,
|
||||
E::Item: Borrow<Element>,
|
||||
{
|
||||
self.linewidth(-1.0);
|
||||
let elements = elements.into_iter();
|
||||
self.encode_path(elements, true);
|
||||
self.begin_clip(Some(blend));
|
||||
if self.layers.len() >= MAX_BLEND_STACK {
|
||||
panic!("Maximum clip/blend stack size {} exceeded", MAX_BLEND_STACK);
|
||||
}
|
||||
self.layers.push(blend);
|
||||
}
|
||||
|
||||
/// Pops the current layer.
|
||||
pub fn pop_layer(&mut self) {}
|
||||
pub fn pop_layer(&mut self) {
|
||||
if let Some(layer) = self.layers.pop() {
|
||||
self.end_clip(Some(layer));
|
||||
}
|
||||
}
|
||||
|
||||
/// Fills a shape using the specified style and brush.
|
||||
pub fn fill<'s, E>(
|
||||
|
@ -79,8 +94,17 @@ impl<'a> Builder<'a> {
|
|||
E::IntoIter: Clone,
|
||||
E::Item: Borrow<Element>,
|
||||
{
|
||||
self.linewidth(-1.0);
|
||||
let elements = elements.into_iter();
|
||||
self.encode_path(elements, true);
|
||||
if let Some(brush_transform) = brush_transform {
|
||||
self.transform(brush_transform);
|
||||
self.swap_last_tags();
|
||||
self.encode_brush(brush);
|
||||
self.transform(brush_transform.inverse());
|
||||
} else {
|
||||
self.encode_brush(brush);
|
||||
}
|
||||
}
|
||||
|
||||
/// Strokes a shape using the specified style and brush.
|
||||
|
@ -96,8 +120,17 @@ impl<'a> Builder<'a> {
|
|||
E::IntoIter: Clone,
|
||||
E::Item: Borrow<Element>,
|
||||
{
|
||||
self.linewidth(style.width);
|
||||
let elements = elements.into_iter();
|
||||
self.encode_path(elements, false);
|
||||
if let Some(brush_transform) = brush_transform {
|
||||
self.transform(brush_transform);
|
||||
self.swap_last_tags();
|
||||
self.encode_brush(brush);
|
||||
self.transform(brush_transform.inverse());
|
||||
} else {
|
||||
self.encode_brush(brush);
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends a fragment to the scene.
|
||||
|
@ -140,8 +173,14 @@ impl<'a> Builder<'a> {
|
|||
}
|
||||
|
||||
/// Completes construction and finalizes the underlying scene.
|
||||
pub fn finish(self) {}
|
||||
pub fn finish(self) {
|
||||
while let Some(layer) = self.layers.pop() {
|
||||
self.end_clip(Some(layer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Builder<'a> {
|
||||
fn encode_path<E>(&mut self, elements: E, is_fill: bool)
|
||||
where
|
||||
E: Iterator,
|
||||
|
@ -183,6 +222,24 @@ impl<'a> Builder<'a> {
|
|||
self.scene.n_pathseg += n_pathseg;
|
||||
}
|
||||
|
||||
fn transform(&mut self, transform: Affine) {
|
||||
self.scene.tag_stream.push(0x20);
|
||||
self.scene.transform_stream.push(transform);
|
||||
}
|
||||
|
||||
// Swap the last two tags in the tag stream; used for transformed
|
||||
// gradients.
|
||||
fn swap_last_tags(&mut self) {
|
||||
let len = self.scene.tag_stream.len();
|
||||
self.scene.tag_stream.swap(len - 1, len - 2);
|
||||
}
|
||||
|
||||
// -1.0 means "fill"
|
||||
fn linewidth(&mut self, linewidth: f32) {
|
||||
self.scene.tag_stream.push(0x40);
|
||||
self.scene.linewidth_stream.push(linewidth);
|
||||
}
|
||||
|
||||
fn encode_brush(&mut self, brush: &Brush) {
|
||||
match brush {
|
||||
Brush::Solid(color) => {
|
||||
|
@ -237,6 +294,28 @@ impl<'a> Builder<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Start a clip.
|
||||
fn begin_clip(&mut self, blend: Option<Blend>) {
|
||||
self.scene.drawtag_stream.push(DRAWTAG_BEGINCLIP);
|
||||
let element = Clip {
|
||||
blend: blend.unwrap_or(Blend::default()).pack(),
|
||||
};
|
||||
self.scene.drawdata_stream.extend(bytemuck::bytes_of(&element));
|
||||
self.scene.n_clip += 1;
|
||||
}
|
||||
|
||||
fn end_clip(&mut self, blend: Option<Blend>) {
|
||||
self.scene.drawtag_stream.push(DRAWTAG_ENDCLIP);
|
||||
let element = Clip {
|
||||
blend: blend.unwrap_or(Blend::default()).pack(),
|
||||
};
|
||||
self.scene.drawdata_stream.extend(bytemuck::bytes_of(&element));
|
||||
// This is a dummy path, and will go away with the new clip impl.
|
||||
self.scene.tag_stream.push(0x10);
|
||||
self.scene.n_path += 1;
|
||||
self.scene.n_clip += 1;
|
||||
}
|
||||
}
|
||||
|
||||
enum ResourceData<'a> {
|
||||
|
@ -244,6 +323,17 @@ enum ResourceData<'a> {
|
|||
Scene(&'a mut ResourceContext),
|
||||
}
|
||||
|
||||
impl ResourceData<'_> {
|
||||
fn clear(&mut self) {
|
||||
match self {
|
||||
Self::Fragment(res) {
|
||||
res.patches.clear();
|
||||
res.stops.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tags for draw objects. See shader/drawtag.h for the authoritative source.
|
||||
const DRAWTAG_FILLCOLOR: u32 = 0x44;
|
||||
const DRAWTAG_FILLLINGRADIENT: u32 = 0x114;
|
||||
|
|
Loading…
Reference in a new issue