fyroxed_base/scene/commands/
material.rs1use crate::{
22 command::{CommandContext, CommandTrait},
23 fyrox::{
24 asset::ResourceData,
25 core::{log::Log, sstorage::ImmutableString},
26 material::{
27 shader::ShaderResource, Material, MaterialProperty, MaterialResource,
28 MaterialResourceBinding,
29 },
30 },
31};
32use std::path::{Path, PathBuf};
33
34fn try_save(path: Option<&Path>, material: &MaterialResource) {
35 if let Some(path) = path {
36 Log::verify(material.data_ref().save(path));
37 } else {
38 Log::warn("The edited material cannot be saved, because it does not have a path!")
39 }
40}
41
42#[derive(Debug)]
43pub struct SetMaterialBindingCommand {
44 material: MaterialResource,
45 name: ImmutableString,
46 binding: Option<MaterialResourceBinding>,
47 path: Option<PathBuf>,
48}
49
50impl SetMaterialBindingCommand {
51 pub fn new(
52 material: MaterialResource,
53 name: ImmutableString,
54 binding: MaterialResourceBinding,
55 path: Option<PathBuf>,
56 ) -> Self {
57 Self {
58 material,
59 name,
60 binding: Some(binding),
61 path,
62 }
63 }
64
65 fn swap(&mut self) {
66 let mut material = self.material.data_ref();
67
68 let old_value = material.binding_ref(self.name.clone()).cloned();
69 let new_value = std::mem::replace(&mut self.binding, old_value);
70 if let Some(new_value) = new_value {
71 material.bind(self.name.clone(), new_value);
72 } else {
73 material.unbind(self.name.clone());
74 }
75
76 drop(material);
77 try_save(self.path.as_deref(), &self.material);
78 }
79}
80
81impl CommandTrait for SetMaterialBindingCommand {
82 fn name(&mut self, _: &dyn CommandContext) -> String {
83 format!("Set Material {} Property Value", self.name)
84 }
85
86 fn execute(&mut self, _: &mut dyn CommandContext) {
87 self.swap();
88 }
89
90 fn revert(&mut self, _: &mut dyn CommandContext) {
91 self.swap();
92 }
93}
94
95#[derive(Debug)]
96pub struct SetMaterialPropertyGroupPropertyValueCommand {
97 material: MaterialResource,
98 group_name: ImmutableString,
99 property_name: ImmutableString,
100 value: Option<MaterialProperty>,
101 path: Option<PathBuf>,
102}
103
104impl SetMaterialPropertyGroupPropertyValueCommand {
105 pub fn new(
106 material: MaterialResource,
107 group_name: ImmutableString,
108 property_name: ImmutableString,
109 value: MaterialProperty,
110 path: Option<PathBuf>,
111 ) -> Self {
112 Self {
113 material,
114 group_name,
115 property_name,
116 value: Some(value),
117 path,
118 }
119 }
120
121 fn swap(&mut self) {
122 let mut material = self.material.data_ref();
123
124 let group = material.try_get_or_insert_property_group(self.group_name.clone());
125 let old_value = group.property_ref(self.property_name.clone()).cloned();
126 let new_value = std::mem::replace(&mut self.value, old_value);
127 if let Some(new_value) = new_value {
128 group.set_property(self.property_name.clone(), new_value);
129 } else {
130 group.unset_property(self.property_name.clone());
131 }
132
133 drop(material);
134 try_save(self.path.as_deref(), &self.material);
135 }
136}
137
138impl CommandTrait for SetMaterialPropertyGroupPropertyValueCommand {
139 fn name(&mut self, _: &dyn CommandContext) -> String {
140 format!("Set Material {} Property Value", self.property_name)
141 }
142
143 fn execute(&mut self, _: &mut dyn CommandContext) {
144 self.swap();
145 }
146
147 fn revert(&mut self, _: &mut dyn CommandContext) {
148 self.swap();
149 }
150}
151
152#[derive(Debug)]
153enum SetMaterialShaderCommandState {
154 Undefined,
155 NonExecuted { new_shader: ShaderResource },
156 Executed { old_material: Material },
157 Reverted { new_material: Material },
158}
159
160#[derive(Debug)]
161pub struct SetMaterialShaderCommand {
162 material: MaterialResource,
163 path: Option<PathBuf>,
164 state: SetMaterialShaderCommandState,
165}
166
167impl SetMaterialShaderCommand {
168 pub fn new(material: MaterialResource, shader: ShaderResource, path: Option<PathBuf>) -> Self {
169 Self {
170 material,
171 state: SetMaterialShaderCommandState::NonExecuted { new_shader: shader },
172 path,
173 }
174 }
175
176 fn swap(&mut self, _context: &mut dyn CommandContext) {
177 match std::mem::replace(&mut self.state, SetMaterialShaderCommandState::Undefined) {
178 SetMaterialShaderCommandState::Undefined => {
179 unreachable!()
180 }
181 SetMaterialShaderCommandState::NonExecuted { new_shader } => {
182 let mut material = self.material.data_ref();
183
184 let old_material =
185 std::mem::replace(&mut *material, Material::from_shader(new_shader));
186
187 self.state = SetMaterialShaderCommandState::Executed { old_material };
188 }
189 SetMaterialShaderCommandState::Executed { old_material } => {
190 let mut material = self.material.data_ref();
191
192 let new_material = std::mem::replace(&mut *material, old_material);
193
194 self.state = SetMaterialShaderCommandState::Reverted { new_material };
195 }
196 SetMaterialShaderCommandState::Reverted { new_material } => {
197 let mut material = self.material.data_ref();
198
199 let old_material = std::mem::replace(&mut *material, new_material);
200
201 self.state = SetMaterialShaderCommandState::Executed { old_material };
202 }
203 }
204
205 try_save(self.path.as_deref(), &self.material);
206 }
207}
208
209impl CommandTrait for SetMaterialShaderCommand {
210 fn name(&mut self, _: &dyn CommandContext) -> String {
211 "Set Material Shader".to_owned()
212 }
213
214 fn execute(&mut self, ctx: &mut dyn CommandContext) {
215 self.swap(ctx);
216 }
217
218 fn revert(&mut self, ctx: &mut dyn CommandContext) {
219 self.swap(ctx);
220 }
221}