diff --git a/pgpu-render/src/render.rs b/pgpu-render/src/render.rs index bbea802..591fdeb 100644 --- a/pgpu-render/src/render.rs +++ b/pgpu-render/src/render.rs @@ -18,7 +18,7 @@ use piet_gpu::{PixelFormat, RenderConfig}; use piet_gpu_hal::{QueryPool, Session}; use piet_scene::glyph::pinot::{types::Tag, FontDataRef}; use piet_scene::glyph::{GlyphContext, GlyphProvider}; -use piet_scene::{Affine, Rect, ResourceContext, Scene, SceneFragment}; +use piet_scene::{Affine, Rect, Scene, SceneFragment}; /// State and resources for rendering a scene. pub struct PgpuRenderer { @@ -105,23 +105,17 @@ impl PgpuRenderer { /// Encoded streams and resources describing a vector graphics scene. pub struct PgpuScene { scene: Scene, - rcx: ResourceContext, } impl PgpuScene { pub fn new() -> Self { Self { scene: Scene::default(), - rcx: ResourceContext::new(), } } pub fn builder(&mut self) -> PgpuSceneBuilder { - self.rcx.advance(); - PgpuSceneBuilder(piet_scene::SceneBuilder::for_scene( - &mut self.scene, - &mut self.rcx, - )) + PgpuSceneBuilder(piet_scene::SceneBuilder::for_scene(&mut self.scene)) } } diff --git a/piet-gpu/bin/android.rs b/piet-gpu/bin/android.rs index cf5db9d..d94b77f 100644 --- a/piet-gpu/bin/android.rs +++ b/piet-gpu/bin/android.rs @@ -18,7 +18,7 @@ use piet_gpu_hal::{ }; use piet_gpu::{samples, RenderDriver, Renderer, SimpleText}; -use piet_scene::{ResourceContext, Scene, SceneBuilder}; +use piet_scene::{Scene, SceneBuilder}; #[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))] fn main() { @@ -134,13 +134,12 @@ impl GfxState { } let mut text = SimpleText::new(); let mut scene = Scene::default(); - let mut rcx = ResourceContext::default(); - let mut builder = SceneBuilder::for_scene(&mut scene, &mut rcx); + let mut builder = SceneBuilder::for_scene(&mut scene); samples::render_anim_frame(&mut builder, self.current_frame); //samples::render_tiger(&mut builder, false); render_info(&mut text, &mut builder, &info_string); builder.finish(); - if let Err(e) = self.render_driver.upload_scene(&self.session, &scene, &rcx) { + if let Err(e) = self.render_driver.upload_scene(&self.session, &scene) { println!("error in uploading: {}", e); } let (image_idx, acquisition_semaphore) = self.swapchain.next().unwrap(); diff --git a/piet-gpu/bin/cli.rs b/piet-gpu/bin/cli.rs index 632fa74..4e52542 100644 --- a/piet-gpu/bin/cli.rs +++ b/piet-gpu/bin/cli.rs @@ -7,7 +7,7 @@ use clap::{App, Arg}; use piet_gpu_hal::{BufferUsage, Error, Instance, InstanceFlags, Session}; use piet_gpu::{samples, PicoSvg, RenderDriver, Renderer}; -use piet_scene::{ResourceContext, Scene, SceneBuilder}; +use piet_scene::{Scene, SceneBuilder}; const WIDTH: usize = 2048; const HEIGHT: usize = 1536; @@ -229,12 +229,10 @@ fn main() -> Result<(), Error> { .get_matches(); let instance = Instance::new(InstanceFlags::default())?; let mut scene = Scene::default(); - let mut rcx = ResourceContext::default(); unsafe { let device = instance.device()?; let session = Session::new(device); - rcx.advance(); - let mut builder = SceneBuilder::for_scene(&mut scene, &mut rcx); + let mut builder = SceneBuilder::for_scene(&mut scene); if let Some(input) = matches.value_of("INPUT") { let mut scale = matches .value_of("scale") @@ -257,7 +255,7 @@ fn main() -> Result<(), Error> { let renderer = Renderer::new(&session, WIDTH, HEIGHT, 1)?; let mut render_driver = RenderDriver::new(&session, 1, renderer); let start = std::time::Instant::now(); - render_driver.upload_scene(&session, &scene, &rcx)?; + render_driver.upload_scene(&session, &scene)?; let image_usage = BufferUsage::MAP_READ | BufferUsage::COPY_DST; let image_buf = session.create_buffer((WIDTH * HEIGHT * 4) as u64, image_usage)?; diff --git a/piet-gpu/bin/winit.rs b/piet-gpu/bin/winit.rs index 92fc35d..94a2237 100644 --- a/piet-gpu/bin/winit.rs +++ b/piet-gpu/bin/winit.rs @@ -1,6 +1,6 @@ use piet_gpu::{samples, PicoSvg, RenderDriver, Renderer, SimpleText}; use piet_gpu_hal::{Error, ImageLayout, Instance, InstanceFlags, Session}; -use piet_scene::{ResourceContext, Scene, SceneBuilder}; +use piet_scene::{Scene, SceneBuilder}; use clap::{App, Arg}; @@ -58,7 +58,6 @@ fn main() -> Result<(), Error> { let instance = Instance::new(InstanceFlags::default())?; let mut info_string = "info".to_string(); let mut scene = Scene::default(); - let mut rcx = ResourceContext::default(); let mut simple_text = piet_gpu::SimpleText::new(); unsafe { let surface = instance.surface(&window)?; @@ -113,17 +112,15 @@ fn main() -> Result<(), Error> { } if let Some(svg) = &svg { - rcx.advance(); - let mut builder = SceneBuilder::for_scene(&mut scene, &mut rcx); + let mut builder = SceneBuilder::for_scene(&mut scene); samples::render_svg(&mut builder, svg, false); render_info(&mut simple_text, &mut builder, &info_string); builder.finish(); - if let Err(e) = render_driver.upload_scene(&session, &scene, &rcx) { + if let Err(e) = render_driver.upload_scene(&session, &scene) { println!("error in uploading: {}", e); } } else { - rcx.advance(); - let mut builder = SceneBuilder::for_scene(&mut scene, &mut rcx); + let mut builder = SceneBuilder::for_scene(&mut scene); const N_SAMPLES: usize = 4; match sample_index % N_SAMPLES { @@ -138,7 +135,7 @@ fn main() -> Result<(), Error> { } render_info(&mut simple_text, &mut builder, &info_string); builder.finish(); - if let Err(e) = render_driver.upload_scene(&session, &scene, &rcx) { + if let Err(e) = render_driver.upload_scene(&session, &scene) { println!("error in uploading: {}", e); } } diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index a3d86b2..b2dfffb 100644 --- a/piet-gpu/src/lib.rs +++ b/piet-gpu/src/lib.rs @@ -1,4 +1,5 @@ mod pico_svg; +mod ramp; mod render_driver; pub mod samples; mod simple_text; @@ -7,6 +8,7 @@ pub mod stages; pub use piet_scene as scene; use bytemuck::{Pod, Zeroable}; +use scene::ResourcePatch; use std::convert::TryInto; pub use render_driver::RenderDriver; @@ -17,7 +19,7 @@ use piet_gpu_hal::{ DescriptorSet, Error, Image, ImageLayout, Pipeline, QueryPool, Session, }; -use piet_scene::{ResourceContext, Scene}; +use piet_scene::Scene; pub use pico_svg::PicoSvg; use stages::{ClipBinding, ElementBinding, ElementCode, DRAW_PART_SIZE, PATHSEG_PART_SIZE}; @@ -154,6 +156,9 @@ pub struct Renderer { gradient_bufs: Vec, gradients: Image, + + ramps: ramp::RampCache, + drawdata_patches: Vec<(usize, u32)>, } impl RenderConfig { @@ -364,6 +369,9 @@ impl Renderer { .build(&session, &k4_pipeline)?; let scene_stats = Default::default(); + let ramps = ramp::RampCache::default(); + let drawdata_patches = vec![]; + Ok(Renderer { width, height, @@ -403,26 +411,34 @@ impl Renderer { _bg_image: bg_image, gradient_bufs, gradients, + ramps, + drawdata_patches, }) } - pub fn upload_scene( - &mut self, - scene: &Scene, - rcx: &ResourceContext, - buf_ix: usize, - ) -> Result<(), Error> { + pub fn upload_scene(&mut self, scene: &Scene, buf_ix: usize) -> Result<(), Error> { + self.drawdata_patches.clear(); self.scene_stats = SceneStats::from_scene(scene); - + self.ramps.advance(); + let data = scene.data(); + let stop_data = &data.resources.stops; + for patch in &data.resources.patches { + match patch { + ResourcePatch::Ramp { offset, stops } => { + let ramp_id = self.ramps.add(&stop_data[stops.clone()]); + self.drawdata_patches.push((*offset, ramp_id)); + } + } + } unsafe { self.upload_config(buf_ix)?; { let mut mapped_scene = self.scene_bufs[buf_ix].map_write(..)?; - write_scene(scene, &mut mapped_scene); + write_scene(scene, &self.drawdata_patches, &mut mapped_scene); } // Upload gradient data. - let ramp_data = rcx.ramp_data(); + let ramp_data = self.ramps.data(); if !ramp_data.is_empty() { assert!( self.gradient_bufs[buf_ix].size() as usize @@ -870,12 +886,28 @@ impl SceneStats { } } -fn write_scene(scene: &Scene, buf: &mut BufWrite) { +fn write_scene(scene: &Scene, drawdata_patches: &[(usize, u32)], buf: &mut BufWrite) { let data = scene.data(); buf.extend_slice(&data.drawtag_stream); let n_drawobj = data.drawtag_stream.len(); buf.fill_zero(padding(n_drawobj, DRAW_PART_SIZE as usize) * DRAWTAG_SIZE); - buf.extend_slice(&data.drawdata_stream); + if !drawdata_patches.is_empty() { + let mut pos = 0; + for patch in drawdata_patches { + let offset = patch.0; + let value = patch.1; + if pos < offset { + buf.extend_slice(&data.drawdata_stream[pos..offset]); + } + buf.push(value); + pos = offset + 4; + } + if pos < data.drawdata_stream.len() { + buf.extend_slice(&data.drawdata_stream[pos..]) + } + } else { + buf.extend_slice(&data.drawdata_stream); + } buf.extend_slice(&data.transform_stream); buf.extend_slice(&data.linewidth_stream); buf.extend_slice(&data.tag_stream); diff --git a/piet-scene/src/resource/gradient.rs b/piet-gpu/src/ramp.rs similarity index 95% rename from piet-scene/src/resource/gradient.rs rename to piet-gpu/src/ramp.rs index 8a23216..8e4ca19 100644 --- a/piet-scene/src/resource/gradient.rs +++ b/piet-gpu/src/ramp.rs @@ -1,4 +1,5 @@ -use crate::brush::{Color, GradientStop, GradientStops}; +use piet_scene::{Color, GradientStop, GradientStops}; + use std::collections::HashMap; const N_SAMPLES: usize = 512; @@ -21,12 +22,6 @@ impl RampCache { } } - pub fn clear(&mut self) { - self.epoch = 0; - self.map.clear(); - self.data.clear(); - } - pub fn add(&mut self, stops: &[GradientStop]) -> u32 { if let Some(entry) = self.map.get_mut(stops) { entry.1 = self.epoch; diff --git a/piet-gpu/src/render_driver.rs b/piet-gpu/src/render_driver.rs index afeec5e..c4d8043 100644 --- a/piet-gpu/src/render_driver.rs +++ b/piet-gpu/src/render_driver.rs @@ -15,7 +15,7 @@ // Also licensed under MIT license, at your choice. use piet_gpu_hal::{CmdBuf, Error, Image, QueryPool, Semaphore, Session, SubmittedCmdBuf}; -use piet_scene::{ResourceContext, Scene}; +use piet_scene::Scene; use crate::{MemoryHeader, Renderer, SceneStats}; @@ -86,15 +86,10 @@ impl RenderDriver { } } - pub fn upload_scene( - &mut self, - session: &Session, - scene: &Scene, - rcx: &ResourceContext, - ) -> Result<(), Error> { + pub fn upload_scene(&mut self, session: &Session, scene: &Scene) -> Result<(), Error> { let stats = SceneStats::from_scene(scene); self.ensure_scene_buffers(session, &stats)?; - self.renderer.upload_scene(scene, rcx, self.buf_ix) + self.renderer.upload_scene(scene, self.buf_ix) } fn ensure_scene_buffers(&mut self, session: &Session, stats: &SceneStats) -> Result<(), Error> { diff --git a/piet-gpu/src/samples.rs b/piet-gpu/src/samples.rs index b3b4b8b..a04f95b 100644 --- a/piet-gpu/src/samples.rs +++ b/piet-gpu/src/samples.rs @@ -168,7 +168,10 @@ pub fn render_blend_grid(sb: &mut SceneBuilder) { let i = ix % 4; let j = ix / 4; let transform = Affine::translate(i as f32 * 225., j as f32 * 225.); - render_blend_square(sb, blend.into(), transform); + let square = blend_square(blend.into()); + sb.append(&square, Some(transform)); + // sb.append(&square, Some(transform)); + // render_blend_square(sb, blend.into(), transform); } } @@ -265,6 +268,101 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin sb.pop_layer(); } +#[allow(unused)] +fn blend_square(blend: BlendMode) -> SceneFragment { + let mut fragment = SceneFragment::default(); + let mut sb = SceneBuilder::for_fragment(&mut fragment); + // Inspired by https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode + let rect = Rect::from_origin_size(Point::new(0., 0.), 200., 200.); + let stops = &[ + GradientStop { + color: Color::rgb8(0, 0, 0), + offset: 0.0, + }, + GradientStop { + color: Color::rgb8(255, 255, 255), + offset: 1.0, + }, + ][..]; + let linear = Brush::LinearGradient(LinearGradient { + start: Point::new(0.0, 0.0), + end: Point::new(200.0, 0.0), + stops: stops.into(), + extend: ExtendMode::Pad, + }); + sb.fill(Fill::NonZero, &linear, None, rect.elements()); + const GRADIENTS: &[(f32, f32, Color)] = &[ + (150., 0., Color::rgb8(64, 240, 255)), + (175., 100., Color::rgb8(240, 96, 255)), + (125., 200., Color::rgb8(255, 192, 64)), + ]; + for (x, y, c) in GRADIENTS { + let mut color2 = c.clone(); + color2.a = 0; + let stops = &[ + GradientStop { + color: c.clone(), + offset: 0.0, + }, + GradientStop { + color: color2, + offset: 1.0, + }, + ][..]; + let rad = Brush::RadialGradient(RadialGradient { + center0: Point::new(*x, *y), + center1: Point::new(*x, *y), + radius0: 0.0, + radius1: 100.0, + stops: stops.into(), + extend: ExtendMode::Pad, + }); + sb.fill(Fill::NonZero, &rad, None, rect.elements()); + } + const COLORS: &[Color] = &[ + Color::rgb8(0, 0, 255), + Color::rgb8(0, 255, 0), + Color::rgb8(255, 0, 0), + ]; + sb.push_layer(Mix::Normal.into(), rect.elements()); + for (i, c) in COLORS.iter().enumerate() { + let stops = &[ + GradientStop { + color: Color::rgb8(255, 255, 255), + offset: 0.0, + }, + GradientStop { + color: c.clone(), + offset: 1.0, + }, + ][..]; + let linear = Brush::LinearGradient(LinearGradient { + start: Point::new(0.0, 0.0), + end: Point::new(0.0, 200.0), + stops: stops.into(), + extend: ExtendMode::Pad, + }); + sb.transform(Affine::IDENTITY); + sb.push_layer(blend, rect.elements()); + // squash the ellipse + let a = Affine::translate(100., 100.) + * Affine::rotate(std::f32::consts::FRAC_PI_3 * (i * 2 + 1) as f32) + * Affine::scale(1.0, 0.357) + * Affine::translate(-100., -100.); + sb.transform(a); + sb.fill( + Fill::NonZero, + &linear, + None, + make_ellipse(100., 100., 90., 90.), + ); + sb.pop_layer(); + } + sb.pop_layer(); + sb.finish(); + fragment +} + #[allow(unused)] pub fn render_anim_frame(sb: &mut SceneBuilder, text: &mut SimpleText, i: usize) { sb.fill( diff --git a/piet-scene/src/resource.rs b/piet-scene/src/resource.rs new file mode 100644 index 0000000..7069304 --- /dev/null +++ b/piet-scene/src/resource.rs @@ -0,0 +1,31 @@ +use crate::brush::GradientStop; +use core::ops::Range; + +#[derive(Default)] +/// Collection of late bound resources for a scene or scene fragment. +pub struct ResourceBundle { + /// Sequence of resource patches. + pub patches: Vec, + /// Cache of gradient stops, referenced by range from the patches. + pub stops: Vec, +} + +impl ResourceBundle { + /// Clears the resource set. + pub(crate) fn clear(&mut self) { + self.patches.clear(); + self.stops.clear(); + } +} + +#[derive(Clone)] +/// Description of a late bound resource. +pub enum ResourcePatch { + /// Gradient ramp resource. + Ramp { + /// Byte offset to the ramp id in the draw data stream. + offset: usize, + /// Range of the gradient stops in the resource set. + stops: Range, + }, +} diff --git a/piet-scene/src/resource/mod.rs b/piet-scene/src/resource/mod.rs deleted file mode 100644 index 2e6b2d6..0000000 --- a/piet-scene/src/resource/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -mod gradient; - -use crate::brush::GradientStop; -use gradient::RampCache; - -/// Context for caching resources across rendering operations. -#[derive(Default)] -pub struct ResourceContext { - ramps: RampCache, -} - -impl ResourceContext { - pub fn new() -> Self { - Self::default() - } - - pub fn advance(&mut self) { - self.ramps.advance(); - } - - pub fn clear(&mut self) { - self.ramps.clear(); - } - - pub fn add_ramp(&mut self, stops: &[GradientStop]) -> u32 { - self.ramps.add(stops) - } - - pub fn ramp_data(&self) -> &[u32] { - &self.ramps.data() - } -} diff --git a/piet-scene/src/scene/builder.rs b/piet-scene/src/scene/builder.rs index 37befac..d7c8b03 100644 --- a/piet-scene/src/scene/builder.rs +++ b/piet-scene/src/scene/builder.rs @@ -15,12 +15,8 @@ // Also licensed under MIT license, at your choice. use super::style::{Fill, Stroke}; -use super::{ - Affine, BlendMode, FragmentResources, PathElement, ResourcePatch, Scene, SceneData, - SceneFragment, -}; -use crate::brush::*; -use crate::resource::ResourceContext; +use super::{Affine, BlendMode, PathElement, Scene, SceneData, SceneFragment}; +use crate::{brush::*, ResourcePatch}; use bytemuck::{Pod, Zeroable}; use core::borrow::Borrow; use smallvec::SmallVec; @@ -28,37 +24,27 @@ use smallvec::SmallVec; /// Builder for constructing a scene or scene fragment. pub struct SceneBuilder<'a> { scene: &'a mut SceneData, - resources: ResourceData<'a>, layers: SmallVec<[BlendMode; 8]>, } impl<'a> SceneBuilder<'a> { /// Creates a new builder for filling a scene. Any current content in the scene /// will be cleared. - pub fn for_scene(scene: &'a mut Scene, rcx: &'a mut ResourceContext) -> Self { - Self::new(&mut scene.data, ResourceData::Scene(rcx)) + pub fn for_scene(scene: &'a mut Scene) -> Self { + Self::new(&mut scene.data, false) } /// Creates a new builder for filling a scene fragment. Any current content in /// the fragment will be cleared. pub fn for_fragment(fragment: &'a mut SceneFragment) -> Self { - Self::new( - &mut fragment.data, - ResourceData::Fragment(&mut fragment.resources), - ) + Self::new(&mut fragment.data, true) } /// Creates a new builder for constructing a scene. - fn new(scene: &'a mut SceneData, mut resources: ResourceData<'a>) -> Self { - let is_fragment = match resources { - ResourceData::Fragment(_) => true, - _ => false, - }; + fn new(scene: &'a mut SceneData, is_fragment: bool) -> Self { scene.reset(is_fragment); - resources.clear(); Self { scene, - resources, layers: Default::default(), } } @@ -161,7 +147,6 @@ impl<'a> SceneBuilder<'a> { /// Appends a fragment to the scene. pub fn append(&mut self, fragment: &SceneFragment, transform: Option) { - let drawdata_base = self.scene.drawdata_stream.len(); let mut cur_transform = self.scene.transform_stream.last().copied(); if let Some(transform) = transform { if cur_transform.is_none() { @@ -172,39 +157,6 @@ impl<'a> SceneBuilder<'a> { self.encode_transform(Affine::IDENTITY); } self.scene.append(&fragment.data, &transform); - match &mut self.resources { - ResourceData::Scene(res) => { - for patch in &fragment.resources.patches { - match patch { - ResourcePatch::Ramp { - drawdata_offset, - stops, - } => { - let stops = &fragment.resources.stops[stops.clone()]; - let ramp_id = res.add_ramp(stops); - let patch_base = *drawdata_offset + drawdata_base; - (&mut self.scene.drawdata_stream[patch_base..patch_base + 4]) - .copy_from_slice(bytemuck::bytes_of(&ramp_id)); - } - } - } - } - ResourceData::Fragment(res) => { - let stops_base = res.stops.len(); - res.stops.extend_from_slice(&fragment.resources.stops); - res.patches.extend(fragment.resources.patches.iter().map( - |pending| match pending { - ResourcePatch::Ramp { - drawdata_offset, - stops, - } => ResourcePatch::Ramp { - drawdata_offset: drawdata_offset + drawdata_base, - stops: stops.start + stops_base..stops.end + stops_base, - }, - }, - )); - } - } // Prevent fragments from affecting transform state. Should we allow this? if let Some(transform) = cur_transform { self.transform(transform); @@ -325,19 +277,15 @@ impl<'a> SceneBuilder<'a> { } fn add_ramp(&mut self, stops: &[GradientStop]) -> u32 { - match &mut self.resources { - ResourceData::Scene(res) => res.add_ramp(stops), - ResourceData::Fragment(res) => { - let stops_start = res.stops.len(); - res.stops.extend_from_slice(stops); - let id = res.patches.len() as u32; - res.patches.push(ResourcePatch::Ramp { - drawdata_offset: self.scene.drawdata_stream.len(), - stops: stops_start..stops_start + stops.len(), - }); - id - } - } + let offset = self.scene.drawdata_stream.len(); + let resources = &mut self.scene.resources; + let stops_start = resources.stops.len(); + resources.stops.extend_from_slice(stops); + resources.patches.push(ResourcePatch::Ramp { + offset, + stops: stops_start..stops_start + stops.len(), + }); + 0 } /// Start a clip. @@ -366,22 +314,6 @@ impl<'a> SceneBuilder<'a> { self.scene.n_clip += 1; } } -enum ResourceData<'a> { - Fragment(&'a mut FragmentResources), - 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; diff --git a/piet-scene/src/scene/mod.rs b/piet-scene/src/scene/mod.rs index 33abe57..91fd14b 100644 --- a/piet-scene/src/scene/mod.rs +++ b/piet-scene/src/scene/mod.rs @@ -22,11 +22,9 @@ pub use blend::{BlendMode, Compose, Mix}; pub use builder::SceneBuilder; pub use style::*; -use super::brush::*; use super::geometry::{Affine, Point}; use super::path::PathElement; - -use core::ops::Range; +use super::resource::{ResourceBundle, ResourcePatch}; /// Raw data streams describing an encoded scene. #[derive(Default)] @@ -40,6 +38,7 @@ pub struct SceneData { pub n_path: u32, pub n_pathseg: u32, pub n_clip: u32, + pub resources: ResourceBundle, } impl SceneData { @@ -57,6 +56,7 @@ impl SceneData { self.n_path = 0; self.n_pathseg = 0; self.n_clip = 0; + self.resources.clear(); if !is_fragment { self.transform_stream .push(Affine::new(&[1.0, 0.0, 0.0, 1.0, 0.0, 0.0])); @@ -65,9 +65,11 @@ impl SceneData { } fn append(&mut self, other: &SceneData, transform: &Option) { + let stops_base = self.resources.stops.len(); + let drawdata_base = self.drawdata_stream.len(); if let Some(transform) = *transform { self.transform_stream - .extend(other.transform_stream.iter().map(|x| *x * transform)); + .extend(other.transform_stream.iter().map(|x| transform * *x)); } else { self.transform_stream .extend_from_slice(&other.transform_stream); @@ -82,6 +84,20 @@ impl SceneData { self.n_path += other.n_path; self.n_pathseg += other.n_pathseg; self.n_clip += other.n_clip; + self.resources + .stops + .extend_from_slice(&other.resources.stops); + self.resources + .patches + .extend(other.resources.patches.iter().map(|patch| match patch { + ResourcePatch::Ramp { offset, stops } => { + let stops = stops.start + stops_base..stops.end + stops_base; + ResourcePatch::Ramp { + offset: drawdata_base + offset, + stops, + } + } + })); } } @@ -103,7 +119,6 @@ impl Scene { #[derive(Default)] pub struct SceneFragment { data: SceneData, - resources: FragmentResources, } impl SceneFragment { @@ -122,16 +137,3 @@ impl SceneFragment { } } } - -#[derive(Default)] -struct FragmentResources { - patches: Vec, - stops: Vec, -} - -enum ResourcePatch { - Ramp { - drawdata_offset: usize, - stops: Range, - }, -}