Skip to main content

GLTFSystem

Struct GLTFSystem 

Source
pub struct GLTFSystem { /* private fields */ }

Implementations§

Source§

impl GLTFSystem

Source

pub fn new() -> Self

Source

pub fn register_component(&mut self, component_id: ComponentId)

Source

pub fn tracked_components(&self) -> impl Iterator<Item = ComponentId> + '_

Source

pub fn tracked_component_count(&self) -> usize

Source

pub fn cached_resource_count(&self) -> usize

Source

pub fn cached_mesh_count(&self) -> usize

Source

pub fn cached_texture_count(&self) -> usize

Source

pub fn cached_cpu_bytes(&self) -> usize

Source

pub fn tick_with_queue( &mut self, world: &mut World, visuals: &mut VisualWorld, skinned_mesh: &mut SkinnedMeshSystem, emit: &mut dyn SignalEmitter, _dt_sec: f32, )

Discover GLTFComponents and spawn their node/renderable hierarchy.

This runs during SystemWorld::tick so we have access to a SignalEmitter via world.init_component_tree(..., emit).

Examples found in repository?
examples/bisket-vr-debug.rs (lines 1113-1119)
1111fn tick_gltf(universe: &mut engine::Universe) {
1112    let systems = &mut universe.systems;
1113    systems.gltf.tick_with_queue(
1114        &mut universe.world,
1115        &mut universe.visuals,
1116        &mut systems.skinned_mesh,
1117        &mut universe.command_queue,
1118        0.0,
1119    );
1120}
More examples
Hide additional examples
examples/bisket-vr-demo.rs (lines 318-324)
278fn main() {
279    mittens_engine::example_support::ensure_model_assets();
280    utils::logger::init();
281
282    let world = engine::ecs::World::default();
283    let mut universe = engine::Universe::new(world);
284
285    let output = scripting::MeowMeowRunner::eval_with_world_and_assets_at_path(
286        include_str!("bisket-vr-demo.mms"),
287        Some("examples/bisket-vr-demo.mms"),
288        &mut universe.world,
289        &mut universe.systems.rx,
290        Some(&mut universe.render_assets),
291        &mut universe.command_queue,
292    );
293
294    for error in &output.errors {
295        eprintln!("[mms] {error}");
296    }
297    println!(
298        "[mms] {} intent(s) from bisket-vr-demo.mms",
299        output.intents.len()
300    );
301
302    let scope = engine::ecs::ComponentId::default();
303    for intent in output.intents {
304        universe.command_queue.push_intent_now(scope, intent);
305    }
306
307    universe.systems.process_commands(
308        &mut universe.world,
309        &mut universe.visuals,
310        &mut universe.render_assets,
311        &mut universe.command_queue,
312    );
313
314    // Force the glTF subtree to spawn so the armature exists before we query for
315    // bone markers (otherwise the bone components aren't in the world yet).
316    {
317        let systems = &mut universe.systems;
318        systems.gltf.tick_with_queue(
319            &mut universe.world,
320            &mut universe.visuals,
321            &mut systems.skinned_mesh,
322            &mut universe.command_queue,
323            0.0,
324        );
325    }
326    universe.systems.process_commands(
327        &mut universe.world,
328        &mut universe.visuals,
329        &mut universe.render_assets,
330        &mut universe.command_queue,
331    );
332
333    // Find any global root to start the descendant search from. Scanning all
334    // components is fine here — this only runs once at startup.
335    let roots: Vec<engine::ecs::ComponentId> = universe
336        .world
337        .all_components()
338        .filter(|&id| universe.world.parent_of(id).is_none())
339        .collect();
340
341    // ----------------------------------------------------------------------
342    // Dump button — click to print a bone snapshot for offline analysis.
343    //
344    // Topology: scene_root → OV → button_t → button_r (+ C, EM, Raycastable).
345    // OV phase so the cube is visible through the avatar body in first-person VR.
346    // Click handler walks the cached bone list, prints world pos + segment
347    // lengths to stdout.  Compare with bisket-vr-debug harness output.
348    // ----------------------------------------------------------------------
349    {
350        // Resolve AVC + driven_t for the dump.
351        let avc_id_opt = universe.world.all_components().find(|&id| {
352            universe
353                .world
354                .get_component_by_id_as::<AvatarControlComponent>(id)
355                .is_some()
356        });
357        if let Some(avc_id) = avc_id_opt {
358            let driven_t = universe.world.parent_of(avc_id).unwrap_or(avc_id);
359            let head_ik_offset_yaw = universe
360                .world
361                .get_component_by_id_as::<AvatarControlComponent>(avc_id)
362                .map(|c| {
363                    if c.forward_plus_z {
364                        0.0
365                    } else {
366                        std::f32::consts::PI
367                    }
368                })
369                .unwrap_or(std::f32::consts::PI);
370
371            // Find each bone under any root (model_root is unique per avatar here).
372            let mut bones: Vec<(String, ComponentId)> = Vec::new();
373            for name in DUMP_BONES {
374                let sel = format!("[name='{}']", name);
375                if let Some(bone) = roots.iter().find_map(|&r| universe.find_component(r, &sel)) {
376                    bones.push((name.to_string(), bone));
377                } else {
378                    eprintln!("[dump] bone not found: {}", name);
379                }
380            }
381            // splice_head = parent of head bone (runtime-inserted by AVC).
382            let splice_head = bones
383                .iter()
384                .find(|(n, _)| n == "J_Bip_C_Head")
385                .and_then(|(_, head)| universe.world.parent_of(*head))
386                .unwrap_or(avc_id);
387
388            let head_bone = bones
389                .iter()
390                .find(|(n, _)| n == "J_Bip_C_Head")
391                .map(|(_, id)| *id)
392                .unwrap_or(splice_head);
393
394            let upper_chest = bones
395                .iter()
396                .find(|(n, _)| n == "J_Bip_C_UpperChest")
397                .map(|(_, id)| *id);
398
399            // Find CameraXR + its transform wrapper to recover authored eye offset.
400            let cxr_id = universe.world.all_components().find(|&cid| {
401                universe
402                    .world
403                    .get_component_by_id_as::<mittens_engine::engine::ecs::component::CameraXRComponent>(cid)
404                    .is_some()
405            });
406            let camera_wrapper_t = cxr_id.and_then(|cid| {
407                universe.world.parent_of(cid).filter(|&p| {
408                    universe
409                        .world
410                        .get_component_by_id_as::<TransformComponent>(p)
411                        .is_some()
412                })
413            });
414            let authored_eye_offset_head_local = camera_wrapper_t
415                .and_then(|t| {
416                    universe
417                        .world
418                        .get_component_by_id_as::<TransformComponent>(t)
419                })
420                .map(|t| t.transform.translation)
421                .unwrap_or([0.0, 0.0, 0.0]);
422
423            let _ = DUMP_TARGETS.set(DumpTargets {
424                bones,
425                driven_t,
426                splice_head,
427                head_bone,
428                upper_chest,
429                camera_wrapper_t,
430                authored_eye_offset_head_local,
431                head_ik_offset_yaw,
432            });
433
434            // Spawn the button.  Position chosen so it's reachable in-VR from
435            // a standing pose: 0.35 m to the right, hip-height, slightly out.
436            let btn_t = universe.world.add_component(
437                TransformComponent::new()
438                    .with_position(0.35, 1.05, -0.35)
439                    .with_scale(0.06, 0.06, 0.06),
440            );
441            let btn_r = universe.world.add_component(RenderableComponent::cube());
442            let btn_c = universe
443                .world
444                .add_component(ColorComponent::rgba(0.95, 0.20, 0.40, 1.0));
445            let btn_em = universe.world.add_component(EmissiveComponent::on());
446            let btn_rcast = universe
447                .world
448                .add_component(RaycastableComponent::enabled());
449            let btn_ov = universe.world.add_component(OverlayComponent::new());
450            let _ = universe.world.add_child(btn_r, btn_c);
451            let _ = universe.world.add_child(btn_r, btn_em);
452            let _ = universe.world.add_child(btn_r, btn_rcast);
453            let _ = universe.world.add_child(btn_t, btn_r);
454            let _ = universe.world.add_child(btn_ov, btn_t);
455
456            // Attach to a stable scene root (the first global root we found).
457            let scene_root = roots
458                .iter()
459                .copied()
460                .find(|&r| {
461                    universe
462                        .world
463                        .get_component_by_id_as::<TransformComponent>(r)
464                        .is_some()
465                        || universe.world.children_of(r).len() > 0
466                })
467                .unwrap_or_else(|| roots[0]);
468            let _ = universe.attach(scene_root, btn_ov);
469
470            // Wire Click handler.  Scope = the renderable (where the raycast hits).
471            universe.add_signal_handler(SignalKind::Click, btn_r, on_dump_click);
472
473            println!(
474                "[dump] button spawned at [0.35, 1.05, -0.35] — click in VR or with desktop pointer to dump bones"
475            );
476        } else {
477            eprintln!("[dump] AvatarControlComponent not found — skipping dump button");
478        }
479    }
480
481    for kind in [
482        SignalKind::DragStart,
483        SignalKind::DragMove,
484        SignalKind::DragEnd,
485        SignalKind::Click,
486    ] {
487        universe
488            .systems
489            .rx
490            .add_global_handler(kind, on_xr_pointer_event);
491    }
492
493    universe.enable_meow_meow_repl();
494    engine::Windowing::run_app(universe).expect("Windowing failed");
495}
examples/vr-input.rs (lines 434-440)
186fn main() {
187    mittens_engine::example_support::ensure_model_assets();
188    utils::logger::init();
189
190    let options = match parse_options() {
191        Ok(options) => options,
192        Err(message) => {
193            eprintln!("{message}");
194            std::process::exit(2);
195        }
196    };
197
198    println!(
199        "[vr-input] xr controller rotation filter pipeline: {}",
200        if options.xr_controller_rotation_filter {
201            "enabled"
202        } else {
203            "disabled"
204        }
205    );
206
207    let world = engine::ecs::World::default();
208    let mut universe = engine::Universe::new(world);
209
210    let renderer_settings = universe
211        .world
212        .add_component(RendererSettingsComponent::msaa_off().with_window_size(320, 240));
213    universe.add(renderer_settings);
214
215    let render_graph = universe.world.add_component(RenderGraphComponent::new());
216    let emissive_pass = universe.world.add_component(EmissivePassComponent::new());
217    let blur_pass = universe.world.add_component(
218        BlurPassComponent::new()
219            .with_radius_ndc(0.06)
220            .with_half_res(true),
221    );
222    let bloom = universe.world.add_component(
223        BloomComponent::new()
224            .with_intensity(0.95)
225            .with_emissive_scale(1.2),
226    );
227    let _ = universe.attach(emissive_pass, blur_pass);
228    let _ = universe.attach(render_graph, emissive_pass);
229    let _ = universe.attach(render_graph, bloom);
230    universe.add(render_graph);
231
232    // Sky base.
233    let background = universe
234        .world
235        .add_component(BackgroundColorComponent::new());
236    let background_c = universe
237        .world
238        .add_component(ColorComponent::rgba(0.62, 0.80, 1.00, 1.0));
239    let _ = universe.world.add_child(background, background_c);
240    universe.add(background);
241
242    // Lighting for the model.
243    let ambient = universe
244        .world
245        .add_component(AmbientLightComponent::rgb(0.18, 0.18, 0.22));
246    universe.add(ambient);
247
248    let sun = universe.world.add_component(
249        DirectionalLightComponent::new()
250            .with_intensity(1.1)
251            .with_color(1.0, 0.98, 0.95),
252    );
253    let sun_dir = universe
254        .world
255        .add_component(TransformComponent::new().with_position(0.15, -0.45, 1.0));
256    let _ = universe.attach(sun_dir, sun);
257    universe.add(sun_dir);
258
259    // --- Desktop camera rig (for debugging while in VR) ---
260    let input = universe
261        .world
262        .add_component(InputComponent::new().with_speed(1.5));
263    let input_mode = universe.world.add_component(
264        InputTransformModeComponent::forward_z()
265            .with_fps_rotation()
266            .with_roll_axis_y(),
267    );
268    let _ = universe.attach(input, input_mode);
269
270    let desktop_rig = universe
271        .world
272        .add_component(TransformComponent::new().with_position(0.0, 1.2, 3.5));
273    let _ = universe.attach(input, desktop_rig);
274
275    let camera3d = universe.world.add_component(Camera3DComponent::new());
276    let _ = universe.attach(desktop_rig, camera3d);
277
278    let pointer = universe.world.add_component(PointerComponent::new());
279    let _ = universe.attach(camera3d, pointer);
280
281    example_util::spawn_desktop_camera_controls_hint(&mut universe, desktop_rig);
282    universe.add(input);
283
284    // --- XR rig (Aim controller debug cubes only; camera has moved to AVC) ---
285    let xr_input = universe.world.add_component(InputXRComponent::on());
286    let xr_gamepad = universe.world.add_component(
287        mittens_engine::engine::ecs::component::InputXRGamepadComponent::new().speed(1.5),
288    );
289    let xr_rig = universe.world.add_component(TransformComponent::new());
290    let _ = universe.attach(xr_input, xr_rig);
291    let _ = universe.attach(xr_input, xr_gamepad);
292
293    // renderer stats
294    let renderer_stats = universe
295        .world
296        .add_component(RendererStatsComponent::new().with_camera_target(CameraTarget::Xr));
297    let render_stats_rig = universe
298        .world
299        .add_component(TransformComponent::new().with_position(0.0, 1.85, 0.6));
300    let _ = universe.attach(render_stats_rig, renderer_stats);
301    let _ = universe.attach(xr_rig, render_stats_rig);
302
303    universe.add(xr_input);
304
305    // Background "skybox" content.
306    spawn_sun_background(&mut universe);
307
308    // --- VTuber model — single-input topology ---
309    //
310    // InputXRComponent drives body translation and head rotation through AvatarControlSystem.
311    // AvatarControlSystem:
312    //   - Splices a TransformComponent under J_Bip_C_Head's parent (the neck) to drive
313    //     head rotation directly. Rotating the head — not the neck — isolates the spine
314    //     so the torso doesn't twist with HMD yaw.
315    //   - Strips rotation from model_root (body faces body_yaw, not raw HMD yaw).
316    //   - Bakes the π Y handedness correction into the head rotation math.
317    //   - Smoothly rotates body to follow head when yaw delta exceeds threshold.
318    //   - Measures J_Bip_C_Head local Y in the rest pose and sets model_root.y = -bone_local_y,
319    //     so the head bone sits at driven_t world Y (= HMD height) with no hardcoded constant.
320    //   - Re-parents CameraXRComponent under J_Bip_C_Head for first-person alignment.
321    //
322    // Topology (after AVC init):
323    //   editor_root
324    //     └── avatar_input_xr (InputXRComponent)
325    //           └── avatar_driven_t (TransformComponent)
326    //                 └── AvatarControlComponent
327    //                       ├── body_pipeline → pipeline_output
328    //                       │     └── model_root (y auto-calibrated from J_Bip_C_Head)
329    //                       │           └── GLTFComponent → ... → J_Bip_C_Head
330    //                       │                                           └── CameraXRComponent
331    //                       ├── CTLXR(Left, Grip) → re-parented to lower_arm
332    //                       └── CTLXR(Right, Grip) → re-parented to lower_arm
333
334    let editor_root = universe.world.add_component(EditorComponent::new());
335
336    let avatar_input_xr = universe.world.add_component(InputXRComponent::on());
337    let avatar_xr_gamepad = universe.world.add_component(
338        mittens_engine::engine::ecs::component::InputXRGamepadComponent::new().speed(1.5),
339    );
340    let avatar_driven_t = universe.world.add_component(TransformComponent::new());
341    let _ = universe.attach(avatar_input_xr, avatar_driven_t);
342    let _ = universe.attach(avatar_input_xr, avatar_xr_gamepad);
343
344    // AvatarControlComponent: -Z forward (OpenXR default), body starts facing -Z (π yaw).
345    // camera_bone triggers auto-calibration of model_root.y from J_Bip_C_Head rest pose height,
346    // and causes any CameraXR/Camera3D direct children of AVC to be re-parented to that bone.
347    let avatar_control = universe.world.add_component(
348        AvatarControlComponent::new()
349            .with_head_bone("J_Bip_C_Head")
350            .with_camera_bone("J_Bip_C_Head")
351            .with_left_hand_bone("J_Bip_L_Hand")
352            .with_right_hand_bone("J_Bip_R_Hand")
353            .with_initial_yaw(std::f32::consts::PI)
354            .with_hand_rotation_smoothing(220.0),
355    );
356    let _ = universe.attach(avatar_driven_t, avatar_control);
357
358    // CameraXR as a direct child of AVC — discovered and re-parented to J_Bip_C_Head at init.
359    let camera_xr = universe.world.add_component(CameraXRComponent::on());
360    let _ = universe.attach(avatar_control, camera_xr);
361    let head_pointer = universe.world.add_component(PointerComponent::new());
362    let _ = universe.attach(camera_xr, head_pointer);
363
364    // Grip controllers for hand bone splicing — children of AvatarControlComponent so
365    // AvatarControlSystem discovers them by topology. Each needs a TransformComponent
366    // child (driven_t) that OpenXRSystem writes each tick.
367    let left_grip = universe.world.add_component(ControllerXRComponent::new(
368        true,
369        ControllerHand::Left,
370        ControllerPoseKind::Grip,
371    ));
372    let left_grip_t = universe.world.add_component(TransformComponent::new());
373    let _ = universe.attach(left_grip, left_grip_t);
374    let left_pointer = universe.world.add_component(PointerComponent::new());
375    let _ = universe.attach(left_grip_t, left_pointer);
376    let _ = universe.attach(avatar_control, left_grip);
377
378    let right_grip = universe.world.add_component(ControllerXRComponent::new(
379        true,
380        ControllerHand::Right,
381        ControllerPoseKind::Grip,
382    ));
383    let right_grip_t = universe.world.add_component(TransformComponent::new());
384    let _ = universe.attach(right_grip, right_grip_t);
385    let right_pointer = universe.world.add_component(PointerComponent::new());
386    let _ = universe.attach(right_grip_t, right_pointer);
387    let _ = universe.attach(avatar_control, right_grip);
388
389    // model_root: no explicit Y offset — AvatarControlSystem calibrates it from J_Bip_C_Head.
390    let model_root = universe.world.add_component(TransformComponent::new());
391    let model = universe
392        .world
393        .add_component(GLTFComponent::new("assets/models/pc-rei.hoodie.glb"));
394    let emissive = universe.world.add_component(EmissiveComponent::on());
395    let _ = universe.attach(model, emissive);
396
397    let _ = universe.attach(editor_root, avatar_input_xr);
398    let _ = universe.attach(avatar_control, model_root);
399    let _ = universe.attach(model_root, model);
400    universe.add(editor_root);
401
402    // --- Controller debug cubes (tracked poses) ---
403    let _left = spawn_controller_cube(
404        &mut universe,
405        xr_rig,
406        ControllerHand::Left,
407        (0.10, 0.90, 1.00, 1.0),
408        220.0,
409        options.xr_controller_rotation_filter,
410    );
411    let _right = spawn_controller_cube(
412        &mut universe,
413        xr_rig,
414        ControllerHand::Right,
415        (1.00, 0.35, 0.35, 1.0),
416        220.0,
417        options.xr_controller_rotation_filter,
418    );
419
420    // Enable OpenXR runtime.
421    let xr_root = universe.world.add_component(XrComponent::on());
422    universe.add(xr_root);
423
424    universe.systems.process_commands(
425        &mut universe.world,
426        &mut universe.visuals,
427        &mut universe.render_assets,
428        &mut universe.command_queue,
429    );
430
431    // Force the glTF subtree to spawn so we can query the armature for bone markers.
432    {
433        let systems = &mut universe.systems;
434        systems.gltf.tick_with_queue(
435            &mut universe.world,
436            &mut universe.visuals,
437            &mut systems.skinned_mesh,
438            &mut universe.command_queue,
439            0.0,
440        );
441    }
442    universe.systems.process_commands(
443        &mut universe.world,
444        &mut universe.visuals,
445        &mut universe.render_assets,
446        &mut universe.command_queue,
447    );
448
449    // Bone markers for editor inspection.
450    let marker_joints: &[(&str, (f32, f32, f32, f32))] = &[
451        ("[name='J_Bip_C_Head']", (0.85, 0.20, 0.85, 0.9)),
452        ("[name='J_Bip_C_Neck']", (0.20, 0.85, 0.85, 0.9)),
453        ("[name='J_Bip_C_UpperChest']", (0.20, 0.20, 0.85, 0.9)),
454        ("[name='J_Bip_L_UpperArm']", (0.85, 0.85, 0.20, 0.9)),
455        ("[name='J_Bip_R_UpperArm']", (0.85, 0.60, 0.20, 0.9)),
456    ];
457
458    for &(selector, color) in marker_joints {
459        let Some(bone) = universe.find_component(model_root, selector) else {
460            continue;
461        };
462        let marker_t = universe
463            .world
464            .add_component(TransformComponent::new().with_scale(0.025, 0.025, 0.025));
465        let marker_r = universe.world.add_component(RenderableComponent::cube());
466        let marker_c = universe
467            .world
468            .add_component(ColorComponent::rgba(color.0, color.1, color.2, color.3));
469        let marker_rcast = universe
470            .world
471            .add_component(RaycastableComponent::enabled());
472        let _ = universe.world.add_child(marker_r, marker_c);
473        let _ = universe.world.add_child(marker_r, marker_rcast);
474        let _ = universe.world.add_child(marker_t, marker_r);
475        let _ = universe.attach(bone, marker_t);
476    }
477
478    universe.enable_repl();
479    engine::Windowing::run_app(universe).expect("Windowing failed");
480}
examples/vtuber-joints-example.rs (lines 284-290)
14fn main() {
15    mittens_engine::example_support::ensure_model_assets();
16    utils::logger::init();
17
18    let world = engine::ecs::World::default();
19    let mut universe = engine::Universe::new(world);
20
21    // Slow the global beat clock so beat-based animations run half as fast.
22    let clock = universe
23        .world
24        .add_component(ClockComponent::new().with_bpm(60.0));
25    universe.add(clock);
26
27    // Light pink background.
28    let background = universe
29        .world
30        .add_component(BackgroundColorComponent::new());
31    let background_c = universe
32        .world
33        .add_component(ColorComponent::rgba(1.0, 0.82, 0.90, 1.0));
34    let _ = universe.world.add_child(background, background_c);
35    universe.add(background);
36
37    // Small ambient so shadowed areas aren't pure black.
38    let ambient = universe
39        .world
40        .add_component(AmbientLightComponent::rgb(0.10, 0.10, 0.12));
41    universe.add(ambient);
42
43    // --- Camera rig (WASD + mouse) ---
44    let input = universe
45        .world
46        .add_component(InputComponent::new().with_speed(1.5));
47    let input_mode = universe.world.add_component(
48        InputTransformModeComponent::forward_z()
49            .with_fps_rotation()
50            .with_roll_axis_y(),
51    );
52    let _ = universe.attach(input, input_mode);
53
54    // Start slightly pulled back looking towards the origin.
55    let rig_transform = universe
56        .world
57        .add_component(TransformComponent::new().with_position(0.0, 0.0, 6.0));
58    let _ = universe.attach(input, rig_transform);
59
60    let camera3d = universe.world.add_component(Camera3DComponent::new());
61    let _ = universe.attach(rig_transform, camera3d);
62
63    // Pointer so gizmos can be interacted with.
64    let pointer = universe.world.add_component(PointerComponent::new());
65    let _ = universe.attach(camera3d, pointer);
66
67    // Topology: I { T { C3D } } — add a small camera-attached controls hint.
68    example_util::spawn_desktop_camera_controls_hint(&mut universe, rig_transform);
69
70    universe.add(input);
71
72    // --- lighting ---
73    let sun = universe.world.add_component(
74        DirectionalLightComponent::new()
75            .with_intensity(1.2)
76            .with_color(1.0, 0.98, 0.94),
77    );
78    let sun_dir = universe
79        .world
80        .add_component(TransformComponent::new().with_position(0.0, -0.35, 1.0));
81    let _ = universe.attach(sun_dir, sun);
82    universe.add(sun_dir);
83
84    let light_transform = universe.world.add_component(
85        TransformComponent::new()
86            .with_position(1.0, 6.0, 3.0)
87            .with_scale(0.1, 0.1, 0.1),
88    );
89    let light = universe.world.add_component(
90        engine::ecs::component::PointLightComponent::new()
91            .with_distance(120.0)
92            .with_color(1.0, 1.0, 1.0),
93    );
94    let _ = universe.attach(light_transform, light);
95    universe.add(light_transform);
96
97    // --- VTuber model ---
98    let model_uri = "assets/models/pc-rei.hoodie.glb";
99
100    // Wrap the model subtree in an editor root so transform-only glTF nodes can be visualized
101    // (and thus raycasted/selected) without affecting non-editor scenes.
102    let editor_root = universe.world.add_component(EditorComponent::new());
103
104    let model_root = universe.world.add_component(TransformComponent::new());
105    let model = universe.world.add_component(GLTFComponent::new(model_uri));
106
107    // emissive for pc-rei
108    let emissive = universe.world.add_component(EmissiveComponent::on());
109    let _ = universe.attach(model, emissive);
110
111    let xr_input = universe.world.add_component(InputXRComponent::on());
112    let xr_gamepad = universe
113        .world
114        .add_component(engine::ecs::component::InputXRGamepadComponent::new().speed(1.5));
115    let xr_head = universe.world.add_component(TransformComponent::new());
116    let xr_camera = universe.world.add_component(CameraXRComponent::on());
117    let _ = universe.attach(xr_input, xr_head);
118    let _ = universe.attach(xr_input, xr_gamepad);
119    let _ = universe.attach(xr_head, xr_camera);
120    let xr_pointer = universe.world.add_component(PointerComponent::new());
121    let _ = universe.attach(xr_camera, xr_pointer);
122    let _ = universe.attach(xr_head, editor_root);
123
124    let _ = universe.attach(model_root, model);
125
126    let _ = universe.attach(editor_root, model_root);
127
128    // Initialize the editor root so GLTFComponent gets registered.
129    universe.add(xr_input);
130    universe.add(editor_root);
131
132    // --- Background clouds (occluded + lit) ---
133    let bg_root = universe.world.add_component(
134        engine::ecs::component::BackgroundComponent::new().with_occlusion_and_lighting(),
135    );
136    universe.add(bg_root);
137    let mut cloud_params = example_util::CloudRingParams::default();
138    cloud_params.cloud_count = 8; // +3 clusters
139    cloud_params.angle_jitter = 0.35;
140    cloud_params.high_y_probability = 0.5;
141    cloud_params.high_y_multiplier = 1.5;
142    cloud_params.seed = 0x57_55_B0_01u32;
143    example_util::spawn_cloud_ring(&mut universe, bg_root, cloud_params);
144
145    // --- Simple environment ---
146    let spawn_cube = |universe: &mut engine::Universe,
147                      position: (f32, f32, f32),
148                      scale: (f32, f32, f32),
149                      color: (f32, f32, f32, f32)| {
150        let transform = universe.world.add_component(
151            TransformComponent::new()
152                .with_position(position.0, position.1, position.2)
153                .with_scale(scale.0, scale.1, scale.2),
154        );
155        let renderable = universe.world.add_component(RenderableComponent::cube());
156        let color = universe
157            .world
158            .add_component(ColorComponent::rgba(color.0, color.1, color.2, color.3));
159
160        let _ = universe.attach(transform, renderable);
161        let _ = universe.attach(renderable, color);
162
163        universe.add(transform);
164    };
165
166    // floor
167    spawn_cube(
168        &mut universe,
169        (0.0, -0.05, 0.0),
170        (10.0, 0.1, 10.0),
171        (0.92, 0.92, 0.92, 1.0),
172    );
173
174    // back wall
175    spawn_cube(
176        &mut universe,
177        (-3.0, 1.5, -5.0),
178        (3.0, 3.0, 1.0),
179        (0.95, 0.94, 0.96, 1.0),
180    );
181
182    // desk
183    spawn_cube(
184        &mut universe,
185        (0.0, 0.35, 1.0),
186        (1.0, 0.75, 0.5),
187        (0.75, 0.70, 0.65, 1.0),
188    );
189
190    // --- Editor-side stacked cubes (inside the editor subtree for picking/gizmos) ---
191    {
192        let spawn_editor_cube = |universe: &mut engine::Universe,
193                                 editor_root: engine::ecs::ComponentId,
194                                 name: &str,
195                                 position: (f32, f32, f32),
196                                 scale: (f32, f32, f32),
197                                 color: (f32, f32, f32, f32)| {
198            let transform = universe.world.add_component_boxed_named(
199                format!("{name}_t"),
200                Box::new(
201                    TransformComponent::new()
202                        .with_position(position.0, position.1, position.2)
203                        .with_scale(scale.0, scale.1, scale.2),
204                ),
205            );
206            let renderable = universe.world.add_component_boxed_named(
207                format!("{name}_r"),
208                Box::new(RenderableComponent::cube()),
209            );
210            let color_comp = universe.world.add_component_boxed_named(
211                format!("{name}_color"),
212                Box::new(ColorComponent::rgba(color.0, color.1, color.2, color.3)),
213            );
214            let raycastable = universe.world.add_component_boxed_named(
215                format!("{name}_raycastable"),
216                Box::new(RaycastableComponent::enabled()),
217            );
218
219            let _ = universe.world.add_child(transform, renderable);
220            let _ = universe.world.add_child(renderable, color_comp);
221            let _ = universe.world.add_child(renderable, raycastable);
222
223            // One attach into the initialized editor subtree triggers init for the new subtree.
224            let _ = universe.attach(editor_root, transform);
225        };
226
227        // Place the stack beside the desk (a bit to the right).
228        let stack_x = 1.35;
229        let stack_z = 1.0;
230        let s = 0.25;
231        let half = 0.5 * s;
232        let light_brown = (0.80, 0.72, 0.55, 1.0);
233        let cyan = (0.20, 1.00, 1.00, 1.0);
234
235        spawn_editor_cube(
236            &mut universe,
237            editor_root,
238            "editor_stack_0",
239            (stack_x, half, stack_z),
240            (s, s, s),
241            light_brown,
242        );
243        spawn_editor_cube(
244            &mut universe,
245            editor_root,
246            "editor_stack_1",
247            (stack_x, half + 1.0 * s, stack_z),
248            (s, s, s),
249            light_brown,
250        );
251        spawn_editor_cube(
252            &mut universe,
253            editor_root,
254            "editor_stack_2",
255            (stack_x, half + 2.0 * s, stack_z),
256            (s, s, s),
257            light_brown,
258        );
259        spawn_editor_cube(
260            &mut universe,
261            editor_root,
262            "editor_stack_top",
263            (stack_x, half + 3.0 * s, stack_z),
264            (s, s, s),
265            cyan,
266        );
267    }
268
269    let xr_root = universe
270        .world
271        .add_component(engine::ecs::component::XrComponent::on());
272    universe.add(xr_root);
273
274    universe.systems.process_commands(
275        &mut universe.world,
276        &mut universe.visuals,
277        &mut universe.render_assets,
278        &mut universe.command_queue,
279    );
280
281    // Spawn the glTF subtree once up-front so joint ComponentIds exist.
282    {
283        let systems = &mut universe.systems;
284        systems.gltf.tick_with_queue(
285            &mut universe.world,
286            &mut universe.visuals,
287            &mut systems.skinned_mesh,
288            &mut universe.command_queue,
289            0.0,
290        );
291    }
292    universe.systems.process_commands(
293        &mut universe.world,
294        &mut universe.visuals,
295        &mut universe.render_assets,
296        &mut universe.command_queue,
297    );
298
299    // Register imported meshes into RenderAssets early so we can inspect skin weights
300    // (textures will still be uploaded later during normal rendering).
301    universe
302        .systems
303        .gltf
304        .flush_mesh_imports_only(&mut universe.render_assets);
305
306    // --- Joint printout + animation binding (in the example) ---
307    let all_joints = collect_joint_transforms(
308        &universe.world,
309        &universe.systems.skinned_mesh,
310        &universe.visuals,
311        model,
312        model_root,
313    );
314    println!("[vtuber-joints-example] joints found: {}", all_joints.len());
315    for (i, (node_index, joint_tx)) in all_joints.iter().enumerate() {
316        println!("  joint[{i:03}] node_index={node_index} transform={joint_tx:?}");
317    }
318
319    let node_index_to_transform: HashMap<usize, engine::ecs::ComponentId> =
320        all_joints.iter().copied().collect();
321
322    // Example settings are hardcoded to keep this example simple.
323    let joint_offset: usize = 0;
324    let wiggle_count: usize = 16;
325
326    let target_mesh_key = "pc-rei.hoodie:Body_(merged).baked:prim0".to_string();
327    let target_joint_names: Vec<String> = vec![
328        "J_Bip_L_UpperArm".to_string(),
329        "J_Bip_R_UpperArm".to_string(),
330    ];
331
332    let print_transform_updates: bool = false;
333
334    let selected_joint_transforms: Vec<(usize, engine::ecs::ComponentId)> =
335        select_named_joints(&universe.world, &all_joints, &target_joint_names)
336            .or_else(|| {
337                select_body_prim0_influencers(
338                    &universe,
339                    model_root,
340                    &target_mesh_key,
341                    wiggle_count,
342                    &node_index_to_transform,
343                )
344            })
345            .unwrap_or_else(|| select_joint_range(&all_joints, joint_offset, wiggle_count));
346    println!(
347        "[vtuber-joints-example] wiggle selection: target_mesh_key='{}' offset={} count={} selected={}",
348        target_mesh_key,
349        joint_offset,
350        wiggle_count,
351        selected_joint_transforms.len()
352    );
353
354    debug_print_selected_joint_influence(
355        &universe,
356        &target_mesh_key,
357        model_root,
358        &selected_joint_transforms,
359    );
360
361    println!("[vtuber-joints-example] selected joints:");
362    for (i, (node_index, joint_tx)) in selected_joint_transforms.iter().enumerate() {
363        let name = universe
364            .world
365            .get_component_record(*joint_tx)
366            .map(|n| n.name.as_str())
367            .unwrap_or("<unknown>");
368        println!("  sel[{i:02}] node_index={node_index} name={name} transform={joint_tx:?}");
369    }
370
371    if print_transform_updates {
372        println!("[vtuber-joints-example] note: joint animation disabled");
373    }
374
375    universe.systems.process_commands(
376        &mut universe.world,
377        &mut universe.visuals,
378        &mut universe.render_assets,
379        &mut universe.command_queue,
380    );
381
382    universe.enable_repl();
383    engine::Windowing::run_app(universe).expect("Windowing failed");
384}
Source

