1use crate::*;
2
3#[derive(Clone, Debug)]
5pub struct Image {
6 pub id: Option<String>,
8 pub name: Option<String>,
10 pub format: Option<String>,
17 pub height: u32,
20 pub width: u32,
23 pub depth: u32,
26 pub asset: Option<Box<Asset>>,
28 pub source: ImageSource,
30 pub extra: Vec<Extra>,
32}
33
34impl Image {
35 pub fn new(id: impl Into<String>, name: Option<String>, source: ImageSource) -> Self {
37 Self {
38 id: Some(id.into()),
39 name,
40 format: None,
41 height: 0,
42 width: 0,
43 depth: 1,
44 asset: None,
45 source,
46 extra: vec![],
47 }
48 }
49}
50
51impl XNode for Image {
52 const NAME: &'static str = "image";
53 fn parse(element: &Element) -> Result<Self> {
54 debug_assert_eq!(element.name(), Self::NAME);
55 let mut it = element.children().peekable();
56 Ok(Image {
57 id: element.attr("id").map(Into::into),
58 name: element.attr("name").map(Into::into),
59 format: element.attr("format").map(Into::into),
60 height: parse_attr(element.attr("height"))?.unwrap_or(0),
61 width: parse_attr(element.attr("width"))?.unwrap_or(0),
62 depth: parse_attr(element.attr("depth"))?.unwrap_or(1),
63 asset: Asset::parse_opt_box(&mut it)?,
64 source: parse_one_many(&mut it, ImageSource::parse)?,
65 extra: Extra::parse_many(it)?,
66 })
67 }
68}
69
70impl XNodeWrite for Image {
71 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
72 let mut e = Self::elem();
73 e.opt_attr("id", &self.id);
74 e.opt_attr("name", &self.name);
75 e.opt_attr("format", &self.format);
76 e.def_print_attr("height", self.height, 0);
77 e.def_print_attr("width", self.width, 0);
78 e.def_print_attr("depth", self.depth, 1);
79 let e = e.start(w)?;
80 self.asset.write_to(w)?;
81 self.source.write_to(w)?;
82 self.extra.write_to(w)?;
83 e.end(w)
84 }
85}
86
87#[derive(Clone, Debug)]
89pub enum ImageParam {
90 NewParam(NewParam),
92 Image(Image),
94}
95
96impl From<Image> for ImageParam {
97 fn from(v: Image) -> Self {
98 Self::Image(v)
99 }
100}
101
102impl ImageParam {
103 pub(crate) fn parse_list(it: &mut ElementIter<'_>) -> Result<Vec<Self>> {
104 parse_list_many(it, |e| {
105 Ok(Some(match e.name() {
106 Image::NAME => Self::Image(Image::parse(e)?),
107 NewParam::NAME => Self::NewParam(NewParam::parse(e)?),
108 _ => return Ok(None),
109 }))
110 })
111 }
112}
113
114impl XNodeWrite for ImageParam {
115 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
116 match self {
117 Self::NewParam(e) => e.write_to(w),
118 Self::Image(e) => e.write_to(w),
119 }
120 }
121}
122
123fn parse_hex_array(s: &str) -> Box<[u8]> {
124 let mut out = vec![];
125 let mut hi = 0;
126 let mut odd = false;
127 for c in s.bytes() {
128 let c = match c {
129 b'0'..=b'9' => c - b'0',
130 b'a'..=b'f' => c - b'a' + 10,
131 b'A'..=b'F' => c - b'A' + 10,
132 _ => continue,
133 };
134 if odd {
135 out.push(hi << 4 | c)
136 } else {
137 hi = c
138 }
139 odd = !odd
140 }
141 out.into()
142}
143
144#[derive(Clone, Debug)]
146pub enum ImageSource {
147 Data(Box<[u8]>),
149 InitFrom(Url),
151}
152
153impl ImageSource {
154 pub fn parse(element: &Element) -> Result<Option<Self>> {
156 Ok(Some(match element.name() {
157 "data" => {
158 let s = get_text(element).ok_or("expected text element")?;
159 ImageSource::Data(parse_hex_array(s))
160 }
161 "init_from" => ImageSource::InitFrom(parse_elem(element)?),
162 _ => return Ok(None),
163 }))
164 }
165}
166
167impl XNodeWrite for ImageSource {
168 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
169 match self {
170 Self::Data(data) => {
171 let e = ElemBuilder::new("data").start(w)?;
172 let mut indent = false;
173 for chunk in data.chunks(40) {
174 if indent {
175 w.write_indent()?
176 }
177 indent = true;
178 for &c in chunk {
179 write!(w.get_mut(), "{:x}", c)?
180 }
181 }
182 e.end(w)
183 }
184 Self::InitFrom(url) => ElemBuilder::print("init_from", url, w),
185 }
186 }
187}
188
189#[derive(Clone, Debug)]
191pub struct Sampler2D {
192 pub source: NameRef<Surface>,
196 pub wrap_s: WrapMode,
198 pub wrap_t: WrapMode,
200 pub min_filter: SamplerFilter,
207 pub mag_filter: SamplerFilter,
212 pub mip_filter: SamplerFilter,
214 pub border_color: Option<Box<[f32; 4]>>,
218 pub mipmap_max_level: u8,
220 pub mipmap_bias: f32,
223 pub extra: Vec<Extra>,
225}
226
227impl Sampler2D {
228 pub fn new(source: String) -> Self {
230 Self {
231 source: Ref::new(source),
232 wrap_s: Default::default(),
233 wrap_t: Default::default(),
234 min_filter: Default::default(),
235 mag_filter: Default::default(),
236 mip_filter: Default::default(),
237 border_color: None,
238 mipmap_max_level: 0,
239 mipmap_bias: 0.,
240 extra: vec![],
241 }
242 }
243}
244
245impl XNode for Sampler2D {
246 const NAME: &'static str = "sampler2D";
247 fn parse(element: &Element) -> Result<Self> {
248 debug_assert_eq!(element.name(), Self::NAME);
249 let mut it = element.children().peekable();
250 Ok(Sampler2D {
251 source: parse_one("source", &mut it, parse_elem)?,
252 wrap_s: parse_opt("wrap_s", &mut it, parse_elem)?.unwrap_or_default(),
253 wrap_t: parse_opt("wrap_t", &mut it, parse_elem)?.unwrap_or_default(),
254 min_filter: parse_opt("minfilter", &mut it, parse_elem)?.unwrap_or_default(),
255 mag_filter: parse_opt("magfilter", &mut it, parse_elem)?.unwrap_or_default(),
256 mip_filter: parse_opt("mipfilter", &mut it, parse_elem)?.unwrap_or_default(),
257 border_color: parse_opt("border_color", &mut it, parse_array_n)?,
258 mipmap_max_level: parse_opt("mipmap_maxlevel", &mut it, parse_elem)?.unwrap_or(0),
259 mipmap_bias: parse_opt("mipmap_bias", &mut it, parse_elem)?.unwrap_or(0.),
260 extra: Extra::parse_many(it)?,
261 })
262 }
263}
264
265impl XNodeWrite for Sampler2D {
266 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
267 let e = Self::elem().start(w)?;
268 ElemBuilder::print("source", &self.source, w)?;
269 ElemBuilder::def_print("wrap_s", self.wrap_s, Default::default(), w)?;
270 ElemBuilder::def_print("wrap_t", self.wrap_t, Default::default(), w)?;
271 ElemBuilder::def_print("minfilter", self.min_filter, Default::default(), w)?;
272 ElemBuilder::def_print("magfilter", self.mag_filter, Default::default(), w)?;
273 ElemBuilder::def_print("mipfilter", self.mip_filter, Default::default(), w)?;
274 opt(&self.border_color, |e| {
275 ElemBuilder::print_arr("border_color", &**e, w)
276 })?;
277 ElemBuilder::def_print("mipmap_maxlevel", self.mipmap_max_level, 0, w)?;
278 ElemBuilder::def_print("mipmap_bias", self.mipmap_bias, 0., w)?;
279 self.extra.write_to(w)?;
280 e.end(w)
281 }
282}
283
284#[derive(Clone, Copy, Debug, PartialEq, Eq)]
287pub enum WrapMode {
288 Wrap,
291 Mirror,
295 Clamp,
305 Border,
311 None,
315}
316
317impl Default for WrapMode {
318 fn default() -> Self {
319 Self::Wrap
320 }
321}
322
323impl FromStr for WrapMode {
324 type Err = ();
325
326 fn from_str(s: &str) -> Result<Self, Self::Err> {
327 match s {
328 "WRAP" => Ok(Self::Wrap),
329 "MIRROR" => Ok(Self::Mirror),
330 "CLAMP" => Ok(Self::Clamp),
331 "BORDER" => Ok(Self::Border),
332 "NONE" => Ok(Self::None),
333 _ => Err(()),
334 }
335 }
336}
337
338impl WrapMode {
339 pub fn to_str(self) -> &'static str {
341 match self {
342 Self::Wrap => "WRAP",
343 Self::Mirror => "MIRROR",
344 Self::Clamp => "CLAMP",
345 Self::Border => "BORDER",
346 Self::None => "NONE",
347 }
348 }
349}
350
351impl Display for WrapMode {
352 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
353 Display::fmt(self.to_str(), f)
354 }
355}
356
357#[derive(Clone, Copy, Debug, PartialEq, Eq)]
359#[allow(missing_docs)]
360pub enum SamplerFilter {
361 None,
362 Nearest,
363 Linear,
364 NearestMipmapNearest,
365 LinearMipmapNearest,
366 NearestMipmapLinear,
367 LinearMipmapLinear,
368}
369
370impl Default for SamplerFilter {
371 fn default() -> Self {
372 Self::None
373 }
374}
375
376impl FromStr for SamplerFilter {
377 type Err = ();
378
379 fn from_str(s: &str) -> Result<Self, Self::Err> {
380 match s {
381 "NONE" => Ok(Self::None),
382 "NEAREST" => Ok(Self::Nearest),
383 "LINEAR" => Ok(Self::Linear),
384 "NEAREST_MIPMAP_NEAREST" => Ok(Self::NearestMipmapNearest),
385 "LINEAR_MIPMAP_NEAREST" => Ok(Self::LinearMipmapNearest),
386 "NEAREST_MIPMAP_LINEAR" => Ok(Self::NearestMipmapLinear),
387 "LINEAR_MIPMAP_LINEAR" => Ok(Self::LinearMipmapLinear),
388 _ => Err(()),
389 }
390 }
391}
392
393impl SamplerFilter {
394 pub fn to_str(self) -> &'static str {
396 match self {
397 Self::None => "NONE",
398 Self::Nearest => "NEAREST",
399 Self::Linear => "LINEAR",
400 Self::NearestMipmapNearest => "NEAREST_MIPMAP_NEAREST",
401 Self::LinearMipmapNearest => "LINEAR_MIPMAP_NEAREST",
402 Self::NearestMipmapLinear => "NEAREST_MIPMAP_LINEAR",
403 Self::LinearMipmapLinear => "LINEAR_MIPMAP_LINEAR",
404 }
405 }
406}
407
408impl Display for SamplerFilter {
409 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
410 Display::fmt(self.to_str(), f)
411 }
412}
413
414#[derive(Clone, Debug)]
417pub struct Surface {
418 pub ty: SurfaceType,
420 pub init: SurfaceInit,
422 pub format: Option<String>,
427 pub format_hint: Option<Box<FormatHint>>,
432 pub size: Option<Box<[u32; 3]>>,
440 pub viewport_ratio: Option<Box<[f32; 2]>>,
449 pub mip_levels: u32,
454 pub mipmap_generate: bool,
464 pub extra: Vec<Extra>,
466}
467
468impl Surface {
469 pub fn new(ty: SurfaceType, init: SurfaceInit) -> Self {
471 Self {
472 ty,
473 init,
474 format: None,
475 format_hint: None,
476 size: None,
477 viewport_ratio: None,
478 mip_levels: 0,
479 mipmap_generate: false,
480 extra: vec![],
481 }
482 }
483}
484
485impl XNode for Surface {
486 const NAME: &'static str = "surface";
487 fn parse(element: &Element) -> Result<Self> {
488 debug_assert_eq!(element.name(), Self::NAME);
489 let mut it = element.children().peekable();
490 let res = Surface {
491 ty: parse_attr(element.attr("type"))?.ok_or("expected 'type' attr")?,
492 init: parse_one_many(&mut it, SurfaceInit::parse)?,
493 format: parse_opt("format", &mut it, parse_text)?,
494 format_hint: FormatHint::parse_opt_box(&mut it)?,
495 size: parse_opt("size", &mut it, parse_array_n)?,
496 viewport_ratio: parse_opt("viewport_ratio", &mut it, parse_array_n)?,
497 mip_levels: parse_opt("mip_levels", &mut it, parse_elem)?.unwrap_or(0),
498 mipmap_generate: parse_opt("mipmap_generate", &mut it, parse_elem)?.unwrap_or(false),
499 extra: Extra::parse_many(it)?,
500 };
501 if res.size.is_some() && res.viewport_ratio.is_some() {
502 return Err("size and viewport_ratio cannot be used together".into());
503 }
504 Ok(res)
505 }
506}
507
508impl XNodeWrite for Surface {
509 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
510 let mut e = Self::elem();
511 e.print_attr("type", self.ty);
512 let e = e.start(w)?;
513 self.init.write_to(w)?;
514 opt(&self.format, |e| ElemBuilder::print_str("format", e, w))?;
515 self.format_hint.write_to(w)?;
516 opt(&self.size, |e| ElemBuilder::print_arr("size", &**e, w))?;
517 opt(&self.viewport_ratio, |e| {
518 ElemBuilder::print_arr("viewport_ratio", &**e, w)
519 })?;
520 ElemBuilder::def_print("mip_levels", self.mip_levels, 0, w)?;
521 ElemBuilder::def_print("mipmap_generate", self.mipmap_generate, false, w)?;
522 self.extra.write_to(w)?;
523 e.end(w)
524 }
525}
526
527#[derive(Clone, Copy, Debug, PartialEq, Eq)]
529pub enum SurfaceType {
530 Untyped,
539 _1D,
541 _2D,
543 _3D,
545 Rect,
547 Cube,
549 Depth,
551}
552
553impl Default for SurfaceType {
554 fn default() -> Self {
555 Self::Untyped
556 }
557}
558
559impl FromStr for SurfaceType {
560 type Err = ();
561
562 fn from_str(s: &str) -> Result<Self, Self::Err> {
563 match s {
564 "UNTYPED" => Ok(Self::Untyped),
565 "1D" => Ok(Self::_1D),
566 "2D" => Ok(Self::_2D),
567 "3D" => Ok(Self::_3D),
568 "RECT" => Ok(Self::Rect),
569 "CUBE" => Ok(Self::Cube),
570 "DEPTH" => Ok(Self::Depth),
571 _ => Err(()),
572 }
573 }
574}
575
576impl SurfaceType {
577 pub fn to_str(self) -> &'static str {
579 match self {
580 Self::Untyped => "UNTYPED",
581 Self::_1D => "1D",
582 Self::_2D => "2D",
583 Self::_3D => "3D",
584 Self::Rect => "RECT",
585 Self::Cube => "CUBE",
586 Self::Depth => "DEPTH",
587 }
588 }
589}
590
591impl Display for SurfaceType {
592 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
593 Display::fmt(self.to_str(), f)
594 }
595}
596
597#[derive(Clone, Debug)]
600pub struct FormatHint {
601 pub channels: SurfaceChannels,
603 pub range: SurfaceRange,
605 pub precision: SurfacePrecision,
607 pub options: Vec<SurfaceOption>,
610 pub extra: Vec<Extra>,
612}
613
614impl FormatHint {
615 pub fn new(
617 channels: SurfaceChannels,
618 range: SurfaceRange,
619 precision: SurfacePrecision,
620 ) -> Self {
621 Self {
622 channels,
623 range,
624 precision,
625 options: vec![],
626 extra: vec![],
627 }
628 }
629}
630
631impl XNode for FormatHint {
632 const NAME: &'static str = "format_hint";
633 fn parse(element: &Element) -> Result<Self> {
634 debug_assert_eq!(element.name(), Self::NAME);
635 let mut it = element.children().peekable();
636 Ok(FormatHint {
637 channels: parse_one("channels", &mut it, parse_elem)?,
638 range: parse_one("range", &mut it, parse_elem)?,
639 precision: parse_one("precision", &mut it, parse_elem)?,
640 options: parse_list("option", &mut it, parse_elem)?,
641 extra: Extra::parse_many(it)?,
642 })
643 }
644}
645
646impl XNodeWrite for FormatHint {
647 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
648 let e = Self::elem().start(w)?;
649 ElemBuilder::print("channels", &self.channels, w)?;
650 ElemBuilder::print("range", &self.range, w)?;
651 ElemBuilder::print("precision", &self.precision, w)?;
652 many(&self.options, |e| ElemBuilder::print("option", e, w))?;
653 self.extra.write_to(w)?;
654 e.end(w)
655 }
656}
657
658#[derive(Clone, Debug)]
661pub enum SurfaceInit {
662 Null,
669 Target,
672 From {
683 mip: u32,
685 slice: u32,
690 face: SurfaceFace,
694 image: NameRef<Image>,
697 },
698}
699
700impl SurfaceInit {
701 pub fn init_from(image: impl Into<String>) -> Self {
703 Self::From {
704 mip: 0,
705 slice: 0,
706 face: Default::default(),
707 image: Ref::new(image.into()),
708 }
709 }
710 pub fn parse(element: &Element) -> Result<Option<Self>> {
712 Ok(Some(match element.name() {
713 "init_as_null" => Self::Null,
714 "init_as_target" => Self::Target,
715 "init_cube" | "init_volume" | "init_planar" => unimplemented!(),
716 "init_from" => Self::From {
717 mip: parse_attr(element.attr("mip"))?.unwrap_or(0),
718 slice: parse_attr(element.attr("slice"))?.unwrap_or(0),
719 face: parse_attr(element.attr("face"))?.unwrap_or_default(),
720 image: parse_elem(element)?,
721 },
722 _ => return Ok(None),
723 }))
724 }
725}
726
727impl XNodeWrite for SurfaceInit {
728 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
729 match self {
730 Self::Null => ElemBuilder::new("init_as_null").end(w),
731 Self::Target => ElemBuilder::new("init_as_target").end(w),
732 &Self::From {
733 mip,
734 slice,
735 face,
736 ref image,
737 } => {
738 let mut e = ElemBuilder::new("init_from");
739 e.def_print_attr("mip", mip, 0);
740 e.def_print_attr("slice", slice, 0);
741 e.def_print_attr("face", face, Default::default());
742 let e = e.start(w)?;
743 print_elem(image, w)?;
744 e.end(w)
745 }
746 }
747 }
748}
749
750#[derive(Clone, Copy, Debug, PartialEq, Eq)]
752pub enum SurfaceFace {
753 PosX,
755 NegX,
757 PosY,
759 NegY,
761 PosZ,
763 NegZ,
765}
766
767impl Default for SurfaceFace {
768 fn default() -> Self {
769 Self::PosX
770 }
771}
772
773impl FromStr for SurfaceFace {
774 type Err = ();
775
776 fn from_str(s: &str) -> Result<Self, Self::Err> {
777 match s {
778 "POSITIVE_X" => Ok(Self::PosX),
779 "NEGATIVE_X" => Ok(Self::NegX),
780 "POSITIVE_Y" => Ok(Self::PosY),
781 "NEGATIVE_Y" => Ok(Self::NegY),
782 "POSITIVE_Z" => Ok(Self::PosZ),
783 "NEGATIVE_Z" => Ok(Self::NegZ),
784 _ => Err(()),
785 }
786 }
787}
788
789impl SurfaceFace {
790 pub fn to_str(self) -> &'static str {
792 match self {
793 Self::PosX => "POSITIVE_X",
794 Self::NegX => "NEGATIVE_X",
795 Self::PosY => "POSITIVE_Y",
796 Self::NegY => "NEGATIVE_Y",
797 Self::PosZ => "POSITIVE_Z",
798 Self::NegZ => "NEGATIVE_Z",
799 }
800 }
801}
802
803impl Display for SurfaceFace {
804 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
805 Display::fmt(self.to_str(), f)
806 }
807}
808
809#[derive(Clone, Copy, Debug, PartialEq, Eq)]
813pub enum SurfaceChannels {
814 RGB,
816 RGBA,
819 L,
821 LA,
823 D,
825 XYZ,
827 XYZW,
829}
830
831impl FromStr for SurfaceChannels {
832 type Err = ();
833
834 fn from_str(s: &str) -> Result<Self, Self::Err> {
835 match s {
836 "RGB" => Ok(Self::RGB),
837 "RGBA" => Ok(Self::RGBA),
838 "L" => Ok(Self::L),
839 "LA" => Ok(Self::LA),
840 "D" => Ok(Self::D),
841 "XYZ" => Ok(Self::XYZ),
842 "XYZW" => Ok(Self::XYZW),
843 _ => Err(()),
844 }
845 }
846}
847
848impl SurfaceChannels {
849 pub fn to_str(self) -> &'static str {
851 match self {
852 Self::RGB => "RGB",
853 Self::RGBA => "RGBA",
854 Self::L => "L",
855 Self::LA => "LA",
856 Self::D => "D",
857 Self::XYZ => "XYZ",
858 Self::XYZW => "XYZW",
859 }
860 }
861}
862
863impl Display for SurfaceChannels {
864 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
865 Display::fmt(self.to_str(), f)
866 }
867}
868
869#[derive(Clone, Copy, Debug, PartialEq, Eq)]
874pub enum SurfaceRange {
875 SNorm,
878 UNorm,
881 SInt,
884 UInt,
887 Float,
889}
890
891impl FromStr for SurfaceRange {
892 type Err = ();
893
894 fn from_str(s: &str) -> Result<Self, Self::Err> {
895 match s {
896 "SNORM" => Ok(Self::SNorm),
897 "UNORM" => Ok(Self::UNorm),
898 "SINT" => Ok(Self::SInt),
899 "UINT" => Ok(Self::UInt),
900 "FLOAT" => Ok(Self::Float),
901 _ => Err(()),
902 }
903 }
904}
905
906impl SurfaceRange {
907 pub fn to_str(self) -> &'static str {
909 match self {
910 Self::SNorm => "SNORM",
911 Self::UNorm => "UNORM",
912 Self::SInt => "SINT",
913 Self::UInt => "UINT",
914 Self::Float => "FLOAT",
915 }
916 }
917}
918
919impl Display for SurfaceRange {
920 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
921 Display::fmt(self.to_str(), f)
922 }
923}
924
925#[derive(Clone, Copy, Debug, PartialEq, Eq)]
931pub enum SurfacePrecision {
932 Low,
935 Mid,
938 High,
941}
942
943impl FromStr for SurfacePrecision {
944 type Err = ();
945
946 fn from_str(s: &str) -> Result<Self, Self::Err> {
947 match s {
948 "LOW" => Ok(Self::Low),
949 "MID" => Ok(Self::Mid),
950 "HIGH" => Ok(Self::High),
951 _ => Err(()),
952 }
953 }
954}
955
956impl SurfacePrecision {
957 pub fn to_str(self) -> &'static str {
959 match self {
960 Self::Low => "LOW",
961 Self::Mid => "MID",
962 Self::High => "HIGH",
963 }
964 }
965}
966
967impl Display for SurfacePrecision {
968 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
969 Display::fmt(self.to_str(), f)
970 }
971}
972
973#[derive(Clone, Copy, Debug, PartialEq, Eq)]
976pub enum SurfaceOption {
977 SrgbGamma,
980 Normalized3,
983 Normalized4,
986 Compressible,
990}
991
992impl FromStr for SurfaceOption {
993 type Err = ();
994
995 fn from_str(s: &str) -> Result<Self, Self::Err> {
996 match s {
997 "SRGB_GAMMA" => Ok(Self::SrgbGamma),
998 "NORMALIZED3" => Ok(Self::Normalized3),
999 "NORMALIZED4" => Ok(Self::Normalized4),
1000 "COMPRESSABLE" => Ok(Self::Compressible),
1001 _ => Err(()),
1002 }
1003 }
1004}
1005
1006impl SurfaceOption {
1007 pub fn to_str(self) -> &'static str {
1009 match self {
1010 Self::SrgbGamma => "SRGB_GAMMA",
1011 Self::Normalized3 => "NORMALIZED3",
1012 Self::Normalized4 => "NORMALIZED4",
1013 Self::Compressible => "COMPRESSABLE",
1014 }
1015 }
1016}
1017
1018impl Display for SurfaceOption {
1019 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1020 Display::fmt(self.to_str(), f)
1021 }
1022}