Skip to content

Commit 10919ab

Browse files
committed
Code reorganization
1 parent 7f3d314 commit 10919ab

File tree

9 files changed

+381
-278
lines changed

9 files changed

+381
-278
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ find_package(docopt CONFIG)
44
find_package(lodepng CONFIG)
55

66
# Generic test that uses conan libs
7-
add_executable(intro main.cpp)
7+
add_executable(intro main.cpp color.hpp size.hpp point.hpp vector2d.hpp bitmap.hpp bitmap.cpp game_components.hpp)
88
target_link_libraries(
99
intro
1010
PRIVATE project_options

src/bitmap.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include <lodepng.h>
2+
3+
#include "bitmap.hpp"
4+
5+
namespace lefticus::my_awesome_game {
6+
Vector2D<Color> load_png(const std::filesystem::path &filename)
7+
{
8+
std::vector<unsigned char> image;// the raw pixels
9+
unsigned width{};
10+
unsigned height{};
11+
12+
// decode
13+
unsigned error = lodepng::decode(image, width, height, filename.string());
14+
15+
// if there's an error, display it
16+
if (error != 0) {
17+
throw std::runtime_error(fmt::format("lodepng decoder error {}: {}", error, lodepng_error_text(error)));
18+
}
19+
20+
// the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ...
21+
//
22+
Vector2D<Color> results{ Size{ static_cast<std::size_t>(width), static_cast<std::size_t>(height) } };
23+
24+
std::size_t position = 0;
25+
for (std::size_t cur_y = 0; cur_y < results.size().height; ++cur_y) {
26+
for (std::size_t cur_x = 0; cur_x < results.size().width; ++cur_x) {
27+
auto &color = results.at(Point{ cur_x, cur_y });
28+
// cppcheck is wrong about this.
29+
color.R = image[position++];// cppcheck-suppress danglingTempReference
30+
color.G = image[position++];// cppcheck-suppress danglingTempReference
31+
color.B = image[position++];// cppcheck-suppress danglingTempReference
32+
color.A = image[position++];// cppcheck-suppress danglingTempReference
33+
}
34+
}
35+
36+
return results;
37+
}
38+
}// namespace lefticus::my_awesome_game

src/bitmap.hpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#ifndef MY_AWESOME_GAME_BITMAP_HPP
2+
#define MY_AWESOME_GAME_BITMAP_HPP
3+
4+
#include <filesystem>
5+
#include <ftxui/dom/node.hpp>
6+
7+
#include "color.hpp"
8+
#include "size.hpp"
9+
#include "vector2d.hpp"
10+
#include <fmt/format.h>
11+
12+
namespace lefticus::my_awesome_game {
13+
14+
// A simple way of representing a bitmap on screen using only characters
15+
struct Bitmap : ftxui::Node
16+
{
17+
explicit Bitmap(const Size size) : pixels(size) {}
18+
19+
void ComputeRequirement() override
20+
{
21+
requirement_ = ftxui::Requirement{ .min_x = static_cast<int>(pixels.size().width),
22+
.min_y = static_cast<int>(pixels.size().height / 2),
23+
.selected_box{ 0, 0, 0, 0 } };
24+
}
25+
26+
void Render(ftxui::Screen &screen) override
27+
{
28+
for (std::size_t cur_x = 0; cur_x < pixels.size().width; ++cur_x) {
29+
for (std::size_t cur_y = 0; cur_y < pixels.size().height / 2; ++cur_y) {
30+
auto &ftxui_pixel = screen.PixelAt(box_.x_min + static_cast<int>(cur_x), box_.y_min + static_cast<int>(cur_y));
31+
ftxui_pixel.character = "";
32+
const auto &top_color = pixels.at(Point{ cur_x, cur_y * 2 });
33+
const auto &bottom_color = pixels.at(Point{ cur_x, cur_y * 2 + 1 });
34+
ftxui_pixel.background_color = ftxui::Color{ top_color.R, top_color.G, top_color.B };
35+
ftxui_pixel.foreground_color = ftxui::Color{ bottom_color.R, bottom_color.G, bottom_color.B };
36+
}
37+
}
38+
}
39+
40+
Vector2D<Color> pixels;
41+
};
42+
43+
Vector2D<Color> load_png(const std::filesystem::path &filename);
44+
45+
}// namespace lefticus::my_awesome_game
46+
47+
#endif// MY_AWESOME_GAME_BITMAP_HPP

src/color.hpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#ifndef MY_AWESOME_GAME_COLOR_HPP
2+
#define MY_AWESOME_GAME_COLOR_HPP
3+
4+
#include <cmath>
5+
#include <cstdint>
6+
#include <limits>
7+
#include <type_traits>
8+
9+
10+
// Todo: move this into `tools` project?
11+
namespace lefticus::my_awesome_game {
12+
template<typename Type> struct Basic_Color;
13+
14+
template<typename OutType, typename InType>
15+
[[nodiscard]] constexpr Basic_Color<OutType> color_cast(Basic_Color<InType> input) noexcept
16+
{
17+
if constexpr (std::is_same_v<OutType, InType>) { return input; }
18+
19+
constexpr auto to_function = [] {
20+
if constexpr (std::is_floating_point_v<InType>) {
21+
if constexpr (std::is_floating_point_v<OutType>) {
22+
// just static cast from one floating point to_function another
23+
return [](const auto input_color_component) { return static_cast<OutType>(input_color_component); };
24+
} else {
25+
// from floating point to_function integral
26+
// we want to_function scale 0-1 to_function 0-maxint for given type
27+
return [](const auto input_color_component) {
28+
return static_cast<OutType>(std::llround(input_color_component * std::numeric_limits<OutType>::max()));
29+
};
30+
}
31+
} else {
32+
// input is not floating point
33+
if constexpr (std::is_integral_v<OutType>) {
34+
// and neither is output
35+
return [](const auto input_color_component) {
36+
// scale 0-1, then scale that to_function output type
37+
return static_cast<OutType>(std::llround(
38+
(static_cast<double>(input_color_component) / static_cast<double>(std::numeric_limits<InType>::max()))
39+
* static_cast<double>(std::numeric_limits<OutType>::max())));
40+
};
41+
} else {
42+
// output is floating point
43+
return [](const auto input_color_component) {
44+
return static_cast<OutType>(input_color_component) / static_cast<OutType>(std::numeric_limits<InType>::max());
45+
};
46+
}
47+
}
48+
}();
49+
50+
return Basic_Color<OutType>{ to_function(input.R), to_function(input.G), to_function(input.B), to_function(input.A) };
51+
}
52+
53+
template<typename Type> struct Basic_Color
54+
{
55+
Type R{};
56+
Type G{};
57+
Type B{};
58+
Type A{};
59+
60+
61+
template<typename RHS> constexpr auto &operator+=(Basic_Color<RHS> rhs) noexcept
62+
{
63+
// from stackoverflow
64+
// Short answer:
65+
// if we want to overlay color0 over color1 both with some alpha then
66+
// a01 = (1 - a0)·a1 + a0
67+
// r01 = ((1 - a0)·a1·r1 + a0·r0) / a01
68+
// g01 = ((1 - a0)·a1·g1 + a0·g0) / a01
69+
// b01 = ((1 - a0)·a1·b1 + a0·b0) / a01
70+
71+
const auto color1 = color_cast<double>(*this);
72+
const auto color0 = color_cast<double>(rhs);
73+
auto color01 = Basic_Color<double>{};
74+
75+
color01.A = (1 - color0.A) * color1.A + color0.A;
76+
color01.R = ((1 - color0.A) * color1.A * color1.R + color0.A * color0.R) / color01.A;
77+
color01.G = ((1 - color0.A) * color1.A * color1.G + color0.A * color0.G) / color01.A;
78+
color01.B = ((1 - color0.A) * color1.A * color1.B + color0.A * color0.B) / color01.A;
79+
80+
*this = color_cast<Type>(color01);
81+
return *this;
82+
}
83+
};
84+
85+
using Color = Basic_Color<std::uint8_t>;
86+
}// namespace lefticus::my_awesome_game
87+
88+
#endif// MY_AWESOME_GAME_COLOR_HPP

src/game_components.hpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#ifndef MY_AWESOME_GAME_GAME_COMPONENTS_HPP
2+
#define MY_AWESOME_GAME_GAME_COMPONENTS_HPP
3+
4+
#include <functional>
5+
#include <chrono>
6+
#include <map>
7+
8+
#include "color.hpp"
9+
#include "vector2d.hpp"
10+
11+
namespace lefticus::my_awesome_game
12+
{
13+
14+
enum struct Direction { North, South, East, West };
15+
16+
struct Location
17+
{
18+
std::function<void()> action;
19+
std::function<void(Vector2D_Span<Color> &, std::chrono::milliseconds, Point)> draw;
20+
std::function<bool(std::chrono::milliseconds, Point, Direction)> can_enter;
21+
};
22+
23+
struct Character
24+
{
25+
Point map_location{};
26+
std::function<void(Vector2D_Span<Color> &, std::chrono::milliseconds, Point)> draw;
27+
};
28+
29+
30+
struct Game_Map
31+
{
32+
explicit Game_Map(const Size size) : locations{ size } {}
33+
Vector2D<Location> locations;
34+
[[nodiscard]] bool can_enter_from(std::chrono::milliseconds game_clock, Point location, Direction from) const
35+
{
36+
const auto &map_location = locations.at(location);
37+
if (map_location.can_enter) {
38+
return map_location.can_enter(game_clock, location, from);
39+
} else {
40+
return true;
41+
}
42+
}
43+
};
44+
45+
struct Game
46+
{
47+
48+
std::map<std::string, Game_Map> maps;
49+
Character character;
50+
std::function<void (Game &)> start_game;
51+
52+
};
53+
54+
}
55+
56+
#endif// MY_AWESOME_GAME_GAME_COMPONENTS_HPP

0 commit comments

Comments
 (0)