From e28d8b2a9366d631954bee525fdcd536d99cfc30 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 1/4] `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 a0554f94fefe38011bd8249d6f3058c838fff62a 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 2/4] 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 206456ce48cfa84152d4f6fd6af048e340f48daa 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 3/4] 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 760345e83ec649f784b8d538a4edac29fe3993f3 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 4/4] 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 6f60575..5c201be 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; @@ -24,7 +25,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, }; @@ -247,6 +251,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)); @@ -702,6 +707,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 })?;