1use std::ops::{Mul, MulAssign};
2
3use crate::c::c_float;
4
5#[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}