Skip to content

Commit 2df5e3f

Browse files
committed
Add image method.
1 parent c725352 commit 2df5e3f

6 files changed

Lines changed: 207 additions & 10 deletions

File tree

crates/processing_pyo3/src/graphics.rs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -807,13 +807,67 @@ impl Graphics {
807807
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
808808
}
809809

810-
pub fn image(&self, file: &str) -> PyResult<Image> {
810+
pub fn load_image(&self, file: &str) -> PyResult<Image> {
811811
match image_load(file) {
812812
Ok(image) => Ok(Image { entity: image }),
813813
Err(e) => Err(PyRuntimeError::new_err(format!("{e}"))),
814814
}
815815
}
816816

817+
#[pyo3(signature = (source, dx, dy, d_width=None, d_height=None, sx=None, sy=None, s_width=None, s_height=None))]
818+
pub fn image(
819+
&self,
820+
source: ImageRef,
821+
dx: f32,
822+
dy: f32,
823+
d_width: Option<f32>,
824+
d_height: Option<f32>,
825+
sx: Option<f32>,
826+
sy: Option<f32>,
827+
s_width: Option<f32>,
828+
s_height: Option<f32>,
829+
) -> PyResult<()> {
830+
graphics_record_command(
831+
self.entity,
832+
DrawCommand::Image {
833+
entity: source.entity,
834+
dx,
835+
dy,
836+
d_width,
837+
d_height,
838+
sx,
839+
sy,
840+
s_width,
841+
s_height,
842+
},
843+
)
844+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
845+
}
846+
847+
#[pyo3(signature = (*args))]
848+
pub fn tint(&self, args: &Bound<'_, PyTuple>) -> PyResult<()> {
849+
let color = extract_color_with_mode(
850+
args,
851+
&graphics_get_color_mode(self.entity)
852+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))?,
853+
)?;
854+
graphics_record_command(self.entity, DrawCommand::Tint(color))
855+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
856+
}
857+
858+
pub fn no_tint(&self) -> PyResult<()> {
859+
graphics_record_command(self.entity, DrawCommand::NoTint)
860+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
861+
}
862+
863+
pub fn image_mode(&self, mode: u8) -> PyResult<()> {
864+
graphics_record_command(
865+
self.entity,
866+
DrawCommand::ImageMode(processing::prelude::ShapeMode::from(mode)),
867+
)
868+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
869+
}
870+
817871
pub fn create_image(&self, width: u32, height: u32) -> PyResult<Image> {
818872
let size = Extent3d {
819873
width,

crates/processing_pyo3/src/lib.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,10 +1378,46 @@ mod mewnala {
13781378

13791379
#[pyfunction]
13801380
#[pyo3(pass_module, signature = (image_file))]
1381-
fn image(module: &Bound<'_, PyModule>, image_file: &str) -> PyResult<Image> {
1381+
fn load_image(module: &Bound<'_, PyModule>, image_file: &str) -> PyResult<Image> {
13821382
let graphics =
13831383
get_graphics(module)?.ok_or_else(|| PyRuntimeError::new_err("call size() first"))?;
1384-
graphics.image(image_file)
1384+
graphics.load_image(image_file)
1385+
}
1386+
1387+
#[pyfunction]
1388+
#[pyo3(pass_module, signature = (source, dx, dy, d_width=None, d_height=None, sx=None, sy=None, s_width=None, s_height=None))]
1389+
#[allow(clippy::too_many_arguments)]
1390+
fn image(
1391+
module: &Bound<'_, PyModule>,
1392+
source: graphics::ImageRef,
1393+
dx: f32,
1394+
dy: f32,
1395+
d_width: Option<f32>,
1396+
d_height: Option<f32>,
1397+
sx: Option<f32>,
1398+
sy: Option<f32>,
1399+
s_width: Option<f32>,
1400+
s_height: Option<f32>,
1401+
) -> PyResult<()> {
1402+
graphics!(module).image(source, dx, dy, d_width, d_height, sx, sy, s_width, s_height)
1403+
}
1404+
1405+
#[pyfunction]
1406+
#[pyo3(pass_module, signature = (*args))]
1407+
fn tint(module: &Bound<'_, PyModule>, args: &Bound<'_, PyTuple>) -> PyResult<()> {
1408+
graphics!(module).tint(args)
1409+
}
1410+
1411+
#[pyfunction]
1412+
#[pyo3(pass_module)]
1413+
fn no_tint(module: &Bound<'_, PyModule>) -> PyResult<()> {
1414+
graphics!(module).no_tint()
1415+
}
1416+
1417+
#[pyfunction]
1418+
#[pyo3(pass_module)]
1419+
fn image_mode(module: &Bound<'_, PyModule>, mode: u8) -> PyResult<()> {
1420+
graphics!(module).image_mode(mode)
13851421
}
13861422

13871423
#[pyfunction]

crates/processing_pyo3/src/math.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,10 @@ impl PyMat2 {
793793
let m01: f32 = args.get_item(1)?.extract()?;
794794
let m10: f32 = args.get_item(2)?.extract()?;
795795
let m11: f32 = args.get_item(3)?.extract()?;
796-
Ok(Self(Mat2::from_cols(Vec2::new(m00, m01), Vec2::new(m10, m11))))
796+
Ok(Self(Mat2::from_cols(
797+
Vec2::new(m00, m01),
798+
Vec2::new(m10, m11),
799+
)))
797800
}
798801
_ => Err(PyTypeError::new_err("Mat2 takes 0 or 4 arguments")),
799802
}
@@ -818,10 +821,7 @@ impl PyMat2 {
818821
.unbind());
819822
}
820823
if let Ok(v) = rhs.extract::<PyRef<PyVec2>>() {
821-
return Ok(PyVec2(self.0 * v.0)
822-
.into_pyobject(py)?
823-
.into_any()
824-
.unbind());
824+
return Ok(PyVec2(self.0 * v.0).into_pyobject(py)?.into_any().unbind());
825825
}
826826
Err(PyTypeError::new_err(
827827
"unsupported operand type(s) for *: 'Mat2'",

crates/processing_render/src/render/command.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,20 @@ pub enum DrawCommand {
311311
NoTexture,
312312
TextureTransform(Affine2),
313313
Unlit,
314+
Tint(Color),
315+
NoTint,
316+
ImageMode(ShapeMode),
317+
Image {
318+
entity: Entity,
319+
dx: f32,
320+
dy: f32,
321+
d_width: Option<f32>,
322+
d_height: Option<f32>,
323+
sx: Option<f32>,
324+
sy: Option<f32>,
325+
s_width: Option<f32>,
326+
s_height: Option<f32>,
327+
},
314328
RectMode(ShapeMode),
315329
EllipseMode(ShapeMode),
316330
Rect {

crates/processing_render/src/render/material.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub enum MaterialKey {
1717
Color {
1818
transparent: bool,
1919
background_image: Option<Handle<Image>>,
20+
uv_transform: Affine2,
2021
blend_state: Option<BlendState>,
2122
},
2223
Pbr {
@@ -109,12 +110,14 @@ impl MaterialKey {
109110
MaterialKey::Color {
110111
transparent,
111112
background_image,
113+
uv_transform,
112114
blend_state,
113115
} => StandardMaterial {
114116
base_color: Color::WHITE,
115117
unlit: true,
116118
cull_mode: None,
117119
base_color_texture: background_image.clone(),
120+
uv_transform: *uv_transform,
118121
alpha_mode: if blend_state.is_some() || *transparent {
119122
AlphaMode::Blend
120123
} else {

crates/processing_render/src/render/mod.rs

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub mod transform;
77
use bevy::{
88
camera::visibility::RenderLayers,
99
ecs::system::SystemParam,
10-
math::{Affine3A, Mat4, Vec4},
10+
math::{Affine2, Affine3A, Mat4, Vec4},
1111
prelude::*,
1212
render::render_resource::BlendState,
1313
};
@@ -80,6 +80,8 @@ pub struct RenderState {
8080
pub material_key: MaterialKey,
8181
pub blend_state: Option<BlendState>,
8282
pub transform: TransformStack,
83+
pub tint_color: Option<Color>,
84+
pub image_mode: ShapeMode,
8385
pub rect_mode: ShapeMode,
8486
pub ellipse_mode: ShapeMode,
8587
pub shape_builder: Option<ShapeBuilder>,
@@ -95,9 +97,12 @@ impl RenderState {
9597
material_key: MaterialKey::Color {
9698
transparent: false,
9799
background_image: None,
100+
uv_transform: Affine2::IDENTITY,
98101
blend_state: None,
99102
},
100103
blend_state: None,
104+
tint_color: None,
105+
image_mode: ShapeMode::Corner,
101106
transform: TransformStack::new(),
102107
rect_mode: ShapeMode::Corner,
103108
ellipse_mode: ShapeMode::Center,
@@ -113,9 +118,12 @@ impl RenderState {
113118
self.material_key = MaterialKey::Color {
114119
transparent: false,
115120
background_image: None,
121+
uv_transform: Affine2::IDENTITY,
116122
blend_state: None,
117123
};
118124
self.blend_state = None;
125+
self.tint_color = None;
126+
self.image_mode = ShapeMode::Corner;
119127
self.transform = TransformStack::new();
120128
self.rect_mode = ShapeMode::Corner;
121129
self.ellipse_mode = ShapeMode::Center;
@@ -232,6 +240,7 @@ pub fn flush_draw_commands(
232240
state.material_key = MaterialKey::Color {
233241
transparent: state.fill_is_transparent(),
234242
background_image: None,
243+
uv_transform: Affine2::IDENTITY,
235244
blend_state: None,
236245
};
237246
}
@@ -755,6 +764,82 @@ pub fn flush_draw_commands(
755764
}
756765
}
757766
}
767+
DrawCommand::Tint(color) => {
768+
state.tint_color = Some(color);
769+
}
770+
DrawCommand::NoTint => {
771+
state.tint_color = None;
772+
}
773+
DrawCommand::ImageMode(mode) => {
774+
state.image_mode = mode;
775+
}
776+
DrawCommand::Image {
777+
entity,
778+
dx,
779+
dy,
780+
d_width,
781+
d_height,
782+
sx,
783+
sy,
784+
s_width,
785+
s_height,
786+
} => {
787+
let Some(p_image) = p_images.get(entity).ok() else {
788+
warn!("Could not find PImage for entity {:?}", entity);
789+
continue;
790+
};
791+
792+
let img_w = p_image.size.width as f32;
793+
let img_h = p_image.size.height as f32;
794+
let dw = d_width.unwrap_or(img_w);
795+
let dh = d_height.unwrap_or(img_h);
796+
let (x, y, w, h) = apply_shape_mode(state.image_mode, dx, dy, dw, dh);
797+
798+
let uv_xform = match (sx, sy, s_width, s_height) {
799+
(Some(sx), Some(sy), Some(sw), Some(sh)) => {
800+
Affine2::from_scale_angle_translation(
801+
Vec2::new(sw / img_w, sh / img_h),
802+
0.0,
803+
Vec2::new(sx / img_w, sy / img_h),
804+
)
805+
}
806+
_ => Affine2::IDENTITY,
807+
};
808+
809+
let tint = state.tint_color.unwrap_or(Color::WHITE);
810+
let material_key = MaterialKey::Color {
811+
transparent: tint.alpha() < 1.0,
812+
background_image: Some(p_image.handle.clone()),
813+
uv_transform: uv_xform,
814+
blend_state: state.blend_state,
815+
};
816+
let stroke_config = state.stroke_config;
817+
818+
flush_batch(&mut res, &mut batch, &p_material_handles);
819+
start_batch(
820+
&mut res,
821+
&mut batch,
822+
&state,
823+
material_key,
824+
&p_material_handles,
825+
);
826+
827+
if let Some(ref mut mesh) = batch.current_mesh {
828+
rect(
829+
mesh,
830+
x,
831+
y,
832+
w,
833+
h,
834+
[0.0; 4],
835+
tint,
836+
TessellationMode::Fill,
837+
&stroke_config,
838+
);
839+
}
840+
841+
flush_batch(&mut res, &mut batch, &p_material_handles);
842+
}
758843
DrawCommand::BackgroundColor(color) => {
759844
flush_batch(&mut res, &mut batch, &p_material_handles);
760845

@@ -764,6 +849,7 @@ pub fn flush_draw_commands(
764849
let material_key = MaterialKey::Color {
765850
transparent: color.alpha() < 1.0,
766851
background_image: None,
852+
uv_transform: Affine2::IDENTITY,
767853
blend_state: Some(BlendState::REPLACE),
768854
};
769855
let material_handle = material_key.to_material(&mut res.materials);
@@ -792,6 +878,7 @@ pub fn flush_draw_commands(
792878
let material_key = MaterialKey::Color {
793879
transparent: false,
794880
background_image: Some(p_image.handle.clone()),
881+
uv_transform: Affine2::IDENTITY,
795882
blend_state: Some(BlendState::REPLACE),
796883
};
797884
let material_handle = material_key.to_material(&mut res.materials);
@@ -1111,10 +1198,13 @@ fn material_key_with_color(
11111198
) -> MaterialKey {
11121199
match key {
11131200
MaterialKey::Color {
1114-
background_image, ..
1201+
background_image,
1202+
uv_transform,
1203+
..
11151204
} => MaterialKey::Color {
11161205
transparent: color.alpha() < 1.0,
11171206
background_image: background_image.clone(),
1207+
uv_transform: *uv_transform,
11181208
blend_state,
11191209
},
11201210
MaterialKey::Pbr { .. } => {

0 commit comments

Comments
 (0)