Skip to main content

simple_demo/
simple-demo.rs

1use mittens_engine::{engine, utils};
2
3#[path = "example_util/mod.rs"]
4mod example_util;
5
6fn build_demo_scene_7_shapes(universe: &mut engine::Universe) {
7    use engine::ecs::component::{
8        Camera3DComponent, ColorComponent, EmissiveComponent, GLTFComponent, InputComponent,
9        InputTransformModeComponent, PointLightComponent, RenderableComponent, TextureComponent,
10        TransformComponent,
11    };
12    use engine::graphics::BuiltinMeshType;
13    use engine::graphics::primitives::MaterialHandle;
14
15    // Built-in CPU meshes are pre-registered; just fetch stable handles.
16    let tri_mesh = universe.render_assets.get_mesh(BuiltinMeshType::Triangle2D);
17    let square_mesh = universe.render_assets.get_mesh(BuiltinMeshType::Quad2D);
18    let tetra_mesh = universe
19        .render_assets
20        .get_mesh(BuiltinMeshType::Tetrahedron);
21
22    fn spawn(
23        universe: &mut engine::Universe,
24        mesh: engine::graphics::primitives::CpuMeshHandle,
25        x: f32,
26        y: f32,
27        s: f32,
28        r: f32,
29        color: [f32; 4],
30        input_driven: bool,
31        emissive: bool,
32    ) -> engine::ecs::ComponentId {
33        let transform = universe.world.add_component(
34            TransformComponent::new()
35                .with_position(x, y, 0.0)
36                .with_scale(s, s, 1.0)
37                .with_rotation_euler(0.0, 0.0, r),
38        );
39        let renderable = universe.world.add_component(RenderableComponent::new(
40            engine::graphics::primitives::Renderable::new(mesh, MaterialHandle::TOON_MESH),
41        ));
42        let color_c = universe.world.add_component(ColorComponent { rgba: color });
43
44        if emissive {
45            let emissive_c = universe.world.add_component(EmissiveComponent::on());
46            let _ = universe.attach(renderable, emissive_c);
47        }
48
49        // Topology: (optional Input) -> Transform -> Renderable
50        let _ = universe.attach(transform, renderable);
51        let _ = universe.attach(renderable, color_c);
52
53        if input_driven {
54            let input = universe
55                .world
56                .add_component(InputComponent::new().with_speed(0.5));
57            let _ = universe.attach(input, transform);
58            universe.add(input);
59        } else {
60            universe.add(transform);
61        }
62
63        transform
64    }
65
66    fn spawn_3d(
67        universe: &mut engine::Universe,
68        mesh: engine::graphics::primitives::CpuMeshHandle,
69        x: f32,
70        y: f32,
71        z: f32,
72        s: f32,
73        rx: f32,
74        ry: f32,
75        rz: f32,
76        color: [f32; 4],
77    ) -> engine::ecs::ComponentId {
78        let transform = universe.world.add_component(
79            TransformComponent::new()
80                .with_position(x, y, z)
81                .with_scale(s, s, s)
82                .with_rotation_euler(rx, ry, rz),
83        );
84        let renderable = universe.world.add_component(RenderableComponent::new(
85            engine::graphics::primitives::Renderable::new(mesh, MaterialHandle::TOON_MESH),
86        ));
87        let color_c = universe.world.add_component(ColorComponent { rgba: color });
88
89        let _ = universe.attach(transform, renderable);
90        let _ = universe.attach(renderable, color_c);
91        universe.add(transform);
92
93        transform
94    }
95
96    // Spawn shapes.
97    // One triangle is input-driven (WASD/QE). Build a small "rig" so both the triangle
98    // and the camera can be driven by the same InputComponent.
99
100    // Topology: Input -> (InputTransformMode) -> RigTransform -> (CameraTransform -> Camera3D), (TriRootTransform -> ...)
101    let tri_input = universe
102        .world
103        .add_component(InputComponent::new().with_speed(0.5));
104    let input_mode = universe
105        .world
106        .add_component(InputTransformModeComponent::forward_z().with_roll_axis_y());
107    let _ = universe.attach(tri_input, input_mode);
108
109    // Start pulled back so the demo meshes at z=0 are in view.
110    // The camera will be attached directly under this transform, so there is no local
111    // camera offset that would cause orbiting when yawing.
112    let rig_transform = universe
113        .world
114        .add_component(TransformComponent::new().with_position(0.0, 0.0, 2.5));
115    let _ = universe.attach(tri_input, rig_transform);
116
117    // Camera: attached directly to the rig transform.
118    let camera3d = universe.world.add_component(Camera3DComponent::new());
119    let _ = universe.attach(rig_transform, camera3d);
120
121    // Topology: I { T { C3D } } — add a small camera-attached controls hint.
122    example_util::spawn_desktop_camera_controls_hint(universe, rig_transform);
123
124    let tri_root_transform = universe
125        .world
126        .add_component(TransformComponent::new().with_position(0.5, 0.50, 0.0));
127
128    // Visual transform under the root; this is where we apply rotation/scale.
129    let tri_visual_transform = universe.world.add_component(
130        TransformComponent::new()
131            .with_scale(0.30, 0.30, 1.0)
132            .with_rotation_euler(0.0, 0.0, (2.0 * 3.14159 / 3.0) + 3.14159),
133    );
134    let tri_renderable = universe.world.add_component(RenderableComponent::new(
135        engine::graphics::primitives::Renderable::new(tri_mesh, MaterialHandle::TOON_MESH),
136    ));
137    let tri_color = universe
138        .world
139        .add_component(ColorComponent::rgba(0.2, 1.0, 0.2, 1.0));
140
141    let _ = universe.attach(rig_transform, tri_root_transform);
142    let _ = universe.attach(tri_root_transform, tri_visual_transform);
143    let _ = universe.attach(tri_visual_transform, tri_renderable);
144    let _ = universe.attach(tri_renderable, tri_color);
145
146    let tri_light = universe.world.add_component(
147        PointLightComponent::new()
148            .with_distance(10.0)
149            .with_color(1.0, 1.0, 1.0),
150    );
151
152    let light_transform = universe.world.add_component(
153        TransformComponent::new()
154            .with_position(0.5, 0.50, 1.0)
155            .with_scale(0.1, 0.1, 0.1),
156    );
157
158    let _ = universe.attach(light_transform, tri_light);
159
160    universe.add(tri_input);
161    universe.add(light_transform);
162
163    spawn(
164        universe,
165        square_mesh,
166        -0.80,
167        -0.30,
168        0.25,
169        0.0,
170        [1.0, 0.2, 0.2, 1.0],
171        false,
172        true,
173    );
174    spawn(
175        universe,
176        square_mesh,
177        -0.40,
178        -0.30,
179        0.25,
180        0.0,
181        [1.0, 0.6, 0.2, 1.0],
182        false,
183        true,
184    );
185
186    // 3D primitive: tetrahedron.
187    spawn_3d(
188        universe,
189        tetra_mesh,
190        0.55,
191        -0.15,
192        0.0,
193        0.35,
194        0.75,
195        0.55,
196        0.0,
197        [0.2, 0.7, 1.0, 1.0],
198    );
199    spawn(
200        universe,
201        square_mesh,
202        0.00,
203        -0.30,
204        0.25,
205        0.0,
206        [1.0, 1.0, 0.2, 1.0],
207        false,
208        true,
209    );
210    spawn(
211        universe,
212        square_mesh,
213        0.40,
214        -0.30,
215        0.25,
216        0.0,
217        [0.2, 0.6, 1.0, 1.0],
218        false,
219        true,
220    );
221    spawn(
222        universe,
223        square_mesh,
224        0.80,
225        -0.30,
226        0.25,
227        0.0,
228        [0.8, 0.2, 1.0, 1.0],
229        false,
230        true,
231    );
232    spawn(
233        universe,
234        tri_mesh,
235        0.30,
236        0.35,
237        0.30,
238        -3.14159,
239        [1.0, 1.0, 1.0, 1.0],
240        false,
241        false,
242    );
243
244    // Textured square.
245    let tex_transform = universe.world.add_component(
246        TransformComponent::new()
247            .with_position(0.0, 0.1, 0.0)
248            .with_scale(0.45, 0.45, 1.0),
249    );
250    let tex_renderable = universe.world.add_component(RenderableComponent::new(
251        engine::graphics::primitives::Renderable::new(square_mesh, MaterialHandle::TOON_MESH),
252    ));
253    let tex_color = universe
254        .world
255        .add_component(ColorComponent::rgba(1.0, 1.0, 1.0, 1.0));
256    let tex = universe.world.add_component(TextureComponent::from_dds(
257        "assets/textures/cat-face-amused.dds",
258    ));
259
260    let _ = universe.attach(tex_transform, tex_renderable);
261    let _ = universe.attach(tex_renderable, tex_color);
262    let _ = universe.attach(tex_renderable, tex);
263    universe.add(tex_transform);
264
265    // glTF: color-cat
266    // Attach GLTFComponent under a Transform so GLTFSystem can use it as an anchor.
267    let cat_anchor = universe.world.add_component(
268        TransformComponent::new()
269            .with_position(0.0, -0.10, -4.0)
270            .with_scale(0.50, 0.50, 0.50)
271            .with_rotation_euler(0.0, 0.0, 0.0),
272    );
273    let cat_gltf = universe
274        .world
275        .add_component(GLTFComponent::new("assets/models/color-cat.2.glb"));
276    let _ = universe.attach(cat_anchor, cat_gltf);
277    universe.add(cat_anchor);
278}
279
280fn main() {
281    mittens_engine::example_support::ensure_model_assets();
282    utils::logger::init();
283
284    let world = engine::ecs::World::default();
285    let mut universe = engine::Universe::new(world);
286
287    build_demo_scene_7_shapes(&mut universe);
288
289    universe.systems.process_commands(
290        &mut universe.world,
291        &mut universe.visuals,
292        &mut universe.render_assets,
293        &mut universe.command_queue,
294    );
295    universe.enable_repl();
296    engine::Windowing::run_app(universe).expect("Windowing failed");
297}