Skip to content

Commit 907ff07

Browse files
committed
Implement background.
1 parent 2232a0d commit 907ff07

File tree

9 files changed

+147
-18
lines changed

9 files changed

+147
-18
lines changed

core/src/processing/webgpu/PGraphicsWebGPU.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ public void setSize(int w, int h) {
2626
}
2727
}
2828

29+
@Override
30+
public void beginDraw() {
31+
super.beginDraw();
32+
checkSettings();
33+
}
34+
2935
@Override
3036
public void endDraw() {
3137
super.endDraw();
@@ -35,7 +41,18 @@ public void endDraw() {
3541
@Override
3642
public void dispose() {
3743
super.dispose();
38-
44+
if (windowId != 0) {
45+
PWebGPU.destroySurface(windowId);
46+
windowId = 0;
47+
}
3948
PWebGPU.exit();
4049
}
50+
51+
@Override
52+
protected void backgroundImpl() {
53+
if (windowId == 0) {
54+
return;
55+
}
56+
PWebGPU.backgroundColor(windowId, backgroundR, backgroundG, backgroundB, backgroundA);
57+
}
4158
}

core/src/processing/webgpu/PWebGPU.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
import processing.core.NativeLibrary;
44

5+
import java.lang.foreign.Arena;
56
import java.lang.foreign.MemorySegment;
67

78
import static java.lang.foreign.MemorySegment.NULL;
89
import static processing.ffi.processing_h.*;
10+
import processing.ffi.Color;
911

1012
/**
1113
* PWebGPU provides the native interface layer for libProcessing's WebGPU support.
@@ -47,6 +49,16 @@ public static long createSurface(long windowHandle, int width, int height, float
4749
return windowId;
4850
}
4951

52+
/**
53+
* Destroys a WebGPU surface.
54+
*
55+
* @param windowId The window ID returned from createSurface
56+
*/
57+
public static void destroySurface(long windowId) {
58+
processing_destroy_surface(windowId);
59+
checkError();
60+
}
61+
5062
/**
5163
* Updates a window's size.
5264
*
@@ -55,7 +67,7 @@ public static long createSurface(long windowHandle, int width, int height, float
5567
* @param height New physical window height in pixels
5668
*/
5769
public static void windowResized(long windowId, int width, int height) {
58-
processing_window_resized(windowId, width, height);
70+
processing_resize_surface(windowId, width, height);
5971
checkError();
6072
}
6173

@@ -75,6 +87,20 @@ public static void exit() {
7587
checkError();
7688
}
7789

90+
public static void backgroundColor(long windowId, float r, float g, float b, float a) {
91+
try (Arena arena = Arena.ofConfined()) {
92+
MemorySegment color = Color.allocate(arena);
93+
94+
Color.r(color, r);
95+
Color.g(color, g);
96+
Color.b(color, b);
97+
Color.a(color, a);
98+
99+
processing_background_color(windowId, color);
100+
checkError();
101+
}
102+
}
103+
78104
/**
79105
* Checks for errors from the native library and throws a PWebGPUException if an error occurred.
80106
*/

libProcessing/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

libProcessing/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
[workspace]
22
resolver = "3"
33
members = ["ffi","renderer"]
4+
5+
[workspace.dependencies]
6+
bevy = { version = "0.17", no-default-features = true, features = [
7+
"bevy_render",
8+
"bevy_color",
9+
] }

libProcessing/ffi/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ crate-type = ["cdylib"]
99

1010
[dependencies]
1111
renderer = { path = "../renderer" }
12+
bevy = { workspace = true }
1213

1314
[build-dependencies]
1415
cbindgen = "0.29"

libProcessing/ffi/src/color.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// A sRGB (?) color
2+
#[repr(C)]
3+
pub struct Color {
4+
pub r: f32,
5+
pub g: f32,
6+
pub b: f32,
7+
pub a: f32,
8+
}
9+
10+
impl From<Color> for bevy::color::Color {
11+
fn from(color: Color) -> Self {
12+
bevy::color::Color::srgba(color.r, color.g, color.b, color.a)
13+
}
14+
}

libProcessing/ffi/src/lib.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
use crate::color::Color;
2+
use bevy::prelude::Entity;
3+
4+
mod color;
15
mod error;
26

37
/// Initialize libProcessing.
@@ -31,16 +35,41 @@ pub extern "C" fn processing_create_surface(
3135
.unwrap_or(0)
3236
}
3337

38+
/// Destroy the surface associated with the given window ID.
39+
///
40+
/// SAFETY:
41+
/// - Init and create_surface have been called.
42+
/// - window_id is a valid ID returned from create_surface.
43+
/// - This is called from the same thread as init.
44+
#[unsafe(no_mangle)]
45+
pub extern "C" fn processing_destroy_surface(window_id: u64) {
46+
error::clear_error();
47+
let window_entity = Entity::from_bits(window_id);
48+
error::check(|| renderer::destroy_surface(window_entity));
49+
}
50+
3451
/// Update window size when resized.
3552
///
3653
/// SAFETY:
3754
/// - Init and create_surface have been called.
3855
/// - window_id is a valid ID returned from create_surface.
3956
/// - This is called from the same thread as init.
4057
#[unsafe(no_mangle)]
41-
pub extern "C" fn processing_window_resized(window_id: u64, width: u32, height: u32) {
58+
pub extern "C" fn processing_resize_surface(window_id: u64, width: u32, height: u32) {
59+
error::clear_error();
60+
let window_entity = Entity::from_bits(window_id);
61+
error::check(|| renderer::resize_surface(window_entity, width, height));
62+
}
63+
64+
/// Set the background color for the given window.
65+
///
66+
/// SAFETY:
67+
/// - This is called from the same thread as init.
68+
#[unsafe(no_mangle)]
69+
pub extern "C" fn processing_background_color(window_id: u64, color: Color) {
4270
error::clear_error();
43-
error::check(|| renderer::window_resized(window_id, width, height));
71+
let window_entity = Entity::from_bits(window_id);
72+
error::check(|| renderer::background_color(window_entity, color.into()));
4473
}
4574

4675
/// Step the application forward.

libProcessing/renderer/Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ edition = "2024"
66
[dependencies]
77
tracing = "0.1"
88
tracing-subscriber = "0.3"
9-
bevy = { version = "0.17", no-default-features = true, features = [
10-
"bevy_render"
11-
] }
9+
bevy = { workspace = true }
1210
thiserror = "2"
1311
raw-window-handle = "0.6"
1412

libProcessing/renderer/src/lib.rs

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,27 @@ use crate::error::Result;
44
use bevy::app::{App, AppExit};
55
use bevy::log::tracing_subscriber;
66
use bevy::prelude::*;
7-
use bevy::window::{
8-
RawHandleWrapper, Window, WindowResolution, WindowWrapper,
9-
};
7+
use bevy::window::{RawHandleWrapper, Window, WindowRef, WindowResolution, WindowWrapper};
108
use raw_window_handle::{
119
DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, RawDisplayHandle,
1210
RawWindowHandle, WindowHandle,
1311
};
1412
use std::cell::RefCell;
1513
use std::num::NonZero;
14+
use std::sync::atomic::AtomicU32;
1615
use std::sync::OnceLock;
16+
use bevy::camera::RenderTarget;
17+
use bevy::camera::visibility::RenderLayers;
1718
use tracing::debug;
1819

1920
static IS_INIT: OnceLock<()> = OnceLock::new();
21+
static WINDOW_COUNT: AtomicU32 = AtomicU32::new(0);
2022

2123
thread_local! {
2224
static APP: OnceLock<RefCell<App>> = OnceLock::default();
2325
}
2426

27+
2528
fn app<T>(cb: impl FnOnce(&App) -> Result<T>) -> Result<T> {
2629
let res = APP.with(|app_lock| {
2730
let app = app_lock
@@ -144,7 +147,7 @@ pub fn create_surface(
144147
let handle_wrapper = RawHandleWrapper::new(&window_wrapper)?;
145148

146149
let entity_id = app_mut(|app| {
147-
let entity = app
150+
let mut window = app
148151
.world_mut()
149152
.spawn((
150153
Window {
@@ -153,22 +156,44 @@ pub fn create_surface(
153156
..default()
154157
},
155158
handle_wrapper,
156-
))
157-
.id();
159+
));
160+
161+
let count = WINDOW_COUNT.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
162+
let render_layer = RenderLayers::none().with(count as usize);
158163

159-
// TODO: spawn a camera for this window with a render target of this window
164+
let window_entity = window.id();
165+
window.with_children(|parent| {
166+
parent.spawn((
167+
Camera3d::default(),
168+
Camera {
169+
target: RenderTarget::Window(WindowRef::Entity(window_entity)),
170+
..default()
171+
},
172+
Projection::Orthographic(OrthographicProjection::default_3d()),
173+
render_layer,
174+
));
175+
});
160176

161-
Ok(entity.to_bits())
177+
Ok(window_entity.to_bits())
162178
})?;
163179

164180
Ok(entity_id)
165181
}
166182

183+
pub fn destroy_surface(window_entity: Entity) -> Result<()>{
184+
app_mut(|app| {
185+
if app.world_mut().get::<Window>(window_entity).is_some() {
186+
app.world_mut().despawn(window_entity);
187+
WINDOW_COUNT.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
188+
}
189+
Ok(())
190+
})
191+
}
192+
167193
/// Update window size when resized.
168-
pub fn window_resized(window_id: u64, width: u32, height: u32) -> Result<()> {
194+
pub fn resize_surface(window_entity: Entity, width: u32, height: u32) -> Result<()> {
169195
app_mut(|app| {
170-
let entity = Entity::from_bits(window_id);
171-
if let Some(mut window) = app.world_mut().get_mut::<Window>(entity) {
196+
if let Some(mut window) = app.world_mut().get_mut::<Window>(window_entity) {
172197
window.resolution.set_physical_resolution(width, height);
173198
Ok(())
174199
} else {
@@ -240,6 +265,18 @@ pub fn exit(exit_code: u8) -> Result<()> {
240265
})
241266
}
242267

268+
pub fn background_color(window_entity: Entity, color: Color) -> Result<()> {
269+
app_mut(|app| {
270+
let mut camera_query = app.world_mut().query::<(&mut Camera, &ChildOf)>();
271+
for (mut camera, parent) in camera_query.iter_mut(&mut app.world_mut()) {
272+
if parent.parent() == window_entity {
273+
camera.clear_color = ClearColorConfig::Custom(color);
274+
}
275+
}
276+
Ok(())
277+
})
278+
}
279+
243280
fn setup_tracing() -> Result<()> {
244281
let subscriber = tracing_subscriber::FmtSubscriber::new();
245282
tracing::subscriber::set_global_default(subscriber)?;

0 commit comments

Comments
 (0)