Skip to content

Commit 0b1e96c

Browse files
committed
Move to c++ 20 and add colors
1 parent c62e63a commit 0b1e96c

7 files changed

Lines changed: 496 additions & 4 deletions

File tree

CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12...3.27.4)
22

33
project(twbl)
44

5-
set(CMAKE_CXX_STANDARD 17)
5+
set(CMAKE_CXX_STANDARD 20)
66
set(CMAKE_CXX_STANDARD_REQUIRED On)
77

88
option(TWBL_DEBUG "activate bot debug comments" OFF)
@@ -43,7 +43,7 @@ FILE(GLOB BOT_SOURCE_FILES
4343
set(TWBL_DEPS ${CMAKE_DL_LIBS})
4444

4545
add_library(twbl STATIC ${BOT_SOURCE_FILES})
46-
target_compile_options(twbl PRIVATE -std=gnu++17)
46+
target_compile_options(twbl PRIVATE -std=gnu++20)
4747
add_compiler_flag_if_supported(-Wno-format-truncation)
4848
target_link_libraries(twbl ${TWBL_DEPS})
4949
include_directories(src)
@@ -74,7 +74,7 @@ endif()
7474

7575
add_executable(twbl_probe ${BOT_SOURCE_FILES} src/tools/twbl_probe.cpp)
7676
target_link_libraries(twbl_probe ${TWBL_DEPS} ${LINK_FLAGS_PLATFORM})
77-
target_compile_options(twbl_probe PRIVATE -std=gnu++17)
77+
target_compile_options(twbl_probe PRIVATE -std=gnu++20)
7878

7979
# tests
8080

@@ -89,7 +89,7 @@ function(register_test test_name)
8989
set(test_target "test_${test_name}")
9090
add_executable(${test_target} ${TEST_SOURCE_FILES})
9191
target_link_libraries(${test_target} twbl ${TWBL_DEPS} ${LINK_FLAGS_PLATFORM})
92-
target_compile_options(${test_target} PRIVATE -std=gnu++17)
92+
target_compile_options(${test_target} PRIVATE -std=gnu++20)
9393
add_test(NAME ${test_target}
9494
COMMAND ${test_target})
9595
endfunction()

src/twbl/teeworlds/base/color.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include <twbl/teeworlds/base/color.h>
2+
#include <twbl/teeworlds/base/system.h>
3+
4+
template<typename T>
5+
std::optional<T> color_parse(const char *pStr)
6+
{
7+
if(!str_isallnum_hex(pStr))
8+
return {};
9+
10+
const unsigned Num = str_toulong_base(pStr, 16);
11+
12+
T Color;
13+
switch(str_length(pStr))
14+
{
15+
case 3:
16+
Color.x = (((Num >> 8) & 0x0F) + ((Num >> 4) & 0xF0)) / 255.0f;
17+
Color.y = (((Num >> 4) & 0x0F) + ((Num >> 0) & 0xF0)) / 255.0f;
18+
Color.z = (((Num >> 0) & 0x0F) + ((Num << 4) & 0xF0)) / 255.0f;
19+
Color.a = 1.0f;
20+
return Color;
21+
22+
case 4:
23+
Color.x = (((Num >> 12) & 0x0F) + ((Num >> 8) & 0xF0)) / 255.0f;
24+
Color.y = (((Num >> 8) & 0x0F) + ((Num >> 4) & 0xF0)) / 255.0f;
25+
Color.z = (((Num >> 4) & 0x0F) + ((Num >> 0) & 0xF0)) / 255.0f;
26+
Color.a = (((Num >> 0) & 0x0F) + ((Num << 4) & 0xF0)) / 255.0f;
27+
return Color;
28+
29+
case 6:
30+
Color.x = ((Num >> 16) & 0xFF) / 255.0f;
31+
Color.y = ((Num >> 8) & 0xFF) / 255.0f;
32+
Color.z = ((Num >> 0) & 0xFF) / 255.0f;
33+
Color.a = 1.0f;
34+
return Color;
35+
36+
case 8:
37+
Color.x = ((Num >> 24) & 0xFF) / 255.0f;
38+
Color.y = ((Num >> 16) & 0xFF) / 255.0f;
39+
Color.z = ((Num >> 8) & 0xFF) / 255.0f;
40+
Color.a = ((Num >> 0) & 0xFF) / 255.0f;
41+
return Color;
42+
43+
default:
44+
return {};
45+
}
46+
}
47+
48+
template std::optional<ColorRGBA> color_parse<ColorRGBA>(const char *);

src/twbl/teeworlds/base/color.h

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
#ifndef TWBL_SRC_SHARED_COLOR_H
2+
#define TWBL_SRC_SHARED_COLOR_H
3+
4+
#if __has_include(<base/color.h>)
5+
#include <base/color.h>
6+
#else
7+
8+
#include <twbl/teeworlds/base/math.h>
9+
10+
#include <optional>
11+
#include <type_traits>
12+
13+
/*
14+
Title: Color handling
15+
*/
16+
/*
17+
Function: RgbToHue
18+
Determines the hue from RGB values
19+
*/
20+
constexpr float RgbToHue(float r, float g, float b)
21+
{
22+
float h_min = minimum(r, g, b);
23+
float h_max = maximum(r, g, b);
24+
25+
float hue = 0.0f;
26+
if(h_max != h_min)
27+
{
28+
float c = h_max - h_min;
29+
if(h_max == r)
30+
hue = (g - b) / c + (g < b ? 6 : 0);
31+
else if(h_max == g)
32+
hue = (b - r) / c + 2;
33+
else
34+
hue = (r - g) / c + 4;
35+
}
36+
37+
return hue / 6.0f;
38+
}
39+
40+
// Curiously Recurring Template Pattern for type safety
41+
template<typename DerivedT>
42+
class color4_base
43+
{
44+
public:
45+
union
46+
{
47+
float x, r, h;
48+
};
49+
union
50+
{
51+
float y, g, s;
52+
};
53+
union
54+
{
55+
float z, b, l, v;
56+
};
57+
union
58+
{
59+
float w, a;
60+
};
61+
62+
constexpr color4_base() :
63+
x(), y(), z(), a()
64+
{
65+
}
66+
67+
constexpr color4_base(float nx, float ny, float nz, float na) :
68+
x(nx), y(ny), z(nz), a(na)
69+
{
70+
}
71+
72+
constexpr color4_base(float nx, float ny, float nz) :
73+
x(nx), y(ny), z(nz), a(1.0f)
74+
{
75+
}
76+
77+
constexpr color4_base(unsigned col, bool alpha = false)
78+
{
79+
a = alpha ? ((col >> 24) & 0xFF) / 255.0f : 1.0f;
80+
x = ((col >> 16) & 0xFF) / 255.0f;
81+
y = ((col >> 8) & 0xFF) / 255.0f;
82+
z = ((col >> 0) & 0xFF) / 255.0f;
83+
}
84+
85+
// Disallow casting between different instantiations of the color4_base template.
86+
// The color_cast functions below should be used to convert between colors.
87+
template<typename OtherDerivedT>
88+
requires(!std::is_same_v<DerivedT, OtherDerivedT>)
89+
color4_base(const color4_base<OtherDerivedT> &Other) = delete;
90+
91+
constexpr float &operator[](int index)
92+
{
93+
return ((float *)this)[index];
94+
}
95+
96+
constexpr bool operator==(const color4_base &col) const { return x == col.x && y == col.y && z == col.z && a == col.a; }
97+
constexpr bool operator!=(const color4_base &col) const { return x != col.x || y != col.y || z != col.z || a != col.a; }
98+
99+
constexpr unsigned Pack(bool Alpha = true) const
100+
{
101+
return (Alpha ? ((unsigned)round_to_int(a * 255.0f) << 24) : 0) + ((unsigned)round_to_int(x * 255.0f) << 16) + ((unsigned)round_to_int(y * 255.0f) << 8) + (unsigned)round_to_int(z * 255.0f);
102+
}
103+
104+
constexpr unsigned PackAlphaLast(bool Alpha = true) const
105+
{
106+
if(Alpha)
107+
return ((unsigned)round_to_int(x * 255.0f) << 24) + ((unsigned)round_to_int(y * 255.0f) << 16) + ((unsigned)round_to_int(z * 255.0f) << 8) + (unsigned)round_to_int(a * 255.0f);
108+
return ((unsigned)round_to_int(x * 255.0f) << 16) + ((unsigned)round_to_int(y * 255.0f) << 8) + (unsigned)round_to_int(z * 255.0f);
109+
}
110+
111+
constexpr DerivedT WithAlpha(float alpha) const
112+
{
113+
DerivedT col(static_cast<const DerivedT &>(*this));
114+
col.a = alpha;
115+
return col;
116+
}
117+
118+
constexpr DerivedT WithMultipliedAlpha(float alpha) const
119+
{
120+
DerivedT col(static_cast<const DerivedT &>(*this));
121+
col.a *= alpha;
122+
return col;
123+
}
124+
125+
template<typename UnpackT>
126+
constexpr static UnpackT UnpackAlphaLast(unsigned Color, bool Alpha = true)
127+
{
128+
UnpackT Result;
129+
if(Alpha)
130+
{
131+
Result.x = ((Color >> 24) & 0xFF) / 255.0f;
132+
Result.y = ((Color >> 16) & 0xFF) / 255.0f;
133+
Result.z = ((Color >> 8) & 0xFF) / 255.0f;
134+
Result.a = ((Color >> 0) & 0xFF) / 255.0f;
135+
}
136+
else
137+
{
138+
Result.x = ((Color >> 16) & 0xFF) / 255.0f;
139+
Result.y = ((Color >> 8) & 0xFF) / 255.0f;
140+
Result.z = ((Color >> 0) & 0xFF) / 255.0f;
141+
Result.a = 1.0f;
142+
}
143+
return Result;
144+
}
145+
};
146+
147+
class ColorHSLA : public color4_base<ColorHSLA>
148+
{
149+
public:
150+
using color4_base::color4_base;
151+
constexpr ColorHSLA() = default;
152+
153+
constexpr static const float DARKEST_LGT = 0.5f;
154+
constexpr static const float DARKEST_LGT7 = 61.0f / 255.0f;
155+
156+
constexpr ColorHSLA UnclampLighting(float Darkest) const
157+
{
158+
ColorHSLA col = *this;
159+
col.l = Darkest + col.l * (1.0f - Darkest);
160+
return col;
161+
}
162+
163+
constexpr unsigned Pack(bool Alpha = true) const
164+
{
165+
return color4_base::Pack(Alpha);
166+
}
167+
168+
constexpr unsigned Pack(float Darkest, bool Alpha = false) const
169+
{
170+
ColorHSLA col = *this;
171+
col.l = (l - Darkest) / (1 - Darkest);
172+
col.l = std::clamp(col.l, 0.0f, 1.0f);
173+
return col.Pack(Alpha);
174+
}
175+
};
176+
177+
class ColorHSVA : public color4_base<ColorHSVA>
178+
{
179+
public:
180+
using color4_base::color4_base;
181+
constexpr ColorHSVA() = default;
182+
};
183+
184+
class ColorRGBA : public color4_base<ColorRGBA>
185+
{
186+
public:
187+
using color4_base::color4_base;
188+
constexpr ColorRGBA() = default;
189+
190+
constexpr ColorRGBA Multiply(const ColorRGBA &Other) const
191+
{
192+
ColorRGBA Color = *this;
193+
Color.r *= Other.r;
194+
Color.g *= Other.g;
195+
Color.b *= Other.b;
196+
Color.a *= Other.a;
197+
return Color;
198+
}
199+
200+
template<Numeric T>
201+
constexpr ColorRGBA Multiply(const T &Factor) const
202+
{
203+
ColorRGBA Color = *this;
204+
Color.r *= Factor;
205+
Color.g *= Factor;
206+
Color.b *= Factor;
207+
Color.a *= Factor;
208+
return Color;
209+
}
210+
};
211+
212+
template<typename T, typename F>
213+
constexpr T color_cast(const F &) = delete;
214+
215+
template<>
216+
constexpr ColorHSLA color_cast(const ColorRGBA &rgb)
217+
{
218+
float Min = minimum(rgb.r, rgb.g, rgb.b);
219+
float Max = maximum(rgb.r, rgb.g, rgb.b);
220+
221+
float c = Max - Min;
222+
float h = RgbToHue(rgb.r, rgb.g, rgb.b);
223+
float l = 0.5f * (Max + Min);
224+
float s = (Max != 0.0f && Min != 1.0f) ? (c / (1 - (absolute(2 * l - 1)))) : 0;
225+
226+
return ColorHSLA(h, s, l, rgb.a);
227+
}
228+
229+
template<>
230+
constexpr ColorRGBA color_cast(const ColorHSLA &hsl)
231+
{
232+
float h1 = hsl.h * 6;
233+
float c = (1.f - absolute(2 * hsl.l - 1)) * hsl.s;
234+
float x = c * (1.f - absolute(std::fmod(h1, 2) - 1.f));
235+
236+
float r = 0.0f;
237+
float g = 0.0f;
238+
float b = 0.0f;
239+
switch(round_truncate(h1))
240+
{
241+
case 0:
242+
r = c;
243+
g = x;
244+
break;
245+
case 1:
246+
r = x;
247+
g = c;
248+
break;
249+
case 2:
250+
g = c;
251+
b = x;
252+
break;
253+
case 3:
254+
g = x;
255+
b = c;
256+
break;
257+
case 4:
258+
r = x;
259+
b = c;
260+
break;
261+
case 5:
262+
case 6:
263+
r = c;
264+
b = x;
265+
break;
266+
}
267+
268+
float m = hsl.l - (c / 2);
269+
return ColorRGBA(r + m, g + m, b + m, hsl.a);
270+
}
271+
272+
template<>
273+
constexpr ColorHSLA color_cast(const ColorHSVA &hsv)
274+
{
275+
float l = hsv.v * (1 - hsv.s * 0.5f);
276+
return ColorHSLA(hsv.h, (l == 0.0f || l == 1.0f) ? 0 : (hsv.v - l) / minimum(l, 1 - l), l, hsv.a);
277+
}
278+
279+
template<>
280+
constexpr ColorHSVA color_cast(const ColorHSLA &hsl)
281+
{
282+
float v = hsl.l + hsl.s * minimum(hsl.l, 1 - hsl.l);
283+
return ColorHSVA(hsl.h, v == 0.0f ? 0 : 2 - (2 * hsl.l / v), v, hsl.a);
284+
}
285+
286+
template<>
287+
constexpr ColorRGBA color_cast(const ColorHSVA &hsv)
288+
{
289+
return color_cast<ColorRGBA>(color_cast<ColorHSLA>(hsv));
290+
}
291+
292+
template<>
293+
constexpr ColorHSVA color_cast(const ColorRGBA &rgb)
294+
{
295+
return color_cast<ColorHSVA>(color_cast<ColorHSLA>(rgb));
296+
}
297+
298+
template<typename T>
299+
constexpr T color_scale(const T &col, float s)
300+
{
301+
return T(col.x * s, col.y * s, col.z * s, col.a * s);
302+
}
303+
304+
template<typename T>
305+
constexpr T color_invert(const T &col)
306+
{
307+
return T(1.0f - col.x, 1.0f - col.y, 1.0f - col.z, 1.0f - col.a);
308+
}
309+
310+
template<typename T>
311+
std::optional<T> color_parse(const char *pStr);
312+
313+
#endif
314+
#endif

0 commit comments

Comments
 (0)