1use std::ffi::{c_char, CString};
2use paste::paste;
3
4macro_rules! typed_ptr {
5 ( $name:ident ) => {
6 #[repr(C)]
7 #[derive(Copy, Clone)]
8 pub struct $name {
9 ptr: *mut c_char
10 }
11 };
12}
13
14typed_ptr!(_Color);
15typed_ptr!(_ColorNote);
16typed_ptr!(_BombNote);
17typed_ptr!(_ChainHeadNote);
18typed_ptr!(_ChainLinkNote);
19typed_ptr!(_ChainNote);
20typed_ptr!(_Arc);
21typed_ptr!(_Wall);
22typed_ptr!(_Saber);
23typed_ptr!(_Vec2);
25typed_ptr!(_Vec3);
26typed_ptr!(_Vec4);
27typed_ptr!(_Quat);
28
29macro_rules! color_methods {
30 ( $tp:ty, $name:tt ) => {
31 paste! {
32 extern "C" {
33 fn [<_ $name _set_color>]($name: $tp, color: _Color);
34 fn [<_ $name _get_color>]($name: $tp) -> _Color;
35 }
36 }
37 }
38}
39
40macro_rules! position_methods {
41 ( $tp:ty, $name:tt ) => {
42 paste! {
43 extern "C" {
44 fn [<_ $name _set_position>]($name: $tp, pos: _Vec3);
45 fn [<_ $name _get_position>]($name: $tp) -> _Vec3;
46 fn [<_ $name _set_orientation>]($name: $tp, orientation: _Quat);
47 fn [<_ $name _get_orientation>]($name: $tp) -> _Quat;
48 }
49 }
50 }
51}
52
53macro_rules! gameplay_object_methods {
54 ( $tp:ty, $name:tt ) => {
55 paste! {
56 extern "C" {
57 fn [<_create_ $name>](beat: f32) -> $tp;
58 fn [<_beatmap_add_ $name>]($name: $tp);
59 fn [<_beatmap_remove_ $name>]($name: $tp);
60 }
61 }
62 position_methods! { $tp, $name }
63 color_methods! { $tp, $name }
64 };
65}
66
67macro_rules! attrs {
68 ( $tp:ty, $name:tt, $( $attr:ident: $attr_tp:ty ),* $(,)? ) => {
69 extern "C" {
70 paste! {
71 $(
72 fn [<_ $name _get_attr_ $attr>]($name: [<_ $tp>]) -> $attr_tp;
73 fn [<_ $name _set_attr_ $attr>]($name: [<_ $tp>], $attr: $attr_tp);
74 )*
75 }
76 }
77
78 impl $tp {
79 $(
80
81 paste! {
82 pub fn [<get_ $attr>](&self) -> $attr_tp {
83 unsafe { [<_ $name _get_attr_ $attr>](self._inner) }
84 }
85 pub fn [<set_ $attr>](&self, $attr: $attr_tp) {
86 unsafe { [<_ $name _set_attr_ $attr>](self._inner, $attr) }
87 }
88 }
89
90 )*
91 }
92 };
93}
94
95gameplay_object_methods! { _ColorNote, color_note }
96gameplay_object_methods! { _BombNote, bomb_note }
97gameplay_object_methods! { _Arc, arc }
98gameplay_object_methods! { _Wall, wall }
99gameplay_object_methods! { _ChainHeadNote, chain_head_note }
100gameplay_object_methods! { _ChainLinkNote, chain_link_note }
101gameplay_object_methods! { _ChainNote, chain_note }
102
103color_methods! { _Saber, saber }
104
105extern "C" {
106 fn _get_left_saber() -> _Saber;
107 fn _get_right_saber() -> _Saber;
108
109 fn _log(message: *const c_char);
110
111 fn _drop_reference(ptr: *mut c_char);
113
114
115 fn _vec2_from_native(x: f32, y: f32) -> _Vec2;
116 fn _vec3_from_native(x: f32, y: f32, z: f32) -> _Vec3;
117 fn _vec4_from_native(x: f32, y: f32, z: f32, w: f32) -> _Vec4;
118 fn _quat_from_native(x: f32, y: f32, z: f32, w: f32) -> _Quat;
119
120 fn _color_set_rgb(color: _Color, r: f32, g: f32, b: f32);
121 fn _color_set_rgba(color: _Color, r: f32, g: f32, b: f32, a: f32);
122
123}
124
125macro_rules! cstr {
126 ( $str:expr ) => {
127 CString::new($str).unwrap()
128 };
129}
130
131pub struct Log {}
134impl Log {
135 pub fn info(message: &str) {
136 let s = format!("info: {}", message);
137 let c = cstr!(s);
138 unsafe { _log(c.as_ptr()) };
139 }
140
141 pub fn warning(message: &str) {
142 let s = format!("warning: {}", message);
143 let c = cstr!(s);
144 unsafe { _log(c.as_ptr()) };
145 }
146
147 pub fn error(message: &str) {
148 let s = format!("error: {}", message);
149 let c = cstr!(s);
150 unsafe { _log(c.as_ptr()) };
151 }
152
153 pub fn debug(message: &str) {
154 let s = format!("debug: {}", message);
155 let c = cstr!(s);
156 unsafe { _log(c.as_ptr()) };
157 }
158
159}
160
161macro_rules! wrapped {
162 ( $name:tt ) => {
163 pub struct $name {
164 _inner: paste! { [<_ $name>] }
165 }
166 };
167}
168
169macro_rules! instantiable_obj {
170 ( $ty:tt, $name:tt ) => {
171 wrapped! { $ty }
172 paste! {
173
174 pub fn [<create_ $name>](beat: f32) -> $ty {
175 unsafe { $ty { _inner: [<_create_ $name>](beat) } }
176 }
177
178 impl Beatmap {
179 pub fn [<add_ $name>]($name: $ty) {
180 unsafe {
181 [<_beatmap_add_ $name>]($name._inner);
182 }
183 }
184 }
185 }
186 };
187}
188
189pub struct Beatmap;
190pub struct Data;
191
192instantiable_obj! { ColorNote, color_note }
193instantiable_obj! { BombNote, bomb_note }
194instantiable_obj! { ChainHeadNote, chain_head_note }
195instantiable_obj! { ChainLinkNote, chain_link_note }
196instantiable_obj! { ChainNote, chain_note }
197instantiable_obj! { Arc, arc }
198instantiable_obj! { Wall, wall }
199
200wrapped! { Vec2 }
201
202
203wrapped! { Vec3 }
204wrapped! { Vec4 }
205wrapped! { Quat }
206wrapped! { Color }
207
208attrs! { Vec2, vec2, x: f32, y: f32 }
209attrs! { Vec3, vec3, x: f32, y: f32, z: f32 }
210attrs! { Vec4, vec4, x: f32, y: f32, z: f32, w: f32 }
211attrs! { Quat, quat, x: f32, y: f32, z: f32, w: f32 }
212attrs! { Color, color, r: f32, g: f32, b: f32, a: f32 }
213
214trait UnityConvertible {
215 type UnityType;
216 fn to_unity_type(self) -> Self::UnityType;
217 fn from_unity_type(t: Self::UnityType) -> Self;
218}
219
220impl UnityConvertible for glam::Vec2 {
221 type UnityType = Vec2;
222 fn to_unity_type(self) -> Self::UnityType {
223 Vec2 { _inner: unsafe { _vec2_from_native(self.x, self.y) } }
224 }
225 fn from_unity_type(t: Self::UnityType) -> Self {
226 glam::Vec2::new(t.get_x(), t.get_y())
227 }
228}
229
230impl UnityConvertible for glam::Vec3 {
231 type UnityType = Vec3;
232 fn to_unity_type(self) -> Self::UnityType {
233 Vec3 { _inner: unsafe { _vec3_from_native(self.x, self.y, self.z) } }
234 }
235 fn from_unity_type(t: Self::UnityType) -> Self {
236 glam::Vec3::new(t.get_x(), t.get_y(), t.get_z())
237 }
238}
239
240impl UnityConvertible for glam::Vec4 {
241 type UnityType = Vec4;
242 fn to_unity_type(self) -> Self::UnityType {
243 Vec4 { _inner: unsafe { _vec4_from_native(self.x, self.y, self.z, self.w) } }
244 }
245 fn from_unity_type(t: Self::UnityType) -> Self {
246 glam::Vec4::new(t.get_x(), t.get_y(), t.get_z(), t.get_w())
247 }
248}
249
250impl UnityConvertible for glam::Quat {
251 type UnityType = Quat;
252 fn to_unity_type(self) -> Self::UnityType {
253 Quat { _inner: unsafe { _quat_from_native(self.x, self.y, self.z, self.w) } }
254 }
255 fn from_unity_type(t: Self::UnityType) -> Self {
256 glam::Quat::from_xyzw(t.get_x(), t.get_y(), t.get_z(), t.get_w())
257 }
258}
259
260
261impl Color {
262 pub fn set_rgb(&self, r: f32, g: f32, b: f32) {
263 unsafe { _color_set_rgb(self._inner, r, g, b) };
264 }
265
266 pub fn set_rgba(&self, r: f32, g: f32, b: f32, a: f32) {
267 unsafe { _color_set_rgba(self._inner, r, g, b, a) };
268 }
269}
270