mittens_engine/engine/ecs/component/
renderable.rs1use crate::engine::ecs::ComponentId;
2use crate::engine::ecs::component::Component;
3use crate::engine::ecs::component::ce_helpers::{ce, ce_call, num};
4use crate::engine::graphics::mesh::MeshFactory;
5use crate::engine::graphics::primitives::{
6 CpuMeshHandle, InstanceHandle, MaterialHandle, Renderable,
7};
8use crate::engine::graphics::render_assets::RenderAssets;
9
10#[derive(Debug, Clone, PartialEq)]
11pub enum AuthoredRenderableShape {
12 Builtin(&'static str),
13 Cone {
14 segments: u32,
15 },
16 Icosahedron {
17 tessellations: u32,
18 sphericalness: f32,
19 },
20 PartialAnnulus2d {
21 inner_radius: f32,
22 outer_radius: f32,
23 start_angle_radians: f32,
24 sweep_angle_radians: f32,
25 segments: u32,
26 },
27 Star {
28 points: u32,
29 inner_radius_fraction: f32,
30 outer_bevel_segments: u32,
31 inner_bevel_segments: u32,
32 },
33 Heart {
34 segments: u32,
35 },
36 WireframeBox {
37 thickness: f32,
38 },
39}
40
41#[derive(Debug, Clone)]
43pub struct RenderableComponent {
44 pub renderable: Renderable,
45 pub authored_shape: Option<AuthoredRenderableShape>,
46
47 pub handle: Option<InstanceHandle>,
49
50 component: Option<ComponentId>,
51}
52
53impl RenderableComponent {
54 pub fn new(renderable: Renderable) -> Self {
55 Self {
56 renderable,
57 authored_shape: None,
58 handle: None,
59 component: None,
60 }
61 }
62
63 pub fn from_cpu_mesh_handle(h: CpuMeshHandle, material: MaterialHandle) -> Self {
64 Self::new(Renderable::new(h, material))
65 }
66
67 pub fn get_handle(&self) -> Option<InstanceHandle> {
68 self.handle
69 }
70
71 pub fn triangle() -> Self {
73 let mut s =
74 Self::from_cpu_mesh_handle(CpuMeshHandle::TRIANGLE_2D, MaterialHandle::TOON_MESH);
75 s.authored_shape = Some(AuthoredRenderableShape::Builtin("triangle"));
76 s
77 }
78
79 pub fn triangle_dynamic(render_assets: &mut RenderAssets) -> Self {
81 let h = render_assets.register_mesh(MeshFactory::triangle_2d());
82 Self::new(
83 Renderable::new(h, MaterialHandle::TOON_MESH)
84 .with_base_mesh(CpuMeshHandle::TRIANGLE_2D),
85 )
86 }
87
88 pub fn square() -> Self {
90 let mut s = Self::from_cpu_mesh_handle(CpuMeshHandle::QUAD_2D, MaterialHandle::TOON_MESH);
91 s.authored_shape = Some(AuthoredRenderableShape::Builtin("square"));
92 s
93 }
94
95 pub fn plane() -> Self {
97 Self::square()
98 }
99
100 pub fn square_dynamic(render_assets: &mut RenderAssets) -> Self {
102 let h = render_assets.register_mesh(MeshFactory::quad_2d());
103 Self::new(
104 Renderable::new(h, MaterialHandle::TOON_MESH).with_base_mesh(CpuMeshHandle::QUAD_2D),
105 )
106 }
107
108 pub fn cube() -> Self {
110 let mut s = Self::from_cpu_mesh_handle(CpuMeshHandle::CUBE, MaterialHandle::TOON_MESH);
111 s.authored_shape = Some(AuthoredRenderableShape::Builtin("cube"));
112 s
113 }
114
115 pub fn cube_dynamic(render_assets: &mut RenderAssets) -> Self {
117 let h = render_assets.register_mesh(MeshFactory::cube());
118 Self::new(Renderable::new(h, MaterialHandle::TOON_MESH).with_base_mesh(CpuMeshHandle::CUBE))
119 }
120
121 pub fn wireframe_box(render_assets: &mut RenderAssets, thickness: f32) -> Self {
123 let thickness = thickness.clamp(1.0e-4, 1.0);
124 let handle = render_assets.wireframe_box_mesh(thickness);
125 let mut component = Self::new(
126 Renderable::new(handle, MaterialHandle::TOON_MESH).with_base_mesh(CpuMeshHandle::CUBE),
127 );
128 component.authored_shape = Some(AuthoredRenderableShape::WireframeBox { thickness });
129 component
130 }
131
132 pub fn sphere() -> Self {
134 let mut s = Self::from_cpu_mesh_handle(CpuMeshHandle::SPHERE, MaterialHandle::TOON_MESH);
135 s.authored_shape = Some(AuthoredRenderableShape::Builtin("sphere"));
136 s
137 }
138
139 pub fn sphere_dynamic(render_assets: &mut RenderAssets) -> Self {
141 let h = render_assets.register_mesh(MeshFactory::sphere());
142 Self::new(
143 Renderable::new(h, MaterialHandle::TOON_MESH).with_base_mesh(CpuMeshHandle::SPHERE),
144 )
145 }
146
147 pub fn cone() -> Self {
149 let mut s = Self::from_cpu_mesh_handle(CpuMeshHandle::CONE, MaterialHandle::TOON_MESH);
150 s.authored_shape = Some(AuthoredRenderableShape::Builtin("cone"));
151 s
152 }
153
154 pub fn cone_dynamic(render_assets: &mut RenderAssets, segments: u32) -> Self {
156 let h = render_assets.register_mesh(MeshFactory::cone(segments));
157 let mut s = Self::new(
158 Renderable::new(h, MaterialHandle::TOON_MESH).with_base_mesh(CpuMeshHandle::CONE),
159 );
160 s.authored_shape = Some(AuthoredRenderableShape::Cone { segments });
161 s
162 }
163
164 pub fn icosahedron(
165 render_assets: &mut RenderAssets,
166 tessellations: u32,
167 sphericalness: f32,
168 ) -> Self {
169 let h = render_assets.register_mesh(MeshFactory::icosahedron(tessellations, sphericalness));
170 let mut s = Self::new(Renderable::new(h, MaterialHandle::TOON_MESH));
171 s.authored_shape = Some(AuthoredRenderableShape::Icosahedron {
172 tessellations,
173 sphericalness,
174 });
175 s
176 }
177
178 pub fn tetrahedron() -> Self {
180 let mut s =
181 Self::from_cpu_mesh_handle(CpuMeshHandle::TETRAHEDRON, MaterialHandle::TOON_MESH);
182 s.authored_shape = Some(AuthoredRenderableShape::Builtin("tetrahedron"));
183 s
184 }
185
186 pub fn tetrahedron_dynamic(render_assets: &mut RenderAssets) -> Self {
188 let h = render_assets.register_mesh(MeshFactory::tetrahedron());
189 Self::new(
190 Renderable::new(h, MaterialHandle::TOON_MESH)
191 .with_base_mesh(CpuMeshHandle::TETRAHEDRON),
192 )
193 }
194
195 pub fn color_tetrahedron() -> Self {
197 Self::tetrahedron()
198 }
199
200 pub fn circle2d() -> Self {
202 let mut s = Self::from_cpu_mesh_handle(CpuMeshHandle::CIRCLE_2D, MaterialHandle::TOON_MESH);
203 s.authored_shape = Some(AuthoredRenderableShape::Builtin("circle2d"));
204 s
205 }
206
207 pub fn partial_annulus_2d(
208 render_assets: &mut RenderAssets,
209 inner_radius: f32,
210 outer_radius: f32,
211 start_angle_radians: f32,
212 sweep_angle_radians: f32,
213 segments: u32,
214 ) -> Self {
215 let mesh = MeshFactory::partial_annulus_2d(
216 inner_radius,
217 outer_radius,
218 start_angle_radians,
219 sweep_angle_radians,
220 segments,
221 );
222 let h = render_assets.register_mesh(mesh);
223 let mut s = Self::new(Renderable::new(h, MaterialHandle::TOON_MESH));
224 s.authored_shape = Some(AuthoredRenderableShape::PartialAnnulus2d {
225 inner_radius,
226 outer_radius,
227 start_angle_radians,
228 sweep_angle_radians,
229 segments,
230 });
231 s
232 }
233
234 pub fn star(
235 render_assets: &mut RenderAssets,
236 points: u32,
237 inner_radius_fraction: f32,
238 outer_bevel_segments: u32,
239 inner_bevel_segments: u32,
240 ) -> Self {
241 let h = render_assets.register_mesh(MeshFactory::star(
242 points,
243 inner_radius_fraction,
244 outer_bevel_segments,
245 inner_bevel_segments,
246 ));
247 let mut s = Self::new(Renderable::new(h, MaterialHandle::TOON_MESH));
248 s.authored_shape = Some(AuthoredRenderableShape::Star {
249 points,
250 inner_radius_fraction,
251 outer_bevel_segments,
252 inner_bevel_segments,
253 });
254 s
255 }
256
257 pub fn heart(render_assets: &mut RenderAssets, segments: u32) -> Self {
258 let h = render_assets.register_mesh(MeshFactory::heart(segments));
259 let mut s = Self::new(Renderable::new(h, MaterialHandle::TOON_MESH));
260 s.authored_shape = Some(AuthoredRenderableShape::Heart { segments });
261 s
262 }
263}
264
265impl Component for RenderableComponent {
266 fn name(&self) -> &'static str {
267 "renderable"
268 }
269
270 fn set_id(&mut self, component: ComponentId) {
271 self.component = Some(component);
272 }
273
274 fn as_any(&self) -> &dyn std::any::Any {
275 self
276 }
277
278 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
279 self
280 }
281
282 fn init(&mut self, emit: &mut dyn crate::engine::ecs::SignalEmitter, component: ComponentId) {
283 emit.push_intent_now(
284 component,
285 crate::engine::ecs::IntentValue::RegisterRenderable {
286 component_ids: vec![component],
287 },
288 );
289 }
290
291 fn cleanup(
292 &mut self,
293 emit: &mut dyn crate::engine::ecs::SignalEmitter,
294 component: ComponentId,
295 ) {
296 emit.push_intent_now(
297 component,
298 crate::engine::ecs::IntentValue::RemoveRenderable {
299 component_ids: vec![component],
300 },
301 );
302 }
303
304 fn to_mms_ast(
305 &self,
306 _world: &crate::engine::ecs::World,
307 ) -> crate::scripting::ast::ComponentExpression {
308 match &self.authored_shape {
309 Some(AuthoredRenderableShape::Builtin(name)) => ce_call("Renderable", name, vec![]),
310 Some(AuthoredRenderableShape::Cone { segments }) => {
311 ce_call("Renderable", "cone", vec![num(*segments as f64)])
312 }
313 Some(AuthoredRenderableShape::Icosahedron {
314 tessellations,
315 sphericalness,
316 }) => ce_call(
317 "Renderable",
318 "icosahedron",
319 vec![num(*tessellations as f64), num(*sphericalness as f64)],
320 ),
321 Some(AuthoredRenderableShape::PartialAnnulus2d {
322 inner_radius,
323 outer_radius,
324 start_angle_radians,
325 sweep_angle_radians,
326 segments,
327 }) => ce_call(
328 "Renderable",
329 "partial_annulus_2d",
330 vec![
331 num(*inner_radius as f64),
332 num(*outer_radius as f64),
333 num(*start_angle_radians as f64),
334 num(*sweep_angle_radians as f64),
335 num(*segments as f64),
336 ],
337 ),
338 Some(AuthoredRenderableShape::Star {
339 points,
340 inner_radius_fraction,
341 outer_bevel_segments,
342 inner_bevel_segments,
343 }) => ce_call(
344 "Renderable",
345 "star",
346 vec![
347 num(*points as f64),
348 num(*inner_radius_fraction as f64),
349 num(*outer_bevel_segments as f64),
350 num(*inner_bevel_segments as f64),
351 ],
352 ),
353 Some(AuthoredRenderableShape::Heart { segments }) => {
354 ce_call("Renderable", "heart", vec![num(*segments as f64)])
355 }
356 Some(AuthoredRenderableShape::WireframeBox { thickness }) => {
357 ce_call("Renderable", "wireframe_box", vec![num(*thickness as f64)])
358 }
359 None => ce("Renderable"),
360 }
361 }
362}