1- use bevy:: prelude:: Entity ;
1+ use bevy:: {
2+ prelude:: Entity ,
3+ render:: render_resource:: { Extent3d , TextureFormat } ,
4+ } ;
25use processing:: prelude:: * ;
36
47use crate :: color:: Color ;
@@ -26,43 +29,43 @@ pub extern "C" fn processing_init() {
2629/// - window_handle is a valid GLFW window pointer.
2730/// - This is called from the same thread as init.
2831#[ unsafe( no_mangle) ]
29- pub extern "C" fn processing_create_surface (
32+ pub extern "C" fn processing_surface_create (
3033 window_handle : u64 ,
3134 display_handle : u64 ,
3235 width : u32 ,
3336 height : u32 ,
3437 scale_factor : f32 ,
3538) -> u64 {
3639 error:: clear_error ( ) ;
37- error:: check ( || create_surface ( window_handle, display_handle, width, height, scale_factor) )
40+ error:: check ( || surface_create ( window_handle, display_handle, width, height, scale_factor) )
3841 . map ( |e| e. to_bits ( ) )
3942 . unwrap_or ( 0 )
4043}
4144
4245/// Destroy the surface associated with the given window ID.
4346///
4447/// SAFETY:
45- /// - Init and create_surface have been called.
46- /// - window_id is a valid ID returned from create_surface .
48+ /// - Init and surface_create have been called.
49+ /// - window_id is a valid ID returned from surface_create .
4750/// - This is called from the same thread as init.
4851#[ unsafe( no_mangle) ]
49- pub extern "C" fn processing_destroy_surface ( window_id : u64 ) {
52+ pub extern "C" fn processing_surface_destroy ( window_id : u64 ) {
5053 error:: clear_error ( ) ;
5154 let window_entity = Entity :: from_bits ( window_id) ;
52- error:: check ( || destroy_surface ( window_entity) ) ;
55+ error:: check ( || surface_destroy ( window_entity) ) ;
5356}
5457
5558/// Update window size when resized.
5659///
5760/// SAFETY:
58- /// - Init and create_surface have been called.
59- /// - window_id is a valid ID returned from create_surface .
61+ /// - Init and surface_create have been called.
62+ /// - window_id is a valid ID returned from surface_create .
6063/// - This is called from the same thread as init.
6164#[ unsafe( no_mangle) ]
62- pub extern "C" fn processing_resize_surface ( window_id : u64 , width : u32 , height : u32 ) {
65+ pub extern "C" fn processing_surface_resize ( window_id : u64 , width : u32 , height : u32 ) {
6366 error:: clear_error ( ) ;
6467 let window_entity = Entity :: from_bits ( window_id) ;
65- error:: check ( || resize_surface ( window_entity, width, height) ) ;
68+ error:: check ( || surface_resize ( window_entity, width, height) ) ;
6669}
6770
6871/// Set the background color for the given window.
@@ -73,7 +76,21 @@ pub extern "C" fn processing_resize_surface(window_id: u64, width: u32, height:
7376pub extern "C" fn processing_background_color ( window_id : u64 , color : Color ) {
7477 error:: clear_error ( ) ;
7578 let window_entity = Entity :: from_bits ( window_id) ;
76- error:: check ( || background_color ( window_entity, color. into ( ) ) ) ;
79+ error:: check ( || record_command ( window_entity, DrawCommand :: BackgroundColor ( color. into ( ) ) ) ) ;
80+ }
81+
82+ /// Set the background image for the given window.
83+ ///
84+ /// SAFETY:
85+ /// - This is called from the same thread as init.
86+ /// - image_id is a valid ID returned from processing_image_create.
87+ /// - The image has been fully uploaded.
88+ #[ unsafe( no_mangle) ]
89+ pub extern "C" fn processing_background_image ( window_id : u64 , image_id : u64 ) {
90+ error:: clear_error ( ) ;
91+ let window_entity = Entity :: from_bits ( window_id) ;
92+ let image_entity = Entity :: from_bits ( image_id) ;
93+ error:: check ( || record_command ( window_entity, DrawCommand :: BackgroundImage ( image_entity) ) ) ;
7794}
7895
7996/// Begins the draw for the given window.
@@ -126,8 +143,8 @@ pub extern "C" fn processing_exit(exit_code: u8) {
126143/// Set the fill color.
127144///
128145/// SAFETY:
129- /// - Init and create_surface have been called.
130- /// - window_id is a valid ID returned from create_surface .
146+ /// - Init and surface_create have been called.
147+ /// - window_id is a valid ID returned from surface_create .
131148/// - This is called from the same thread as init.
132149#[ unsafe( no_mangle) ]
133150pub extern "C" fn processing_set_fill ( window_id : u64 , r : f32 , g : f32 , b : f32 , a : f32 ) {
@@ -140,8 +157,8 @@ pub extern "C" fn processing_set_fill(window_id: u64, r: f32, g: f32, b: f32, a:
140157/// Set the stroke color.
141158///
142159/// SAFETY:
143- /// - Init and create_surface have been called.
144- /// - window_id is a valid ID returned from create_surface .
160+ /// - Init and surface_create have been called.
161+ /// - window_id is a valid ID returned from surface_create .
145162/// - This is called from the same thread as init.
146163#[ unsafe( no_mangle) ]
147164pub extern "C" fn processing_set_stroke_color ( window_id : u64 , r : f32 , g : f32 , b : f32 , a : f32 ) {
@@ -154,8 +171,8 @@ pub extern "C" fn processing_set_stroke_color(window_id: u64, r: f32, g: f32, b:
154171/// Set the stroke weight.
155172///
156173/// SAFETY:
157- /// - Init and create_surface have been called.
158- /// - window_id is a valid ID returned from create_surface .
174+ /// - Init and surface_create have been called.
175+ /// - window_id is a valid ID returned from surface_create .
159176/// - This is called from the same thread as init.
160177#[ unsafe( no_mangle) ]
161178pub extern "C" fn processing_set_stroke_weight ( window_id : u64 , weight : f32 ) {
@@ -167,8 +184,8 @@ pub extern "C" fn processing_set_stroke_weight(window_id: u64, weight: f32) {
167184/// Disable fill for subsequent shapes.
168185///
169186/// SAFETY:
170- /// - Init and create_surface have been called.
171- /// - window_id is a valid ID returned from create_surface .
187+ /// - Init and surface_create have been called.
188+ /// - window_id is a valid ID returned from surface_create .
172189/// - This is called from the same thread as init.
173190#[ unsafe( no_mangle) ]
174191pub extern "C" fn processing_no_fill ( window_id : u64 ) {
@@ -180,8 +197,8 @@ pub extern "C" fn processing_no_fill(window_id: u64) {
180197/// Disable stroke for subsequent shapes.
181198///
182199/// SAFETY:
183- /// - Init and create_surface have been called.
184- /// - window_id is a valid ID returned from create_surface .
200+ /// - Init and surface_create have been called.
201+ /// - window_id is a valid ID returned from surface_create .
185202/// - This is called from the same thread as init.
186203#[ unsafe( no_mangle) ]
187204pub extern "C" fn processing_no_stroke ( window_id : u64 ) {
@@ -193,8 +210,8 @@ pub extern "C" fn processing_no_stroke(window_id: u64) {
193210/// Draw a rectangle.
194211///
195212/// SAFETY:
196- /// - Init and create_surface have been called.
197- /// - window_id is a valid ID returned from create_surface .
213+ /// - Init and surface_create have been called.
214+ /// - window_id is a valid ID returned from surface_create .
198215/// - This is called from the same thread as init.
199216#[ unsafe( no_mangle) ]
200217pub extern "C" fn processing_rect (
@@ -223,3 +240,113 @@ pub extern "C" fn processing_rect(
223240 )
224241 } ) ;
225242}
243+
244+ /// Create an image from raw pixel data.
245+ ///
246+ /// # Safety
247+ /// - Init has been called.
248+ /// - data is a valid pointer to data_len bytes of RGBA pixel data.
249+ /// - This is called from the same thread as init.
250+ #[ unsafe( no_mangle) ]
251+ pub unsafe extern "C" fn processing_image_create (
252+ width : u32 ,
253+ height : u32 ,
254+ data : * const u8 ,
255+ data_len : usize ,
256+ ) -> u64 {
257+ error:: clear_error ( ) ;
258+ // SAFETY: Caller must ensure that `data` is valid for `data_len` bytes.
259+ let data = unsafe { std:: slice:: from_raw_parts ( data, data_len) } ;
260+ error:: check ( || {
261+ let size = Extent3d {
262+ width,
263+ height,
264+ depth_or_array_layers : 1 ,
265+ } ;
266+ image_create ( size, data. to_vec ( ) , TextureFormat :: Rgba8UnormSrgb )
267+ } )
268+ . map ( |entity| entity. to_bits ( ) )
269+ . unwrap_or ( 0 )
270+ }
271+
272+ /// Load an image from a file path.
273+ ///
274+ /// # Safety
275+ /// - Init has been called.
276+ /// - path is a valid null-terminated C string.
277+ /// - This is called from the same thread as init.
278+ ///
279+ /// Note: This function is currently synchronous but Bevy's asset loading is async.
280+ /// The image may not be immediately available. This needs to be improved.
281+ #[ unsafe( no_mangle) ]
282+ pub unsafe extern "C" fn processing_image_load ( path : * const std:: ffi:: c_char ) -> u64 {
283+ error:: clear_error ( ) ;
284+
285+ // SAFETY: Caller guarantees path is a valid C string
286+ let c_str = unsafe { std:: ffi:: CStr :: from_ptr ( path) } ;
287+ let path_str = match c_str. to_str ( ) {
288+ Ok ( s) => s,
289+ Err ( _) => {
290+ error:: set_error ( "Invalid UTF-8 in image path" ) ;
291+ return 0 ;
292+ }
293+ } ;
294+
295+ error:: check ( || image_load ( path_str) )
296+ . map ( |entity| entity. to_bits ( ) )
297+ . unwrap_or ( 0 )
298+ }
299+
300+ #[ unsafe( no_mangle) ]
301+ pub extern "C" fn processing_image_resize ( image_id : u64 , new_width : u32 , new_height : u32 ) {
302+ error:: clear_error ( ) ;
303+ let image_entity = Entity :: from_bits ( image_id) ;
304+ let new_size = Extent3d {
305+ width : new_width,
306+ height : new_height,
307+ depth_or_array_layers : 1 ,
308+ } ;
309+ error:: check ( || image_resize ( image_entity, new_size) ) ;
310+ }
311+
312+ /// Load pixels from an image into a caller-provided buffer.
313+ ///
314+ /// # Safety
315+ /// - Init and image_create have been called.
316+ /// - image_id is a valid ID returned from image_create.
317+ /// - buffer is a valid pointer to at least buffer_len Color elements.
318+ /// - buffer_len must equal width * height of the image.
319+ /// - This is called from the same thread as init.
320+ #[ unsafe( no_mangle) ]
321+ pub unsafe extern "C" fn processing_image_load_pixels (
322+ image_id : u64 ,
323+ buffer : * mut Color ,
324+ buffer_len : usize ,
325+ ) {
326+ error:: clear_error ( ) ;
327+ let image_entity = Entity :: from_bits ( image_id) ;
328+ error:: check ( || {
329+ let colors = image_load_pixels ( image_entity) ?;
330+
331+ // Validate buffer size
332+ if colors. len ( ) != buffer_len {
333+ let error_msg = format ! (
334+ "Buffer size mismatch: expected {}, got {}" ,
335+ colors. len( ) ,
336+ buffer_len
337+ ) ;
338+ error:: set_error ( & error_msg) ;
339+ return Err ( error:: ProcessingError :: InvalidArgument ( error_msg) ) ;
340+ }
341+
342+ // SAFETY: Caller guarantees buffer is valid for buffer_len elements
343+ unsafe {
344+ let buffer_slice = std:: slice:: from_raw_parts_mut ( buffer, buffer_len) ;
345+ for ( i, color) in colors. iter ( ) . enumerate ( ) {
346+ buffer_slice[ i] = Color :: from ( * color) ;
347+ }
348+ }
349+
350+ Ok ( ( ) )
351+ } ) ;
352+ }
0 commit comments