lotus_shared/
graphics.rs

1use serde::{Deserialize, Serialize};
2
3#[cfg(feature = "internal")]
4use crate::content::ContentId;
5
6/// A color in the RGBA format.
7#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
8pub struct Color {
9    pub r: u8,
10    pub g: u8,
11    pub b: u8,
12    pub a: u8,
13}
14
15impl Color {
16    pub const WHITE: Self = Self::rgb(255, 255, 255);
17    pub const BLACK: Self = Self::rgb(0, 0, 0);
18    pub const RED: Self = Self::rgb(255, 0, 0);
19    pub const GREEN: Self = Self::rgb(0, 255, 0);
20    pub const BLUE: Self = Self::rgb(0, 0, 255);
21    pub const YELLOW: Self = Self::rgb(255, 255, 0);
22    pub const CYAN: Self = Self::rgb(0, 255, 255);
23    pub const MAGENTA: Self = Self::rgb(255, 0, 255);
24
25    pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
26        Self::rgba(r, g, b, 255)
27    }
28
29    pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
30        Self { r, g, b, a }
31    }
32}
33
34impl From<u32> for Color {
35    fn from(value: u32) -> Self {
36        let r = ((value >> 24) & 0xFF) as u8;
37        let g = ((value >> 16) & 0xFF) as u8;
38        let b = ((value >> 8) & 0xFF) as u8;
39        let a = (value & 0xFF) as u8;
40
41        Color::rgba(r, g, b, a)
42    }
43}
44
45impl From<Color> for u32 {
46    fn from(value: Color) -> Self {
47        let r = value.r as u32;
48        let g = value.g as u32;
49        let b = value.b as u32;
50        let a = value.a as u32;
51
52        (r << 24) | (g << 16) | (b << 8) | a
53    }
54}
55
56#[cfg(feature = "bevy")]
57mod _bevy {
58    use super::*;
59
60    impl From<bevy::color::Color> for Color {
61        fn from(value: bevy::color::Color) -> Self {
62            let value = value.to_srgba();
63
64            Self::rgba(
65                (value.red * 255.0) as u8,
66                (value.green * 255.0) as u8,
67                (value.blue * 255.0) as u8,
68                (value.alpha * 255.0) as u8,
69            )
70        }
71    }
72
73    impl From<Color> for bevy::color::Color {
74        fn from(value: Color) -> Self {
75            bevy::color::Color::srgba(
76                value.r as f32 / 255.0,
77                value.g as f32 / 255.0,
78                value.b as f32 / 255.0,
79                value.a as f32 / 255.0,
80            )
81        }
82    }
83}
84
85#[cfg(feature = "image")]
86mod _image {
87    use super::*;
88
89    impl From<image::Rgba<u8>> for Color {
90        fn from(value: image::Rgba<u8>) -> Self {
91            Self::rgba(value[0], value[1], value[2], value[3])
92        }
93    }
94
95    impl From<Color> for image::Rgba<u8> {
96        fn from(value: Color) -> Self {
97            [value.r, value.g, value.b, value.a].into()
98        }
99    }
100}
101
102pub mod textures {
103    use std::borrow::Cow;
104
105    use glam::IVec2;
106    use serde::{Deserialize, Serialize};
107
108    use crate::{
109        content::ContentId,
110        math::{Rectangle, UVec2},
111    };
112
113    use super::Color;
114
115    /// Options for creating a texture.
116    #[derive(Clone, Serialize, Deserialize)]
117    pub struct TextureCreationOptions<'a> {
118        /// The width of the texture.
119        pub width: u32,
120        /// The height of the texture.
121        pub height: u32,
122        /// The data of the texture. This is currently a placeholder for future use.
123        pub data: Option<Cow<'a, [u8]>>,
124        /// Whether to generate mipmaps for the texture.
125        pub mipmaps: bool,
126    }
127
128    impl From<(u32, u32)> for TextureCreationOptions<'_> {
129        fn from((width, height): (u32, u32)) -> Self {
130            Self {
131                width,
132                height,
133                data: None,
134                mipmaps: false,
135            }
136        }
137    }
138
139    /// A handle to a texture.
140    #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
141    #[serde(transparent)]
142    pub struct TextureHandle(u32);
143
144    #[cfg(feature = "internal")]
145    impl TextureHandle {
146        /// Create a new texture handle.
147        pub fn new(value: u32) -> Self {
148            Self(value)
149        }
150
151        /// Get the ID of the texture handle.
152        pub fn id(&self) -> u32 {
153            self.0
154        }
155    }
156
157    /// An action to perform on a texture.
158    #[derive(Clone, Serialize, Deserialize)]
159    pub enum TextureAction {
160        /// Clear the texture with a color.
161        Clear(Color),
162        /// Draw pixels on the texture.
163        DrawPixels(Box<[DrawPixel]>),
164        /// Draw a rectangle on the texture.
165        DrawRect {
166            start: UVec2,
167            end: UVec2,
168            color: Color,
169        },
170        /// Draw text on the texture.
171        DrawText {
172            font: ContentId,
173            text: String,
174            top_left: IVec2,
175            letter_spacing: u32,
176            full_color: Option<Color>,
177            alpha_mode: AlphaMode,
178            target_rect: Option<Rectangle>,
179        },
180        // DrawTexture {
181        //     texture: ContentId,
182        //     options: DrawTextureOpts,
183        // },
184        /// Draw a script texture on the texture.
185        DrawScriptTexture {
186            handle: TextureHandle,
187            options: DrawTextureOpts,
188        },
189    }
190
191    /// Controls how alpha (transparency) is handled when drawing.
192    #[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
193    pub enum AlphaMode {
194        /// The texture is drawn completely opaque, ignoring alpha values.
195        /// Any pixels drawn will completely replace the existing pixels.
196        #[default]
197        Opaque,
198        /// Alpha values below the threshold are considered fully transparent,
199        /// while values above or equal to the threshold are considered fully opaque.
200        /// The threshold should be between 0.0 and 1.0.
201        Mask(f32),
202        /// Alpha values are used to blend the new pixels with existing pixels.
203        /// The alpha channel determines the opacity of each pixel being drawn.
204        Blend,
205    }
206
207    /// Options for drawing a texture.
208    #[derive(Default, Clone, Copy, Serialize, Deserialize)]
209    pub struct DrawTextureOpts {
210        /// The source rectangle of the texture to draw.
211        pub source_rect: Option<Rectangle>,
212        /// The target rectangle of the texture to draw to.
213        pub target_rect: Option<Rectangle>,
214    }
215
216    /// A pixel to draw on a texture.
217    #[derive(Clone, Copy, Serialize, Deserialize)]
218    pub struct DrawPixel {
219        /// The position of the pixel.
220        pub pos: UVec2,
221        /// The color of the pixel.
222        pub color: Color,
223    }
224
225    impl From<(UVec2, Color)> for DrawPixel {
226        fn from((position, color): (UVec2, Color)) -> Self {
227            Self {
228                pos: position,
229                color,
230            }
231        }
232    }
233
234    impl From<(u32, u32, Color)> for DrawPixel {
235        fn from((x, y, color): (u32, u32, Color)) -> Self {
236            Self {
237                pos: UVec2 { x, y },
238                color,
239            }
240        }
241    }
242}
243
244#[cfg(feature = "internal")]
245#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct DrawableTextureProperties {
247    pub width: u32,
248    pub height: u32,
249    pub texture_variable_id: String,
250    pub font: ContentId,
251    pub text_variable_id: String,
252    pub set_color: bool,
253    pub color: Color,
254    pub horizontal_alignment: TextHorizontalAlignment,
255    pub vertical_alignment: TextVerticalAlignment,
256    pub alignment_resolution: u8,
257}
258
259#[cfg(feature = "internal")]
260#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
261pub enum TextHorizontalAlignment {
262    #[default]
263    Center,
264    Left,
265    Right,
266    IntCenterLeft,
267    IntCenterRight,
268}
269
270#[cfg(feature = "internal")]
271#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
272pub enum TextVerticalAlignment {
273    #[default]
274    Center,
275    Top,
276    Bottom,
277}