PixelBullet  0.0.1
A C++ game engine
Loading...
Searching...
No Matches
color.h
1#pragma once
2
3#include "pixelbullet/serialization/node.h"
4
5#define GLM_ENABLE_EXPERIMENTAL
6#include <glm/geometric.hpp>
7#include <glm/vec4.hpp>
8
9#include <cmath>
10#include <cstddef>
11#include <cstdint>
12#include <iomanip>
13#include <sstream>
14#include <stdexcept>
15#include <string>
16
17namespace pixelbullet
18{
19
23class Color
24{
25public:
26 enum class Packing
27 {
28 Rgba,
29 Argb,
30 Rgb
31 };
32
33 constexpr Color() noexcept
34 : value(1.0f) // Defaults to white (1,1,1,1)
35 {
36 }
37
41 constexpr Color(float r, float g, float b, float a = 1.0f) noexcept
42 : value(r, g, b, a)
43 {
44 }
45
50 constexpr Color(uint32_t i, Packing packing = Packing::Rgb)
51 {
52 switch (packing)
53 {
54 case Packing::Rgba:
55 value.x = static_cast<float>((i >> 24) & 0xFF) / 255.0f;
56 value.y = static_cast<float>((i >> 16) & 0xFF) / 255.0f;
57 value.z = static_cast<float>((i >> 8) & 0xFF) / 255.0f;
58 value.w = static_cast<float>(i & 0xFF) / 255.0f;
59 break;
60 case Packing::Argb:
61 value.w = static_cast<float>((i >> 24) & 0xFF) / 255.0f;
62 value.x = static_cast<float>((i >> 16) & 0xFF) / 255.0f;
63 value.y = static_cast<float>((i >> 8) & 0xFF) / 255.0f;
64 value.z = static_cast<float>(i & 0xFF) / 255.0f;
65 break;
66 case Packing::Rgb:
67 value.x = static_cast<float>((i >> 16) & 0xFF) / 255.0f;
68 value.y = static_cast<float>((i >> 8) & 0xFF) / 255.0f;
69 value.z = static_cast<float>(i & 0xFF) / 255.0f;
70 value.w = 1.0f;
71 break;
72 default:
73 throw std::runtime_error("Unknown Color packing");
74 }
75 }
76
80 explicit Color(std::string hex, float a = 1.0f)
81 {
82 if (!hex.empty() && hex[0] == '#')
83 {
84 hex.erase(0, 1);
85 }
86 if (hex.size() != 6)
87 {
88 throw std::runtime_error("Invalid hex color string");
89 }
90 uint32_t hexValue = 0;
91 for (char digit : hex)
92 {
93 const int value = hex_digit_value(digit);
94 if (value < 0)
95 {
96 throw std::runtime_error("Invalid hex color string");
97 }
98 hexValue = (hexValue << 4u) | static_cast<uint32_t>(value);
99 }
100
101 value.x = static_cast<float>((hexValue >> 16) & 0xFF) / 255.0f;
102 value.y = static_cast<float>((hexValue >> 8) & 0xFF) / 255.0f;
103 value.z = static_cast<float>(hexValue & 0xFF) / 255.0f;
104 value.w = a;
105 }
106
110 constexpr Color lerp(const Color& other, float t) const noexcept
111 {
112 return Color(value.x + (other.value.x - value.x) * t, value.y + (other.value.y - value.y) * t,
113 value.z + (other.value.z - value.z) * t, value.w + (other.value.w - value.w) * t);
114 }
115
119 Color normalized() const
120 {
121 float len = length();
122 if (len == 0.0f)
123 {
124 throw std::runtime_error("Cannot normalize zero-length color");
125 }
126 return Color(value.x / len, value.y / len, value.z / len, value.w / len);
127 }
128
132 constexpr float length_squared() const noexcept
133 {
134 return glm::dot(value, value);
135 }
136
140 float length() const noexcept
141 {
142 return std::sqrt(length_squared());
143 }
144
148 constexpr uint32_t packed(Packing packing = Packing::Rgba) const
149 {
150 switch (packing)
151 {
152 case Packing::Rgba:
153 return (static_cast<uint32_t>(to_byte(value.x)) << 24) | (static_cast<uint32_t>(to_byte(value.y)) << 16) |
154 (static_cast<uint32_t>(to_byte(value.z)) << 8) | static_cast<uint32_t>(to_byte(value.w));
155 case Packing::Argb:
156 return (static_cast<uint32_t>(to_byte(value.w)) << 24) | (static_cast<uint32_t>(to_byte(value.x)) << 16) |
157 (static_cast<uint32_t>(to_byte(value.y)) << 8) | static_cast<uint32_t>(to_byte(value.z));
158 case Packing::Rgb:
159 return (static_cast<uint32_t>(to_byte(value.x)) << 16) | (static_cast<uint32_t>(to_byte(value.y)) << 8) |
160 static_cast<uint32_t>(to_byte(value.z));
161 default:
162 throw std::runtime_error("Unknown Color packing");
163 }
164 }
165
169 std::string to_hex() const
170 {
171 std::stringstream stream;
172 stream << "#" << std::uppercase << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(to_byte(value.x))
173 << std::setw(2) << static_cast<int>(to_byte(value.y)) << std::setw(2) << static_cast<int>(to_byte(value.z));
174 return stream.str();
175 }
176
178 constexpr float operator[](uint32_t i) const noexcept
179 {
180 return (i == 0) ? value.x : (i == 1) ? value.y : (i == 2) ? value.z : value.w;
181 }
182 constexpr float& operator[](uint32_t i)
183 {
184 return (i == 0) ? value.x : (i == 1) ? value.y : (i == 2) ? value.z : value.w;
185 }
186
187 constexpr bool operator==(const Color& rhs) const noexcept
188 {
189 return value == rhs.value;
190 }
191 constexpr bool operator!=(const Color& rhs) const noexcept
192 {
193 return !(*this == rhs);
194 }
195
196 // Arithmetic operators:
197 friend constexpr Color operator+(const Color& lhs, const Color& rhs) noexcept
198 {
199 return Color(lhs.value.x + rhs.value.x, lhs.value.y + rhs.value.y, lhs.value.z + rhs.value.z, lhs.value.w + rhs.value.w);
200 }
201 friend constexpr Color operator-(const Color& lhs, const Color& rhs) noexcept
202 {
203 return Color(lhs.value.x - rhs.value.x, lhs.value.y - rhs.value.y, lhs.value.z - rhs.value.z, lhs.value.w - rhs.value.w);
204 }
205 friend constexpr Color operator*(const Color& lhs, const Color& rhs) noexcept
206 {
207 return Color(lhs.value.x * rhs.value.x, lhs.value.y * rhs.value.y, lhs.value.z * rhs.value.z, lhs.value.w * rhs.value.w);
208 }
209 friend constexpr Color operator/(const Color& lhs, const Color& rhs) noexcept
210 {
211 return Color(lhs.value.x / rhs.value.x, lhs.value.y / rhs.value.y, lhs.value.z / rhs.value.z, lhs.value.w / rhs.value.w);
212 }
213 friend constexpr Color operator*(float lhs, const Color& rhs) noexcept
214 {
215 return Color(lhs * rhs.value.x, lhs * rhs.value.y, lhs * rhs.value.z, lhs * rhs.value.w);
216 }
217 friend constexpr Color operator*(const Color& lhs, float rhs) noexcept
218 {
219 return rhs * lhs;
220 }
221 friend constexpr Color operator/(const Color& lhs, float rhs) noexcept
222 {
223 return Color(lhs.value.x / rhs, lhs.value.y / rhs, lhs.value.z / rhs, lhs.value.w / rhs);
224 }
225 friend constexpr Color operator+(const Color& lhs, float rhs) noexcept
226 {
227 return Color(lhs.value.x + rhs, lhs.value.y + rhs, lhs.value.z + rhs, lhs.value.w + rhs);
228 }
229 friend constexpr Color operator-(const Color& lhs, float rhs) noexcept
230 {
231 return Color(lhs.value.x - rhs, lhs.value.y - rhs, lhs.value.z - rhs, lhs.value.w - rhs);
232 }
233
234 constexpr Color& operator+=(const Color& rhs) noexcept
235 {
236 *this = *this + rhs;
237 return *this;
238 }
239 constexpr Color& operator-=(const Color& rhs) noexcept
240 {
241 *this = *this - rhs;
242 return *this;
243 }
244 constexpr Color& operator*=(const Color& rhs) noexcept
245 {
246 *this = *this * rhs;
247 return *this;
248 }
249 constexpr Color& operator/=(const Color& rhs) noexcept
250 {
251 *this = *this / rhs;
252 return *this;
253 }
254 constexpr Color& operator+=(float rhs) noexcept
255 {
256 *this = *this + rhs;
257 return *this;
258 }
259 constexpr Color& operator-=(float rhs) noexcept
260 {
261 *this = *this - rhs;
262 return *this;
263 }
264 constexpr Color& operator*=(float rhs) noexcept
265 {
266 *this = *this * rhs;
267 return *this;
268 }
269 constexpr Color& operator/=(float rhs) noexcept
270 {
271 *this = *this / rhs;
272 return *this;
273 }
274
275 friend const Node& operator>>(const Node& node, Color& color);
276 friend Node& operator<<(Node& node, const Color& color);
277
278 static const Color clear;
279 static const Color black;
280 static const Color grey;
281 static const Color silver;
282 static const Color white;
283 static const Color maroon;
284 static const Color red;
285 static const Color olive;
286 static const Color yellow;
287 static const Color green;
288 static const Color lime;
289 static const Color teal;
290 static const Color aqua;
291 static const Color navy;
292 static const Color blue;
293 static const Color purple;
294 static const Color fuchsia;
295
296private:
297 static constexpr uint8_t to_byte(float component) noexcept
298 {
299 if (!(component > 0.0f))
300 {
301 return 0u;
302 }
303 if (component >= 1.0f)
304 {
305 return 255u;
306 }
307 return static_cast<uint8_t>(component * 255.0f + 0.5f);
308 }
309
310 static constexpr int hex_digit_value(char digit) noexcept
311 {
312 if (digit >= '0' && digit <= '9')
313 {
314 return digit - '0';
315 }
316 if (digit >= 'A' && digit <= 'F')
317 {
318 return digit - 'A' + 10;
319 }
320 if (digit >= 'a' && digit <= 'f')
321 {
322 return digit - 'a' + 10;
323 }
324 return -1;
325 }
326
327 glm::vec4 value;
328};
329
330// Node conversion operators for Color.
331inline const Node& operator>>(const Node& node, Color& color)
332{
333 if (!node.properties().empty())
334 {
335 node["r"] >> color.value.x;
336 node["g"] >> color.value.y;
337 node["b"] >> color.value.z;
338 node["a"] >> color.value.w;
339 }
340 else
341 {
342 std::string hex;
343 node >> hex;
344 color = Color(hex);
345 }
346 return node;
347}
348
349inline Node& operator<<(Node& node, const Color& color)
350{
351 node["r"] << color.value.x;
352 node["g"] << color.value.y;
353 node["b"] << color.value.z;
354 node["a"] << color.value.w;
355 return node;
356}
357} // namespace pixelbullet
A polished Color class storing RGBA values in a glm::vec4.
Definition color.h:24
Color normalized() const
Normalizes this color (treating it as a 4D vector).
Definition color.h:119
constexpr uint32_t packed(Packing packing=Packing::Rgba) const
Returns the packed 32-bit integer representation.
Definition color.h:148
Color(std::string hex, float a=1.0f)
Constructs a Color from a hexadecimal string (e.g. "#FF00FF").
Definition color.h:80
std::string to_hex() const
Returns the hexadecimal string representation (e.g. "#FF00FF").
Definition color.h:169
constexpr Color(uint32_t i, Packing packing=Packing::Rgb)
Constructs a Color from a packed 32-bit integer. The 'packing' parameter defines the component order.
Definition color.h:50
constexpr float length_squared() const noexcept
Returns the squared length of the color vector.
Definition color.h:132
constexpr Color lerp(const Color &other, float t) const noexcept
Returns a color that is the linear interpolation between this and another color.
Definition color.h:110
constexpr Color(float r, float g, float b, float a=1.0f) noexcept
Constructs a Color from individual float components (0.0f to 1.0f).
Definition color.h:41
constexpr float operator[](uint32_t i) const noexcept
Component access (0: red, 1: green, 2: blue, 3: alpha).
Definition color.h:178
float length() const noexcept
Returns the length of the color vector.
Definition color.h:140
Represents a hierarchical node capable of storing various data types and supporting YAML serializatio...
Definition node.h:49