ark_module/types/render.rs
1//! 🌈 Render module
2//!
3//! TODO: Add overviewdescription how they work and how to use it
4//!
5//! Also see the Developer Guide section about [render modules](https://ark.embark.dev/guide/api/render.html)
6
7pub use ark_api_ffi::entrypoints::render::RenderDrawFlags;
8pub use ark_api_ffi::entrypoints::render::RenderDrawInfo;
9pub use ark_api_ffi::entrypoints::render::RenderFrameInfo;
10
11/// Render module creation & update trait
12pub trait RenderModule {
13 /// Creation of a new module
14 ///
15 /// This is called once on startup of the module
16 fn new() -> Self;
17
18 /// Implement the rendering for an entity here.
19 ///
20 /// `cache_id` is unique per entity, and can be used internally to cache entity-specific data.
21 /// It is unrelated to the `instance_id` you can specify in the render API, although you might
22 /// find it useful to use the `cache_id` to come up with suitably unique and stable `instance_id`s.
23 ///
24 /// `static_data` is the data array you specified when creating the Shape.
25 /// `dynamic_data` is empty by default but can be set at any time on the Render component of the Entity.
26 fn draw(
27 &mut self,
28 common_info: &RenderFrameInfo,
29 object_to_world: macaw::Mat4,
30 static_data: &[u8],
31 dynamic_data: &[u8],
32 cache_id: u64,
33 );
34
35 /// Gets called when you can safely delete all cached information related to a specific `cache_id`.
36 fn removed(&mut self, cache_id: u64);
37}
38
39/// Implement a render module
40#[macro_export]
41macro_rules! impl_render_module {
42 ($module: ty) => {
43 use $crate::render::RenderModule as _;
44
45 static mut MODULE: Option<$module> = None;
46
47 #[no_mangle]
48 pub fn ark_initialize() {
49 $crate::init();
50 // SAFETY: Sound to access static as we do not use threads in Wasm and this is guaranteed to be called first in the module
51 unsafe {
52 MODULE = Some(<$module as $crate::render::RenderModule>::new());
53 }
54 }
55
56 #[no_mangle]
57 pub unsafe fn ark_render_frame(
58 frame_info_ptr: *const $crate::render::RenderFrameInfo,
59 draw_info_ptr: *const $crate::render::RenderDrawInfo,
60 draw_info_len: u32,
61 ) {
62 // SAFETY: Sound to access static as we do not use threads in Wasm and this is guaranteed to be initialized on startup with `ark_initialize` first
63 unsafe {
64 let module = MODULE.as_mut().unwrap();
65 let slice = std::slice::from_raw_parts::<$crate::render::RenderDrawInfo>(
66 draw_info_ptr,
67 draw_info_len as usize,
68 );
69 for entry in slice {
70 let static_data_slice = std::slice::from_raw_parts::<u8>(
71 entry.static_data_ptr as *const u8,
72 entry.static_data_len as usize,
73 );
74 let dynamic_data_slice = std::slice::from_raw_parts::<u8>(
75 entry.dynamic_data_ptr as *const u8,
76 entry.dynamic_data_len as usize,
77 );
78 if entry
79 .flags
80 .contains($crate::render::RenderDrawFlags::REMOVED)
81 {
82 // Instance was removed
83 <$module as $crate::render::RenderModule>::removed(module, entry.cache_id);
84 } else {
85 <$module as $crate::render::RenderModule>::draw(
86 module,
87 frame_info_ptr.as_ref().unwrap(),
88 macaw::Mat4::from_cols_array(&entry.object_to_world),
89 static_data_slice,
90 dynamic_data_slice,
91 entry.cache_id,
92 );
93 }
94 }
95 }
96 }
97 };
98}