Skip to main content

RenderableComponent

Struct RenderableComponent 

Source
pub struct RenderableComponent {
    pub renderable: Renderable,
    pub authored_shape: Option<AuthoredRenderableShape>,
    pub handle: Option<InstanceHandle>,
    /* private fields */
}
Expand description

Renderable component.

Fields§

§renderable: Renderable§authored_shape: Option<AuthoredRenderableShape>§handle: Option<InstanceHandle>

VisualWorld instance handle created for this renderable.

Implementations§

Source§

impl RenderableComponent

Source

pub fn new(renderable: Renderable) -> Self

Examples found in repository?
examples/simple-demo.rs (lines 39-41)
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}
More examples
Hide additional examples
examples/vr-input.rs (lines 78-81)
62fn spawn_sun_background(universe: &mut engine::Universe) {
63    let bg_root = universe
64        .world
65        .add_component(engine::ecs::component::BackgroundComponent::new());
66    universe.add(bg_root);
67
68    let circle_mesh = universe.render_assets.get_mesh(BuiltinMeshType::Circle2D);
69
70    // Big yellow disk.
71    let sun_t = universe.world.add_component(
72        TransformComponent::new()
73            .with_position(2.0, 1.5, -8.0)
74            .with_scale(3.5, 3.5, 3.5),
75    );
76    let sun_r = universe
77        .world
78        .add_component(RenderableComponent::new(Renderable::new(
79            circle_mesh,
80            MaterialHandle::TOON_MESH,
81        )));
82    let sun_color = universe
83        .world
84        .add_component(ColorComponent::rgba(1.0, 0.85, 0.15, 1.0));
85    let sun_emissive = universe.world.add_component(EmissiveComponent::on());
86
87    let _ = universe.attach(bg_root, sun_t);
88    let _ = universe.attach(sun_t, sun_r);
89    let _ = universe.attach(sun_r, sun_color);
90    let _ = universe.attach(sun_r, sun_emissive);
91
92    // Small white highlight disk.
93    let highlight_t = universe.world.add_component(
94        TransformComponent::new()
95            .with_position(-0.35, 0.35, -0.01)
96            .with_scale(0.45, 0.45, 0.45),
97    );
98    let highlight_r = universe
99        .world
100        .add_component(RenderableComponent::new(Renderable::new(
101            circle_mesh,
102            MaterialHandle::TOON_MESH,
103        )));
104    let highlight_color = universe
105        .world
106        .add_component(ColorComponent::rgba(1.0, 1.0, 1.0, 1.0));
107    let highlight_emissive = universe.world.add_component(EmissiveComponent::on());
108
109    let _ = universe.attach(sun_t, highlight_t);
110    let _ = universe.attach(highlight_t, highlight_r);
111    let _ = universe.attach(highlight_r, highlight_color);
112    let _ = universe.attach(highlight_r, highlight_emissive);
113}
examples/example_util/mod.rs (lines 161-166)
105pub fn spawn_cloud_ring(
106    universe: &mut engine::Universe,
107    bg_root: engine::ecs::ComponentId,
108    p: CloudRingParams,
109) {
110    if p.cloud_count == 0 || p.radius == 0.0 {
111        return;
112    }
113
114    let cube_mesh = universe
115        .render_assets
116        .get_mesh(engine::graphics::BuiltinMeshType::Cube);
117
118    let step = std::f32::consts::TAU / (p.cloud_count as f32);
119    let angle_jitter = p.angle_jitter.clamp(0.0, 1.0);
120    let high_y_probability = p.high_y_probability.clamp(0.0, 1.0);
121
122    for i in 0..p.cloud_count {
123        let seed_i = p.seed ^ i.wrapping_mul(0x9E37_79B9);
124        let jitter = (rand01(seed_i ^ 0xa53a_9d2d) - 0.5) * step * angle_jitter;
125        let a = (i as f32) * step + jitter;
126        let cx = p.radius * a.cos();
127        let cz = p.radius * a.sin();
128
129        let cy = if rand01(seed_i ^ 0x7f4a_7c15) < high_y_probability {
130            p.center_y * p.high_y_multiplier
131        } else {
132            p.center_y
133        };
134
135        let center_tx = universe.world.add_component(
136            engine::ecs::component::TransformComponent::new().with_position(cx, cy, cz),
137        );
138        let _ = universe.attach(bg_root, center_tx);
139
140        let base_seed = seed_i ^ 0x243f_6a88;
141        for puff_i in 0..p.puffs_per_cloud {
142            let seed = base_seed ^ puff_i.wrapping_mul(1_103_515_245);
143
144            let ox = (rand01(seed ^ 0x68bc_21eb) - 0.5) * 9.0;
145            let oy = (rand01(seed ^ 0x02e5_be93) - 0.5) * 4.0;
146            let oz = (rand01(seed ^ 0xa1d3_4f2b) - 0.5) * 9.0;
147
148            let base = 0.7 + rand01(seed ^ 0x9e37_79b9) * 2.8;
149            let sx = base * (0.7 + rand01(seed ^ 0x243f_6a88) * 0.9);
150            let sy = base * (0.6 + rand01(seed ^ 0x85a3_08d3) * 1.0);
151            let sz = base * (0.7 + rand01(seed ^ 0x1319_8a2e) * 0.9);
152
153            let tx = universe.world.add_component(
154                engine::ecs::component::TransformComponent::new()
155                    .with_position(ox, oy, oz)
156                    .with_scale(sx, sy, sz),
157            );
158            let renderable =
159                universe
160                    .world
161                    .add_component(engine::ecs::component::RenderableComponent::new(
162                        engine::graphics::primitives::Renderable::new(
163                            cube_mesh,
164                            engine::graphics::primitives::MaterialHandle::TOON_MESH,
165                        ),
166                    ));
167
168            let t = rand01(seed ^ 0x7f4a_7c15);
169            let r = 0.70 + 0.10 * t;
170            let g = 0.72 + 0.10 * t;
171            let b = 0.80 + 0.12 * t;
172            let color = universe
173                .world
174                .add_component(engine::ecs::component::ColorComponent::rgba(r, g, b, 1.0));
175
176            let _ = universe.attach(center_tx, tx);
177            let _ = universe.attach(tx, renderable);
178            let _ = universe.attach(renderable, color);
179        }
180    }
181}
examples/mesh-factory-example.rs (lines 107-110)
55    fn spawn_labeled_mesh(
56        universe: &mut engine::Universe,
57        x: f32,
58        y: f32,
59        label: &str,
60        mesh: engine::graphics::primitives::CpuMeshHandle,
61        scale: [f32; 3],
62        color: [f32; 4],
63    ) {
64        use engine::ecs::component::{
65            ActionComponent, AnimationComponent, AnimationState, ColorComponent, EmissiveComponent,
66            KeyframeComponent, RenderableComponent, TextComponent, TransformComponent,
67        };
68        use engine::graphics::primitives::{MaterialHandle, Renderable};
69
70        // Mesh.
71        let root = universe.world.add_component(
72            TransformComponent::new()
73                .with_position(x, y, 0.0)
74                .with_scale(scale[0], scale[1], scale[2]),
75        );
76
77        // Spin each shape around its own +Y axis using AnimationComponent + keyframes.
78        // We fill [0, 2) beats densely so it looks smooth.
79        let anim = universe
80            .world
81            .add_component(AnimationComponent::new().with_state(AnimationState::Looping));
82        let _ = universe.attach(root, anim);
83
84        let steps: usize = 64;
85        for i in 0..steps {
86            let beat = (i as f64) * (2.0 / (steps as f64));
87            let kf = universe.world.add_component(KeyframeComponent::new(beat));
88            let _ = universe.attach(anim, kf);
89
90            // Full turn over 2 beats.
91            let angle = (std::f64::consts::TAU * (beat / 2.0)) as f32;
92            let rotation = utils::math::quat_from_axis_angle([0.0, 1.0, 0.0], angle);
93
94            let action_cid = universe.world.add_component(ActionComponent::new(
95                engine::ecs::IntentValue::UpdateTransform {
96                    component_ids: vec![root],
97                    translation: [x, y, 0.0],
98                    rotation_quat_xyzw: rotation,
99                    scale,
100                },
101            ));
102            let _ = universe.attach(kf, action_cid);
103        }
104
105        let renderable = universe
106            .world
107            .add_component(RenderableComponent::new(Renderable::new(
108                mesh,
109                MaterialHandle::TOON_MESH,
110            )));
111        let color_c = universe
112            .world
113            .add_component(ColorComponent::rgba(color[0], color[1], color[2], color[3]));
114        let emissive = universe.world.add_component(EmissiveComponent::on());
115
116        let _ = universe.attach(root, renderable);
117        let _ = universe.attach(renderable, color_c);
118        let _ = universe.attach(renderable, emissive);
119
120        universe.add(root);
121
122        // Label (separate transform so we can scale text independently).
123        let text_root = universe.world.add_component(
124            TransformComponent::new()
125                .with_position(x, y + 0.75, 0.05)
126                .with_scale(0.09, 0.09, 1.0),
127        );
128        let text = universe
129            .world
130            .add_component(TextComponent::with_word_wrap_tokens(
131                label,
132                LABEL_WRAP_AT,
133                ["::", "(", ")", ",", "."],
134            ));
135        let text_color = universe
136            .world
137            .add_component(ColorComponent::rgba(1.0, 1.0, 1.0, 1.0));
138        let text_emissive = universe.world.add_component(EmissiveComponent::on());
139        let _ = universe.attach(text_root, text);
140        let _ = universe.attach(text, text_color);
141        let _ = universe.attach(text, text_emissive);
142        universe.add(text_root);
143    }
examples/openxr.rs (lines 106-111)
6fn main() {
7    mittens_engine::example_support::ensure_model_assets();
8    utils::logger::init();
9
10    let world = engine::ecs::World::default();
11    let mut universe = engine::Universe::new(world);
12
13    let background = universe
14        .world
15        .add_component(engine::ecs::component::BackgroundColorComponent::new());
16    let background_c = universe
17        .world
18        .add_component(engine::ecs::component::ColorComponent::rgba(
19            0.3, 0.1, 1.0, 1.0,
20        ));
21    let _ = universe.world.add_child(background, background_c);
22    universe.add(background);
23
24    // --- Camera rig (WASD/QE) ---
25    // Keep this similar to the main demo so we can fly around the cube field.
26    let input = universe
27        .world
28        .add_component(engine::ecs::component::InputComponent::new().with_speed(1.5));
29    let input_mode = universe.world.add_component(
30        engine::ecs::component::InputTransformModeComponent::forward_z().with_roll_axis_y(),
31    );
32    let _ = universe.attach(input, input_mode);
33
34    // Start pulled back so the grid is in view.
35    let rig_transform = universe.world.add_component(
36        engine::ecs::component::TransformComponent::new().with_position(0.0, 0.0, 4.0),
37    );
38    let _ = universe.attach(input, rig_transform);
39
40    let camera3d = universe
41        .world
42        .add_component(engine::ecs::component::Camera3DComponent::new());
43    let _ = universe.attach(rig_transform, camera3d);
44
45    // Topology: I { T { C3D } } — add a small camera-attached controls hint.
46    example_util::spawn_desktop_camera_controls_hint(&mut universe, rig_transform);
47
48    // Simple point light so the toon shader reads well.
49    let light = universe.world.add_component(
50        engine::ecs::component::PointLightComponent::new()
51            .with_distance(50.0)
52            .with_color(1.0, 1.0, 1.0),
53    );
54    let light_transform = universe.world.add_component(
55        engine::ecs::component::TransformComponent::new().with_position(0.0, 5.0, 2.0),
56    );
57    let _ = universe.attach(light_transform, light);
58
59    universe.add(input);
60    universe.add(light_transform);
61
62    // --- 16x16x16 cube grid ---
63    let cube_mesh = universe
64        .render_assets
65        .get_mesh(engine::graphics::BuiltinMeshType::Cube);
66
67    let n: usize = 32;
68    let cube_scale: f32 = 0.10;
69    let gap: f32 = 0.50;
70    let step: f32 = cube_scale + gap;
71
72    // Center positions around 0 by subtracting half the extent (in steps).
73    let half_extent_x = (n as f32 - 1.0) * step * 0.5;
74    let half_extent_y = (n as f32 - 1.0) * step * 0.5;
75    let half_extent_z = (n as f32 - 1.0) * step * 0.5;
76
77    // Move the whole container up/back based on its content size, plus the requested offsets.
78    // - up by +0.5 and by half the content height
79    // - back by -(0.5 + 1.0) and by half the content depth
80    let container_offset_y = half_extent_y + 0.5;
81    let container_offset_z = -(half_extent_z + 1.0 + 0.5);
82
83    let container = universe.world.add_component(
84        engine::ecs::component::TransformComponent::new().with_position(
85            0.0,
86            container_offset_y,
87            container_offset_z,
88        ),
89    );
90
91    for z in 0..n {
92        for y in 0..n {
93            for x in 0..n {
94                let px = x as f32 * step - half_extent_x;
95                let py = y as f32 * step - half_extent_y;
96                let pz = z as f32 * step - half_extent_z;
97
98                let tx = universe.world.add_component(
99                    engine::ecs::component::TransformComponent::new()
100                        .with_position(px, py, pz)
101                        .with_scale(cube_scale, cube_scale, cube_scale),
102                );
103                let renderable =
104                    universe
105                        .world
106                        .add_component(engine::ecs::component::RenderableComponent::new(
107                            engine::graphics::primitives::Renderable::new(
108                                cube_mesh,
109                                engine::graphics::primitives::MaterialHandle::TOON_MESH,
110                            ),
111                        ));
112
113                let denom = (n - 1) as f32;
114                let color = engine::ecs::component::ColorComponent::rgba(
115                    f32::sin(x as f32 / 10.0),
116                    y as f32 / denom,
117                    z as f32 / denom,
118                    1.0,
119                );
120                let color_c = universe.world.add_component(color);
121
122                let _ = universe.attach(container, tx);
123                let _ = universe.attach(tx, renderable);
124                let _ = universe.attach(renderable, color_c);
125            }
126        }
127    }
128
129    universe.add(container);
130    universe.systems.process_commands(
131        &mut universe.world,
132        &mut universe.visuals,
133        &mut universe.render_assets,
134        &mut universe.command_queue,
135    );
136
137    let xr_input = universe
138        .world
139        .add_component(engine::ecs::component::InputXRComponent::on());
140    let xr_gamepad = universe
141        .world
142        .add_component(engine::ecs::component::InputXRGamepadComponent::new().speed(1.5));
143    let xr_head = universe
144        .world
145        .add_component(engine::ecs::component::TransformComponent::new());
146    let camera_xr = universe
147        .world
148        .add_component(engine::ecs::component::CameraXRComponent::on());
149    let _ = universe.attach(xr_input, xr_head);
150    let _ = universe.attach(xr_input, xr_gamepad);
151    let _ = universe.attach(xr_head, camera_xr);
152    universe.add(xr_input);
153
154    // Add an OpenXR component so OpenXRSystem initializes and starts polling events.
155    let xr_root = universe
156        .world
157        .add_component(engine::ecs::component::XrComponent::on());
158    universe.add(xr_root);
159    universe.systems.process_commands(
160        &mut universe.world,
161        &mut universe.visuals,
162        &mut universe.render_assets,
163        &mut universe.command_queue,
164    );
165
166    universe.enable_repl();
167    engine::Windowing::run_app(universe).expect("Windowing failed");
168}
examples/gestures-and-gizmos.rs (lines 52-55)
13fn build_gestures_and_gizmos_scene(universe: &mut engine::Universe) -> Scene {
14    use engine::ecs::component::{
15        BackgroundColorComponent, BackgroundComponent, Camera3DComponent, ColorComponent,
16        DirectionalLightComponent, InputComponent, InputTransformModeComponent, PointerComponent,
17        RaycastableComponent, RenderableComponent, TransformComponent, TransformGizmoComponent,
18    };
19    use engine::graphics::BuiltinMeshType;
20    use engine::graphics::primitives::{MaterialHandle, Renderable};
21
22    let tri_mesh = universe.render_assets.get_mesh(BuiltinMeshType::Triangle2D);
23    let cube_mesh = universe.render_assets.get_mesh(BuiltinMeshType::Cube);
24    let tetra_mesh = universe
25        .render_assets
26        .get_mesh(BuiltinMeshType::Tetrahedron);
27
28    // BackgroundColor { C.rgba }
29    let bg_color = universe
30        .world
31        .add_component(BackgroundColorComponent::new());
32    let bg_color_c = universe
33        .world
34        .add_component(ColorComponent::rgba(0.90, 0.90, 0.90, 1.0));
35    let _ = universe.world.add_child(bg_color, bg_color_c);
36    universe.add(bg_color);
37
38    // ambient light
39    let ambient = universe
40        .world
41        .add_component(AmbientLightComponent::rgb(0.25, 0.25, 0.25));
42    universe.add(ambient);
43
44    // ground plane
45    let ground_tx = universe.world.add_component(
46        TransformComponent::new()
47            .with_position(0.0, -2.5, 0.0)
48            .with_scale(20.0, 1.0, 20.0),
49    );
50    let ground_r = universe
51        .world
52        .add_component(RenderableComponent::new(Renderable::new(
53            universe.render_assets.get_mesh(BuiltinMeshType::Cube),
54            MaterialHandle::TOON_MESH,
55        )));
56    let ground_c = universe
57        .world
58        .add_component(ColorComponent::rgba(0.75, 0.75, 0.75, 1.0));
59    let _ = universe.attach(ground_tx, ground_r);
60    let _ = universe.attach(ground_r, ground_c);
61    let _ = universe.add(ground_tx);
62
63    // Background {
64    //     with_occlusion_and_lighting()
65    //     // using the example utils to add clouds to the background
66    // }
67    let bg_root = universe
68        .world
69        .add_component(BackgroundComponent::new().with_occlusion_and_lighting());
70    universe.add(bg_root);
71
72    // DirectionalLight {
73    //     T { translate [1, 1, 1] }
74    // }
75    // Directional lights encode their direction in the node's world position.
76    let sun_t = universe
77        .world
78        .add_component(TransformComponent::new().with_position(1.0, 1.0, 1.0));
79    let sun = universe
80        .world
81        .add_component(DirectionalLightComponent::new());
82    let _ = universe.attach(sun_t, sun);
83    universe.add(sun_t);
84
85    // i = input
86    // t = transform
87    // c3d = camera3d
88    //
89    // I {
90    //     T {
91    //         C3D { with_fps_rotation().with_roll_axis_y() }
92    //     }
93    // }
94    let input = universe
95        .world
96        .add_component(InputComponent::new().with_speed(2.5));
97    let input_mode = universe.world.add_component(
98        InputTransformModeComponent::forward_z()
99            .with_fps_rotation()
100            .with_roll_axis_y(),
101    );
102
103    let _ = universe.attach(input, input_mode);
104
105    // Forward is -Z, so put the camera at +Z looking toward the origin.
106    let rig_t = universe
107        .world
108        .add_component(TransformComponent::new().with_position(0.0, 0.0, 3.5));
109    let _ = universe.attach(input, rig_t);
110
111    let cam = universe
112        .world
113        .add_component(Camera3DComponent::new().with_far(600.0).with_fov(70.0));
114    let _ = universe.attach(rig_t, cam);
115
116    // Opt-in: treat this camera rig as a pointer source.
117    let pointer = universe.world.add_component(PointerComponent::new());
118    let _ = universe.attach(cam, pointer);
119
120    // Topology: I { T { C3D } } — add a small camera-attached controls hint.
121    example_util::spawn_desktop_camera_controls_hint(universe, rig_t);
122
123    fn spawn_shape_with_gizmo(
124        universe: &mut engine::Universe,
125        mesh: engine::graphics::primitives::CpuMeshHandle,
126        pos: [f32; 3],
127        scale: [f32; 3],
128        rot_euler: [f32; 3],
129        color: [f32; 4],
130    ) {
131        let t = universe.world.add_component(
132            TransformComponent::new()
133                .with_position(pos[0], pos[1], pos[2])
134                .with_scale(scale[0], scale[1], scale[2])
135                .with_rotation_euler(rot_euler[0], rot_euler[1], rot_euler[2]),
136        );
137        let r = universe
138            .world
139            .add_component(RenderableComponent::new(Renderable::new(
140                mesh,
141                MaterialHandle::TOON_MESH,
142            )));
143        let c = universe
144            .world
145            .add_component(ColorComponent::rgba(color[0], color[1], color[2], color[3]));
146        let rc = universe
147            .world
148            .add_component(RaycastableComponent::enabled());
149        let g = universe.world.add_component(TransformGizmoComponent::new());
150
151        let _ = universe.attach(t, r);
152        let _ = universe.attach(r, c);
153        let _ = universe.attach(r, rc);
154        let _ = universe.attach(t, g);
155
156        universe.add(t);
157    }
158
159    fn spawn_shape_raycastable_no_gizmo(
160        universe: &mut engine::Universe,
161        mesh: engine::graphics::primitives::CpuMeshHandle,
162        pos: [f32; 3],
163        scale: [f32; 3],
164        rot_euler: [f32; 3],
165        color: [f32; 4],
166    ) {
167        let t = universe.world.add_component(
168            TransformComponent::new()
169                .with_position(pos[0], pos[1], pos[2])
170                .with_scale(scale[0], scale[1], scale[2])
171                .with_rotation_euler(rot_euler[0], rot_euler[1], rot_euler[2]),
172        );
173        let r = universe
174            .world
175            .add_component(RenderableComponent::new(Renderable::new(
176                mesh,
177                MaterialHandle::TOON_MESH,
178            )));
179        let c = universe
180            .world
181            .add_component(ColorComponent::rgba(color[0], color[1], color[2], color[3]));
182        let rc = universe
183            .world
184            .add_component(RaycastableComponent::enabled());
185
186        let _ = universe.attach(t, r);
187        let _ = universe.attach(r, c);
188        let _ = universe.attach(r, rc);
189
190        universe.add(t);
191    }
192
193    spawn_shape_with_gizmo(
194        universe,
195        tri_mesh,
196        [-1.2, 0.0, 0.0],
197        [0.65, 0.65, 0.65],
198        [0.0, 0.0, 0.0],
199        [0.2, 0.9, 0.25, 1.0],
200    );
201    spawn_shape_with_gizmo(
202        universe,
203        cube_mesh,
204        [0.0, 0.0, 0.0],
205        [0.55, 0.55, 0.55],
206        [0.0, 0.0, 0.0],
207        [0.95, 0.25, 0.2, 1.0],
208    );
209    spawn_shape_with_gizmo(
210        universe,
211        tetra_mesh,
212        [1.2, 0.0, 0.0],
213        [0.7, 0.7, 0.7],
214        [0.0, 0.0, 0.0],
215        [0.2, 0.55, 1.0, 1.0],
216    );
217
218    // Standalone tetrahedron: no gizmo, but explicitly raycastable.
219    // This helps isolate tetra picking vs gizmo-handle interception.
220    spawn_shape_raycastable_no_gizmo(
221        universe,
222        tetra_mesh,
223        [2.6, -0.6, 0.0],
224        [0.95, 0.95, 0.95],
225        [0.0, 0.0, 0.0],
226        [0.85, 0.85, 1.0, 1.0],
227    );
228
229    universe.add(input);
230
231    Scene { bg_root }
232}
Source

