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 <cstdint>
11#include <iomanip>
12#include <sstream>
13#include <stdexcept>
14#include <string>
15
16namespace pixelbullet
17{
18
22class Color
23{
24public:
25 enum class Type
26 {
27 RGBA,
28 ARGB,
29 RGB
30 };
31
32 constexpr Color() noexcept
33 : value(1.0f) // Defaults to white (1,1,1,1)
34 {
35 }
36
40 constexpr Color(float r, float g, float b, float a = 1.0f) noexcept
41 : value(r, g, b, a)
42 {
43 }
44
49 constexpr Color(uint32_t i, Type type = Type::RGB)
50 {
51 switch (type)
52 {
53 case Type::RGBA:
54 value.x = static_cast<float>((i >> 24) & 0xFF) / 255.0f;
55 value.y = static_cast<float>((i >> 16) & 0xFF) / 255.0f;
56 value.z = static_cast<float>((i >> 8) & 0xFF) / 255.0f;
57 value.w = static_cast<float>(i & 0xFF) / 255.0f;
58 break;
59 case Type::ARGB:
60 value.w = static_cast<float>((i >> 24) & 0xFF) / 255.0f;
61 value.x = static_cast<float>((i >> 16) & 0xFF) / 255.0f;
62 value.y = static_cast<float>((i >> 8) & 0xFF) / 255.0f;
63 value.z = static_cast<float>(i & 0xFF) / 255.0f;
64 break;
65 case Type::RGB:
66 value.x = static_cast<float>((i >> 16) & 0xFF) / 255.0f;
67 value.y = static_cast<float>((i >> 8) & 0xFF) / 255.0f;
68 value.z = static_cast<float>(i & 0xFF) / 255.0f;
69 value.w = 1.0f;
70 break;
71 default:
72 throw std::runtime_error("Unknown Color type");
73 }
74 }
75
79 explicit Color(std::string hex, float a = 1.0f)
80 {
81 if (!hex.empty() && hex[0] == '#')
82 {
83 hex.erase(0, 1);
84 }
85 if (hex.size() != 6)
86 {
87 throw std::runtime_error("Invalid hex color string");
88 }
89 uint32_t hexValue = std::stoul(hex, nullptr, 16);
90 value.x = static_cast<float>((hexValue >> 16) & 0xFF) / 255.0f;
91 value.y = static_cast<float>((hexValue >> 8) & 0xFF) / 255.0f;
92 value.z = static_cast<float>(hexValue & 0xFF) / 255.0f;
93 value.w = a;
94 }
95
99 constexpr Color Lerp(const Color& other, float t) const noexcept
100 {
101 return Color(value.x + (other.value.x - value.x) * t, value.y + (other.value.y - value.y) * t,
102 value.z + (other.value.z - value.z) * t, value.w + (other.value.w - value.w) * t);
103 }
104
109 {
110 float len = Length();
111 if (len == 0.0f)
112 {
113 throw std::runtime_error("Cannot normalize zero-length color");
114 }
115 return Color(value.x / len, value.y / len, value.z / len, value.w / len);
116 }
117
121 constexpr float Length2() const noexcept
122 {
123 return glm::dot(value, value);
124 }
125
129 float Length() const noexcept
130 {
131 return std::sqrt(Length2());
132 }
133
137 constexpr uint32_t GetInt(Type type = Type::RGBA) const
138 {
139 switch (type)
140 {
141 case Type::RGBA:
142 return (static_cast<uint32_t>(value.x * 255.0f) << 24) | (static_cast<uint32_t>(value.y * 255.0f) << 16) |
143 (static_cast<uint32_t>(value.z * 255.0f) << 8) | (static_cast<uint32_t>(value.w * 255.0f));
144 case Type::ARGB:
145 return (static_cast<uint32_t>(value.w * 255.0f) << 24) | (static_cast<uint32_t>(value.x * 255.0f) << 16) |
146 (static_cast<uint32_t>(value.y * 255.0f) << 8) | (static_cast<uint32_t>(value.z * 255.0f));
147 case Type::RGB:
148 return (static_cast<uint32_t>(value.x * 255.0f) << 16) | (static_cast<uint32_t>(value.y * 255.0f) << 8) |
149 (static_cast<uint32_t>(value.z * 255.0f));
150 default:
151 throw std::runtime_error("Unknown Color type");
152 }
153 }
154
158 std::string GetHex() const
159 {
160 std::stringstream stream;
161 stream << "#" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(value.x * 255.0f) << std::setw(2)
162 << static_cast<int>(value.y * 255.0f) << std::setw(2) << static_cast<int>(value.z * 255.0f);
163 return stream.str();
164 }
165
167 constexpr float operator[](uint32_t i) const noexcept
168 {
169 return (i == 0) ? value.x : (i == 1) ? value.y : (i == 2) ? value.z : value.w;
170 }
171 constexpr float& operator[](uint32_t i)
172 {
173 return (i == 0) ? value.x : (i == 1) ? value.y : (i == 2) ? value.z : value.w;
174 }
175
176 constexpr bool operator==(const Color& rhs) const noexcept
177 {
178 return value == rhs.value;
179 }
180 constexpr bool operator!=(const Color& rhs) const noexcept
181 {
182 return !(*this == rhs);
183 }
184
185 // Arithmetic operators:
186 friend constexpr Color operator+(const Color& lhs, const Color& rhs) noexcept
187 {
188 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);
189 }
190 friend constexpr Color operator-(const Color& lhs, const Color& rhs) noexcept
191 {
192 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);
193 }
194 friend constexpr Color operator*(const Color& lhs, const Color& rhs) noexcept
195 {
196 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);
197 }
198 friend constexpr Color operator/(const Color& lhs, const Color& rhs) noexcept
199 {
200 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);
201 }
202 friend constexpr Color operator*(float lhs, const Color& rhs) noexcept
203 {
204 return Color(lhs * rhs.value.x, lhs * rhs.value.y, lhs * rhs.value.z, lhs * rhs.value.w);
205 }
206 friend constexpr Color operator*(const Color& lhs, float rhs) noexcept
207 {
208 return rhs * lhs;
209 }
210 friend constexpr Color operator/(const Color& lhs, float rhs) noexcept
211 {
212 return Color(lhs.value.x / rhs, lhs.value.y / rhs, lhs.value.z / rhs, lhs.value.w / rhs);
213 }
214 friend constexpr Color operator+(const Color& lhs, float rhs) noexcept
215 {
216 return Color(lhs.value.x + rhs, lhs.value.y + rhs, lhs.value.z + rhs, lhs.value.w);
217 }
218 friend constexpr Color operator-(const Color& lhs, float rhs) noexcept
219 {
220 return Color(lhs.value.x - rhs, lhs.value.y - rhs, lhs.value.z - rhs, lhs.value.w);
221 }
222
223 constexpr Color& operator+=(const Color& rhs) noexcept
224 {
225 *this = *this + rhs;
226 return *this;
227 }
228 constexpr Color& operator-=(const Color& rhs) noexcept
229 {
230 *this = *this - rhs;
231 return *this;
232 }
233 constexpr Color& operator*=(const Color& rhs) noexcept
234 {
235 *this = *this * rhs;
236 return *this;
237 }
238 constexpr Color& operator/=(const Color& rhs) noexcept
239 {
240 *this = *this / rhs;
241 return *this;
242 }
243 constexpr Color& operator+=(float rhs) noexcept
244 {
245 *this = *this + rhs;
246 return *this;
247 }
248 constexpr Color& operator-=(float rhs) noexcept
249 {
250 *this = *this - rhs;
251 return *this;
252 }
253 constexpr Color& operator*=(float rhs) noexcept
254 {
255 *this = *this * rhs;
256 return *this;
257 }
258 constexpr Color& operator/=(float rhs) noexcept
259 {
260 *this = *this / rhs;
261 return *this;
262 }
263
264 friend const Node& operator>>(const Node& node, Color& color);
265 friend Node& operator<<(Node& node, const Color& color);
266
267 static const Color clear;
268 static const Color black;
269 static const Color grey;
270 static const Color silver;
271 static const Color white;
272 static const Color maroon;
273 static const Color red;
274 static const Color olive;
275 static const Color yellow;
276 static const Color green;
277 static const Color lime;
278 static const Color teal;
279 static const Color aqua;
280 static const Color navy;
281 static const Color blue;
282 static const Color purple;
283 static const Color fuchsia;
284
285private:
286 glm::vec4 value;
287};
288
289// Node conversion operators for Color.
290inline const Node& operator>>(const Node& node, Color& color)
291{
292 if (!node.GetProperties().empty())
293 {
294 node["r"] >> color.value.x;
295 node["g"] >> color.value.y;
296 node["b"] >> color.value.z;
297 node["a"] >> color.value.w;
298 }
299 else
300 {
301 std::string hex;
302 node >> hex;
303 color = Color(hex);
304 }
305 return node;
306}
307
308inline Node& operator<<(Node& node, const Color& color)
309{
310 node["r"] << color.value.x;
311 node["g"] << color.value.y;
312 node["b"] << color.value.z;
313 node["a"] << color.value.w;
314 return node;
315}
316} // namespace pixelbullet
A polished Color class storing RGBA values in a glm::vec4.
Definition color.h:23
Color Normalize() const
Normalizes this color (treating it as a 4D vector).
Definition color.h:108
Color(std::string hex, float a=1.0f)
Constructs a Color from a hexadecimal string (e.g. "#FF00FF").
Definition color.h:79
constexpr Color(uint32_t i, Type type=Type::RGB)
Constructs a Color from a packed 32-bit integer. The 'type' parameter defines the component order.
Definition color.h:49
float Length() const noexcept
Returns the length of the color vector.
Definition color.h:129
constexpr float Length2() const noexcept
Returns the squared length of the color vector.
Definition color.h:121
std::string GetHex() const
Returns the hexadecimal string representation (e.g. "#FF00FF").
Definition color.h:158
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:99
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:40
constexpr float operator[](uint32_t i) const noexcept
Component access (0: red, 1: green, 2: blue, 3: alpha)
Definition color.h:167
constexpr uint32_t GetInt(Type type=Type::RGBA) const
Returns the packed 32-bit integer representation.
Definition color.h:137