pub fn flush_imports( &mut self, render_assets: &mut RenderAssets, texture_system: &mut TextureSystem, uploader: &mut dyn RenderUploader, )

Source

pub fn flush_mesh_imports_only(&mut self, render_assets: &mut RenderAssets)

Register imported CPU meshes into RenderAssets without uploading textures.

This is useful for headless/early inspection (e.g. examples that want to analyze JOINTS_0/WEIGHTS_0) before a renderer is initialized.

Examples found in repository?
examples/vtuber-joints-example.rs (line 304)
14fn main() {
15    mittens_engine::example_support::ensure_model_assets();
16    utils::logger::init();
17
18    let world = engine::ecs::World::default();
19    let mut universe = engine::Universe::new(world);
20
21    // Slow the global beat clock so beat-based animations run half as fast.
22    let clock = universe
23        .world
24        .add_component(ClockComponent::new().with_bpm(60.0));
25    universe.add(clock);
26
27    // Light pink background.
28    let background = universe
29        .world
30        .add_component(BackgroundColorComponent::new());
31    let background_c = universe
32        .world
33        .add_component(ColorComponent::rgba(1.0, 0.82, 0.90, 1.0));
34    let _ = universe.world.add_child(background, background_c);
35    universe.add(background);
36
37    // Small ambient so shadowed areas aren't pure black.
38    let ambient = universe
39        .world
40        .add_component(AmbientLightComponent::rgb(0.10, 0.10, 0.12));
41    universe.add(ambient);
42
43    // --- Camera rig (WASD + mouse) ---
44    let input = universe
45        .world
46        .add_component(InputComponent::new().with_speed(1.5));
47    let input_mode = universe.world.add_component(
48        InputTransformModeComponent::forward_z()
49            .with_fps_rotation()
50            .with_roll_axis_y(),
51    );
52    let _ = universe.attach(input, input_mode);
53
54    // Start slightly pulled back looking towards the origin.
55    let rig_transform = universe
56        .world
57        .add_component(TransformComponent::new().with_position(0.0, 0.0, 6.0));
58    let _ = universe.attach(input, rig_transform);
59
60    let camera3d = universe.world.add_component(Camera3DComponent::new());
61    let _ = universe.attach(rig_transform, camera3d);
62
63    // Pointer so gizmos can be interacted with.
64    let pointer = universe.world.add_component(PointerComponent::new());
65    let _ = universe.attach(camera3d, pointer);
66
67    // Topology: I { T { C3D } } — add a small camera-attached controls hint.
68    example_util::spawn_desktop_camera_controls_hint(&mut universe, rig_transform);
69
70    universe.add(input);
71
72    // --- lighting ---
73    let sun = universe.world.add_component(
74        DirectionalLightComponent::new()
75            .with_intensity(1.2)
76            .with_color(1.0, 0.98, 0.94),
77    );
78    let sun_dir = universe
79        .world
80        .add_component(TransformComponent::new().with_position(0.0, -0.35, 1.0));
81    let _ = universe.attach(sun_dir, sun);
82    universe.add(sun_dir);
83
84    let light_transform = universe.world.add_component(
85        TransformComponent::new()
86            .with_position(1.0, 6.0, 3.0)
87            .with_scale(0.1, 0.1, 0.1),
88    );
89    let light = universe.world.add_component(
90        engine::ecs::component::PointLightComponent::new()
91            .with_distance(120.0)
92            .with_color(1.0, 1.0, 1.0),
93    );
94    let _ = universe.attach(light_transform, light);
95    universe.add(light_transform);
96
97    // --- VTuber model ---
98    let model_uri = "assets/models/pc-rei.hoodie.glb";
99
100    // Wrap the model subtree in an editor root so transform-only glTF nodes can be visualized
101    // (and thus raycasted/selected) without affecting non-editor scenes.
102    let editor_root = universe.world.add_component(EditorComponent::new());
103
104    let model_root = universe.world.add_component(TransformComponent::new());
105    let model = universe.world.add_component(GLTFComponent::new(model_uri));
106
107    // emissive for pc-rei
108    let emissive = universe.world.add_component(EmissiveComponent::on());
109    let _ = universe.attach(model, emissive);
110
111    let xr_input = universe.world.add_component(InputXRComponent::on());
112    let xr_gamepad = universe
113        .world
114        .add_component(engine::ecs::component::InputXRGamepadComponent::new().speed(1.5));
115    let xr_head = universe.world.add_component(TransformComponent::new());
116    let xr_camera = universe.world.add_component(CameraXRComponent::on());
117    let _ = universe.attach(xr_input, xr_head);
118    let _ = universe.attach(xr_input, xr_gamepad);
119    let _ = universe.attach(xr_head, xr_camera);
120    let xr_pointer = universe.world.add_component(PointerComponent::new());
121    let _ = universe.attach(xr_camera, xr_pointer);
122    let _ = universe.attach(xr_head, editor_root);
123
124    let _ = universe.attach(model_root, model);
125
126    let _ = universe.attach(editor_root, model_root);
127
128    // Initialize the editor root so GLTFComponent gets registered.
129    universe.add(xr_input);
130    universe.add(editor_root);
131
132    // --- Background clouds (occluded + lit) ---
133    let bg_root = universe.world.add_component(
134        engine::ecs::component::BackgroundComponent::new().with_occlusion_and_lighting(),
135    );
136    universe.add(bg_root);
137    let mut cloud_params = example_util::CloudRingParams::default();
138    cloud_params.cloud_count = 8; // +3 clusters
139    cloud_params.angle_jitter = 0.35;
140    cloud_params.high_y_probability = 0.5;
141    cloud_params.high_y_multiplier = 1.5;
142    cloud_params.seed = 0x57_55_B0_01u32;
143    example_util::spawn_cloud_ring(&mut universe, bg_root, cloud_params);
144
145    // --- Simple environment ---
146    let spawn_cube = |universe: &mut engine::Universe,
147                      position: (f32, f32, f32),
148                      scale: (f32, f32, f32),
149                      color: (f32, f32, f32, f32)| {
150        let transform = universe.world.add_component(
151            TransformComponent::new()
152                .with_position(position.0, position.1, position.2)
153                .with_scale(scale.0, scale.1, scale.2),
154        );
155        let renderable = universe.world.add_component(RenderableComponent::cube());
156        let color = universe
157            .world
158            .add_component(ColorComponent::rgba(color.0, color.1, color.2, color.3));
159
160        let _ = universe.attach(transform, renderable);
161        let _ = universe.attach(renderable, color);
162
163        universe.add(transform);
164    };
165
166    // floor
167    spawn_cube(
168        &mut universe,
169        (0.0, -0.05, 0.0),
170        (10.0, 0.1, 10.0),
171        (0.92, 0.92, 0.92, 1.0),
172    );
173
174    // back wall
175    spawn_cube(
176        &mut universe,
177        (-3.0, 1.5, -5.0),
178        (3.0, 3.0, 1.0),
179        (0.95, 0.94, 0.96, 1.0),
180    );
181
182    // desk
183    spawn_cube(
184        &mut universe,
185        (0.0, 0.35, 1.0),
186        (1.0, 0.75, 0.5),
187        (0.75, 0.70, 0.65, 1.0),
188    );
189
190    // --- Editor-side stacked cubes (inside the editor subtree for picking/gizmos) ---
191    {
192        let spawn_editor_cube = |universe: &mut engine::Universe,
193                                 editor_root: engine::ecs::ComponentId,
194                                 name: &str,
195                                 position: (f32, f32, f32),
196                                 scale: (f32, f32, f32),
197                                 color: (f32, f32, f32, f32)| {
198            let transform = universe.world.add_component_boxed_named(
199                format!("{name}_t"),
200                Box::new(
201                    TransformComponent::new()
202                        .with_position(position.0, position.1, position.2)
203                        .with_scale(scale.0, scale.1, scale.2),
204                ),
205            );
206            let renderable = universe.world.add_component_boxed_named(
207                format!("{name}_r"),
208                Box::new(RenderableComponent::cube()),
209            );
210            let color_comp = universe.world.add_component_boxed_named(
211                format!("{name}_color"),
212                Box::new(ColorComponent::rgba(color.0, color.1, color.2, color.3)),
213            );
214            let raycastable = universe.world.add_component_boxed_named(
215                format!("{name}_raycastable"),
216                Box::new(RaycastableComponent::enabled()),
217            );
218
219            let _ = universe.world.add_child(transform, renderable);
220            let _ = universe.world.add_child(renderable, color_comp);
221            let _ = universe.world.add_child(renderable, raycastable);
222
223            // One attach into the initialized editor subtree triggers init for the new subtree.
224            let _ = universe.attach(editor_root, transform);
225        };
226
227        // Place the stack beside the desk (a bit to the right).
228        let stack_x = 1.35;
229        let stack_z = 1.0;
230        let s = 0.25;
231        let half = 0.5 * s;
232        let light_brown = (0.80, 0.72, 0.55, 1.0);
233        let cyan = (0.20, 1.00, 1.00, 1.0);
234
235        spawn_editor_cube(
236            &mut universe,
237            editor_root,
238            "editor_stack_0",
239            (stack_x, half, stack_z),
240            (s, s, s),
241            light_brown,
242        );
243        spawn_editor_cube(
244            &mut universe,
245            editor_root,
246            "editor_stack_1",
247            (stack_x, half + 1.0 * s, stack_z),
248            (s, s, s),
249            light_brown,
250        );
251        spawn_editor_cube(
252            &mut universe,
253            editor_root,
254            "editor_stack_2",
255            (stack_x, half + 2.0 * s, stack_z),
256            (s, s, s),
257            light_brown,
258        );
259        spawn_editor_cube(
260            &mut universe,
261            editor_root,
262            "editor_stack_top",
263            (stack_x, half + 3.0 * s, stack_z),
264            (s, s, s),
265            cyan,
266        );
267    }
268
269    let xr_root = universe
270        .world
271        .add_component(engine::ecs::component::XrComponent::on());
272    universe.add(xr_root);
273
274    universe.systems.process_commands(
275        &mut universe.world,
276        &mut universe.visuals,
277        &mut universe.render_assets,
278        &mut universe.command_queue,
279    );
280
281    // Spawn the glTF subtree once up-front so joint ComponentIds exist.
282    {
283        let systems = &mut universe.systems;
284        systems.gltf.tick_with_queue(
285            &mut universe.world,
286            &mut universe.visuals,
287            &mut systems.skinned_mesh,
288            &mut universe.command_queue,
289            0.0,
290        );
291    }
292    universe.systems.process_commands(
293        &mut universe.world,
294        &mut universe.visuals,
295        &mut universe.render_assets,
296        &mut universe.command_queue,
297    );
298
299    // Register imported meshes into RenderAssets early so we can inspect skin weights
300    // (textures will still be uploaded later during normal rendering).
301    universe
302        .systems
303        .gltf
304        .flush_mesh_imports_only(&mut universe.render_assets);
305
306    // --- Joint printout + animation binding (in the example) ---
307    let all_joints = collect_joint_transforms(
308        &universe.world,
309        &universe.systems.skinned_mesh,
310        &universe.visuals,
311        model,
312        model_root,
313    );
314    println!("[vtuber-joints-example] joints found: {}", all_joints.len());
315    for (i, (node_index, joint_tx)) in all_joints.iter().enumerate() {
316        println!("  joint[{i:03}] node_index={node_index} transform={joint_tx:?}");
317    }
318
319    let node_index_to_transform: HashMap<usize, engine::ecs::ComponentId> =
320        all_joints.iter().copied().collect();
321
322    // Example settings are hardcoded to keep this example simple.
323    let joint_offset: usize = 0;
324    let wiggle_count: usize = 16;
325
326    let target_mesh_key = "pc-rei.hoodie:Body_(merged).baked:prim0".to_string();
327    let target_joint_names: Vec<String> = vec![
328        "J_Bip_L_UpperArm".to_string(),
329        "J_Bip_R_UpperArm".to_string(),
330    ];
331
332    let print_transform_updates: bool = false;
333
334    let selected_joint_transforms: Vec<(usize, engine::ecs::ComponentId)> =
335        select_named_joints(&universe.world, &all_joints, &target_joint_names)
336            .or_else(|| {
337                select_body_prim0_influencers(
338                    &universe,
339                    model_root,
340                    &target_mesh_key,
341                    wiggle_count,
342                    &node_index_to_transform,
343                )
344            })
345            .unwrap_or_else(|| select_joint_range(&all_joints, joint_offset, wiggle_count));
346    println!(
347        "[vtuber-joints-example] wiggle selection: target_mesh_key='{}' offset={} count={} selected={}",
348        target_mesh_key,
349        joint_offset,
350        wiggle_count,
351        selected_joint_transforms.len()
352    );
353
354    debug_print_selected_joint_influence(
355        &universe,
356        &target_mesh_key,
357        model_root,
358        &selected_joint_transforms,
359    );
360
361    println!("[vtuber-joints-example] selected joints:");
362    for (i, (node_index, joint_tx)) in selected_joint_transforms.iter().enumerate() {
363        let name = universe
364            .world
365            .get_component_record(*joint_tx)
366            .map(|n| n.name.as_str())
367            .unwrap_or("<unknown>");
368        println!("  sel[{i:02}] node_index={node_index} name={name} transform={joint_tx:?}");
369    }
370
371    if print_transform_updates {
372        println!("[vtuber-joints-example] note: joint animation disabled");
373    }
374
375    universe.systems.process_commands(
376        &mut universe.world,
377        &mut universe.visuals,
378        &mut universe.render_assets,
379        &mut universe.command_queue,
380    );
381
382    universe.enable_repl();
383    engine::Windowing::run_app(universe).expect("Windowing failed");
384}

Trait Implementations§

Source§

impl Debug for GLTFSystem

Source§

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

Formats the value using the given formatter. Read more
Source§

impl Default for GLTFSystem

Source§

fn default() -> GLTFSystem

Returns the “default value” for a type. Read more
Source§

impl System for GLTFSystem

Source§

fn tick( &mut self, _world: &mut World, _visuals: &mut VisualWorld, _input: &InputState, _dt_sec: f32, )

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> 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> 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, 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