dae_parser/fx/
param.rs

1use crate::*;
2
3/// Instruction to create a new, named `Param` object in the FX Runtime,
4/// assign it a type, an initial value, and additional attributes at declaration time.
5#[derive(Clone, Debug)]
6pub struct NewParam {
7    /// Identifier for this parameter (that is, the variable name).
8    pub sid: String,
9    /// A list of strongly typed annotation remarks.
10    pub annotate: Vec<Annotate>,
11    /// Meta-information that describes the purpose of the parameter declaration.
12    pub semantic: Option<String>,
13    /// Additional information about the volatility or linkage.
14    pub modifier: Option<Modifier>,
15    /// The parameter's type.
16    pub ty: ParamType,
17}
18
19impl NewParam {
20    /// Create a `NewParam` with the given name and type.
21    pub fn new(sid: impl Into<String>, ty: impl Into<ParamType>) -> Self {
22        Self {
23            sid: sid.into(),
24            annotate: vec![],
25            semantic: None,
26            modifier: None,
27            ty: ty.into(),
28        }
29    }
30}
31
32impl XNode for NewParam {
33    const NAME: &'static str = "newparam";
34    fn parse(element: &Element) -> Result<Self> {
35        debug_assert_eq!(element.name(), Self::NAME);
36        let mut it = element.children().peekable();
37        let res = NewParam {
38            sid: element.attr("sid").ok_or("expecting sid attr")?.into(),
39            annotate: Annotate::parse_list(&mut it)?,
40            semantic: parse_opt("semantic", &mut it, parse_text)?,
41            modifier: parse_opt("modifier", &mut it, parse_elem)?,
42            ty: parse_one_many(&mut it, ParamType::parse)?,
43        };
44        finish(res, it)
45    }
46}
47
48impl XNodeWrite for NewParam {
49    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
50        let mut e = Self::elem();
51        e.attr("sid", &self.sid);
52        let e = e.start(w)?;
53        self.annotate.write_to(w)?;
54        opt(&self.semantic, |e| ElemBuilder::print_str("semantic", e, w))?;
55        ElemBuilder::opt_print("modifier", &self.modifier, w)?;
56        self.ty.write_to(w)?;
57        e.end(w)
58    }
59}
60
61/// Assigns a new value to a previously defined parameter.
62///
63/// This type corresponds to the `<setparam>` element in the COLLADA spec
64/// in the special case where the parent is an `<instance_effect>`.
65#[derive(Clone, Debug)]
66pub struct EffectSetParam {
67    /// Attempts to reference the predefined parameter that will have its value set.
68    pub ref_: String,
69    /// The value of the parameter.
70    // This is slightly inaccurate; the collada spec allows a larger set of types here
71    // than the ones used in <annotation>.
72    pub value: AnnotType,
73}
74
75impl EffectSetParam {
76    /// Construct a new `EffectSetParam` with the given name and type.
77    pub fn new(ref_: impl Into<String>, value: impl Into<AnnotType>) -> Self {
78        Self {
79            ref_: ref_.into(),
80            value: value.into(),
81        }
82    }
83}
84
85impl XNode for EffectSetParam {
86    const NAME: &'static str = "setparam";
87    fn parse(element: &Element) -> Result<Self> {
88        debug_assert_eq!(element.name(), Self::NAME);
89        let mut it = element.children().peekable();
90        let res = EffectSetParam {
91            ref_: element.attr("ref").ok_or("expected ref attr")?.into(),
92            value: parse_one_many(&mut it, AnnotType::parse)?,
93        };
94        finish(res, it)
95    }
96}
97
98impl XNodeWrite for EffectSetParam {
99    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
100        let mut e = Self::elem();
101        e.attr("ref", &self.ref_);
102        let e = e.start(w)?;
103        self.value.write_to(w)?;
104        e.end(w)
105    }
106}
107
108/// Adds a strongly typed annotation remark to the parent object.
109#[derive(Clone, Debug)]
110pub struct Annotate {
111    /// The text string name of this element that represents the `SYMBOL` in an object of
112    /// the form `SYMBOL = VALUE`.
113    pub name: String,
114    /// A strongly typed value that represents the VALUE in an object of
115    /// the form SYMBOL = VALUE. Consists of a COLLADA type
116    /// element that contains a value of that type.
117    pub value: AnnotType,
118}
119
120impl Annotate {
121    /// Construct a new annotation with the given name and typed value.
122    pub fn new(name: impl Into<String>, value: impl Into<AnnotType>) -> Self {
123        Self {
124            name: name.into(),
125            value: value.into(),
126        }
127    }
128}
129
130impl XNode for Annotate {
131    const NAME: &'static str = "annotate";
132    fn parse(element: &Element) -> Result<Self> {
133        debug_assert_eq!(element.name(), Self::NAME);
134        let mut it = element.children().peekable();
135        let res = Annotate {
136            name: element.attr("name").ok_or("expecting name attr")?.into(),
137            value: parse_one_many(&mut it, AnnotType::parse)?,
138        };
139        finish(res, it)
140    }
141}
142
143impl XNodeWrite for Annotate {
144    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
145        let mut e = Self::elem();
146        e.attr("name", &self.name);
147        let e = e.start(w)?;
148        self.value.write_to(w)?;
149        e.end(w)
150    }
151}
152
153mk_extensible_enum! {
154  /// Additional information about the volatility or linkage of a parameter.
155  pub enum Modifier {
156      /// `CONST` linkage modifier
157      Const = "CONST",
158      /// `UNIFORM` linkage modifier
159      Uniform = "UNIFORM",
160      /// `VARYING` linkage modifier
161      Varying = "VARYING",
162      /// `STATIC` linkage modifier
163      Static = "STATIC",
164      /// `VOLATILE` linkage modifier
165      Volatile = "VOLATILE",
166      /// `EXTERN` linkage modifier
167      Extern = "EXTERN",
168      /// `SHARED` linkage modifier
169      Shared = "SHARED",
170  }
171}
172
173/// A strongly typed value that represents the `VALUE` in an object of the form `SYMBOL = VALUE`.
174#[derive(Clone, Debug)]
175pub enum AnnotType {
176    /// `bool` type
177    Bool(bool),
178    /// `bool2` type
179    Bool2([bool; 2]),
180    /// `bool3` type
181    Bool3([bool; 3]),
182    /// `bool4` type
183    Bool4([bool; 4]),
184    /// `int` type
185    Int(u32),
186    /// `int2` type
187    Int2([u32; 2]),
188    /// `int3` type
189    Int3(Box<[u32; 3]>),
190    /// `int4` type
191    Int4(Box<[u32; 4]>),
192    /// `float` type
193    Float(f32),
194    /// `float2` type
195    Float2([f32; 2]),
196    /// `float3` type
197    Float3(Box<[f32; 3]>),
198    /// `float4` type
199    Float4(Box<[f32; 4]>),
200    /// `float2x2` type (linearized)
201    Float2x2(Box<[f32; 2 * 2]>),
202    /// `float3x3` type (linearized)
203    Float3x3(Box<[f32; 3 * 3]>),
204    /// `float4x4` type (linearized)
205    Float4x4(Box<[f32; 4 * 4]>),
206    /// `string` type
207    String(Box<str>),
208}
209
210impl From<&str> for AnnotType {
211    fn from(v: &str) -> Self {
212        Self::String(v.into())
213    }
214}
215
216impl From<Box<str>> for AnnotType {
217    fn from(v: Box<str>) -> Self {
218        Self::String(v)
219    }
220}
221
222impl From<bool> for AnnotType {
223    fn from(v: bool) -> Self {
224        Self::Bool(v)
225    }
226}
227
228impl From<f32> for AnnotType {
229    fn from(v: f32) -> Self {
230        Self::Float(v)
231    }
232}
233
234impl From<u32> for AnnotType {
235    fn from(v: u32) -> Self {
236        Self::Int(v)
237    }
238}
239
240impl AnnotType {
241    /// Parse a [`AnnotType`] from an XML element.
242    pub fn parse(e: &Element) -> Result<Option<Self>> {
243        Ok(Some(match e.name() {
244            "bool" => Self::Bool(parse_elem(e)?),
245            "bool2" => Self::Bool2(*parse_array_n(e)?),
246            "bool3" => Self::Bool3(*parse_array_n(e)?),
247            "bool4" => Self::Bool4(*parse_array_n(e)?),
248            "int" => Self::Int(parse_elem(e)?),
249            "int2" => Self::Int2(*parse_array_n(e)?),
250            "int3" => Self::Int3(parse_array_n(e)?),
251            "int4" => Self::Int4(parse_array_n(e)?),
252            "float" => Self::Float(parse_elem(e)?),
253            "float2" => Self::Float2(*parse_array_n(e)?),
254            "float3" => Self::Float3(parse_array_n(e)?),
255            "float4" => Self::Float4(parse_array_n(e)?),
256            "float2x2" => Self::Float2x2(parse_array_n(e)?),
257            "float3x3" => Self::Float3x3(parse_array_n(e)?),
258            "float4x4" => Self::Float4x4(parse_array_n(e)?),
259            "string" => Self::String(parse_text(e)?.into()),
260            _ => return Ok(None),
261        }))
262    }
263}
264
265impl XNodeWrite for AnnotType {
266    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
267        match self {
268            AnnotType::Bool(e) => ElemBuilder::print("bool", e, w),
269            AnnotType::Bool2(e) => ElemBuilder::print_arr("bool2", e, w),
270            AnnotType::Bool3(e) => ElemBuilder::print_arr("bool3", e, w),
271            AnnotType::Bool4(e) => ElemBuilder::print_arr("bool4", e, w),
272            AnnotType::Int(e) => ElemBuilder::print("int", e, w),
273            AnnotType::Int2(e) => ElemBuilder::print_arr("int2", e, w),
274            AnnotType::Int3(e) => ElemBuilder::print_arr("int3", &**e, w),
275            AnnotType::Int4(e) => ElemBuilder::print_arr("int4", &**e, w),
276            AnnotType::Float(e) => ElemBuilder::print("float", e, w),
277            AnnotType::Float2(e) => ElemBuilder::print_arr("float2", e, w),
278            AnnotType::Float3(e) => ElemBuilder::print_arr("float3", &**e, w),
279            AnnotType::Float4(e) => ElemBuilder::print_arr("float4", &**e, w),
280            AnnotType::Float2x2(e) => ElemBuilder::print_arr("float2x2", &**e, w),
281            AnnotType::Float3x3(e) => ElemBuilder::print_arr("float3x3", &**e, w),
282            AnnotType::Float4x4(e) => ElemBuilder::print_arr("float4x4", &**e, w),
283            AnnotType::String(e) => ElemBuilder::print_str("string", e, w),
284        }
285    }
286}
287/// A parameter's type. We do not have full support here,
288/// but unknown types can be retrieved in the `Other` variant.
289#[derive(Clone, Debug)]
290pub enum ParamType {
291    /// `float` type
292    Float(f32),
293    /// `float2` type
294    Float2([f32; 2]),
295    /// `float3` type
296    Float3(Box<[f32; 3]>),
297    /// `float4` type
298    Float4(Box<[f32; 4]>),
299    /// `surface` type
300    Surface(Box<Surface>),
301    /// `sampler2D` type
302    Sampler2D(Box<Sampler2D>),
303    /// Any other type, stored as a raw XML element.
304    Other(Box<Element>),
305}
306
307impl From<f32> for ParamType {
308    fn from(v: f32) -> Self {
309        Self::Float(v)
310    }
311}
312
313impl ParamType {
314    /// Parse a [`ParamType`] from an XML element.
315    pub fn parse(e: &Element) -> Result<Option<Self>> {
316        Ok(Some(match e.name() {
317            "float" => Self::Float(parse_elem(e)?),
318            "float2" => Self::Float2(*parse_array_n(e)?),
319            "float3" => Self::Float3(parse_array_n(e)?),
320            "float4" => Self::Float4(parse_array_n(e)?),
321            Surface::NAME => Self::Surface(Surface::parse_box(e)?),
322            Sampler2D::NAME => Self::Sampler2D(Sampler2D::parse_box(e)?),
323            _ => Self::Other(Box::new(e.clone())),
324        }))
325    }
326
327    /// Downcast this element to a [`Surface`].
328    pub fn as_surface(&self) -> Option<&Surface> {
329        match self {
330            ParamType::Surface(s) => Some(s),
331            _ => None,
332        }
333    }
334
335    /// Downcast this element to a [`Sampler2D`].
336    pub fn as_sampler2d(&self) -> Option<&Sampler2D> {
337        match self {
338            ParamType::Sampler2D(s) => Some(s),
339            _ => None,
340        }
341    }
342}
343
344impl XNodeWrite for ParamType {
345    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
346        match self {
347            ParamType::Float(e) => ElemBuilder::print("float", e, w),
348            ParamType::Float2(e) => ElemBuilder::print_arr("float2", e, w),
349            ParamType::Float3(e) => ElemBuilder::print_arr("float3", &**e, w),
350            ParamType::Float4(e) => ElemBuilder::print_arr("float4", &**e, w),
351            ParamType::Surface(e) => e.write_to(w),
352            ParamType::Sampler2D(e) => e.write_to(w),
353            ParamType::Other(e) => XNodeWrite::write_to(e, w),
354        }
355    }
356}