1use crate::{
26 core::{
27 algebra::{Vector2, Vector3, Vector4},
28 color::Color,
29 math::{aabb::AxisAlignedBoundingBox, Rect, TriangleDefinition},
30 pool::Handle,
31 reflect::prelude::*,
32 type_traits::prelude::*,
33 uuid::{uuid, Uuid},
34 value_as_u8_slice,
35 variable::InheritableVariable,
36 visitor::{Visit, VisitResult, Visitor},
37 },
38 graph::{constructor::ConstructorProvider, BaseSceneGraph},
39 material::{self, Material, MaterialResource},
40 renderer::{self, bundle::RenderContext},
41 scene::{
42 base::{Base, BaseBuilder},
43 graph::Graph,
44 mesh::{
45 buffer::{
46 VertexAttributeDataType, VertexAttributeDescriptor, VertexAttributeUsage,
47 VertexTrait,
48 },
49 RenderPath,
50 },
51 node::{constructor::NodeConstructor, Node, NodeTrait, RdcControlFlow},
52 },
53};
54use bytemuck::{Pod, Zeroable};
55use std::ops::{Deref, DerefMut};
56
57#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
59#[repr(C)] pub struct SpriteVertex {
61 pub position: Vector3<f32>,
63 pub tex_coord: Vector2<f32>,
65 pub params: Vector4<f32>,
67 pub color: Color,
69}
70
71impl VertexTrait for SpriteVertex {
72 fn layout() -> &'static [VertexAttributeDescriptor] {
73 &[
74 VertexAttributeDescriptor {
75 usage: VertexAttributeUsage::Position,
76 data_type: VertexAttributeDataType::F32,
77 size: 3,
78 divisor: 0,
79 shader_location: 0,
80 normalized: false,
81 },
82 VertexAttributeDescriptor {
83 usage: VertexAttributeUsage::TexCoord0,
84 data_type: VertexAttributeDataType::F32,
85 size: 2,
86 divisor: 0,
87 shader_location: 1,
88 normalized: false,
89 },
90 VertexAttributeDescriptor {
91 usage: VertexAttributeUsage::Custom0,
92 data_type: VertexAttributeDataType::F32,
93 size: 4,
94 divisor: 0,
95 shader_location: 2,
96 normalized: false,
97 },
98 VertexAttributeDescriptor {
99 usage: VertexAttributeUsage::Color,
100 data_type: VertexAttributeDataType::U8,
101 size: 4,
102 divisor: 0,
103 shader_location: 3,
104 normalized: true,
105 },
106 ]
107 }
108}
109
110#[derive(Debug, Reflect, Clone, ComponentProvider)]
156#[reflect(derived_type = "Node")]
157pub struct Sprite {
158 base: Base,
159
160 #[reflect(setter = "set_uv_rect")]
161 uv_rect: InheritableVariable<Rect<f32>>,
162
163 material: InheritableVariable<MaterialResource>,
164
165 #[reflect(setter = "set_color")]
166 color: InheritableVariable<Color>,
167
168 #[reflect(min_value = 0.0, step = 0.1)]
169 #[reflect(setter = "set_size")]
170 size: InheritableVariable<f32>,
171
172 #[reflect(setter = "set_rotation")]
173 rotation: InheritableVariable<f32>,
174
175 #[reflect(setter = "set_flip_x")]
176 flip_x: InheritableVariable<bool>,
177
178 #[reflect(setter = "set_flip_y")]
179 flip_y: InheritableVariable<bool>,
180}
181
182impl Visit for Sprite {
183 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
184 let mut region = visitor.enter_region(name)?;
185
186 if region.is_reading() {
187 if let Some(material) =
188 material::visit_old_texture_as_material(&mut region, Material::standard_sprite)
189 {
190 self.material = material.into();
191 } else {
192 self.material.visit("Material", &mut region)?;
193 }
194 } else {
195 self.material.visit("Material", &mut region)?;
196 }
197
198 self.base.visit("Base", &mut region)?;
199 self.color.visit("Color", &mut region)?;
200 self.size.visit("Size", &mut region)?;
201 self.rotation.visit("Rotation", &mut region)?;
202
203 let _ = self.flip_x.visit("FlipX", &mut region);
205 let _ = self.flip_y.visit("FlipY", &mut region);
206 let _ = self.uv_rect.visit("UvRect", &mut region);
207
208 Ok(())
209 }
210}
211
212impl Deref for Sprite {
213 type Target = Base;
214
215 fn deref(&self) -> &Self::Target {
216 &self.base
217 }
218}
219
220impl DerefMut for Sprite {
221 fn deref_mut(&mut self) -> &mut Self::Target {
222 &mut self.base
223 }
224}
225
226impl Default for Sprite {
227 fn default() -> Self {
228 SpriteBuilder::new(BaseBuilder::new()).build_sprite()
229 }
230}
231
232impl TypeUuidProvider for Sprite {
233 fn type_uuid() -> Uuid {
234 uuid!("60fd7e34-46c1-4ae9-8803-1f5f4c341518")
235 }
236}
237
238impl Sprite {
239 pub fn set_size(&mut self, size: f32) -> f32 {
244 self.size.set_value_and_mark_modified(size)
245 }
246
247 pub fn size(&self) -> f32 {
249 *self.size
250 }
251
252 pub fn set_color(&mut self, color: Color) -> Color {
254 self.color.set_value_and_mark_modified(color)
255 }
256
257 pub fn color(&self) -> Color {
259 *self.color
260 }
261
262 pub fn set_rotation(&mut self, rotation: f32) -> f32 {
264 self.rotation.set_value_and_mark_modified(rotation)
265 }
266
267 pub fn rotation(&self) -> f32 {
269 *self.rotation
270 }
271
272 pub fn material(&self) -> &InheritableVariable<MaterialResource> {
274 &self.material
275 }
276
277 pub fn material_mut(&mut self) -> &mut InheritableVariable<MaterialResource> {
279 &mut self.material
280 }
281
282 pub fn uv_rect(&self) -> Rect<f32> {
286 *self.uv_rect
287 }
288
289 pub fn set_uv_rect(&mut self, uv_rect: Rect<f32>) -> Rect<f32> {
298 self.uv_rect.set_value_and_mark_modified(uv_rect)
299 }
300
301 pub fn set_flip_x(&mut self, flip: bool) -> bool {
303 self.flip_x.set_value_and_mark_modified(flip)
304 }
305
306 pub fn is_flip_x(&self) -> bool {
308 *self.flip_x
309 }
310
311 pub fn set_flip_y(&mut self, flip: bool) -> bool {
313 self.flip_y.set_value_and_mark_modified(flip)
314 }
315
316 pub fn is_flip_y(&self) -> bool {
318 *self.flip_y
319 }
320}
321
322impl ConstructorProvider<Node, Graph> for Sprite {
323 fn constructor() -> NodeConstructor {
324 NodeConstructor::new::<Self>().with_variant("Sprite (3D)", |_| {
325 SpriteBuilder::new(BaseBuilder::new().with_name("Sprite"))
326 .build_node()
327 .into()
328 })
329 }
330}
331
332impl NodeTrait for Sprite {
333 fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
334 AxisAlignedBoundingBox::from_radius(*self.size)
335 }
336
337 fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
338 self.base.world_bounding_box()
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) || !self.cast_shadows() {
351 return RdcControlFlow::Continue;
352 }
353
354 let position = self.global_position();
355
356 type Vertex = SpriteVertex;
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,
366 tex_coord: Vector2::new(
367 if *self.flip_x { lx } else { rx },
368 if *self.flip_y { by } else { ty },
369 ),
370 params: Vector4::new(*self.size, *self.rotation, 0.5, 0.5),
371 color: *self.color,
372 },
373 Vertex {
374 position,
375 tex_coord: Vector2::new(
376 if *self.flip_x { rx } else { lx },
377 if *self.flip_y { by } else { ty },
378 ),
379 params: Vector4::new(*self.size, *self.rotation, -0.5, 0.5),
380 color: *self.color,
381 },
382 Vertex {
383 position,
384 tex_coord: Vector2::new(
385 if *self.flip_x { rx } else { lx },
386 if *self.flip_y { ty } else { by },
387 ),
388 params: Vector4::new(*self.size, *self.rotation, -0.5, -0.5),
389 color: *self.color,
390 },
391 Vertex {
392 position,
393 tex_coord: Vector2::new(
394 if *self.flip_x { lx } else { rx },
395 if *self.flip_y { ty } else { by },
396 ),
397 params: Vector4::new(*self.size, *self.rotation, 0.5, -0.5),
398 color: *self.color,
399 },
400 ];
401
402 let triangles = [TriangleDefinition([0, 1, 2]), TriangleDefinition([0, 2, 3])];
403
404 let sort_index = ctx.calculate_sorting_index(self.global_position());
405
406 ctx.storage.push_triangles(
407 ctx.dynamic_surface_cache,
408 Vertex::layout(),
409 &self.material,
410 RenderPath::Forward,
411 sort_index,
412 self.handle(),
413 &mut move |mut vertex_buffer, mut triangle_buffer| {
414 let start_vertex_index = vertex_buffer.vertex_count();
415
416 for vertex in vertices.iter() {
417 vertex_buffer
418 .push_vertex_raw(value_as_u8_slice(vertex))
419 .unwrap();
420 }
421
422 triangle_buffer
423 .push_triangles_iter_with_offset(start_vertex_index, triangles.into_iter());
424 },
425 );
426
427 RdcControlFlow::Continue
428 }
429}
430
431pub struct SpriteBuilder {
434 base_builder: BaseBuilder,
435 uv_rect: Rect<f32>,
436 material: MaterialResource,
437 color: Color,
438 size: f32,
439 rotation: f32,
440 flip_x: bool,
441 flip_y: bool,
442}
443
444impl SpriteBuilder {
445 pub fn new(base_builder: BaseBuilder) -> Self {
447 Self {
448 base_builder,
449 material: MaterialResource::new_ok(
450 Uuid::new_v4(),
451 Default::default(),
452 Material::standard_sprite(),
453 ),
454 uv_rect: Rect::new(0.0, 0.0, 1.0, 1.0),
455 color: Color::WHITE,
456 size: 0.2,
457 rotation: 0.0,
458 flip_x: false,
459 flip_y: false,
460 }
461 }
462
463 pub fn with_uv_rect(mut self, uv_rect: Rect<f32>) -> Self {
466 self.uv_rect = uv_rect;
467 self
468 }
469
470 pub fn with_material(mut self, material: MaterialResource) -> Self {
472 self.material = material;
473 self
474 }
475
476 pub fn with_color(mut self, color: Color) -> Self {
478 self.color = color;
479 self
480 }
481
482 pub fn with_size(mut self, size: f32) -> Self {
484 self.size = size;
485 self
486 }
487
488 pub fn with_rotation(mut self, rotation: f32) -> Self {
490 self.rotation = rotation;
491 self
492 }
493
494 pub fn with_flip_x(mut self, flip_x: bool) -> Self {
496 self.flip_x = flip_x;
497 self
498 }
499
500 pub fn with_flip_y(mut self, flip_y: bool) -> Self {
502 self.flip_y = flip_y;
503 self
504 }
505
506 fn build_sprite(self) -> Sprite {
507 Sprite {
508 base: self.base_builder.build_base(),
509 material: self.material.into(),
510 uv_rect: self.uv_rect.into(),
511 color: self.color.into(),
512 size: self.size.into(),
513 rotation: self.rotation.into(),
514 flip_x: self.flip_x.into(),
515 flip_y: self.flip_y.into(),
516 }
517 }
518
519 pub fn build_node(self) -> Node {
521 Node::new(self.build_sprite())
522 }
523
524 pub fn build(self, graph: &mut Graph) -> Handle<Node> {
526 graph.add_node(self.build_node())
527 }
528}