primer commit

This commit is contained in:
2025-04-08 08:23:18 +02:00
parent 94c89b7ced
commit b6682fe7ff
30 changed files with 18573 additions and 1 deletions

324
source/screen.cpp Normal file
View File

@@ -0,0 +1,324 @@
#include "screen.h"
#include <SDL3/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#include <SDL3/SDL_error.h> // for SDL_GetError
#include <SDL3/SDL_hints.h> // for SDL_SetHint, SDL_HINT_RENDER_DRIVER
#include <SDL3/SDL_init.h> // for SDL_Init, SDL_INIT_VIDEO
#include <SDL3/SDL_log.h> // for SDL_LogCategory, SDL_LogInfo, SDL_Lo...
#include <SDL3/SDL_pixels.h> // for SDL_PixelFormat
#include <algorithm> // for min, max
#include <string> // for char_traits, operator+, to_string
#include "mouse.h" // for updateCursorVisibility
#include "options.h" // for Options, options, OptionsWindow, Opt...
#include "surface.h" // for Surface, readPalFile
// [SINGLETON]
Screen *Screen::screen_ = nullptr;
// [SINGLETON] Crearemos el objeto con esta función estática
void Screen::init()
{
Screen::screen_ = new Screen();
}
// [SINGLETON] Destruiremos el objeto con esta función estática
void Screen::destroy()
{
delete Screen::screen_;
}
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
Screen *Screen::get()
{
return Screen::screen_;
}
// Constructor
Screen::Screen()
{
// Arranca SDL VIDEO, crea la ventana y el renderizador
initSDL();
// Obtiene información sobre la pantalla
getDisplayInfo();
// Ajusta los tamaños
adjustWindowSize();
// Crea la textura donde se dibujan los graficos del juego
game_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, options.logo.width, options.logo.height);
if (!game_texture_)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: game_texture_ could not be created! SDL Error: %s", SDL_GetError());
}
SDL_SetTextureScaleMode(game_texture_, options.video.scale_mode);
// Crea la surface donde se dibujan los graficos del juego
game_surface_ = std::make_shared<Surface>(options.logo.width, options.logo.height);
game_surface_->setPalette(readPalFile("jailgames.pal"));
game_surface_->clear(0);
// Establece la surface que actuará como renderer para recibir las llamadas a render()
renderer_surface_ = std::make_shared<std::shared_ptr<Surface>>(game_surface_);
// Establece el modo de video
setFullscreenMode(options.video.fullscreen);
// Muestra la ventana
show();
}
// Destructor
Screen::~Screen()
{
SDL_DestroyTexture(game_texture_);
SDL_DestroyRenderer(renderer_);
SDL_DestroyWindow(window_);
}
// Limpia el renderer
void Screen::clearRenderer(Color color)
{
SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, 0xFF);
SDL_RenderClear(renderer_);
}
// Prepara para empezar a dibujar en la textura de juego
void Screen::start() { setRendererSurface(nullptr); }
// Vuelca el contenido del renderizador en pantalla
void Screen::render()
{
// Copia la surface a la textura
surfaceToTexture();
// Copia la textura al renderizador
textureToRenderer();
}
// Establece el modo de video
void Screen::setFullscreenMode(bool mode)
{
// Actualiza las opciones
options.video.fullscreen = mode;
// Configura el modo de pantalla
SDL_SetWindowFullscreen(window_, options.video.fullscreen);
}
// Camibia entre pantalla completa y ventana
void Screen::toggleFullscreen()
{
options.video.fullscreen = !options.video.fullscreen;
setFullscreenMode();
}
// Reduce el tamaño de la ventana
bool Screen::decWindowZoom()
{
if (!options.video.fullscreen)
{
const int PREVIOUS_ZOOM = options.window.zoom;
--options.window.zoom;
options.window.zoom = std::max(options.window.zoom, 1);
if (options.window.zoom != PREVIOUS_ZOOM)
{
adjustWindowSize();
return true;
}
}
return false;
}
// Aumenta el tamaño de la ventana
bool Screen::incWindowZoom()
{
if (!options.video.fullscreen)
{
const int PREVIOUS_ZOOM = options.window.zoom;
++options.window.zoom;
options.window.zoom = std::min(options.window.zoom, options.window.max_zoom);
if (options.window.zoom != PREVIOUS_ZOOM)
{
adjustWindowSize();
return true;
}
}
return false;
}
// Actualiza la lógica de la clase
void Screen::update()
{
Mouse::updateCursorVisibility();
}
// Calcula el tamaño de la ventana
void Screen::adjustWindowSize()
{
window_width_ = options.logo.width;
window_height_ = options.logo.height;
// Establece el nuevo tamaño
if (!options.video.fullscreen)
{
int old_width, old_height;
SDL_GetWindowSize(window_, &old_width, &old_height);
int old_pos_x, old_pos_y;
SDL_GetWindowPosition(window_, &old_pos_x, &old_pos_y);
const int NEW_POS_X = old_pos_x + (old_width - (window_width_ * options.window.zoom)) / 2;
const int NEW_POS_Y = old_pos_y + (old_height - (window_height_ * options.window.zoom)) / 2;
SDL_SetWindowSize(window_, window_width_ * options.window.zoom, window_height_ * options.window.zoom);
SDL_SetWindowPosition(window_, std::max(NEW_POS_X, WINDOWS_DECORATIONS_), std::max(NEW_POS_Y, 0));
}
}
// Establece el renderizador para las surfaces
void Screen::setRendererSurface(std::shared_ptr<Surface> surface)
{
(surface) ? renderer_surface_ = std::make_shared<std::shared_ptr<Surface>>(surface) : renderer_surface_ = std::make_shared<std::shared_ptr<Surface>>(game_surface_);
}
// Copia la surface a la textura
void Screen::surfaceToTexture()
{
game_surface_->copyToTexture(renderer_, game_texture_);
}
// Copia la textura al renderizador
void Screen::textureToRenderer()
{
SDL_SetRenderTarget(renderer_, nullptr);
SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer_);
SDL_RenderTexture(renderer_, game_texture_, nullptr, nullptr);
SDL_RenderPresent(renderer_);
}
// Limpia la game_surface_
void Screen::clearSurface(Uint8 index) { game_surface_->clear(index); }
// Muestra la ventana
void Screen::show() { SDL_ShowWindow(window_); }
// Oculta la ventana
void Screen::hide() { SDL_HideWindow(window_); }
// Getters
SDL_Renderer *Screen::getRenderer() { return renderer_; }
std::shared_ptr<Surface> Screen::getRendererSurface() { return (*renderer_surface_); }
// Arranca SDL VIDEO y crea la ventana
bool Screen::initSDL()
{
// Indicador de éxito
auto success = true;
// Inicializa SDL
if (!SDL_Init(SDL_INIT_VIDEO))
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_VIDEO could not initialize! SDL Error: %s", SDL_GetError());
success = false;
}
else
{
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "\n** SDL_VIDEO: INITIALIZING\n");
if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"))
{
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: opengl not enabled!");
}
// Crea la ventana
window_ = SDL_CreateWindow(options.window.caption.c_str(), options.logo.width * options.window.zoom, options.logo.height * options.window.zoom, SDL_WINDOW_OPENGL);
if (!window_)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Window could not be created! SDL Error: %s", SDL_GetError());
success = false;
}
else
{
renderer_ = SDL_CreateRenderer(window_, nullptr);
if (!renderer_)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Renderer could not be created! SDL Error: %s", SDL_GetError());
success = false;
}
else
{
SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF);
SDL_SetRenderLogicalPresentation(renderer_, options.logo.width, options.logo.height, SDL_LOGICAL_PRESENTATION_INTEGER_SCALE);
SDL_SetWindowFullscreen(window_, options.video.fullscreen);
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND);
SDL_SetRenderVSync(renderer_, options.video.vertical_sync ? 1 : SDL_RENDERER_VSYNC_DISABLED);
}
}
}
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "** SDL_VIDEO: INITIALIZATION COMPLETE\n");
return success;
}
// Obtiene información sobre la pantalla
void Screen::getDisplayInfo()
{
int i, num_displays = 0;
SDL_DisplayID *displays = SDL_GetDisplays(&num_displays);
if (displays)
{
for (i = 0; i < num_displays; ++i)
{
SDL_DisplayID instance_id = displays[i];
const char *name = SDL_GetDisplayName(instance_id);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Display %" SDL_PRIu32 ": %s", instance_id, name ? name : "Unknown");
}
auto DM = SDL_GetCurrentDisplayMode(displays[0]);
// Calcula el máximo factor de zoom que se puede aplicar a la pantalla
options.window.max_zoom = std::min(DM->w / options.logo.width, DM->h / options.logo.height);
options.window.zoom = std::min(options.window.zoom, options.window.max_zoom);
// Muestra información sobre el tamaño de la pantalla y de la ventana de juego
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Current display mode: %dx%d @ %dHz",
static_cast<int>(DM->w), static_cast<int>(DM->h), static_cast<int>(DM->refresh_rate));
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Window resolution: %dx%d x%d",
static_cast<int>(options.logo.width), static_cast<int>(options.logo.height), options.window.zoom);
options.video.info = std::to_string(static_cast<int>(DM->w)) + " X " +
std::to_string(static_cast<int>(DM->h)) + " AT " +
std::to_string(static_cast<int>(DM->refresh_rate)) + " HZ";
// Calcula el máximo factor de zoom que se puede aplicar a la pantalla
const int MAX_ZOOM = std::min(DM->w / options.logo.width, (DM->h - WINDOWS_DECORATIONS_) / options.logo.height);
// Normaliza los valores de zoom
options.window.zoom = std::min(options.window.zoom, MAX_ZOOM);
SDL_free(displays);
}
}
// Activa / desactiva el escalado entero
void Screen::toggleIntegerScale()
{
options.video.integer_scale = !options.video.integer_scale;
SDL_SetRenderLogicalPresentation(Screen::get()->getRenderer(), options.logo.width, options.logo.height, options.video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX);
}
// Activa / desactiva el vsync
void Screen::toggleVSync()
{
options.video.vertical_sync = !options.video.vertical_sync;
SDL_SetRenderVSync(renderer_, options.video.vertical_sync ? 1 : SDL_RENDERER_VSYNC_DISABLED);
}