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