1use crate::{
27 core::{
28 algebra::{Point3, Vector2, Vector3},
29 color::Color,
30 math::{aabb::AxisAlignedBoundingBox, Rect, TriangleDefinition},
31 pool::Handle,
32 reflect::prelude::*,
33 type_traits::prelude::*,
34 uuid::{uuid, Uuid},
35 value_as_u8_slice,
36 variable::InheritableVariable,
37 visitor::prelude::*,
38 },
39 graph::{constructor::ConstructorProvider, BaseSceneGraph},
40 material::{self, Material, MaterialResource},
41 renderer::{self, bundle::RenderContext},
42 scene::{
43 base::{Base, BaseBuilder},
44 graph::Graph,
45 mesh::{
46 buffer::{
47 VertexAttributeDataType, VertexAttributeDescriptor, VertexAttributeUsage,
48 VertexTrait,
49 },
50 RenderPath,
51 },
52 node::{constructor::NodeConstructor, Node, NodeTrait, RdcControlFlow},
53 },
54};
55use bytemuck::{Pod, Zeroable};
56use std::{
57 hash::{Hash, Hasher},
58 ops::{Deref, DerefMut},
59};
60
61#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
63#[repr(C)] pub struct RectangleVertex {
65 pub position: Vector3<f32>,
67 pub tex_coord: Vector2<f32>,
69 pub color: Color,
71}
72
73impl VertexTrait for RectangleVertex {
74 fn layout() -> &'static [VertexAttributeDescriptor] {
75 &[
76 VertexAttributeDescriptor {
77 usage: VertexAttributeUsage::Position,
78 data_type: VertexAttributeDataType::F32,
79 size: 3,
80 divisor: 0,
81 shader_location: 0,
82 normalized: false,
83 },
84 VertexAttributeDescriptor {
85 usage: VertexAttributeUsage::TexCoord0,
86 data_type: VertexAttributeDataType::F32,
87 size: 2,
88 divisor: 0,
89 shader_location: 1,
90 normalized: false,
91 },
92 VertexAttributeDescriptor {
93 usage: VertexAttributeUsage::Color,
94 data_type: VertexAttributeDataType::U8,
95 size: 4,
96 divisor: 0,
97 shader_location: 2,
98 normalized: true,
99 },
100 ]
101 }
102}
103
104impl PartialEq for RectangleVertex {
105 fn eq(&self, other: &Self) -> bool {
106 self.position == other.position
107 && self.tex_coord == other.tex_coord
108 && self.color == other.color
109 }
110}
111
112impl Hash for RectangleVertex {
116 fn hash<H: Hasher>(&self, state: &mut H) {
117 #[allow(unsafe_code)]
118 unsafe {
119 let bytes = self as *const Self as *const u8;
120 state.write(std::slice::from_raw_parts(
121 bytes,
122 std::mem::size_of::<Self>(),
123 ))
124 }
125 }
126}
127
128#[derive(Reflect, Debug, Clone, ComponentProvider)]
174#[reflect(derived_type = "Node")]
175pub struct Rectangle {
176 base: Base,
177
178 #[reflect(setter = "set_color")]
179 color: InheritableVariable<Color>,
180
181 #[reflect(setter = "set_uv_rect")]
182 uv_rect: InheritableVariable<Rect<f32>>,
183
184 material: InheritableVariable<MaterialResource>,
185
186 #[reflect(setter = "set_flip_x")]
187 flip_x: InheritableVariable<bool>,
188
189 #[reflect(setter = "set_flip_y")]
190 flip_y: InheritableVariable<bool>,
191}
192
193impl Visit for Rectangle {
194 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
195 let mut region = visitor.enter_region(name)?;
196
197 if region.is_reading() {
198 if let Some(material) =
199 material::visit_old_texture_as_material(&mut region, Material::standard_2d)
200 {
201 self.material = material.into();
202 } else {
203 self.material.visit("Material", &mut region)?;
204 }
205 } else {
206 self.material.visit("Material", &mut region)?;
207 }
208
209 self.base.visit("Base", &mut region)?;
210 self.color.visit("Color", &mut region)?;
211
212 let _ = self.flip_x.visit("FlipX", &mut region);
214 let _ = self.flip_y.visit("FlipY", &mut region);
215 let _ = self.uv_rect.visit("UvRect", &mut region);
216
217 Ok(())
218 }
219}
220
221impl Default for Rectangle {
222 fn default() -> Self {
223 Self {
224 base: Default::default(),
225 color: Default::default(),
226 uv_rect: InheritableVariable::new_modified(Rect::new(0.0, 0.0, 1.0, 1.0)),
227 material: InheritableVariable::new_modified(MaterialResource::new_ok(
228 Uuid::new_v4(),
229 Default::default(),
230 Material::standard_2d(),
231 )),
232 flip_x: Default::default(),
233 flip_y: Default::default(),
234 }
235 }
236}
237
238impl Deref for Rectangle {
239 type Target = Base;
240
241 fn deref(&self) -> &Self::Target {
242 &self.base
243 }
244}
245
246impl DerefMut for Rectangle {
247 fn deref_mut(&mut self) -> &mut Self::Target {
248 &mut self.base
249 }
250}
251
252impl TypeUuidProvider for Rectangle {
253 fn type_uuid() -> Uuid {
254 uuid!("bb57b5e0-367a-4490-bf30-7f547407d5b5")
255 }
256}
257
258impl Rectangle {
259 pub fn color(&self) -> Color {
261 *self.color
262 }
263
264 pub fn material(&self) -> &InheritableVariable<MaterialResource> {
266 &self.material
267 }
268
269 pub fn material_mut(&mut self) -> &mut InheritableVariable<MaterialResource> {
271 &mut self.material
272 }
273
274 pub fn set_color(&mut self, color: Color) -> Color {
276 self.color.set_value_and_mark_modified(color)
277 }
278
279 pub fn uv_rect(&self) -> Rect<f32> {
283 *self.uv_rect
284 }
285
286 pub fn set_uv_rect(&mut self, uv_rect: Rect<f32>) -> Rect<f32> {
295 self.uv_rect.set_value_and_mark_modified(uv_rect)
296 }
297
298 pub fn set_flip_x(&mut self, flip: bool) -> bool {
300 self.flip_x.set_value_and_mark_modified(flip)
301 }
302
303 pub fn is_flip_x(&self) -> bool {
305 *self.flip_x
306 }
307
308 pub fn set_flip_y(&mut self, flip: bool) -> bool {
310 self.flip_y.set_value_and_mark_modified(flip)
311 }
312
313 pub fn is_flip_y(&self) -> bool {
315 *self.flip_y
316 }
317}
318
319impl ConstructorProvider<Node, Graph> for Rectangle {
320 fn constructor() -> NodeConstructor {
321 NodeConstructor::new::<Self>()
322 .with_variant("Rectangle (2D Sprite)", |_| {
323 RectangleBuilder::new(BaseBuilder::new().with_name("Sprite (2D)"))
324 .build_node()
325 .into()
326 })
327 .with_group("2D")
328 }
329}
330
331impl NodeTrait for Rectangle {
332 fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
333 AxisAlignedBoundingBox::unit()
334 }
335
336 fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
337 self.local_bounding_box()
338 .transform(&self.global_transform())
339 }
340
341 fn id(&self) -> Uuid {
342 Self::type_uuid()
343 }
344
345 fn collect_render_data(&self, ctx: &mut RenderContext) -> RdcControlFlow {
346 if !self.should_be_rendered(ctx.frustum, ctx.render_mask) {
347 return RdcControlFlow::Continue;
348 }
349
350 if renderer::is_shadow_pass(ctx.render_pass_name) {
351 return RdcControlFlow::Continue;
352 }
353
354 let global_transform = self.global_transform();
355
356 type Vertex = RectangleVertex;
357
358 let lx = self.uv_rect.position.x;
359 let rx = self.uv_rect.position.x + self.uv_rect.size.x;
360 let ty = self.uv_rect.position.y;
361 let by = self.uv_rect.position.y + self.uv_rect.size.y;
362
363 let vertices = [
364 Vertex {
365 position: global_transform
366 .transform_point(&Point3::new(0.5, 0.5, 0.0))
367 .coords,
368 tex_coord: Vector2::new(
369 if *self.flip_x { rx } else { lx },
370 if *self.flip_y { by } else { ty },
371 ),
372 color: *self.color,
373 },
374 Vertex {
375 position: global_transform
376 .transform_point(&Point3::new(-0.5, 0.5, 0.0))
377 .coords,
378 tex_coord: Vector2::new(
379 if *self.flip_x { lx } else { rx },
380 if *self.flip_y { by } else { ty },
381 ),
382 color: *self.color,
383 },
384 Vertex {
385 position: global_transform
386 .transform_point(&Point3::new(-0.5, -0.5, 0.0))
387 .coords,
388 tex_coord: Vector2::new(
389 if *self.flip_x { lx } else { rx },
390 if *self.flip_y { ty } else { by },
391 ),
392 color: *self.color,
393 },
394 Vertex {
395 position: global_transform
396 .transform_point(&Point3::new(0.5, -0.5, 0.0))
397 .coords,
398 tex_coord: Vector2::new(
399 if *self.flip_x { rx } else { lx },
400 if *self.flip_y { ty } else { by },
401 ),
402 color: *self.color,
403 },
404 ];
405
406 let triangles = [TriangleDefinition([0, 1, 2]), TriangleDefinition([0, 2, 3])];
407
408 let sort_index = ctx.calculate_sorting_index(self.global_position());
409
410 ctx.storage.push_triangles(
411 ctx.dynamic_surface_cache,
412 Vertex::layout(),
413 &self.material,
414 RenderPath::Forward,
415 sort_index,
416 self.handle(),
417 &mut move |mut vertex_buffer, mut triangle_buffer| {
418 let start_vertex_index = vertex_buffer.vertex_count();
419
420 for vertex in vertices.iter() {
421 vertex_buffer
422 .push_vertex_raw(value_as_u8_slice(vertex))
423 .unwrap();
424 }
425
426 triangle_buffer
427 .push_triangles_iter_with_offset(start_vertex_index, triangles.into_iter());
428 },
429 );
430
431 RdcControlFlow::Continue
432 }
433}
434
435pub struct RectangleBuilder {
437 base_builder: BaseBuilder,
438 color: Color,
439 uv_rect: Rect<f32>,
440 material: MaterialResource,
441 flip_x: bool,
442 flip_y: bool,
443}
444
445impl RectangleBuilder {
446 pub fn new(base_builder: BaseBuilder) -> Self {
448 Self {
449 base_builder,
450 color: Color::WHITE,
451 uv_rect: Rect::new(0.0, 0.0, 1.0, 1.0),
452 material: MaterialResource::new_ok(
453 Uuid::new_v4(),
454 Default::default(),
455 Material::standard_2d(),
456 ),
457 flip_x: false,
458 flip_y: false,
459 }
460 }
461
462 pub fn with_color(mut self, color: Color) -> Self {
464 self.color = color;
465 self
466 }
467
468 pub fn with_uv_rect(mut self, uv_rect: Rect<f32>) -> Self {
471 self.uv_rect = uv_rect;
472 self
473 }
474
475 pub fn with_material(mut self, material: MaterialResource) -> Self {
477 self.material = material;
478 self
479 }
480
481 pub fn with_flip_x(mut self, flip_x: bool) -> Self {
483 self.flip_x = flip_x;
484 self
485 }
486
487 pub fn with_flip_y(mut self, flip_y: bool) -> Self {
489 self.flip_y = flip_y;
490 self
491 }
492
493 pub fn build_rectangle(self) -> Rectangle {
495 Rectangle {
496 base: self.base_builder.build_base(),
497 color: self.color.into(),
498 uv_rect: self.uv_rect.into(),
499 material: self.material.into(),
500 flip_x: self.flip_x.into(),
501 flip_y: self.flip_y.into(),
502 }
503 }
504
505 pub fn build_node(self) -> Node {
507 Node::new(self.build_rectangle())
508 }
509
510 pub fn build(self, graph: &mut Graph) -> Handle<Node> {
512 graph.add_node(self.build_node())
513 }
514}