1use crate::scene::node::constructor::NodeConstructor;
26use crate::scene::node::RdcControlFlow;
27use crate::{
28 core::{
29 algebra::{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 variable::InheritableVariable,
37 visitor::{Visit, VisitResult, Visitor},
38 },
39 material,
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::{Node, NodeTrait},
53 },
54};
55use bytemuck::{Pod, Zeroable};
56use fyrox_core::value_as_u8_slice;
57use fyrox_graph::constructor::ConstructorProvider;
58use fyrox_graph::BaseSceneGraph;
59use std::ops::{Deref, DerefMut};
60
61#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
63#[repr(C)] pub struct SpriteVertex {
65 pub position: Vector3<f32>,
67 pub tex_coord: Vector2<f32>,
69 pub params: Vector2<f32>,
71 pub color: Color,
73}
74
75impl VertexTrait for SpriteVertex {
76 fn layout() -> &'static [VertexAttributeDescriptor] {
77 &[
78 VertexAttributeDescriptor {
79 usage: VertexAttributeUsage::Position,
80 data_type: VertexAttributeDataType::F32,
81 size: 3,
82 divisor: 0,
83 shader_location: 0,
84 normalized: false,
85 },
86 VertexAttributeDescriptor {
87 usage: VertexAttributeUsage::TexCoord0,
88 data_type: VertexAttributeDataType::F32,
89 size: 2,
90 divisor: 0,
91 shader_location: 1,
92 normalized: false,
93 },
94 VertexAttributeDescriptor {
95 usage: VertexAttributeUsage::Custom0,
96 data_type: VertexAttributeDataType::F32,
97 size: 2,
98 divisor: 0,
99 shader_location: 2,
100 normalized: false,
101 },
102 VertexAttributeDescriptor {
103 usage: VertexAttributeUsage::Color,
104 data_type: VertexAttributeDataType::U8,
105 size: 4,
106 divisor: 0,
107 shader_location: 3,
108 normalized: true,
109 },
110 ]
111 }
112}
113
114#[derive(Debug, Reflect, Clone, ComponentProvider)]
160pub struct Sprite {
161 base: Base,
162
163 #[reflect(setter = "set_uv_rect")]
164 uv_rect: InheritableVariable<Rect<f32>>,
165
166 material: InheritableVariable<MaterialResource>,
167
168 #[reflect(setter = "set_color")]
169 color: InheritableVariable<Color>,
170
171 #[reflect(min_value = 0.0, step = 0.1)]
172 #[reflect(setter = "set_size")]
173 size: InheritableVariable<f32>,
174
175 #[reflect(setter = "set_rotation")]
176 rotation: InheritableVariable<f32>,
177}
178
179impl Visit for Sprite {
180 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
181 let mut region = visitor.enter_region(name)?;
182
183 if region.is_reading() {
184 if let Some(material) =
185 material::visit_old_texture_as_material(&mut region, Material::standard_sprite)
186 {
187 self.material = material.into();
188 } else {
189 self.material.visit("Material", &mut region)?;
190 }
191 } else {
192 self.material.visit("Material", &mut region)?;
193 }
194
195 self.base.visit("Base", &mut region)?;
196 self.color.visit("Color", &mut region)?;
197 self.size.visit("Size", &mut region)?;
198 self.rotation.visit("Rotation", &mut region)?;
199
200 let _ = self.uv_rect.visit("UvRect", &mut region);
202
203 Ok(())
204 }
205}
206
207impl Deref for Sprite {
208 type Target = Base;
209
210 fn deref(&self) -> &Self::Target {
211 &self.base
212 }
213}
214
215impl DerefMut for Sprite {
216 fn deref_mut(&mut self) -> &mut Self::Target {
217 &mut self.base
218 }
219}
220
221impl Default for Sprite {
222 fn default() -> Self {
223 SpriteBuilder::new(BaseBuilder::new()).build_sprite()
224 }
225}
226
227impl TypeUuidProvider for Sprite {
228 fn type_uuid() -> Uuid {
229 uuid!("60fd7e34-46c1-4ae9-8803-1f5f4c341518")
230 }
231}
232
233impl Sprite {
234 pub fn set_size(&mut self, size: f32) -> f32 {
239 self.size.set_value_and_mark_modified(size)
240 }
241
242 pub fn size(&self) -> f32 {
244 *self.size
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 color(&self) -> Color {
254 *self.color
255 }
256
257 pub fn set_rotation(&mut self, rotation: f32) -> f32 {
259 self.rotation.set_value_and_mark_modified(rotation)
260 }
261
262 pub fn rotation(&self) -> f32 {
264 *self.rotation
265 }
266
267 pub fn material(&self) -> &InheritableVariable<MaterialResource> {
269 &self.material
270 }
271
272 pub fn material_mut(&mut self) -> &mut InheritableVariable<MaterialResource> {
274 &mut self.material
275 }
276
277 pub fn uv_rect(&self) -> Rect<f32> {
281 *self.uv_rect
282 }
283
284 pub fn set_uv_rect(&mut self, uv_rect: Rect<f32>) -> Rect<f32> {
293 self.uv_rect.set_value_and_mark_modified(uv_rect)
294 }
295}
296
297impl ConstructorProvider<Node, Graph> for Sprite {
298 fn constructor() -> NodeConstructor {
299 NodeConstructor::new::<Self>().with_variant("Sprite (3D)", |_| {
300 SpriteBuilder::new(BaseBuilder::new().with_name("Sprite"))
301 .build_node()
302 .into()
303 })
304 }
305}
306
307impl NodeTrait for Sprite {
308 fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
309 AxisAlignedBoundingBox::from_radius(*self.size)
310 }
311
312 fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
313 self.base.world_bounding_box()
314 }
315
316 fn id(&self) -> Uuid {
317 Self::type_uuid()
318 }
319
320 fn collect_render_data(&self, ctx: &mut RenderContext) -> RdcControlFlow {
321 if !self.should_be_rendered(ctx.frustum) {
322 return RdcControlFlow::Continue;
323 }
324
325 if renderer::is_shadow_pass(ctx.render_pass_name) || !self.cast_shadows() {
326 return RdcControlFlow::Continue;
327 }
328
329 let position = self.global_position();
330 let params = Vector2::new(*self.size, *self.rotation);
331
332 type Vertex = SpriteVertex;
333
334 let vertices = [
335 Vertex {
336 position,
337 tex_coord: self.uv_rect.right_top_corner(),
338 params,
339 color: *self.color,
340 },
341 Vertex {
342 position,
343 tex_coord: self.uv_rect.left_top_corner(),
344 params,
345 color: *self.color,
346 },
347 Vertex {
348 position,
349 tex_coord: self.uv_rect.left_bottom_corner(),
350 params,
351 color: *self.color,
352 },
353 Vertex {
354 position,
355 tex_coord: self.uv_rect.right_bottom_corner(),
356 params,
357 color: *self.color,
358 },
359 ];
360
361 let triangles = [TriangleDefinition([0, 1, 2]), TriangleDefinition([2, 3, 0])];
362
363 let sort_index = ctx.calculate_sorting_index(self.global_position());
364
365 ctx.storage.push_triangles(
366 Vertex::layout(),
367 &self.material,
368 RenderPath::Forward,
369 sort_index,
370 self.handle(),
371 &mut move |mut vertex_buffer, mut triangle_buffer| {
372 let start_vertex_index = vertex_buffer.vertex_count();
373
374 for vertex in vertices.iter() {
375 vertex_buffer
376 .push_vertex_raw(value_as_u8_slice(vertex))
377 .unwrap();
378 }
379
380 triangle_buffer
381 .push_triangles_iter_with_offset(start_vertex_index, triangles.into_iter());
382 },
383 );
384
385 RdcControlFlow::Continue
386 }
387}
388
389pub struct SpriteBuilder {
392 base_builder: BaseBuilder,
393 uv_rect: Rect<f32>,
394 material: MaterialResource,
395 color: Color,
396 size: f32,
397 rotation: f32,
398}
399
400impl SpriteBuilder {
401 pub fn new(base_builder: BaseBuilder) -> Self {
403 Self {
404 base_builder,
405 material: MaterialResource::new_ok(Default::default(), Material::standard_sprite()),
406 uv_rect: Rect::new(0.0, 0.0, 1.0, 1.0),
407 color: Color::WHITE,
408 size: 0.2,
409 rotation: 0.0,
410 }
411 }
412
413 pub fn with_uv_rect(mut self, uv_rect: Rect<f32>) -> Self {
416 self.uv_rect = uv_rect;
417 self
418 }
419
420 pub fn with_material(mut self, material: MaterialResource) -> Self {
422 self.material = material;
423 self
424 }
425
426 pub fn with_color(mut self, color: Color) -> Self {
428 self.color = color;
429 self
430 }
431
432 pub fn with_size(mut self, size: f32) -> Self {
434 self.size = size;
435 self
436 }
437
438 pub fn with_rotation(mut self, rotation: f32) -> Self {
440 self.rotation = rotation;
441 self
442 }
443
444 fn build_sprite(self) -> Sprite {
445 Sprite {
446 base: self.base_builder.build_base(),
447 material: self.material.into(),
448 uv_rect: self.uv_rect.into(),
449 color: self.color.into(),
450 size: self.size.into(),
451 rotation: self.rotation.into(),
452 }
453 }
454
455 pub fn build_node(self) -> Node {
457 Node::new(self.build_sprite())
458 }
459
460 pub fn build(self, graph: &mut Graph) -> Handle<Node> {
462 graph.add_node(self.build_node())
463 }
464}