1use super::GoudGame;
12use crate::libs::graphics::renderer3d::{
13 FogConfig, GridConfig, Light, LightType, PrimitiveCreateInfo, PrimitiveType, SkyboxConfig,
14};
15use cgmath::{Vector3, Vector4};
16
17const INVALID_OBJECT: u32 = u32::MAX;
19
20impl GoudGame {
27 pub fn create_primitive(&mut self, info: PrimitiveCreateInfo) -> u32 {
29 match &mut self.renderer_3d {
30 Some(renderer) => renderer.create_primitive(info),
31 None => INVALID_OBJECT,
32 }
33 }
34
35 pub fn create_cube(&mut self, texture_id: u32, width: f32, height: f32, depth: f32) -> u32 {
37 self.create_primitive(PrimitiveCreateInfo {
38 primitive_type: PrimitiveType::Cube,
39 width,
40 height,
41 depth,
42 segments: 1,
43 texture_id,
44 })
45 }
46
47 pub fn create_plane(&mut self, texture_id: u32, width: f32, depth: f32) -> u32 {
49 self.create_primitive(PrimitiveCreateInfo {
50 primitive_type: PrimitiveType::Plane,
51 width,
52 height: 0.0,
53 depth,
54 segments: 1,
55 texture_id,
56 })
57 }
58
59 pub fn create_sphere(&mut self, texture_id: u32, diameter: f32, segments: u32) -> u32 {
61 self.create_primitive(PrimitiveCreateInfo {
62 primitive_type: PrimitiveType::Sphere,
63 width: diameter,
64 height: diameter,
65 depth: diameter,
66 segments,
67 texture_id,
68 })
69 }
70
71 pub fn create_cylinder(
73 &mut self,
74 texture_id: u32,
75 radius: f32,
76 height: f32,
77 segments: u32,
78 ) -> u32 {
79 self.create_primitive(PrimitiveCreateInfo {
80 primitive_type: PrimitiveType::Cylinder,
81 width: radius * 2.0,
82 height,
83 depth: radius * 2.0,
84 segments,
85 texture_id,
86 })
87 }
88
89 pub fn set_object_position(&mut self, id: u32, x: f32, y: f32, z: f32) -> bool {
91 match &mut self.renderer_3d {
92 Some(renderer) => renderer.set_object_position(id, x, y, z),
93 None => false,
94 }
95 }
96
97 pub fn set_object_rotation(&mut self, id: u32, x: f32, y: f32, z: f32) -> bool {
99 match &mut self.renderer_3d {
100 Some(renderer) => renderer.set_object_rotation(id, x, y, z),
101 None => false,
102 }
103 }
104
105 pub fn set_object_scale(&mut self, id: u32, x: f32, y: f32, z: f32) -> bool {
107 match &mut self.renderer_3d {
108 Some(renderer) => renderer.set_object_scale(id, x, y, z),
109 None => false,
110 }
111 }
112
113 pub fn destroy_object(&mut self, object_id: u32) -> bool {
115 match &mut self.renderer_3d {
116 Some(renderer) => renderer.remove_object(object_id),
117 None => false,
118 }
119 }
120
121 #[allow(clippy::too_many_arguments)]
123 pub fn add_light(
124 &mut self,
125 light_type: i32,
126 pos_x: f32,
127 pos_y: f32,
128 pos_z: f32,
129 dir_x: f32,
130 dir_y: f32,
131 dir_z: f32,
132 r: f32,
133 g: f32,
134 b: f32,
135 intensity: f32,
136 range: f32,
137 spot_angle: f32,
138 ) -> u32 {
139 let lt = match light_type {
140 1 => LightType::Directional,
141 2 => LightType::Spot,
142 _ => LightType::Point,
143 };
144 match &mut self.renderer_3d {
145 Some(renderer) => renderer.add_light(Light {
146 light_type: lt,
147 position: Vector3::new(pos_x, pos_y, pos_z),
148 direction: Vector3::new(dir_x, dir_y, dir_z),
149 color: Vector3::new(r, g, b),
150 intensity,
151 range,
152 spot_angle,
153 enabled: true,
154 }),
155 None => u32::MAX,
156 }
157 }
158
159 #[allow(clippy::too_many_arguments)]
161 pub fn update_light(
162 &mut self,
163 light_id: u32,
164 light_type: i32,
165 pos_x: f32,
166 pos_y: f32,
167 pos_z: f32,
168 dir_x: f32,
169 dir_y: f32,
170 dir_z: f32,
171 r: f32,
172 g: f32,
173 b: f32,
174 intensity: f32,
175 range: f32,
176 spot_angle: f32,
177 ) -> bool {
178 let lt = match light_type {
179 1 => LightType::Directional,
180 2 => LightType::Spot,
181 _ => LightType::Point,
182 };
183 match &mut self.renderer_3d {
184 Some(renderer) => renderer.update_light(
185 light_id,
186 Light {
187 light_type: lt,
188 position: Vector3::new(pos_x, pos_y, pos_z),
189 direction: Vector3::new(dir_x, dir_y, dir_z),
190 color: Vector3::new(r, g, b),
191 intensity,
192 range,
193 spot_angle,
194 enabled: true,
195 },
196 ),
197 None => false,
198 }
199 }
200
201 pub fn remove_light(&mut self, light_id: u32) -> bool {
203 match &mut self.renderer_3d {
204 Some(renderer) => renderer.remove_light(light_id),
205 None => false,
206 }
207 }
208
209 pub fn set_camera_position(&mut self, x: f32, y: f32, z: f32) -> bool {
211 match &mut self.renderer_3d {
212 Some(renderer) => {
213 renderer.set_camera_position(x, y, z);
214 true
215 }
216 None => false,
217 }
218 }
219
220 pub fn set_camera_rotation(&mut self, pitch: f32, yaw: f32, roll: f32) -> bool {
222 match &mut self.renderer_3d {
223 Some(renderer) => {
224 renderer.set_camera_rotation(pitch, yaw, roll);
225 true
226 }
227 None => false,
228 }
229 }
230
231 pub fn configure_grid(&mut self, enabled: bool, size: f32, divisions: u32) -> bool {
233 match &mut self.renderer_3d {
234 Some(renderer) => {
235 renderer.configure_grid(GridConfig {
236 enabled,
237 size,
238 divisions,
239 ..Default::default()
240 });
241 true
242 }
243 None => false,
244 }
245 }
246
247 pub fn set_grid_enabled(&mut self, enabled: bool) -> bool {
249 match &mut self.renderer_3d {
250 Some(renderer) => {
251 renderer.set_grid_enabled(enabled);
252 true
253 }
254 None => false,
255 }
256 }
257
258 pub fn configure_skybox(&mut self, enabled: bool, r: f32, g: f32, b: f32, a: f32) -> bool {
260 match &mut self.renderer_3d {
261 Some(renderer) => {
262 renderer.configure_skybox(SkyboxConfig {
263 enabled,
264 color: Vector4::new(r, g, b, a),
265 });
266 true
267 }
268 None => false,
269 }
270 }
271
272 pub fn configure_fog(&mut self, enabled: bool, r: f32, g: f32, b: f32, density: f32) -> bool {
274 match &mut self.renderer_3d {
275 Some(renderer) => {
276 renderer.configure_fog(FogConfig {
277 enabled,
278 color: Vector3::new(r, g, b),
279 density,
280 });
281 true
282 }
283 None => false,
284 }
285 }
286
287 pub fn set_fog_enabled(&mut self, enabled: bool) -> bool {
289 match &mut self.renderer_3d {
290 Some(renderer) => {
291 renderer.set_fog_enabled(enabled);
292 true
293 }
294 None => false,
295 }
296 }
297
298 pub fn render(&mut self) -> bool {
300 match &mut self.renderer_3d {
301 Some(renderer) => {
302 renderer.render(None);
303 true
304 }
305 None => false,
306 }
307 }
308
309 pub fn render_all(&mut self) -> bool {
311 self.render()
312 }
313
314 #[inline]
316 pub fn has_3d_renderer(&self) -> bool {
317 self.renderer_3d.is_some()
318 }
319}
320
321#[cfg(test)]
326mod tests {
327 use super::*;
328 use crate::sdk::GameConfig;
329
330 #[test]
331 fn test_create_cube_headless() {
332 let mut game = GoudGame::new(GameConfig::default()).unwrap();
333 assert_eq!(game.create_cube(0, 1.0, 1.0, 1.0), u32::MAX);
334 }
335
336 #[test]
337 fn test_set_object_position_headless() {
338 let mut game = GoudGame::new(GameConfig::default()).unwrap();
339 assert!(!game.set_object_position(0, 1.0, 2.0, 3.0));
340 }
341
342 #[test]
343 fn test_set_camera_position_headless() {
344 let mut game = GoudGame::new(GameConfig::default()).unwrap();
345 assert!(!game.set_camera_position(0.0, 5.0, -10.0));
346 }
347
348 #[test]
349 fn test_render_3d_headless() {
350 let mut game = GoudGame::new(GameConfig::default()).unwrap();
351 assert!(!game.render());
352 }
353
354 #[test]
355 fn test_has_3d_renderer_headless() {
356 let game = GoudGame::new(GameConfig::default()).unwrap();
357 assert!(!game.has_3d_renderer());
358 }
359
360 #[test]
361 fn test_add_light_headless() {
362 let mut game = GoudGame::new(GameConfig::default()).unwrap();
363 let id = game.add_light(
364 0, 0.0, 5.0, 0.0, 0.0, -1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 10.0, 0.0,
365 );
366 assert_eq!(id, u32::MAX);
367 }
368
369 #[test]
370 fn test_render_all_headless() {
371 let mut game = GoudGame::new(GameConfig::default()).unwrap();
372 assert!(!game.render_all());
373 }
374
375 #[test]
376 fn test_configure_grid_headless() {
377 let mut game = GoudGame::new(GameConfig::default()).unwrap();
378 assert!(!game.configure_grid(true, 10.0, 10));
379 }
380
381 #[test]
382 fn test_configure_skybox_headless() {
383 let mut game = GoudGame::new(GameConfig::default()).unwrap();
384 assert!(!game.configure_skybox(true, 0.5, 0.5, 0.8, 1.0));
385 }
386
387 #[test]
388 fn test_configure_fog_headless() {
389 let mut game = GoudGame::new(GameConfig::default()).unwrap();
390 assert!(!game.configure_fog(true, 0.5, 0.5, 0.5, 0.01));
391 }
392
393 #[test]
394 fn test_set_fog_enabled_headless() {
395 let mut game = GoudGame::new(GameConfig::default()).unwrap();
396 assert!(!game.set_fog_enabled(true));
397 }
398
399 #[test]
400 fn test_destroy_object_headless() {
401 let mut game = GoudGame::new(GameConfig::default()).unwrap();
402 assert!(!game.destroy_object(0));
403 }
404}