pub fn from_cpu_mesh_handle(h: CpuMeshHandle, material: MaterialHandle) -> Self

Source

pub fn get_handle(&self) -> Option<InstanceHandle>

Examples found in repository?
examples/vtuber-joints-example.rs (line 440)
422fn debug_print_selected_joint_influence(
423    universe: &engine::Universe,
424    mesh_key: &str,
425    model_root: engine::ecs::ComponentId,
426    selected: &[(usize, engine::ecs::ComponentId)],
427) {
428    let Some(renderable) = find_renderable_by_mesh_key(&universe.world, model_root, mesh_key)
429    else {
430        println!(
431            "[vtuber-joints-example] influence: mesh_key='{}' renderable not found",
432            mesh_key
433        );
434        return;
435    };
436
437    let renderable_handle = universe
438        .world
439        .get_component_by_id_as::<RenderableComponent>(renderable)
440        .and_then(|r| r.get_handle());
441    println!(
442        "[vtuber-joints-example] influence: mesh_key='{}' renderable={:?} instance_handle={:?}",
443        mesh_key, renderable, renderable_handle
444    );
445    let Some(skin_id) = find_skin_id_for_renderable(&universe.world, renderable) else {
446        println!(
447            "[vtuber-joints-example] influence: mesh_key='{}' has no skin_id",
448            mesh_key
449        );
450        return;
451    };
452    let Some(skin) = universe.visuals.skin(skin_id) else {
453        println!(
454            "[vtuber-joints-example] influence: skin_id={:?} missing in visuals",
455            skin_id
456        );
457        return;
458    };
459    let Some(cpu_h) = universe.render_assets.imported_mesh(mesh_key) else {
460        println!(
461            "[vtuber-joints-example] influence: mesh_key='{}' missing in RenderAssets (did meshes register?)",
462            mesh_key
463        );
464        return;
465    };
466    let Some(cpu) = universe.render_assets.cpu_mesh(cpu_h) else {
467        println!(
468            "[vtuber-joints-example] influence: mesh_key='{}' cpu mesh handle invalid",
469            mesh_key
470        );
471        return;
472    };
473    let (Some(joints0), Some(weights0)) = (cpu.joints0.as_ref(), cpu.weights0.as_ref()) else {
474        println!(
475            "[vtuber-joints-example] influence: mesh_key='{}' has no skin attributes",
476            mesh_key
477        );
478        return;
479    };
480
481    let joint_count = skin.joint_count();
482    let totals = compute_total_weight_per_joint(joints0, weights0, joint_count);
483
484    println!(
485        "[vtuber-joints-example] influence: mesh_key='{}' verts={} joints={}",
486        mesh_key,
487        cpu.vertices.len(),
488        joint_count
489    );
490
491    for &(node_index, joint_tx) in selected.iter() {
492        // Find the skin joint index that maps to this node.
493        let skin_joint_index = skin
494            .joint_node_indices
495            .iter()
496            .position(|&ni| ni == node_index);
497
498        let name = universe
499            .world
500            .get_component_record(joint_tx)
501            .map(|r| r.name.as_str())
502            .unwrap_or("<unknown>");
503
504        match skin_joint_index {
505            Some(j) => {
506                let total = totals.get(j).copied().unwrap_or(0.0);
507                println!(
508                    "  influence: name='{}' node_index={} skin_joint_index={} total_weight={:.3}",
509                    name, node_index, j, total
510                );
511            }
512            None => {
513                println!(
514                    "  influence: name='{}' node_index={} skin_joint_index=<none>",
515                    name, node_index
516                );
517            }
518        }
519    }
520}
Source

