mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 20:51:29 +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,
|
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 {
|
impl std::ops::Mul for Affine {
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
mod ramp_cache;
|
mod gradient;
|
||||||
|
|
||||||
use crate::brush::{Brush, Stop};
|
use crate::brush::{Brush, Stop};
|
||||||
use ramp_cache::RampCache;
|
use gradient::RampCache;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// Context for caching resources across rendering operations.
|
/// Context for caching resources across rendering operations.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ResourceContext {
|
pub struct ResourceContext {
|
||||||
ramp_cache: RampCache,
|
ramps: RampCache,
|
||||||
|
persistent_map: HashMap<u64, PersistentBrushData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResourceContext {
|
impl ResourceContext {
|
||||||
|
@ -15,14 +17,23 @@ impl ResourceContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn advance(&mut self) {
|
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 {
|
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 {
|
pub fn create_brush(&mut self, brush: &Brush) -> PersistentBrush {
|
||||||
|
match brush {
|
||||||
|
Brush::Persistent(dup) => return *dup,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
PersistentBrush { kind: 0, id: 0 }
|
PersistentBrush { kind: 0, id: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,3 +46,8 @@ pub struct PersistentBrush {
|
||||||
kind: u8,
|
kind: u8,
|
||||||
id: u64,
|
id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PersistentBrushData {
|
||||||
|
brush: Brush,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ use crate::resource::ResourceContext;
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
|
|
||||||
|
const MAX_BLEND_STACK: usize = 256;
|
||||||
|
|
||||||
/// Creates a new builder for constructing a scene.
|
/// Creates a new builder for constructing a scene.
|
||||||
pub fn build_scene<'a>(scene: &'a mut Scene, resources: &'a mut ResourceContext) -> Builder<'a> {
|
pub fn build_scene<'a>(scene: &'a mut Scene, resources: &'a mut ResourceContext) -> Builder<'a> {
|
||||||
Builder::new(&mut scene.data, ResourceData::Scene(resources))
|
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> {
|
pub struct Builder<'a> {
|
||||||
scene: &'a mut SceneData,
|
scene: &'a mut SceneData,
|
||||||
resources: ResourceData<'a>,
|
resources: ResourceData<'a>,
|
||||||
|
layers: Vec<Blend>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Builder<'a> {
|
impl<'a> Builder<'a> {
|
||||||
/// Creates a new builder for constructing a scene.
|
/// Creates a new builder for constructing a scene.
|
||||||
fn new(scene: &'a mut SceneData, resources: ResourceData<'a>) -> Self {
|
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.
|
/// Pushes a transform matrix onto the stack.
|
||||||
|
@ -60,12 +65,22 @@ impl<'a> Builder<'a> {
|
||||||
E::IntoIter: Clone,
|
E::IntoIter: Clone,
|
||||||
E::Item: Borrow<Element>,
|
E::Item: Borrow<Element>,
|
||||||
{
|
{
|
||||||
|
self.linewidth(-1.0);
|
||||||
let elements = elements.into_iter();
|
let elements = elements.into_iter();
|
||||||
self.encode_path(elements, true);
|
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.
|
/// 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.
|
/// Fills a shape using the specified style and brush.
|
||||||
pub fn fill<'s, E>(
|
pub fn fill<'s, E>(
|
||||||
|
@ -79,8 +94,17 @@ impl<'a> Builder<'a> {
|
||||||
E::IntoIter: Clone,
|
E::IntoIter: Clone,
|
||||||
E::Item: Borrow<Element>,
|
E::Item: Borrow<Element>,
|
||||||
{
|
{
|
||||||
|
self.linewidth(-1.0);
|
||||||
let elements = elements.into_iter();
|
let elements = elements.into_iter();
|
||||||
self.encode_path(elements, true);
|
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.
|
/// Strokes a shape using the specified style and brush.
|
||||||
|
@ -96,8 +120,17 @@ impl<'a> Builder<'a> {
|
||||||
E::IntoIter: Clone,
|
E::IntoIter: Clone,
|
||||||
E::Item: Borrow<Element>,
|
E::Item: Borrow<Element>,
|
||||||
{
|
{
|
||||||
|
self.linewidth(style.width);
|
||||||
let elements = elements.into_iter();
|
let elements = elements.into_iter();
|
||||||
self.encode_path(elements, false);
|
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.
|
/// Appends a fragment to the scene.
|
||||||
|
@ -140,8 +173,14 @@ impl<'a> Builder<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Completes construction and finalizes the underlying scene.
|
/// 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)
|
fn encode_path<E>(&mut self, elements: E, is_fill: bool)
|
||||||
where
|
where
|
||||||
E: Iterator,
|
E: Iterator,
|
||||||
|
@ -183,6 +222,24 @@ impl<'a> Builder<'a> {
|
||||||
self.scene.n_pathseg += n_pathseg;
|
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) {
|
fn encode_brush(&mut self, brush: &Brush) {
|
||||||
match brush {
|
match brush {
|
||||||
Brush::Solid(color) => {
|
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> {
|
enum ResourceData<'a> {
|
||||||
|
@ -244,6 +323,17 @@ enum ResourceData<'a> {
|
||||||
Scene(&'a mut ResourceContext),
|
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.
|
// Tags for draw objects. See shader/drawtag.h for the authoritative source.
|
||||||
const DRAWTAG_FILLCOLOR: u32 = 0x44;
|
const DRAWTAG_FILLCOLOR: u32 = 0x44;
|
||||||
const DRAWTAG_FILLLINGRADIENT: u32 = 0x114;
|
const DRAWTAG_FILLLINGRADIENT: u32 = 0x114;
|
||||||
|
|
Loading…
Reference in a new issue