#include "core/rendering/screen.hpp" #include #include #include #include "utils/defaults.hpp" #include "utils/defines.hpp" namespace { auto toSdlPresentation(Defaults::ScalingMode mode) -> SDL_RendererLogicalPresentation { switch (mode) { case Defaults::ScalingMode::DISABLED: return SDL_LOGICAL_PRESENTATION_DISABLED; case Defaults::ScalingMode::STRETCH: return SDL_LOGICAL_PRESENTATION_STRETCH; case Defaults::ScalingMode::LETTERBOX: return SDL_LOGICAL_PRESENTATION_LETTERBOX; case Defaults::ScalingMode::OVERSCAN: return SDL_LOGICAL_PRESENTATION_OVERSCAN; case Defaults::ScalingMode::INTEGER: return SDL_LOGICAL_PRESENTATION_INTEGER_SCALE; } return SDL_LOGICAL_PRESENTATION_LETTERBOX; } auto toSdlScaleMode(Defaults::TextureFilter filter) -> SDL_ScaleMode { return filter == Defaults::TextureFilter::LINEAR ? SDL_SCALEMODE_LINEAR : SDL_SCALEMODE_NEAREST; } } // namespace Screen* Screen::instance = nullptr; void Screen::init() { if (instance == nullptr) { instance = new Screen(); } } void Screen::destroy() { delete instance; instance = nullptr; } auto Screen::get() -> Screen* { return instance; } Screen::Screen() { if (!SDL_InitSubSystem(SDL_INIT_VIDEO)) { std::fprintf(stderr, "SDL_InitSubSystem(VIDEO) failed: %s\n", SDL_GetError()); std::exit(EXIT_FAILURE); } const int WIN_W = GameCanvas::WIDTH * Defaults::Window::ZOOM; const int WIN_H = GameCanvas::HEIGHT * Defaults::Window::ZOOM; Uint32 win_flags = SDL_WINDOW_RESIZABLE; if (Defaults::Window::FULLSCREEN) { win_flags |= SDL_WINDOW_FULLSCREEN; } window_ = SDL_CreateWindow(Texts::WINDOW_TITLE, WIN_W, WIN_H, win_flags); if (window_ == nullptr) { std::fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); std::exit(EXIT_FAILURE); } renderer_ = SDL_CreateRenderer(window_, nullptr); if (renderer_ == nullptr) { std::fprintf(stderr, "SDL_CreateRenderer failed: %s\n", SDL_GetError()); std::exit(EXIT_FAILURE); } SDL_SetRenderVSync(renderer_, Defaults::Video::VSYNC ? 1 : 0); SDL_SetRenderLogicalPresentation(renderer_, GameCanvas::WIDTH, GameCanvas::HEIGHT, toSdlPresentation(Defaults::Video::SCALING_MODE)); // Destination ARGB texture: paletted surfaces will be blitted onto this // (each surface contributes its own palette, so the final image is full ARGB). game_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, GameCanvas::WIDTH, GameCanvas::HEIGHT); if (game_texture_ == nullptr) { std::fprintf(stderr, "SDL_CreateTexture failed: %s\n", SDL_GetError()); std::exit(EXIT_FAILURE); } SDL_SetTextureScaleMode(game_texture_, toSdlScaleMode(Defaults::Video::TEXTURE_FILTER)); } Screen::~Screen() { if (game_texture_ != nullptr) { SDL_DestroyTexture(game_texture_); } if (renderer_ != nullptr) { SDL_DestroyRenderer(renderer_); } if (window_ != nullptr) { SDL_DestroyWindow(window_); } SDL_QuitSubSystem(SDL_INIT_VIDEO); } void Screen::clear(std::uint8_t r, std::uint8_t g, std::uint8_t b) { SDL_SetRenderTarget(renderer_, game_texture_); SDL_SetRenderDrawColor(renderer_, r, g, b, 0xFF); SDL_RenderClear(renderer_); SDL_SetRenderTarget(renderer_, nullptr); } void Screen::present() { SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF); SDL_RenderClear(renderer_); SDL_RenderTexture(renderer_, game_texture_, nullptr, nullptr); SDL_RenderPresent(renderer_); }