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
impl TextureComponent
pub fn new(uri: impl Into<String>) -> Self
pub fn unresolved() -> Self
Sourcepub fn with_uri(uri: impl Into<String>) -> Self
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
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}pub fn render_image(selector: impl Into<String>) -> Self
pub fn from_handle(handle: TextureHandle) -> Self
Sourcepub fn from_png(uri: impl Into<String>) -> Self
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://).
Sourcepub fn from_dds(uri: impl Into<String>) -> Self
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}pub fn refresh_format_from_uri(&mut self)
pub fn uri(&self) -> Option<&str>
Trait Implementations§
Source§impl Clone for TextureComponent
impl Clone for TextureComponent
Source§fn clone(&self) -> TextureComponent
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)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreSource§impl Component for TextureComponent
impl Component for TextureComponent
Source§fn name(&self) -> &'static str
fn name(&self) -> &'static str
Short debug/type name for this component kind (e.g. “transform”, “camera”).
fn as_any(&self) -> &dyn Any
fn as_any_mut(&mut self) -> &mut dyn Any
Source§fn init(&mut self, emit: &mut dyn SignalEmitter, component: ComponentId)
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
fn to_mms_ast(&self, _world: &World) -> ComponentExpression
Encode this component as an MMS Component Expression AST node. Read more
fn set_id(&mut self, _component: ComponentId)
Source§fn cleanup(&mut self, _emit: &mut dyn SignalEmitter, _component: ComponentId)
fn cleanup(&mut self, _emit: &mut dyn SignalEmitter, _component: ComponentId)
Called when component is removed from the World.
Auto Trait Implementations§
impl Freeze for TextureComponent
impl RefUnwindSafe for TextureComponent
impl Send for TextureComponent
impl Sync for TextureComponent
impl Unpin for TextureComponent
impl UnsafeUnpin for TextureComponent
impl UnwindSafe for TextureComponent
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
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>
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)
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)
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.