rusty_spine/
color.rs

1use std::ops::{Mul, MulAssign};
2
3use crate::c::c_float;
4
5/// RGBA F32 color that is byte-compatible with the Spine runtime.
6#[derive(Copy, Clone, Debug, Default, PartialEq)]
7#[repr(C)]
8pub struct Color {
9    pub r: c_float,
10    pub g: c_float,
11    pub b: c_float,
12    pub a: c_float,
13}
14
15impl Color {
16    #[must_use]
17    pub const fn new_rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
18        Self { r, g, b, a }
19    }
20
21    pub fn set_r(&mut self, r: c_float) -> &mut Self {
22        self.r = r;
23        self
24    }
25
26    pub fn set_g(&mut self, g: c_float) -> &mut Self {
27        self.g = g;
28        self
29    }
30
31    pub fn set_b(&mut self, b: c_float) -> &mut Self {
32        self.b = b;
33        self
34    }
35
36    pub fn set_a(&mut self, a: c_float) -> &mut Self {
37        self.a = a;
38        self
39    }
40
41    pub fn set_from_floats(&mut self, r: c_float, g: c_float, b: c_float, a: c_float) -> &mut Self {
42        self.r = r;
43        self.g = g;
44        self.b = b;
45        self.a = a;
46        self.clamp();
47        self
48    }
49
50    pub fn set_from_floats3(&mut self, r: c_float, g: c_float, b: c_float) -> &mut Self {
51        self.r = r;
52        self.g = g;
53        self.b = b;
54        self.clamp();
55        self
56    }
57
58    pub fn set_from_color(&mut self, other: &Color) -> &mut Self {
59        self.r = other.r;
60        self.g = other.g;
61        self.b = other.b;
62        self.a = other.a;
63        self
64    }
65
66    pub fn set_from_color3(&mut self, other: &Color) -> &mut Self {
67        self.r = other.r;
68        self.g = other.g;
69        self.b = other.b;
70        self
71    }
72
73    pub fn add_floats(&mut self, r: c_float, g: c_float, b: c_float, a: c_float) -> &mut Self {
74        self.r += r;
75        self.g += g;
76        self.b += b;
77        self.a += a;
78        self.clamp();
79        self
80    }
81
82    pub fn add_floats3(&mut self, r: c_float, g: c_float, b: c_float) -> &mut Self {
83        self.r += r;
84        self.g += g;
85        self.b += b;
86        self.clamp();
87        self
88    }
89
90    pub fn add_color(&mut self, other: &Color) -> &mut Self {
91        self.r += other.r;
92        self.g += other.g;
93        self.b += other.b;
94        self.a += other.a;
95        self.clamp();
96        self
97    }
98
99    pub fn clamp(&mut self) -> &mut Self {
100        self.r = self.r.clamp(0., 1.);
101        self.g = self.r.clamp(0., 1.);
102        self.b = self.r.clamp(0., 1.);
103        self.a = self.r.clamp(0., 1.);
104        self
105    }
106
107    pub fn premultiply_alpha(&mut self) {
108        self.r *= self.a;
109        self.g *= self.a;
110        self.b *= self.a;
111    }
112
113    #[must_use]
114    pub fn linear_to_nonlinear(&self) -> Color {
115        Color {
116            r: linear_to_nonlinear(self.r),
117            g: linear_to_nonlinear(self.g),
118            b: linear_to_nonlinear(self.b),
119            a: self.a,
120        }
121    }
122
123    #[must_use]
124    pub fn nonlinear_to_linear(&self) -> Color {
125        Color {
126            r: nonlinear_to_linear(self.r),
127            g: nonlinear_to_linear(self.g),
128            b: nonlinear_to_linear(self.b),
129            a: self.a,
130        }
131    }
132}
133
134impl Mul<f32> for Color {
135    type Output = Color;
136
137    fn mul(self, rhs: f32) -> Self::Output {
138        Color {
139            r: self.r * rhs,
140            g: self.g * rhs,
141            b: self.b * rhs,
142            a: self.a * rhs,
143        }
144    }
145}
146
147impl Mul<Color> for Color {
148    type Output = Color;
149
150    fn mul(self, rhs: Color) -> Self::Output {
151        Color {
152            r: self.r * rhs.r,
153            g: self.g * rhs.g,
154            b: self.b * rhs.b,
155            a: self.a * rhs.a,
156        }
157    }
158}
159
160impl MulAssign<f32> for Color {
161    fn mul_assign(&mut self, rhs: f32) {
162        self.r *= rhs;
163        self.g *= rhs;
164        self.b *= rhs;
165        self.a *= rhs;
166    }
167}
168
169impl MulAssign<Color> for Color {
170    fn mul_assign(&mut self, rhs: Color) {
171        self.r *= rhs.r;
172        self.g *= rhs.g;
173        self.b *= rhs.b;
174        self.a *= rhs.a;
175    }
176}
177
178impl From<[f32; 4]> for Color {
179    fn from(value: [f32; 4]) -> Self {
180        Self {
181            r: value[0],
182            g: value[1],
183            b: value[2],
184            a: value[3],
185        }
186    }
187}
188
189fn linear_to_nonlinear(x: f32) -> f32 {
190    if x <= 0.0 {
191        x
192    } else if x <= 0.0031308 {
193        x * 12.92
194    } else {
195        (1.055 * x.powf(1.0 / 2.4)) - 0.055
196    }
197}
198
199fn nonlinear_to_linear(x: f32) -> f32 {
200    if x <= 0.0 {
201        x
202    } else if x <= 0.04045 {
203        x / 12.92
204    } else {
205        ((x + 0.055) / 1.055).powf(2.4)
206    }
207}