pub fn triangle() -> Self

Predefined renderable: 2D triangle (shared built-in mesh handle).

Source

pub fn triangle_dynamic(render_assets: &mut RenderAssets) -> Self

Predefined renderable: 2D triangle (unique CPU mesh registered into render_assets).

Source

pub fn square() -> Self

Predefined renderable: 2D square/quad (shared built-in mesh handle).

Examples found in repository?
examples/triage/panel-pierce.rs (line 40)
16fn spawn_row(
17    universe: &mut engine::Universe,
18    scrolling: engine::ecs::ComponentId,
19    index: usize,
20) -> engine::ecs::ComponentId {
21    use engine::ecs::component::{
22        ColorComponent, RenderableComponent, TextComponent, TransformComponent,
23    };
24
25    let label = format!("row_{index:02}");
26    let row = universe.world.add_component_boxed_named(
27        label.clone(),
28        Box::new(TransformComponent::new().with_position(0.0, -(index as f32) * 1.15, 0.05)),
29    );
30    let panel = universe.world.add_component_boxed_named(
31        format!("{label}_panel"),
32        Box::new(
33            TransformComponent::new()
34                .with_position(2.3, -0.45, 0.0)
35                .with_scale(4.6, 0.9, 1.0),
36        ),
37    );
38    let panel_renderable = universe.world.add_component_boxed_named(
39        format!("{label}_rend"),
40        Box::new(RenderableComponent::square()),
41    );
42    let panel_color = universe
43        .world
44        .add_component(ColorComponent::rgba(0.98, 0.94, 0.78, 1.0));
45
46    let text_anchor = universe.world.add_component_boxed_named(
47        format!("{label}_text_anchor"),
48        Box::new(
49            TransformComponent::new()
50                .with_position(0.35, -0.38, 0.02)
51                .with_scale(0.11, 0.11, 0.11),
52        ),
53    );
54    let text = universe.world.add_component_boxed_named(
55        format!("{label}_text"),
56        Box::new(TextComponent::new(label.clone())),
57    );
58    let text_color = universe
59        .world
60        .add_component(ColorComponent::rgba(0.20, 0.16, 0.08, 1.0));
61
62    let _ = universe.world.add_child(row, panel);
63    let _ = universe.world.add_child(panel, panel_renderable);
64    let _ = universe.world.add_child(panel_renderable, panel_color);
65    let _ = universe.world.add_child(row, text_anchor);
66    let _ = universe.world.add_child(text_anchor, text);
67    let _ = universe.world.add_child(text, text_color);
68
69    universe.attach(scrolling, row).expect("attach scroll row");
70    row
71}
More examples
Hide additional examples
examples/opacity-example.rs (line 119)
91fn spawn_text_label_with_bg(
92    universe: &mut engine::Universe,
93    position: (f32, f32, f32),
94    text: &str,
95    bg_opacity: f32,
96) {
97    // T_root {
98    //   T_bg { R_bg { Color black, Opacity } }
99    //   T_scale { TXT { filtering } }
100    // }
101
102    let text_root = universe
103        .world
104        .add_component(TransformComponent::new().with_position(position.0, position.1, position.2));
105
106    // Background quad (slightly behind the glyph quads).
107    let (cols, rows) = text_block_dimensions(text);
108    let text_scale = 0.18_f32;
109    let pad_x = 0.55_f32;
110    let pad_y = 0.45_f32;
111    let bg_w = cols as f32 * text_scale + pad_x;
112    let bg_h = rows as f32 * text_scale + pad_y;
113
114    let bg_t = universe.world.add_component(
115        TransformComponent::new()
116            .with_position(1.5, 0.0, -0.02)
117            .with_scale(bg_w, bg_h, 1.0),
118    );
119    let bg_r = universe.world.add_component(RenderableComponent::square());
120    let _ = universe.attach(text_root, bg_t);
121    let _ = universe.attach(bg_t, bg_r);
122
123    let bg_c = universe
124        .world
125        .add_component(ColorComponent::rgba(0.0, 0.0, 0.0, 1.0));
126    let _ = universe.attach(bg_r, bg_c);
127
128    let bg_o = universe
129        .world
130        .add_component(OpacityComponent::new().with_opacity(bg_opacity));
131    let _ = universe.attach(bg_r, bg_o);
132
133    let text_scale_t = universe
134        .world
135        .add_component(TransformComponent::new().with_scale(text_scale, text_scale, 1.0));
136    let _ = universe.attach(text_root, text_scale_t);
137
138    let text_c = universe.world.add_component(TextComponent::new(text));
139    let _ = universe.attach(text_scale_t, text_c);
140
141    // Keep it crisp.
142    let filtering = universe
143        .world
144        .add_component(TextureFilteringComponent::nearest());
145    let _ = universe.attach(text_c, filtering);
146
147    // Force the label into the transparent pass so it layers correctly with the background.
148    // (Pass selection currently does not consider texture alpha.)
149    let color = universe
150        .world
151        .add_component(ColorComponent::rgba(1.0, 1.0, 1.0, 0.998));
152    let _ = universe.attach(text_c, color);
153
154    universe.add(text_root);
155}
examples/scrolling.rs (line 57)
30fn spawn_scroll_item(
31    universe: &mut engine::Universe,
32    scrolling: engine::ecs::ComponentId,
33    prefix: &str,
34    index: usize,
35    panel_rgba: [f32; 4],
36    text_rgba: [f32; 4],
37) -> engine::ecs::ComponentId {
38    use engine::ecs::component::{
39        ColorComponent, RenderableComponent, TextComponent, TransformComponent,
40    };
41
42    let label = format!("{prefix}_item_{index:02}");
43    let root = universe.world.add_component_boxed_named(
44        label.clone(),
45        Box::new(TransformComponent::new().with_position(0.0, -(index as f32) * 1.15, 0.05)),
46    );
47    let panel = universe.world.add_component_boxed_named(
48        format!("{label}_panel"),
49        Box::new(
50            TransformComponent::new()
51                .with_position(2.3, -0.45, 0.0)
52                .with_scale(4.6, 0.9, 1.0),
53        ),
54    );
55    let panel_renderable = universe.world.add_component_boxed_named(
56        format!("{label}_renderable"),
57        Box::new(RenderableComponent::square()),
58    );
59    let panel_color = universe.world.add_component(ColorComponent::rgba(
60        panel_rgba[0],
61        panel_rgba[1],
62        panel_rgba[2],
63        panel_rgba[3],
64    ));
65
66    let text_anchor = universe.world.add_component_boxed_named(
67        format!("{label}_text_anchor"),
68        Box::new(
69            TransformComponent::new()
70                .with_position(0.35, -0.38, 0.02)
71                .with_scale(0.11, 0.11, 0.11),
72        ),
73    );
74    let text = universe.world.add_component_boxed_named(
75        format!("{label}_text"),
76        Box::new(TextComponent::new(label.clone())),
77    );
78    let text_color = universe.world.add_component(ColorComponent::rgba(
79        text_rgba[0],
80        text_rgba[1],
81        text_rgba[2],
82        text_rgba[3],
83    ));
84
85    let _ = universe.world.add_child(root, panel);
86    let _ = universe.world.add_child(panel, panel_renderable);
87    let _ = universe.world.add_child(panel_renderable, panel_color);
88    let _ = universe.world.add_child(root, text_anchor);
89    let _ = universe.world.add_child(text_anchor, text);
90    let _ = universe.world.add_child(text, text_color);
91
92    universe
93        .attach(scrolling, root)
94        .expect("attach scroll item");
95    root
96}
examples/transparent-cutout-example.rs (line 121)
34fn main() {
35    mittens_engine::example_support::ensure_model_assets();
36    utils::logger::init();
37
38    let world = engine::ecs::World::default();
39    let mut universe = engine::Universe::new(world);
40
41    // Orange/yellow-ish clear color so cutout edges read.
42    let clear = universe
43        .world
44        .add_component(BackgroundColorComponent::new());
45    let clear_c = universe
46        .world
47        .add_component(ColorComponent::rgba(0.98, 0.72, 0.22, 1.0));
48    let _ = universe.world.add_child(clear, clear_c);
49    universe.add(clear);
50
51    // Warm-ish ambient so the gold cubes don’t go too dark.
52    let ambient = universe
53        .world
54        .add_component(AmbientLightComponent::rgb(0.22, 0.16, 0.08));
55    universe.add(ambient);
56
57    // --- Camera rig (WASD/QE) ---
58    let input = universe
59        .world
60        .add_component(InputComponent::new().with_speed(2.0));
61    let input_mode = universe
62        .world
63        .add_component(InputTransformModeComponent::forward_z().with_roll_axis_y());
64    let _ = universe.attach(input, input_mode);
65
66    // Start a bit pulled back, looking toward the origin.
67    let rig_transform = universe
68        .world
69        .add_component(TransformComponent::new().with_position(0.0, 0.0, 5.0));
70    let _ = universe.attach(input, rig_transform);
71
72    let camera3d = universe
73        .world
74        .add_component(Camera3DComponent::new().with_far(200.0).with_fov(55.0));
75    let _ = universe.attach(rig_transform, camera3d);
76
77    // Topology: I { T { C3D } } — add a small camera-attached controls hint.
78    example_util::spawn_desktop_camera_controls_hint(&mut universe, rig_transform);
79    universe.add(input);
80
81    // Key light for toon shading.
82    let light = universe.world.add_component(
83        PointLightComponent::new()
84            .with_distance(50.0)
85            .with_intensity(2.2)
86            .with_color(1.0, 0.98, 0.92),
87    );
88    let light_transform = universe
89        .world
90        .add_component(TransformComponent::new().with_position(2.0, 3.0, 4.0));
91    let _ = universe.attach(light_transform, light);
92    universe.add(light_transform);
93
94    // --- Transparent cutout: 100 cat faces in a 10x10 grid ---
95    // Place them *behind* the starting camera position (camera starts at z=+5.0).
96    // Not attached to the camera rig.
97    let cat_grid_root = universe
98        .world
99        .add_component(TransformComponent::new().with_position(0.0, 0.0, 9.0));
100    universe.add(cat_grid_root);
101
102    let grid_w: i32 = 10;
103    let grid_h: i32 = 10;
104    let spacing: f32 = 0.7;
105    let half_w = (grid_w as f32 - 1.0) * spacing * 0.5;
106    let half_h = (grid_h as f32 - 1.0) * spacing * 0.5;
107
108    for y in 0..grid_h {
109        for x in 0..grid_w {
110            // Topology: cat_grid_root { T_quad { R_quad { Texture + Filtering + Cutout + Color } } }
111            let px = x as f32 * spacing - half_w;
112            let py = y as f32 * spacing - half_h;
113
114            let pz: f32 = (x as f32) % half_w;
115
116            let quad_t = universe.world.add_component(
117                TransformComponent::new()
118                    .with_position(px, py, pz)
119                    .with_scale(0.55, 0.55, 1.0),
120            );
121            let quad_r = universe.world.add_component(RenderableComponent::square());
122
123            let quad_tex = universe.world.add_component(TextureComponent::with_uri(
124                "assets/textures/cat-face-amused.dds",
125            ));
126            let quad_filtering = universe
127                .world
128                .add_component(TextureFilteringComponent::linear());
129            let quad_cutout = universe
130                .world
131                .add_component(TransparentCutoutComponent::new());
132            let quad_color = universe
133                .world
134                .add_component(ColorComponent::rgba(1.0, 1.0, 1.0, 1.0));
135
136            let _ = universe.attach(cat_grid_root, quad_t);
137            let _ = universe.attach(quad_t, quad_r);
138            let _ = universe.attach(quad_r, quad_tex);
139            let _ = universe.attach(quad_r, quad_filtering);
140            let _ = universe.attach(quad_r, quad_cutout);
141            let _ = universe.attach(quad_r, quad_color);
142        }
143    }
144
145    // --- Gold/yellow cubes behind the quad ---
146    // Parent them under a transform so it’s easy to tweak their depth.
147    let cubes_root = universe
148        .world
149        .add_component(TransformComponent::new().with_position(0.0, 0.0, 4.6));
150
151    // point light for cats
152    let cat_light_tx = universe
153        .world
154        .add_component(TransformComponent::new().with_position(0.0, 2.0, 7.0));
155
156    let cat_light = universe.world.add_component(
157        PointLightComponent::new()
158            .with_distance(150.0)
159            .with_intensity(1.5)
160            .with_color(1.0, 0.98, 0.92),
161    );
162    let _ = universe.attach(cat_light_tx, cat_light);
163    let _ = universe.attach(cubes_root, cat_light_tx);
164
165    universe.add(cubes_root);
166
167    let gold_a = (1.0, 0.86, 0.22);
168    let gold_b = (1.0, 0.74, 0.10);
169    let gold_c = (0.95, 0.92, 0.32);
170
171    // A loose cluster that’s visible through the cutout (transparent) area.
172    spawn_gold_cube(&mut universe, cubes_root, (-1.1, -0.3, -0.2), 0.45, gold_a);
173    spawn_gold_cube(&mut universe, cubes_root, (1.0, -0.4, -0.4), 0.40, gold_b);
174    spawn_gold_cube(&mut universe, cubes_root, (-0.2, 0.9, -0.6), 0.38, gold_c);
175    spawn_gold_cube(&mut universe, cubes_root, (0.7, 0.6, -0.9), 0.32, gold_a);
176    spawn_gold_cube(&mut universe, cubes_root, (-0.8, 0.4, -1.1), 0.36, gold_b);
177
178    // Bigger orange/yellow cubes behind the cluster (to make the cutout depth obvious).
179    let orange_gold_a = (1.0, 0.62, 0.10);
180    let orange_gold_b = (1.0, 0.78, 0.18);
181    spawn_gold_cube(
182        &mut universe,
183        cubes_root,
184        (0.0, -0.1, -2.1),
185        1.15,
186        orange_gold_b,
187    );
188    spawn_gold_cube(
189        &mut universe,
190        cubes_root,
191        (-1.8, 0.6, -2.6),
192        0.95,
193        orange_gold_a,
194    );
195    spawn_gold_cube(
196        &mut universe,
197        cubes_root,
198        (1.9, 0.7, -2.9),
199        1.05,
200        orange_gold_b,
201    );
202    spawn_gold_cube(
203        &mut universe,
204        cubes_root,
205        (0.9, 1.8, -3.2),
206        0.90,
207        orange_gold_a,
208    );
209    spawn_gold_cube(
210        &mut universe,
211        cubes_root,
212        (-0.9, 1.7, -3.5),
213        1.10,
214        orange_gold_b,
215    );
216
217    // Process init-time registrations (loads textures, registers renderables, etc.).
218    universe.systems.process_commands(
219        &mut universe.world,
220        &mut universe.visuals,
221        &mut universe.render_assets,
222        &mut universe.command_queue,
223    );
224
225    universe.enable_repl();
226    engine::Windowing::run_app(universe).expect("Windowing failed");
227}
examples/text-example.rs (line 43)
6fn main() {
7    mittens_engine::example_support::ensure_model_assets();
8    utils::logger::init();
9
10    let world = engine::ecs::World::default();
11    let mut universe = engine::Universe::new(world);
12
13    // Input-driven camera rig.
14    // Topology: I { T { C3D } }
15    let input = universe
16        .world
17        .add_component(engine::ecs::component::InputComponent::new().with_speed(1.5));
18    let camera3d = universe
19        .world
20        .add_component(engine::ecs::component::Camera3DComponent::new());
21    let rig_transform = universe.world.add_component(
22        engine::ecs::component::TransformComponent::new().with_position(0.0, 0.0, 2.5),
23    );
24    let input_mode = universe.world.add_component(
25        engine::ecs::component::InputTransformModeComponent::forward_z().with_roll_axis_y(),
26    );
27    let _ = universe.attach(input, input_mode);
28    let _ = universe.attach(input, rig_transform);
29    let _ = universe.attach(rig_transform, camera3d);
30
31    // Topology: I { T { C3D } } — add a small camera-attached controls hint.
32    example_util::spawn_desktop_camera_controls_hint(&mut universe, rig_transform);
33    universe.add(input);
34
35    // Debug square: show the full font texture.
36    let debug_root = universe.world.add_component(
37        engine::ecs::component::TransformComponent::new()
38            .with_position(0.6, -0.2, 0.0)
39            .with_scale(0.8, 0.8, 1.0),
40    );
41    let debug_renderable = universe
42        .world
43        .add_component(engine::ecs::component::RenderableComponent::square());
44    let debug_tex =
45        universe
46            .world
47            .add_component(engine::ecs::component::TextureComponent::with_uri(
48                "assets/textures/font_system.dds",
49            ));
50    let debug_filtering = universe
51        .world
52        .add_component(engine::ecs::component::TextureFilteringComponent::nearest_magnification());
53    let _ = universe.attach(debug_root, debug_renderable);
54    let _ = universe.attach(debug_renderable, debug_tex);
55    let _ = universe.attach(debug_renderable, debug_filtering);
56    universe.add(debug_root);
57
58    // Light so we can actually see non-emissive materials.
59    let light_transform = universe.world.add_component(
60        engine::ecs::component::TransformComponent::new().with_position(0.0, 0.0, 2.0),
61    );
62    let light = universe.world.add_component(
63        engine::ecs::component::PointLightComponent::new()
64            .with_distance(25.0)
65            .with_color(1.0, 1.0, 1.0),
66    );
67    let _ = universe.attach(light_transform, light);
68    universe.add(light_transform);
69
70    // 4 red cubes around the perimeter of the world (easy visual anchors).
71    fn spawn_red_cube(universe: &mut engine::Universe, x: f32, y: f32, z: f32, s: f32) {
72        let t = universe.world.add_component(
73            engine::ecs::component::TransformComponent::new()
74                .with_position(x, y, z)
75                .with_scale(s, s, s),
76        );
77        let r = universe
78            .world
79            .add_component(engine::ecs::component::RenderableComponent::cube());
80        let c = universe
81            .world
82            .add_component(engine::ecs::component::ColorComponent::rgba(
83                1.0, 0.0, 0.0, 1.0,
84            ));
85        let e = universe
86            .world
87            .add_component(engine::ecs::component::EmissiveComponent::on());
88
89        let _ = universe.attach(t, r);
90        let _ = universe.attach(r, c);
91        let _ = universe.attach(r, e);
92
93        universe.add(t);
94    }
95
96    let p = 1.5;
97    let s = 0.25;
98    spawn_red_cube(&mut universe, -p, -p, 0.0, s);
99    spawn_red_cube(&mut universe, p, -p, 0.0, s);
100    spawn_red_cube(&mut universe, -p, p, 0.0, s);
101    spawn_red_cube(&mut universe, p, p, 0.0, s);
102
103    use engine::ecs::component::{
104        ColorComponent, TextComponent, TextShadowComponent, TextureComponent,
105        TextureFilteringComponent, TransformComponent, TransparentCutoutComponent,
106    };
107
108    fn spawn_text_style(
109        universe: &mut engine::Universe,
110        pos: [f32; 3],
111        scale: f32,
112        text: &str,
113        color: [f32; 4],
114        shadow: TextShadowComponent,
115        filtering: TextureFilteringComponent,
116    ) {
117        let root = universe.world.add_component(
118            TransformComponent::new()
119                .with_position(pos[0], pos[1], pos[2])
120                .with_scale(scale, scale, 1.0),
121        );
122
123        // Color must be an ancestor of the glyph renderables.
124        let color_id = universe
125            .world
126            .add_component(ColorComponent::rgba(color[0], color[1], color[2], color[3]));
127        let _ = universe.attach(root, color_id);
128
129        let text_id = universe.world.add_component(TextComponent::new(text));
130        let _ = universe.attach(color_id, text_id);
131
132        // Route into cutout pass for cleaner edges.
133        let cutout = universe
134            .world
135            .add_component(TransparentCutoutComponent::new());
136        let _ = universe.attach(text_id, cutout);
137
138        // Use the same atlas as the debug quad.
139        let tex = universe
140            .world
141            .add_component(TextureComponent::with_uri("assets/textures/font.dds"));
142        let _ = universe.attach(text_id, tex);
143
144        let shadow_id = universe.world.add_component(shadow);
145        let _ = universe.attach(text_id, shadow_id);
146
147        let filtering_id = universe.world.add_component(filtering);
148        let _ = universe.attach(text_id, filtering_id);
149
150        universe.add(root);
151    }
152
153    // Multiple text samples to show:
154    // - different inherited colors
155    // - different shadow settings
156    // - different texture filtering
157    spawn_text_style(
158        &mut universe,
159        [-0.95, 0.45, 0.0],
160        0.12,
161        "NEAREST_MAG\n(crisp)\nAaBbCc 123",
162        [1.0, 1.0, 1.0, 1.0],
163        TextShadowComponent::new()
164            .with_scale(1.35)
165            .with_offset([0.06, -0.06, 0.0015]),
166        TextureFilteringComponent::nearest_magnification(),
167    );
168
169    spawn_text_style(
170        &mut universe,
171        [-0.95, 0.05, 0.0],
172        0.12,
173        "LINEAR\n(softer)\nAaBbCc 123",
174        [0.55, 0.90, 1.0, 1.0],
175        TextShadowComponent::new()
176            .with_rgba([0.0, 0.0, 0.15, 1.0])
177            .with_scale(1.20)
178            .with_offset([0.05, -0.04, 0.0015]),
179        TextureFilteringComponent::linear(),
180    );
181
182    spawn_text_style(
183        &mut universe,
184        [-0.95, -0.35, 0.0],
185        0.12,
186        "NEAREST\n(pixelly)\nAaBbCc 123",
187        [1.0, 0.85, 0.35, 1.0],
188        TextShadowComponent::new()
189            .with_rgba([0.15, 0.0, 0.0, 1.0])
190            .with_scale(1.55)
191            .with_offset([0.08, -0.08, 0.0015]),
192        TextureFilteringComponent::nearest(),
193    );
194
195    // Process init-time registrations (Text expands into glyph subtrees here).
196    universe.systems.process_commands(
197        &mut universe.world,
198        &mut universe.visuals,
199        &mut universe.render_assets,
200        &mut universe.command_queue,
201    );
202
203    engine::Windowing::run_app(universe).expect("Windowing failed");
204}
examples/folder-text.rs (line 240)
60fn main() {
61    mittens_engine::example_support::ensure_model_assets();
62    utils::logger::init();
63
64    // Usage:
65    //   cargo run --example folder-text -- [folder] [spacing]
66    // Defaults:
67    //   folder=src  spacing=0.3
68    let mut args = std::env::args().skip(1);
69    let folder = args.next().unwrap_or_else(|| "src".to_string());
70    let spacing: f32 = args
71        .next()
72        .and_then(|s| s.parse::<f32>().ok())
73        .unwrap_or(1.0);
74
75    // Safety caps: this demo can explode the ECS if we load huge projects.
76    const MAX_FILES: usize = 42;
77    const MAX_CHARS_PER_FILE: usize = 10_000;
78    const WRAP_AT: usize = 90;
79    const TEXT_SCALE: f32 = 0.01;
80
81    let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
82    let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
83    let scan_root = {
84        let p = PathBuf::from(&folder);
85        if p.is_absolute() {
86            p
87        } else {
88            // Resolve relative paths from the crate root, not the process CWD.
89            manifest_dir.join(p)
90        }
91    };
92    eprintln!("[folder-text] cwd={:?}", cwd);
93    eprintln!("[folder-text] manifest_dir={:?}", manifest_dir);
94    eprintln!("[folder-text] scan_root={:?}", scan_root);
95
96    let mut files = Vec::new();
97    collect_rs_files(&scan_root, &mut files);
98    files.sort();
99
100    if files.is_empty() {
101        eprintln!(
102            "[folder-text] No .rs files found under folder={:?} (resolved={:?})",
103            folder, scan_root
104        );
105    }
106
107    let files: Vec<PathBuf> = files.into_iter().take(MAX_FILES).collect();
108    eprintln!(
109        "[folder-text] Loaded {} file(s) from {:?} (spacing={})",
110        files.len(),
111        folder,
112        spacing
113    );
114
115    #[derive(Debug, Clone)]
116    struct FileEntry {
117        path: PathBuf,
118        display_text: String,
119        max_cols: usize,
120        rows: usize,
121    }
122
123    // Group files by folder.
124    // Layout:
125    // - each folder becomes a column along +X
126    // - within a folder, files stack along +Y (8 high)
127    // - after 8, additional files start a new stack further along +Z
128    let mut files_by_folder: BTreeMap<PathBuf, Vec<FileEntry>> = BTreeMap::new();
129    for path in files {
130        let Ok(content) = std::fs::read_to_string(&path) else {
131            eprintln!("[folder-text] Failed to read {:?}", path);
132            continue;
133        };
134
135        let mut display_text = format!(
136            "// {}\n\n{}",
137            path.strip_prefix(&manifest_dir).unwrap_or(&path).display(),
138            content
139        );
140
141        if display_text.chars().count() > MAX_CHARS_PER_FILE {
142            display_text = display_text
143                .chars()
144                .take(MAX_CHARS_PER_FILE)
145                .collect::<String>();
146            display_text.push_str("\n\n// ... truncated ...\n");
147        }
148
149        let (max_cols, rows) = measure_text_bounds(&display_text, WRAP_AT);
150
151        let folder_key = path.parent().unwrap_or(&scan_root).to_path_buf();
152        files_by_folder
153            .entry(folder_key)
154            .or_default()
155            .push(FileEntry {
156                path,
157                display_text,
158                max_cols,
159                rows,
160            });
161    }
162
163    let column_count = files_by_folder.len().max(1);
164
165    let world = engine::ecs::World::default();
166    let mut universe = engine::Universe::new(world);
167
168    let bg_r = 0.25;
169    let bg_g = 0.25;
170    let bg_b = 0.25;
171    let background = universe
172        .world
173        .add_component(engine::ecs::component::BackgroundColorComponent::new());
174    let background_c = universe
175        .world
176        .add_component(engine::ecs::component::ColorComponent::rgba(
177            bg_r, bg_g, bg_b, 1.00,
178        ));
179    let _ = universe.world.add_child(background, background_c);
180    universe.add(background);
181
182    let ambient = universe
183        .world
184        .add_component(engine::ecs::component::AmbientLightComponent::rgb(
185            bg_r, bg_g, bg_b,
186        ));
187    universe.add(ambient);
188
189    // Input-driven camera rig.
190    // Topology: I { T { C3D } }
191    let input = universe
192        .world
193        .add_component(engine::ecs::component::InputComponent::new().with_speed(1.5));
194
195    // Center the camera horizontally over the spawned columns.
196    let center_x = if column_count <= 1 {
197        0.0
198    } else {
199        ((column_count - 1) as f32) * spacing * 0.5
200    };
201
202    // Bring camera closer: these text blocks are tiny.
203    let rig_transform = universe.world.add_component(
204        engine::ecs::component::TransformComponent::new().with_position(center_x, 0.0, 1.2),
205    );
206    let camera3d = universe
207        .world
208        .add_component(engine::ecs::component::Camera3DComponent::new());
209    let input_mode = universe.world.add_component(
210        engine::ecs::component::InputTransformModeComponent::forward_z().with_roll_axis_y(),
211    );
212    let _ = universe.attach(input, input_mode);
213    let _ = universe.attach(input, rig_transform);
214    let _ = universe.attach(rig_transform, camera3d);
215
216    // Topology: I { T { C3D } } — add a small camera-attached controls hint.
217    example_util::spawn_desktop_camera_controls_hint(&mut universe, rig_transform);
218    universe.add(input);
219
220    // Big floor plane under everything.
221    // RenderableComponent::square() is an XY quad facing +Z; rotate it to XZ facing +Y.
222    let max_stacks = files_by_folder
223        .values()
224        .map(|v| (v.len() + 7) / 8)
225        .max()
226        .unwrap_or(1)
227        .max(1);
228    let total_width = (column_count as f32) * spacing;
229    let total_depth = (max_stacks as f32) * spacing;
230    let floor_w = total_width.max(10.0);
231    let floor_h = total_depth.max(10.0);
232    let floor_transform = universe.world.add_component(
233        engine::ecs::component::TransformComponent::new()
234            .with_position(0.0, -2.0, 0.0)
235            .with_rotation_euler(-std::f32::consts::FRAC_PI_2, 0.0, 0.0)
236            .with_scale(floor_w, floor_h, 1.0),
237    );
238    let floor_renderable = universe
239        .world
240        .add_component(engine::ecs::component::RenderableComponent::square());
241    let floor_color = universe
242        .world
243        .add_component(engine::ecs::component::ColorComponent::rgba(
244            0.88, 0.88, 0.88, 1.0,
245        ));
246    let _ = universe.attach(floor_transform, floor_renderable);
247    let _ = universe.attach(floor_renderable, floor_color);
248    universe.add(floor_transform);
249
250    // 4 red cubes around the perimeter of the world (easy visual anchors).
251    fn spawn_red_cube(universe: &mut engine::Universe, x: f32, y: f32, z: f32, s: f32) {
252        let t = universe.world.add_component(
253            engine::ecs::component::TransformComponent::new()
254                .with_position(x, y, z)
255                .with_scale(s, s, s),
256        );
257        let r = universe
258            .world
259            .add_component(engine::ecs::component::RenderableComponent::cube());
260        let c = universe
261            .world
262            .add_component(engine::ecs::component::ColorComponent::rgba(
263                1.0, 0.0, 0.0, 1.0,
264            ));
265
266        let light_transform = universe.world.add_component(
267            engine::ecs::component::TransformComponent::new().with_position(0.0, s * 0.75, 0.0),
268        );
269        let light = universe.world.add_component(
270            engine::ecs::component::PointLightComponent::new()
271                .with_intensity(1.5)
272                .with_distance(20.0)
273                .with_color(1.0, 0.0, 0.0),
274        );
275
276        let _ = universe.attach(t, r);
277        let _ = universe.attach(r, c);
278        let _ = universe.attach(t, light_transform);
279        let _ = universe.attach(light_transform, light);
280
281        universe.add(t);
282    }
283
284    let p = 1.5;
285    let s = 0.25;
286    spawn_red_cube(&mut universe, -p, -p, 0.0, s);
287    spawn_red_cube(&mut universe, p, -p, 0.0, s);
288    spawn_red_cube(&mut universe, -p, p, 0.0, s);
289    spawn_red_cube(&mut universe, p, p, 0.0, s);
290
291    let start_x = -center_x;
292    let stack_depth = spacing;
293    let row_gap_world = 0.35;
294
295    // One global point light at the top of the overall text "tower".
296    let pad_y = 4.0;
297    let global_max_panel_h_world = files_by_folder
298        .values()
299        .flat_map(|v| v.iter())
300        .map(|e| ((e.rows as f32) + pad_y) * TEXT_SCALE)
301        .fold(0.0_f32, f32::max)
302        .max(0.6);
303    let global_slot_h_world = global_max_panel_h_world + row_gap_world;
304    let tower_top_y = (7.0 * global_slot_h_world) + 4.0;
305    let tower_center_z = total_depth * 0.5;
306
307    let tower_light_transform = universe.world.add_component(
308        engine::ecs::component::TransformComponent::new().with_position(
309            0.0,
310            tower_top_y,
311            tower_center_z,
312        ),
313    );
314    let tower_light = universe.world.add_component(
315        engine::ecs::component::PointLightComponent::new()
316            .with_intensity(2.0)
317            .with_distance(120.0)
318            .with_color(1.0, 1.0, 1.0),
319    );
320    let _ = universe.attach(tower_light_transform, tower_light);
321    universe.add(tower_light_transform);
322
323    for (col_idx, (_folder, mut entries)) in files_by_folder.into_iter().enumerate() {
324        entries.sort_by(|a, b| a.path.cmp(&b.path));
325
326        // Slot height (world units) based on the tallest panel in this folder.
327        let pad_y = 4.0;
328        let max_panel_h_world = entries
329            .iter()
330            .map(|e| ((e.rows as f32) + pad_y) * TEXT_SCALE)
331            .fold(0.0_f32, f32::max)
332            .max(0.6);
333        let slot_h_world = max_panel_h_world + row_gap_world;
334
335        let col_x = start_x + (col_idx as f32) * spacing;
336
337        for (i, entry) in entries.into_iter().enumerate() {
338            let row = (i % 8) as f32;
339            let stack = (i / 8) as f32;
340            let file_y = row * slot_h_world;
341            let file_z = stack * stack_depth;
342
343            let file_group = universe.world.add_component(
344                engine::ecs::component::TransformComponent::new()
345                    .with_position(col_x, file_y, file_z),
346            );
347
348            // Text subtree (tiny scale).
349            let file_root = universe.world.add_component(
350                engine::ecs::component::TransformComponent::new()
351                    .with_position(0.0, 1.0, 0.0)
352                    .with_scale(TEXT_SCALE, TEXT_SCALE, 1.0)
353                    .with_rotation_euler(0.0, std::f32::consts::PI / 6.0, 0.0),
354            );
355            let _ = universe.attach(file_group, file_root);
356
357            // Background panel behind the text.
358            // Size is based on wrapped line count (matches TextSystem's strict wrapping behavior).
359            let (max_cols, rows) = (entry.max_cols, entry.rows);
360            let pad_x = 4.0;
361            let pad_y = 4.0;
362            let w = (max_cols as f32) + pad_x;
363            let h = (rows as f32) + pad_y;
364
365            // Text glyph quads are centered at integer (col,row) positions and are 1x1, so the
366            // text's AABB (in text-space) is roughly:
367            //   x: [-0.5, max_cols-0.5]
368            //   y: [-(rows-1)-0.5, 0.5]
369            // Centering the background quad at those midpoints keeps it aligned as text grows.
370            let bg_x = (max_cols as f32 - 1.0) * 0.5;
371            let bg_y = -((rows as f32 - 1.0) * 0.5);
372
373            let bg_transform = universe.world.add_component(
374                engine::ecs::component::TransformComponent::new()
375                    .with_position(bg_x, bg_y, -0.05)
376                    .with_scale(w, h, 1.0),
377            );
378            let bg_renderable = universe
379                .world
380                .add_component(engine::ecs::component::RenderableComponent::square());
381            let bg_quant = universe.world.add_component(
382                engine::ecs::component::LightQuantizationComponent::steps(5.0),
383            );
384            let bg_color =
385                universe
386                    .world
387                    .add_component(engine::ecs::component::ColorComponent::rgba(
388                        0.2, 0.2, 0.2, 1.0,
389                    ));
390            let _ = universe.attach(file_root, bg_transform);
391            let _ = universe.attach(bg_transform, bg_renderable);
392            let _ = universe.attach(bg_renderable, bg_quant);
393            let _ = universe.attach(bg_renderable, bg_color);
394
395            let text =
396                universe
397                    .world
398                    .add_component(engine::ecs::component::TextComponent::with_wrap(
399                        entry.display_text,
400                        WRAP_AT,
401                    ));
402            let cutout = universe
403                .world
404                .add_component(engine::ecs::component::TransparentCutoutComponent::new());
405            let filtering = universe.world.add_component(
406                engine::ecs::component::TextureFilteringComponent::nearest_magnification(),
407            );
408            // let color = universe
409            //     .world
410            //     .add_component(engine::ecs::component::ColorComponent::rgba(0.7, 0.7, 1.0, 1.0));
411            let emissive = universe
412                .world
413                .add_component(engine::ecs::component::EmissiveComponent::on());
414            let _ = universe.attach(file_root, text);
415            let _ = universe.attach(text, cutout);
416            let _ = universe.attach(text, filtering);
417            //let _ = universe.world.add_child(text, color);
418            let _ = universe.attach(text, emissive);
419
420            universe.add(file_group);
421        }
422    }
423
424    // Process init-time registrations (Text expands into glyph subtrees here).
425    universe.systems.process_commands(
426        &mut universe.world,
427        &mut universe.visuals,
428        &mut universe.render_assets,
429        &mut universe.command_queue,
430    );
431
432    engine::Windowing::run_app(universe).expect("Windowing failed");
433}
Source

