Compare commits

...

34 Commits

Author SHA1 Message Date
m
73b49dd403 Pushing whats there 2024-11-22 13:46:04 -05:00
m
70b762b2ce Some corrections to cellular automata generation 2023-07-23 15:41:01 -04:00
53e3bf7fa4 Merge pull request 'feature/rla-19_Zoom' (#20) from feature/rla-19_Zoom into master
Reviewed-on: #20
2023-07-23 18:39:48 +00:00
m
ddfa3c1dc9 Zoom fully working and code cleaned up, scaling x and y now done in game rather than rendering, closes #19 2023-07-23 14:39:16 -04:00
m
3d056481b2 Merge branch 'master' into feature/rla-19_Zoom 2023-07-23 14:34:34 -04:00
m
206868efc5 Working zoom 2023-07-23 14:33:59 -04:00
f2f875a976 Merge pull request 'Implements cellular automata, closes #13' (#16) from feature/rla-13_CellularAutomata into master
Reviewed-on: #16
2023-07-23 17:45:59 +00:00
m
a11e4fa5a1 Implements cellular automata, closes #13 2023-07-23 13:45:25 -04:00
f5bd7c949a Merge pull request 'Removes the test alog, cleans up some renderer stuff, starts work on cellular automata, closes #14' (#15) from feature/rla-14_AlgorithmsUI into master
Reviewed-on: #15
2023-07-23 14:58:44 +00:00
m
f6b6293532 Removes the test alog, cleans up some renderer stuff, starts work on cellular automata, closes #14 2023-07-23 10:58:01 -04:00
daef8463bf Merge pull request 'feature/rla-11_AlgorithmsP1' (#12) from feature/rla-11_AlgorithmsP1 into master
Reviewed-on: #12
2023-07-23 05:04:15 +00:00
m
abf3e3a719 Cleaned up drunken walk, closes #11 2023-07-23 01:03:10 -04:00
m
d7fa6069f8 Drunken walk working but needs some updates as it can go 'off map' and then walk back in, effectively 2023-07-23 00:57:19 -04:00
55e2186c86 Merge pull request 'feature/rla-7_Logging' (#10) from feature/rla-7_Logging into master
Reviewed-on: #10
2023-07-19 02:01:13 +00:00
m
dbf0458f82 Adds engine configurable minimum logging level, closes #7 2023-07-18 22:00:20 -04:00
m
f71ecc432a Adds basic logging setup using a static logger and a few logging levels 2023-07-18 21:56:06 -04:00
8f454f6cdc Merge pull request 'Switches to a rendering pipeline with separated out steps, closes #8' (#9) from feature/rla-8_RenderingPipeline into master
Reviewed-on: #9
2023-07-18 22:38:12 +00:00
m
ec07eeda57 Switches to a rendering pipeline with separated out steps, closes #8 2023-07-18 18:36:38 -04:00
m
16ca6de3d4 Switch to vcpkg from Conan after something broke our build and the Conan support in clion seems outdated 2023-07-17 23:35:05 -04:00
a01ff2ec0e Renderers no longer have an init function and are expected to be prepared in their constructor (whatever it is)
We can do something similar for input processor (probably a good idea?) or go with the plan for game and use a template, engine can know about the renderers as long as it treats them as generic pointers, but shouldn't know about the game
Game can either be a templated make_unique or we can just enforce a game class naming
Or pass game in at start loop
2022-01-20 08:49:32 -05:00
bc6fa836b0 Moved out renderer to being selected in engine constructor based on a parsed enum. Next is to have the renderer initialize in constructor, and probably make game into a templated parameter that does the same along with input processor 2022-01-20 08:20:17 -05:00
1a917af13c fixed several memory leaks caused by not including virtual destructors, added a config for the visualizer, next up is lua 2021-12-22 12:33:47 -05:00
00abbbebbd Fixed an issue with lua context manager, tested to make sure it worked, started a document for the algorithm lua structure, updated engine loop 2021-12-12 23:36:13 -05:00
8213dd8cb3 started pulling in lua stuff, fixed an issue with camera range 2021-12-12 17:17:09 -05:00
d5fd89e228 ranges done, cool stuff 2021-12-12 12:06:31 -05:00
f360be0c8d About to test out ranges of points 2021-12-12 10:42:53 -05:00
cd37945791 Added some helpers to camera and range lib to replace the standard ranges library due to some issues clangd has with the gcc implementation 2021-12-12 03:48:56 -05:00
a328246a1e added support for smaller maps than the window 2021-12-11 22:00:21 -05:00
2308ef4eb2 Camera implemented 2021-12-11 21:32:43 -05:00
10e2b3c538 Added default font and exception throwing to replace some nullptr returns 2021-12-11 12:10:56 -05:00
d2826f08fe color keying for sprite sheets and properly keyed texture map params 2021-12-10 11:53:07 -05:00
ea172110ea switched up some pointers to shared, added some more rendering example 2021-12-06 23:38:36 -05:00
994a128c14 Input processor interface and sdl implementation added, now frees text textures after displaying text, need to look into caching so we can let manager handle it 2021-12-06 14:54:11 -05:00
26b341ee63 sprites and ttf work 2021-12-05 22:24:10 -05:00
51 changed files with 2104 additions and 154 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
/cmake-build-debug/
.name

View File

@@ -1,10 +1,36 @@
cmake_minimum_required(VERSION 3.22) # Specifies the required CMake version.
set(CMAKE_CXX_STANDARD 20) # c++ 20
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
cmake_minimum_required(VERSION 3.16) # Specifies the required CMake version.
project(rla_iipp) # Defines the project name.
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) # Includes the contents of the conanbuildinfo.cmake file.
conan_basic_setup() # Prepares the CMakeList.txt for Conan.
#[[include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) # Includes the contents of the conanbuildinfo.cmake file.
conan_basic_setup() # Prepares the CMakeList.txt for Conan.]]
# $source_files is a space-delimited list of filenames.
add_executable(rla_iipp src/main.cpp src/engine/engine.hpp src/engine/game/game.hpp src/engine/rendering/renderer.hpp src/game/visualizer.hpp src/game/visualizer.cpp src/engine/rendering/sdl/sdlrenderer.cpp src/engine/rendering/sdl/sdlrenderer.hpp src/engine/rendering/sdl/sdlrenderer.cpp src/engine/rendering/sdl/sdlrenderer.hpp src/engine/engine.cpp src/engine/engine.hpp src/engine/rendering/sdl/sdltexturemanager.cpp src/engine/rendering/sdl/sdltexturemanager.hpp) # Specifies the executable to build.
target_link_libraries(rla_iipp ${CONAN_LIBS}) # Specifies what libraries to link, using Conan.
file(COPY assets DESTINATION ${CMAKE_BINARY_DIR}/bin)
add_executable(rla_iipp src/main.cpp src/engine/engine.hpp src/engine/game/game.hpp src/engine/rendering/renderer.hpp src/game/visualizer.hpp src/game/visualizer.cpp src/engine/rendering/sdl/sdlrenderer.cpp src/engine/rendering/sdl/sdlrenderer.hpp src/engine/rendering/sdl/sdlrenderer.cpp src/engine/rendering/sdl/sdlrenderer.hpp src/engine/engine.cpp src/engine/engine.hpp src/engine/rendering/sdl/sdltexturemanager.cpp src/engine/rendering/sdl/sdltexturemanager.hpp src/engine/resources/resourcemanager.hpp src/engine/rendering/sdl/sdlfontmanager.cpp src/engine/rendering/sdl/sdlfontmanager.hpp src/engine/input/inputprocessor.hpp src/engine/input/sdlinputprocessor.cpp src/engine/input/sdlinputprocessor.hpp src/engine/utility/camera.cpp src/engine/utility/camera.hpp src/engine/utility/point.hpp src/engine/utility/rectangle.hpp src/engine/utility/grid2d.hpp src/engine/scripting/luacontextmanager.cpp src/engine/scripting/luacontextmanager.hpp src/game/algorithmmanager.cpp src/game/algorithmmanager.hpp src/game/tilemap.cpp src/game/tilemap.hpp src/engine/rlengineexception.hpp src/engine/rendering/renderingpipelinestep.hpp src/engine/rendering/pipeline_steps/gamerenderingstep.cpp src/engine/rendering/pipeline_steps/gamerenderingstep.hpp src/engine/rendering/pipeline_steps/fpscounterrenderingstep.cpp src/engine/rendering/pipeline_steps/fpscounterrenderingstep.hpp src/engine/modules/logger.cpp src/engine/modules/logger.hpp) # Specifies the executable to build.
# vcpkg packages
find_package(SDL2 CONFIG REQUIRED)
target_link_libraries(rla_iipp
PRIVATE
$<TARGET_NAME_IF_EXISTS:SDL2::SDL2main>
$<IF:$<TARGET_EXISTS:SDL2::SDL2>,SDL2::SDL2,SDL2::SDL2-static>
)
find_package(SDL2_ttf CONFIG REQUIRED)
target_link_libraries(rla_iipp PRIVATE $<IF:$<TARGET_EXISTS:SDL2_ttf::SDL2_ttf>,SDL2_ttf::SDL2_ttf,SDL2_ttf::SDL2_ttf-static>)
find_package(SDL2_image CONFIG REQUIRED)
target_link_libraries(rla_iipp PRIVATE $<IF:$<TARGET_EXISTS:SDL2_image::SDL2_image>,SDL2_image::SDL2_image,SDL2_image::SDL2_image-static>)
find_package(fmt CONFIG REQUIRED)
target_link_libraries(rla_iipp PRIVATE fmt::fmt)
find_package(tomlplusplus CONFIG REQUIRED)
target_link_libraries(rla_iipp PRIVATE tomlplusplus::tomlplusplus)
find_package(sol2 CONFIG REQUIRED)
target_link_libraries(rla_iipp PRIVATE lua)
target_link_libraries(rla_iipp PRIVATE sol2)
find_package(range-v3 CONFIG REQUIRED)
target_link_libraries(rla_iipp PRIVATE range-v3::meta range-v3::concepts range-v3::range-v3)
#[[target_link_libraries(rla_iipp ${CONAN_LIBS}) # Specifies what libraries to link, using Conan.]]
file(COPY assets DESTINATION ${CMAKE_BINARY_DIR}/bin)
file(COPY config DESTINATION ${CMAKE_BINARY_DIR}/bin)
file(COPY scripts DESTINATION ${CMAKE_BINARY_DIR}/bin)

Binary file not shown.

BIN
assets/fonts/lazy.ttf Executable file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

BIN
assets/sprites/map0.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

BIN
assets/sprites/map1.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

BIN
assets/sprites/map2.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

View File

@@ -1,7 +0,0 @@
[requires]
sdl/2.0.16
sdl_ttf/2.0.15
sdl_image/2.0.5
lua/5.4.3
[generators]
cmake

16
config/engine.toml Normal file
View File

@@ -0,0 +1,16 @@
[display]
target_fps = 61
window_width = 800
window_height = 600
window_title = "Roguelike Algorithm Visualizer"
rendering_engine = 0
[overlay]
show_fps = true
[logging]
minimum_level = 1
[font]
default_font_name = "Consolas-Regular"
default_font_size = 12

9
config/visualizer.toml Normal file
View File

@@ -0,0 +1,9 @@
[rendering]
tile_size_w = 48
tile_size_h = 48
[map]
map_size_w = 80
map_size_h = 50
floor_char = '.'
wall_char = '#'

28
documents/algorithms.txt Normal file
View File

@@ -0,0 +1,28 @@
Dungeon generation algorithms are written in lua and dropped into scripting->algorithms. They are automatically parsed by the visualizer and assigned keys in the program to run them.
Algorithms are made up of a single lua file (possibly more with requires) with the following functionality:
Provided:
global algorithm_manager.register_algorithm(name, init_function, update_function, updates_per_second)
Registers an algorithm with the program with a given name, init function, update function, and updates per second
map.draw_floor(x, y)
Draws a floor on the map at a given x, y position
map.draw_wall(x, y)
draws a wall on the map at a given x, y position
map.fill(bool wall)
Fills the map with either floors (false) or walls (true)
map.is_wall(x, y)
returns true if map[x,y] is a wall, false otherwise
Necessary:
init_function(map_w, map_h)
Should initialize the function fresh with a given width and height.
update()
Called updates_per_second times per second. Should calculate new map state and draw on the map as needed. The map will have the previous state retained.
Returns true if finished, else false

View File

@@ -0,0 +1,84 @@
CellularAutomata = {
map_w = 0,
map_h = 0,
iterations = 0,
}
function CellularAutomata.get_neighbors(map, x, y)
local min_x = math.max(0, x-1)
local min_y = math.max(0, y-1)
local max_x = math.min(x+1, map:get_width()-1)
local max_y = math.min(y+1, map:get_height()-1)
local result = {}
for mx = min_x, max_x do
for my = min_y, max_y do
table.insert(result, {x = mx, y = my})
end
end
return result
end
function CellularAutomata:initialize(w, h)
self.map_w = w
self.map_h = h
self.iterations = 3
math.randomseed()
for mx = 0, w-1 do
for my = 0, h-1 do
local is_wall = math.random(0, 1) == 1
if is_wall then
visualizer.map:draw_wall(mx, my)
else
visualizer.map:draw_floor(mx, my)
end
end
end
end
function CellularAutomata:update()
if self.iterations <= 0 then
return true
end
local old_map = visualizer.map
local new_map = old_map:clone()
for mx = 0, self.map_w - 1 do
for my = 0, self.map_h - 1 do
local neighbors = self.get_neighbors(old_map, mx, my)
local expected_neighbors = 9
local walls = expected_neighbors - #neighbors
local required_walls = 5
--print(old_map:is_wall(mx, my))
--print(new_map:is_wall(mx, my))
for k,v in ipairs(neighbors) do
if old_map:is_wall(v.x, v.y) then
walls = walls + 1
end
end
if walls >= required_walls then
new_map:draw_wall(mx, my)
else
new_map:draw_floor(mx, my)
end
--print(old_map:is_wall(mx, my))
--print(new_map:is_wall(mx, my))
end
end
-- Now draw the new map onto the existing one
for mx = 0, self.map_w - 1 do
for my = 0, self.map_h - 1 do
if new_map:is_wall(mx, my) then
old_map:draw_wall(mx, my)
else
old_map:draw_floor(mx, my)
end
end
end
self.iterations = self.iterations - 1
return false
end
visualizer.algorithm_manager:register_algorithm("Cellular Automata", function (w, h) CellularAutomata:initialize(w, h) end, function () return CellularAutomata:update() end, 1)

View File

@@ -0,0 +1,36 @@
DrunkenWalk = {
curr_x = 0,
curr_y = 0,
map_w = 0,
map_h = 0,
iterations = 0
}
function DrunkenWalk:initialize(w, h)
math.randomseed()
self.map_w = w
self.map_h = h
self.iterations = 200
visualizer.map:fill(true)
self.curr_x = math.random(0, w-1)
self.curr_y = math.random(0, h-1);
end
function DrunkenWalk:update()
new_x = self.curr_x + math.random(-1, 1)
new_y = self.curr_y + math.random(-1, 1)
while new_x >= self.map_w or new_x < 0 or new_y >= self.map_h or new_y < 0 do
new_x = self.curr_x + math.random(-1, 1)
new_y = self.curr_y + math.random(-1, 1)
end
self.curr_x = new_x
self.curr_y = new_y
visualizer.map:draw_floor(self.curr_x, self.curr_y)
self.iterations = self.iterations - 1
if self.iterations == 0 then
return true
end
return false
end
visualizer.algorithm_manager:register_algorithm("Drunken Walk", function (w, h) DrunkenWalk:initialize(w, h) end, function () return DrunkenWalk:update() end, 60)

View File

@@ -3,56 +3,110 @@
//
#include "engine.hpp"
#include <cstdio>
#include "rendering/sdl/sdlrenderer.hpp"
#include "rlengineexception.hpp"
#include "rendering/pipeline_steps/gamerenderingstep.hpp"
#include "rendering/pipeline_steps/fpscounterrenderingstep.hpp"
#include <chrono>
#include <thread>
#include <lua.hpp>
#include <exception>
using namespace std::chrono_literals;
void Engine::start_loop() {
const auto one_second_milli = std::chrono::milliseconds(1s);
if(game == nullptr) {
printf("game is null\n");
return;
throw MissingGameException();
}
if(renderer == nullptr) {
printf("renderer is null\n");
return;
throw MissingRendererException();
}
RendererParams renderParams = game->get_renderer_params();
renderer->initialize(renderParams);
renderer->flush();
auto duration_per_frame = one_second_milli / game->get_framerate();
auto last_frame = std::chrono::high_resolution_clock::now();
auto game_params = GameInitArgs{this->config.target_fps, this->config.window_width, this->config.window_height};
game->initialize(game_params);
Logger::log(LogLevel::DEBUG, "Engine init finished");
std::vector<std::unique_ptr<RenderingPipelineStep>> rendering_steps = build_render_pipline();
auto duration_per_frame = one_second_milli / this->config.target_fps;
while(true) {
auto starttime = std::chrono::high_resolution_clock::now();
bool end = game->update();
// Input and update
auto input = this->input_processor->process_input();
bool end = game->update(input);
if(end) {
break;
}
game->render(renderer.get());
// Rendering
std::for_each(rendering_steps.begin(), rendering_steps.end(), [this](std::unique_ptr<RenderingPipelineStep>& step) {
step->render_step(this->renderer.get());
});
renderer->flush();
// timing and sleep
auto endtime = std::chrono::high_resolution_clock::now();
last_frame = render_fps(endtime, last_frame);
std::this_thread::sleep_for(duration_per_frame);
auto update_duration = std::chrono::duration_cast<std::chrono::milliseconds>(endtime - starttime);
std::this_thread::sleep_for(duration_per_frame - update_duration);
}
}
Engine::Engine(std::unique_ptr<Game> game, std::unique_ptr<Renderer> renderer) {
this->renderer = std::move(renderer);
Engine::Engine(std::unique_ptr<Game> game,
std::unique_ptr<InputProcessor> input_processor) {
this->game = std::move(game);
this->input_processor = std::move(input_processor);
this->parse_config(ENGINE_CONFIG_FILE);
Logger::set_minimum_loglevel(this->config.minimum_loglevel);
this->setup_renderer(this->config.selected_renderer);
}
std::chrono::time_point<std::chrono::system_clock>
Engine::render_fps(std::chrono::time_point<std::chrono::system_clock> end,
std::chrono::time_point<std::chrono::system_clock> lastframe) {
double frames = 1;
std::chrono::duration<double> dur = end - lastframe;
if(SHOW_FPS) {
printf("fps: %f\n", frames/dur.count());
}
return end;
void Engine::load_config(const std::string &path, const std::function<void (toml::table)>& f) {
std::string full_path = fmt::format("{}/{}", CONFIG_DIR, path);
auto table = toml::parse_file(full_path);
f(table);
}
void Engine::parse_config(const std::string& config_file_path) {
EngineConfig new_config = EngineConfig();
load_config("engine.toml", [&new_config](const toml::table& table) {
new_config.show_fps = table["overlay"]["show_fps"].value_or<bool>(DEFAULT_SHOW_FPS);
new_config.window_width = table["display"]["window_width"].value_or(DEFAULT_WINDOW_WIDTH);
new_config.window_height = table["display"]["window_height"].value_or(DEFAULT_WINDOW_HEIGHT);
new_config.target_fps = table["display"]["target_fps"].value_or(DEFAULT_TARGET_FPS);
new_config.window_title = table["display"]["window_title"].value_or(DEFAULT_WINDOW_TITLE);
auto default_font_path = fmt::format("fonts/{}.ttf", table["font"]["default_font_name"].value_or(DEFAULT_FONT_NAME));
auto default_font_size = table["font"]["default_font_size"].value_or(DEFAULT_FONT_SIZE);
new_config.default_font = TextRenderDetails{default_font_path, default_font_size, COLOR_WHITE};
new_config.selected_renderer = static_cast<RendererTypes>(table["display"]["rendering_engine"].value_or((int)RendererTypes::SDL_HARDWARE));
new_config.minimum_loglevel = static_cast<LogLevel>(table["logging"]["minimum_level"].value_or((int)LogLevel::DEBUG));
});
this->config = new_config;
}
void Engine::setup_renderer(RendererTypes rendering_engine) {
std::unique_ptr<Renderer> rendering_engine_ptr;
auto render_params = RendererParams{this->config.window_title, this->config.window_width, this->config.window_height, this->config.default_font};
switch(rendering_engine) {
case SDL_HARDWARE: rendering_engine_ptr = std::make_unique<SdlRenderer>(render_params); break;
default: throw RLEngineException("Invalid renderer specified");
}
this->renderer = std::move(rendering_engine_ptr);
}
std::vector<std::unique_ptr<RenderingPipelineStep>> Engine::build_render_pipline() {
std::vector<std::unique_ptr<RenderingPipelineStep>> result = std::vector<std::unique_ptr<RenderingPipelineStep>>();
result.push_back(std::make_unique<GameRenderingStep>(this->game.get()));
if(this->config.show_fps) {
result.push_back(std::make_unique<FpsCounterRenderingStep>());
}
return result;
}
Engine::~Engine() = default;
const char *MissingGameException::what() const noexcept {
return MISSING_GAME_ERROR;
}
const char *MissingRendererException::what() const noexcept {
return MISSING_RENDERER_ERROR;
}

View File

@@ -4,23 +4,73 @@
#ifndef RLA_IIPP_ENGINE_HPP
#define RLA_IIPP_ENGINE_HPP
#define FMT_HEADER_ONLY
#include <memory>
#include <chrono>
#include "game/game.hpp"
#include <fmt/format.h>
#include <toml++/toml.h>
#include <functional>
#include "rendering/renderer.hpp"
static const bool SHOW_FPS = true;
static const std::string RESOURCE_DIR = "assets";
#include "input/inputprocessor.hpp"
#include "rendering/renderingpipelinestep.hpp"
#include "modules/logger.hpp"
#define MISSING_GAME_ERROR "Game pointer is null"
#define MISSING_RENDERER_ERROR "Renderer pointer is null"
#define RESOURCE_DIR "assets"
#define CONFIG_DIR "config"
#define DEFAULT_TARGET_FPS 61
#define DEFAULT_WINDOW_WIDTH 800
#define DEFAULT_WINDOW_HEIGHT 600
#define DEFAULT_WINDOW_TITLE "RLEngine"
#define DEFAULT_SHOW_FPS false
#define DEFAULT_FONT_NAME "Consolas-Regular"
#define DEFAULT_FONT_SIZE 12
#define ENGINE_CONFIG_FILE "engine.toml"
enum RendererTypes : int {
SDL_HARDWARE = 0
};
struct EngineConfig {
unsigned int target_fps;
int window_width;
int window_height;
bool show_fps;
std::string window_title;
TextRenderDetails default_font;
RendererTypes selected_renderer;
LogLevel minimum_loglevel;
};
class Engine {
public:
Engine(std::unique_ptr<Game> game, std::unique_ptr<Renderer> renderer);
Engine(std::unique_ptr<Game> game,
std::unique_ptr<InputProcessor> input_processor);
void start_loop();
std::chrono::time_point<std::chrono::system_clock> render_fps(std::chrono::time_point<std::chrono::system_clock> end, std::chrono::time_point<std::chrono::system_clock> lastframe);
static void load_config(const std::string& path, const std::function<void (toml::table)>& f);
virtual ~Engine();
private:
EngineConfig config;
std::unique_ptr<Game> game = nullptr;
std::unique_ptr<Renderer> renderer = nullptr;
std::unique_ptr<InputProcessor> input_processor = nullptr;
void parse_config(const std::string& config_file_path);
void setup_renderer(RendererTypes rendering_engine);
std::vector<std::unique_ptr<RenderingPipelineStep>> build_render_pipline();
};
class MissingGameException : public std::exception {
public:
[[nodiscard]] const char *what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW override;
};
class MissingRendererException : public std::exception {
public:
[[nodiscard]] const char *what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW override;
};

View File

@@ -5,12 +5,21 @@
#ifndef RLA_IIPP_GAME_HPP
#define RLA_IIPP_GAME_HPP
#include "../rendering/renderer.hpp"
#include "../input/inputprocessor.hpp"
struct GameInitArgs {
unsigned int target_fps;
int window_width;
int window_height;
};
class Game {
public:
virtual bool update() = 0;
virtual bool update(InputResult input) = 0;
virtual void render(Renderer* renderer) = 0;
virtual RendererParams get_renderer_params() = 0;
virtual unsigned int get_framerate() = 0;
virtual void initialize(GameInitArgs args)=0;
virtual ~Game()=default;
};
#endif //RLA_IIPP_GAME_HPP

View File

@@ -0,0 +1,275 @@
//
// Created by m on 12/6/21.
//
#ifndef RLA_IIPP_INPUTPROCESSOR_HPP
#define RLA_IIPP_INPUTPROCESSOR_HPP
enum InputProcessorKeycode {
KEY_UNKNOWN,
KEY_RETURN,
KEY_ESCAPE,
KEY_BACKSPACE,
KEY_TAB,
KEY_SPACE,
KEY_EXCLAIM,
KEY_QUOTEDBL,
KEY_HASH,
KEY_PERCENT,
KEY_DOLLAR,
KEY_AMPERSAND,
KEY_QUOTE,
KEY_LEFTPAREN,
KEY_RIGHTPAREN,
KEY_ASTERISK,
KEY_PLUS,
KEY_COMMA,
KEY_MINUS,
KEY_PERIOD,
KEY_SLASH,
KEY_0,
KEY_1,
KEY_2,
KEY_3,
KEY_4,
KEY_5,
KEY_6,
KEY_7,
KEY_8,
KEY_9,
KEY_COLON,
KEY_SEMICOLON,
KEY_LESS,
KEY_EQUALS,
KEY_GREATER,
KEY_QUESTION,
KEY_AT,
KEY_LEFTBRACKET,
KEY_BACKSLASH,
KEY_RIGHTBRACKET,
KEY_CARET,
KEY_UNDERSCORE,
KEY_BACKQUOTE,
KEY_a,
KEY_b,
KEY_c,
KEY_d,
KEY_e,
KEY_f,
KEY_g,
KEY_h,
KEY_i,
KEY_j,
KEY_k,
KEY_l,
KEY_m,
KEY_n,
KEY_o,
KEY_p,
KEY_q,
KEY_r,
KEY_s,
KEY_t,
KEY_u,
KEY_v,
KEY_w,
KEY_x,
KEY_y,
KEY_z,
KEY_CAPSLOCK,
KEY_F1,
KEY_F2,
KEY_F3,
KEY_F4,
KEY_F5,
KEY_F6,
KEY_F7,
KEY_F8,
KEY_F9,
KEY_F10,
KEY_F11,
KEY_F12,
KEY_PRINTSCREEN,
KEY_SCROLLLOCK,
KEY_PAUSE,
KEY_INSERT,
KEY_HOME,
KEY_PAGEUP,
KEY_DELETE,
KEY_END,
KEY_PAGEDOWN,
KEY_RIGHT,
KEY_LEFT,
KEY_DOWN,
KEY_UP,
KEY_NUMLOCKCLEAR,
KEY_KP_DIVIDE,
KEY_KP_MULTIPLY,
KEY_KP_MINUS,
KEY_KP_PLUS,
KEY_KP_ENTER,
KEY_KP_1,
KEY_KP_2,
KEY_KP_3,
KEY_KP_4,
KEY_KP_5,
KEY_KP_6,
KEY_KP_7,
KEY_KP_8,
KEY_KP_9,
KEY_KP_0,
KEY_KP_PERIOD,
KEY_APPLICATION,
KEY_POWER,
KEY_KP_EQUALS,
KEY_F13,
KEY_F14,
KEY_F15,
KEY_F16,
KEY_F17,
KEY_F18,
KEY_F19,
KEY_F20,
KEY_F21,
KEY_F22,
KEY_F23,
KEY_F24,
KEY_EXECUTE,
KEY_HELP,
KEY_MENU,
KEY_SELECT,
KEY_STOP,
KEY_AGAIN,
KEY_UNDO,
KEY_CUT,
KEY_COPY,
KEY_PASTE,
KEY_FIND,
KEY_MUTE,
KEY_VOLUMEUP,
KEY_VOLUMEDOWN,
KEY_KP_COMMA,
KEY_KP_EQUALSAS400,
KEY_ALTERASE,
KEY_SYSREQ,
KEY_CANCEL,
KEY_CLEAR,
KEY_PRIOR,
KEY_RETURN2,
KEY_SEPARATOR,
KEY_OUT,
KEY_OPER,
KEY_CLEARAGAIN,
KEY_CRSEL,
KEY_EXSEL,
KEY_KP_00,
KEY_KP_000,
KEY_THOUSANDSSEPARATOR,
KEY_DECIMALSEPARATOR,
KEY_CURRENCYUNIT,
KEY_CURRENCYSUBUNIT,
KEY_KP_LEFTPAREN,
KEY_KP_RIGHTPAREN,
KEY_KP_LEFTBRACE,
KEY_KP_RIGHTBRACE,
KEY_KP_TAB,
KEY_KP_BACKSPACE,
KEY_KP_A,
KEY_KP_B,
KEY_KP_C,
KEY_KP_D,
KEY_KP_E,
KEY_KP_F,
KEY_KP_XOR,
KEY_KP_POWER,
KEY_KP_PERCENT,
KEY_KP_LESS,
KEY_KP_GREATER,
KEY_KP_AMPERSAND,
KEY_KP_DBLAMPERSAND,
KEY_KP_VERTICALBAR,
KEY_KP_DBLVERTICALBAR,
KEY_KP_COLON,
KEY_KP_HASH,
KEY_KP_SPACE,
KEY_KP_AT,
KEY_KP_EXCLAM,
KEY_KP_MEMSTORE,
KEY_KP_MEMRECALL,
KEY_KP_MEMCLEAR,
KEY_KP_MEMADD,
KEY_KP_MEMSUBTRACT,
KEY_KP_MEMMULTIPLY,
KEY_KP_MEMDIVIDE,
KEY_KP_PLUSMINUS,
KEY_KP_CLEAR,
KEY_KP_CLEARENTRY,
KEY_KP_BINARY,
KEY_KP_OCTAL,
KEY_KP_DECIMAL,
KEY_KP_HEXADECIMAL,
KEY_LCTRL,
KEY_LSHIFT,
KEY_LALT,
KEY_LGUI,
KEY_RCTRL,
KEY_RSHIFT,
KEY_RALT,
KEY_RGUI,
KEY_MODE,
KEY_AUDIONEXT,
KEY_AUDIOPREV,
KEY_AUDIOSTOP,
KEY_AUDIOPLAY,
KEY_AUDIOMUTE,
KEY_MEDIASELECT,
KEY_WWW,
KEY_MAIL,
KEY_CALCULATOR,
KEY_COMPUTER,
KEY_AC_SEARCH,
KEY_AC_HOME,
KEY_AC_BACK,
KEY_AC_FORWARD,
KEY_AC_STOP,
KEY_AC_REFRESH,
KEY_AC_BOOKMARKS,
KEY_BRIGHTNESSDOWN,
KEY_BRIGHTNESSUP,
KEY_DISPLAYSWITCH,
KEY_KBDILLUMTOGGLE,
KEY_KBDILLUMDOWN,
KEY_KBDILLUMUP,
KEY_EJECT,
KEY_SLEEP,
KEY_APP1,
KEY_APP2,
KEY_AUDIOREWIND,
KEY_AUDIOFASTFORWARD
};
struct InputResult {
InputProcessorKeycode keycode = KEY_UNKNOWN;
};
class InputProcessor {
public:
virtual InputResult process_input()=0;
virtual ~InputProcessor()=default;
};
#endif //RLA_IIPP_INPUTPROCESSOR_HPP

View File

@@ -0,0 +1,294 @@
//
// Created by m on 12/6/21.
//
#include "sdlinputprocessor.hpp"
InputResult SdlInputProcessor::process_input() {
SDL_Event event;
InputResult result;
while(SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_QUIT: exit(EXIT_SUCCESS); // immediately exit here, eventually maybe make this na input
case SDL_KEYDOWN: result.keycode = get_keycode(event.key.keysym.sym); break;
}
}
return result;
}
SdlInputProcessor::SdlInputProcessor() {
this->keycode_map[SDLK_UNKNOWN] = KEY_UNKNOWN;
this->keycode_map[SDLK_RETURN] = KEY_RETURN;
this->keycode_map[SDLK_ESCAPE] = KEY_ESCAPE;
this->keycode_map[SDLK_BACKSPACE] = KEY_BACKSPACE;
this->keycode_map[SDLK_TAB] = KEY_TAB;
this->keycode_map[SDLK_SPACE] = KEY_SPACE;
this->keycode_map[SDLK_EXCLAIM] = KEY_EXCLAIM;
this->keycode_map[SDLK_QUOTEDBL] = KEY_QUOTEDBL;
this->keycode_map[SDLK_HASH] = KEY_HASH;
this->keycode_map[SDLK_PERCENT] = KEY_PERCENT;
this->keycode_map[SDLK_DOLLAR] = KEY_DOLLAR;
this->keycode_map[SDLK_AMPERSAND] = KEY_AMPERSAND;
this->keycode_map[SDLK_QUOTE] = KEY_QUOTE;
this->keycode_map[SDLK_LEFTPAREN] = KEY_LEFTPAREN;
this->keycode_map[SDLK_RIGHTPAREN] = KEY_RIGHTPAREN;
this->keycode_map[SDLK_ASTERISK] = KEY_ASTERISK;
this->keycode_map[SDLK_PLUS] = KEY_PLUS;
this->keycode_map[SDLK_COMMA] = KEY_COMMA;
this->keycode_map[SDLK_MINUS] = KEY_MINUS;
this->keycode_map[SDLK_PERIOD] = KEY_PERIOD;
this->keycode_map[SDLK_SLASH] = KEY_SLASH;
this->keycode_map[SDLK_0] = KEY_0;
this->keycode_map[SDLK_1] = KEY_1;
this->keycode_map[SDLK_2] = KEY_2;
this->keycode_map[SDLK_3] = KEY_3;
this->keycode_map[SDLK_4] = KEY_4;
this->keycode_map[SDLK_5] = KEY_5;
this->keycode_map[SDLK_6] = KEY_6;
this->keycode_map[SDLK_7] = KEY_7;
this->keycode_map[SDLK_8] = KEY_8;
this->keycode_map[SDLK_9] = KEY_9;
this->keycode_map[SDLK_COLON] = KEY_COLON;
this->keycode_map[SDLK_SEMICOLON] = KEY_SEMICOLON;
this->keycode_map[SDLK_LESS] = KEY_LESS;
this->keycode_map[SDLK_EQUALS] = KEY_EQUALS;
this->keycode_map[SDLK_GREATER] = KEY_GREATER;
this->keycode_map[SDLK_QUESTION] = KEY_QUESTION;
this->keycode_map[SDLK_AT] = KEY_AT;
this->keycode_map[SDLK_LEFTBRACKET] = KEY_LEFTBRACKET;
this->keycode_map[SDLK_BACKSLASH] = KEY_BACKSLASH;
this->keycode_map[SDLK_RIGHTBRACKET] = KEY_RIGHTBRACKET;
this->keycode_map[SDLK_CARET] = KEY_CARET;
this->keycode_map[SDLK_UNDERSCORE] = KEY_UNDERSCORE;
this->keycode_map[SDLK_BACKQUOTE] = KEY_BACKQUOTE;
this->keycode_map[SDLK_a] = KEY_a;
this->keycode_map[SDLK_b] = KEY_b;
this->keycode_map[SDLK_c] = KEY_c;
this->keycode_map[SDLK_d] = KEY_d;
this->keycode_map[SDLK_e] = KEY_e;
this->keycode_map[SDLK_f] = KEY_f;
this->keycode_map[SDLK_g] = KEY_g;
this->keycode_map[SDLK_h] = KEY_h;
this->keycode_map[SDLK_i] = KEY_i;
this->keycode_map[SDLK_j] = KEY_j;
this->keycode_map[SDLK_k] = KEY_k;
this->keycode_map[SDLK_l] = KEY_l;
this->keycode_map[SDLK_m] = KEY_m;
this->keycode_map[SDLK_n] = KEY_n;
this->keycode_map[SDLK_o] = KEY_o;
this->keycode_map[SDLK_p] = KEY_p;
this->keycode_map[SDLK_q] = KEY_q;
this->keycode_map[SDLK_r] = KEY_r;
this->keycode_map[SDLK_s] = KEY_s;
this->keycode_map[SDLK_t] = KEY_t;
this->keycode_map[SDLK_u] = KEY_u;
this->keycode_map[SDLK_v] = KEY_v;
this->keycode_map[SDLK_w] = KEY_w;
this->keycode_map[SDLK_x] = KEY_x;
this->keycode_map[SDLK_y] = KEY_y;
this->keycode_map[SDLK_z] = KEY_z;
this->keycode_map[SDLK_CAPSLOCK] = KEY_CAPSLOCK;
this->keycode_map[SDLK_F1] = KEY_F1;
this->keycode_map[SDLK_F2] = KEY_F2;
this->keycode_map[SDLK_F3] = KEY_F3;
this->keycode_map[SDLK_F4] = KEY_F4;
this->keycode_map[SDLK_F5] = KEY_F5;
this->keycode_map[SDLK_F6] = KEY_F6;
this->keycode_map[SDLK_F7] = KEY_F7;
this->keycode_map[SDLK_F8] = KEY_F8;
this->keycode_map[SDLK_F9] = KEY_F9;
this->keycode_map[SDLK_F10] = KEY_F10;
this->keycode_map[SDLK_F11] = KEY_F11;
this->keycode_map[SDLK_F12] = KEY_F12;
this->keycode_map[SDLK_PRINTSCREEN] = KEY_PRINTSCREEN;
this->keycode_map[SDLK_SCROLLLOCK] = KEY_SCROLLLOCK;
this->keycode_map[SDLK_PAUSE] = KEY_PAUSE;
this->keycode_map[SDLK_INSERT] = KEY_INSERT;
this->keycode_map[SDLK_HOME] = KEY_HOME;
this->keycode_map[SDLK_PAGEUP] = KEY_PAGEUP;
this->keycode_map[SDLK_DELETE] = KEY_DELETE;
this->keycode_map[SDLK_END] = KEY_END;
this->keycode_map[SDLK_PAGEDOWN] = KEY_PAGEDOWN;
this->keycode_map[SDLK_RIGHT] = KEY_RIGHT;
this->keycode_map[SDLK_LEFT] = KEY_LEFT;
this->keycode_map[SDLK_DOWN] = KEY_DOWN;
this->keycode_map[SDLK_UP] = KEY_UP;
this->keycode_map[SDLK_NUMLOCKCLEAR] = KEY_NUMLOCKCLEAR;
this->keycode_map[SDLK_KP_DIVIDE] = KEY_KP_DIVIDE;
this->keycode_map[SDLK_KP_MULTIPLY] = KEY_KP_MULTIPLY;
this->keycode_map[SDLK_KP_MINUS] = KEY_KP_MINUS;
this->keycode_map[SDLK_KP_PLUS] = KEY_KP_PLUS;
this->keycode_map[SDLK_KP_ENTER] = KEY_KP_ENTER;
this->keycode_map[SDLK_KP_1] = KEY_KP_1;
this->keycode_map[SDLK_KP_2] = KEY_KP_2;
this->keycode_map[SDLK_KP_3] = KEY_KP_3;
this->keycode_map[SDLK_KP_4] = KEY_KP_4;
this->keycode_map[SDLK_KP_5] = KEY_KP_5;
this->keycode_map[SDLK_KP_6] = KEY_KP_6;
this->keycode_map[SDLK_KP_7] = KEY_KP_7;
this->keycode_map[SDLK_KP_8] = KEY_KP_8;
this->keycode_map[SDLK_KP_9] = KEY_KP_9;
this->keycode_map[SDLK_KP_0] = KEY_KP_0;
this->keycode_map[SDLK_KP_PERIOD] = KEY_KP_PERIOD;
this->keycode_map[SDLK_APPLICATION] = KEY_APPLICATION;
this->keycode_map[SDLK_POWER] = KEY_POWER;
this->keycode_map[SDLK_KP_EQUALS] = KEY_KP_EQUALS;
this->keycode_map[SDLK_F13] = KEY_F13;
this->keycode_map[SDLK_F14] = KEY_F14;
this->keycode_map[SDLK_F15] = KEY_F15;
this->keycode_map[SDLK_F16] = KEY_F16;
this->keycode_map[SDLK_F17] = KEY_F17;
this->keycode_map[SDLK_F18] = KEY_F18;
this->keycode_map[SDLK_F19] = KEY_F19;
this->keycode_map[SDLK_F20] = KEY_F20;
this->keycode_map[SDLK_F21] = KEY_F21;
this->keycode_map[SDLK_F22] = KEY_F22;
this->keycode_map[SDLK_F23] = KEY_F23;
this->keycode_map[SDLK_F24] = KEY_F24;
this->keycode_map[SDLK_EXECUTE] = KEY_EXECUTE;
this->keycode_map[SDLK_HELP] = KEY_HELP;
this->keycode_map[SDLK_MENU] = KEY_MENU;
this->keycode_map[SDLK_SELECT] = KEY_SELECT;
this->keycode_map[SDLK_STOP] = KEY_STOP;
this->keycode_map[SDLK_AGAIN] = KEY_AGAIN;
this->keycode_map[SDLK_UNDO] = KEY_UNDO;
this->keycode_map[SDLK_CUT] = KEY_CUT;
this->keycode_map[SDLK_COPY] = KEY_COPY;
this->keycode_map[SDLK_PASTE] = KEY_PASTE;
this->keycode_map[SDLK_FIND] = KEY_FIND;
this->keycode_map[SDLK_MUTE] = KEY_MUTE;
this->keycode_map[SDLK_VOLUMEUP] = KEY_VOLUMEUP;
this->keycode_map[SDLK_VOLUMEDOWN] = KEY_VOLUMEDOWN;
this->keycode_map[SDLK_KP_COMMA] = KEY_KP_COMMA;
this->keycode_map[SDLK_KP_EQUALSAS400] = KEY_KP_EQUALSAS400;
this->keycode_map[SDLK_ALTERASE] = KEY_ALTERASE;
this->keycode_map[SDLK_SYSREQ] = KEY_SYSREQ;
this->keycode_map[SDLK_CANCEL] = KEY_CANCEL;
this->keycode_map[SDLK_CLEAR] = KEY_CLEAR;
this->keycode_map[SDLK_PRIOR] = KEY_PRIOR;
this->keycode_map[SDLK_RETURN2] = KEY_RETURN2;
this->keycode_map[SDLK_SEPARATOR] = KEY_SEPARATOR;
this->keycode_map[SDLK_OUT] = KEY_OUT;
this->keycode_map[SDLK_OPER] = KEY_OPER;
this->keycode_map[SDLK_CLEARAGAIN] = KEY_CLEARAGAIN;
this->keycode_map[SDLK_CRSEL] = KEY_CRSEL;
this->keycode_map[SDLK_EXSEL] = KEY_EXSEL;
this->keycode_map[SDLK_KP_00] = KEY_KP_00;
this->keycode_map[SDLK_KP_000] = KEY_KP_000;
this->keycode_map[SDLK_THOUSANDSSEPARATOR] = KEY_THOUSANDSSEPARATOR;
this->keycode_map[SDLK_DECIMALSEPARATOR] = KEY_DECIMALSEPARATOR;
this->keycode_map[SDLK_CURRENCYUNIT] = KEY_CURRENCYUNIT;
this->keycode_map[SDLK_CURRENCYSUBUNIT] = KEY_CURRENCYSUBUNIT;
this->keycode_map[SDLK_KP_LEFTPAREN] = KEY_KP_LEFTPAREN;
this->keycode_map[SDLK_KP_RIGHTPAREN] = KEY_KP_RIGHTPAREN;
this->keycode_map[SDLK_KP_LEFTBRACE] = KEY_KP_LEFTBRACE;
this->keycode_map[SDLK_KP_RIGHTBRACE] = KEY_KP_RIGHTBRACE;
this->keycode_map[SDLK_KP_TAB] = KEY_KP_TAB;
this->keycode_map[SDLK_KP_BACKSPACE] = KEY_KP_BACKSPACE;
this->keycode_map[SDLK_KP_A] = KEY_KP_A;
this->keycode_map[SDLK_KP_B] = KEY_KP_B;
this->keycode_map[SDLK_KP_C] = KEY_KP_C;
this->keycode_map[SDLK_KP_D] = KEY_KP_D;
this->keycode_map[SDLK_KP_E] = KEY_KP_E;
this->keycode_map[SDLK_KP_F] = KEY_KP_F;
this->keycode_map[SDLK_KP_XOR] = KEY_KP_XOR;
this->keycode_map[SDLK_KP_POWER] = KEY_KP_POWER;
this->keycode_map[SDLK_KP_PERCENT] = KEY_KP_PERCENT;
this->keycode_map[SDLK_KP_LESS] = KEY_KP_LESS;
this->keycode_map[SDLK_KP_GREATER] = KEY_KP_GREATER;
this->keycode_map[SDLK_KP_AMPERSAND] = KEY_KP_AMPERSAND;
this->keycode_map[SDLK_KP_DBLAMPERSAND] = KEY_KP_DBLAMPERSAND;
this->keycode_map[SDLK_KP_VERTICALBAR] = KEY_KP_VERTICALBAR;
this->keycode_map[SDLK_KP_DBLVERTICALBAR] = KEY_KP_DBLVERTICALBAR;
this->keycode_map[SDLK_KP_COLON] = KEY_KP_COLON;
this->keycode_map[SDLK_KP_HASH] = KEY_KP_HASH;
this->keycode_map[SDLK_KP_SPACE] = KEY_KP_SPACE;
this->keycode_map[SDLK_KP_AT] = KEY_KP_AT;
this->keycode_map[SDLK_KP_EXCLAM] = KEY_KP_EXCLAM;
this->keycode_map[SDLK_KP_MEMSTORE] = KEY_KP_MEMSTORE;
this->keycode_map[SDLK_KP_MEMRECALL] = KEY_KP_MEMRECALL;
this->keycode_map[SDLK_KP_MEMCLEAR] = KEY_KP_MEMCLEAR;
this->keycode_map[SDLK_KP_MEMADD] = KEY_KP_MEMADD;
this->keycode_map[SDLK_KP_MEMSUBTRACT] = KEY_KP_MEMSUBTRACT;
this->keycode_map[SDLK_KP_MEMMULTIPLY] = KEY_KP_MEMMULTIPLY;
this->keycode_map[SDLK_KP_MEMDIVIDE] = KEY_KP_MEMDIVIDE;
this->keycode_map[SDLK_KP_PLUSMINUS] = KEY_KP_PLUSMINUS;
this->keycode_map[SDLK_KP_CLEAR] = KEY_KP_CLEAR;
this->keycode_map[SDLK_KP_CLEARENTRY] = KEY_KP_CLEARENTRY;
this->keycode_map[SDLK_KP_BINARY] = KEY_KP_BINARY;
this->keycode_map[SDLK_KP_OCTAL] = KEY_KP_OCTAL;
this->keycode_map[SDLK_KP_DECIMAL] = KEY_KP_DECIMAL;
this->keycode_map[SDLK_KP_HEXADECIMAL] = KEY_KP_HEXADECIMAL;
this->keycode_map[SDLK_LCTRL] = KEY_LCTRL;
this->keycode_map[SDLK_LSHIFT] = KEY_LSHIFT;
this->keycode_map[SDLK_LALT] = KEY_LALT;
this->keycode_map[SDLK_LGUI] = KEY_LGUI;
this->keycode_map[SDLK_RCTRL] = KEY_RCTRL;
this->keycode_map[SDLK_RSHIFT] = KEY_RSHIFT;
this->keycode_map[SDLK_RALT] = KEY_RALT;
this->keycode_map[SDLK_RGUI] = KEY_RGUI;
this->keycode_map[SDLK_MODE] = KEY_MODE;
this->keycode_map[SDLK_AUDIONEXT] = KEY_AUDIONEXT;
this->keycode_map[SDLK_AUDIOPREV] = KEY_AUDIOPREV;
this->keycode_map[SDLK_AUDIOSTOP] = KEY_AUDIOSTOP;
this->keycode_map[SDLK_AUDIOPLAY] = KEY_AUDIOPLAY;
this->keycode_map[SDLK_AUDIOMUTE] = KEY_AUDIOMUTE;
this->keycode_map[SDLK_MEDIASELECT] = KEY_MEDIASELECT;
this->keycode_map[SDLK_WWW] = KEY_WWW;
this->keycode_map[SDLK_MAIL] = KEY_MAIL;
this->keycode_map[SDLK_CALCULATOR] = KEY_CALCULATOR;
this->keycode_map[SDLK_COMPUTER] = KEY_COMPUTER;
this->keycode_map[SDLK_AC_SEARCH] = KEY_AC_SEARCH;
this->keycode_map[SDLK_AC_HOME] = KEY_AC_HOME;
this->keycode_map[SDLK_AC_BACK] = KEY_AC_BACK;
this->keycode_map[SDLK_AC_FORWARD] = KEY_AC_FORWARD;
this->keycode_map[SDLK_AC_STOP] = KEY_AC_STOP;
this->keycode_map[SDLK_AC_REFRESH] = KEY_AC_REFRESH;
this->keycode_map[SDLK_AC_BOOKMARKS] = KEY_AC_BOOKMARKS;
this->keycode_map[SDLK_BRIGHTNESSDOWN] = KEY_BRIGHTNESSDOWN;
this->keycode_map[SDLK_BRIGHTNESSUP] = KEY_BRIGHTNESSUP;
this->keycode_map[SDLK_DISPLAYSWITCH] = KEY_DISPLAYSWITCH;
this->keycode_map[SDLK_KBDILLUMTOGGLE] = KEY_KBDILLUMTOGGLE;
this->keycode_map[SDLK_KBDILLUMDOWN] = KEY_KBDILLUMDOWN;
this->keycode_map[SDLK_KBDILLUMUP] = KEY_KBDILLUMUP;
this->keycode_map[SDLK_EJECT] = KEY_EJECT;
this->keycode_map[SDLK_SLEEP] = KEY_SLEEP;
this->keycode_map[SDLK_APP1] = KEY_APP1;
this->keycode_map[SDLK_APP2] = KEY_APP2;
this->keycode_map[SDLK_AUDIOREWIND] = KEY_AUDIOREWIND;
this->keycode_map[SDLK_AUDIOFASTFORWARD] = KEY_AUDIOFASTFORWARD;
}
InputProcessorKeycode SdlInputProcessor::get_keycode(SDL_Keycode keycode) {
if(this->keycode_map.find(keycode) == this->keycode_map.end()) {
return KEY_UNKNOWN;
}
return this->keycode_map[keycode];
}

View File

@@ -0,0 +1,26 @@
//
// Created by m on 12/6/21.
//
#ifndef RLA_IIPP_SDLINPUTPROCESSOR_HPP
#define RLA_IIPP_SDLINPUTPROCESSOR_HPP
#include "inputprocessor.hpp"
#include <SDL.h>
#include <unordered_map>
class SdlInputProcessor : public InputProcessor {
InputResult process_input() override;
public:
SdlInputProcessor();
~SdlInputProcessor() override = default;
private:
std::unordered_map<SDL_Keycode,InputProcessorKeycode> keycode_map;
InputProcessorKeycode get_keycode(SDL_Keycode keycode);
};
#endif //RLA_IIPP_SDLINPUTPROCESSOR_HPP

View File

@@ -0,0 +1,47 @@
//
// Created by m on 7/18/23.
//
#include "logger.hpp"
#include <fmt/format.h>
#include <fmt/chrono.h>
#include <iostream>
LogLevel Logger::minimum_loglevel = LogLevel::DEBUG;
void Logger::set_minimum_loglevel(LogLevel logLevel) {
Logger::minimum_loglevel = logLevel;
}
void Logger::log(LogLevel level, const std::string &msg) {
if(level < Logger::minimum_loglevel) {
return;
}
auto loglevel_name = "UNKNOWN";
switch (level) {
case LogLevel::TRACE:
loglevel_name = "TRA";
break;
case DEBUG:
loglevel_name = "DEB";
break;
case INFO:
loglevel_name = "INF";
break;
case WARNING:
loglevel_name = "WAR";
break;
case ERROR:
loglevel_name = "ERR";
break;
case NONE:
loglevel_name = "NON";
break;
}
auto output = fmt::format("[{}][{}] {}", std::chrono::system_clock::now(), loglevel_name, msg);
if(level == LogLevel::ERROR) {
std::cerr << output << "\n";
}
std::cout << output << "\n";
}

View File

@@ -0,0 +1,29 @@
//
// Created by m on 7/18/23.
//
#ifndef RLA_IIPP_LOGGER_HPP
#define RLA_IIPP_LOGGER_HPP
#include <string>
#include <unordered_map>
enum LogLevel: int {
TRACE = 0,
DEBUG = 1,
INFO = 2,
WARNING = 3,
ERROR = 4,
NONE = 5
};
class Logger {
public:
static void set_minimum_loglevel(LogLevel logLevel);
static void log(LogLevel level, const std::string& msg);
private:
static LogLevel minimum_loglevel;
};
#endif //RLA_IIPP_LOGGER_HPP

View File

@@ -0,0 +1,19 @@
//
// Created by m on 7/18/23.
//
#include <fmt/format.h>
#include "fpscounterrenderingstep.hpp"
void FpsCounterRenderingStep::render_step(Renderer *renderer) {
const double frames = 1;
const double smooth = 0.9;
std::chrono::time_point<std::chrono::system_clock> end = std::chrono::system_clock::now();
std::chrono::duration<double> dur = end - this->lastFrame;
renderer->draw_text(std::nullopt, fmt::format("{:.2f}", frames/dur.count()), 0, 0);
this->lastFrame = end;
}
FpsCounterRenderingStep::FpsCounterRenderingStep() {
this->lastFrame = std::chrono::high_resolution_clock::now();
}

View File

@@ -0,0 +1,22 @@
//
// Created by m on 7/18/23.
//
#ifndef RLA_IIPP_FPSCOUNTERRENDERINGSTEP_HPP
#define RLA_IIPP_FPSCOUNTERRENDERINGSTEP_HPP
#include <chrono>
#include "../renderingpipelinestep.hpp"
class FpsCounterRenderingStep : public RenderingPipelineStep {
void render_step(Renderer *renderer) override;
public:
FpsCounterRenderingStep();
private:
std::chrono::time_point<std::chrono::system_clock> lastFrame;
};
#endif //RLA_IIPP_FPSCOUNTERRENDERINGSTEP_HPP

View File

@@ -0,0 +1,11 @@
//
// Created by m on 7/18/23.
//
#include "gamerenderingstep.hpp"
void GameRenderingStep::render_step(Renderer *renderer) {
game->render(renderer);
}
GameRenderingStep::GameRenderingStep(Game *game) : game(game) {}

View File

@@ -0,0 +1,22 @@
//
// Created by m on 7/18/23.
//
#ifndef RLA_IIPP_GAMERENDERINGSTEP_HPP
#define RLA_IIPP_GAMERENDERINGSTEP_HPP
#include "../renderingpipelinestep.hpp"
#include "../../game/game.hpp"
class GameRenderingStep : public RenderingPipelineStep {
void render_step(Renderer *renderer) override;
private:
Game* game;
public:
explicit GameRenderingStep(Game *game);
};
#endif //RLA_IIPP_GAMERENDERINGSTEP_HPP

View File

@@ -5,6 +5,9 @@
#ifndef RLA_IIPP_RENDERER_HPP
#define RLA_IIPP_RENDERER_HPP
#include <string>
#include <memory>
#include <ostream>
#include <optional>
struct Color {
public:
@@ -13,21 +16,56 @@ public:
unsigned char b;
unsigned char a;
Color(){}
Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) : r(r), g(g), b(b), a(a) {}
};
#define COLOR_BLACK Color(0, 0, 0, 255)
#define COLOR_WHITE Color(255, 255, 255, 255)
#define COLOR_RED Color(255, 0, 0, 255)
#define COLOR_GREEN Color(0, 255, 0, 255)
#define COLOR_BLUE Color(0, 0, 255, 255)
struct SpriteSheet {
std::string path;
int sprite_width;
int sprite_height;
std::optional<Color> color_key;
};
struct Sprite {
SpriteSheet *sprite_sheet;
int index;
};
struct TextRenderDetails {
std::string font_path;
int size;
Color color;
TextRenderDetails(){};
TextRenderDetails(const std::string &fontPath, int size, const Color &color) : font_path(
fontPath), size(size), color(color) {}
};
struct RendererParams {
std::string title;
unsigned int width;
unsigned int height;
int width;
int height;
TextRenderDetails default_font;
};
class Renderer {
public:
virtual void initialize(RendererParams params)=0;
virtual void flush() = 0;
virtual void draw_point(int x, int y, Color color) = 0;
virtual void draw_text(std::string text,int x, int y)=0;
virtual void draw_text(std::optional<TextRenderDetails> details, std::string text,int x, int y)=0;
virtual void draw_sprite(Sprite sprite, int x, int y)=0;
virtual void draw_sprite(Sprite sprite, int x, int y, float scale)=0;
virtual TextRenderDetails get_default_text_render_details()=0;
virtual ~Renderer() = default;
};
#endif //RLA_IIPP_RENDERER_HPP

View File

@@ -0,0 +1,17 @@
//
// Created by m on 7/18/23.
//
#ifndef RLA_IIPP_RENDERINGPIPELINESTEP_HPP
#define RLA_IIPP_RENDERINGPIPELINESTEP_HPP
#include "renderer.hpp"
class RenderingPipelineStep {
public:
virtual ~RenderingPipelineStep() = default;
virtual void render_step(Renderer* renderer) = 0;
};
#endif //RLA_IIPP_RENDERINGPIPELINESTEP_HPP

View File

@@ -0,0 +1,18 @@
//
// Created by m on 12/5/21.
//
#include "sdlfontmanager.hpp"
std::string SdlFontManager::get_key(SdlFontArgs args) {
return fmt::format("{}_{}", args.size, get_resource_path(args.font_path));
}
std::shared_ptr<TTF_Font> SdlFontManager::load_resource(SdlFontArgs args) {
std::string path = get_resource_path(args.font_path);
TTF_Font *font = TTF_OpenFont(path.c_str(), args.size);
if(font == nullptr) {
throw MissingFontException(path, TTF_GetError());
}
return std::shared_ptr<TTF_Font>(font, TTF_CloseFont);
}

View File

@@ -0,0 +1,45 @@
//
// Created by m on 12/5/21.
//
#ifndef RLA_IIPP_SDLFONTMANAGER_HPP
#define RLA_IIPP_SDLFONTMANAGER_HPP
#include <string>
#include <utility>
#include <SDL_ttf.h>
#include "../../resources/resourcemanager.hpp"
struct SdlFontArgs {
int size;
std::string font_path;
SdlFontArgs(int size, std::string fontPath) : size(size), font_path(std::move(fontPath)) {}
};
class SdlFontManager : public ResourceManager<std::shared_ptr<TTF_Font>, std::string, SdlFontArgs> {
std::string get_key(SdlFontArgs args) override;
std::shared_ptr<TTF_Font> load_resource(SdlFontArgs args) override;
};
class MissingFontException : public std::exception {
private:
std::string msg;
public:
[[nodiscard]] const char *what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW override {
return msg.c_str();
}
explicit MissingFontException(const std::string& missing_font, std::string reason) {
msg = fmt::format("Unable to load font [{}] because: {}", missing_font, reason);
}
};
#endif //RLA_IIPP_SDLFONTMANAGER_HPP

View File

@@ -2,57 +2,102 @@
// Created by m on 12/3/21.
//
#include <cstdio>
#include <utility>
#include "sdlrenderer.hpp"
void SdlRenderer::initialize(RendererParams params) {
void SdlRenderer::flush() {
SDL_RenderPresent(this->renderer.get());
SDL_SetRenderDrawColor(this->renderer.get(), COLOR_BLACK.r, COLOR_BLACK.g, COLOR_BLACK.b, COLOR_BLACK.a);
SDL_RenderClear(this->renderer.get());
}
void SdlRenderer::draw_point(int x, int y, Color color) {
SDL_SetRenderDrawColor(this->renderer.get(), color.r, color.g, color.b, color.a);
SDL_RenderDrawPoint(this->renderer.get(), x, y);
}
void SdlRenderer::draw_text(std::optional<TextRenderDetails> details, std::string text, int x, int y) {
TextRenderDetails unpacked_details = details.value_or(this->renderer_params.default_font);
std::shared_ptr<TTF_Font> font = this->font_manager->fetch_resource(SdlFontArgs(unpacked_details.size, unpacked_details.font_path));
std::shared_ptr<SDL_Texture> texture = this->texture_manager->load_text_as_texture(text, font, unpacked_details.color);
render_texture(x, y, texture, nullptr, nullptr);
}
SdlRenderer::~SdlRenderer() {
// clear resource managers pointing to shared pointers
// This avoids an invalid read, since otherwise TTF_Quit will cleanup fonts and then clearing the shared pointers will try it again
font_manager->clear_all_resources();
texture_manager->clear_all_resources();
// exit subsystems
IMG_Quit();
TTF_Quit();
SDL_Quit();
}
void SdlRenderer::render_texture(int x, int y, const std::shared_ptr<SDL_Texture>& texture, SDL_Rect *src, SDL_Rect *dest) {
int w, h;
if(src == nullptr) {
SDL_QueryTexture(texture.get(), nullptr, nullptr, &w, &h);
}
else {
w = src->w;
h = src->h;
}
SDL_Rect destination_rect;
if(dest == nullptr) {
destination_rect = {x,y,w,h};
}
else {
destination_rect = *dest;
}
SDL_RenderCopy(this->renderer.get(), texture.get(), src, &destination_rect);
}
void SdlRenderer::draw_sprite(Sprite sprite, int x, int y) {
this->draw_sprite(sprite, x, y, 1);
}
void SdlRenderer::draw_sprite(Sprite sprite, int x, int y, float scale) {
SpriteSheet *sprite_sheet = sprite.sprite_sheet;
TextureManagerFetchArgs args = TextureManagerFetchArgs {sprite_sheet->path, sprite_sheet->color_key};
std::shared_ptr<SDL_Texture> texture = this->texture_manager->fetch_resource(args);
int w, h;
SDL_QueryTexture(texture.get(), nullptr, nullptr, &w, &h);
int l = (sprite_sheet->sprite_width * sprite.index) / w;
int src_y = l*sprite_sheet->sprite_height;
int src_x = (sprite_sheet->sprite_width * sprite.index) % w;
auto source = SDL_Rect{src_x, src_y, sprite_sheet->sprite_width, sprite_sheet->sprite_height};
auto dest = SDL_Rect {x, y, (int)std::ceil(sprite_sheet->sprite_width * scale), (int)std::ceil(sprite_sheet->sprite_height * scale)};
render_texture(x, y, texture, &source, &dest);
}
SdlRenderer::SdlRenderer(RendererParams renderer_params) : renderer_params(std::move(renderer_params)) {
if(SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("SDL vide oinit failed: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
auto img_flags = IMG_INIT_PNG;
if(!(IMG_Init(img_flags) & img_flags)) {
printf("Failed to init image loading: %s", IMG_GetError());
printf("Failed to init image loading: %s\n", IMG_GetError());
exit(EXIT_FAILURE);
}
SDL_Window* sdl_window = SDL_CreateWindow(params.title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, params.width, params.height, SDL_WINDOW_SHOWN);
if(TTF_Init() < 0) {
printf("Failed to initialize font loading: %s\n", TTF_GetError());
exit(EXIT_FAILURE);
}
SDL_Window* sdl_window = SDL_CreateWindow(this->renderer_params.title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, this->renderer_params.width, this->renderer_params.height, SDL_WINDOW_SHOWN);
if(sdl_window == nullptr) {
printf("error making window: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
else {
this->window = sdl_window;
SDL_Renderer* sdl_renderer = SDL_CreateRenderer(this->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
this->renderer = sdl_renderer;
this->window = std::unique_ptr<SDL_Window, SDL_WindowDeleter>(sdl_window);
SDL_Renderer* sdl_renderer = SDL_CreateRenderer(this->window.get(), -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
this->renderer = std::shared_ptr<SDL_Renderer>(sdl_renderer, SDL_DestroyRenderer);
this->texture_manager = std::make_unique<SdlTextureManager>();
this->texture_manager = std::make_unique<SdlTextureManager>(this->renderer);
this->font_manager = std::make_unique<SdlFontManager>();
SDL_RenderClear(this->renderer);
SDL_RenderClear(this->renderer.get());
}
}
void SdlRenderer::flush() {
SDL_RenderPresent(this->renderer);
SDL_SetRenderDrawColor(this->renderer, 0, 0, 0, 255);
SDL_RenderClear(this->renderer);
}
void SdlRenderer::draw_point(int x, int y, Color color) {
SDL_SetRenderDrawColor(this->renderer, color.r, color.g, color.b, color.a);
SDL_RenderDrawPoint(this->renderer, x, y);
}
void SdlRenderer::draw_text(std::string text, int x, int y) {
}
SdlRenderer::~SdlRenderer() {
// destroy components
SDL_DestroyRenderer(this->renderer);
this->renderer = nullptr;
SDL_DestroyWindow(this->window);
this->window = nullptr;
// exit subsystems
IMG_Quit();
SDL_Quit();
}

View File

@@ -6,27 +6,34 @@
#define RLA_IIPP_SDLRENDERER_HPP
#include "../renderer.hpp"
#include "sdltexturemanager.hpp"
#include "sdlfontmanager.hpp"
#include <SDL.h>
#include <SDL_ttf.h>
#include <SDL_image.h>
struct SDL_WindowDeleter {
void operator()(SDL_Window* window) { SDL_DestroyWindow(window);}
};
class SdlRenderer : public Renderer {
void initialize(RendererParams params) override;
public:
~SdlRenderer() override;
explicit SdlRenderer(RendererParams renderer_params);
void draw_text(std::optional<TextRenderDetails> details, std::string text, int x, int y) override;
void flush() override;
void draw_point(int x, int y, Color color) override;
public:
~SdlRenderer();
public:
void draw_text(std::string text, int x, int y) override;
void draw_sprite(Sprite sprite, int x, int y) override;
void draw_sprite(Sprite sprite, int x, int y, float scale) override;
TextRenderDetails get_default_text_render_details() override {
return this->renderer_params.default_font;
}
private:
SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
RendererParams renderer_params;
std::unique_ptr<SDL_Window, SDL_WindowDeleter> window;
std::shared_ptr<SDL_Renderer> renderer = nullptr;
std::unique_ptr<SdlTextureManager> texture_manager = nullptr;
std::unique_ptr<SdlFontManager> font_manager = nullptr;
void render_texture(int x, int y, const std::shared_ptr<SDL_Texture>& texture, SDL_Rect *src, SDL_Rect *dest);
};

View File

@@ -4,27 +4,6 @@
#include "sdltexturemanager.hpp"
SdlTextureManager::SdlTextureManager() {
this->texture_map = std::unordered_map<std::string, SDL_Texture*>();
}
SDL_Texture *SdlTextureManager::load_texture(const std::string &path, SDL_Renderer *renderer) {
std::string full_path = RESOURCE_DIR + "/" + path;
if(this->texture_map.find(full_path) == this->texture_map.end()) {
SDL_Surface* surface = load_surface(full_path);
if(surface == nullptr) {
return nullptr;
}
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
if(texture == nullptr) {
printf("failed ot load image into texture: %s\n", IMG_GetError());
}
this->texture_map[path] = texture;
SDL_FreeSurface(surface);
}
return this->texture_map[path];
}
SDL_Surface *SdlTextureManager::load_surface(const std::string& path) {
SDL_Surface* surface = IMG_Load(path.c_str());
if(surface == nullptr) {
@@ -33,8 +12,42 @@ SDL_Surface *SdlTextureManager::load_surface(const std::string& path) {
return surface;
}
SdlTextureManager::~SdlTextureManager() {
std::for_each(this->texture_map.begin(), this->texture_map.end(), [](const std::pair<std::string, SDL_Texture *>& pair) {
SDL_DestroyTexture(pair.second);
});
std::shared_ptr<SDL_Texture> SdlTextureManager::load_resource(TextureManagerFetchArgs args) {
std::string full_path = get_resource_path(args.path);
SDL_Surface* surface = load_surface(full_path);
if(surface == nullptr) {
throw MissingTextureException(full_path, SDL_GetError());
}
if(args.color_key.has_value()) {
Color color_key = args.color_key.value();
SDL_SetColorKey(surface, SDL_TRUE, SDL_MapRGB(surface->format, color_key.r, color_key.g, color_key.b));
}
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer.get(), surface);
SDL_FreeSurface(surface);
if(texture == nullptr) {
throw MissingTextureException(full_path, SDL_GetError());
}
return {texture, SDL_DestroyTexture};
}
std::string SdlTextureManager::get_key(TextureManagerFetchArgs args) {
std::string key;
if(args.color_key.has_value()) {
key += fmt::format("{}_{}_{}_{}_", args.color_key->r, args.color_key->g, args.color_key->b, args.color_key->a);
}
key += fmt::format("{}", args.path);
return key;
}
std::shared_ptr<SDL_Texture> SdlTextureManager::load_text_as_texture(const std::string& text, const std::shared_ptr<TTF_Font>& font, Color color) {
SDL_Surface *surface = TTF_RenderText_Solid(font.get(), text.c_str(), {color.r, color.g, color.b});
if(surface == nullptr) {
throw MissingTextureException("font", SDL_GetError());
}
SDL_Texture *texture = SDL_CreateTextureFromSurface(this->renderer.get(), surface);
SDL_FreeSurface(surface);
if(texture == nullptr) {
throw MissingTextureException("font", SDL_GetError());
}
return std::shared_ptr<SDL_Texture>(texture, SDL_DestroyTexture);
}

View File

@@ -8,20 +8,44 @@
#include <string>
#include <unordered_map>
#include "../../engine.hpp"
#include "../../resources/resourcemanager.hpp"
#include <SDL_image.h>
#include <algorithm>
#include <SDL_ttf.h>
struct TextureManagerFetchArgs {
std::string path;
std::optional<Color> color_key;
};
class SdlTextureManager : public ResourceManager<std::shared_ptr<SDL_Texture>, std::string, TextureManagerFetchArgs> {
protected:
std::shared_ptr<SDL_Texture> load_resource(TextureManagerFetchArgs args) override;
std::string get_key(TextureManagerFetchArgs args) override;
class SdlTextureManager {
public:
SDL_Texture *load_texture(const std::string &path, SDL_Renderer *renderer);
SdlTextureManager();
explicit SdlTextureManager(std::shared_ptr<SDL_Renderer> renderer) : renderer(renderer) {}
std::shared_ptr<SDL_Texture> load_text_as_texture(const std::string& text, const std::shared_ptr<TTF_Font>& font, Color color);
virtual ~SdlTextureManager();
private:
std::unordered_map<std::string, SDL_Texture*> texture_map;
std::shared_ptr<SDL_Renderer> renderer = nullptr;
static SDL_Surface* load_surface(const std::string& path);
};
class MissingTextureException: public std::exception {
private:
std::string msg;
public:
[[nodiscard]] const char *what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW override {
return msg.c_str();
}
MissingTextureException(const std::string& path, const std::string& error) {
msg = fmt::format("Failed ot load texture at path [{}] because: {}", path, error);
}
};
#endif //RLA_IIPP_SDLTEXTUREMANAGER_HPP

View File

@@ -0,0 +1,41 @@
//
// Created by m on 12/4/21.
//
#ifndef RLA_IIPP_RESOURCEMANAGER_HPP
#define RLA_IIPP_RESOURCEMANAGER_HPP
#include <unordered_map>
#include "../engine.hpp"
template<typename T, typename K, typename A>
class ResourceManager {
public:
virtual T fetch_resource(A args) {
K key = get_key(args);
if(!this->resource_map.contains(key)) {
T resource = this->load_resource(args);
this->resource_map[key] = resource;
}
return this->resource_map[key];
}
virtual void clear_resource(A args) {
K key = get_key(args);
if(this->resource_map.contains(key)) {
this->resource_map.erase(key);
}
}
virtual void clear_all_resources() {
this->resource_map.clear();
}
protected:
std::unordered_map<K, T> resource_map;
virtual K get_key(A args)=0;
virtual T load_resource(A args)=0;
std::string get_resource_path(std::string path) {
return fmt::format("{}/{}", RESOURCE_DIR, path);
}
};
#endif //RLA_IIPP_RESOURCEMANAGER_HPP

View File

@@ -0,0 +1,27 @@
//
// Created by m on 12/20/21.
//
#ifndef RLA_IIPP_RLENGINEEXCEPTION_HPP
#define RLA_IIPP_RLENGINEEXCEPTION_HPP
#include <exception>
#include <string>
#include <utility>
class RLEngineException : public std::exception {
public:
[[nodiscard]] const char *what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW override {
return message.c_str();
}
explicit RLEngineException(std::string message) : message(std::move(message)) {}
private:
std::string message;
};
#endif //RLA_IIPP_RLENGINEEXCEPTION_HPP

View File

@@ -0,0 +1,16 @@
//
// Created by m on 12/12/21.
//
#include "luacontextmanager.hpp"
std::string LuaContextManager::get_key(std::string args) {
return args;
}
// TODO: Switch the arg to a struct and use that to init libraries
std::shared_ptr<sol::state> LuaContextManager::load_resource(std::string args) {
auto lua = std::make_shared<sol::state>();
lua->open_libraries(sol::lib::base, sol::lib::package, sol::lib::math, sol::lib::table);
return lua;
}

View File

@@ -0,0 +1,28 @@
//
// Created by m on 12/12/21.
//
#ifndef RLA_IIPP_LUACONTEXTMANAGER_HPP
#define RLA_IIPP_LUACONTEXTMANAGER_HPP
#include <sol/sol.hpp>
#include "../resources/resourcemanager.hpp"
class LuaContextManager : public ResourceManager<std::shared_ptr<sol::state>, std::string, std::string> {
public:
std::shared_ptr<sol::state> get_default_context() {
return fetch_resource(DEFAULT_CONTEXT_KEY);
}
void clear_default_context() {
clear_resource(DEFAULT_CONTEXT_KEY);
}
protected:
std::string get_key(std::string args) override;
std::shared_ptr<sol::state> load_resource(std::string args) override;
private:
const std::string DEFAULT_CONTEXT_KEY = "default";
};
#endif //RLA_IIPP_LUACONTEXTMANAGER_HPP

View File

@@ -0,0 +1,71 @@
//
// Created by m on 12/11/21.
//
#include "camera.hpp"
Rectangle Camera::get_bounds() {
return cached_bounds;
}
void Camera::move_camera(Point new_center) {
bool recalculate_bounds = false;
if(new_center != this->center) {
recalculate_bounds = true;
}
this->center = new_center;
if(recalculate_bounds) {
this->cached_bounds = calculate_bounds();
}
}
void Camera::set_bounds(int max_x, int max_y) {
this->max_x = max_x;
this->max_y = max_y;
this->cached_bounds = calculate_bounds();
}
Rectangle Camera::calculate_bounds() const {
auto tiles_rendered_x = this->get_tiles_rendered_x();
auto tiles_rendered_y = this->get_tiles_rendered_y();
int minx = std::clamp(center.x-(tiles_rendered_x/2), 0, std::max(0,max_x - tiles_rendered_x));
int miny = std::clamp(center.y-(tiles_rendered_y/2), 0, std::max(0,max_y - tiles_rendered_y));
int width = std::min(tiles_rendered_x, max_x-minx);
int height = std::min(tiles_rendered_y, max_y-miny);
return Rectangle{minx, miny, width, height};
}
Point Camera::camera_coords_to_screen_coords(Point camera_coord) {
auto bounds = get_bounds();
return Point{camera_coord.x-bounds.x, camera_coord.y-bounds.y};
}
ranges::any_view<Point> Camera::get_range() {
auto bounds = get_bounds();
int height = bounds.height;
int width = bounds.width;
int miny = bounds.y;
int minx = bounds.x;
return ranges::views::iota(miny, miny+height) | ranges::views::transform([width, minx](int y) {
return ranges::views::iota(minx, minx+width) | ranges::views::transform([y](int x) {
return Point{x,y};
});
}) | ranges::views::join;
}
float Camera::get_scale() const {
return scale;
}
void Camera::set_scale(float scale) {
this->scale = scale;
this->cached_bounds = calculate_bounds();
}
int Camera::get_tiles_rendered_x() const {
return (int)std::ceil(tiles_rendered_x / this->scale);
}
int Camera::get_tiles_rendered_y() const {
return (int)std::ceil(tiles_rendered_y / this->scale);
}

View File

@@ -0,0 +1,53 @@
//
// Created by m on 12/11/21.
//
#ifndef RLA_IIPP_CAMERA_HPP
#define RLA_IIPP_CAMERA_HPP
#include "point.hpp"
#include "rectangle.hpp"
#include <range/v3/view.hpp>
#include <algorithm>
class Camera {
private:
// center of the camera
Point center=Point();
int tiles_rendered_x=0;
int tiles_rendered_y=0;
int max_x=0;
int max_y=0;
Rectangle cached_bounds=Rectangle();
Rectangle calculate_bounds() const;
float scale = 1;
[[nodiscard]] int get_tiles_rendered_x() const;
[[nodiscard]] int get_tiles_rendered_y() const;
public:
[[nodiscard]] float get_scale() const;
void set_scale(float scale);
public:
Rectangle get_bounds();
void move_camera(Point new_center);
void set_bounds(int max_x, int max_y);
Point camera_coords_to_screen_coords(Point camera_coord);
ranges::any_view<Point> get_range();
Camera()=default;
Camera(const Point &center, int tilesRenderedX, int tilesRenderedY, int maxX, int maxY) : center(center),
tiles_rendered_x(
tilesRenderedX),
tiles_rendered_y(
tilesRenderedY),
max_x(maxX),
max_y(maxY)
{
cached_bounds = calculate_bounds();
}
};
#endif //RLA_IIPP_CAMERA_HPP

View File

@@ -0,0 +1,44 @@
//
// Created by m on 12/11/21.
//
#ifndef RLA_IIPP_GRID2D_HPP
#define RLA_IIPP_GRID2D_HPP
#include <vector>
#include <range/v3/view.hpp>
#include "point.hpp"
template<typename T>
class Grid2D {
private:
std::vector<std::vector<T>> grid{};
public:
Grid2D(int width, int height) {
grid = std::vector<std::vector<T>>(height, std::vector<T>(width));
}
int get_width() {
return grid[0].size();
}
int get_height() {
return grid.size();
}
void insert(int x, int y, T arg) {
grid[y][x] = arg;
}
T get(int x, int y) {
return grid[y][x];
}
ranges::any_view<Point> get_range() {
int height = get_height();
int width = get_width();
return ranges::views::iota(0, height) | ranges::views::transform([height, width](int y) {
return ranges::views::iota(0, width) | ranges::views::transform([y](int x) {
return Point{x,y};
});
}) | ranges::views::join;
}
};
#endif //RLA_IIPP_GRID2D_HPP

View File

@@ -0,0 +1,24 @@
//
// Created by m on 12/11/21.
//
#ifndef RLA_IIPP_POINT_HPP
#define RLA_IIPP_POINT_HPP
struct Point {
int x;
int y;
bool operator==(const Point &rhs) const {
return x == rhs.x &&
y == rhs.y;
}
bool operator!=(const Point &rhs) const {
return !(rhs == *this);
}
};
#endif //RLA_IIPP_POINT_HPP

View File

@@ -0,0 +1,17 @@
//
// Created by m on 12/11/21.
//
#ifndef RLA_IIPP_RECTANGLE_HPP
#define RLA_IIPP_RECTANGLE_HPP
struct Rectangle {
int x;
int y;
int width;
int height;
};
#endif //RLA_IIPP_RECTANGLE_HPP

View File

@@ -0,0 +1,62 @@
//
// Created by m on 12/13/21.
//
#include "algorithmmanager.hpp"
#include "../engine/modules/logger.hpp"
#include <utility>
#include <fmt/format.h>
void AlgorithmManager::register_algorithm(std::string name, sol::function initialize, sol::function update,
unsigned int updates_per_second) {
unsigned int frames_per_update = target_fps / updates_per_second;
DungeonAlgorithm algorithm = {
frames_per_update,
std::move(update),
std::move(initialize),
std::move(name)
};
algorithms.push_back(algorithm);
}
ranges::any_view<DungeonAlgorithm*, ranges::category::random_access | ranges::category::sized> AlgorithmManager::get_algorithms() {
auto view = algorithms | ranges::view::transform([](auto& algo) {
return &algo;
});
return view;
}
void AlgorithmManager::load_algorithm(DungeonAlgorithm *algorithm, int w, int h) {
algorithm_done = false;
ticks = 0;
loaded_algorithm = algorithm;
auto init_result = loaded_algorithm->initialize(w, h);
if(!init_result.valid()) {
sol::error err = init_result;
Logger::log(LogLevel::ERROR, fmt::format("error while initializing lua: {}", err.what()));
}
}
void AlgorithmManager::tick_algorithm() {
if(this->loaded_algorithm == nullptr || algorithm_done) {
return;
}
if(ticks >= this->loaded_algorithm->frames_per_update) {
ticks = 0;
auto update_result = this->loaded_algorithm->update();
if(update_result.valid()) {
algorithm_done = update_result;
if(algorithm_done) {
Logger::log(LogLevel::DEBUG, "Finished running algorithm");
}
}
else {
algorithm_done = true;
sol::error err = update_result;
Logger::log(LogLevel::ERROR, fmt::format("An error occurred while running update: {}", err.what()));
}
}
ticks++;
}

View File

@@ -0,0 +1,36 @@
//
// Created by m on 12/13/21.
//
#ifndef RLA_IIPP_ALGORITHMMANAGER_HPP
#define RLA_IIPP_ALGORITHMMANAGER_HPP
#include <sol/sol.hpp>
#include <range/v3/view.hpp>
struct DungeonAlgorithm {
unsigned int frames_per_update=1;
sol::protected_function update;
sol::protected_function initialize;
std::string name;
};
class AlgorithmManager {
private:
std::vector<DungeonAlgorithm> algorithms;
unsigned int target_fps=1;
unsigned int ticks=0;
DungeonAlgorithm* loaded_algorithm = nullptr;
bool algorithm_done = false;
public:
void register_algorithm(std::string name, sol::function initialize, sol::function update, unsigned int updates_per_second);
ranges::any_view<DungeonAlgorithm*, ranges::category::random_access | ranges::category::sized> get_algorithms();
void load_algorithm(DungeonAlgorithm* algorithm, int w, int h);
void tick_algorithm();
DungeonAlgorithm* get_currently_running_algorithm() {
return algorithm_done ? nullptr : loaded_algorithm;
}
explicit AlgorithmManager(unsigned int targetFps) : target_fps(targetFps) {}
AlgorithmManager() = default;
};
#endif //RLA_IIPP_ALGORITHMMANAGER_HPP

50
src/game/tilemap.cpp Normal file
View File

@@ -0,0 +1,50 @@
//
// Created by m on 12/14/21.
//
#include "tilemap.hpp"
#include "../engine/utility/point.hpp"
#include "../engine/modules/logger.hpp"
#include <fmt/format.h>
void TileMap::draw_floor(int x, int y) {
Logger::log(LogLevel::DEBUG, fmt::format("Drawing floor at x: {} y: {}", x, y));
grid.insert(x, y, floor_tile);
}
void TileMap::draw_wall(int x, int y) {
Logger::log(LogLevel::DEBUG, fmt::format("Drawing wall at x: {} y: {}", x, y));
grid.insert(x, y, wall_tile);
}
char TileMap::get_tile(int x, int y) {
return grid.get(x, y);
}
void TileMap::fill(bool wall) {
Logger::log(LogLevel::DEBUG, fmt::format("Running fill with wall: {}", wall));
for(Point p : grid.get_range()) {
if(wall) {
draw_wall(p.x, p.y);
}
else {
draw_floor(p.x, p.y);
}
}
}
bool TileMap::is_wall(int x, int y) {
return get_tile(x, y) == wall_tile;
}
int TileMap::get_width() {
return grid.get_width();
}
int TileMap::get_height() {
return grid.get_height();
}
TileMap TileMap::clone() {
return {this->get_width(), this->get_height(), this->wall_tile, this->floor_tile};
}

35
src/game/tilemap.hpp Normal file
View File

@@ -0,0 +1,35 @@
//
// Created by m on 12/14/21.
//
#ifndef RLA_IIPP_TILEMAP_HPP
#define RLA_IIPP_TILEMAP_HPP
#include "../engine/utility/grid2d.hpp"
class TileMap {
private:
Grid2D<char> grid = Grid2D<char>(0, 0);
char wall_tile;
char floor_tile;
public:
void draw_floor(int x, int y);
void draw_wall(int x, int y);
void fill(bool wall);
char get_tile(int x, int y);
bool is_wall(int x, int y);
int get_width();
int get_height();
TileMap clone();
TileMap(int width, int height, char wall_tile, char floor_tile) {
this->grid = Grid2D<char>(width, height);
this->wall_tile = wall_tile;
this->floor_tile = floor_tile;
}
};
#endif //RLA_IIPP_TILEMAP_HPP

View File

@@ -2,32 +2,148 @@
// Created by m on 12/3/21.
//
#include <filesystem>
#include "visualizer.hpp"
#define TITLE "test"
#define WIN_WIDTH 800
#define WIN_HEIGHT 600
#define TARGET_FPS 60
bool Visualizer::update() {
this->x += 1;
if(this->x > WIN_WIDTH) {
this->x = 0;
#include "tilemap.hpp"
bool Visualizer::update(InputResult input) {
if(input.keycode == KEY_ESCAPE) {
return true;
}
this->algorithm_manager.tick_algorithm();
switch(input.keycode) {
case KEY_RIGHT: x += 1; break;
case KEY_LEFT: x -= 1; break;
case KEY_UP: y -= 1; break;
case KEY_DOWN: y += 1; break;
case KEY_KP_PLUS:
this->camera.set_scale(this->camera.get_scale() * 2); break;
case KEY_KP_MINUS:
this->camera.set_scale(this->camera.get_scale() / 2); break;
default: break;
}
if(input.keycode >= InputProcessorKeycode::KEY_1 && input.keycode <= InputProcessorKeycode::KEY_9) {
if(this->keycode_to_algorithm.contains(input.keycode)) {
auto algorithm = this->keycode_to_algorithm[input.keycode];
this->algorithm_manager.load_algorithm(algorithm, this->map_size_w, this->map_size_h);
}
}
this->x = std::clamp(this->x, 0, (int)this->tile_map.get_width()-1);
this->y = std::clamp(this->y, 0, (int)this->tile_map.get_height()-1);
this->camera.move_camera(Point{x,y});
return false;
}
RendererParams Visualizer::get_renderer_params() {
return {TITLE, WIN_WIDTH, WIN_HEIGHT};
}
unsigned int Visualizer::get_framerate() {
return TARGET_FPS;
}
void Visualizer::render(Renderer *renderer) {
Color color = Color(255, 255, 255, 255);
for(int y=0;y<WIN_HEIGHT;y++) {
renderer->draw_point(this->x, y, color);
SpriteSheet tiles = SpriteSheet{"sprites/map1.bmp", tile_width, tile_height};
SpriteSheet characters = SpriteSheet{"sprites/character.bmp", tile_width, tile_height, COLOR_BLACK};
float scale = this->camera.get_scale();
int scaled_tile_width = (int)std::ceil(tile_width * scale);
int scaled_tile_height = (int)std::ceil(tile_height * scale);
auto grass = Sprite{&tiles, 0};
auto wall = Sprite{&tiles, 497};
auto character = Sprite{&characters, this->sprite_index};
for(Point p : camera.get_range()) {
auto wp = camera.camera_coords_to_screen_coords(p);
int wx = wp.x, wy = wp.y;
if(this->tile_map.get_tile(p.x, p.y) == floor_char) {
renderer->draw_sprite(grass, wx*scaled_tile_width, wy*scaled_tile_height, scale);
}
else {
renderer->draw_sprite(wall, wx*scaled_tile_width, wy*scaled_tile_height, scale);
}
if(p.x == x && p.y == y) {
renderer->draw_sprite(character, wx*scaled_tile_width, wy*scaled_tile_height, scale);
}
}
// Draw keycode to algo mappings
auto default_font_details = renderer->get_default_text_render_details();
auto running_algorithm = this->algorithm_manager.get_currently_running_algorithm();
for(auto pairing : this->keycode_to_algorithm) {
auto index = pairing.first-InputProcessorKeycode::KEY_1;
auto draw_params = default_font_details;
if(pairing.second == running_algorithm) {
draw_params.color = COLOR_RED;
}
renderer->draw_text(draw_params, fmt::format("{}: {}", index+1, pairing.second->name), 0, this->window_height-((index+1)*default_font_details.size));
}
}
void Visualizer::initialize(GameInitArgs args) {
this->window_width = args.window_width;
this->window_height = args.window_height;
Engine::load_config(CONFIG_FILE, [this](toml::table table) {
this->tile_width = table["rendering"]["tile_size_w"].value_or(DEFAULT_TILE_WIDTH);
this->tile_height = table["rendering"]["tile_size_h"].value_or(DEFAULT_TILE_HEIGHT);
this->map_size_w = table["map"]["map_size_w"].value_or(DEFAULT_MAP_SIZE_W);
this->map_size_h = table["map"]["map_size_h"].value_or(DEFAULT_MAP_SIZE_H);
this->floor_char = table["map"]["floor_char"].value_or(DEFAULT_FLOOR_CHAR)[0];
this->wall_char = table["map"]["wall_char"].value_or(DEFAULT_WALL_CHAR)[0];
});
int tilesx = (window_width / tile_width)+1;
int tilesy = (window_height / tile_height)+1;
initialize_map(map_size_w, map_size_h);
this->camera = Camera(Point{x,y}, tilesx, tilesy, tile_map.get_width(), tile_map.get_height());
this->algorithm_manager = AlgorithmManager(args.target_fps);
this->initialize_context();
this->load_algorithms();
Logger::log(LogLevel::DEBUG, "Game initialization finished");
}
void Visualizer::initialize_map(int width, int height) {
this->tile_map = TileMap(width, height, wall_char, floor_char);
for(int ty=0;ty<this->tile_map.get_height();ty++) {
for (int tx = 0; tx < tile_map.get_width(); tx++) {
this->tile_map.draw_floor(tx, ty);
}
}
}
void Visualizer::initialize_context() {
auto lua = lua_context_manager.get_default_context();
auto tilemap_lua = lua->new_usertype<TileMap>("TileMap", sol::no_constructor);
tilemap_lua["draw_floor"] = &TileMap::draw_floor;
tilemap_lua["draw_wall"] = &TileMap::draw_wall;
tilemap_lua["fill"] = &TileMap::fill;
tilemap_lua["is_wall"] = &TileMap::is_wall;
tilemap_lua["clone"] = &TileMap::clone;
tilemap_lua["get_width"] = &TileMap::get_width;
tilemap_lua["get_height"] = &TileMap::get_height;
auto algo_manager_lua = lua->new_usertype<AlgorithmManager>("AlgorithmManager", sol::no_constructor);
algo_manager_lua["register_algorithm"] = &AlgorithmManager::register_algorithm;
auto game_state_lua = lua->new_usertype<Visualizer>("Visualizer", sol::no_constructor);
game_state_lua.set("algorithm_manager", sol::readonly(&Visualizer::algorithm_manager));
game_state_lua.set("map", &Visualizer::tile_map);
lua->set("visualizer", this);
}
void Visualizer::load_algorithms() {
auto lua = lua_context_manager.get_default_context();
const std::string algorithms_directory = "scripts/algorithms";
for(const auto& file : std::filesystem::directory_iterator(algorithms_directory)) {
lua->script_file(file.path());
}
Logger::log(LogLevel::DEBUG, "finished loading lua files");
auto algorithms = this->algorithm_manager.get_algorithms();
auto algorithm_count = algorithms.size();
Logger::log(LogLevel::DEBUG, fmt::format("algorithms: {}", algorithm_count));
for(int code = InputProcessorKeycode::KEY_1;code < InputProcessorKeycode::KEY_9;code++) {
auto index = code-InputProcessorKeycode::KEY_1;
if(algorithms.size() <= index) {
break;
}
auto algo = algorithms[index];
this->keycode_to_algorithm[(InputProcessorKeycode)code] = algo;
}
}

View File

@@ -2,25 +2,60 @@
// Created by m on 12/3/21.
//
#include "../engine/game/game.hpp"
#include "../engine/rendering/renderer.hpp"
#include "../engine/utility/camera.hpp"
#include "../engine/utility/grid2d.hpp"
#include "../engine/scripting/luacontextmanager.hpp"
#include "algorithmmanager.hpp"
#include "tilemap.hpp"
#include <vector>
#include <range/v3/range.hpp>
#include <range/v3/view.hpp>
#ifndef RLA_IIPP_VISUALIZER_HPP
#define RLA_IIPP_VISUALIZER_HPP
#define DEFAULT_MAP_SIZE_W 20
#define DEFAULT_MAP_SIZE_H 20
#define DEFAULT_TILE_WIDTH 48
#define DEFAULT_TILE_HEIGHT 48
#define DEFAULT_WALL_CHAR "#"
#define DEFAULT_FLOOR_CHAR "."
#define CONFIG_FILE "visualizer.toml"
class Visualizer : public Game {
public:
bool update() override;
bool update(InputResult input) override;
void render(Renderer* renderer) override;
RendererParams get_renderer_params() override;
unsigned int get_framerate() override;
~Visualizer();
void initialize(GameInitArgs args) override;
private:
int window_width = 0;
int window_height = 0;
TileMap tile_map = TileMap(0, 0, DEFAULT_WALL_CHAR[0], DEFAULT_FLOOR_CHAR[0]);
Camera camera = Camera();
LuaContextManager lua_context_manager;
AlgorithmManager algorithm_manager;
std::unordered_map<InputProcessorKeycode, DungeonAlgorithm*> keycode_to_algorithm;
int x = 0;
int y=0;
int sprite_index = 1;
char floor_char;
char wall_char;
int map_size_w;
int map_size_h;
int tile_width;
int tile_height;
void initialize_map(int width, int height);
void initialize_context();
void load_algorithms();
};

View File

@@ -4,12 +4,12 @@
#include "engine/rendering/sdl/sdlrenderer.hpp"
#include "engine/engine.hpp"
#include "game/visualizer.hpp"
#include "engine/input/sdlinputprocessor.hpp"
int main() {
std::unique_ptr<Renderer> renderer = std::make_unique<SdlRenderer>();
std::unique_ptr<Game> game = std::make_unique<Visualizer>();
auto* engine = new Engine(std::move(game), std::move(renderer));
std::unique_ptr<InputProcessor> input_processor = std::make_unique<SdlInputProcessor>();
auto engine = std::make_unique<Engine>(std::move(game), std::move(input_processor));
engine->start_loop();
return 0;

37
vcpkg.json Normal file
View File

@@ -0,0 +1,37 @@
{
"name" : "rla-iipp",
"version-string" : "1.0.0",
"builtin-baseline" : "21bbb14c4113b89cd06402e852e075341722304f",
"dependencies" : [ {
"name" : "sdl2",
"version>=" : "2.26.5",
"$comment" : " find_package(SDL2 CONFIG REQUIRED)\n\n target_link_libraries(main\n\n PRIVATE\n\n $<TARGET_NAME_IF_EXISTS:SDL2::SDL2main>\n\n $<IF:$<TARGET_EXISTS:SDL2::SDL2>,SDL2::SDL2,SDL2::SDL2-static>\n\n )\n"
}, {
"name" : "sdl2-ttf",
"version>=" : "2.20.2",
"$comment" : " find_package(SDL2_ttf CONFIG REQUIRED)\n\n target_link_libraries(main PRIVATE $<IF:$<TARGET_EXISTS:SDL2_ttf::SDL2_ttf>,SDL2_ttf::SDL2_ttf,SDL2_ttf::SDL2_ttf-static>)\n"
}, {
"name" : "sdl2-image",
"version>=" : "2.6.3",
"$comment" : " find_package(SDL2_image CONFIG REQUIRED)\n\n target_link_libraries(main PRIVATE $<IF:$<TARGET_EXISTS:SDL2_image::SDL2_image>,SDL2_image::SDL2_image,SDL2_image::SDL2_image-static>)\n"
}, {
"name" : "fmt",
"version>=" : "10.0.0",
"$comment" : " find_package(fmt CONFIG REQUIRED)\n\n target_link_libraries(main PRIVATE fmt::fmt)\n"
}, {
"name" : "tomlplusplus",
"version>=" : "3.1.0",
"$comment" : " # this is heuristically generated, and may not be correct\n\n find_package(tomlplusplus CONFIG REQUIRED)\n\n target_link_libraries(main PRIVATE tomlplusplus::tomlplusplus)\n"
}, {
"name" : "sol2",
"version>=" : "3.3.0",
"$comment" : " # this is heuristically generated, and may not be correct\n\n find_package(sol2 CONFIG REQUIRED)\n\n target_link_libraries(main PRIVATE sol2)\n"
}, {
"name" : "range-v3",
"version>=" : "0.12.0#1",
"$comment" : " # this is heuristically generated, and may not be correct\n\n find_package(range-v3 CONFIG REQUIRED)\n\n target_link_libraries(main PRIVATE range-v3::meta range-v3::concepts range-v3::range-v3)\n"
}, {
"name" : "lua",
"version>=" : "5.4.6"
} ]
}