Skip to content

Commit 9b7fe28

Browse files
committed
RGBA support
1 parent 1ffb716 commit 9b7fe28

File tree

1 file changed

+105
-17
lines changed

1 file changed

+105
-17
lines changed

src/main.cpp

Lines changed: 105 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,80 @@
1414
// the source template at `configured_files/config.hpp.in`.
1515
#include <internal_use_only/config.hpp>
1616

17+
template<typename Type> struct Basic_Color;
1718

18-
struct Color
19+
template<typename OutType, typename InType>
20+
[[nodiscard]] constexpr Basic_Color<OutType> color_cast(Basic_Color<InType> input) noexcept
1921
{
20-
std::uint8_t R{};
21-
std::uint8_t G{};
22-
std::uint8_t B{};
22+
if constexpr (std::is_same_v<OutType, InType>) { return input; }
23+
24+
constexpr auto to = [] {
25+
if constexpr (std::is_floating_point_v<InType>) {
26+
if constexpr (std::is_floating_point_v<OutType>) {
27+
// just static cast from one floating point to another
28+
return [](const auto in) { return static_cast<OutType>(in); };
29+
} else {
30+
// from floating point to integral
31+
// we want to scale 0-1 to 0-maxint for given type
32+
return
33+
[](const auto in) { return static_cast<OutType>(std::llround(in * std::numeric_limits<OutType>::max())); };
34+
}
35+
} else {
36+
// input is not floating point
37+
if constexpr (std::is_integral_v<OutType>) {
38+
// and neither is output
39+
return [](const auto in) {
40+
// scale 0-1, then scale that to output type
41+
return static_cast<OutType>(
42+
std::llround((static_cast<double>(in) / static_cast<double>(std::numeric_limits<InType>::max()))
43+
* static_cast<double>(std::numeric_limits<OutType>::max())));
44+
};
45+
} else {
46+
// output is floating point
47+
return [](const auto in) {
48+
return static_cast<OutType>(in) / static_cast<OutType>(std::numeric_limits<InType>::max());
49+
};
50+
}
51+
}
52+
}();
53+
54+
return Basic_Color<OutType>{ to(input.R), to(input.G), to(input.B), to(input.A) };
55+
}
56+
57+
template<typename Type> struct Basic_Color
58+
{
59+
Type R{};
60+
Type G{};
61+
Type B{};
62+
Type A{};
63+
64+
65+
template<typename RHS> constexpr auto &operator+=(Basic_Color<RHS> rhs) noexcept
66+
{
67+
// from stackoverflow
68+
// Short answer:
69+
// if we want to overlay c0 over c1 both with some alpha then
70+
// a01 = (1 - a0)·a1 + a0
71+
// r01 = ((1 - a0)·a1·r1 + a0·r0) / a01
72+
// g01 = ((1 - a0)·a1·g1 + a0·g0) / a01
73+
// b01 = ((1 - a0)·a1·b1 + a0·b0) / a01
74+
75+
const auto c1 = color_cast<double>(*this);
76+
const auto c0 = color_cast<double>(rhs);
77+
auto c01 = Basic_Color<double>{};
78+
79+
c01.A = (1 - c0.A) * c1.A + c0.A;
80+
c01.R = ((1 - c0.A) * c1.A * c1.R + c0.A * c0.R) / c01.A;
81+
c01.G = ((1 - c0.A) * c1.A * c1.G + c0.A * c0.G) / c01.A;
82+
c01.B = ((1 - c0.A) * c1.A * c1.B + c0.A * c0.B) / c01.A;
83+
84+
*this = color_cast<Type>(c01);
85+
return *this;
86+
}
2387
};
2488

89+
using Color = Basic_Color<std::uint8_t>;
90+
2591
struct Size
2692
{
2793
std::size_t width;
@@ -137,12 +203,19 @@ struct Bitmap : ftxui::Node
137203
Vector2D<Color> pixels;
138204
};
139205

