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+
2591struct Size
2692{
2793 std::size_t width;
@@ -137,12 +203,19 @@ struct Bitmap : ftxui::Node
137203 Vector2D<Color> pixels;
138204};
139205
206+
140207struct 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
147220struct 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