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