mireforge_render/
lib.rs

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