Skip to main content

TextureComponent

Struct TextureComponent 

Source
pub struct TextureComponent {
    pub source: TextureSource,
    pub format: CatEngineTextureFormat,
    pub render_image: Option<String>,
}
Expand description

Reference to a texture image by URI.

This component is intended to be attached as a descendant of a RenderableComponent. The URI is stored in TextureSystem; loading, decoding, and GPU upload happen when the system sees the texture is attached to a renderable.

Fields§

§source: TextureSource§format: CatEngineTextureFormat§render_image: Option<String>

Implementations§

Source§

impl TextureComponent

Source

pub fn new(uri: impl Into<String>) -> Self

Source

pub fn unresolved() -> Self

Source

pub fn with_uri(uri: impl Into<String>) -> Self

Examples found in repository?
examples/font-example.rs (line 181)
125    fn spawn_text_block(
126        universe: &mut engine::Universe,
127        position: (f32, f32, f32),
128        scale: f32,
129        text: &str,
130        font_texture_uri: Option<&str>,
131        text_color_rgba: Option<[f32; 4]>,
132        shadow: Option<TextShadowComponent>,
133        filtering: TextureFilteringComponent,
134    ) -> f32 {
135        // T_root { T_scale { [Color] { TXT { shadow, filtering } } } }
136        let text_root = universe.world.add_component(
137            TransformComponent::new().with_position(position.0, position.1, position.2),
138        );
139
140        let text_scale = universe
141            .world
142            .add_component(TransformComponent::new().with_scale(scale, scale, 1.0));
143        let _ = universe.attach(text_root, text_scale);
144
145        let text_parent = if let Some([r, g, b, a]) = text_color_rgba {
146            let color = universe
147                .world
148                .add_component(ColorComponent::rgba(r, g, b, a));
149            let _ = universe.attach(text_scale, color);
150            color
151        } else {
152            text_scale
153        };
154
155        let text_c = universe.world.add_component(TextComponent::new(text));
156        let _ = universe.attach(text_parent, text_c);
157
158        // Explicit opt-in: make the glyph renderables pickable.
159        // TextSystem will propagate this to all spawned glyph quads.
160        let raycastable = universe
161            .world
162            .add_component(RaycastableComponent::enabled());
163        let _ = universe.attach(text_c, raycastable);
164
165        // Route glyph quads into the alpha-to-coverage cutout pass.
166        let cutout = universe
167            .world
168            .add_component(TransparentCutoutComponent::new());
169        let _ = universe.attach(text_c, cutout);
170
171        if let Some(shadow) = shadow {
172            let shadow_id = universe.world.add_component(shadow);
173            let _ = universe.attach(text_c, shadow_id);
174        }
175
176        // Optional: override the font atlas for this text block.
177        // TextSystem will propagate this to all glyph renderables.
178        if let Some(uri) = font_texture_uri {
179            let tex = universe
180                .world
181                .add_component(TextureComponent::with_uri(uri));
182            let _ = universe.attach(text_c, tex);
183        }
184
185        let filtering_id = universe.world.add_component(filtering);
186        let _ = universe.attach(text_c, filtering_id);
187
188        universe.add(text_root);
189
190        estimate_text_height_world(text, scale)
191    }
More examples
Hide additional examples
examples/text-animation.rs (lines 76-78)
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    // Small on-screen help.
32    example_util::spawn_desktop_camera_controls_hint(&mut universe, rig_transform);
33    universe.add(input);
34
35    // Light so we can see non-emissive materials.
36    let light_transform = universe.world.add_component(
37        engine::ecs::component::TransformComponent::new().with_position(0.0, 0.0, 2.0),
38    );
39    let light = universe.world.add_component(
40        engine::ecs::component::PointLightComponent::new()
41            .with_distance(25.0)
42            .with_color(1.0, 1.0, 1.0),
43    );
44    let _ = universe.attach(light_transform, light);
45    universe.add(light_transform);
46
47    use engine::ecs::component::{
48        ColorComponent, TextComponent, TextShadowComponent, TextureComponent,
49        TextureFilteringComponent, TransformComponent, TransparentCutoutComponent,
50    };
51
52    // Styled text root.
53    let text_root = universe.world.add_component(
54        TransformComponent::new()
55            .with_position(0.0, 0.0, 0.0)
56            .with_scale(0.25, 0.25, 1.0),
57    );
58
59    // Color must be an ancestor of the glyph renderables.
60    let color_id = universe
61        .world
62        .add_component(ColorComponent::rgba(1.0, 1.0, 1.0, 1.0));
63    let _ = universe.attach(text_root, color_id);
64
65    // This is the component we animate via SetText.
66    let text_id = universe.world.add_component(TextComponent::new(">w<"));
67    let _ = universe.attach(color_id, text_id);
68
69    // Route into cutout pass for cleaner edges.
70    let cutout = universe
71        .world
72        .add_component(TransparentCutoutComponent::new());
73    let _ = universe.attach(text_id, cutout);
74
75    // Font atlas.
76    let tex = universe.world.add_component(TextureComponent::with_uri(
77        "assets/textures/font_system.dds",
78    ));
79    let _ = universe.attach(text_id, tex);
80
81    let shadow = universe.world.add_component(
82        TextShadowComponent::new()
83            .with_scale(1.35)
84            .with_offset([0.06, -0.06, 0.0015]),
85    );
86    let filtering = universe
87        .world
88        .add_component(TextureFilteringComponent::nearest_magnification());
89
90    let _ = universe.attach(text_id, shadow);
91    let _ = universe.attach(text_id, filtering);
92
93    universe.add(text_root);
94
95    let clock_component = universe
96        .world
97        .add_component(engine::ecs::component::ClockComponent::new().with_bpm(140.0));
98    let _ = universe.add(clock_component);
99
100    // Looping animation: 4 beats long, 4 keyframes.
101    let anim = universe
102        .world
103        .add_component(engine::ecs::component::AnimationComponent::new());
104
105    let faces = [">w<", "^w^", "-_-", "o_o"];
106    for (i, &face) in faces.iter().enumerate() {
107        let kf = universe
108            .world
109            .add_component(engine::ecs::component::KeyframeComponent::new(i as f64));
110
111        // Each keyframe emits a SetText intent.
112        let action = universe
113            .world
114            .add_component(engine::ecs::component::ActionComponent::new(
115                engine::ecs::IntentValue::SetText {
116                    component_ids: vec![text_id],
117                    text: face.to_string(),
118                },
119            ));
120
121        let _ = universe.attach(anim, kf);
122        let _ = universe.attach(kf, action);
123    }
124
125    universe.add(anim);
126
127    // Process init-time registrations (Text expands into glyph subtrees here).
128    universe.systems.process_commands(
129        &mut universe.world,
130        &mut universe.visuals,
131        &mut universe.render_assets,
132        &mut universe.command_queue,
133    );
134
135    engine::Windowing::run_app(universe).expect("Windowing failed");
136}
examples/transparent-cutout-example.rs (lines 123-125)
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 (lines 47-49)
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}
Source

pub fn render_image(selector: impl Into<String>) -> Self

Source

pub fn from_handle(handle: TextureHandle) -> Self

Source

pub fn from_png(uri: impl Into<String>) -> Self

Construct a texture component referencing a PNG file.

Currently, the engine treats uri as a local filesystem path (optionally prefixed with file://).

Source

pub fn from_dds(uri: impl Into<String>) -> Self

Construct a texture component referencing a DDS file containing BC7 blocks.

Examples found in repository?
examples/simple-demo.rs (lines 256-258)
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}
Source

pub fn refresh_format_from_uri(&mut self)

Source

pub fn uri(&self) -> Option<&str>

Trait Implementations§

Source§

impl Clone for TextureComponent

Source§

fn clone(&self) -> TextureComponent

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 TextureComponent

Source§

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

Short debug/type name for this component kind (e.g. “transform”, “camera”).
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 to_mms_ast(&self, _world: &World) -> ComponentExpression

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

fn set_id(&mut self, _component: ComponentId)

Source§

fn cleanup(&mut self, _emit: &mut dyn SignalEmitter, _component: ComponentId)

Called when component is removed from the World.
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 TextureComponent

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