1#include <algorithm>
2#include <cmath>
3
4#include <gfx/seadColor.h>
5#include <math/seadMathCalcCommon.h>
6
7namespace sead
8{
9const Color4f Color4f::cBlack(0.0f, 0.0f, 0.0f, 1.0f);
10const Color4f Color4f::cGray(0.5f, 0.5f, 0.5f, 1.0f);
11const Color4f Color4f::cWhite(1.0f, 1.0f, 1.0f, 1.0f);
12const Color4f Color4f::cRed(1.0f, 0.0f, 0.0f, 1.0f);
13const Color4f Color4f::cGreen(0.0f, 1.0f, 0.0f, 1.0f);
14const Color4f Color4f::cBlue(0.0f, 0.0f, 1.0f, 1.0f);
15const Color4f Color4f::cYellow(1.0f, 1.0f, 0.0f, 1.0f);
16const Color4f Color4f::cMagenta(1.0f, 0.0f, 1.0f, 1.0f);
17const Color4f Color4f::cCyan(0.0f, 1.0f, 1.0f, 1.0f);
18const f32 Color4f::cElementMax = 1.0f;
19const f32 Color4f::cElementMin = 0.0f;
20
21Color4f Color4f::lerp(const Color4f& color1, const Color4f& color2, f32 t)
22{
23 t = sead::Mathf::clamp(value: t, low: cElementMin, high: cElementMax);
24 const f32 a = sead::lerp(a: color1.a, b: color2.a, t);
25 const f32 r = sead::lerp(a: color1.r, b: color2.r, t);
26 const f32 g = sead::lerp(a: color1.g, b: color2.g, t);
27 const f32 b = sead::lerp(a: color1.b, b: color2.b, t);
28 return {r, g, b, a};
29}
30
31void Color4f::setLerp(const Color4f& color1, const Color4f& color2, f32 t)
32{
33 t = sead::Mathf::clamp(value: t, low: cElementMin, high: cElementMax);
34 a = sead::lerp(a: color1.a, b: color2.a, t);
35 r = sead::lerp(a: color1.r, b: color2.r, t);
36 g = sead::lerp(a: color1.g, b: color2.g, t);
37 b = sead::lerp(a: color1.b, b: color2.b, t);
38}
39
40void Color4f::setGammaCollection(const Color4f& value, f32 gamma)
41{
42 a = value.a;
43 r = std::pow(lcpp_x: value.r, lcpp_y: gamma);
44 g = std::pow(lcpp_x: value.g, lcpp_y: gamma);
45 b = std::pow(lcpp_x: value.b, lcpp_y: gamma);
46}
47
48void Color4f::adjustOverflow()
49{
50 r = sead::Mathf::clamp(value: r, low: cElementMin, high: cElementMax);
51 g = sead::Mathf::clamp(value: g, low: cElementMin, high: cElementMax);
52 b = sead::Mathf::clamp(value: b, low: cElementMin, high: cElementMax);
53 a = sead::Mathf::clamp(value: a, low: cElementMin, high: cElementMax);
54}
55
56#define SEAD_COLOR4F_OPERATORS(OP, OP2) \
57 Color4f& Color4f::operator OP(const Color4f& rhs) \
58 { \
59 r OP rhs.r; \
60 g OP rhs.g; \
61 b OP rhs.b; \
62 a OP rhs.a; \
63 return *this; \
64 } \
65 Color4f& Color4f::operator OP(f32 x) \
66 { \
67 r OP x; \
68 g OP x; \
69 b OP x; \
70 a OP x; \
71 return *this; \
72 } \
73 Color4f operator OP2(const Color4f& lhs, const Color4f& rhs) \
74 { \
75 Color4f result = lhs; \
76 result OP rhs; \
77 return result; \
78 } \
79 Color4f operator OP2(const Color4f& lhs, f32 x) \
80 { \
81 Color4f result = lhs; \
82 result OP x; \
83 return result; \
84 }
85
86SEAD_COLOR4F_OPERATORS(+=, +)
87SEAD_COLOR4F_OPERATORS(-=, -)
88SEAD_COLOR4F_OPERATORS(*=, *)
89SEAD_COLOR4F_OPERATORS(/=, /)
90
91bool operator==(const Color4f& lhs, const Color4f& rhs)
92{
93 return lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && lhs.a == rhs.a;
94}
95
96const Color4u8 Color4u8::cBlack(0, 0, 0, 255);
97const Color4u8 Color4u8::cGray(128, 128, 128, 255);
98const Color4u8 Color4u8::cWhite(255, 255, 255, 255);
99const Color4u8 Color4u8::cRed(255, 0, 0, 255);
100const Color4u8 Color4u8::cGreen(0, 255, 0, 255);
101const Color4u8 Color4u8::cBlue(0, 0, 255, 255);
102const Color4u8 Color4u8::cYellow(255, 255, 0, 255);
103const Color4u8 Color4u8::cMagenta(255, 0, 255, 255);
104const Color4u8 Color4u8::cCyan(0, 255, 255, 255);
105const u8 Color4u8::cElementMax = 255;
106const u8 Color4u8::cElementMin = 0;
107
108// NON_MATCHING: but semantically equivalent (setLerp is matching after all)
109Color4u8 Color4u8::lerp(const Color4u8& color1, const Color4u8& color2, f32 t)
110{
111 Color4u8 result = color1;
112 result.setLerp(color1, color2, t);
113 return result;
114}
115
116void Color4u8::setf(f32 fr, f32 fg, f32 fb, f32 fa)
117{
118 r = sead::Mathf::clamp(value: fr, low: 0.0f, high: 1.0f) * 255.0f;
119 g = sead::Mathf::clamp(value: fg, low: 0.0f, high: 1.0f) * 255.0f;
120 b = sead::Mathf::clamp(value: fb, low: 0.0f, high: 1.0f) * 255.0f;
121 a = sead::Mathf::clamp(value: fa, low: 0.0f, high: 1.0f) * 255.0f;
122}
123
124void Color4u8::setLerp(const Color4u8& color1, const Color4u8& color2, f32 t)
125{
126 t = sead::Mathf::clamp(value: t, low: 0.0f, high: 1.0f);
127 a = sead::lerp(a: color1.a, b: color2.a, t);
128 r = sead::lerp(a: color1.r, b: color2.r, t);
129 g = sead::lerp(a: color1.g, b: color2.g, t);
130 b = sead::lerp(a: color1.b, b: color2.b, t);
131}
132
133void Color4u8::setGammaCollection(const Color4u8& value, f32 gamma)
134{
135 a = value.a;
136 r = sead::Mathf::clamp(value: std::pow(lcpp_x: f32(value.r) / 255.0f, lcpp_y: gamma), low: 0.0f, high: 1.0f) * 255.0f;
137 g = sead::Mathf::clamp(value: std::pow(lcpp_x: f32(value.g) / 255.0f, lcpp_y: gamma), low: 0.0f, high: 1.0f) * 255.0f;
138 b = sead::Mathf::clamp(value: std::pow(lcpp_x: f32(value.b) / 255.0f, lcpp_y: gamma), low: 0.0f, high: 1.0f) * 255.0f;
139}
140
141#define SEAD_Color4u8_OPERATORS(OP, OP2) \
142 Color4u8 operator OP2(const Color4u8& lhs, const Color4u8& rhs) \
143 { \
144 Color4u8 result = lhs; \
145 result OP rhs; \
146 return result; \
147 } \
148 Color4u8 operator OP2(const Color4u8& lhs, u8 x) \
149 { \
150 Color4u8 result = lhs; \
151 result OP x; \
152 return result; \
153 }
154
155SEAD_Color4u8_OPERATORS(+=, +);
156SEAD_Color4u8_OPERATORS(-=, -);
157SEAD_Color4u8_OPERATORS(*=, *);
158SEAD_Color4u8_OPERATORS(/=, /);
159SEAD_Color4u8_OPERATORS(|=, |);
160SEAD_Color4u8_OPERATORS(&=, &);
161
162Color4u8& Color4u8::operator+=(const Color4u8& rhs)
163{
164 return apply_(fn: [&](auto m) { this->*m = std::min<u32>(0xFF, u32(this->*m) + rhs.*m); });
165}
166
167Color4u8& Color4u8::operator-=(const Color4u8& rhs)
168{
169 return apply_(fn: [&](auto m) { this->*m = this->*m >= rhs.*m ? this->*m - rhs.*m : 0; });
170}
171
172Color4u8& Color4u8::operator*=(const Color4u8& rhs)
173{
174 return apply_(fn: [&](auto m) { this->*m = this->*m * rhs.*m / 0xFF; });
175}
176
177Color4u8& Color4u8::operator/=(const Color4u8& rhs)
178{
179 return apply_(fn: [&](auto m) {
180 if (rhs.*m)
181 this->*m = std::min<u32>(a: 0xFF, b: 255 * u32(this->*m) / u32(rhs.*m));
182 else
183 this->*m = 255;
184 });
185}
186
187Color4u8& Color4u8::operator|=(const Color4u8& rhs)
188{
189 return apply_(fn: [&](auto m) { this->*m = this->*m | rhs.*m; });
190}
191
192Color4u8& Color4u8::operator&=(const Color4u8& rhs)
193{
194 return apply_(fn: [&](auto m) { this->*m = this->*m & rhs.*m; });
195}
196
197bool operator==(const Color4u8& lhs, const Color4u8& rhs)
198{
199 return lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && lhs.a == rhs.a;
200}
201
202Color4u8& Color4u8::operator+=(u8 x)
203{
204 return apply_(fn: [&](auto m) { this->*m = std::min<u32>(a: 0xFF, b: x + u32(this->*m)); });
205}
206
207Color4u8& Color4u8::operator-=(u8 x)
208{
209 return apply_(fn: [&](auto m) { this->*m = this->*m >= x ? this->*m - x : 0; });
210}
211
212// NON_MATCHING: regalloc, one harmless reordering
213Color4u8& Color4u8::operator*=(float x)
214{
215 return apply_(fn: [&](auto m) { this->*m = std::max(0.0f, this->*m * x); });
216}
217
218Color4u8& Color4u8::operator/=(float x)
219{
220 return apply_(fn: [&](auto m) {
221 if (x == 0.0f)
222 {
223 this->*m = 255;
224 return;
225 }
226 const float q = float(this->*m) / x;
227 if (q < 0.0f)
228 this->*m = 0;
229 else if (q > 255.0f)
230 this->*m = 255;
231 else
232 this->*m = q;
233 });
234}
235
236Color4u8& Color4u8::operator|=(u8 x)
237{
238 return apply_(fn: [&](auto m) { this->*m = this->*m | x; });
239}
240
241Color4u8& Color4u8::operator&=(u8 x)
242{
243 return apply_(fn: [&](auto m) { this->*m = this->*m & x; });
244}
245
246// NON_MATCHING: see Color4u8::operator*(f32)
247Color4u8 operator*(const Color4u8& lhs, f32 x)
248{
249 Color4u8 result = lhs;
250 result *= x;
251 return result;
252}
253
254// NON_MATCHING: equivalent but affected by the same issue as Color4u8::lerp
255Color4u8 operator/(const Color4u8& lhs, f32 x)
256{
257 Color4u8 result = lhs;
258 result /= x;
259 return result;
260}
261} // namespace sead
262