From 4deb239f9d73b663fe8906468d9b7828605b4ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Tue, 3 Feb 2026 15:36:00 +0100 Subject: [PATCH 01/15] `lights` rust example --- Cargo.toml | 4 +++ examples/lights.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 examples/lights.rs diff --git a/Cargo.toml b/Cargo.toml index bf30fe3..e63a2d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,6 +64,10 @@ path = "examples/animated_mesh.rs" name = "custom_attribute" path = "examples/custom_attribute.rs" +[[example]] +name = "lights" +path = "examples/lights.rs" + [profile.wasm-release] inherits = "release" opt-level = "z" diff --git a/examples/lights.rs b/examples/lights.rs new file mode 100644 index 0000000..ff116d5 --- /dev/null +++ b/examples/lights.rs @@ -0,0 +1,68 @@ +mod glfw; + +use glfw::GlfwContext; +use processing::prelude::*; +use processing_render::render::command::DrawCommand; + +fn main() { + match sketch() { + Ok(_) => { + eprintln!("Sketch completed successfully"); + exit(0).unwrap(); + } + Err(e) => { + eprintln!("Sketch error: {:?}", e); + exit(1).unwrap(); + } + }; +} + +fn sketch() -> error::Result<()> { + let mut glfw_ctx = GlfwContext::new(400, 400)?; + init(Config::default())?; + + let width = 400; + let height = 400; + let scale_factor = 1.0; + + let surface = glfw_ctx.create_surface(width, height, scale_factor)?; + let graphics = graphics_create(surface, width, height)?; + let box_geo = geometry_box(10.0, 10.0, 10.0)?; + + let point_light = light_create()?; + + graphics_mode_3d(graphics)?; + graphics_camera_position(graphics, 100.0, 100.0, 300.0)?; + graphics_camera_look_at(graphics, 0.0, 0.0, 0.0)?; + + let mut angle = 0.0; + + while glfw_ctx.poll_events() { + graphics_begin_draw(graphics)?; + + graphics_record_command( + graphics, + DrawCommand::BackgroundColor(bevy::color::Color::srgb(0.18, 0.20, 0.15)), + )?; + + graphics_record_command(graphics, DrawCommand::Light(point_light))?; + + graphics_record_command(graphics, DrawCommand::PushMatrix)?; + graphics_record_command(graphics, DrawCommand::Translate { x: 25.0, y: 25.0 })?; + graphics_record_command(graphics, DrawCommand::Rotate { angle })?; + graphics_record_command(graphics, DrawCommand::Geometry(box_geo))?; + graphics_record_command(graphics, DrawCommand::PopMatrix)?; + + graphics_record_command(graphics, DrawCommand::PushMatrix)?; + graphics_record_command(graphics, DrawCommand::Translate { x: -25.0, y: 20.0 })?; + graphics_record_command(graphics, DrawCommand::Scale { x: 1.5, y: 2.0 })?; + graphics_record_command(graphics, DrawCommand::Rotate { angle })?; + graphics_record_command(graphics, DrawCommand::Geometry(box_geo))?; + graphics_record_command(graphics, DrawCommand::PopMatrix)?; + + graphics_end_draw(graphics)?; + + angle += 0.02; + } + Ok(()) +} From a98953134add40fe50dde70bfced55c1a7f9c1d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Tue, 3 Feb 2026 15:46:52 +0100 Subject: [PATCH 02/15] Add DrawCommand::Light --- crates/processing_render/src/render/command.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/processing_render/src/render/command.rs b/crates/processing_render/src/render/command.rs index f800a23..535dd4d 100644 --- a/crates/processing_render/src/render/command.rs +++ b/crates/processing_render/src/render/command.rs @@ -37,6 +37,7 @@ pub enum DrawCommand { angle: f32, }, Geometry(Entity), + Light(Entity), } #[derive(Debug, Default, Component)] From 3032dbbd4af9b18e13675985427019114f48ab06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Tue, 3 Feb 2026 16:46:08 +0100 Subject: [PATCH 03/15] TODO for `Light` API docs --- docs/api.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index c0cc4ce..21511fd 100644 --- a/docs/api.md +++ b/docs/api.md @@ -34,6 +34,10 @@ rendering texture that the camera draws to (`ViewTarget`), which is not typicall For consistency, all image functions should accept a graphics object, although its internal image representation is not guaranteed to be the same as a user-created image. +### Light + +[//]: # (TODO: Document Image API object) + ### Image Images are 2D or 3D arrays of pixels that can be drawn onto surfaces. They can be created from files, generated procedurally, @@ -85,4 +89,4 @@ can also be used to implement 2D image processing effects, etc. ### Shader -[//]: # (TODO: Document Shader API object, do we even need this with a sufficiently robust Material API?) \ No newline at end of file +[//]: # (TODO: Document Shader API object, do we even need this with a sufficiently robust Material API?) From 2b0cb2c52537a28966f65aada12257a12e2473c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Fri, 6 Feb 2026 12:36:16 -0500 Subject: [PATCH 04/15] WIP - instantiate lights in setup. no draw --- crates/processing_render/src/lib.rs | 17 +++++++- crates/processing_render/src/light.rs | 42 +++++++++++++++++++ .../processing_render/src/render/command.rs | 2 +- crates/processing_render/src/render/mod.rs | 21 +++++++++- examples/lights.rs | 7 ++-- 5 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 crates/processing_render/src/light.rs diff --git a/crates/processing_render/src/lib.rs b/crates/processing_render/src/lib.rs index 3b37229..f0b3cd1 100644 --- a/crates/processing_render/src/lib.rs +++ b/crates/processing_render/src/lib.rs @@ -3,6 +3,7 @@ pub mod error; pub mod geometry; mod graphics; pub mod image; +pub mod light; pub mod render; mod surface; pub mod transform; @@ -25,7 +26,10 @@ use tracing::debug; use crate::geometry::{AttributeFormat, AttributeValue}; use crate::graphics::flush; use crate::{ - graphics::GraphicsPlugin, image::ImagePlugin, render::command::DrawCommand, + graphics::GraphicsPlugin, + image::ImagePlugin, + light::{LightPlugin, LightType}, + render::command::DrawCommand, surface::SurfacePlugin, }; @@ -248,6 +252,7 @@ fn create_app(config: Config) -> App { GraphicsPlugin, SurfacePlugin, geometry::GeometryPlugin, + LightPlugin, )); app.add_systems(First, (clear_transient_meshes, activate_cameras)) .add_systems(Update, flush_draw_commands.before(AssetEventSystems)); @@ -774,6 +779,16 @@ pub fn image_destroy(entity: Entity) -> error::Result<()> { }) } +// pub fn geometry_box(width: f32, height: f32, depth: f32) -> error::Result { +pub fn light_create(light_type: LightType, x: f32, y: f32, z: f32) -> error::Result { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached_with(light::create, (light_type, x, y, z)) + .unwrap()) + }) +} + pub fn geometry_layout_create() -> error::Result { app_mut(|app| { Ok(app diff --git a/crates/processing_render/src/light.rs b/crates/processing_render/src/light.rs new file mode 100644 index 0000000..e6a2e35 --- /dev/null +++ b/crates/processing_render/src/light.rs @@ -0,0 +1,42 @@ +//! A light in Processing +//! + +use bevy::prelude::*; + +pub struct LightPlugin; + +impl Plugin for LightPlugin { + fn build(&self, _app: &mut App) {} +} + +#[derive(Component)] +pub struct Light { + pub light_type: LightType, + pub pos: Vec3, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum LightType { + Ambient, + Directional, + Point, + Spot, +} + +pub fn create( + In((light_type, x, y, z)): In<(LightType, f32, f32, f32)>, + mut commands: Commands, +) -> Entity { + // let light = Light { + // light_type: light_type, + // pos: Vec3::new(x, y, z), + // }; + // commands.spawn(light).id() + + match light_type { + LightType::Directional => commands + .spawn((DirectionalLight::default(), Transform::from_xyz(x, y, z))) + .id(), + _ => commands.spawn(AmbientLight::default()).id(), + } +} diff --git a/crates/processing_render/src/render/command.rs b/crates/processing_render/src/render/command.rs index 535dd4d..118bfd3 100644 --- a/crates/processing_render/src/render/command.rs +++ b/crates/processing_render/src/render/command.rs @@ -37,7 +37,7 @@ pub enum DrawCommand { angle: f32, }, Geometry(Entity), - Light(Entity), + // Light(Entity), } #[derive(Debug, Default, Component)] diff --git a/crates/processing_render/src/render/mod.rs b/crates/processing_render/src/render/mod.rs index 7871f14..15f2e7b 100644 --- a/crates/processing_render/src/render/mod.rs +++ b/crates/processing_render/src/render/mod.rs @@ -102,6 +102,7 @@ pub fn flush_draw_commands( >, p_images: Query<&Image>, p_geometries: Query<&Geometry>, + // p_lights: Query<&Light>, ) { for (graphics_entity, mut cmd_buffer, mut state, render_layers, projection, camera_transform) in graphics.iter_mut() @@ -234,7 +235,25 @@ pub fn flush_draw_commands( )); batch.draw_index += 1; - } + } // DrawCommand::Light(entity) => { + // let Some(light) = p_lights.get(entity).ok() else { + // warn!("Could not find Light for entity {:?}", entity); + // continue; + // }; + + // flush_batch(&mut res, &mut batch); + + // let pos = light.pos; + // res.commands.spawn(( + // PointLight { + // color: Color::srgba(1.0, 0.25, 0.44, 1.0), + // ..default() + // }, + // Transform::from_xyz(pos.x, pos.y, pos.z), + // )); + + // batch.draw_index += 1; + // } } } diff --git a/examples/lights.rs b/examples/lights.rs index ff116d5..b848219 100644 --- a/examples/lights.rs +++ b/examples/lights.rs @@ -2,6 +2,7 @@ mod glfw; use glfw::GlfwContext; use processing::prelude::*; +use processing_render::light::LightType; use processing_render::render::command::DrawCommand; fn main() { @@ -29,7 +30,9 @@ fn sketch() -> error::Result<()> { let graphics = graphics_create(surface, width, height)?; let box_geo = geometry_box(10.0, 10.0, 10.0)?; - let point_light = light_create()?; + // We will only declare lights in `setup` + // rather than calling some sort of `light()` method inside of `draw` + let _point_light = light_create(LightType::Point, 0.0, 0.0, 0.0)?; graphics_mode_3d(graphics)?; graphics_camera_position(graphics, 100.0, 100.0, 300.0)?; @@ -45,8 +48,6 @@ fn sketch() -> error::Result<()> { DrawCommand::BackgroundColor(bevy::color::Color::srgb(0.18, 0.20, 0.15)), )?; - graphics_record_command(graphics, DrawCommand::Light(point_light))?; - graphics_record_command(graphics, DrawCommand::PushMatrix)?; graphics_record_command(graphics, DrawCommand::Translate { x: 25.0, y: 25.0 })?; graphics_record_command(graphics, DrawCommand::Rotate { angle })?; From db5a8652d6ddcd08bd868b655bc091c4cc6ca29b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Mon, 9 Feb 2026 09:35:24 -0500 Subject: [PATCH 05/15] Remove Ambient light enum --- crates/processing_render/src/light.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/processing_render/src/light.rs b/crates/processing_render/src/light.rs index e6a2e35..d43510c 100644 --- a/crates/processing_render/src/light.rs +++ b/crates/processing_render/src/light.rs @@ -17,7 +17,6 @@ pub struct Light { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum LightType { - Ambient, Directional, Point, Spot, @@ -37,6 +36,6 @@ pub fn create( LightType::Directional => commands .spawn((DirectionalLight::default(), Transform::from_xyz(x, y, z))) .id(), - _ => commands.spawn(AmbientLight::default()).id(), + _ => commands.spawn(DirectionalLight::default()).id(), } } From cae5247cdb80bf53c8499c1ed0946ae9fb197cb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Mon, 9 Feb 2026 09:38:39 -0500 Subject: [PATCH 06/15] Remove commented out code for lights being drawn every frame --- crates/processing_render/src/light.rs | 6 ------ crates/processing_render/src/render/mod.rs | 20 +------------------- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/crates/processing_render/src/light.rs b/crates/processing_render/src/light.rs index d43510c..b4ab183 100644 --- a/crates/processing_render/src/light.rs +++ b/crates/processing_render/src/light.rs @@ -26,12 +26,6 @@ pub fn create( In((light_type, x, y, z)): In<(LightType, f32, f32, f32)>, mut commands: Commands, ) -> Entity { - // let light = Light { - // light_type: light_type, - // pos: Vec3::new(x, y, z), - // }; - // commands.spawn(light).id() - match light_type { LightType::Directional => commands .spawn((DirectionalLight::default(), Transform::from_xyz(x, y, z))) diff --git a/crates/processing_render/src/render/mod.rs b/crates/processing_render/src/render/mod.rs index 15f2e7b..c00b345 100644 --- a/crates/processing_render/src/render/mod.rs +++ b/crates/processing_render/src/render/mod.rs @@ -235,25 +235,7 @@ pub fn flush_draw_commands( )); batch.draw_index += 1; - } // DrawCommand::Light(entity) => { - // let Some(light) = p_lights.get(entity).ok() else { - // warn!("Could not find Light for entity {:?}", entity); - // continue; - // }; - - // flush_batch(&mut res, &mut batch); - - // let pos = light.pos; - // res.commands.spawn(( - // PointLight { - // color: Color::srgba(1.0, 0.25, 0.44, 1.0), - // ..default() - // }, - // Transform::from_xyz(pos.x, pos.y, pos.z), - // )); - - // batch.draw_index += 1; - // } + } } } From 656a87c892cd7134ba1ba05c8b5ff96e35109197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Mon, 9 Feb 2026 15:32:59 -0500 Subject: [PATCH 07/15] Create creation methods for directional, point, and spot lights --- crates/processing_render/src/lib.rs | 83 ++++++++++++++++++++++--- crates/processing_render/src/light.rs | 87 +++++++++++++++++++++------ examples/lights.rs | 3 +- 3 files changed, 147 insertions(+), 26 deletions(-) diff --git a/crates/processing_render/src/lib.rs b/crates/processing_render/src/lib.rs index f0b3cd1..64419df 100644 --- a/crates/processing_render/src/lib.rs +++ b/crates/processing_render/src/lib.rs @@ -26,10 +26,7 @@ use tracing::debug; use crate::geometry::{AttributeFormat, AttributeValue}; use crate::graphics::flush; use crate::{ - graphics::GraphicsPlugin, - image::ImagePlugin, - light::{LightPlugin, LightType}, - render::command::DrawCommand, + graphics::GraphicsPlugin, image::ImagePlugin, light::LightPlugin, render::command::DrawCommand, surface::SurfacePlugin, }; @@ -779,12 +776,84 @@ pub fn image_destroy(entity: Entity) -> error::Result<()> { }) } -// pub fn geometry_box(width: f32, height: f32, depth: f32) -> error::Result { -pub fn light_create(light_type: LightType, x: f32, y: f32, z: f32) -> error::Result { +pub fn light_create_directional( + x: f32, + y: f32, + z: f32, + r: f32, + g: f32, + b: f32, + a: f32, + illuminance: f32, +) -> error::Result { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached_with( + light::create_directional, + (x, y, z, r, g, b, a, illuminance), + ) + .unwrap()) + }) +} + +pub fn light_create_point( + x: f32, + y: f32, + z: f32, + r: f32, + g: f32, + b: f32, + a: f32, + intensity: f32, + range: f32, + radius: f32, +) -> error::Result { app_mut(|app| { Ok(app .world_mut() - .run_system_cached_with(light::create, (light_type, x, y, z)) + .run_system_cached_with( + light::create_point, + (x, y, z, r, g, b, a, intensity, range, radius), + ) + .unwrap()) + }) +} + +pub fn light_create_spot( + x: f32, + y: f32, + z: f32, + r: f32, + g: f32, + b: f32, + a: f32, + intensity: f32, + range: f32, + radius: f32, + inner_angle: f32, + outer_angle: f32, +) -> error::Result { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached_with( + light::create_spot, + ( + x, + y, + z, + r, + g, + b, + a, + intensity, + range, + radius, + inner_angle, + outer_angle, + ), + ) .unwrap()) }) } diff --git a/crates/processing_render/src/light.rs b/crates/processing_render/src/light.rs index b4ab183..c0b5dda 100644 --- a/crates/processing_render/src/light.rs +++ b/crates/processing_render/src/light.rs @@ -9,27 +9,80 @@ impl Plugin for LightPlugin { fn build(&self, _app: &mut App) {} } -#[derive(Component)] -pub struct Light { - pub light_type: LightType, - pub pos: Vec3, +pub fn create_directional( + In((px, py, pz, r, g, b, a, illuminance)): In<(f32, f32, f32, f32, f32, f32, f32, f32)>, + mut commands: Commands, +) -> Entity { + commands + .spawn(( + DirectionalLight { + illuminance, + color: Color::srgba(r, g, b, a), + ..default() + }, + Transform::from_xyz(px, py, pz), + )) + .id() } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum LightType { - Directional, - Point, - Spot, +pub fn create_point( + In((px, py, pz, r, g, b, a, intensity, range, radius)): In<( + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + )>, + mut commands: Commands, +) -> Entity { + commands + .spawn(( + PointLight { + intensity, + color: Color::srgba(r, g, b, a), + range, + radius, + ..default() + }, + Transform::from_xyz(px, py, pz), + )) + .id() } -pub fn create( - In((light_type, x, y, z)): In<(LightType, f32, f32, f32)>, +pub fn create_spot( + In((px, py, pz, r, g, b, a, intensity, range, radius, inner_angle, outer_angle)): In<( + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + )>, mut commands: Commands, ) -> Entity { - match light_type { - LightType::Directional => commands - .spawn((DirectionalLight::default(), Transform::from_xyz(x, y, z))) - .id(), - _ => commands.spawn(DirectionalLight::default()).id(), - } + commands + .spawn(( + SpotLight { + color: Color::srgba(r, g, b, a), + intensity, + range, + radius, + inner_angle, + outer_angle, + ..default() + }, + Transform::from_xyz(px, py, pz), + )) + .id() } diff --git a/examples/lights.rs b/examples/lights.rs index b848219..f16258b 100644 --- a/examples/lights.rs +++ b/examples/lights.rs @@ -2,7 +2,6 @@ mod glfw; use glfw::GlfwContext; use processing::prelude::*; -use processing_render::light::LightType; use processing_render::render::command::DrawCommand; fn main() { @@ -32,7 +31,7 @@ fn sketch() -> error::Result<()> { // We will only declare lights in `setup` // rather than calling some sort of `light()` method inside of `draw` - let _point_light = light_create(LightType::Point, 0.0, 0.0, 0.0)?; + let _dir_light = light_create_directional(0.0, 0.0, 0.0, 0.5, 0.43, 1.0, 1.0, 1000.0); graphics_mode_3d(graphics)?; graphics_camera_position(graphics, 100.0, 100.0, 300.0)?; From 84b94ddc6e8aeb21c3294be36590b9dddefc75f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Mon, 9 Feb 2026 15:35:17 -0500 Subject: [PATCH 08/15] Remove `Light` command --- crates/processing_render/src/render/command.rs | 1 - crates/processing_render/src/render/mod.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/crates/processing_render/src/render/command.rs b/crates/processing_render/src/render/command.rs index 118bfd3..f800a23 100644 --- a/crates/processing_render/src/render/command.rs +++ b/crates/processing_render/src/render/command.rs @@ -37,7 +37,6 @@ pub enum DrawCommand { angle: f32, }, Geometry(Entity), - // Light(Entity), } #[derive(Debug, Default, Component)] diff --git a/crates/processing_render/src/render/mod.rs b/crates/processing_render/src/render/mod.rs index c00b345..7871f14 100644 --- a/crates/processing_render/src/render/mod.rs +++ b/crates/processing_render/src/render/mod.rs @@ -102,7 +102,6 @@ pub fn flush_draw_commands( >, p_images: Query<&Image>, p_geometries: Query<&Geometry>, - // p_lights: Query<&Light>, ) { for (graphics_entity, mut cmd_buffer, mut state, render_layers, projection, camera_transform) in graphics.iter_mut() From a50e964b298f3d9057b9208c288ec34942828736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Mon, 9 Feb 2026 19:17:53 -0500 Subject: [PATCH 09/15] Use bevy::color::Color as an argument to lighting methods --- crates/processing_render/src/lib.rs | 27 ++++++-------------------- crates/processing_render/src/light.rs | 28 +++++++-------------------- examples/lights.rs | 8 +++++++- 3 files changed, 20 insertions(+), 43 deletions(-) diff --git a/crates/processing_render/src/lib.rs b/crates/processing_render/src/lib.rs index 64419df..7013e33 100644 --- a/crates/processing_render/src/lib.rs +++ b/crates/processing_render/src/lib.rs @@ -780,19 +780,13 @@ pub fn light_create_directional( x: f32, y: f32, z: f32, - r: f32, - g: f32, - b: f32, - a: f32, + color: Color, illuminance: f32, ) -> error::Result { app_mut(|app| { Ok(app .world_mut() - .run_system_cached_with( - light::create_directional, - (x, y, z, r, g, b, a, illuminance), - ) + .run_system_cached_with(light::create_directional, (x, y, z, color, illuminance)) .unwrap()) }) } @@ -801,10 +795,7 @@ pub fn light_create_point( x: f32, y: f32, z: f32, - r: f32, - g: f32, - b: f32, - a: f32, + color: Color, intensity: f32, range: f32, radius: f32, @@ -814,7 +805,7 @@ pub fn light_create_point( .world_mut() .run_system_cached_with( light::create_point, - (x, y, z, r, g, b, a, intensity, range, radius), + (x, y, z, color, intensity, range, radius), ) .unwrap()) }) @@ -824,10 +815,7 @@ pub fn light_create_spot( x: f32, y: f32, z: f32, - r: f32, - g: f32, - b: f32, - a: f32, + color: Color, intensity: f32, range: f32, radius: f32, @@ -843,10 +831,7 @@ pub fn light_create_spot( x, y, z, - r, - g, - b, - a, + color, intensity, range, radius, diff --git a/crates/processing_render/src/light.rs b/crates/processing_render/src/light.rs index c0b5dda..b96b9a1 100644 --- a/crates/processing_render/src/light.rs +++ b/crates/processing_render/src/light.rs @@ -10,14 +10,14 @@ impl Plugin for LightPlugin { } pub fn create_directional( - In((px, py, pz, r, g, b, a, illuminance)): In<(f32, f32, f32, f32, f32, f32, f32, f32)>, + In((px, py, pz, color, illuminance)): In<(f32, f32, f32, Color, f32)>, mut commands: Commands, ) -> Entity { commands .spawn(( DirectionalLight { illuminance, - color: Color::srgba(r, g, b, a), + color, ..default() }, Transform::from_xyz(px, py, pz), @@ -26,25 +26,14 @@ pub fn create_directional( } pub fn create_point( - In((px, py, pz, r, g, b, a, intensity, range, radius)): In<( - f32, - f32, - f32, - f32, - f32, - f32, - f32, - f32, - f32, - f32, - )>, + In((px, py, pz, color, intensity, range, radius)): In<(f32, f32, f32, Color, f32, f32, f32)>, mut commands: Commands, ) -> Entity { commands .spawn(( PointLight { intensity, - color: Color::srgba(r, g, b, a), + color, range, radius, ..default() @@ -55,14 +44,11 @@ pub fn create_point( } pub fn create_spot( - In((px, py, pz, r, g, b, a, intensity, range, radius, inner_angle, outer_angle)): In<( - f32, - f32, - f32, - f32, + In((px, py, pz, color, intensity, range, radius, inner_angle, outer_angle)): In<( f32, f32, f32, + Color, f32, f32, f32, @@ -74,7 +60,7 @@ pub fn create_spot( commands .spawn(( SpotLight { - color: Color::srgba(r, g, b, a), + color, intensity, range, radius, diff --git a/examples/lights.rs b/examples/lights.rs index f16258b..e480bba 100644 --- a/examples/lights.rs +++ b/examples/lights.rs @@ -31,7 +31,13 @@ fn sketch() -> error::Result<()> { // We will only declare lights in `setup` // rather than calling some sort of `light()` method inside of `draw` - let _dir_light = light_create_directional(0.0, 0.0, 0.0, 0.5, 0.43, 1.0, 1.0, 1000.0); + let _dir_light = light_create_directional( + 0.0, + 0.0, + 0.0, + bevy::color::Color::srgb(1.0, 0.0, 0.0), + 1000.0, + ); graphics_mode_3d(graphics)?; graphics_camera_position(graphics, 100.0, 100.0, 300.0)?; From ae1d3519af996400b943b9eed4cd6ae5db425f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Mon, 9 Feb 2026 19:20:57 -0500 Subject: [PATCH 10/15] set MaterialKey unlit = false --- crates/processing_render/src/render/material.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/processing_render/src/render/material.rs b/crates/processing_render/src/render/material.rs index fc2030c..e256056 100644 --- a/crates/processing_render/src/render/material.rs +++ b/crates/processing_render/src/render/material.rs @@ -10,7 +10,7 @@ impl MaterialKey { pub fn to_material(&self) -> StandardMaterial { StandardMaterial { base_color: Color::WHITE, - unlit: true, + unlit: false, cull_mode: None, base_color_texture: self.background_image.clone(), alpha_mode: if self.transparent { From 030516bbb2997e3e2b4205b5c460791313638c13 Mon Sep 17 00:00:00 2001 From: charlotte Date: Mon, 9 Feb 2026 17:41:14 -0800 Subject: [PATCH 11/15] Make light create accept a geometry entity to grab render layers. --- crates/processing_render/src/lib.rs | 26 +++++++------ crates/processing_render/src/light.rs | 53 ++++++++++++++++++++------- examples/lights.rs | 3 +- 3 files changed, 57 insertions(+), 25 deletions(-) diff --git a/crates/processing_render/src/lib.rs b/crates/processing_render/src/lib.rs index 7013e33..399c36c 100644 --- a/crates/processing_render/src/lib.rs +++ b/crates/processing_render/src/lib.rs @@ -777,6 +777,7 @@ pub fn image_destroy(entity: Entity) -> error::Result<()> { } pub fn light_create_directional( + graphics_entity: Entity, x: f32, y: f32, z: f32, @@ -784,14 +785,17 @@ pub fn light_create_directional( illuminance: f32, ) -> error::Result { app_mut(|app| { - Ok(app - .world_mut() - .run_system_cached_with(light::create_directional, (x, y, z, color, illuminance)) - .unwrap()) + app.world_mut() + .run_system_cached_with( + light::create_directional, + (graphics_entity, x, y, z, color, illuminance), + ) + .unwrap() }) } pub fn light_create_point( + graphics_entity: Entity, x: f32, y: f32, z: f32, @@ -801,17 +805,17 @@ pub fn light_create_point( radius: f32, ) -> error::Result { app_mut(|app| { - Ok(app - .world_mut() + app.world_mut() .run_system_cached_with( light::create_point, - (x, y, z, color, intensity, range, radius), + (graphics_entity, x, y, z, color, intensity, range, radius), ) - .unwrap()) + .unwrap() }) } pub fn light_create_spot( + graphics_entity: Entity, x: f32, y: f32, z: f32, @@ -823,11 +827,11 @@ pub fn light_create_spot( outer_angle: f32, ) -> error::Result { app_mut(|app| { - Ok(app - .world_mut() + app.world_mut() .run_system_cached_with( light::create_spot, ( + graphics_entity, x, y, z, @@ -839,7 +843,7 @@ pub fn light_create_spot( outer_angle, ), ) - .unwrap()) + .unwrap() }) } diff --git a/crates/processing_render/src/light.rs b/crates/processing_render/src/light.rs index b96b9a1..2c34eb8 100644 --- a/crates/processing_render/src/light.rs +++ b/crates/processing_render/src/light.rs @@ -1,7 +1,9 @@ //! A light in Processing //! -use bevy::prelude::*; +use bevy::{camera::visibility::RenderLayers, prelude::*}; + +use crate::{error::ProcessingError, graphics::Graphics}; pub struct LightPlugin; @@ -10,10 +12,14 @@ impl Plugin for LightPlugin { } pub fn create_directional( - In((px, py, pz, color, illuminance)): In<(f32, f32, f32, Color, f32)>, + In((entity, px, py, pz, color, illuminance)): In<(Entity, f32, f32, f32, Color, f32)>, mut commands: Commands, -) -> Entity { - commands + graphics: Query<&RenderLayers, With>, +) -> Result { + let layer = graphics + .get(entity) + .map_err(|_| ProcessingError::GraphicsNotFound)?; + Ok(commands .spawn(( DirectionalLight { illuminance, @@ -21,15 +27,29 @@ pub fn create_directional( ..default() }, Transform::from_xyz(px, py, pz), + layer.clone(), )) - .id() + .id()) } pub fn create_point( - In((px, py, pz, color, intensity, range, radius)): In<(f32, f32, f32, Color, f32, f32, f32)>, + In((entity, px, py, pz, color, intensity, range, radius)): In<( + Entity, + f32, + f32, + f32, + Color, + f32, + f32, + f32, + )>, mut commands: Commands, -) -> Entity { - commands + graphics: Query<&RenderLayers, With>, +) -> Result { + let layer = graphics + .get(entity) + .map_err(|_| ProcessingError::GraphicsNotFound)?; + Ok(commands .spawn(( PointLight { intensity, @@ -39,12 +59,14 @@ pub fn create_point( ..default() }, Transform::from_xyz(px, py, pz), + layer.clone(), )) - .id() + .id()) } pub fn create_spot( - In((px, py, pz, color, intensity, range, radius, inner_angle, outer_angle)): In<( + In((entity, px, py, pz, color, intensity, range, radius, inner_angle, outer_angle)): In<( + Entity, f32, f32, f32, @@ -56,8 +78,12 @@ pub fn create_spot( f32, )>, mut commands: Commands, -) -> Entity { - commands + graphics: Query<&RenderLayers, With>, +) -> Result { + let layer = graphics + .get(entity) + .map_err(|_| ProcessingError::GraphicsNotFound)?; + Ok(commands .spawn(( SpotLight { color, @@ -69,6 +95,7 @@ pub fn create_spot( ..default() }, Transform::from_xyz(px, py, pz), + layer.clone(), )) - .id() + .id()) } diff --git a/examples/lights.rs b/examples/lights.rs index e480bba..ce83ea2 100644 --- a/examples/lights.rs +++ b/examples/lights.rs @@ -32,12 +32,13 @@ fn sketch() -> error::Result<()> { // We will only declare lights in `setup` // rather than calling some sort of `light()` method inside of `draw` let _dir_light = light_create_directional( + graphics, 0.0, 0.0, 0.0, bevy::color::Color::srgb(1.0, 0.0, 0.0), 1000.0, - ); + )?; graphics_mode_3d(graphics)?; graphics_camera_position(graphics, 100.0, 100.0, 300.0)?; From f45af33727c49da6b08d38ebeaf82dc4ce905b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Tue, 10 Feb 2026 10:57:53 -0500 Subject: [PATCH 12/15] All lights working in lights example --- examples/lights.rs | 51 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/examples/lights.rs b/examples/lights.rs index ce83ea2..f4c90c0 100644 --- a/examples/lights.rs +++ b/examples/lights.rs @@ -31,18 +31,47 @@ fn sketch() -> error::Result<()> { // We will only declare lights in `setup` // rather than calling some sort of `light()` method inside of `draw` - let _dir_light = light_create_directional( + let dir_light = light_create_directional( graphics, 0.0, 0.0, 0.0, - bevy::color::Color::srgb(1.0, 0.0, 0.0), + bevy::color::Color::srgb(0.35, 0.25, 0.5), 1000.0, )?; + transform_set_position(dir_light, 10.0, 10.0, 0.0)?; + + let point_light = light_create_point( + graphics, + 100.0, + 100.0, + 10.0, + bevy::color::Color::srgb(1.0, 0.5, 0.25), + 1_000_000.0, + 20.0, + 0.0, + )?; + transform_set_position(point_light, 10.0, 10.0, 0.0)?; + transform_look_at(point_light, 0.0, 0.0, 0.0)?; + + let spot_light = light_create_spot( + graphics, + -15.0, + -15.0, + 0.0, + bevy::color::Color::srgb(0.25, 0.5, 0.88), + 1_000_000.0, + 25.0, + 0.6, + 0.8, + core::f32::consts::FRAC_PI_4, + )?; + transform_set_position(spot_light, 5.0, 7.5, 10.0)?; + transform_look_at(spot_light, 0.0, 0.0, 0.0)?; graphics_mode_3d(graphics)?; - graphics_camera_position(graphics, 100.0, 100.0, 300.0)?; - graphics_camera_look_at(graphics, 0.0, 0.0, 0.0)?; + transform_set_position(graphics, 100.0, 100.0, 300.0)?; + transform_look_at(graphics, 0.0, 0.0, 0.0)?; let mut angle = 0.0; @@ -54,15 +83,15 @@ fn sketch() -> error::Result<()> { DrawCommand::BackgroundColor(bevy::color::Color::srgb(0.18, 0.20, 0.15)), )?; - graphics_record_command(graphics, DrawCommand::PushMatrix)?; - graphics_record_command(graphics, DrawCommand::Translate { x: 25.0, y: 25.0 })?; - graphics_record_command(graphics, DrawCommand::Rotate { angle })?; - graphics_record_command(graphics, DrawCommand::Geometry(box_geo))?; - graphics_record_command(graphics, DrawCommand::PopMatrix)?; + // graphics_record_command(graphics, DrawCommand::PushMatrix)?; + // graphics_record_command(graphics, DrawCommand::Translate { x: 0.0, y: 0.0 })?; + // graphics_record_command(graphics, DrawCommand::Rotate { angle })?; + // graphics_record_command(graphics, DrawCommand::Geometry(box_geo))?; + // graphics_record_command(graphics, DrawCommand::PopMatrix)?; graphics_record_command(graphics, DrawCommand::PushMatrix)?; - graphics_record_command(graphics, DrawCommand::Translate { x: -25.0, y: 20.0 })?; - graphics_record_command(graphics, DrawCommand::Scale { x: 1.5, y: 2.0 })?; + graphics_record_command(graphics, DrawCommand::Translate { x: 0.0, y: 0.0 })?; + // graphics_record_command(graphics, DrawCommand::Scale { x: 5.0, y: 5.0 })?; graphics_record_command(graphics, DrawCommand::Rotate { angle })?; graphics_record_command(graphics, DrawCommand::Geometry(box_geo))?; graphics_record_command(graphics, DrawCommand::PopMatrix)?; From b9e339e69851ac22e16dc08d502b0757e826415a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Tue, 10 Feb 2026 15:27:44 -0500 Subject: [PATCH 13/15] remove positional arguments in favor of using transform_set_position --- crates/processing_render/src/lib.rs | 16 ++-------------- crates/processing_render/src/light.rs | 21 +++------------------ examples/lights.rs | 16 ++-------------- 3 files changed, 7 insertions(+), 46 deletions(-) diff --git a/crates/processing_render/src/lib.rs b/crates/processing_render/src/lib.rs index 399c36c..b9f4348 100644 --- a/crates/processing_render/src/lib.rs +++ b/crates/processing_render/src/lib.rs @@ -778,9 +778,6 @@ pub fn image_destroy(entity: Entity) -> error::Result<()> { pub fn light_create_directional( graphics_entity: Entity, - x: f32, - y: f32, - z: f32, color: Color, illuminance: f32, ) -> error::Result { @@ -788,7 +785,7 @@ pub fn light_create_directional( app.world_mut() .run_system_cached_with( light::create_directional, - (graphics_entity, x, y, z, color, illuminance), + (graphics_entity, color, illuminance), ) .unwrap() }) @@ -796,9 +793,6 @@ pub fn light_create_directional( pub fn light_create_point( graphics_entity: Entity, - x: f32, - y: f32, - z: f32, color: Color, intensity: f32, range: f32, @@ -808,7 +802,7 @@ pub fn light_create_point( app.world_mut() .run_system_cached_with( light::create_point, - (graphics_entity, x, y, z, color, intensity, range, radius), + (graphics_entity, color, intensity, range, radius), ) .unwrap() }) @@ -816,9 +810,6 @@ pub fn light_create_point( pub fn light_create_spot( graphics_entity: Entity, - x: f32, - y: f32, - z: f32, color: Color, intensity: f32, range: f32, @@ -832,9 +823,6 @@ pub fn light_create_spot( light::create_spot, ( graphics_entity, - x, - y, - z, color, intensity, range, diff --git a/crates/processing_render/src/light.rs b/crates/processing_render/src/light.rs index 2c34eb8..423703c 100644 --- a/crates/processing_render/src/light.rs +++ b/crates/processing_render/src/light.rs @@ -12,7 +12,7 @@ impl Plugin for LightPlugin { } pub fn create_directional( - In((entity, px, py, pz, color, illuminance)): In<(Entity, f32, f32, f32, Color, f32)>, + In((entity, color, illuminance)): In<(Entity, Color, f32)>, mut commands: Commands, graphics: Query<&RenderLayers, With>, ) -> Result { @@ -26,23 +26,13 @@ pub fn create_directional( color, ..default() }, - Transform::from_xyz(px, py, pz), layer.clone(), )) .id()) } pub fn create_point( - In((entity, px, py, pz, color, intensity, range, radius)): In<( - Entity, - f32, - f32, - f32, - Color, - f32, - f32, - f32, - )>, + In((entity, color, intensity, range, radius)): In<(Entity, Color, f32, f32, f32)>, mut commands: Commands, graphics: Query<&RenderLayers, With>, ) -> Result { @@ -58,18 +48,14 @@ pub fn create_point( radius, ..default() }, - Transform::from_xyz(px, py, pz), layer.clone(), )) .id()) } pub fn create_spot( - In((entity, px, py, pz, color, intensity, range, radius, inner_angle, outer_angle)): In<( + In((entity, color, intensity, range, radius, inner_angle, outer_angle)): In<( Entity, - f32, - f32, - f32, Color, f32, f32, @@ -94,7 +80,6 @@ pub fn create_spot( outer_angle, ..default() }, - Transform::from_xyz(px, py, pz), layer.clone(), )) .id()) diff --git a/examples/lights.rs b/examples/lights.rs index f4c90c0..e9c9d18 100644 --- a/examples/lights.rs +++ b/examples/lights.rs @@ -31,21 +31,12 @@ fn sketch() -> error::Result<()> { // We will only declare lights in `setup` // rather than calling some sort of `light()` method inside of `draw` - let dir_light = light_create_directional( - graphics, - 0.0, - 0.0, - 0.0, - bevy::color::Color::srgb(0.35, 0.25, 0.5), - 1000.0, - )?; + let dir_light = + light_create_directional(graphics, bevy::color::Color::srgb(0.35, 0.25, 0.5), 1000.0)?; transform_set_position(dir_light, 10.0, 10.0, 0.0)?; let point_light = light_create_point( graphics, - 100.0, - 100.0, - 10.0, bevy::color::Color::srgb(1.0, 0.5, 0.25), 1_000_000.0, 20.0, @@ -56,9 +47,6 @@ fn sketch() -> error::Result<()> { let spot_light = light_create_spot( graphics, - -15.0, - -15.0, - 0.0, bevy::color::Color::srgb(0.25, 0.5, 0.88), 1_000_000.0, 25.0, From ce9d61731733caf892157ed737c562a9b00c05f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Tue, 10 Feb 2026 16:50:05 -0500 Subject: [PATCH 14/15] example with all lights --- examples/lights.rs | 52 ++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/examples/lights.rs b/examples/lights.rs index e9c9d18..d2aa4b8 100644 --- a/examples/lights.rs +++ b/examples/lights.rs @@ -27,34 +27,48 @@ fn sketch() -> error::Result<()> { let surface = glfw_ctx.create_surface(width, height, scale_factor)?; let graphics = graphics_create(surface, width, height)?; - let box_geo = geometry_box(10.0, 10.0, 10.0)?; + let box_geo = geometry_box(100.0, 100.0, 100.0)?; // We will only declare lights in `setup` // rather than calling some sort of `light()` method inside of `draw` - let dir_light = - light_create_directional(graphics, bevy::color::Color::srgb(0.35, 0.25, 0.5), 1000.0)?; - transform_set_position(dir_light, 10.0, 10.0, 0.0)?; - let point_light = light_create_point( + // create a directional light + let _dir_light = + light_create_directional(graphics, bevy::color::Color::srgb(0.35, 0.25, 0.5), 500.0)?; + + // create a point light + let point_light_a = light_create_point( graphics, bevy::color::Color::srgb(1.0, 0.5, 0.25), 1_000_000.0, - 20.0, - 0.0, + 200.0, + 0.5, + )?; + transform_set_position(point_light_a, -25.0, 5.0, 51.0)?; + transform_look_at(point_light_a, 0.0, 0.0, 0.0)?; + + // create another point light + let point_light_b = light_create_point( + graphics, + bevy::color::Color::srgb(0.0, 0.5, 0.75), + 2_000_000.0, + 200.0, + 0.25, )?; - transform_set_position(point_light, 10.0, 10.0, 0.0)?; - transform_look_at(point_light, 0.0, 0.0, 0.0)?; + transform_set_position(point_light_b, 0.0, 5.0, 50.5)?; + transform_look_at(point_light_b, 0.0, 0.0, 0.0)?; + // and a spot light, too! let spot_light = light_create_spot( graphics, - bevy::color::Color::srgb(0.25, 0.5, 0.88), - 1_000_000.0, - 25.0, - 0.6, - 0.8, + bevy::color::Color::srgb(0.25, 0.8, 0.19), + 15.0 * 1_000_000.0, + 200.0, + 0.84, + 0.0, core::f32::consts::FRAC_PI_4, )?; - transform_set_position(spot_light, 5.0, 7.5, 10.0)?; + transform_set_position(spot_light, 40.0, 0.0, 70.0)?; transform_look_at(spot_light, 0.0, 0.0, 0.0)?; graphics_mode_3d(graphics)?; @@ -71,15 +85,7 @@ fn sketch() -> error::Result<()> { DrawCommand::BackgroundColor(bevy::color::Color::srgb(0.18, 0.20, 0.15)), )?; - // graphics_record_command(graphics, DrawCommand::PushMatrix)?; - // graphics_record_command(graphics, DrawCommand::Translate { x: 0.0, y: 0.0 })?; - // graphics_record_command(graphics, DrawCommand::Rotate { angle })?; - // graphics_record_command(graphics, DrawCommand::Geometry(box_geo))?; - // graphics_record_command(graphics, DrawCommand::PopMatrix)?; - graphics_record_command(graphics, DrawCommand::PushMatrix)?; - graphics_record_command(graphics, DrawCommand::Translate { x: 0.0, y: 0.0 })?; - // graphics_record_command(graphics, DrawCommand::Scale { x: 5.0, y: 5.0 })?; graphics_record_command(graphics, DrawCommand::Rotate { angle })?; graphics_record_command(graphics, DrawCommand::Geometry(box_geo))?; graphics_record_command(graphics, DrawCommand::PopMatrix)?; From 439801218c5020a2b8c5e0078c827ea80967def1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Tue, 10 Feb 2026 17:25:30 -0500 Subject: [PATCH 15/15] ffi methods --- crates/processing_ffi/src/lib.rs | 55 ++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/crates/processing_ffi/src/lib.rs b/crates/processing_ffi/src/lib.rs index cebbef7..ad795cf 100644 --- a/crates/processing_ffi/src/lib.rs +++ b/crates/processing_ffi/src/lib.rs @@ -1091,3 +1091,58 @@ pub extern "C" fn processing_geometry_box(width: f32, height: f32, depth: f32) - .map(|e| e.to_bits()) .unwrap_or(0) } + +#[unsafe(no_mangle)] +pub extern "C" fn processing_light_create_directional( + graphics_id: u64, + color: Color, + illuminance: f32, +) -> u64 { + error::clear_error(); + let graphics_entity = Entity::from_bits(graphics_id); + error::check(|| light_create_directional(graphics_entity, color.into(), illuminance)) + .map(|e| e.to_bits()) + .unwrap_or(0) +} + +#[unsafe(no_mangle)] +pub extern "C" fn processing_light_create_point( + graphics_id: u64, + color: Color, + intensity: f32, + range: f32, + radius: f32, +) -> u64 { + error::clear_error(); + let graphics_entity = Entity::from_bits(graphics_id); + error::check(|| light_create_point(graphics_entity, color.into(), intensity, range, radius)) + .map(|e| e.to_bits()) + .unwrap_or(0) +} + +#[unsafe(no_mangle)] +pub extern "C" fn processing_light_create_spot( + graphics_id: u64, + color: Color, + intensity: f32, + range: f32, + radius: f32, + inner_angle: f32, + outer_angle: f32, +) -> u64 { + error::clear_error(); + let graphics_entity = Entity::from_bits(graphics_id); + error::check(|| { + light_create_spot( + graphics_entity, + color.into(), + intensity, + range, + radius, + inner_angle, + outer_angle, + ) + }) + .map(|e| e.to_bits()) + .unwrap_or(0) +}