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.