pub fn plane() -> Self

Predefined renderable: 2D plane/quad (alias of square).

Source

pub fn square_dynamic(render_assets: &mut RenderAssets) -> Self

Predefined renderable: 2D square/quad (unique CPU mesh registered into render_assets).

Source

pub fn cube() -> Self

Predefined renderable: cube primitive (shared built-in mesh handle).

Examples found in repository?
examples/transparent-cutout-example.rs (line 24)
12fn spawn_gold_cube(
13    universe: &mut engine::Universe,
14    parent: engine::ecs::ComponentId,
15    position: (f32, f32, f32),
16    scale: f32,
17    color: (f32, f32, f32),
18) {
19    let t = universe.world.add_component(
20        TransformComponent::new()
21            .with_position(position.0, position.1, position.2)
22            .with_scale(scale, scale, scale),
23    );
24    let r = universe.world.add_component(RenderableComponent::cube());
25    let c = universe
26        .world
27        .add_component(ColorComponent::rgba(color.0, color.1, color.2, 1.0));
28
29    let _ = universe.attach(parent, t);
30    let _ = universe.attach(t, r);
31    let _ = universe.attach(r, c);
32}
More examples
Hide additional examples
examples/button-press.rs (line 189)
176fn spawn_raycastable_cube(
177    universe: &mut engine::Universe,
178    parent: engine::ecs::ComponentId,
179    pos: [f32; 3],
180    scale: [f32; 3],
181) -> engine::ecs::ComponentId {
182    use engine::ecs::component::{RaycastableComponent, RenderableComponent, TransformComponent};
183
184    let t = universe.world.add_component(
185        TransformComponent::new()
186            .with_position(pos[0], pos[1], pos[2])
187            .with_scale(scale[0], scale[1], scale[2]),
188    );
189    let r = universe.world.add_component(RenderableComponent::cube());
190    let rc = universe
191        .world
192        .add_component(RaycastableComponent::enabled());
193
194    let _ = universe.attach(parent, t);
195    let _ = universe.attach(t, r);
196    let _ = universe.attach(r, rc);
197
198    r
199}
examples/text-example.rs (line 79)
71    fn spawn_red_cube(universe: &mut engine::Universe, x: f32, y: f32, z: f32, s: f32) {
72        let t = universe.world.add_component(
73            engine::ecs::component::TransformComponent::new()
74                .with_position(x, y, z)
75                .with_scale(s, s, s),
76        );
77        let r = universe
78            .world
79            .add_component(engine::ecs::component::RenderableComponent::cube());
80        let c = universe
81            .world
82            .add_component(engine::ecs::component::ColorComponent::rgba(
83                1.0, 0.0, 0.0, 1.0,
84            ));
85        let e = universe
86            .world
87            .add_component(engine::ecs::component::EmissiveComponent::on());
88
89        let _ = universe.attach(t, r);
90        let _ = universe.attach(r, c);
91        let _ = universe.attach(r, e);
92
93        universe.add(t);
94    }
examples/opacity-example.rs (line 25)
12fn spawn_cube(
13    universe: &mut engine::Universe,
14    parent: engine::ecs::ComponentId,
15    position: (f32, f32, f32),
16    scale: (f32, f32, f32),
17    color: Option<(f32, f32, f32, f32)>,
18    opacity: Option<OpacityComponent>,
19) {
20    let t = universe.world.add_component(
21        TransformComponent::new()
22            .with_position(position.0, position.1, position.2)
23            .with_scale(scale.0, scale.1, scale.2),
24    );
25    let r = universe.world.add_component(RenderableComponent::cube());
26
27    let _ = universe.attach(parent, t);
28    let _ = universe.attach(t, r);
29
30    if let Some((cr, cg, cb, ca)) = color {
31        let c = universe
32            .world
33            .add_component(ColorComponent::rgba(cr, cg, cb, ca));
34        let _ = universe.attach(r, c);
35    }
36
37    if let Some(o) = opacity {
38        let o = universe.world.add_component(o);
39        let _ = universe.attach(r, o);
40    }
41}
42
43fn spawn_text_label(universe: &mut engine::Universe, position: (f32, f32, f32), text: &str) {
44    // T_root { T_scale { TXT { filtering } } }
45    let text_root = universe
46        .world
47        .add_component(TransformComponent::new().with_position(position.0, position.1, position.2));
48
49    let text_scale = universe
50        .world
51        .add_component(TransformComponent::new().with_scale(0.18, 0.18, 1.0));
52    let _ = universe.attach(text_root, text_scale);
53
54    let text_c = universe.world.add_component(TextComponent::new(text));
55    let _ = universe.attach(text_scale, text_c);
56
57    // Keep it crisp.
58    let filtering = universe
59        .world
60        .add_component(TextureFilteringComponent::nearest());
61    let _ = universe.attach(text_c, filtering);
62
63    // White label.
64    let color = universe
65        .world
66        .add_component(ColorComponent::rgba(1.0, 1.0, 1.0, 1.0));
67    let _ = universe.attach(text_c, color);
68
69    universe.add(text_root);
70}
71
72fn text_block_dimensions(text: &str) -> (usize, usize) {
73    let mut max_cols = 0usize;
74    let mut rows = 1usize;
75    let mut cur = 0usize;
76
77    for ch in text.chars() {
78        if ch == '\n' {
79            max_cols = max_cols.max(cur);
80            cur = 0;
81            rows += 1;
82        } else {
83            cur += 1;
84        }
85    }
86    max_cols = max_cols.max(cur);
87
88    (max_cols.max(1), rows.max(1))
89}
90
91fn spawn_text_label_with_bg(
92    universe: &mut engine::Universe,
93    position: (f32, f32, f32),
94    text: &str,
95    bg_opacity: f32,
96) {
97    // T_root {
98    //   T_bg { R_bg { Color black, Opacity } }
99    //   T_scale { TXT { filtering } }
100    // }
101
102    let text_root = universe
103        .world
104        .add_component(TransformComponent::new().with_position(position.0, position.1, position.2));
105
106    // Background quad (slightly behind the glyph quads).
107    let (cols, rows) = text_block_dimensions(text);
108    let text_scale = 0.18_f32;
109    let pad_x = 0.55_f32;
110    let pad_y = 0.45_f32;
111    let bg_w = cols as f32 * text_scale + pad_x;
112    let bg_h = rows as f32 * text_scale + pad_y;
113
114    let bg_t = universe.world.add_component(
115        TransformComponent::new()
116            .with_position(1.5, 0.0, -0.02)
117            .with_scale(bg_w, bg_h, 1.0),
118    );
119    let bg_r = universe.world.add_component(RenderableComponent::square());
120    let _ = universe.attach(text_root, bg_t);
121    let _ = universe.attach(bg_t, bg_r);
122
123    let bg_c = universe
124        .world
125        .add_component(ColorComponent::rgba(0.0, 0.0, 0.0, 1.0));
126    let _ = universe.attach(bg_r, bg_c);
127
128    let bg_o = universe
129        .world
130        .add_component(OpacityComponent::new().with_opacity(bg_opacity));
131    let _ = universe.attach(bg_r, bg_o);
132
133    let text_scale_t = universe
134        .world
135        .add_component(TransformComponent::new().with_scale(text_scale, text_scale, 1.0));
136    let _ = universe.attach(text_root, text_scale_t);
137
138    let text_c = universe.world.add_component(TextComponent::new(text));
139    let _ = universe.attach(text_scale_t, text_c);
140
141    // Keep it crisp.
142    let filtering = universe
143        .world
144        .add_component(TextureFilteringComponent::nearest());
145    let _ = universe.attach(text_c, filtering);
146
147    // Force the label into the transparent pass so it layers correctly with the background.
148    // (Pass selection currently does not consider texture alpha.)
149    let color = universe
150        .world
151        .add_component(ColorComponent::rgba(1.0, 1.0, 1.0, 0.998));
152    let _ = universe.attach(text_c, color);
153
154    universe.add(text_root);
155}
156
157fn spawn_demo_spot(
158    universe: &mut engine::Universe,
159    spot_pos: (f32, f32, f32),
160    opacity: f32,
161    multiple_layers: bool,
162    grid_n: i32,
163) {
164    let spot = universe
165        .world
166        .add_component(TransformComponent::new().with_position(spot_pos.0, spot_pos.1, spot_pos.2));
167
168    // All cubes inherit this color.
169    let white = universe
170        .world
171        .add_component(ColorComponent::rgba(1.0, 1.0, 1.0, 1.0));
172    let _ = universe.attach(spot, white);
173
174    // All cubes inherit this opacity (no per-cube OpacityComponent needed).
175    let mut oc = OpacityComponent::new().with_opacity(opacity);
176    if multiple_layers {
177        oc = oc.with_multiple_layers();
178    }
179    let oc = universe.world.add_component(oc);
180    let _ = universe.attach(spot, oc);
181
182    universe.add(spot);
183
184    // Cube grid.
185    let n = grid_n.max(1);
186    let spacing = if n <= 2 { 1.0 } else { 0.6 };
187    let cube_scale = if n <= 2 { 0.8 } else { 0.45 };
188    let half = (n as f32 - 1.0) * spacing * 0.5;
189
190    for z in 0..n {
191        for y in 0..n {
192            for x in 0..n {
193                let px = x as f32 * spacing - half;
194                let py = y as f32 * spacing;
195                let pz = z as f32 * spacing - half;
196
197                spawn_cube(
198                    universe,
199                    spot,
200                    (px, py, pz),
201                    (cube_scale, cube_scale, cube_scale),
202                    None,
203                    None,
204                );
205            }
206        }
207    }
208
209    // Label above.
210    let label = format!(
211        "opacity: {:.2}\nmulti-layer: {}",
212        opacity,
213        if multiple_layers { "true" } else { "false" }
214    );
215    // Keep labels away from the cube volume so they don't intersect.
216    let label_y = spot_pos.1 + (n as f32 * spacing) + 1.8;
217    let label_x = spot_pos.0 - (half + 0.6);
218    let label_z = spot_pos.2 - (half + 1.0);
219    spawn_text_label(universe, (label_x, label_y, label_z), &label);
220}
221
222fn spawn_demo_strip_pair(
223    universe: &mut engine::Universe,
224    spot_pos: (f32, f32, f32),
225    transparent_multiple_layers: bool,
226) {
227    let n_z: i32 = 4;
228    let spacing = 1.0;
229    let cube_scale = 0.8;
230    let half_z = (n_z as f32 - 1.0) * spacing * 0.5;
231
232    // Transparent strip (1x4 along Z).
233    let transparent_root = universe
234        .world
235        .add_component(TransformComponent::new().with_position(spot_pos.0, spot_pos.1, spot_pos.2));
236
237    let white = universe
238        .world
239        .add_component(ColorComponent::rgba(1.0, 1.0, 1.0, 1.0));
240    let _ = universe.attach(transparent_root, white);
241
242    let mut oc = OpacityComponent::new().with_opacity(0.50);
243    if transparent_multiple_layers {
244        oc = oc.with_multiple_layers();
245    }
246    let oc = universe.world.add_component(oc);
247    let _ = universe.attach(transparent_root, oc);
248
249    universe.add(transparent_root);
250
251    for z in 0..n_z {
252        let pz = z as f32 * spacing - half_z;
253        spawn_cube(
254            universe,
255            transparent_root,
256            (0.0, 0.0, pz),
257            (cube_scale, cube_scale, cube_scale),
258            None,
259            None,
260        );
261    }
262
263    // Opaque strip to the left, same spacing/scale.
264    let opaque_root = universe
265        .world
266        .add_component(TransformComponent::new().with_position(
267            spot_pos.0 - spacing,
268            spot_pos.1,
269            spot_pos.2,
270        ));
271    let white = universe
272        .world
273        .add_component(ColorComponent::rgba(1.0, 1.0, 1.0, 1.0));
274    let _ = universe.attach(opaque_root, white);
275    universe.add(opaque_root);
276
277    for z in 0..n_z {
278        let pz = z as f32 * spacing - half_z;
279        spawn_cube(
280            universe,
281            opaque_root,
282            (0.0, 0.0, pz),
283            (cube_scale, cube_scale, cube_scale),
284            None,
285            None,
286        );
287    }
288
289    let label = format!(
290        "mini: opaque + transparent strip\ntransparent opacity: 0.50\nmulti-layer: {}",
291        if transparent_multiple_layers {
292            "true"
293        } else {
294            "false"
295        }
296    );
297    let label_y = spot_pos.1 + spacing + 1.8;
298    let label_x = spot_pos.0 - (spacing * 2.6);
299    let label_z = spot_pos.2 - (half_z + 1.0);
300    spawn_text_label(universe, (label_x, label_y, label_z), &label);
301}
302
303fn spawn_demo_xy_plane(
304    universe: &mut engine::Universe,
305    spot_pos: (f32, f32, f32),
306    opacity: f32,
307    n_x: i32,
308    n_y: i32,
309    z: f32,
310) {
311    let spot = universe
312        .world
313        .add_component(TransformComponent::new().with_position(spot_pos.0, spot_pos.1, spot_pos.2));
314
315    let white = universe
316        .world
317        .add_component(ColorComponent::rgba(1.0, 1.0, 1.0, 1.0));
318    let _ = universe.attach(spot, white);
319
320    let oc = universe
321        .world
322        .add_component(OpacityComponent::new().with_opacity(opacity));
323    let _ = universe.attach(spot, oc);
324
325    universe.add(spot);
326
327    let nx = n_x.max(1);
328    let ny = n_y.max(1);
329    let spacing = 0.45;
330    let cube_scale = 0.35;
331    let half_x = (nx as f32 - 1.0) * spacing * 0.5;
332
333    for y in 0..ny {
334        for x in 0..nx {
335            let px = x as f32 * spacing - half_x;
336            let py = y as f32 * spacing;
337            spawn_cube(
338                universe,
339                spot,
340                (px, py, z),
341                (cube_scale, cube_scale, cube_scale),
342                None,
343                None,
344            );
345        }
346    }
347
348    // Label in front of the plane.
349    let label = format!(
350        "XY plane: {}x{}\nopacity: {:.2}\nmulti-layer: false",
351        nx, ny, opacity
352    );
353    let label_x = spot_pos.0 - (half_x + 0.6);
354    let label_y = spot_pos.1 + (ny as f32 * spacing) + 1.2;
355    let label_z = spot_pos.2 - 2.5;
356    spawn_text_label_with_bg(universe, (label_x, label_y, label_z), &label, 0.50);
357}
358
359fn main() {
360    mittens_engine::example_support::ensure_model_assets();
361    utils::logger::init();
362
363    let world = engine::ecs::World::default();
364    let mut universe = engine::Universe::new(world);
365
366    // Dark brown / pink background.
367    let bg = universe
368        .world
369        .add_component(BackgroundColorComponent::new());
370    let bg_c = universe
371        .world
372        .add_component(ColorComponent::rgba(0.22, 0.08, 0.10, 1.0));
373    let _ = universe.world.add_child(bg, bg_c);
374    universe.add(bg);
375
376    // Ambient so unlit areas aren't black.
377    let ambient = universe
378        .world
379        .add_component(AmbientLightComponent::rgb(0.35, 0.35, 0.40));
380    universe.add(ambient);
381
382    // A bright overhead light.
383    let light_t = universe.world.add_component(
384        TransformComponent::new()
385            .with_position(0.0, 18.0, 10.0)
386            .with_scale(0.2, 0.2, 0.2),
387    );
388    let light = universe.world.add_component(
389        PointLightComponent::new()
390            .with_color(1.0, 1.0, 1.0)
391            .with_intensity(1.6)
392            .with_distance(80.0),
393    );
394    let _ = universe.attach(light_t, light);
395    universe.add(light_t);
396
397    // --- Camera rig ---
398    // I { T { C3D { with_fps_rotation with_roll_axis_y } } }
399    let input = universe
400        .world
401        .add_component(InputComponent::new().with_speed(3.0));
402    let input_mode = universe.world.add_component(
403        InputTransformModeComponent::forward_z()
404            .with_roll_axis_y()
405            .with_fps_rotation(),
406    );
407    let _ = universe.attach(input, input_mode);
408
409    let rig_transform = universe
410        .world
411        .add_component(TransformComponent::new().with_position(0.0, 6.0, 20.0));
412    let _ = universe.attach(input, rig_transform);
413
414    let camera = universe.world.add_component(Camera3DComponent::new());
415    let _ = universe.attach(rig_transform, camera);
416
417    // Topology: I { T { C3D } } — add a small camera-attached controls hint.
418    example_util::spawn_desktop_camera_controls_hint(&mut universe, rig_transform);
419
420    universe.add(input);
421
422    // --- Ground ---
423    let ground = universe.world.add_component(
424        TransformComponent::new()
425            .with_position(0.0, -0.6, 0.0)
426            .with_scale(60.0, 1.0, 60.0),
427    );
428    let ground_r = universe.world.add_component(RenderableComponent::cube());
429    let ground_c = universe
430        .world
431        .add_component(ColorComponent::rgba(0.95, 0.95, 0.95, 1.0));
432    let _ = universe.attach(ground, ground_r);
433    let _ = universe.attach(ground_r, ground_c);
434    universe.add(ground);
435
436    // --- Opaque yellow cubes behind (contrast reference) ---
437    for i in 0..6 {
438        let x = -10.0 + i as f32 * 4.0;
439        spawn_cube(
440            &mut universe,
441            ground,
442            (x, 1.2, -18.0),
443            (2.0, 2.0, 2.0),
444            Some((1.0, 0.92, 0.15, 1.0)),
445            None,
446        );
447    }
448
449    // --- Demo spots ---
450    // Left of the left big spot: a single-layer transparent XY plane (16x16).
451    spawn_demo_xy_plane(&mut universe, (-14.0, 0.0, 0.0), 0.50, 16, 16, 0.0);
452
453    // Big spots: 8x8x8
454    // Left: single-layer transparent (instanced)
455    spawn_demo_spot(&mut universe, (-4.0, 0.0, 0.0), 0.50, false, 8);
456
457    // Right: multi-layer transparent (sorted)
458    spawn_demo_spot(&mut universe, (4.0, 0.0, 0.0), 0.50, true, 8);
459
460    // Small spots: opaque 1x4 strip + transparent 1x4 strip (along Z).
461    spawn_demo_strip_pair(&mut universe, (-4.0, 0.0, 10.0), false);
462    spawn_demo_strip_pair(&mut universe, (4.0, 0.0, 10.0), true);
463
464    // Process init-time registrations.
465    universe.systems.process_commands(
466        &mut universe.world,
467        &mut universe.visuals,
468        &mut universe.render_assets,
469        &mut universe.command_queue,
470    );
471
472    universe.enable_repl();
473
474    engine::Windowing::run_app(universe).expect("Windowing failed");
475}
examples/animation-for-topology.rs (line 34)
20fn spawn_emissive_marker_cube(
21    universe: &mut engine::Universe,
22    parent: engine::ecs::ComponentId,
23    local_pos: (f32, f32, f32),
24    scale: f32,
25    rgba: [f32; 4],
26) {
27    let tx = universe.world.add_component(
28        engine::ecs::component::TransformComponent::new()
29            .with_position(local_pos.0, local_pos.1, local_pos.2)
30            .with_scale(scale, scale, scale),
31    );
32    let r = universe
33        .world
34        .add_component(engine::ecs::component::RenderableComponent::cube());
35    let c = universe
36        .world
37        .add_component(engine::ecs::component::ColorComponent::rgba(
38            rgba[0], rgba[1], rgba[2], rgba[3],
39        ));
40    let e = universe
41        .world
42        .add_component(engine::ecs::component::EmissiveComponent::on());
43
44    let _ = universe.attach(parent, tx);
45    let _ = universe.attach(tx, r);
46    let _ = universe.attach(r, c);
47    let _ = universe.attach(r, e);
48}
49
50/// Create a cube subtree ahead-of-time (not attached to the scene).
51///
52/// Returns the root `TransformComponent` id.
53fn spawn_detached_cube_prefab(
54    universe: &mut engine::Universe,
55    scale: f32,
56    rgba: [f32; 4],
57) -> engine::ecs::ComponentId {
58    let tx = universe.world.add_component(
59        engine::ecs::component::TransformComponent::new().with_scale(scale, scale, scale),
60    );
61    let r = universe
62        .world
63        .add_component(engine::ecs::component::RenderableComponent::cube());
64    let c = universe
65        .world
66        .add_component(engine::ecs::component::ColorComponent::rgba(
67            rgba[0], rgba[1], rgba[2], rgba[3],
68        ));
69    let e = universe
70        .world
71        .add_component(engine::ecs::component::EmissiveComponent::on());
72
73    let _ = universe.attach(tx, r);
74    let _ = universe.attach(r, c);
75    let _ = universe.attach(r, e);
76
77    tx
78}
examples/animation-example.rs (line 131)
117    fn spawn_emissive_cube(
118        universe: &mut engine::Universe,
119        parent: engine::ecs::ComponentId,
120        pos: (f32, f32, f32),
121        scale: f32,
122        rgba: [f32; 4],
123    ) {
124        let tx = universe.world.add_component(
125            engine::ecs::component::TransformComponent::new()
126                .with_position(pos.0, pos.1, pos.2)
127                .with_scale(scale, scale, scale),
128        );
129        let r = universe
130            .world
131            .add_component(engine::ecs::component::RenderableComponent::cube());
132        let c = universe
133            .world
134            .add_component(engine::ecs::component::ColorComponent::rgba(
135                rgba[0], rgba[1], rgba[2], rgba[3],
136            ));
137        let e = universe
138            .world
139            .add_component(engine::ecs::component::EmissiveComponent::on());
140        let _ = universe.attach(parent, tx);
141        let _ = universe.attach(tx, r);
142        let _ = universe.attach(r, c);
143        let _ = universe.attach(r, e);
144    }
145
146    fn spawn_op_cube(
147        universe: &mut engine::Universe,
148        parent: engine::ecs::ComponentId,
149        pos: (f32, f32, f32),
150        scale: f32,
151        base_rgba: [f32; 4],
152    ) -> engine::ecs::ComponentId {
153        let tx = universe.world.add_component(
154            engine::ecs::component::TransformComponent::new()
155                .with_position(pos.0, pos.1, pos.2)
156                .with_scale(scale, scale, scale),
157        );
158        let r = universe
159            .world
160            .add_component(engine::ecs::component::RenderableComponent::cube());
161        let c = universe
162            .world
163            .add_component(engine::ecs::component::ColorComponent::rgba(
164                base_rgba[0],
165                base_rgba[1],
166                base_rgba[2],
167                base_rgba[3],
168            ));
169        let e = universe
170            .world
171            .add_component(engine::ecs::component::EmissiveComponent::on());
172
173        let _ = universe.attach(parent, tx);
174        let _ = universe.attach(tx, r);
175        let _ = universe.attach(r, c);
176        let _ = universe.attach(r, e);
177
178        tx
179    }
Source

