1#![warn(missing_docs)]
6
7use crate::shader::{ShaderResource, ShaderResourceExtension};
8use fxhash::FxHashMap;
9use fyrox_core::{
10 algebra::{Matrix2, Matrix3, Matrix4, Vector2, Vector3, Vector4},
11 color::Color,
12 io::FileError,
13 parking_lot::Mutex,
14 reflect::prelude::*,
15 sstorage::ImmutableString,
16 uuid::{uuid, Uuid},
17 visitor::{prelude::*, RegionGuard},
18 SafeLock, TypeUuidProvider,
19};
20use fyrox_graphics::gpu_program::SamplerFallback;
21use fyrox_resource::{
22 io::ResourceIo,
23 manager::{BuiltInResource, ResourceManager},
24 state::ResourceState,
25 untyped::ResourceKind,
26 Resource, ResourceData,
27};
28use fyrox_texture::TextureResource;
29use lazy_static::lazy_static;
30use std::{
31 any::Any,
32 error::Error,
33 fmt::{Display, Formatter},
34 path::Path,
35 sync::Arc,
36};
37use strum_macros::{AsRefStr, EnumString, VariantNames};
38
39pub mod loader;
40pub mod shader;
41
42#[derive(Default, Debug, Visit, Clone, Reflect, TypeUuidProvider)]
44#[type_uuid(id = "e1642a47-d372-4840-a8eb-f16350f436f8")]
45pub struct MaterialTextureBinding {
46 pub value: Option<TextureResource>,
49}
50
51#[derive(Debug, Visit, Clone, Reflect, TypeUuidProvider, AsRefStr, EnumString, VariantNames)]
58#[type_uuid(id = "2df8f1e5-0075-4d0d-9860-70fc27d3e165")]
59pub enum MaterialResourceBinding {
60 Texture(MaterialTextureBinding),
62 PropertyGroup(MaterialPropertyGroup),
64}
65
66impl Default for MaterialResourceBinding {
67 fn default() -> Self {
68 Self::PropertyGroup(Default::default())
69 }
70}
71
72impl MaterialResourceBinding {
73 pub fn as_texture(&self) -> Option<TextureResource> {
75 if let Self::Texture(binding) = self {
76 binding.value.clone()
77 } else {
78 None
79 }
80 }
81}
82
83#[derive(Default, Debug, Visit, Clone, Reflect)]
86pub struct MaterialPropertyGroup {
87 properties: FxHashMap<ImmutableString, MaterialProperty>,
88}
89
90impl MaterialPropertyGroup {
91 pub fn property_ref(&self, name: impl Into<ImmutableString>) -> Option<&MaterialProperty> {
107 let name = name.into();
108 self.properties.get(&name)
109 }
110
111 pub fn property_mut(
128 &mut self,
129 name: impl Into<ImmutableString>,
130 ) -> Option<&mut MaterialProperty> {
131 let name = name.into();
132 self.properties.get_mut(&name)
133 }
134
135 pub fn set_property(
153 &mut self,
154 name: impl Into<ImmutableString>,
155 new_value: impl Into<MaterialProperty>,
156 ) {
157 self.properties.insert(name.into(), new_value.into());
158 }
159
160 pub fn unset_property(&mut self, name: impl Into<ImmutableString>) -> Option<MaterialProperty> {
162 self.properties.remove(&name.into())
163 }
164
165 pub fn properties(&self) -> &FxHashMap<ImmutableString, MaterialProperty> {
167 &self.properties
168 }
169}
170
171#[derive(Debug, Visit, Clone, Reflect, AsRefStr, EnumString, VariantNames, TypeUuidProvider)]
173#[type_uuid(id = "1c25018d-ab6e-4dca-99a6-e3d9639bc33c")]
174pub enum MaterialProperty {
175 Float(f32),
177
178 FloatArray(Vec<f32>),
180
181 Int(i32),
183
184 IntArray(Vec<i32>),
186
187 UInt(u32),
189
190 UIntArray(Vec<u32>),
192
193 Vector2(Vector2<f32>),
195
196 Vector2Array(Vec<Vector2<f32>>),
198
199 Vector3(Vector3<f32>),
201
202 Vector3Array(Vec<Vector3<f32>>),
204
205 Vector4(Vector4<f32>),
207
208 Vector4Array(Vec<Vector4<f32>>),
210
211 Matrix2(Matrix2<f32>),
213
214 Matrix2Array(Vec<Matrix2<f32>>),
216
217 Matrix3(Matrix3<f32>),
219
220 Matrix3Array(Vec<Matrix3<f32>>),
222
223 Matrix4(Matrix4<f32>),
225
226 Matrix4Array(Vec<Matrix4<f32>>),
228
229 Bool(bool),
231
232 Color(Color),
234}
235
236macro_rules! impl_from {
237 ($variant:ident => $value_type:ty) => {
238 impl From<$value_type> for MaterialProperty {
239 fn from(value: $value_type) -> Self {
240 Self::$variant(value)
241 }
242 }
243 };
244}
245
246impl_from!(Float => f32);
247impl_from!(FloatArray => Vec<f32>);
248impl_from!(Int => i32);
249impl_from!(IntArray => Vec<i32>);
250impl_from!(UInt => u32);
251impl_from!(UIntArray => Vec<u32>);
252impl_from!(Vector2 => Vector2<f32>);
253impl_from!(Vector2Array => Vec<Vector2<f32>>);
254impl_from!(Vector3 => Vector3<f32>);
255impl_from!(Vector3Array => Vec<Vector3<f32>>);
256impl_from!(Vector4 => Vector4<f32>);
257impl_from!(Vector4Array => Vec<Vector4<f32>>);
258impl_from!(Matrix2 => Matrix2<f32>);
259impl_from!(Matrix2Array => Vec<Matrix2<f32>>);
260impl_from!(Matrix3 => Matrix3<f32>);
261impl_from!(Matrix3Array => Vec<Matrix3<f32>>);
262impl_from!(Matrix4 => Matrix4<f32>);
263impl_from!(Matrix4Array => Vec<Matrix4<f32>>);
264impl_from!(Bool => bool);
265impl_from!(Color => Color);
266
267#[derive(Debug, Copy, Clone)]
269pub enum MaterialPropertyRef<'a> {
270 Float(&'a f32),
272
273 FloatArray(&'a [f32]),
275
276 Int(&'a i32),
278
279 IntArray(&'a [i32]),
281
282 UInt(&'a u32),
284
285 UIntArray(&'a [u32]),
287
288 Vector2(&'a Vector2<f32>),
290
291 Vector2Array(&'a [Vector2<f32>]),
293
294 Vector3(&'a Vector3<f32>),
296
297 Vector3Array(&'a [Vector3<f32>]),
299
300 Vector4(&'a Vector4<f32>),
302
303 Vector4Array(&'a [Vector4<f32>]),
305
306 Matrix2(&'a Matrix2<f32>),
308
309 Matrix2Array(&'a [Matrix2<f32>]),
311
312 Matrix3(&'a Matrix3<f32>),
314
315 Matrix3Array(&'a [Matrix3<f32>]),
317
318 Matrix4(&'a Matrix4<f32>),
320
321 Matrix4Array(&'a [Matrix4<f32>]),
323
324 Bool(&'a bool),
326
327 Color(&'a Color),
329}
330
331impl MaterialProperty {
332 pub fn as_ref(&self) -> MaterialPropertyRef<'_> {
334 match self {
335 MaterialProperty::Float(v) => MaterialPropertyRef::Float(v),
336 MaterialProperty::FloatArray(v) => MaterialPropertyRef::FloatArray(v),
337 MaterialProperty::Int(v) => MaterialPropertyRef::Int(v),
338 MaterialProperty::IntArray(v) => MaterialPropertyRef::IntArray(v),
339 MaterialProperty::UInt(v) => MaterialPropertyRef::UInt(v),
340 MaterialProperty::UIntArray(v) => MaterialPropertyRef::UIntArray(v),
341 MaterialProperty::Vector2(v) => MaterialPropertyRef::Vector2(v),
342 MaterialProperty::Vector2Array(v) => MaterialPropertyRef::Vector2Array(v),
343 MaterialProperty::Vector3(v) => MaterialPropertyRef::Vector3(v),
344 MaterialProperty::Vector3Array(v) => MaterialPropertyRef::Vector3Array(v),
345 MaterialProperty::Vector4(v) => MaterialPropertyRef::Vector4(v),
346 MaterialProperty::Vector4Array(v) => MaterialPropertyRef::Vector4Array(v),
347 MaterialProperty::Matrix2(v) => MaterialPropertyRef::Matrix2(v),
348 MaterialProperty::Matrix2Array(v) => MaterialPropertyRef::Matrix2Array(v),
349 MaterialProperty::Matrix3(v) => MaterialPropertyRef::Matrix3(v),
350 MaterialProperty::Matrix3Array(v) => MaterialPropertyRef::Matrix3Array(v),
351 MaterialProperty::Matrix4(v) => MaterialPropertyRef::Matrix4(v),
352 MaterialProperty::Matrix4Array(v) => MaterialPropertyRef::Matrix4Array(v),
353 MaterialProperty::Bool(v) => MaterialPropertyRef::Bool(v),
354 MaterialProperty::Color(v) => MaterialPropertyRef::Color(v),
355 }
356 }
357}
358
359macro_rules! impl_from_ref {
360 ($variant:ident => $value_type:ty) => {
361 impl<'a> From<&'a $value_type> for MaterialPropertyRef<'a> {
362 fn from(value: &'a $value_type) -> Self {
363 Self::$variant(value)
364 }
365 }
366 };
367}
368
369impl_from_ref!(Float => f32);
370impl_from_ref!(FloatArray => [f32]);
371impl_from_ref!(Int => i32);
372impl_from_ref!(IntArray => [i32]);
373impl_from_ref!(UInt => u32);
374impl_from_ref!(UIntArray => [u32]);
375impl_from_ref!(Vector2 => Vector2<f32>);
376impl_from_ref!(Vector2Array => [Vector2<f32>]);
377impl_from_ref!(Vector3 => Vector3<f32>);
378impl_from_ref!(Vector3Array => [Vector3<f32>]);
379impl_from_ref!(Vector4 => Vector4<f32>);
380impl_from_ref!(Vector4Array => [Vector4<f32>]);
381impl_from_ref!(Matrix2 => Matrix2<f32>);
382impl_from_ref!(Matrix2Array => [Matrix2<f32>]);
383impl_from_ref!(Matrix3 => Matrix3<f32>);
384impl_from_ref!(Matrix3Array => [Matrix3<f32>]);
385impl_from_ref!(Matrix4 => Matrix4<f32>);
386impl_from_ref!(Matrix4Array => [Matrix4<f32>]);
387impl_from_ref!(Bool => bool);
388impl_from_ref!(Color => Color);
389
390impl From<Option<TextureResource>> for MaterialResourceBinding {
391 fn from(value: Option<TextureResource>) -> Self {
392 Self::Texture(MaterialTextureBinding { value })
393 }
394}
395
396impl From<TextureResource> for MaterialResourceBinding {
397 fn from(value: TextureResource) -> Self {
398 Self::Texture(MaterialTextureBinding { value: Some(value) })
399 }
400}
401
402macro_rules! define_as {
403 ($(#[$meta:meta])* $name:ident = $variant:ident -> $ty:ty) => {
404 $(#[$meta])*
405 pub fn $name(&self) -> Option<$ty> {
406 if let MaterialProperty::$variant(v) = self {
407 Some(*v)
408 } else {
409 None
410 }
411 }
412 };
413}
414
415macro_rules! define_as_ref {
416 ($(#[$meta:meta])* $name:ident = $variant:ident -> $ty:ty) => {
417 $(#[$meta])*
418 pub fn $name(&self) -> Option<&$ty> {
419 if let MaterialProperty::$variant(v) = self {
420 Some(v)
421 } else {
422 None
423 }
424 }
425 };
426}
427
428impl MaterialProperty {
429 define_as!(
430 as_float = Float -> f32
432 );
433 define_as_ref!(
434 as_float_array = FloatArray -> [f32]
436 );
437 define_as!(
438 as_int = Int -> i32
440 );
441 define_as_ref!(
442 as_int_array = IntArray -> [i32]
444 );
445 define_as!(
446 as_uint = UInt -> u32
448 );
449 define_as_ref!(
450 as_uint_array = UIntArray -> [u32]
452 );
453 define_as!(
454 as_bool = Bool -> bool
456 );
457 define_as!(
458 as_color = Color -> Color
460 );
461 define_as!(
462 as_vector2 = Vector2 -> Vector2<f32>
464 );
465 define_as_ref!(
466 as_vector2_array = Vector2Array -> [Vector2<f32>]
468 );
469 define_as!(
470 as_vector3 = Vector3 -> Vector3<f32>
472 );
473 define_as_ref!(
474 as_vector3_array = Vector3Array -> [Vector3<f32>]
476 );
477 define_as!(
478 as_vector4 = Vector4 -> Vector4<f32>
480 );
481 define_as_ref!(
482 as_vector4_array = Vector4Array -> [Vector4<f32>]
484 );
485 define_as!(
486 as_matrix2 = Matrix2 -> Matrix2<f32>
488 );
489 define_as_ref!(
490 as_matrix2_array = Matrix2Array -> [Matrix2<f32>]
492 );
493 define_as!(
494 as_matrix3 = Matrix3 -> Matrix3<f32>
496 );
497 define_as_ref!(
498 as_matrix3_array = Matrix3Array -> [Matrix3<f32>]
500 );
501 define_as!(
502 as_matrix4 = Matrix4 -> Matrix4<f32>
504 );
505 define_as_ref!(
506 as_matrix4_array = Matrix4Array -> [Matrix4<f32>]
508 );
509}
510
511impl Default for MaterialProperty {
512 fn default() -> Self {
513 Self::Float(0.0)
514 }
515}
516
517#[derive(Debug, Clone, Reflect)]
607pub struct Material {
608 shader: ShaderResource,
609 resource_bindings: FxHashMap<ImmutableString, MaterialResourceBinding>,
610}
611
612#[derive(Debug, Visit, Clone, Reflect)]
613enum OldMaterialProperty {
614 Float(f32),
615 FloatArray(Vec<f32>),
616 Int(i32),
617 IntArray(Vec<i32>),
618 UInt(u32),
619 UIntArray(Vec<u32>),
620 Vector2(Vector2<f32>),
621 Vector2Array(Vec<Vector2<f32>>),
622 Vector3(Vector3<f32>),
623 Vector3Array(Vec<Vector3<f32>>),
624 Vector4(Vector4<f32>),
625 Vector4Array(Vec<Vector4<f32>>),
626 Matrix2(Matrix2<f32>),
627 Matrix2Array(Vec<Matrix2<f32>>),
628 Matrix3(Matrix3<f32>),
629 Matrix3Array(Vec<Matrix3<f32>>),
630 Matrix4(Matrix4<f32>),
631 Matrix4Array(Vec<Matrix4<f32>>),
632 Bool(bool),
633 Color(Color),
634 Sampler {
635 value: Option<TextureResource>,
636 fallback: SamplerFallback,
637 },
638}
639
640impl Default for OldMaterialProperty {
641 fn default() -> Self {
642 Self::Float(0.0)
643 }
644}
645
646impl Visit for Material {
647 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
648 let mut region = visitor.enter_region(name)?;
649
650 let mut shader = if region.is_reading() {
651 ShaderResource::default()
656 } else {
657 self.shader.clone()
658 };
659 shader.visit("Shader", &mut region)?;
660 self.shader = shader;
661
662 if region.is_reading() {
663 let mut old_properties = FxHashMap::<ImmutableString, OldMaterialProperty>::default();
665 if old_properties.visit("Properties", &mut region).is_ok() {
666 for (name, old_property) in &old_properties {
667 if let OldMaterialProperty::Sampler { value, .. } = old_property {
668 self.bind(
669 name.clone(),
670 MaterialResourceBinding::Texture(MaterialTextureBinding {
671 value: value.clone(),
672 }),
673 )
674 }
675 }
676
677 let properties = self.try_get_or_insert_property_group("properties");
678
679 for (name, old_property) in old_properties {
680 match old_property {
681 OldMaterialProperty::Float(v) => properties.set_property(name, v),
682 OldMaterialProperty::FloatArray(v) => properties.set_property(name, v),
683 OldMaterialProperty::Int(v) => properties.set_property(name, v),
684 OldMaterialProperty::IntArray(v) => properties.set_property(name, v),
685 OldMaterialProperty::UInt(v) => properties.set_property(name, v),
686 OldMaterialProperty::UIntArray(v) => properties.set_property(name, v),
687 OldMaterialProperty::Vector2(v) => properties.set_property(name, v),
688 OldMaterialProperty::Vector2Array(v) => properties.set_property(name, v),
689 OldMaterialProperty::Vector3(v) => properties.set_property(name, v),
690 OldMaterialProperty::Vector3Array(v) => properties.set_property(name, v),
691 OldMaterialProperty::Vector4(v) => properties.set_property(name, v),
692 OldMaterialProperty::Vector4Array(v) => properties.set_property(name, v),
693 OldMaterialProperty::Matrix2(v) => properties.set_property(name, v),
694 OldMaterialProperty::Matrix2Array(v) => properties.set_property(name, v),
695 OldMaterialProperty::Matrix3(v) => properties.set_property(name, v),
696 OldMaterialProperty::Matrix3Array(v) => properties.set_property(name, v),
697 OldMaterialProperty::Matrix4(v) => properties.set_property(name, v),
698 OldMaterialProperty::Matrix4Array(v) => properties.set_property(name, v),
699 OldMaterialProperty::Bool(v) => properties.set_property(name, v),
700 OldMaterialProperty::Color(v) => properties.set_property(name, v),
701 _ => (),
702 };
703 }
704 } else {
705 self.resource_bindings
706 .visit("ResourceBindings", &mut region)?;
707 }
708 } else {
709 self.resource_bindings
710 .visit("ResourceBindings", &mut region)?;
711 }
712
713 Ok(())
714 }
715}
716
717impl Default for Material {
718 fn default() -> Self {
719 Material::standard()
720 }
721}
722
723impl TypeUuidProvider for Material {
724 fn type_uuid() -> Uuid {
725 uuid!("0e54fe44-0c58-4108-a681-d6eefc88c234")
726 }
727}
728
729impl ResourceData for Material {
730 fn type_uuid(&self) -> Uuid {
731 <Self as TypeUuidProvider>::type_uuid()
732 }
733
734 fn save(&mut self, path: &Path) -> Result<(), Box<dyn Error>> {
735 let mut visitor = Visitor::new();
736 self.visit("Material", &mut visitor)?;
737 visitor.save_ascii_to_file(path)?;
738 Ok(())
739 }
740
741 fn can_be_saved(&self) -> bool {
742 true
743 }
744
745 fn try_clone_box(&self) -> Option<Box<dyn ResourceData>> {
746 Some(Box::new(self.clone()))
747 }
748}
749
750#[derive(Debug)]
752pub enum MaterialError {
753 Visit(VisitError),
755}
756
757impl From<VisitError> for MaterialError {
758 fn from(value: VisitError) -> Self {
759 Self::Visit(value)
760 }
761}
762
763impl From<FileError> for MaterialError {
764 fn from(value: FileError) -> Self {
765 Self::Visit(VisitError::FileLoadError(value))
766 }
767}
768
769impl Display for MaterialError {
770 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
771 match self {
772 MaterialError::Visit(e) => {
773 write!(f, "Failed to visit data source. Reason: {e:?}")
774 }
775 }
776 }
777}
778
779impl Material {
780 pub fn standard() -> Self {
802 Self::from_shader(ShaderResource::standard())
803 }
804
805 pub fn standard_2d() -> Self {
807 Self::from_shader(ShaderResource::standard_2d())
808 }
809
810 pub fn standard_particle_system() -> Self {
812 Self::from_shader(ShaderResource::standard_particle_system())
813 }
814
815 pub fn standard_sprite() -> Self {
817 Self::from_shader(ShaderResource::standard_sprite())
818 }
819
820 pub fn standard_two_sides() -> Self {
822 Self::from_shader(ShaderResource::standard_twosides())
823 }
824
825 pub fn standard_terrain() -> Self {
827 Self::from_shader(ShaderResource::standard_terrain())
828 }
829
830 pub fn standard_tile() -> Self {
832 Self::from_shader(ShaderResource::standard_tile())
833 }
834
835 pub fn standard_widget() -> Self {
837 Self::from_shader(ShaderResource::standard_widget())
838 }
839
840 pub fn from_shader(shader: ShaderResource) -> Self {
863 Self {
864 shader,
865 resource_bindings: Default::default(),
866 }
867 }
868
869 pub async fn from_file<P>(
871 path: P,
872 io: &dyn ResourceIo,
873 resource_manager: ResourceManager,
874 ) -> Result<Self, MaterialError>
875 where
876 P: AsRef<Path>,
877 {
878 let content = io.load_file(path.as_ref()).await?;
879 let mut material = Material {
880 shader: Default::default(),
881 resource_bindings: Default::default(),
882 };
883 let mut visitor = Visitor::load_from_memory(&content)?;
884 visitor.blackboard.register(Arc::new(resource_manager));
885 material.visit("Material", &mut visitor)?;
886 Ok(material)
887 }
888
889 pub fn binding_ref(
896 &self,
897 name: impl Into<ImmutableString>,
898 ) -> Option<&MaterialResourceBinding> {
899 let name = name.into();
900 self.resource_bindings.get(&name)
901 }
902
903 pub fn binding_mut(
910 &mut self,
911 name: impl Into<ImmutableString>,
912 ) -> Option<&mut MaterialResourceBinding> {
913 let name = name.into();
914 self.resource_bindings.get_mut(&name)
915 }
916
917 pub fn texture_ref(&self, name: impl Into<ImmutableString>) -> Option<&MaterialTextureBinding> {
919 if let Some(MaterialResourceBinding::Texture(binding)) = self.binding_ref(name) {
920 Some(binding)
921 } else {
922 None
923 }
924 }
925
926 pub fn texture_mut(
928 &mut self,
929 name: impl Into<ImmutableString>,
930 ) -> Option<&mut MaterialTextureBinding> {
931 if let Some(MaterialResourceBinding::Texture(binding)) = self.binding_mut(name) {
932 Some(binding)
933 } else {
934 None
935 }
936 }
937
938 pub fn property_group_ref(
961 &self,
962 name: impl Into<ImmutableString>,
963 ) -> Option<&MaterialPropertyGroup> {
964 self.binding_ref(name).and_then(|binding| match binding {
965 MaterialResourceBinding::Texture { .. } => None,
966 MaterialResourceBinding::PropertyGroup(group) => Some(group),
967 })
968 }
969
970 pub fn property_group_mut(
992 &mut self,
993 name: impl Into<ImmutableString>,
994 ) -> Option<&mut MaterialPropertyGroup> {
995 self.binding_mut(name).and_then(|binding| match binding {
996 MaterialResourceBinding::Texture { .. } => None,
997 MaterialResourceBinding::PropertyGroup(group) => Some(group),
998 })
999 }
1000
1001 pub fn try_get_or_insert_property_group(
1004 &mut self,
1005 name: impl Into<ImmutableString>,
1006 ) -> &mut MaterialPropertyGroup {
1007 let name = name.into();
1008 if let MaterialResourceBinding::PropertyGroup(group) = self
1009 .resource_bindings
1010 .entry(name.clone())
1011 .or_insert_with(|| {
1012 MaterialResourceBinding::PropertyGroup(MaterialPropertyGroup::default())
1013 })
1014 {
1015 group
1016 } else {
1017 panic!("There's already a material resource binding with {name}!");
1018 }
1019 }
1020
1021 pub fn bind(
1040 &mut self,
1041 name: impl Into<ImmutableString>,
1042 new_value: impl Into<MaterialResourceBinding>,
1043 ) {
1044 self.resource_bindings.insert(name.into(), new_value.into());
1045 }
1046
1047 pub fn unbind(&mut self, name: impl Into<ImmutableString>) -> Option<MaterialResourceBinding> {
1049 self.resource_bindings.remove(&name.into())
1050 }
1051
1052 pub fn set_property(
1076 &mut self,
1077 name: impl Into<ImmutableString>,
1078 new_value: impl Into<MaterialProperty>,
1079 ) {
1080 self.try_get_or_insert_property_group("properties")
1081 .set_property(name, new_value);
1082 }
1083
1084 pub fn shader(&self) -> &ShaderResource {
1086 &self.shader
1087 }
1088
1089 pub fn bindings(&self) -> &FxHashMap<ImmutableString, MaterialResourceBinding> {
1091 &self.resource_bindings
1092 }
1093
1094 pub fn texture(&self, name: impl Into<ImmutableString>) -> Option<TextureResource> {
1096 self.resource_bindings.get(&name.into()).and_then(|v| {
1097 if let MaterialResourceBinding::Texture(binding) = v {
1098 binding.value.clone()
1099 } else {
1100 None
1101 }
1102 })
1103 }
1104}
1105
1106pub type MaterialResource = Resource<Material>;
1113
1114pub trait MaterialResourceExtension {
1116 fn new(material: Material) -> Self;
1124
1125 fn deep_copy(&self) -> MaterialResource;
1127
1128 fn deep_copy_as_embedded(&self) -> MaterialResource {
1130 let material = self.deep_copy();
1131 let mut header = material.header();
1132 header.kind.make_embedded();
1133 drop(header);
1134 material
1135 }
1136}
1137
1138impl MaterialResourceExtension for MaterialResource {
1139 #[inline(never)] fn new(material: Material) -> Self {
1141 Self::new_ok(Uuid::new_v4(), ResourceKind::Embedded, material)
1142 }
1143
1144 fn deep_copy(&self) -> MaterialResource {
1145 let material_state = self.header();
1146 match material_state.state {
1147 ResourceState::Unloaded => self.resource_uuid().into(),
1148 ResourceState::Pending { .. } => {
1149 MaterialResource::new_pending(self.resource_uuid(), ResourceKind::External)
1150 }
1151 ResourceState::LoadError {
1152 ref error,
1153 ref path,
1154 } => MaterialResource::new_load_error(
1155 ResourceKind::External,
1156 path.clone(),
1157 error.clone(),
1158 ),
1159 ResourceState::Ok { ref data } => MaterialResource::new_ok(
1160 Uuid::new_v4(),
1161 ResourceKind::Embedded,
1162 (&**data as &dyn Any)
1163 .downcast_ref::<Material>()
1164 .unwrap()
1165 .clone(),
1166 ),
1167 }
1168 }
1169}
1170
1171#[doc(hidden)]
1172pub fn visit_old_material(region: &mut RegionGuard) -> Option<MaterialResource> {
1173 let mut old_material = Arc::new(Mutex::new(Material::default()));
1174 if let Ok(mut inner) = region.enter_region("Material") {
1175 if old_material.visit("Value", &mut inner).is_ok() {
1176 return Some(MaterialResource::new_ok(
1177 Uuid::new_v4(),
1178 Default::default(),
1179 old_material.safe_lock().clone(),
1180 ));
1181 }
1182 }
1183 None
1184}
1185
1186#[doc(hidden)]
1187pub fn visit_old_texture_as_material<F>(
1188 region: &mut RegionGuard,
1189 make_default_material: F,
1190) -> Option<MaterialResource>
1191where
1192 F: FnOnce() -> Material,
1193{
1194 let mut old_texture: Option<TextureResource> = None;
1195 if let Ok(mut inner) = region.enter_region("Texture") {
1196 if old_texture.visit("Value", &mut inner).is_ok() {
1197 let mut material = make_default_material();
1198 material.bind("diffuseTexture", old_texture);
1199 return Some(MaterialResource::new_ok(
1200 Uuid::new_v4(),
1201 Default::default(),
1202 material,
1203 ));
1204 }
1205 }
1206 None
1207}
1208
1209lazy_static! {
1210 pub static ref STANDARD: BuiltInResource<Material> = BuiltInResource::new_no_source("__StandardMaterial",
1213 MaterialResource::new_ok(
1214 uuid!("fac37721-d1b8-422e-ae0c-83196ecd0a26"),
1215 ResourceKind::External,
1216 Material::from_shader(ShaderResource::standard()),
1217 )
1218 );
1219
1220 pub static ref STANDARD_2D: BuiltInResource<Material> = BuiltInResource::new_no_source("__Standard2DMaterial",
1223 MaterialResource::new_ok(
1224 uuid!("fe78a0d0-d059-4156-bc63-c3d2e36ad4b6"),
1225 ResourceKind::External,
1226 Material::from_shader(ShaderResource::standard_2d()),
1227 )
1228 );
1229
1230 pub static ref STANDARD_PARTICLE_SYSTEM: BuiltInResource<Material> = BuiltInResource::new_no_source(
1233 "__StandardParticleSystemMaterial",
1234 MaterialResource::new_ok(
1235 uuid!("5bebe6e5-4aeb-496f-88f6-abe2b1ac798b"),
1236 ResourceKind::External,
1237 Material::from_shader(ShaderResource::standard_particle_system(),),
1238 )
1239 );
1240
1241 pub static ref STANDARD_SPRITE: BuiltInResource<Material> = BuiltInResource::new_no_source(
1244 "__StandardSpriteMaterial",
1245 MaterialResource::new_ok(
1246 uuid!("3e331786-baae-412b-9d99-7370174bca43"),
1247 ResourceKind::External,
1248 Material::from_shader(ShaderResource::standard_sprite()),
1249 )
1250 );
1251
1252 pub static ref STANDARD_TERRAIN: BuiltInResource<Material> = BuiltInResource::new_no_source(
1255 "__StandardTerrainMaterial",
1256 MaterialResource::new_ok(
1257 uuid!("0e407e22-41ad-4763-9adb-9d2e86351ece"),
1258 ResourceKind::External,
1259 Material::from_shader(ShaderResource::standard_terrain()),
1260 )
1261 );
1262
1263 pub static ref STANDARD_TWOSIDES: BuiltInResource<Material> = BuiltInResource::new_no_source(
1266 "__StandardTwoSidesMaterial",
1267 MaterialResource::new_ok(
1268 uuid!("24115321-7766-495c-bc3a-75db2f73d26d"),
1269 ResourceKind::External,
1270 Material::from_shader(ShaderResource::standard_twosides()),
1271 )
1272 );
1273
1274 pub static ref STANDARD_WIDGET: BuiltInResource<Material> = BuiltInResource::new_no_source(
1277 "__StandardWidgetMaterial",
1278 MaterialResource::new_ok(
1279 uuid!("e5d61a6f-5c94-4137-b303-1ae29cfff6e7"),
1280 ResourceKind::External,
1281 Material::from_shader(ShaderResource::standard_widget()),
1282 )
1283 );
1284}