guillaume 1.0.0
Guillaume is a component-based UI framework library built around a primitive rendering system. It's designed for building user interfaces across XR platforms and traditional platforms with custom rendering backends and input handling. The framework is lightweight, flexible, and easy to integrate into existing projects.
Loading...
Searching...
No Matches
color.hpp
1/*
2 Copyright (c) 2025 ETIB Corporation
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 */
22
23#pragma once
24
25#include <algorithm>
26#include <cmath>
27#include <cstdint>
28#include <iomanip>
29#include <sstream>
30#include <stdexcept>
31#include <string>
32
42class Color {
43private:
44 float _r;
45 float _g;
46 float _b;
47 float _a;
48
49 static constexpr float _clamp01(float v) {
50 return v < 0.0f ? 0.0f : (v > 1.0f ? 1.0f : v);
51 }
52
53public:
57 Color(void) : _r(0.0f), _g(0.0f), _b(0.0f), _a(1.0f) {}
58
62 Color(float r, float g, float b)
63 : _r(_clamp01(r)), _g(_clamp01(g)), _b(_clamp01(b)), _a(1.0f) {}
64
68 Color(float r, float g, float b, float a)
69 : _r(_clamp01(r)), _g(_clamp01(g)), _b(_clamp01(b)), _a(_clamp01(a)) {}
70
74 float r(void) const { return _r; }
78 float g(void) const { return _g; }
82 float b(void) const { return _b; }
86 float a(void) const { return _a; }
87
95 void setR(float v) { _r = _clamp01(v); }
100 void setG(float v) { _g = _clamp01(v); }
105 void setB(float v) { _b = _clamp01(v); }
110 void setA(float v) { _a = _clamp01(v); }
111
115 Color withAlpha(float alpha) const { return Color(_r, _g, _b, alpha); }
116
122 Color lerp(const Color &to, float t) const {
123 float u = _clamp01(t);
124 return Color(_r + (to._r - _r) * u, _g + (to._g - _g) * u,
125 _b + (to._b - _b) * u, _a + (to._a - _a) * u);
126 }
127
132 Color premultiplied() const { return Color(_r * _a, _g * _a, _b * _a, _a); }
133
138 Color over(const Color &bg) const {
139 float outA = _a + bg._a * (1.0f - _a);
140 if (outA <= 0.0f)
141 return Color(0, 0, 0, 0);
142 float outR = (_r * _a + bg._r * bg._a * (1.0f - _a)) / outA;
143 float outG = (_g * _a + bg._g * bg._a * (1.0f - _a)) / outA;
144 float outB = (_b * _a + bg._b * bg._a * (1.0f - _a)) / outA;
145 return Color(outR, outG, outB, outA);
146 }
147
154 struct RGBA8 {
156 uint8_t r;
158 uint8_t g;
160 uint8_t b;
162 uint8_t a;
163 };
164
169 RGBA8 toRGBA8() const {
170 auto to8 = [](float v) -> uint8_t {
171 float cl = v <= 0.0f ? 0.0f : (v >= 1.0f ? 1.0f : v);
172 return static_cast<uint8_t>(std::round(cl * 255.0f));
173 };
174 return RGBA8{to8(_r), to8(_g), to8(_b), to8(_a)};
175 }
176
180 static Color fromRGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255) {
181 auto toF = [](uint8_t v) -> float {
182 return static_cast<float>(v) / 255.0f;
183 };
184 return Color(toF(r), toF(g), toF(b), toF(a));
185 }
186
191 std::string toHex(bool includeAlphaIfOpaque = false) const {
192 auto p = toRGBA8();
193 std::ostringstream oss;
194 oss << '#' << std::uppercase << std::hex << std::setfill('0')
195 << std::setw(2) << static_cast<int>(p.r) << std::setw(2)
196 << static_cast<int>(p.g) << std::setw(2) << static_cast<int>(p.b);
197 if (includeAlphaIfOpaque || p.a != 255) {
198 oss << std::setw(2) << static_cast<int>(p.a);
199 }
200 return oss.str();
201 }
202
214 static Color fromHex(const std::string &hex) {
215 auto isHex = [](char c) {
216 return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
217 (c >= 'A' && c <= 'F');
218 };
219
220 std::string s = hex;
221 if (!s.empty() && s[0] == '#')
222 s.erase(0, 1);
223 if (s.size() != 3 && s.size() != 4 && s.size() != 6 && s.size() != 8)
224 throw std::invalid_argument("Invalid hex color length");
225 for (char c : s) {
226 if (!isHex(c))
227 throw std::invalid_argument("Invalid hex color character");
228 }
229
230 auto hexToByte = [](const std::string &hh) -> uint8_t {
231 return static_cast<uint8_t>(std::stoul(hh, nullptr, 16));
232 };
233
234 if (s.size() == 3 || s.size() == 4) {
235 // short form: expand nibbles: #RGB -> #RRGGBB
236 uint8_t r = hexToByte(std::string{s[0], s[0]});
237 uint8_t g = hexToByte(std::string{s[1], s[1]});
238 uint8_t b = hexToByte(std::string{s[2], s[2]});
239 uint8_t a = 0xFF;
240 if (s.size() == 4)
241 a = hexToByte(std::string{s[3], s[3]});
242 return fromRGBA8(r, g, b, a);
243 }
244
245 // long form
246 uint8_t r = hexToByte(s.substr(0, 2));
247 uint8_t g = hexToByte(s.substr(2, 2));
248 uint8_t b = hexToByte(s.substr(4, 2));
249 uint8_t a = 0xFF;
250 if (s.size() == 8)
251 a = hexToByte(s.substr(6, 2));
252 return fromRGBA8(r, g, b, a);
253 }
254
258 bool operator==(const Color &other) const {
259 return _r == other._r && _g == other._g && _b == other._b && _a == other._a;
260 }
265 bool operator!=(const Color &other) const { return !(*this == other); }
266
270 Color operator+(const Color &o) const {
271 return Color(_clamp01(_r + o._r), _clamp01(_g + o._g), _clamp01(_b + o._b),
272 _clamp01(_a + o._a));
273 }
274
278 Color operator-(const Color &o) const {
279 return Color(_clamp01(_r - o._r), _clamp01(_g - o._g), _clamp01(_b - o._b),
280 _clamp01(_a - o._a));
281 }
282
286 Color operator*(float s) const {
287 return Color(_clamp01(_r * s), _clamp01(_g * s), _clamp01(_b * s), _a);
288 }
289
294 static Color Black() { return Color(0.0f, 0.0f, 0.0f, 1.0f); }
296 static Color White() { return Color(1.0f, 1.0f, 1.0f, 1.0f); }
298 static Color Red() { return Color(1.0f, 0.0f, 0.0f, 1.0f); }
300 static Color Green() { return Color(0.0f, 1.0f, 0.0f, 1.0f); }
302 static Color Blue() { return Color(0.0f, 0.0f, 1.0f, 1.0f); }
304 static Color Transparent() { return Color(0.0f, 0.0f, 0.0f, 0.0f); }
305};
Represents an RGBA color with floating-point channels in [0, 1].
Definition color.hpp:42
void setB(float v)
Set blue component.
Definition color.hpp:105
bool operator!=(const Color &other) const
Inequality operator.
Definition color.hpp:265
Color withAlpha(float alpha) const
Return a copy with a different alpha (keeps RGB).
Definition color.hpp:115
Color lerp(const Color &to, float t) const
Linear interpolation between two colors (component-wise).
Definition color.hpp:122
static Color Green()
Opaque green (0,1,0,1)
Definition color.hpp:300
float r(void) const
Red component in [0,1].
Definition color.hpp:74
Color(float r, float g, float b)
Construct from RGB, alpha defaults to 1.0.
Definition color.hpp:62
static Color Red()
Opaque red (1,0,0,1)
Definition color.hpp:298
Color operator+(const Color &o) const
Component-wise addition (clamped).
Definition color.hpp:270
Color operator*(float s) const
Scalar multiplication (scales RGB; alpha unchanged by default).
Definition color.hpp:286
void setG(float v)
Set green component.
Definition color.hpp:100
static Color Transparent()
Fully transparent black (0,0,0,0)
Definition color.hpp:304
Color(float r, float g, float b, float a)
Construct from RGBA.
Definition color.hpp:68
Color premultiplied() const
Premultiplied alpha representation.
Definition color.hpp:132
void setA(float v)
Set alpha component.
Definition color.hpp:110
static Color Blue()
Opaque blue (0,0,1,1)
Definition color.hpp:302
static Color fromHex(const std::string &hex)
Parse from hexadecimal string.
Definition color.hpp:214
float b(void) const
Blue component in [0,1].
Definition color.hpp:82
void setR(float v)
Setters (values are clamped to [0,1]).
Definition color.hpp:95
static Color White()
Opaque white (1,1,1,1)
Definition color.hpp:296
static Color fromRGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Create from 8-bit per channel RGBA values.
Definition color.hpp:180
Color(void)
Construct a fully-opaque black color (0,0,0,1).
Definition color.hpp:57
RGBA8 toRGBA8() const
Convert to 8-bit per channel RGBA.
Definition color.hpp:169
float g(void) const
Green component in [0,1].
Definition color.hpp:78
float a(void) const
Alpha component in [0,1].
Definition color.hpp:86
bool operator==(const Color &other) const
Equality operators (exact component-wise equality).
Definition color.hpp:258
Color operator-(const Color &o) const
Component-wise subtraction (clamped to [0,1]).
Definition color.hpp:278
static Color Black()
Common named colors (opaque unless specified).
Definition color.hpp:294
std::string toHex(bool includeAlphaIfOpaque=false) const
Convert to hexadecimal string. Formats as "#RRGGBB" if a==1 else "#RRGGBBAA".
Definition color.hpp:191
Color over(const Color &bg) const
Alpha blend this color over a background color. Uses standard source-over compositing in linear space...
Definition color.hpp:138
8-bit RGBA packed representation.
Definition color.hpp:154
uint8_t g
Green channel (0..255)
Definition color.hpp:158
uint8_t r
Red channel (0..255)
Definition color.hpp:156
uint8_t b
Blue channel (0..255)
Definition color.hpp:160
uint8_t a
Alpha channel (0..255)
Definition color.hpp:162