1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use crate::{
api::{self, Api, ApiWithCtx},
component::{ComponentTuple, ComponentsIterator},
ComponentMask,
};
use std::{
ffi::{c_void, CString},
slice,
};
use tm_sys::ffi::{
tm_component_i, tm_component_mask_t, tm_engine_i, tm_engine_o, tm_engine_update_set_t,
tm_entity_api, tm_entity_context_o, TM_ENTITY_API_NAME,
};
#[derive(Copy, Clone)]
pub struct EntityApi {
api: *mut tm_entity_api,
}
unsafe impl Send for EntityApi {}
unsafe impl Sync for EntityApi {}
impl Api for EntityApi {
type CType = *mut tm_entity_api;
const NAME: &'static [u8] = TM_ENTITY_API_NAME;
#[inline]
fn new(api: *mut c_void) -> Self {
Self { api: api as _ }
}
}
#[derive(Copy, Clone)]
pub struct EntityApiInstance {
api: *mut tm_entity_api,
ctx: *mut tm_entity_context_o,
}
impl ApiWithCtx for EntityApi {
type Ctx = tm_entity_context_o;
type ApiInstance = EntityApiInstance;
#[inline]
fn wrap(self, ctx: *mut Self::Ctx) -> Self::ApiInstance {
EntityApiInstance { api: self.api, ctx }
}
}
struct EngineCallbackData {
ctx: *mut tm_entity_context_o,
update: Box<dyn Fn(*mut tm_entity_context_o, &mut tm_engine_update_set_t)>,
#[allow(clippy::type_complexity)]
filter: Option<Box<dyn Fn(&[u32], &ComponentMask) -> bool>>,
}
unsafe extern "C" fn engine_update(inst: *mut tm_engine_o, data: *mut tm_engine_update_set_t) {
assert!(!inst.is_null());
assert!(!data.is_null());
let callback_data = (inst as *const EngineCallbackData).as_ref().unwrap();
(callback_data.update)(callback_data.ctx, data.as_mut().unwrap());
}
unsafe extern "C" fn engine_filter(
inst: *mut tm_engine_o,
components: *const u32,
num_components: u32,
mask: *const tm_component_mask_t,
) -> bool {
assert!(!inst.is_null());
assert!(!components.is_null());
assert!(!mask.is_null());
let callback_data = (inst as *const EngineCallbackData).as_ref().unwrap();
let components = slice::from_raw_parts(components, num_components as usize);
let mask = mask.as_ref().unwrap();
if let Some(filter) = &callback_data.filter {
filter(components, mask)
} else {
false
}
}
impl EntityApiInstance {
#[inline]
pub fn lookup_component(&mut self, name_hash: u64) -> u32 {
unsafe { (*self.api).lookup_component.unwrap()(self.ctx, name_hash) }
}
#[inline]
pub fn register_engine<C>(
&mut self,
name: &'static str,
update: impl Fn(&mut EntityApiInstance, ComponentsIterator<C>) + Send + Sync + 'static,
filter: Option<fn(&[u32], &ComponentMask) -> bool>,
) where
C: ComponentTuple,
{
let name = CString::new(name).unwrap();
let has_filter_fn = filter.is_some();
let inst = Box::into_raw(Box::new(EngineCallbackData {
ctx: self.ctx,
update: Box::new(move |ctx, update_set| {
let mut entity_api = api::with_ctx::<EntityApi>(ctx);
let components = ComponentsIterator::<C>::new(update_set);
update(&mut entity_api, components)
}),
filter: if let Some(filter) = filter {
Some(Box::new(filter))
} else {
None
},
})) as *mut tm_engine_o;
let engine = tm_engine_i {
name: name.as_ptr(),
disabled: false,
_padding_215: [0; 3],
num_components: C::get_count(),
components: C::get_components(self),
excludes: [false; 16],
writes: C::get_writes(),
inst,
update: Some(engine_update),
filter: if has_filter_fn {
Some(engine_filter)
} else {
None
},
};
unsafe {
(*self.api).register_engine.unwrap()(self.ctx, &engine as *const _);
}
}
#[inline]
pub fn register_component(&mut self, component: &tm_component_i) -> u32 {
unsafe { (*self.api).register_component.unwrap()(self.ctx, component as *const _) }
}
}
#[inline]
pub fn mask_has_component(mask: &tm_component_mask_t, i: u32) -> bool {
(mask.bits[(i / 64) as usize] & (1 << (i % 64))) > 0
}