Skip to main content

gizmo_engine/
simple.rs

1use crate::app::App;
2use crate::core::world::World;
3use crate::core::Bundle;
4use crate::bundles::{RigidBodyBundle, CameraBundle};
5use crate::physics::components::{Collider, Transform};
6use crate::physics::world::PhysicsWorld;
7use crate::renderer::asset::AssetManager;
8use crate::renderer::components::{Camera, Material, MeshRenderer};
9use crate::renderer::Renderer;
10use std::f32::consts::{FRAC_PI_2, PI};
11use crate::math::{Quat, Vec3, Vec4};
12use crate::systems;
13
14pub struct SimpleSceneState {
15    pub camera_speed: f32,
16    pub camera_pitch: f32,
17    pub camera_yaw: f32,
18    pub camera_pos: Vec3,
19}
20
21#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
22pub struct CameraSettings {
23    pub speed: f32,
24    pub pitch: f32,
25    pub yaw: f32,
26    pub pos: Vec3,
27    pub exposure: f32,
28    pub bloom_intensity: f32,
29}
30
31impl Default for CameraSettings {
32    fn default() -> Self {
33        Self {
34            speed: 15.0,
35            pitch: 0.0,
36            yaw: 0.0,
37            pos: Vec3::new(0.0, 2.0, 5.0),
38            exposure: 1.0,
39            bloom_intensity: 0.05,
40        }
41    }
42}
43
44#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
45pub struct LightingSettings {
46    pub preset: u32,
47    pub preset_2: u32,
48    pub blend_t: f32,
49    pub auto_cycle: bool,
50    pub rotation_speed: f32,
51    pub direct_intensity: f32,
52}
53
54impl Default for LightingSettings {
55    fn default() -> Self {
56        Self {
57            preset: 0,
58            preset_2: 1,
59            blend_t: 0.0,
60            auto_cycle: false,
61            rotation_speed: 1.0,
62            direct_intensity: 4.0,
63        }
64    }
65}
66
67#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
68pub enum CameraState {
69    Orbiting,
70    Stationary,
71    Manual,
72}
73
74impl Default for CameraState {
75    fn default() -> Self {
76        Self::Manual
77    }
78}
79
80#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
81pub enum EditorState {
82    PlayMode,
83    EditMode,
84    Paused,
85}
86
87impl Default for EditorState {
88    fn default() -> Self {
89        Self::PlayMode
90    }
91}
92
93
94pub struct SceneBuilder<'a> {
95    pub world: &'a mut World,
96    pub renderer: &'a Renderer,
97    pub asset_manager: &'a mut AssetManager,
98}
99
100impl<'a> SceneBuilder<'a> {
101    pub fn spawn_cube(&mut self, position: Vec3, size: f32, color: Vec3) {
102        let mesh = AssetManager::create_cube(&self.renderer.device);
103        let tex = self.asset_manager.create_white_texture(
104            &self.renderer.device,
105            &self.renderer.queue,
106            &self.renderer.scene.texture_bind_group_layout,
107        );
108        let mat = Material::new(tex).with_pbr(Vec4::new(color.x, color.y, color.z, 1.0), 1.0, 0.0);
109
110        // Gizmo cube is from -1.0 to 1.0 (size 2.0).
111        // To get a cube of `size`, we scale by `size / 2.0`.
112        let half_extents = size / 2.0;
113
114        let ent = self.world.spawn();
115        self.world.add_component(
116            ent,
117            Transform::new(position).with_scale(Vec3::splat(half_extents)),
118        );
119        self.world.add_component(ent, crate::physics::components::GlobalTransform::default());
120        self.world.add_component(ent, mesh);
121        self.world.add_component(ent, mat);
122        self.world.add_component(ent, MeshRenderer::new());
123        self.world.add_bundle(ent, RigidBodyBundle::dynamic(10.0).with_collider(Collider::box_collider(Vec3::splat(half_extents))));
124    }
125
126    pub fn spawn_sphere(&mut self, position: Vec3, radius: f32, color: Vec3) {
127        let mesh = AssetManager::create_sphere(&self.renderer.device, radius, 32, 32);
128        let tex = self.asset_manager.create_white_texture(
129            &self.renderer.device,
130            &self.renderer.queue,
131            &self.renderer.scene.texture_bind_group_layout,
132        );
133        let mat = Material::new(tex).with_pbr(Vec4::new(color.x, color.y, color.z, 1.0), 1.0, 0.0);
134
135        let ent = self.world.spawn();
136        self.world.add_component(
137            ent,
138            Transform::new(position), // Mesh is created with exactly the given radius
139        );
140        self.world.add_component(ent, crate::physics::components::GlobalTransform::default());
141        self.world.add_component(ent, mesh);
142        self.world.add_component(ent, mat);
143        self.world.add_component(ent, MeshRenderer::new());
144        self.world.add_bundle(ent, RigidBodyBundle::dynamic(10.0).with_collider(Collider::sphere(radius)));
145    }
146
147    pub fn spawn_textured_cube(&mut self, position: Vec3, size: f32) -> crate::core::entity::Entity {
148        let mesh = AssetManager::create_cube(&self.renderer.device);
149        let tex = self.asset_manager.create_uv_debug_texture(
150            &self.renderer.device,
151            &self.renderer.queue,
152            &self.renderer.scene.texture_bind_group_layout,
153        );
154        let mat = Material::new(tex).with_pbr(Vec4::new(0.5, 0.5, 0.5, 1.0), 0.6, 0.0);
155
156        let half_extents = size / 2.0;
157        let ent = self.world.spawn();
158        self.world.add_component(ent, Transform::new(position).with_scale(Vec3::splat(half_extents)));
159        self.world.add_component(ent, crate::physics::components::GlobalTransform::default());
160        self.world.add_component(ent, mesh);
161        self.world.add_component(ent, mat);
162        self.world.add_component(ent, MeshRenderer::new());
163        self.world.add_bundle(ent, RigidBodyBundle::dynamic(10.0).with_collider(Collider::box_collider(Vec3::splat(half_extents))));
164        ent
165    }
166
167    pub fn spawn_textured_sphere(&mut self, position: Vec3, radius: f32) -> crate::core::entity::Entity {
168        let mesh = AssetManager::create_sphere(&self.renderer.device, radius, 32, 32);
169        let tex = self.asset_manager.create_uv_debug_texture(
170            &self.renderer.device,
171            &self.renderer.queue,
172            &self.renderer.scene.texture_bind_group_layout,
173        );
174        let mat = Material::new(tex).with_pbr(Vec4::new(0.5, 0.5, 0.5, 1.0), 0.6, 0.0);
175
176        let ent = self.world.spawn();
177        self.world.add_component(ent, Transform::new(position));
178        self.world.add_component(ent, crate::physics::components::GlobalTransform::default());
179        self.world.add_component(ent, mesh);
180        self.world.add_component(ent, mat);
181        self.world.add_component(ent, MeshRenderer::new());
182        self.world.add_bundle(ent, RigidBodyBundle::dynamic(10.0).with_collider(Collider::sphere(radius)));
183        ent
184    }
185
186    pub fn spawn_textured_cylinder(&mut self, position: Vec3, radius: f32, height: f32) -> crate::core::entity::Entity {
187        let mesh = AssetManager::create_cylinder(&self.renderer.device, radius, height, 32);
188        let tex = self.asset_manager.create_uv_debug_texture(&self.renderer.device, &self.renderer.queue, &self.renderer.scene.texture_bind_group_layout);
189        let mat = Material::new(tex).with_pbr(Vec4::new(0.5, 0.5, 0.5, 1.0), 0.6, 0.0);
190        let ent = self.world.spawn();
191        self.world.add_component(ent, Transform::new(position));
192        self.world.add_component(ent, crate::physics::components::GlobalTransform::default());
193        self.world.add_component(ent, mesh);
194        self.world.add_component(ent, mat);
195        self.world.add_component(ent, MeshRenderer::new());
196        self.world.add_bundle(ent, RigidBodyBundle::dynamic(10.0).with_collider(Collider::sphere(radius)));
197        ent
198    }
199
200    pub fn spawn_textured_cone(&mut self, position: Vec3, radius: f32, height: f32) -> crate::core::entity::Entity {
201        let mesh = AssetManager::create_cone(&self.renderer.device, radius, height, 32);
202        let tex = self.asset_manager.create_uv_debug_texture(&self.renderer.device, &self.renderer.queue, &self.renderer.scene.texture_bind_group_layout);
203        let mat = Material::new(tex).with_pbr(Vec4::new(0.5, 0.5, 0.5, 1.0), 0.6, 0.0);
204        let ent = self.world.spawn();
205        self.world.add_component(ent, Transform::new(position));
206        self.world.add_component(ent, crate::physics::components::GlobalTransform::default());
207        self.world.add_component(ent, mesh);
208        self.world.add_component(ent, mat);
209        self.world.add_component(ent, MeshRenderer::new());
210        self.world.add_bundle(ent, RigidBodyBundle::dynamic(10.0).with_collider(Collider::sphere(radius))); // approximation
211        ent
212    }
213
214    pub fn spawn_textured_torus(&mut self, position: Vec3, radius: f32, tube_radius: f32) -> crate::core::entity::Entity {
215        let mesh = AssetManager::create_torus(&self.renderer.device, radius, tube_radius, 32, 16);
216        let tex = self.asset_manager.create_uv_debug_texture(&self.renderer.device, &self.renderer.queue, &self.renderer.scene.texture_bind_group_layout);
217        let mat = Material::new(tex).with_pbr(Vec4::new(0.5, 0.5, 0.5, 1.0), 0.6, 0.0);
218        let ent = self.world.spawn();
219        self.world.add_component(ent, Transform::new(position));
220        self.world.add_component(ent, crate::physics::components::GlobalTransform::default());
221        self.world.add_component(ent, mesh);
222        self.world.add_component(ent, mat);
223        self.world.add_component(ent, MeshRenderer::new());
224        self.world.add_bundle(ent, RigidBodyBundle::dynamic(10.0).with_collider(Collider::sphere(radius + tube_radius))); // approximation
225        ent
226    }
227
228    pub fn spawn_textured_capsule(&mut self, position: Vec3, radius: f32, depth: f32) -> crate::core::entity::Entity {
229        let mesh = AssetManager::create_capsule(&self.renderer.device, radius, depth, 16, 32);
230        let tex = self.asset_manager.create_uv_debug_texture(&self.renderer.device, &self.renderer.queue, &self.renderer.scene.texture_bind_group_layout);
231        let mat = Material::new(tex).with_pbr(Vec4::new(0.5, 0.5, 0.5, 1.0), 0.6, 0.0);
232        let ent = self.world.spawn();
233        self.world.add_component(ent, Transform::new(position));
234        self.world.add_component(ent, crate::physics::components::GlobalTransform::default());
235        self.world.add_component(ent, mesh);
236        self.world.add_component(ent, mat);
237        self.world.add_component(ent, MeshRenderer::new());
238        self.world.add_bundle(ent, RigidBodyBundle::dynamic(10.0).with_collider(Collider::sphere(radius)));
239        ent
240    }
241
242    pub fn spawn_textured_tetrahedron(&mut self, position: Vec3, size: f32) -> crate::core::entity::Entity {
243        let mesh = AssetManager::create_tetrahedron(&self.renderer.device, size);
244        let tex = self.asset_manager.create_uv_debug_texture(&self.renderer.device, &self.renderer.queue, &self.renderer.scene.texture_bind_group_layout);
245        let mat = Material::new(tex).with_pbr(Vec4::new(0.5, 0.5, 0.5, 1.0), 0.6, 0.0);
246        let ent = self.world.spawn();
247        self.world.add_component(ent, Transform::new(position));
248        self.world.add_component(ent, crate::physics::components::GlobalTransform::default());
249        self.world.add_component(ent, mesh);
250        self.world.add_component(ent, mat);
251        self.world.add_component(ent, MeshRenderer::new());
252        self.world.add_bundle(ent, RigidBodyBundle::dynamic(10.0).with_collider(Collider::sphere(size)));
253        ent
254    }
255
256    pub fn spawn_textured_conical_frustum(&mut self, position: Vec3, radius_bottom: f32, radius_top: f32, height: f32) -> crate::core::entity::Entity {
257        let mesh = AssetManager::create_conical_frustum(&self.renderer.device, radius_bottom, radius_top, height, 32);
258        let tex = self.asset_manager.create_uv_debug_texture(&self.renderer.device, &self.renderer.queue, &self.renderer.scene.texture_bind_group_layout);
259        let mat = Material::new(tex).with_pbr(Vec4::new(0.5, 0.5, 0.5, 1.0), 0.6, 0.0);
260        let ent = self.world.spawn();
261        self.world.add_component(ent, Transform::new(position));
262        self.world.add_component(ent, crate::physics::components::GlobalTransform::default());
263        self.world.add_component(ent, mesh);
264        self.world.add_component(ent, mat);
265        self.world.add_component(ent, MeshRenderer::new());
266        self.world.add_bundle(ent, RigidBodyBundle::dynamic(10.0).with_collider(Collider::sphere(radius_bottom.max(radius_top))));
267        ent
268    }
269
270    pub fn spawn_textured_convex_extrusion(&mut self, position: Vec3, points: &[[f32; 2]], depth: f32) -> crate::core::entity::Entity {
271        let mesh = AssetManager::create_convex_extrusion(&self.renderer.device, points, depth);
272        let tex = self.asset_manager.create_uv_debug_texture(&self.renderer.device, &self.renderer.queue, &self.renderer.scene.texture_bind_group_layout);
273        let mat = Material::new(tex).with_pbr(Vec4::new(0.5, 0.5, 0.5, 1.0), 0.6, 0.0);
274        let ent = self.world.spawn();
275        // Since we are in XZ plane initially in demo2, let's allow it to just spawn.
276        // Or actually the generated extrusion might be in XZ plane already. 
277        self.world.add_component(ent, Transform::new(position));
278        self.world.add_component(ent, crate::physics::components::GlobalTransform::default());
279        self.world.add_component(ent, mesh);
280        self.world.add_component(ent, mat);
281        self.world.add_component(ent, MeshRenderer::new());
282        self.world.add_bundle(ent, RigidBodyBundle::dynamic(10.0).with_collider(Collider::sphere(1.0)));
283        ent
284    }
285
286    pub fn spawn_textured_ring_extrusion(&mut self, position: Vec3, inner_points: &[[f32; 2]], outer_points: &[[f32; 2]], depth: f32) -> crate::core::entity::Entity {
287        let mesh = AssetManager::create_ring_extrusion(&self.renderer.device, inner_points, outer_points, depth);
288        let tex = self.asset_manager.create_uv_debug_texture(&self.renderer.device, &self.renderer.queue, &self.renderer.scene.texture_bind_group_layout);
289        let mat = Material::new(tex).with_pbr(Vec4::new(0.5, 0.5, 0.5, 1.0), 0.6, 0.0);
290        let ent = self.world.spawn();
291        self.world.add_component(ent, Transform::new(position));
292        self.world.add_component(ent, crate::physics::components::GlobalTransform::default());
293        self.world.add_component(ent, mesh);
294        self.world.add_component(ent, mat);
295        self.world.add_component(ent, MeshRenderer::new());
296        self.world.add_bundle(ent, RigidBodyBundle::dynamic(10.0).with_collider(Collider::sphere(1.0)));
297        ent
298    }
299
300    pub fn spawn_ground(&mut self, radius: f32) {
301        let mesh = AssetManager::create_plane(&self.renderer.device, radius * 2.0);
302        let tex = self.asset_manager.create_white_texture(
303            &self.renderer.device,
304            &self.renderer.queue,
305            &self.renderer.scene.texture_bind_group_layout,
306        );
307        let mat = Material::new(tex).with_pbr(Vec4::new(0.2, 0.2, 0.2, 1.0), 0.9, 0.0);
308
309        let ent = self.world.spawn();
310        self.world.add_component(
311            ent,
312            Transform::new(Vec3::new(0.0, 0.0, 0.0)),
313        );
314        self.world.add_component(ent, crate::physics::components::GlobalTransform::default());
315        self.world.add_component(ent, mesh);
316        self.world.add_component(ent, mat);
317        self.world.add_component(ent, MeshRenderer::new());
318        self.world.add_bundle(ent, RigidBodyBundle::static_body().with_collider(Collider::plane(Vec3::new(0.0, 1.0, 0.0), 0.0)));
319    }
320
321    pub fn spawn_point_light(&mut self, position: Vec3) {
322        let light_ent = self.world.spawn();
323        let mut bundle = crate::bundles::PointLightBundle::default();
324        bundle.position = position;
325        bundle.color = Vec3::new(1.0, 1.0, 1.0);
326        bundle.intensity = 20.0;
327        
328        bundle.apply(self.world, light_ent);
329    }
330    
331    pub fn spawn_camera(&mut self, state: &mut SimpleSceneState, pos: Vec3, look_at: Vec3) {
332        let look_dir = (look_at - pos).normalize_or_zero();
333        state.camera_pos = pos;
334        if look_dir != Vec3::ZERO {
335            state.camera_yaw = look_dir.z.atan2(look_dir.x);
336            state.camera_pitch = look_dir.y.asin();
337        }
338
339        let camera_ent = self.world.spawn();
340        let mut bundle = CameraBundle::default();
341        bundle.position = state.camera_pos;
342        bundle.yaw = state.camera_yaw;
343        bundle.pitch = state.camera_pitch;
344
345        bundle.apply(self.world, camera_ent);
346    }
347}
348
349pub trait SimpleAppExt {
350    fn with_simple_scene<F>(self, setup_fn: F) -> Self
351    where
352        F: FnOnce(&mut SceneBuilder, &mut SimpleSceneState) + 'static;
353}
354
355impl SimpleAppExt for App<SimpleSceneState> {
356    fn with_simple_scene<F>(self, setup_fn: F) -> Self
357    where
358        F: FnOnce(&mut SceneBuilder, &mut SimpleSceneState) + 'static,
359    {
360        self.set_setup(move |world, renderer| {
361            let mut asset_manager = AssetManager::new();
362            let phys_world = PhysicsWorld::new().with_gravity(Vec3::new(0.0, -9.81, 0.0));
363
364            let mut state = SimpleSceneState {
365                camera_speed: 15.0,
366                camera_pitch: 0.0,
367                camera_yaw: 0.0,
368                camera_pos: Vec3::new(0.0, 2.0, 5.0),
369            };
370
371            let mut builder = SceneBuilder {
372                world,
373                renderer,
374                asset_manager: &mut asset_manager,
375            };
376
377            setup_fn(&mut builder, &mut state);
378
379            world.insert_resource(phys_world);
380            world.insert_resource(asset_manager);
381            state
382        })
383        .set_update(|world, state, dt, input| {
384            if input.is_mouse_button_pressed(1) {
385                let delta = input.mouse_delta();
386                state.camera_yaw -= delta.0 * 0.005;
387                state.camera_pitch -= delta.1 * 0.005;
388                state.camera_pitch = state.camera_pitch.clamp(-PI / 2.0 + 0.1, PI / 2.0 - 0.1);
389            }
390
391            let fx = state.camera_yaw.cos() * state.camera_pitch.cos();
392            let fy = state.camera_pitch.sin();
393            let fz = state.camera_yaw.sin() * state.camera_pitch.cos();
394            let forward = Vec3::new(fx, fy, fz).normalize();
395            let right = forward.cross(Vec3::new(0.0, 1.0, 0.0)).normalize();
396            let up = Vec3::new(0.0, 1.0, 0.0);
397
398            let speed = if input.is_key_pressed(crate::winit::keyboard::KeyCode::ShiftLeft as u32) {
399                state.camera_speed * 3.0
400            } else {
401                state.camera_speed
402            };
403
404            let mut cam_move = Vec3::ZERO;
405            if input.is_key_pressed(crate::winit::keyboard::KeyCode::KeyW as u32) { cam_move += forward; }
406            if input.is_key_pressed(crate::winit::keyboard::KeyCode::KeyS as u32) { cam_move -= forward; }
407            if input.is_key_pressed(crate::winit::keyboard::KeyCode::KeyD as u32) { cam_move += right; }
408            if input.is_key_pressed(crate::winit::keyboard::KeyCode::KeyA as u32) { cam_move -= right; }
409            if input.is_key_pressed(crate::winit::keyboard::KeyCode::KeyE as u32) { cam_move += up; }
410            if input.is_key_pressed(crate::winit::keyboard::KeyCode::KeyQ as u32) { cam_move -= up; }
411
412            if cam_move.length_squared() > 0.0 {
413                state.camera_pos += cam_move.normalize() * speed * dt;
414            }
415
416            if let Some(mut q) = world.query::<(
417                crate::core::query::Mut<Transform>,
418                crate::core::query::Mut<Camera>,
419            )>() {
420                let yaw_rot = Quat::from_rotation_y(-state.camera_yaw + FRAC_PI_2);
421                let pitch_rot = Quat::from_rotation_x(state.camera_pitch);
422                let rot = yaw_rot * pitch_rot;
423
424                for (_, (mut trans, mut cam)) in q.iter_mut() {
425                    trans.position = state.camera_pos;
426                    trans.rotation = rot;
427                    cam.yaw = state.camera_yaw;
428                    cam.pitch = state.camera_pitch;
429                }
430            }
431
432            let mut physics_dt = dt.min(0.1);
433            while physics_dt > 0.0 {
434                let step = physics_dt.min(0.016);
435                systems::cpu_physics_step_system(world, step);
436                physics_dt -= step;
437            }
438
439            use crate::core::system::System;
440            let mut transform_sync = systems::transform::TransformSyncSystem;
441            let mut transform_propagate = systems::transform::TransformPropagateSystem;
442            transform_sync.run(world, dt);
443            transform_propagate.run(world, dt);
444        })
445        .set_render(|world, _state, encoder, view, renderer, _light_time| {
446            // Basit sahnelerde varsayılan olarak gelen GPU compute sistemlerini ve reflection'ları kapatıyoruz
447            // Böylece sadece bizim eklediğimiz küp ve ışık temiz bir şekilde render edilecek.
448            renderer.gpu_physics = None;
449            renderer.gpu_fluid = None;
450            renderer.gpu_particles = None;
451            renderer.ssr = None; // Arkadaki istenmeyen yansımaları (Screen Space Reflections) kapatır
452            renderer.ssgi = None; // SSGI kapatır
453            
454            systems::default_render_pass(world, encoder, view, renderer);
455        })
456    }
457}
458
459#[cfg(test)]
460mod tests {
461    use super::*;
462
463    #[test]
464    fn test_camera_settings_default() {
465        let settings = CameraSettings::default();
466        assert_eq!(settings.speed, 15.0);
467        assert_eq!(settings.pitch, 0.0);
468        assert_eq!(settings.yaw, 0.0);
469        assert_eq!(settings.pos, Vec3::new(0.0, 2.0, 5.0));
470        assert_eq!(settings.exposure, 1.0);
471        assert_eq!(settings.bloom_intensity, 0.05);
472    }
473
474    #[test]
475    fn test_lighting_settings_default() {
476        let settings = LightingSettings::default();
477        assert_eq!(settings.preset, 0);
478        assert_eq!(settings.preset_2, 1);
479        assert_eq!(settings.blend_t, 0.0);
480        assert_eq!(settings.auto_cycle, false);
481        assert_eq!(settings.rotation_speed, 1.0);
482        assert_eq!(settings.direct_intensity, 4.0);
483    }
484
485    #[test]
486    fn test_camera_state_transitions() {
487        let mut state = CameraState::default();
488        assert_eq!(state, CameraState::Manual);
489        
490        state = CameraState::Orbiting;
491        assert_eq!(state, CameraState::Orbiting);
492        
493        state = CameraState::Stationary;
494        assert_eq!(state, CameraState::Stationary);
495    }
496
497    #[test]
498    fn test_editor_state_transitions() {
499        let mut state = EditorState::default();
500        assert_eq!(state, EditorState::PlayMode);
501        
502        state = EditorState::EditMode;
503        assert_eq!(state, EditorState::EditMode);
504        
505        state = EditorState::Paused;
506        assert_eq!(state, EditorState::Paused);
507    }
508}