pub fn cube_dynamic(render_assets: &mut RenderAssets) -> Self

Predefined renderable: cube primitive (unique CPU mesh registered into render_assets).

Source

pub fn wireframe_box(render_assets: &mut RenderAssets, thickness: f32) -> Self

Unit wireframe box with twelve solid edges of configurable relative thickness.

Source

pub fn sphere() -> Self

Predefined renderable: sphere primitive (shared built-in mesh handle).

Source

pub fn sphere_dynamic(render_assets: &mut RenderAssets) -> Self

Predefined renderable: sphere primitive (unique CPU mesh registered into render_assets).

Source

pub fn cone() -> Self

Predefined renderable: cone primitive (shared built-in mesh handle).

Source

pub fn cone_dynamic(render_assets: &mut RenderAssets, segments: u32) -> Self

Predefined renderable: cone primitive (unique CPU mesh registered into render_assets).

Source

pub fn icosahedron( render_assets: &mut RenderAssets, tessellations: u32, sphericalness: f32, ) -> Self

Source

pub fn tetrahedron() -> Self

Predefined renderable: tetrahedron primitive (shared built-in mesh handle).

Source

pub fn tetrahedron_dynamic(render_assets: &mut RenderAssets) -> Self

Predefined renderable: tetrahedron primitive (unique CPU mesh registered into render_assets).

