swamp_render/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5pub mod anim;
6pub mod prelude;
7
8use int_math::UVec2;
9use std::fmt;
10
11pub enum VirtualScale {
12    IntScale(u16),
13    FloatScale(f32),
14}
15
16fn gcd(a: u16, b: u16) -> u16 {
17    if b == 0 {
18        a
19    } else {
20        gcd(b, a % b)
21    }
22}
23
24fn aspect_ratio(size: UVec2) -> (u16, u16) {
25    let divisor = gcd(size.x, size.y);
26    (size.x / divisor, size.y / divisor)
27}
28
29#[derive(Debug)]
30pub enum AspectRatio {
31    Ratio16By9,
32    Ratio21By9,
33    Ratio16By10,
34    Ratio4By3,
35    Other(f32),
36}
37
38impl AspectRatio {
39    fn convert(value: UVec2) -> Self {
40        let aspect = aspect_ratio(value);
41        match aspect {
42            (16, 9) => Self::Ratio16By9,
43            (21, 9) => Self::Ratio21By9,
44            (16, 10) => Self::Ratio16By10,
45            (4, 3) => Self::Ratio4By3,
46            _ => Self::Other(value.x as f32 / value.y as f32),
47        }
48    }
49}
50
51impl From<(u16, u16)> for AspectRatio {
52    fn from(value: (u16, u16)) -> Self {
53        Self::convert(value.into())
54    }
55}
56
57impl From<UVec2> for AspectRatio {
58    fn from(value: UVec2) -> Self {
59        Self::convert(value)
60    }
61}
62
63impl fmt::Display for AspectRatio {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        match self {
66            Self::Ratio16By9 => write!(f, "16:9"),
67            Self::Ratio16By10 => write!(f, "16:10"),
68            Self::Ratio21By9 => write!(f, "21:9"),
69            Self::Ratio4By3 => write!(f, "4:3"),
70            Self::Other(vec) => write!(f, "aspect ratio: {vec:?}"),
71        }
72    }
73}
74
75#[derive(Debug, Copy, Clone)]
76pub struct Color {
77    r: u8,
78    g: u8,
79    b: u8,
80    a: u8,
81}
82
83impl Default for Color {
84    fn default() -> Self {
85        Self {
86            r: 255,
87            g: 255,
88            b: 255,
89            a: 255,
90        }
91    }
92}
93
94impl Color {
95    #[must_use]
96    pub fn from_f32(r: f32, g: f32, b: f32, a: f32) -> Self {
97        Self::from_octet(
98            (r * 255.0) as u8,
99            (g * 255.0) as u8,
100            (b * 255.0) as u8,
101            (a * 255.0) as u8,
102        )
103    }
104
105    #[must_use]
106    pub fn to_f32_slice(&self) -> [f32; 4] {
107        [
108            self.r as f32 / 255.0,
109            self.g as f32 / 255.0,
110            self.b as f32 / 255.0,
111            self.a as f32 / 255.0,
112        ]
113    }
114
115    #[must_use]
116    pub const fn from_octet(r: u8, g: u8, b: u8, a: u8) -> Self {
117        Self { r, g, b, a }
118    }
119
120    #[must_use]
121    pub fn to_f64(&self) -> (f64, f64, f64, f64) {
122        (
123            self.r as f64 / 255.0,
124            self.g as f64 / 255.0,
125            self.b as f64 / 255.0,
126            self.a as f64 / 255.0,
127        )
128    }
129}
130
131#[derive(Debug, Eq, PartialEq)]
132pub enum ViewportStrategy {
133    /// Tries to set the viewport to fit the virtual surface size within the physical surface size.
134    /// Depending on resolution, it can cause black borders, both vertically and horizontally.
135    /// Always keeps the aspect ratio, and is "pixel perfect"
136    FitIntegerScaling(UVec2),
137
138    /// Tries to set the viewport to fit the virtual surface size within the physical surface size.
139    /// Depending on resolution, it can cause "black borders", *either* vertically and horizontally.
140    /// Always keeps the aspect ratio, but might not be pixel perfect
141    FitFloatScaling(UVec2),
142
143    /// The viewport will be the same as the physical size.
144    MatchPhysicalSize,
145}