diff --git a/crates/processing_pyo3/src/graphics.rs b/crates/processing_pyo3/src/graphics.rs index bb55257c..30e71403 100644 --- a/crates/processing_pyo3/src/graphics.rs +++ b/crates/processing_pyo3/src/graphics.rs @@ -2206,6 +2206,21 @@ impl Graphics { .map_err(|e| PyRuntimeError::new_err(format!("{e}"))) } + pub fn texture(&self, source: ImageRef) -> PyResult<()> { + graphics_record_command(self.entity, DrawCommand::Texture(source.entity)) + .map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } + + pub fn no_texture(&self) -> PyResult<()> { + graphics_record_command(self.entity, DrawCommand::NoTexture) + .map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } + + pub fn texture_transform(&self, transform: crate::math::PyAffine2) -> PyResult<()> { + graphics_record_command(self.entity, DrawCommand::TextureTransform(transform.0)) + .map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } + pub fn unlit(&self) -> PyResult<()> { graphics_record_command(self.entity, DrawCommand::Unlit) .map_err(|e| PyRuntimeError::new_err(format!("{e}"))) diff --git a/crates/processing_pyo3/src/lib.rs b/crates/processing_pyo3/src/lib.rs index 32eb77c0..0ddc4e09 100644 --- a/crates/processing_pyo3/src/lib.rs +++ b/crates/processing_pyo3/src/lib.rs @@ -2029,6 +2029,27 @@ pub mod mewnala { graphics!(module).emissive(args) } + #[pyfunction] + #[pyo3(pass_module)] + fn texture(module: &Bound<'_, PyModule>, source: graphics::ImageRef) -> PyResult<()> { + graphics!(module).texture(source) + } + + #[pyfunction] + #[pyo3(pass_module)] + fn no_texture(module: &Bound<'_, PyModule>) -> PyResult<()> { + graphics!(module).no_texture() + } + + #[pyfunction] + #[pyo3(pass_module)] + fn texture_transform( + module: &Bound<'_, PyModule>, + transform: crate::math::PyAffine2, + ) -> PyResult<()> { + graphics!(module).texture_transform(transform) + } + #[pyfunction] #[pyo3(pass_module)] fn unlit(module: &Bound<'_, PyModule>) -> PyResult<()> { diff --git a/crates/processing_pyo3/src/webcam.rs b/crates/processing_pyo3/src/webcam.rs index 4d35f890..f57dcf02 100644 --- a/crates/processing_pyo3/src/webcam.rs +++ b/crates/processing_pyo3/src/webcam.rs @@ -5,13 +5,17 @@ use processing_webcam::{ }; use pyo3::{exceptions::PyRuntimeError, prelude::*}; -use crate::graphics::Image; - #[pyclass(unsendable)] pub struct Webcam { entity: Entity, } +impl Webcam { + pub(crate) fn image_entity(&self) -> PyResult { + webcam_image(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } +} + #[pymethods] impl Webcam { /// Opaque id for this object. @@ -45,12 +49,6 @@ impl Webcam { pub fn resolution(&self) -> PyResult<(u32, u32)> { webcam_resolution(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}"))) } - - pub fn image(&self) -> PyResult { - let entity = - webcam_image(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; - Ok(Image::from_entity(entity)) - } } impl Drop for Webcam { diff --git a/crates/processing_render/src/image.rs b/crates/processing_render/src/image.rs index e7a4fcd7..4945b3b5 100644 --- a/crates/processing_render/src/image.rs +++ b/crates/processing_render/src/image.rs @@ -100,6 +100,14 @@ pub fn blit( Ok(()) } +#[derive(Component)] +#[relationship(relationship_target = LinkedImageTarget)] +pub struct LinkedImage(pub Entity); + +#[derive(Component)] +#[relationship_target(relationship = LinkedImage)] +pub struct LinkedImageTarget(Entity); + #[derive(Component)] pub struct Image { pub handle: Handle, diff --git a/crates/processing_render/src/render/command.rs b/crates/processing_render/src/render/command.rs index d514982b..7efecf56 100644 --- a/crates/processing_render/src/render/command.rs +++ b/crates/processing_render/src/render/command.rs @@ -1,3 +1,4 @@ +use bevy::math::Affine2; use bevy::math::Affine3A; use bevy::prelude::*; use bevy::render::render_resource::{BlendComponent, BlendFactor, BlendOperation, BlendState}; @@ -515,6 +516,9 @@ pub enum DrawCommand { Roughness(f32), Metallic(f32), Emissive(Color), + Texture(Entity), + NoTexture, + TextureTransform(Affine2), Unlit, Tint(Color), NoTint, diff --git a/crates/processing_render/src/render/mod.rs b/crates/processing_render/src/render/mod.rs index e841461b..0e797032 100644 --- a/crates/processing_render/src/render/mod.rs +++ b/crates/processing_render/src/render/mod.rs @@ -222,6 +222,25 @@ pub fn flush_draw_commands( pbr.blend_state = None; state.style.material_key = pbr.into(); } + DrawCommand::Texture(entity) => { + if let Ok(img) = p_images.get(entity) { + let mut pbr = state.style.material_key.as_pbr(); + pbr.base_color_texture = Some(img.handle.clone()); + state.style.material_key = pbr.into(); + } + } + DrawCommand::NoTexture => { + if let MaterialKey::Pbr { .. } = &state.style.material_key { + let mut pbr = state.style.material_key.as_pbr(); + pbr.base_color_texture = None; + state.style.material_key = pbr.into(); + } + } + DrawCommand::TextureTransform(transform) => { + let mut pbr = state.style.material_key.as_pbr(); + pbr.uv_transform = transform; + state.style.material_key = pbr.into(); + } DrawCommand::Unlit => { state.style.material_key = MaterialKey::Color { transparent: state.fill_is_transparent(), diff --git a/crates/processing_webcam/src/lib.rs b/crates/processing_webcam/src/lib.rs index 7b66dfcc..04166aec 100644 --- a/crates/processing_webcam/src/lib.rs +++ b/crates/processing_webcam/src/lib.rs @@ -31,6 +31,10 @@ fn create_with_format(In(format): In, mut commands: Commands) -> E } fn create_image(In(entity): In, world: &mut World) -> Result { + if let Some(linked) = world.get::(entity) { + return Ok(linked.0); + } + let stream = world .get::(entity) .ok_or(ProcessingError::WebcamNotConnected)?; @@ -39,6 +43,7 @@ fn create_image(In(entity): In, world: &mut World) -> Result { let child = world .run_system_once_with(image::from_handle, handle) .unwrap()?; + world.entity_mut(entity).insert(image::LinkedImage(child)); world.entity_mut(entity).add_child(child); Ok(child) }