Source

pub fn color_tetrahedron() -> Self

Predefined renderable: tetrahedron (alias of tetrahedron).

Source

pub fn circle2d() -> Self

Predefined renderable: 2D circle (shared built-in mesh handle).

Source

pub fn partial_annulus_2d( render_assets: &mut RenderAssets, inner_radius: f32, outer_radius: f32, start_angle_radians: f32, sweep_angle_radians: f32, segments: u32, ) -> Self

Source

pub fn star( render_assets: &mut RenderAssets, points: u32, inner_radius_fraction: f32, outer_bevel_segments: u32, inner_bevel_segments: u32, ) -> Self

Source

pub fn heart(render_assets: &mut RenderAssets, segments: u32) -> Self

Trait Implementations§

Source§

impl Clone for RenderableComponent

Source§

fn clone(&self) -> RenderableComponent

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Component for RenderableComponent

Source§

fn name(&self) -> &'static str

Short debug/type name for this component kind (e.g. “transform”, “camera”).
Source§

fn set_id(&mut self, component: ComponentId)

Source§

fn as_any(&self) -> &dyn Any

Source§

fn as_any_mut(&mut self) -> &mut dyn Any

Source§

fn init(&mut self, emit: &mut dyn SignalEmitter, component: ComponentId)

Called when component is added to the World
Source§

fn cleanup(&mut self, emit: &mut dyn SignalEmitter, component: ComponentId)

Called when component is removed from the World.
Source§

fn to_mms_ast(&self, _world: &World) -> ComponentExpression

Encode this component as an MMS Component Expression AST node. Read more
Source§

fn encode(&self) -> HashMap<String, Value>

Encode component data to a HashMap for serialization. Read more
Source§

fn decode(&mut self, _data: &HashMap<String, Value>) -> Result<(), String>

Decode component data from a HashMap after deserialization. Read more
Source§

impl Debug for RenderableComponent

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more