1use crate::scene::animation::spritesheet::SpriteSheetAnimation;
26use crate::{
27 core::{
28 algebra::{Vector2, Vector3, Vector4},
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::{Visit, VisitResult, Visitor},
38 },
39 graph::{constructor::ConstructorProvider, SceneGraph},
40 material::{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::ops::{Deref, DerefMut};
57
58#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
60#[repr(C)] pub struct SpriteVertex {
62 pub position: Vector3<f32>,
64 pub tex_coord: Vector2<f32>,
66 pub params: Vector4<f32>,
68 pub color: Color,
70}
71
72impl VertexTrait for SpriteVertex {
73 fn layout() -> &'static [VertexAttributeDescriptor] {
74 &[
75 VertexAttributeDescriptor {
76 usage: VertexAttributeUsage::Position,
77 data_type: VertexAttributeDataType::F32,
78 size: 3,
79 divisor: 0,
80 shader_location: 0,
81 normalized: false,
82 },
83 VertexAttributeDescriptor {
84 usage: VertexAttributeUsage::TexCoord0,
85 data_type: VertexAttributeDataType::F32,
86 size: 2,
87 divisor: 0,
88 shader_location: 1,
89 normalized: false,
90 },
91 VertexAttributeDescriptor {
92 usage: VertexAttributeUsage::Custom0,
93 data_type: VertexAttributeDataType::F32,
94 size: 4,
95 divisor: 0,
96 shader_location: 2,
97 normalized: false,
98 },
99 VertexAttributeDescriptor {
100 usage: VertexAttributeUsage::Color,
101 data_type: VertexAttributeDataType::U8,
102 size: 4,
103 divisor: 0,
104 shader_location: 3,
105 normalized: true,
106 },
107 ]
108 }
109}
110
111#[derive(Debug, Reflect, Clone, ComponentProvider, Visit)]
158#[reflect(derived_type = "Node")]
159pub struct Sprite {
160 base: Base,
161
162 #[reflect(setter = "set_uv_rect")]
163 uv_rect: InheritableVariable<Rect<f32>>,
164
165 material: InheritableVariable<MaterialResource>,
166
167 #[reflect(setter = "set_color")]
168 color: InheritableVariable<Color>,
169
170 #[reflect(min_value = 0.0, step = 0.1)]
171 #[reflect(setter = "set_size")]
172 size: InheritableVariable<f32>,
173
174 #[reflect(setter = "set_rotation")]
175 rotation: InheritableVariable<f32>,
176
177 #[reflect(setter = "set_flip_x")]
178 flip_x: InheritableVariable<bool>,
179
180 #[reflect(setter = "set_flip_y")]
181 flip_y: InheritableVariable<bool>,
182}
183
184impl Deref for Sprite {
185 type Target = Base;
186
187 fn deref(&self) -> &Self::Target {
188 &self.base
189 }
190}
191
192impl DerefMut for Sprite {
193 fn deref_mut(&mut self) -> &mut Self::Target {
194 &mut self.base
195 }
196}
197
198impl Default for Sprite {
199 fn default() -> Self {
200 SpriteBuilder::new(BaseBuilder::new()).build_sprite()
201 }
202}
203
204impl TypeUuidProvider for Sprite {
205 fn type_uuid() -> Uuid {
206 uuid!("60fd7e34-46c1-4ae9-8803-1f5f4c341518")
207 }
208}
209
210impl Sprite {
211 pub fn set_size(&mut self, size: f32) -> f32 {
216 self.size.set_value_and_mark_modified(size)
217 }
218
219 pub fn size(&self) -> f32 {
221 *self.size
222 }
223
224 pub fn set_color(&mut self, color: Color) -> Color {
226 self.color.set_value_and_mark_modified(color)
227 }
228
229 pub fn color(&self) -> Color {
231 *self.color
232 }
233
234 pub fn set_rotation(&mut self, rotation: f32) -> f32 {
236 self.rotation.set_value_and_mark_modified(rotation)
237 }
238
239 pub fn rotation(&self) -> f32 {
241 *self.rotation
242 }
243
244 pub fn material(&self) -> &InheritableVariable<MaterialResource> {
246 &self.material
247 }
248
249 pub fn material_mut(&mut self) -> &mut InheritableVariable<MaterialResource> {
251 &mut self.material
252 }
253
254 pub fn uv_rect(&self) -> Rect<f32> {
258 *self.uv_rect
259 }
260
261 pub fn set_uv_rect(&mut self, uv_rect: Rect<f32>) -> Rect<f32> {
270 self.uv_rect.set_value_and_mark_modified(uv_rect)
271 }
272
273 pub fn set_flip_x(&mut self, flip: bool) -> bool {
275 self.flip_x.set_value_and_mark_modified(flip)
276 }
277
278 pub fn is_flip_x(&self) -> bool {
280 *self.flip_x
281 }
282
283 pub fn set_flip_y(&mut self, flip: bool) -> bool {
285 self.flip_y.set_value_and_mark_modified(flip)
286 }
287
288 pub fn is_flip_y(&self) -> bool {
290 *self.flip_y
291 }
292
293 pub fn apply_animation(&mut self, animation: &SpriteSheetAnimation) {
296 self.material()
297 .data_ref()
298 .bind("diffuseTexture", animation.texture());
299 self.set_uv_rect(animation.current_frame_uv_rect().unwrap_or_default());
300 }
301}
302
303impl ConstructorProvider<Node, Graph> for Sprite {
304 fn constructor() -> NodeConstructor {
305 NodeConstructor::new::<Self>().with_variant("Sprite (3D)", |_| {
306 SpriteBuilder::new(BaseBuilder::new().with_name("Sprite"))
307 .build_node()
308 .into()
309 })
310 }
311}
312
313impl NodeTrait for Sprite {
314 fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
315 AxisAlignedBoundingBox::from_radius(*self.size)
316 }
317
318 fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
319 self.base.world_bounding_box()
320 }
321
322 fn id(&self) -> Uuid {
323 Self::type_uuid()
324 }
325
326 fn collect_render_data(&self, ctx: &mut RenderContext) -> RdcControlFlow {
327 if !self.should_be_rendered(ctx.frustum, ctx.render_mask) {
328 return RdcControlFlow::Continue;
329 }
330
331 if renderer::is_shadow_pass(ctx.render_pass_name) || !self.cast_shadows() {
332 return RdcControlFlow::Continue;
333 }
334
335 let position = self.global_position();
336
337 type Vertex = SpriteVertex;
338
339 let lx = self.uv_rect.position.x;
340 let rx = self.uv_rect.position.x + self.uv_rect.size.x;
341 let ty = self.uv_rect.position.y;
342 let by = self.uv_rect.position.y + self.uv_rect.size.y;
343
344 let vertices = [
345 Vertex {
346 position,
347 tex_coord: Vector2::new(
348 if *self.flip_x { lx } else { rx },
349 if *self.flip_y { by } else { ty },
350 ),
351 params: Vector4::new(*self.size, *self.rotation, 0.5, 0.5),
352 color: *self.color,
353 },
354 Vertex {
355 position,
356 tex_coord: Vector2::new(
357 if *self.flip_x { rx } else { lx },
358 if *self.flip_y { by } else { ty },
359 ),
360 params: Vector4::new(*self.size, *self.rotation, -0.5, 0.5),
361 color: *self.color,
362 },
363 Vertex {
364 position,
365 tex_coord: Vector2::new(
366 if *self.flip_x { rx } else { lx },
367 if *self.flip_y { ty } else { by },
368 ),
369 params: Vector4::new(*self.size, *self.rotation, -0.5, -0.5),
370 color: *self.color,
371 },
372 Vertex {
373 position,
374 tex_coord: Vector2::new(
375 if *self.flip_x { lx } else { rx },
376 if *self.flip_y { ty } else { by },
377 ),
378 params: Vector4::new(*self.size, *self.rotation, 0.5, -0.5),
379 color: *self.color,
380 },
381 ];
382
383 let triangles = [TriangleDefinition([0, 1, 2]), TriangleDefinition([0, 2, 3])];
384
385 let sort_index = ctx.calculate_sorting_index(self.global_position());
386
387 ctx.storage.push_triangles(
388 ctx.dynamic_surface_cache,
389 Vertex::layout(),
390 &self.material,
391 RenderPath::Forward,
392 sort_index,
393 self.handle(),
394 &mut move |mut vertex_buffer, mut triangle_buffer| {
395 let start_vertex_index = vertex_buffer.vertex_count();
396
397 for vertex in vertices.iter() {
398 vertex_buffer
399 .push_vertex_raw(value_as_u8_slice(vertex))
400 .unwrap();
401 }
402
403 triangle_buffer
404 .push_triangles_iter_with_offset(start_vertex_index, triangles.into_iter());
405 },
406 );
407
408 RdcControlFlow::Continue
409 }
410}
411
412pub struct SpriteBuilder {
415 base_builder: BaseBuilder,
416 uv_rect: Rect<f32>,
417 material: MaterialResource,
418 color: Color,
419 size: f32,
420 rotation: f32,
421 flip_x: bool,
422 flip_y: bool,
423}
424
425impl SpriteBuilder {
426 pub fn new(base_builder: BaseBuilder) -> Self {
428 Self {
429 base_builder,
430 material: MaterialResource::new_ok(
431 Uuid::new_v4(),
432 Default::default(),
433 Material::standard_sprite(),
434 ),
435 uv_rect: Rect::new(0.0, 0.0, 1.0, 1.0),
436 color: Color::WHITE,
437 size: 0.2,
438 rotation: 0.0,
439 flip_x: false,
440 flip_y: false,
441 }
442 }
443
444 pub fn with_uv_rect(mut self, uv_rect: Rect<f32>) -> Self {
447 self.uv_rect = uv_rect;
448 self
449 }
450
451 pub fn with_material(mut self, material: MaterialResource) -> Self {
453 self.material = material;
454 self
455 }
456
457 pub fn with_color(mut self, color: Color) -> Self {
459 self.color = color;
460 self
461 }
462
463 pub fn with_size(mut self, size: f32) -> Self {
465 self.size = size;
466 self
467 }
468
469 pub fn with_rotation(mut self, rotation: f32) -> Self {
471 self.rotation = rotation;
472 self
473 }
474
475 pub fn with_flip_x(mut self, flip_x: bool) -> Self {
477 self.flip_x = flip_x;
478 self
479 }
480
481 pub fn with_flip_y(mut self, flip_y: bool) -> Self {
483 self.flip_y = flip_y;
484 self
485 }
486
487 fn build_sprite(self) -> Sprite {
488 Sprite {
489 base: self.base_builder.build_base(),
490 material: self.material.into(),
491 uv_rect: self.uv_rect.into(),
492 color: self.color.into(),
493 size: self.size.into(),
494 rotation: self.rotation.into(),
495 flip_x: self.flip_x.into(),
496 flip_y: self.flip_y.into(),
497 }
498 }
499
500 pub fn build_node(self) -> Node {
502 Node::new(self.build_sprite())
503 }
504
505 pub fn build(self, graph: &mut Graph) -> Handle<Sprite> {
507 graph.add_node(self.build_node()).to_variant()
508 }
509}