1use crate::*;
2
3#[derive(Clone, Debug)]
5pub struct Effect {
6 pub id: String,
8 pub name: Option<String>,
10 pub asset: Option<Box<Asset>>,
12 pub annotate: Vec<Annotate>,
14 pub image: Vec<Image>,
16 pub new_param: Vec<NewParam>,
19 pub profile: Vec<Profile>,
21 pub extra: Vec<Extra>,
23}
24
25impl XNode for Effect {
26 const NAME: &'static str = "effect";
27 fn parse(element: &Element) -> Result<Self> {
28 debug_assert_eq!(element.name(), Self::NAME);
29 let mut it = element.children().peekable();
30 let res = Effect {
31 id: element.attr("id").ok_or("expected id attr")?.into(),
32 name: element.attr("name").map(Into::into),
33 asset: Asset::parse_opt_box(&mut it)?,
34 annotate: Annotate::parse_list(&mut it)?,
35 image: Image::parse_list(&mut it)?,
36 new_param: NewParam::parse_list(&mut it)?,
37 profile: parse_list_many(&mut it, Profile::parse)?,
38 extra: Extra::parse_many(it)?,
39 };
40 if res.profile.is_empty() {
41 return Err("expected at least one profile".into());
42 }
43 Ok(res)
44 }
45}
46
47impl XNodeWrite for Effect {
48 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
49 let mut e = Self::elem();
50 e.attr("id", &self.id);
51 e.opt_attr("name", &self.name);
52 let e = e.start(w)?;
53 self.asset.write_to(w)?;
54 self.annotate.write_to(w)?;
55 self.image.write_to(w)?;
56 self.new_param.write_to(w)?;
57 self.profile.write_to(w)?;
58 self.extra.write_to(w)?;
59 e.end(w)
60 }
61}
62
63impl Effect {
64 pub fn new(id: impl Into<String>, technique: TechniqueFx<CommonData>) -> Self {
66 Self {
67 id: id.into(),
68 name: None,
69 asset: None,
70 annotate: vec![],
71 image: vec![],
72 new_param: vec![],
73 profile: vec![ProfileCommon::new(technique).into()],
74 extra: vec![],
75 }
76 }
77
78 pub fn shader(id: impl Into<String>, shader: impl Into<Shader>) -> Self {
80 Self::new(id, TechniqueFx::new("common", CommonData::shader(shader)))
81 }
82
83 pub fn get_common_profile(&self) -> Option<&ProfileCommon> {
85 self.profile.iter().find_map(Profile::as_common)
86 }
87
88 pub fn get_param(&self, sid: &str) -> Option<&NewParam> {
90 self.new_param.iter().rev().find(|p| p.sid == sid)
91 }
92}
93
94#[derive(Clone, Debug, Default)]
96pub struct InstanceEffectData {
97 pub technique_hint: Vec<TechniqueHint>,
100 pub set_param: Vec<EffectSetParam>,
103}
104
105impl XNodeWrite for InstanceEffectData {
106 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
107 self.technique_hint.write_to(w)?;
108 self.set_param.write_to(w)
109 }
110}
111
112impl Instantiate for Effect {
113 const INSTANCE: &'static str = "instance_effect";
114 type Data = InstanceEffectData;
115 fn parse_data(_: &Element, it: &mut ElementIter<'_>) -> Result<Self::Data> {
116 Ok(InstanceEffectData {
117 technique_hint: TechniqueHint::parse_list(it)?,
118 set_param: EffectSetParam::parse_list(it)?,
119 })
120 }
121 fn is_empty(data: &Self::Data) -> bool {
122 data.technique_hint.is_empty() && data.set_param.is_empty()
123 }
124}
125
126#[derive(Clone, Debug)]
128pub struct BindVertexInput {
129 pub semantic: String,
131 pub input_semantic: String,
133 pub input_set: Option<u32>,
135}
136
137impl BindVertexInput {
138 pub fn new(
140 semantic: impl Into<String>,
141 input_semantic: impl Into<String>,
142 input_set: Option<u32>,
143 ) -> Self {
144 Self {
145 semantic: semantic.into(),
146 input_semantic: input_semantic.into(),
147 input_set,
148 }
149 }
150}
151
152impl XNode for BindVertexInput {
153 const NAME: &'static str = "bind_vertex_input";
154 fn parse(element: &Element) -> Result<Self> {
155 debug_assert_eq!(element.name(), Self::NAME);
156 let semantic = element.attr("semantic");
157 let input_semantic = element.attr("input_semantic");
158 Ok(BindVertexInput {
159 semantic: semantic.ok_or("missing semantic attribute")?.into(),
160 input_semantic: input_semantic.ok_or("missing input semantic")?.into(),
161 input_set: parse_attr(element.attr("input_set"))?,
162 })
163 }
164}
165
166impl XNodeWrite for BindVertexInput {
167 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
168 let mut e = Self::elem();
169 e.attr("semantic", &self.semantic);
170 e.attr("input_semantic", &self.input_semantic);
171 e.opt_print_attr("input_set", &self.input_set);
172 e.end(w)
173 }
174}
175
176pub trait ProfileData: XNodeWrite + Sized {
178 fn parse(it: &mut ElementIter<'_>) -> Result<Self>;
180}
181
182#[derive(Clone, Debug)]
187pub struct TechniqueFx<T> {
188 pub id: Option<String>,
190 pub sid: String,
193 pub asset: Option<Box<Asset>>,
195 pub data: T,
197 pub extra: Vec<Extra>,
199}
200
201impl<T> TechniqueFx<T> {
202 pub fn new(sid: impl Into<String>, data: T) -> Self {
204 Self {
205 id: None,
206 sid: sid.into(),
207 asset: None,
208 data,
209 extra: vec![],
210 }
211 }
212
213 pub fn default(sid: impl Into<String>) -> Self
215 where
216 T: Default,
217 {
218 Self::new(sid, T::default())
219 }
220}
221
222impl<T: ProfileData> XNode for TechniqueFx<T> {
223 const NAME: &'static str = "technique";
224 fn parse(element: &Element) -> Result<Self> {
225 debug_assert_eq!(element.name(), Self::NAME);
226 let mut it = element.children().peekable();
227 Ok(TechniqueFx {
228 id: element.attr("id").map(Into::into),
229 sid: element.attr("sid").ok_or("expecting sid attr")?.into(),
230 asset: Asset::parse_opt_box(&mut it)?,
231 data: T::parse(&mut it)?,
232 extra: Extra::parse_many(it)?,
233 })
234 }
235}
236
237impl<T: ProfileData> XNodeWrite for TechniqueFx<T> {
238 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
239 let mut e = Self::elem();
240 e.opt_attr("id", &self.id);
241 e.attr("sid", &self.sid);
242 let e = e.start(w)?;
243 self.asset.write_to(w)?;
244 self.data.write_to(w)?;
245 self.extra.write_to(w)?;
246 e.end(w)
247 }
248}
249
250#[derive(Clone, Debug)]
252pub struct TechniqueHint {
253 pub platform: Option<String>,
255 pub ref_: String,
257 pub profile: Option<String>,
262}
263
264impl TechniqueHint {
265 pub fn new(
267 platform: impl Into<String>,
268 ref_: impl Into<String>,
269 profile: impl Into<String>,
270 ) -> Self {
271 Self {
272 platform: Some(platform.into()),
273 ref_: ref_.into(),
274 profile: Some(profile.into()),
275 }
276 }
277}
278
279impl XNode for TechniqueHint {
280 const NAME: &'static str = "technique_hint";
281 fn parse(element: &Element) -> Result<Self> {
282 debug_assert_eq!(element.name(), Self::NAME);
283 Ok(TechniqueHint {
284 platform: element.attr("platform").map(Into::into),
285 ref_: element.attr("ref").ok_or("expected 'ref' attr")?.into(),
286 profile: element.attr("profile").map(Into::into),
287 })
288 }
289}
290
291impl XNodeWrite for TechniqueHint {
292 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
293 let mut e = Self::elem();
294 e.opt_attr("platform", &self.platform);
295 e.attr("ref", &self.ref_);
296 e.opt_attr("profile", &self.profile);
297 e.end(w)
298 }
299}