Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ path = "examples/background_image.rs"
name = "update_pixels"
path = "examples/update_pixels.rs"

[[example]]
name = "transforms"
path = "examples/transforms.rs"

[profile.wasm-release]
inherits = "release"
opt-level = "z"
Expand Down
104 changes: 104 additions & 0 deletions crates/processing_ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,110 @@ pub extern "C" fn processing_no_stroke(window_id: u64) {
error::check(|| graphics_record_command(window_entity, DrawCommand::NoStroke));
}

/// Push the current transformation matrix onto the stack.
///
/// SAFETY:
/// - Init and surface_create have been called.
/// - window_id is a valid ID returned from surface_create.
/// - This is called from the same thread as init.
#[unsafe(no_mangle)]
pub extern "C" fn processing_push_matrix(window_id: u64) {
error::clear_error();
let window_entity = Entity::from_bits(window_id);
error::check(|| graphics_record_command(window_entity, DrawCommand::PushMatrix));
}

/// Pop the transformation matrix from the stack.
///
/// SAFETY:
/// - Init and surface_create have been called.
/// - window_id is a valid ID returned from surface_create.
/// - This is called from the same thread as init.
#[unsafe(no_mangle)]
pub extern "C" fn processing_pop_matrix(window_id: u64) {
error::clear_error();
let window_entity = Entity::from_bits(window_id);
error::check(|| graphics_record_command(window_entity, DrawCommand::PopMatrix));
}

/// Reset the transformation matrix to identity.
///
/// SAFETY:
/// - Init and surface_create have been called.
/// - window_id is a valid ID returned from surface_create.
/// - This is called from the same thread as init.
#[unsafe(no_mangle)]
pub extern "C" fn processing_reset_matrix(window_id: u64) {
error::clear_error();
let window_entity = Entity::from_bits(window_id);
error::check(|| graphics_record_command(window_entity, DrawCommand::ResetMatrix));
}

/// Translate the coordinate system.
///
/// SAFETY:
/// - Init and surface_create have been called.
/// - window_id is a valid ID returned from surface_create.
/// - This is called from the same thread as init.
#[unsafe(no_mangle)]
pub extern "C" fn processing_translate(window_id: u64, x: f32, y: f32) {
error::clear_error();
let window_entity = Entity::from_bits(window_id);
error::check(|| graphics_record_command(window_entity, DrawCommand::Translate { x, y }));
}

/// Rotate the coordinate system.
///
/// SAFETY:
/// - Init and surface_create have been called.
/// - window_id is a valid ID returned from surface_create.
/// - This is called from the same thread as init.
#[unsafe(no_mangle)]
pub extern "C" fn processing_rotate(window_id: u64, angle: f32) {
error::clear_error();
let window_entity = Entity::from_bits(window_id);
error::check(|| graphics_record_command(window_entity, DrawCommand::Rotate { angle }));
}

/// Scale the coordinate system.
///
/// SAFETY:
/// - Init and surface_create have been called.
/// - window_id is a valid ID returned from surface_create.
/// - This is called from the same thread as init.
#[unsafe(no_mangle)]
pub extern "C" fn processing_scale(window_id: u64, x: f32, y: f32) {
error::clear_error();
let window_entity = Entity::from_bits(window_id);
error::check(|| graphics_record_command(window_entity, DrawCommand::Scale { x, y }));
}

/// Shear along the X axis.
///
/// SAFETY:
/// - Init and surface_create have been called.
/// - window_id is a valid ID returned from surface_create.
/// - This is called from the same thread as init.
#[unsafe(no_mangle)]
pub extern "C" fn processing_shear_x(window_id: u64, angle: f32) {
error::clear_error();
let window_entity = Entity::from_bits(window_id);
error::check(|| graphics_record_command(window_entity, DrawCommand::ShearX { angle }));
}

/// Shear along the Y axis.
///
/// SAFETY:
/// - Init and surface_create have been called.
/// - window_id is a valid ID returned from surface_create.
/// - This is called from the same thread as init.
#[unsafe(no_mangle)]
pub extern "C" fn processing_shear_y(window_id: u64, angle: f32) {
error::clear_error();
let window_entity = Entity::from_bits(window_id);
error::check(|| graphics_record_command(window_entity, DrawCommand::ShearY { angle }));
}

/// Draw a rectangle.
///
/// SAFETY:
Expand Down
40 changes: 40 additions & 0 deletions crates/processing_pyo3/src/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,46 @@ impl Graphics {
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn push_matrix(&self) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::PushMatrix)
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn pop_matrix(&self) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::PopMatrix)
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn reset_matrix(&self) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::ResetMatrix)
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn translate(&self, x: f32, y: f32) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::Translate { x, y })
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn rotate(&self, angle: f32) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::Rotate { angle })
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn scale(&self, x: f32, y: f32) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::Scale { x, y })
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn shear_x(&self, angle: f32) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::ShearX { angle })
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn shear_y(&self, angle: f32) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::ShearY { angle })
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn begin_draw(&self) -> PyResult<()> {
graphics_begin_draw(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}
Expand Down
24 changes: 20 additions & 4 deletions crates/processing_render/src/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ use crate::{
Flush,
error::{ProcessingError, Result},
image::{Image, bytes_to_pixels, create_readback_buffer, pixel_size, pixels_to_bytes},
render::command::{CommandBuffer, DrawCommand},
render::{
RenderState,
command::{CommandBuffer, DrawCommand},
},
surface::Surface,
};

Expand Down Expand Up @@ -246,6 +249,7 @@ pub fn create(
Transform::from_xyz(0.0, 0.0, 999.9),
render_layer,
CommandBuffer::new(),
RenderState::default(),
SurfaceSize(width, height),
Graphics {
readback_buffer,
Expand Down Expand Up @@ -307,9 +311,21 @@ pub fn destroy(world: &mut World, entity: Entity) -> Result<()> {
world.run_system_cached_with(destroy_inner, entity).unwrap()
}

pub fn begin_draw(_app: &mut App, _entity: Entity) -> Result<()> {
// nothing to do here for now
Ok(())
pub fn begin_draw(world: &mut World, entity: Entity) -> Result<()> {
fn begin_draw_inner(
In(entity): In<Entity>,
mut state_query: Query<&mut RenderState>,
) -> Result<()> {
let mut state = state_query
.get_mut(entity)
.map_err(|_| ProcessingError::GraphicsNotFound)?;
state.reset();
Ok(())
}

world
.run_system_cached_with(begin_draw_inner, entity)
.unwrap()
}

pub fn flush(app: &mut App, entity: Entity) -> Result<()> {
Expand Down
4 changes: 2 additions & 2 deletions crates/processing_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ pub fn graphics_create(surface_entity: Entity, width: u32, height: u32) -> error
}

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

/// Flush current pending draw commands to the graphics surface.
Expand Down
20 changes: 20 additions & 0 deletions crates/processing_render/src/render/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,26 @@ pub enum DrawCommand {
h: f32,
radii: [f32; 4], // [tl, tr, br, bl]
},
PushMatrix,
PopMatrix,
ResetMatrix,
Translate {
x: f32,
y: f32,
},
Rotate {
angle: f32,
},
Scale {
x: f32,
y: f32,
},
ShearX {
angle: f32,
},
ShearY {
angle: f32,
},
}

#[derive(Debug, Default, Component)]
Expand Down
Loading