ona/source/app/sdl.cpp

168 lines
4.4 KiB
C++
Raw Normal View History

2023-02-18 04:34:40 +01:00
module;
#include <SDL2/SDL.h>
export module app.sdl;
import app;
import core;
import core.image;
import core.sequence;
2023-02-18 20:40:12 +01:00
import core.lalgebra;
2023-02-18 04:34:40 +01:00
struct bundled_file_store : public app::file_store {
void read_file(app::path const & file_path, core::callable<void(core::readable const &)> const & then) override {
2023-02-18 20:40:12 +01:00
constexpr core::slice<char const> path_prefix = "./";
constexpr core::usize path_max = 512;
2023-02-18 04:34:40 +01:00
2023-02-18 20:40:12 +01:00
if ((file_path.size() + path_prefix.length) > path_max) core::unreachable();
core::stack<char, path_max> path_buffer{&core::null_allocator()};
if (path_buffer.append("./") != core::append_result::ok) core::unreachable();
2023-02-18 04:34:40 +01:00
// File path is guaranteed to be null-terminated.
2023-02-18 20:40:12 +01:00
if (path_buffer.append(file_path.as_slice()) != core::append_result::ok)
core::unreachable();
2023-02-18 04:34:40 +01:00
2023-02-18 20:40:12 +01:00
SDL_RWops * rw_ops = ::SDL_RWFromFile(path_buffer.begin(), "r");
2023-02-18 04:34:40 +01:00
if (rw_ops == nullptr) return;
then([rw_ops](core::slice<uint8_t> const & buffer) -> size_t {
return ::SDL_RWread(rw_ops, buffer.pointer, sizeof(uint8_t), buffer.length);
});
::SDL_RWclose(rw_ops);
}
};
struct sdl_allocator : public core::allocator {
core::u8 * reallocate(core::u8 * maybe_allocation, core::usize requested_size) override {
return reinterpret_cast<core::u8 *>(::SDL_malloc(requested_size));
}
void deallocate(void * allocation) override {
::SDL_free(allocation);
}
};
struct sdl_system : public app::system {
private:
::SDL_Event sdl_event;
sdl_allocator allocator;
bundled_file_store bundled_store;
public:
sdl_system() :
sdl_event{0},
allocator{} {}
bool poll() override {
while (::SDL_PollEvent(&this->sdl_event) != 0) {
switch (this->sdl_event.type) {
case SDL_QUIT: return false;
}
}
return true;
}
app::file_store & bundle() override {
return this->bundled_store;
}
void log(app::log_level level, core::slice<char const> const & message) override {
core::i32 const length = static_cast<core::i32>(
core::min(message.length, static_cast<size_t>(core::i32_max)));
::SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION,
SDL_LOG_PRIORITY_INFO, "%.*s", length, message.pointer);
}
core::allocator & thread_safe_allocator() override {
return this->allocator;
}
};
struct sdl_graphics : public app::graphics {
static constexpr core::usize title_maximum = 128;
core::u32 title_length;
char title_buffer[title_maximum];
::SDL_Window * sdl_window = nullptr;
::SDL_Renderer * sdl_renderer = nullptr;
sdl_graphics(core::slice<char const> const & title) {
this->retitle(title);
}
void render(canvas & source_canvas) override {
if (this->sdl_renderer != nullptr) {
SDL_SetRenderDrawColor(this->sdl_renderer, source_canvas.background_color.to_r8(),
source_canvas.background_color.to_g8(), source_canvas.background_color.to_b8(),
source_canvas.background_color.to_a8());
SDL_RenderClear(this->sdl_renderer);
}
}
void retitle(core::slice<char const> const & title) override {
this->title_length = core::min(title.length, title_maximum - 1);
for (core::usize i = 0; i < this->title_length; i += 1) title_buffer[i] = title[i];
for (core::usize i = this->title_length; i < title_maximum; i += 1) title_buffer[i] = 0;
if (this->sdl_window != nullptr) ::SDL_SetWindowTitle(this->sdl_window, title_buffer);
}
app::graphics::show_error show(core::u16 physical_width, core::u16 physical_height) override {
if (this->sdl_window == nullptr) {
constexpr int sdl_windowpos = SDL_WINDOWPOS_UNDEFINED;
constexpr core::u32 sdl_windowflags = 0;
this->sdl_window = ::SDL_CreateWindow(title_buffer, sdl_windowpos, sdl_windowpos,
static_cast<int>(physical_width), static_cast<int>(physical_height),
sdl_windowflags);
if (this->sdl_window == nullptr) return show_error::out_of_memory;
} else {
::SDL_ShowWindow(this->sdl_window);
}
if (this->sdl_renderer == nullptr) {
constexpr core::u32 sdl_rendererflags = 0;
this->sdl_renderer = ::SDL_CreateRenderer(this->sdl_window, -1, sdl_rendererflags);
if (this->sdl_renderer == nullptr) return show_error::out_of_memory;
}
return show_error::none;
}
void present() override {
if (this->sdl_renderer != nullptr) {
::SDL_RenderPresent(this->sdl_renderer);
}
}
};
export namespace app {
int display(core::slice<char const> const & title,
core::callable<int(app::system &, app::graphics &)> const & run) {
sdl_system system;
sdl_graphics graphics(title);
return run(system, graphics);
}
}