PixelBullet  0.0.1
A C++ game engine
Loading...
Searching...
No Matches
Color.hpp
1#pragma once
2
3#include "PixelBullet/Serialization/Node.hpp"
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
22 class Color
23 {
24 public:
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) noexcept
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 noexcept
138 {
139 switch (type)
140 {
141 case Type::RGBA:
142 return (static_cast<uint32_t>(value.x * 255.0f) << 24) |
143 (static_cast<uint32_t>(value.y * 255.0f) << 16) |
144 (static_cast<uint32_t>(value.z * 255.0f) << 8) | (static_cast<uint32_t>(value.w * 255.0f));
145 case Type::ARGB:
146 return (static_cast<uint32_t>(value.w * 255.0f) << 24) |
147 (static_cast<uint32_t>(value.x * 255.0f) << 16) |
148 (static_cast<uint32_t>(value.y * 255.0f) << 8) | (static_cast<uint32_t>(value.z * 255.0f));
149 case Type::RGB:
150 return (static_cast<uint32_t>(value.x * 255.0f) << 16) |
151 (static_cast<uint32_t>(value.y * 255.0f) << 8) | (static_cast<uint32_t>(value.z * 255.0f));
152 default:
153 throw std::runtime_error("Unknown Color type");
154 }
155 }
156
160 std::string GetHex() const
161 {
162 std::stringstream stream;
163 stream << "#" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(value.x * 255.0f)
164 << std::setw(2) << static_cast<int>(value.y * 255.0f) << std::setw(2)
165 << static_cast<int>(value.z * 255.0f);
166 return stream.str();
167 }
168
170 constexpr float operator[](uint32_t i) const noexcept
171 {
172 return (i == 0) ? value.x : (i == 1) ? value.y : (i == 2) ? value.z : value.w;
173 }
174 constexpr float& operator[](uint32_t i)
175 {
176 return (i == 0) ? value.x : (i == 1) ? value.y : (i == 2) ? value.z : value.w;
177 }
178
179 constexpr bool operator==(const Color& rhs) const noexcept
180 {
181 return value == rhs.value;
182 }
183 constexpr bool operator!=(const Color& rhs) const noexcept
184 {
185 return !(*this == rhs);
186 }
187
188 // Arithmetic operators:
189 friend constexpr Color operator+(const Color& lhs, const Color& rhs) noexcept
190 {
191 return Color(lhs.value.x + rhs.value.x, lhs.value.y + rhs.value.y, lhs.value.z + rhs.value.z,
192 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,
197 lhs.value.w - rhs.value.w);
198 }
199 friend constexpr Color operator*(const Color& lhs, const Color& rhs) noexcept
200 {
201 return Color(lhs.value.x * rhs.value.x, lhs.value.y * rhs.value.y, lhs.value.z * rhs.value.z,
202 lhs.value.w * rhs.value.w);
203 }
204 friend constexpr Color operator/(const Color& lhs, const Color& rhs) noexcept
205 {
206 return Color(lhs.value.x / rhs.value.x, lhs.value.y / rhs.value.y, lhs.value.z / rhs.value.z,
207 lhs.value.w / rhs.value.w);
208 }
209 friend constexpr Color operator*(float lhs, const Color& rhs) noexcept
210 {
211 return Color(lhs * rhs.value.x, lhs * rhs.value.y, lhs * rhs.value.z, lhs * rhs.value.w);
212 }
213 friend constexpr Color operator*(const Color& lhs, float rhs) noexcept
214 {
215 return rhs * lhs;
216 }
217 friend constexpr Color operator/(const Color& lhs, float rhs) noexcept
218 {
219 return Color(lhs.value.x / rhs, lhs.value.y / rhs, lhs.value.z / rhs, lhs.value.w / rhs);
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);
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);
228 }
229
230 constexpr Color& operator+=(const Color& rhs) noexcept
231 {
232 *this = *this + rhs;
233 return *this;
234 }
235 constexpr Color& operator-=(const Color& rhs) noexcept
236 {
237 *this = *this - rhs;
238 return *this;
239 }
240 constexpr Color& operator*=(const Color& rhs) noexcept
241 {
242 *this = *this * rhs;
243 return *this;
244 }
245 constexpr Color& operator/=(const Color& rhs) noexcept
246 {
247 *this = *this / rhs;
248 return *this;
249 }
250 constexpr Color& operator+=(float rhs) noexcept
251 {
252 *this = *this + rhs;
253 return *this;
254 }
255 constexpr Color& operator-=(float rhs) noexcept
256 {
257 *this = *this - rhs;
258 return *this;
259 }
260 constexpr Color& operator*=(float rhs) noexcept
261 {
262 *this = *this * rhs;
263 return *this;
264 }
265 constexpr Color& operator/=(float rhs) noexcept
266 {
267 *this = *this / rhs;
268 return *this;
269 }
270
271 friend const Node& operator>>(const Node& node, Color& color);
272 friend Node& operator<<(Node& node, const Color& color);
273
274 static const Color Clear;
275 static const Color Black;
276 static const Color Grey;
277 static const Color Silver;
278 static const Color White;
279 static const Color Maroon;
280 static const Color Red;
281 static const Color Olive;
282 static const Color Yellow;
283 static const Color Green;
284 static const Color Lime;
285 static const Color Teal;
286 static const Color Aqua;
287 static const Color Navy;
288 static const Color Blue;
289 static const Color Purple;
290 static const Color Fuchsia;
291
292 private:
293 glm::vec4 value;
294 };
295
296 // Node conversion operators for Color.
297 inline const Node& operator>>(const Node& node, Color& color)
298 {
299 if (!node.GetProperties().empty())
300 {
301 color.value.x = String::From<float>(node["r"].GetValue());
302 color.value.y = String::From<float>(node["g"].GetValue());
303 color.value.z = String::From<float>(node["b"].GetValue());
304 color.value.w = String::From<float>(node["a"].GetValue());
305 }
306 else
307 {
308 std::string hex;
309 node >> hex;
310 color = Color(hex);
311 }
312 return node;
313 }
314
315 inline Node& operator<<(Node& node, const Color& color)
316 {
317 node["r"].SetValue(String::To(color.value.x));
318 node["r"].SetType(NodeType::Decimal);
319 node["g"].SetValue(String::To(color.value.y));
320 node["g"].SetType(NodeType::Decimal);
321 node["b"].SetValue(String::To(color.value.z));
322 node["b"].SetType(NodeType::Decimal);
323 node["a"].SetValue(String::To(color.value.w));
324 node["a"].SetType(NodeType::Decimal);
325 return node;
326 }
327} // namespace PixelBullet
A polished Color class storing RGBA values in a glm::vec4.
Definition Color.hpp:23
float Length() const noexcept
Returns the length of the color vector.
Definition Color.hpp:129
Color Normalize() const
Normalizes this color (treating it as a 4D vector).
Definition Color.hpp:108
std::string GetHex() const
Returns the hexadecimal string representation (e.g. "#FF00FF").
Definition Color.hpp:160
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.hpp:99
Color(std::string hex, float a=1.0f)
Constructs a Color from a hexadecimal string (e.g. "#FF00FF").
Definition Color.hpp:79
constexpr float operator[](uint32_t i) const noexcept
Component access (0: red, 1: green, 2: blue, 3: alpha)
Definition Color.hpp:170
constexpr Color(uint32_t i, Type type=Type::RGB) noexcept
Constructs a Color from a packed 32-bit integer. The 'type' parameter defines the component order.
Definition Color.hpp:49
constexpr uint32_t GetInt(Type type=Type::RGBA) const noexcept
Returns the packed 32-bit integer representation.
Definition Color.hpp:137
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.hpp:40
constexpr float Length2() const noexcept
Returns the squared length of the color vector.
Definition Color.hpp:121