Add a more ergonomic API for texture overrides Signed-off-by: Nico Burns <nico@nicoburns.com>
diff --git a/vello/src/lib.rs b/vello/src/lib.rs index f127ac1..db2037e 100644 --- a/vello/src/lib.rs +++ b/vello/src/lib.rs
@@ -312,6 +312,15 @@ )] pub(crate) type Result<T, E = Error> = std::result::Result<T, E>; +/// An opaque handle to a texture registered with [`Renderer::register_texture`] that +/// can be passed to [`Scene::draw_texture`] to draw the texture. +#[derive(Copy, Clone, PartialEq, Hash)] +pub struct TextureHandle { + pub(crate) id: u64, + pub(crate) width: u32, + pub(crate) height: u32, +} + /// Renders a scene into a texture or surface. /// /// Currently, each renderer only supports a single surface format, if it @@ -520,6 +529,7 @@ /// dimensions would be rendered. /// /// [data]: peniko::Image::data + #[deprecated = "Use register_texture and unregister_texture methods instead"] pub fn override_image( &mut self, image: &peniko::Image, @@ -531,6 +541,40 @@ } } + /// Register a [`wgpu::Texture`] with Vello. You will receive a [`TextureHandle`] which + /// can be used to draw the registered texture using [`Scene::draw_texture`] + /// + /// If the texture is no longer active then it should be unregistered using [`unregister_texture`](Self::unregister_texture) + pub fn register_texture(&mut self, texture: wgpu::Texture) -> TextureHandle { + // Generate a unique ID using peniko::Blob to guarantee it won't clash + // with a user-generated image Blob + let id = peniko::Blob::<()>::new(std::sync::Arc::new(&[])).id(); + + let handle = TextureHandle { + id, + width: texture.width(), + height: texture.height(), + }; + + // Create a texture base for the texture + let texture_base = wgpu::TexelCopyTextureInfoBase { + texture, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + aspect: wgpu::TextureAspect::All, + }; + + // Insert it into the overrides map + self.engine.image_overrides.insert(id, texture_base); + + handle + } + + /// Unregister a [`wgpu::Texture`] that was registered with [`register_texture`](Self::register_texture) + pub fn unregister_texture(&mut self, handle: TextureHandle) { + self.engine.image_overrides.remove(&handle.id); + } + /// Reload the shaders. This should only be used during `vello` development #[cfg(feature = "hot_reload")] #[doc(hidden)] // End-users of Vello should not have `hot_reload` enabled.
diff --git a/vello/src/scene.rs b/vello/src/scene.rs index 0e5f3ed..320c701 100644 --- a/vello/src/scene.rs +++ b/vello/src/scene.rs
@@ -23,6 +23,8 @@ use vello_encoding::BumpAllocatorMemory; use vello_encoding::{Encoding, Glyph, GlyphRun, NormalizedCoord, Patch, Transform}; +use crate::TextureHandle; + // TODO - Document invariants and edge cases (#470) // - What happens when we pass a transform matrix with NaN values to the Scene? // - What happens if a push_layer isn't matched by a pop_layer? @@ -306,6 +308,58 @@ ); } + /// Draws a texture at its natural size with the given transform + /// + /// To get a [`TextureHandle`] to use with this API, first register the texture with the renderer + /// using the [`Renderer::register_texture`](crate::Renderer::register_texture) method. + pub fn draw_texture(&mut self, handle: TextureHandle, transform: Affine) { + self.fill_texture( + Fill::NonZero, + transform, + 1.0, + handle, + None, + &Rect::new(0.0, 0.0, handle.width as f64, handle.height as f64), + Extend::Pad, + Extend::Pad, + ); + } + + /// Fills a shape using the specified texture + /// + /// To get a [`TextureHandle`] to use with this API, first register the texture with the renderer + /// using the [`Renderer::register_texture`](crate::Renderer::register_texture) method. + pub fn fill_texture( + &mut self, + style: Fill, + transform: Affine, + alpha: f32, + handle: TextureHandle, + brush_transform: Option<Affine>, + shape: &impl Shape, + x_extend: Extend, + y_extend: Extend, + ) { + let dummy_image = Image { + data: Blob::from_raw_parts(Arc::new([]), handle.id), + width: handle.width, + height: handle.height, + format: peniko::ImageFormat::Rgba8, + quality: peniko::ImageQuality::High, + x_extend, + y_extend, + alpha, + }; + + self.fill( + style, + transform, + BrushRef::Image(&dummy_image), + brush_transform, + shape, + ); + } + /// Returns a builder for encoding a glyph run. pub fn draw_glyphs(&mut self, font: &Font) -> DrawGlyphs<'_> { // TODO: Integrate `BumpEstimator` with the glyph cache.