Skip to content

Commit 413e765

Browse files
authored
Transform stack (#38)
1 parent 61161fe commit 413e765

File tree

10 files changed

+654
-86
lines changed

10 files changed

+654
-86
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ path = "examples/background_image.rs"
4646
name = "update_pixels"
4747
path = "examples/update_pixels.rs"
4848

49+
[[example]]
50+
name = "transforms"
51+
path = "examples/transforms.rs"
52+
4953
[profile.wasm-release]
5054
inherits = "release"
5155
opt-level = "z"

crates/processing_ffi/src/lib.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,110 @@ pub extern "C" fn processing_no_stroke(window_id: u64) {
211211
error::check(|| graphics_record_command(window_entity, DrawCommand::NoStroke));
212212
}
213213

214+
/// Push the current transformation matrix onto the stack.
215+
///
216+
/// SAFETY:
217+
/// - Init and surface_create have been called.
218+
/// - window_id is a valid ID returned from surface_create.
219+
/// - This is called from the same thread as init.
220+
#[unsafe(no_mangle)]
221+
pub extern "C" fn processing_push_matrix(window_id: u64) {
222+
error::clear_error();
223+
let window_entity = Entity::from_bits(window_id);
224+
error::check(|| graphics_record_command(window_entity, DrawCommand::PushMatrix));
225+
}
226+
227+
/// Pop the transformation matrix from the stack.
228+
///
229+
/// SAFETY:
230+
/// - Init and surface_create have been called.
231+
/// - window_id is a valid ID returned from surface_create.
232+
/// - This is called from the same thread as init.
233+
#[unsafe(no_mangle)]
234+
pub extern "C" fn processing_pop_matrix(window_id: u64) {
235+
error::clear_error();
236+
let window_entity = Entity::from_bits(window_id);
237+
error::check(|| graphics_record_command(window_entity, DrawCommand::PopMatrix));
238+
}
239+
240+
/// Reset the transformation matrix to identity.
241+
///
242+
/// SAFETY:
243+
/// - Init and surface_create have been called.
244+
/// - window_id is a valid ID returned from surface_create.
245+
/// - This is called from the same thread as init.
246+
#[unsafe(no_mangle)]
247+
pub extern "C" fn processing_reset_matrix(window_id: u64) {
248+
error::clear_error();
249+
let window_entity = Entity::from_bits(window_id);
250+
error::check(|| graphics_record_command(window_entity, DrawCommand::ResetMatrix));
251+
}
252+
253+
/// Translate the coordinate system.
254+
///
255+
/// SAFETY:
256+
/// - Init and surface_create have been called.
257+
/// - window_id is a valid ID returned from surface_create.
258+
/// - This is called from the same thread as init.
259+
#[unsafe(no_mangle)]
260+
pub extern "C" fn processing_translate(window_id: u64, x: f32, y: f32) {
261+
error::clear_error();
262+
let window_entity = Entity::from_bits(window_id);
263+
error::check(|| graphics_record_command(window_entity, DrawCommand::Translate { x, y }));
264+
}
265+
266+
/// Rotate the coordinate system.
267+
///
268+
/// SAFETY:
269+
/// - Init and surface_create have been called.
270+
/// - window_id is a valid ID returned from surface_create.
271+
/// - This is called from the same thread as init.
272+
#[unsafe(no_mangle)]
273+
pub extern "C" fn processing_rotate(window_id: u64, angle: f32) {
274+
error::clear_error();
275+
let window_entity = Entity::from_bits(window_id);
276+
error::check(|| graphics_record_command(window_entity, DrawCommand::Rotate { angle }));
277+
}
278+
279+
/// Scale the coordinate system.
280+
///
281+
/// SAFETY:
282+
/// - Init and surface_create have been called.
283+
/// - window_id is a valid ID returned from surface_create.
284+
/// - This is called from the same thread as init.
285+
#[unsafe(no_mangle)]
286+
pub extern "C" fn processing_scale(window_id: u64, x: f32, y: f32) {
287+
error::clear_error();
288+
let window_entity = Entity::from_bits(window_id);
289+
error::check(|| graphics_record_command(window_entity, DrawCommand::Scale { x, y }));
290+
}
291+
292+
/// Shear along the X axis.
293+
///
294+
/// SAFETY:
295+
/// - Init and surface_create have been called.
296+
/// - window_id is a valid ID returned from surface_create.
297+
/// - This is called from the same thread as init.
298+
#[unsafe(no_mangle)]
299+
pub extern "C" fn processing_shear_x(window_id: u64, angle: f32) {
300+
error::clear_error();
301+
let window_entity = Entity::from_bits(window_id);
302+
error::check(|| graphics_record_command(window_entity, DrawCommand::ShearX { angle }));
303+
}
304+
305+
/// Shear along the Y axis.
306+
///
307+
/// SAFETY:
308+
/// - Init and surface_create have been called.
309+
/// - window_id is a valid ID returned from surface_create.
310+
/// - This is called from the same thread as init.
311+
#[unsafe(no_mangle)]
312+
pub extern "C" fn processing_shear_y(window_id: u64, angle: f32) {
313+
error::clear_error();
314+
let window_entity = Entity::from_bits(window_id);
315+
error::check(|| graphics_record_command(window_entity, DrawCommand::ShearY { angle }));
316+
}
317+
214318
/// Draw a rectangle.
215319
///
216320
/// SAFETY:

crates/processing_pyo3/src/graphics.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,46 @@ impl Graphics {
123123
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
124124
}
125125

126+
pub fn push_matrix(&self) -> PyResult<()> {
127+
graphics_record_command(self.entity, DrawCommand::PushMatrix)
128+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
129+
}
130+
131+
pub fn pop_matrix(&self) -> PyResult<()> {
132+
graphics_record_command(self.entity, DrawCommand::PopMatrix)
133+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
134+
}
135+
136+
pub fn reset_matrix(&self) -> PyResult<()> {
137+
graphics_record_command(self.entity, DrawCommand::ResetMatrix)
138+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
139+
}
140+
141+
pub fn translate(&self, x: f32, y: f32) -> PyResult<()> {
142+
graphics_record_command(self.entity, DrawCommand::Translate { x, y })
143+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
144+
}
145+
146+
pub fn rotate(&self, angle: f32) -> PyResult<()> {
147+
graphics_record_command(self.entity, DrawCommand::Rotate { angle })
148+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
149+
}
150+
151+
pub fn scale(&self, x: f32, y: f32) -> PyResult<()> {
152+
graphics_record_command(self.entity, DrawCommand::Scale { x, y })
153+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
154+
}
155+
156+
pub fn shear_x(&self, angle: f32) -> PyResult<()> {
157+
graphics_record_command(self.entity, DrawCommand::ShearX { angle })
158+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
159+
}
160+
161+
pub fn shear_y(&self, angle: f32) -> PyResult<()> {
162+
graphics_record_command(self.entity, DrawCommand::ShearY { angle })
163+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
164+
}
165+
126166
pub fn begin_draw(&self) -> PyResult<()> {
127167
graphics_begin_draw(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
128168
}

crates/processing_render/src/graphics.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ use crate::{
2929
Flush,
3030
error::{ProcessingError, Result},
3131
image::{Image, bytes_to_pixels, create_readback_buffer, pixel_size, pixels_to_bytes},
32-
render::command::{CommandBuffer, DrawCommand},
32+
render::{
33+
RenderState,
34+
command::{CommandBuffer, DrawCommand},
35+
},
3336
surface::Surface,
3437
};
3538

@@ -246,6 +249,7 @@ pub fn create(
246249
Transform::from_xyz(0.0, 0.0, 999.9),
247250
render_layer,
248251
CommandBuffer::new(),
252+
RenderState::default(),
249253
SurfaceSize(width, height),
250254
Graphics {
251255
readback_buffer,
@@ -307,9 +311,21 @@ pub fn destroy(world: &mut World, entity: Entity) -> Result<()> {
307311
world.run_system_cached_with(destroy_inner, entity).unwrap()
308312
}
309313

310-
pub fn begin_draw(_app: &mut App, _entity: Entity) -> Result<()> {
311-
// nothing to do here for now
312-
Ok(())
314+
pub fn begin_draw(world: &mut World, entity: Entity) -> Result<()> {
315+
fn begin_draw_inner(
316+
In(entity): In<Entity>,
317+
mut state_query: Query<&mut RenderState>,
318+
) -> Result<()> {
319+
let mut state = state_query
320+
.get_mut(entity)
321+
.map_err(|_| ProcessingError::GraphicsNotFound)?;
322+
state.reset();
323+
Ok(())
324+
}
325+
326+
world
327+
.run_system_cached_with(begin_draw_inner, entity)
328+
.unwrap()
313329
}
314330

315331
pub fn flush(app: &mut App, entity: Entity) -> Result<()> {

crates/processing_render/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,8 @@ pub fn graphics_create(surface_entity: Entity, width: u32, height: u32) -> error
228228
}
229229

230230
/// Begin a new draw pass for the graphics surface.
231-
pub fn graphics_begin_draw(_graphics_entity: Entity) -> error::Result<()> {
232-
app_mut(|app| graphics::begin_draw(app, _graphics_entity))
231+
pub fn graphics_begin_draw(graphics_entity: Entity) -> error::Result<()> {
232+
app_mut(|app| graphics::begin_draw(app.world_mut(), graphics_entity))
233233
}
234234

235235
/// Flush current pending draw commands to the graphics surface.

crates/processing_render/src/render/command.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,26 @@ pub enum DrawCommand {
1616
h: f32,
1717
radii: [f32; 4], // [tl, tr, br, bl]
1818
},
19+
PushMatrix,
20+
PopMatrix,
21+
ResetMatrix,
22+
Translate {
23+
x: f32,
24+
y: f32,
25+
},
26+
Rotate {
27+
angle: f32,
28+
},
29+
Scale {
30+
x: f32,
31+
y: f32,
32+
},
33+
ShearX {
34+
angle: f32,
35+
},
36+
ShearY {
37+
angle: f32,
38+
},
1939
}
2040

2141
#[derive(Debug, Default, Component)]

0 commit comments

Comments
 (0)