206+
140207
struct Location
141208
{
142209
std::function<void()> action;
143210
std::function<void(Vector2D_Span<Color> &, std::chrono::milliseconds, Point)> draw;
144211
};
145212

213+
struct Character
214+
{
215+
Point map_location{};
216+
std::function<void(Vector2D_Span<Color> &, std::chrono::milliseconds, Point)> draw;
217+
};
218+
146219

147220
struct Game_Map
148221
{
@@ -161,18 +234,16 @@ Game_Map make_map()
161234
for (std::size_t x = 0; x < pixels.size().width; ++x) {
162235
for (std::size_t y = 0; y < pixels.size().height; ++y) {
163236
if (x == 0 || y == 0 || x == pixels.size().width - 1 || y == pixels.size().height - 1) {
164-
pixels.at(Point{ x, y }) = Color{ 128, 128, 128 };// NOLINT Magic numbers
237+
pixels.at(Point{ x, y }) = Color{ 128, 128, 128, 255 };// NOLINT Magic numbers
165238
} else {
166-
switch ((game_clock.count() / 1000) % 2) { // NOLINT Magic numbers
167-
case 0:
168-
pixels.at(Point{ x, y }) = Color{ 255, 255, 255 };// NOLINT Magic numbers
169-
break;
170-
case 1: // NOLINT Magic Numbers
171-
pixels.at(Point{ x, y }) = Color{ 200, 240, 240 };// NOLINT Magic numbers
172-
break;
239+
switch ((game_clock.count() / 1000) % 2) {// NOLINT Magic numbers
240+
case 0:
241+
pixels.at(Point{ x, y }) = Color{ 255, 255, 255, 255 };// NOLINT Magic numbers
242+
break;
243+
case 1:// NOLINT Magic Numbers
244+
pixels.at(Point{ x, y }) = Color{ 200, 240, 240, 255 };// NOLINT Magic numbers
245+
break;
173246
}
174-
175-
176247
}
177248
}
178249
}
@@ -236,24 +307,41 @@ void game_iteration_canvas()
236307
double fps = 0;
237308
auto start_time = std::chrono::steady_clock::now();
238309

310+
Character player;
311+
player.draw = []([[maybe_unused]] Vector2D_Span<Color> &pixels,
312+
[[maybe_unused]] std::chrono::milliseconds game_clock,
313+
[[maybe_unused]] Point map_location) {
314+
// with with a fully saturated red at 50% alpha
315+
for (std::size_t x = 0; x < pixels.size().width; ++x) {
316+
for (std::size_t y = 0; y < pixels.size().height; ++y) {
317+
pixels.at(Point{ x, y }) += Color{ 255, 0, 0, 128 };// NOLINT magic number
318+
}
319+
}
320+
};
239321

240322
// to do, add total game time clock also, not just current elapsed time
241323
auto game_iteration = [&](const std::chrono::steady_clock::duration elapsed_time) {
242324
// in here we simulate however much game time has elapsed. Update animations,
243325
// run character AI, whatever, update stats, etc
244326

245-
// this isn't actually timing based for now, it's just updating the display however fast it can
246327
fps = 1.0
247328
/ (static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(elapsed_time).count())
248329
/ 1'000'000.0);// NOLINT magic numbers
249330

250-
const auto game_clock = std::chrono::steady_clock::now() - start_time;
331+
const auto game_clock =
332+
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time);
251333

334+
// just draw the map
252335
draw(*bm,
253336
Size{ 8, 8 },// NOLINT magic number
254337
Point{ 0, 0 },
255-
std::chrono::duration_cast<std::chrono::milliseconds>(game_clock),
338+
game_clock,
256339
map);
340+
341+
342+
auto player_span = Vector2D_Span<Color>(Point{ 20, 25 }, Size{ 10, 10 }, bm->pixels);// NOLINT Magic number
343+
344+
player.draw(player_span, game_clock, player.map_location);
257345
};
258346

259347
auto screen = ftxui::ScreenInteractive::TerminalOutput();

0 commit comments

Comments
 (0)