Skip to main content

sl_types/
environment.rs

1//! Extended Environment (EEP) value types: the colour, glow, and cloud
2//! parameters carried by a region's or parcel's sky and water settings.
3//!
4//! These are distinct named types (rather than bare `[f32; N]`) so a colour
5//! cannot be transposed with a position, a direction, a scale, or a rotation —
6//! all of which are also arrays of `f32`.
7
8/// An RGB colour — three `f32` channels (normally `0.0..=1.0`, but HDR
9/// environment colours can exceed `1.0`). A named type so a colour cannot be
10/// transposed with a position, direction, or scale.
11#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
12pub struct Color {
13    /// The red channel.
14    red: f32,
15    /// The green channel.
16    green: f32,
17    /// The blue channel.
18    blue: f32,
19}
20
21impl Color {
22    /// Creates a colour from its red/green/blue channels.
23    #[must_use]
24    pub const fn new(red: f32, green: f32, blue: f32) -> Self {
25        Self { red, green, blue }
26    }
27
28    /// The red channel.
29    #[must_use]
30    pub const fn red(&self) -> f32 {
31        self.red
32    }
33
34    /// The green channel.
35    #[must_use]
36    pub const fn green(&self) -> f32 {
37        self.green
38    }
39
40    /// The blue channel.
41    #[must_use]
42    pub const fn blue(&self) -> f32 {
43        self.blue
44    }
45}
46
47/// An RGBA colour — four `f32` channels (RGB plus an alpha channel). The
48/// alpha-carrying sibling of [`Color`]; a distinct type so it can't be
49/// transposed with a 3-channel colour, a position, or a rotation quaternion
50/// (all of which are also arrays of `f32`). Its one wire user is the windlight
51/// `sunlight_color`. Channels are normally `0.0..=1.0` but HDR values can
52/// exceed `1.0`.
53#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
54pub struct ColorAlpha {
55    /// The red channel.
56    red: f32,
57    /// The green channel.
58    green: f32,
59    /// The blue channel.
60    blue: f32,
61    /// The alpha channel.
62    alpha: f32,
63}
64
65impl ColorAlpha {
66    /// Creates a colour from its red/green/blue/alpha channels.
67    #[must_use]
68    pub const fn new(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
69        Self {
70            red,
71            green,
72            blue,
73            alpha,
74        }
75    }
76
77    /// The red channel.
78    #[must_use]
79    pub const fn red(&self) -> f32 {
80        self.red
81    }
82
83    /// The green channel.
84    #[must_use]
85    pub const fn green(&self) -> f32 {
86        self.green
87    }
88
89    /// The blue channel.
90    #[must_use]
91    pub const fn blue(&self) -> f32 {
92        self.blue
93    }
94
95    /// The alpha channel.
96    #[must_use]
97    pub const fn alpha(&self) -> f32 {
98        self.alpha
99    }
100}
101
102/// A windlight sun/moon **glow** parameter. The wire packs it as a 3-vector
103/// `(size, reserved, focus)` whose middle component is unused/reserved (the
104/// viewer always sends `0`); it is preserved verbatim so a decode/encode round
105/// trip is byte-identical. The meaningful channels are [`size`](Self::size) and
106/// [`focus`](Self::focus).
107#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
108pub struct Glow {
109    /// The glow size.
110    size: f32,
111    /// The unused/reserved middle component (preserved for round-trip).
112    reserved: f32,
113    /// The glow focus.
114    focus: f32,
115}
116
117impl Glow {
118    /// Creates a glow from its wire `(size, reserved, focus)` components.
119    #[must_use]
120    pub const fn new(size: f32, reserved: f32, focus: f32) -> Self {
121        Self {
122            size,
123            reserved,
124            focus,
125        }
126    }
127
128    /// The glow size.
129    #[must_use]
130    pub const fn size(&self) -> f32 {
131        self.size
132    }
133
134    /// The unused/reserved middle component (normally `0`).
135    #[must_use]
136    pub const fn reserved(&self) -> f32 {
137        self.reserved
138    }
139
140    /// The glow focus.
141    #[must_use]
142    pub const fn focus(&self) -> f32 {
143        self.focus
144    }
145}
146
147/// A windlight cloud layer's scroll **position** (X, Y) packed with its
148/// **density** (Z) in one wire 3-vector (the viewer's `cloud_pos_density*`).
149/// The three components are semantically distinct — two are a 2-D scroll offset,
150/// one is a density — so they get named accessors rather than `x`/`y`/`z`, and
151/// this type cannot be confused with a position or direction.
152#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
153pub struct CloudPosDensity {
154    /// The cloud-scroll x position.
155    position_x: f32,
156    /// The cloud-scroll y position.
157    position_y: f32,
158    /// The cloud density.
159    density: f32,
160}
161
162impl CloudPosDensity {
163    /// Creates a value from its wire `(position_x, position_y, density)`
164    /// components.
165    #[must_use]
166    pub const fn new(position_x: f32, position_y: f32, density: f32) -> Self {
167        Self {
168            position_x,
169            position_y,
170            density,
171        }
172    }
173
174    /// The cloud-scroll x position.
175    #[must_use]
176    pub const fn position_x(&self) -> f32 {
177        self.position_x
178    }
179
180    /// The cloud-scroll y position.
181    #[must_use]
182    pub const fn position_y(&self) -> f32 {
183        self.position_y
184    }
185
186    /// The cloud density.
187    #[must_use]
188    pub const fn density(&self) -> f32 {
189        self.density
190    }
191}