dae_parser/fx/
profile.rs

1use crate::*;
2
3/// A `<profile_*>` element.
4#[derive(Clone, Debug)]
5pub enum Profile {
6    /// Opens a block of platform-independent declarations for the common,
7    /// fixed-function shader.
8    Common(ProfileCommon),
9    /// Declares platform-specific data types and [`Technique`](TechniqueFx)s
10    /// for the Cg language.
11    CG(ProfileCG),
12    /// Declares platform-specific data types and [`Technique`](TechniqueFx)s
13    /// for OpenGL ES.
14    GLES(ProfileGLES),
15    /// Declares platform-specific data types and [`Technique`](TechniqueFx)s
16    /// for OpenGL Shading Language.
17    GLSL(ProfileGLSL),
18}
19
20impl From<ProfileCommon> for Profile {
21    fn from(v: ProfileCommon) -> Self {
22        Self::Common(v)
23    }
24}
25
26impl From<ProfileCG> for Profile {
27    fn from(v: ProfileCG) -> Self {
28        Self::CG(v)
29    }
30}
31
32impl From<ProfileGLES> for Profile {
33    fn from(v: ProfileGLES) -> Self {
34        Self::GLES(v)
35    }
36}
37
38impl From<ProfileGLSL> for Profile {
39    fn from(v: ProfileGLSL) -> Self {
40        Self::GLSL(v)
41    }
42}
43
44impl Profile {
45    /// Parse a [`Profile`] from an XML element.
46    pub fn parse(e: &Element) -> Result<Option<Self>> {
47        Ok(Some(match e.name() {
48            ProfileCommon::NAME => Self::Common(ProfileCommon::parse(e)?),
49            ProfileCG::NAME => Self::CG(ProfileCG::parse(e)?),
50            ProfileGLES::NAME => Self::GLES(ProfileGLES::parse(e)?),
51            ProfileGLSL::NAME => Self::GLSL(ProfileGLSL::parse(e)?),
52            _ => return Ok(None),
53        }))
54    }
55
56    /// Variant extractor for [`ProfileCommon`].
57    pub fn as_common(&self) -> Option<&ProfileCommon> {
58        match self {
59            Profile::Common(p) => Some(p),
60            _ => None,
61        }
62    }
63}
64
65impl XNodeWrite for Profile {
66    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
67        match self {
68            Self::Common(e) => e.write_to(w),
69            Self::CG(e) => e.write_to(w),
70            Self::GLES(e) => e.write_to(w),
71            Self::GLSL(e) => e.write_to(w),
72        }
73    }
74}
75
76/// Opens a block of platform-independent declarations for the common, fixed-function shader.
77#[derive(Clone, Debug)]
78pub struct ProfileCommon {
79    /// Asset management information about this element.
80    pub asset: Option<Box<Asset>>,
81    /// Declares a standard COLLADA image resource.
82    pub image: Vec<Image>,
83    /// Creates a new parameter from a constrained set of
84    /// types recognizable by all platforms, see [`ParamType`].
85    pub new_param: Vec<NewParam>,
86    /// Declares the only technique for this effect.
87    pub technique: TechniqueFx<CommonData>,
88    /// Provides arbitrary additional information about this element.
89    pub extra: Vec<Extra>,
90}
91
92impl XNode for ProfileCommon {
93    const NAME: &'static str = "profile_COMMON";
94    fn parse(element: &Element) -> Result<Self> {
95        debug_assert_eq!(element.name(), Self::NAME);
96        let mut it = element.children().peekable();
97        let asset = Asset::parse_opt_box(&mut it)?;
98        let image_param = ImageParam::parse_list(&mut it)?;
99        let mut image = vec![];
100        let mut new_param = vec![];
101        for ip in image_param {
102            match ip {
103                ImageParam::Image(e) => image.push(e),
104                ImageParam::NewParam(e) => new_param.push(e),
105            }
106        }
107        Ok(ProfileCommon {
108            asset,
109            image,
110            new_param,
111            technique: TechniqueFx::parse_one(&mut it)?,
112            extra: Extra::parse_many(it)?,
113        })
114    }
115}
116
117impl XNodeWrite for ProfileCommon {
118    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
119        let e = Self::elem().start(w)?;
120        self.asset.write_to(w)?;
121        self.image.write_to(w)?;
122        self.new_param.write_to(w)?;
123        self.technique.write_to(w)?;
124        self.extra.write_to(w)?;
125        e.end(w)
126    }
127}
128
129impl ProfileCommon {
130    /// Construct a new `ProfileCommon` from the `TechniqueFx` data.
131    pub fn new(technique: TechniqueFx<CommonData>) -> Self {
132        Self {
133            asset: None,
134            image: vec![],
135            new_param: vec![],
136            technique,
137            extra: vec![],
138        }
139    }
140
141    /// Get a parameter by name, looking in the parameters to the technique,
142    /// the parameters to the profile, and finally the parameters to the parent effect.
143    pub fn get_param<'a>(&'a self, parent: &'a Effect, sid: &str) -> Option<&'a NewParam> {
144        for p in self.technique.data.image_param.iter().rev() {
145            if let ImageParam::NewParam(p) = p {
146                if p.sid == sid {
147                    return Some(p);
148                }
149            }
150        }
151        for p in self.new_param.iter().rev() {
152            if p.sid == sid {
153                return Some(p);
154            }
155        }
156        parent.get_param(sid)
157    }
158}
159
160/// The extra data in a [`TechniqueFx`] as the child of [`ProfileCommon`].
161#[derive(Clone, Default, Debug)]
162pub struct CommonData {
163    /// A list of [`Image`] and [`NewParam`] elements in no particular order.
164    pub image_param: Vec<ImageParam>,
165    /// A list of shader elements.
166    pub shaders: Vec<Shader>,
167}
168
169impl ProfileData for CommonData {
170    fn parse(it: &mut ElementIter<'_>) -> Result<Self> {
171        Ok(CommonData {
172            image_param: ImageParam::parse_list(it)?,
173            shaders: parse_list_many(it, Shader::parse)?,
174        })
175    }
176}
177
178impl XNodeWrite for CommonData {
179    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
180        self.image_param.write_to(w)?;
181        self.shaders.write_to(w)
182    }
183}
184
185impl CommonData {
186    /// Construct a simple `CommonData` with one shader.
187    pub fn shader(shader: impl Into<Shader>) -> Self {
188        Self {
189            image_param: vec![],
190            shaders: vec![shader.into()],
191        }
192    }
193
194    /// Run the function `f` on all arguments of type [`Texture`] in the profile.
195    pub fn on_textures<'a, E>(
196        &'a self,
197        mut f: impl FnMut(&'a Texture) -> Result<(), E>,
198    ) -> Result<(), E> {
199        for s in &self.shaders {
200            s.on_textures(&mut f)?
201        }
202        Ok(())
203    }
204}
205
206/// The `<profile_CG>` element and its contents are unsupported
207/// and represented here as a raw XML element.
208#[derive(Clone, Debug)]
209pub struct ProfileCG(pub Element); // TODO
210
211impl XNode for ProfileCG {
212    const NAME: &'static str = "profile_CG";
213    fn parse(element: &Element) -> Result<Self> {
214        Ok(ProfileCG(element.clone()))
215    }
216}
217
218impl XNodeWrite for ProfileCG {
219    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
220        XNodeWrite::write_to(&self.0, w)
221    }
222}
223
224/// The `<profile_GLES>` element and its contents are unsupported
225/// and represented here as a raw XML element.
226#[derive(Clone, Debug)]
227pub struct ProfileGLES(pub Element); // TODO
228
229impl XNode for ProfileGLES {
230    const NAME: &'static str = "profile_GLES";
231    fn parse(element: &Element) -> Result<Self> {
232        Ok(ProfileGLES(element.clone()))
233    }
234}
235
236impl XNodeWrite for ProfileGLES {
237    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
238        XNodeWrite::write_to(&self.0, w)
239    }
240}
241
242/// The `<profile_GLSL>` element and its contents are unsupported
243/// and represented here as a raw XML element.
244#[derive(Clone, Debug)]
245pub struct ProfileGLSL(pub Element); // TODO
246
247impl XNode for ProfileGLSL {
248    const NAME: &'static str = "profile_GLSL";
249    fn parse(element: &Element) -> Result<Self> {
250        Ok(ProfileGLSL(element.clone()))
251    }
252}
253
254impl XNodeWrite for ProfileGLSL {
255    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
256        XNodeWrite::write_to(&self.0, w)
257    }
258}