From d7e01786024f8a5eee3a1809d898c0bcbcb2c5b6 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Mon, 3 Mar 2025 19:15:24 +0100 Subject: [PATCH] =?UTF-8?q?Transici=C3=B3=20a=20surface:=20game.cpp=20fet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/palette/ruzx-spectrum-8x.gif | Bin 0 -> 379 bytes data/palette/ruzx-spectrum-revision-2-8x.gif | Bin 0 -> 379 bytes data/palette/zx-spectrum-8x.gif | Bin 0 -> 379 bytes data/palette/zx-spectrum-adjusted-8x.gif | Bin 0 -> 379 bytes data/palette/zxarne-5-2-8x.gif | Bin 0 -> 379 bytes source/credits.cpp | 53 ++++----- source/credits.h | 12 ++- source/director.cpp | 7 ++ source/game.cpp | 14 +-- source/game.h | 25 ++--- source/loading_screen.cpp | 2 +- source/resource.cpp | 2 +- source/screen.cpp | 12 ++- source/screen.h | 4 +- source/surface.cpp | 107 ++++++++++++++++--- source/surface.h | 16 +-- source/title.cpp | 14 +-- source/utils.cpp | 1 + 18 files changed, 177 insertions(+), 92 deletions(-) create mode 100644 data/palette/ruzx-spectrum-8x.gif create mode 100644 data/palette/ruzx-spectrum-revision-2-8x.gif create mode 100644 data/palette/zx-spectrum-8x.gif create mode 100644 data/palette/zx-spectrum-adjusted-8x.gif create mode 100644 data/palette/zxarne-5-2-8x.gif diff --git a/data/palette/ruzx-spectrum-8x.gif b/data/palette/ruzx-spectrum-8x.gif new file mode 100644 index 0000000000000000000000000000000000000000..9665d49bc4c2b3cd472adcedc08259b6db8ffcdc GIT binary patch literal 379 zcmZ?wbh9u|Y+&GEIKlt|{M;5*;bIGv1>cItt9K{P{jc`@sjr6cf?|Qm(wWN>vzolJ z|GyL2>i+Wn+AZ6E{(l43L@c5BpWDwhB-q(8z|~04fSD1fPw^)UCl`>`0hs}E1_SHU z1ckmwN%Nj9UZ?eBpPtfrqvZSF7QDB5_ zmw8wCR|VIE*F`tPH>tL8x9N5WbeZ<>^w~~endCZ!cbe}EwppQb_~ykfU|+Q^xD2oYJK@lCk6&<075U5A^-pY literal 0 HcmV?d00001 diff --git a/data/palette/ruzx-spectrum-revision-2-8x.gif b/data/palette/ruzx-spectrum-revision-2-8x.gif new file mode 100644 index 0000000000000000000000000000000000000000..1369996a6e557608e8ed2dc03df6d796a77bc3c6 GIT binary patch literal 379 zcmZ?wbh9u|Y+&GEIKlt|f`Y0lN<}(#-a+2E|Klv@DSZlY)KItoHxU z{N_C4$cB?gCjWo>|IbITCSnQ2|J;7AA;Hd$0j@@R2F#2=eTqL>IJtnd4#*6UGZhyVAr7HFhM^dD<1TIpgj|6E&%R&B)kYt3b= zeJl3I330Y2ZA>tb;%$HYvB5z}urtMIVStus_tT<-2}#N+>S@{;`dP*~=6Tiy_C?Mm z?q%K;{#C&>;dRjs@lC2NEN!|S0$rv(Tz$3^SSPto;hE+;gJV|c9R7K+3pf`sE?K&4 z#mZG{)~?&IanqKq+ji{SwP)|X0|yr!S;lvK71OD8Y-cxdU)aWcc^B`see5?6-8r`6 p!J{)9p1ruVY)_7rnNxlUiSX(}{t>8UStI=s(t0w6erv{<-E7E!T+k*V@Zgw^rGN?x#fu6Oxou)YG&x^s|g}%=4@Z?2DXB+{?Tx{Hua%!t0_N;+s@knA&tZ zxVlVxSo&-y@Jw=@!Zyu!2H&jEIUMt17YHn3T(Wf8ij}L@tX;QZYJ|Q V>cXei_@$Fik|!ivPL&TtkAL9RpmA^bD98ftnP5vT$+%X&sOOAZIYJK21>Q zTa+*_ZPB__kM_M&IB%4A|J$PXR*(PhYbww%k?23xRN(e9^32NRN%Q`FP6GxW2JbIkLs3+#)WOWe!6 zEBvd1Yr^ZI8{(T(TbSB(JGi<`dszBxC-6*iox(QFcLv|A&^a9QViyQ3VqCIx*@~5` z)~sE(VdJJPTet1lxogkfeFqLMI$uNuV!g19_wp|GYy0?b9=daE#e+v@ mHavTAX~&y)Hx4|R`0AUkoHt6m|83Fxs)zsWnhP{+B>LUjidN=W%=c?4(W;GDAJ$&By0v0| zoDgSg(#8Y>Dc<(S9~&H$1UplV76xdEc0VmTn2@BLqMoLmp`T@(W1eSSU|-~1;$G%m z;a?S86J8hH5Z|QQ!qleQ!PRBj!_sFvfpwDW6!vMpGk9l(&f%XIyFg$OQKJ8*E(k!766S23Sj$9;Aa+l6gBmv?bo+sAkF(4Au|9y~g; l;n|BzJKnszap1|sSKo9cR~J5=chPJ6I;r*LH=P(5tN|g;lk5Nh literal 0 HcmV?d00001 diff --git a/source/credits.cpp b/source/credits.cpp index 9b09192..9e8edd7 100644 --- a/source/credits.cpp +++ b/source/credits.cpp @@ -7,7 +7,7 @@ #include // for SDL_GetTicks #include // for min #include // for basic_ostream, operator<<, cout, endl -#include "s_animated_sprite.h" // for AnimatedSprite +#include "s_animated_sprite.h" // for SAnimatedSprite #include "defines.h" // for GAMECANVAS_HEIGHT, GAMECANVAS_WIDTH #include "global_events.h" // for check #include "global_inputs.h" // for check @@ -18,7 +18,7 @@ // Constructor Credits::Credits() - : shining_sprite_(std::make_shared(Resource::get()->getSurface("shine.gif"), Resource::get()->getAnimations("shine.ani"))) + : shining_sprite_(std::make_shared(Resource::get()->getSurface("shine.gif"), Resource::get()->getAnimations("shine.ani"))) { // Inicializa variables options.section.section = Section::CREDITS; @@ -29,23 +29,15 @@ Credits::Credits() Screen::get()->setBorderColor(stringToColor(options.video.palette, "black")); // Crea la textura para el texto que se escribe en pantalla - text_texture_ = createTexture(Screen::get()->getRenderer(), options.game.width, options.game.height); + text_surface_ = std::make_shared(Screen::get()->getRenderSurfaceData(), options.game.width, options.game.height); // Crea la textura para cubrir el rexto - cover_texture_ = createTexture(Screen::get()->getRenderer(), options.game.width, options.game.height); - SDL_SetTextureBlendMode(cover_texture_, SDL_BLENDMODE_BLEND); + cover_surface_ = std::make_shared(Screen::get()->getRenderSurfaceData(), options.game.width, options.game.height); // Escribe el texto en la textura fillTexture(); } -// Destructor -Credits::~Credits() -{ - SDL_DestroyTexture(text_texture_); - SDL_DestroyTexture(cover_texture_); -} - // Comprueba el manejador de eventos void Credits::checkEvents() { @@ -150,10 +142,8 @@ void Credits::fillTexture() iniTexts(); // Rellena la textura de texto - SDL_SetRenderTarget(Screen::get()->getRenderer(), text_texture_); - Color color = stringToColor(options.video.palette, "black"); - SDL_SetRenderDrawColor(Screen::get()->getRenderer(), color.r, color.g, color.b, 0xFF); - SDL_RenderClear(Screen::get()->getRenderer()); + Screen::get()->setRenderSurfaceData(text_surface_); + Screen::get()->clean(stringToColor("black")); auto text = Resource::get()->getText("smb2"); @@ -178,28 +168,28 @@ void Credits::fillTexture() SDL_SetRenderTarget(Screen::get()->getRenderer(), nullptr); // Rellena la textura que cubre el texto con color transparente - SDL_SetRenderTarget(Screen::get()->getRenderer(), cover_texture_); - SDL_SetRenderDrawColor(Screen::get()->getRenderer(), color.r, color.g, color.b, 0x00); - SDL_RenderClear(Screen::get()->getRenderer()); + Screen::get()->setRenderSurfaceData(text_surface_); + Screen::get()->clean(stringToColor("transparent")); // Los primeros 8 pixels crea una malla - SDL_SetRenderDrawColor(Screen::get()->getRenderer(), color.r, color.g, color.b, 0xFF); + auto surface = Screen::get()->getRenderSurfaceData(); + auto color = stringToColor("black"); for (int i = 0; i < 256; i += 2) { - SDL_RenderDrawPoint(Screen::get()->getRenderer(), i, 0); - SDL_RenderDrawPoint(Screen::get()->getRenderer(), i, 2); - SDL_RenderDrawPoint(Screen::get()->getRenderer(), i, 4); - SDL_RenderDrawPoint(Screen::get()->getRenderer(), i, 6); + text_surface_->putPixel(surface, i, 0, color); + text_surface_->putPixel(surface, i, 2, color); + text_surface_->putPixel(surface, i, 4, color); + text_surface_->putPixel(surface, i, 6, color); - SDL_RenderDrawPoint(Screen::get()->getRenderer(), i + 1, 5); - SDL_RenderDrawPoint(Screen::get()->getRenderer(), i + 1, 7); + text_surface_->putPixel(surface, i + 1, 5, color); + text_surface_->putPixel(surface, i + 1, 7, color); } // El resto se rellena de color sólido SDL_Rect rect = {0, 8, 256, 192}; - SDL_RenderFillRect(Screen::get()->getRenderer(), &rect); + text_surface_->fillRect(surface, &rect, color); - SDL_SetRenderTarget(Screen::get()->getRenderer(), nullptr); + Screen::get()->setRenderSurfaceData(nullptr); } // Actualiza el contador @@ -263,18 +253,17 @@ void Credits::render() Screen::get()->start(); // Limpia la pantalla - Screen::get()->clean(); + Screen::get()->clean(1); if (counter_ < 1150) { // Dibuja la textura con el texto en pantalla - SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, nullptr, nullptr); + text_surface_->render(0, 0); // Dibuja la textura que cubre el texto const int offset = std::min(counter_ / 8, 192 / 2); SDL_Rect srcRect = {0, 0, 256, 192 - (offset * 2)}; - SDL_Rect dstRect = {0, offset * 2, 256, 192 - (offset * 2)}; - SDL_RenderCopy(Screen::get()->getRenderer(), cover_texture_, &srcRect, &dstRect); + cover_surface_->render(0, offset * 2, &srcRect); // Dibuja el sprite con el brillo shining_sprite_->render(); diff --git a/source/credits.h b/source/credits.h index b92b2f0..9b4789d 100644 --- a/source/credits.h +++ b/source/credits.h @@ -6,7 +6,9 @@ #include // for string #include // for vector #include "utils.h" // for Color -class AnimatedSprite; // lines 9-9 +#include +#include "surface.h" +class SAnimatedSprite; // lines 9-9 class Credits { @@ -18,9 +20,9 @@ private: }; // Objetos y punteros - SDL_Texture *text_texture_; // Textura para dibujar el texto - SDL_Texture *cover_texture_; // Textura para cubrir el texto - std::shared_ptr shining_sprite_; // Sprite para el brillo del corazón + std::shared_ptr text_surface_; // Textura para dibujar el texto + std::shared_ptr cover_surface_; // Textura para cubrir el texto + std::shared_ptr shining_sprite_; // Sprite para el brillo del corazón // Variables int counter_ = 0; // Contador @@ -55,7 +57,7 @@ public: Credits(); // Destructor - ~Credits(); + ~Credits() = default; // Bucle principal void run(); diff --git a/source/director.cpp b/source/director.cpp index 726752c..4436186 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -394,6 +394,13 @@ bool Director::setFileList() Asset::get()->add(prefix + "/data/font/8bithud.gif", AssetType::BITMAP); Asset::get()->add(prefix + "/data/font/8bithud.txt", AssetType::FONT); + // Paletas + Asset::get()->add(prefix + "/data/palette/ruzx-spectrum-8x.gif", AssetType::DATA); + Asset::get()->add(prefix + "/data/palette/ruzx-spectrum-revision-2-8x.gif", AssetType::DATA); + Asset::get()->add(prefix + "/data/palette/zxarne-5-2-8x.gif", AssetType::DATA); + Asset::get()->add(prefix + "/data/palette/zx-spectrum-8x.gif", AssetType::DATA); + Asset::get()->add(prefix + "/data/palette/zx-spectrum-adjusted-8x.gif", AssetType::DATA); + // Shaders Asset::get()->add(prefix + "/data/shaders/crtpi_192.glsl", AssetType::DATA); Asset::get()->add(prefix + "/data/shaders/crtpi_240.glsl", AssetType::DATA); diff --git a/source/game.cpp b/source/game.cpp index 0528a3e..8b29e32 100644 --- a/source/game.cpp +++ b/source/game.cpp @@ -66,7 +66,6 @@ Game::Game(GameMode mode) Game::~Game() { ItemTracker::destroy(); - SDL_DestroyTexture(room_name_texture_); } // Comprueba los eventos de la cola @@ -288,7 +287,7 @@ void Game::checkDebugEvents(const SDL_Event &event) void Game::renderRoomName() { // Dibuja la textura con el nombre de la habitación - SDL_RenderCopy(Screen::get()->getRenderer(), room_name_texture_, nullptr, &room_name_rect_); + room_name_surface_->render(nullptr, &room_name_rect_); } // Cambia de habitación @@ -561,19 +560,17 @@ void Game::initStats() void Game::fillRoomNameTexture() { // Pone la textura como destino de renderizado - SDL_SetRenderTarget(Screen::get()->getRenderer(), room_name_texture_); + Screen::get()->setRenderSurfaceData(room_name_surface_); // Rellena la textura de color - const Color color = stringToColor(options.video.palette, "white"); - SDL_SetRenderDrawColor(Screen::get()->getRenderer(), color.r, color.g, color.b, 0xFF); - SDL_RenderClear(Screen::get()->getRenderer()); + Screen::get()->clean(stringToColor("white")); // Escribe el texto en la textura auto text = Resource::get()->getText("smb2"); text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, text->getCharacterSize() / 2, room_->getName(), 1, room_->getBGColor()); // Deja el renderizador por defecto - SDL_SetRenderTarget(Screen::get()->getRenderer(), nullptr); + Screen::get()->setRenderSurfaceData(nullptr); } // Comprueba algunos logros @@ -663,8 +660,7 @@ void Game::initPlayer(const PlayerSpawn &spawn_point, std::shared_ptr room void Game::createRoomNameTexture() { auto text = Resource::get()->getText("smb2"); - room_name_texture_ = createTexture(Screen::get()->getRenderer(), options.game.width, text->getCharacterSize() * 2); - SDL_SetTextureBlendMode(room_name_texture_, SDL_BLENDMODE_BLEND); + room_name_surface_ = std::make_shared(Screen::get()->getRenderSurfaceData(), options.game.width, text->getCharacterSize() * 2); // Establece el destino de la textura room_name_rect_ = {0, PLAY_AREA_HEIGHT, options.game.width, text->getCharacterSize() * 2}; diff --git a/source/game.h b/source/game.h index d1007b7..5e438f3 100644 --- a/source/game.h +++ b/source/game.h @@ -8,11 +8,12 @@ #include // for string #include // for vector #include "player.h" // for PlayerSpawn -class Room; // lines 10-10 -class RoomTracker; // lines 11-11 -class Scoreboard; // lines 12-12 -class Stats; // lines 13-13 -struct ScoreboardData; // lines 14-14 +#include "surface.h" +class Room; // lines 10-10 +class RoomTracker; // lines 11-11 +class Scoreboard; // lines 12-12 +class Stats; // lines 13-13 +struct ScoreboardData; // lines 14-14 enum class GameMode { @@ -41,13 +42,13 @@ private: }; // Objetos y punteros - std::shared_ptr board_; // Estructura con los datos del marcador - std::shared_ptr scoreboard_; // Objeto encargado de gestionar el marcador - std::shared_ptr room_tracker_; // Lleva el control de las habitaciones visitadas - std::shared_ptr room_; // Objeto encargado de gestionar cada habitación del juego - std::shared_ptr player_; // Objeto con el jugador - std::shared_ptr stats_; // Objeto encargado de gestionar las estadísticas - SDL_Texture *room_name_texture_; // Textura para escribir el nombre de la habitación + std::shared_ptr board_; // Estructura con los datos del marcador + std::shared_ptr scoreboard_; // Objeto encargado de gestionar el marcador + std::shared_ptr room_tracker_; // Lleva el control de las habitaciones visitadas + std::shared_ptr room_; // Objeto encargado de gestionar cada habitación del juego + std::shared_ptr player_; // Objeto con el jugador + std::shared_ptr stats_; // Objeto encargado de gestionar las estadísticas + std::shared_ptr room_name_surface_; // Textura para escribir el nombre de la habitación // Variables GameMode mode_; // Modo del juego diff --git a/source/loading_screen.cpp b/source/loading_screen.cpp index 3f96356..fb46784 100644 --- a/source/loading_screen.cpp +++ b/source/loading_screen.cpp @@ -22,7 +22,7 @@ LoadingScreen::LoadingScreen() color_loading_screen_surface_(Resource::get()->getSurface("loading_screen_color.gif")), mono_loading_screen_sprite_(std::make_shared(mono_loading_screen_surface_, 0, 0, mono_loading_screen_surface_->getWidth(), mono_loading_screen_surface_->getHeight())), color_loading_screen_sprite_(std::make_shared(color_loading_screen_surface_, 0, 0, color_loading_screen_surface_->getWidth(), color_loading_screen_surface_->getHeight())), - screen_surface_(std::make_shared(Screen::get()->getRenderSurface(), options.game.width, options.game.height)) + screen_surface_(std::make_shared(Screen::get()->getRenderSurfaceData(), options.game.width, options.game.height)) { // Cambia el destino de las surfaces mono_loading_screen_surface_->setSurfaceDataDest(screen_surface_->getSurfaceData()); diff --git a/source/resource.cpp b/source/resource.cpp index e7aaa7a..6267bec 100644 --- a/source/resource.cpp +++ b/source/resource.cpp @@ -247,7 +247,7 @@ void Resource::loadSurfaces() for (const auto &l : list) { auto name = getFileName(l); - surfaces_.emplace_back(ResourceSurface(name, std::make_shared(Screen::get()->getRenderSurface(), l))); + surfaces_.emplace_back(ResourceSurface(name, std::make_shared(Screen::get()->getRenderSurfaceData(), l))); updateLoadingProgress(); } } diff --git a/source/screen.cpp b/source/screen.cpp index 5b0435a..0e302bc 100644 --- a/source/screen.cpp +++ b/source/screen.cpp @@ -61,6 +61,10 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer) border_texture_ = createTexture(renderer, options.game.width + options.video.border.width * 2, options.game.height + options.video.border.height * 2); setBorderColor(border_color_); + // Crea la surface donde se vuelcan los datos + surface_ = std::make_shared(nullptr, options.game.width, options.game.height); + surface_->loadPalette(Asset::get()->get("zx-spectrum-8x.gif")); + // Establece el modo de video setVideoMode(options.video.mode); @@ -91,7 +95,11 @@ void Screen::clean(Uint8 index) } // Prepara para empezar a dibujar en la textura de juego -void Screen::start() { SDL_SetRenderTarget(renderer_, game_texture_); } +void Screen::start() +{ + SDL_SetRenderTarget(renderer_, game_texture_); + setRenderSurfaceData(nullptr); +} // Prepara para empezar a dibujar en la textura del borde void Screen::startDrawOnBorder() { SDL_SetRenderTarget(renderer_, border_texture_); } @@ -348,7 +356,7 @@ void Screen::resetShaders() } // Establece el renderizador para las surfaces -void Screen::setRenderSurface(std::shared_ptr surface) +void Screen::setRenderSurfaceData(std::shared_ptr surface) { (surface) ? surface_->redirectSurfaceDataTo(surface) : surface_->restoreOriginalSurfaceData(); } \ No newline at end of file diff --git a/source/screen.h b/source/screen.h index 9bb5cda..3af15f3 100644 --- a/source/screen.h +++ b/source/screen.h @@ -134,13 +134,13 @@ public: int getMaxZoom(); // Establece el renderizador para las surfaces - void setRenderSurface(std::shared_ptr surface); + void setRenderSurfaceData(std::shared_ptr surface = nullptr); // Limpia // Getters SDL_Renderer *getRenderer() { return renderer_; } - std::shared_ptr getRenderSurface() { return surface_->getSurfaceData(); } + std::shared_ptr getRenderSurfaceData() { return surface_->getSurfaceData(); } SDL_Texture *getGameTexture() { return game_texture_; }; SDL_Texture *getBorderTexture() { return border_texture_; } }; \ No newline at end of file diff --git a/source/surface.cpp b/source/surface.cpp index f305d4a..26c7587 100644 --- a/source/surface.cpp +++ b/source/surface.cpp @@ -107,21 +107,16 @@ void Surface::clear(Uint8 color) std::fill(surface_data_->data, surface_data_->data + total_pixels, color); } -// Pone un pixel en la superficie de destino -void Surface::putPixel(int x, int y, Uint8 color) +// Pone un pixel en la SurfaceData +void Surface::putPixel(std::shared_ptr surface_data, int x, int y, Uint8 color) { - if (color == transparent_color_) - { - return; // Color transparente, no dibujar - } - - if (x < 0 || y < 0 || x >= surface_data_dest_->width || y >= surface_data_dest_->height) + if (x < 0 || y < 0 || x >= surface_data->width || y >= surface_data->height) { return; // Coordenadas fuera de rango } - const int index = x + y * surface_data_dest_->width; - surface_data_dest_->data[index] = color; + const int index = x + y * surface_data->width; + surface_data->data[index] = color; } // Obtiene el color de un pixel de la superficie de origen @@ -130,6 +125,29 @@ Uint8 Surface::getPixel(int x, int y) return surface_data_->data[x + y * surface_data_->width]; } +// Dibuja un rectangulo +void Surface::fillRect(std::shared_ptr surface_data, SDL_Rect *rect, Uint8 color) +{ + if (!rect) return; // Verificar si el rectángulo es válido + + // Limitar los valores del rectángulo al tamaño de la superficie + int x_start = std::max(0, rect->x); + int y_start = std::max(0, rect->y); + int x_end = std::min(rect->x + rect->w, static_cast(surface_data->width)); + int y_end = std::min(rect->y + rect->h, static_cast(surface_data->height)); + + // Recorrer cada píxel dentro del rectángulo directamente + for (int y = y_start; y < y_end; ++y) + { + for (int x = x_start; x < x_end; ++x) + { + const int index = x + y * surface_data->width; + surface_data->data[index] = color; + } + } +} + + // Copia una región de la superficie de origen a la de destino void Surface::render(int dx, int dy, int sx, int sy, int w, int h) { @@ -158,7 +176,7 @@ void Surface::render(int dx, int dy, int sx, int sy, int w, int h) } // Copia una región de la superficie de origen a la de destino -void Surface::render(int x, int y, SDL_Rect *clip, SDL_RendererFlip flip) +void Surface::render(int x, int y, SDL_Rect *srcRect, SDL_RendererFlip flip) { if (!surface_data_ || !surface_data_dest_) { @@ -166,10 +184,10 @@ void Surface::render(int x, int y, SDL_Rect *clip, SDL_RendererFlip flip) } // Determina la región de origen (clip) a renderizar - int sx = (clip) ? clip->x : 0; - int sy = (clip) ? clip->y : 0; - int w = (clip) ? clip->w : surface_data_->width; - int h = (clip) ? clip->h : surface_data_->height; + int sx = (srcRect) ? srcRect->x : 0; + int sy = (srcRect) ? srcRect->y : 0; + int w = (srcRect) ? srcRect->w : surface_data_->width; + int h = (srcRect) ? srcRect->h : surface_data_->height; // Limitar la región para evitar accesos fuera de rango w = std::min(w, surface_data_->width - sx); @@ -200,6 +218,65 @@ void Surface::render(int x, int y, SDL_Rect *clip, SDL_RendererFlip flip) } } +// Copia una región de la superficie de origen a la de destino +void Surface::render(SDL_Rect *srcRect, SDL_Rect *dstRect, SDL_RendererFlip flip) +{ + if (!surface_data_ || !surface_data_dest_) + { + throw std::runtime_error("Surface source or destination is null."); + } + + // Si srcRect es nullptr, tomar toda la superficie fuente + int sx = (srcRect) ? srcRect->x : 0; + int sy = (srcRect) ? srcRect->y : 0; + int sw = (srcRect) ? srcRect->w : surface_data_->width; + int sh = (srcRect) ? srcRect->h : surface_data_->height; + + // Si dstRect es nullptr, asignar las mismas dimensiones que srcRect + int dx = (dstRect) ? dstRect->x : 0; + int dy = (dstRect) ? dstRect->y : 0; + int dw = (dstRect) ? dstRect->w : sw; + int dh = (dstRect) ? dstRect->h : sh; + + // Asegurarse de que srcRect y dstRect tienen las mismas dimensiones + if (sw != dw || sh != dh) + { + dw = sw; // Respetar las dimensiones de srcRect + dh = sh; + } + + // Limitar la región para evitar accesos fuera de rango en src y dst + sw = std::min(sw, surface_data_->width - sx); + sh = std::min(sh, surface_data_->height - sy); + dw = std::min(dw, surface_data_dest_->width - dx); + dh = std::min(dh, surface_data_dest_->height - dy); + + int final_width = std::min(sw, dw); + int final_height = std::min(sh, dh); + + // Renderiza píxel por píxel aplicando el flip si es necesario + for (int iy = 0; iy < final_height; ++iy) + { + for (int ix = 0; ix < final_width; ++ix) + { + // Coordenadas de origen + int src_x = (flip == SDL_FLIP_HORIZONTAL) ? (sx + final_width - 1 - ix) : (sx + ix); + int src_y = (flip == SDL_FLIP_VERTICAL) ? (sy + final_height - 1 - iy) : (sy + iy); + + // Coordenadas de destino + int dest_x = dx + ix; + int dest_y = dy + iy; + + // Copiar el píxel si no es transparente + Uint8 color = surface_data_->data[src_x + src_y * surface_data_->width]; + if (color != transparent_color_) + { + surface_data_dest_->data[dest_x + dest_y * surface_data_dest_->width] = color; + } + } + } +} + // Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro void Surface::renderWithColorReplace(int x, int y, Uint8 source_color = 0, Uint8 target_color = 0, SDL_Rect *clip = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE) { diff --git a/source/surface.h b/source/surface.h index 5d4bea1..61b5cdb 100644 --- a/source/surface.h +++ b/source/surface.h @@ -66,12 +66,6 @@ private: std::array palette_; // Paleta para volcar la SurfaceData a una Textura int transparent_color_; // Indice de la paleta que se omite en la copia de datos - // Pone un pixel en la superficie de destino - void putPixel(int x, int y, Uint8 color); - - // Obtiene el color de un pixel de la superficie de origen - Uint8 getPixel(int x, int y); - public: // Constructor Surface(std::shared_ptr surface_data_dest, int w, int h); @@ -89,6 +83,7 @@ public: // Copia una región de la SurfaceData de origen a la SurfaceData de destino void render(int dx, int dy, int sx, int sy, int w, int h); void render(int x, int y, SDL_Rect *clip = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE); + void render(SDL_Rect *srcRect = nullptr, SDL_Rect *dstRect = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE); // Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro void renderWithColorReplace(int x, int y, Uint8 source_color = 0, Uint8 target_color = 0, SDL_Rect *clip = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE); @@ -105,6 +100,15 @@ public: // Realiza un efecto de fundido en la paleta bool fadePalette(); + // Pone un pixel en la SurfaceData + void putPixel(std::shared_ptr surface_data, int x, int y, Uint8 color); + + // Obtiene el color de un pixel de la superficie de origen + Uint8 getPixel(int x, int y); + + // Dibuja un rectangulo + void fillRect(std::shared_ptr surface_data, SDL_Rect *rect, Uint8 color); + // Getters std::shared_ptr getSurfaceData() const { return surface_data_; } int getTransparentColor() const { return transparent_color_; } diff --git a/source/title.cpp b/source/title.cpp index 8608507..9ec0926 100644 --- a/source/title.cpp +++ b/source/title.cpp @@ -25,7 +25,7 @@ Title::Title() : surface_(Resource::get()->getSurface("title_logo.gif")), sprite_(std::make_shared(surface_, 0, 0, surface_->getWidth(), surface_->getHeight())), - bg_surface_(std::make_shared(Screen::get()->getRenderSurface(), options.game.width, options.game.height)) + bg_surface_(std::make_shared(Screen::get()->getRenderSurfaceData(), options.game.width, options.game.height)) { // Carga la surface con los gráficos de la pantalla de carga pInit(Screen::get()->getRenderer(), 256, 128); @@ -251,7 +251,7 @@ void Title::render() if (state_ == TitleState::SHOW_MENU) { // Dibuja la textura de fondo - SDL_RenderCopy(Screen::get()->getRenderer(), bg_surface_, nullptr, nullptr); + bg_surface_->render(0, 0); // Dibuja la marquesina renderMarquee(); @@ -311,7 +311,7 @@ void Title::moveCheevosList(int direction) void Title::fillSurface() { // Coloca el puntero del renderizador sobre la textura - Screen::get()->setRenderSurface(bg_surface_); + Screen::get()->setRenderSurfaceData(bg_surface_); // Rellena la textura de color bg_surface_->setColor(255, 0xFF000000); @@ -330,7 +330,7 @@ void Title::fillSurface() text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 20 * TEXT_SIZE, "ESC.EXIT GAME", 1, COLOR); // Devuelve el puntero del renderizador a su sitio - Screen::get()->setRenderSurface(nullptr); + Screen::get()->setRenderSurfaceData(nullptr); } // Crea y rellena la textura para mostrar los logros @@ -345,10 +345,10 @@ void Title::createCheevosTexture() constexpr int CHEEVOS_PADDING = 10; const int CHEEVO_HEIGHT = CHEEVOS_PADDING + (TEXT->getCharacterSize() * 2) + 1; const int CHEEVOS_TEXTURE_HEIGHT = (CHEEVO_HEIGHT * CHEEVOS_LIST.size()) + 2 + TEXT->getCharacterSize() + 8; - cheevos_surface_ = std::make_shared(Screen::get()->getRenderSurface(), CHEEVOS_TEXTURE_WIDTH, CHEEVOS_TEXTURE_HEIGHT); + cheevos_surface_ = std::make_shared(Screen::get()->getRenderSurfaceData(), CHEEVOS_TEXTURE_WIDTH, CHEEVOS_TEXTURE_HEIGHT); // Prepara para dibujar sobre la textura - Screen::get()->setRenderSurface(cheevos_surface_); + Screen::get()->setRenderSurfaceData(cheevos_surface_); // Rellena la textura con color sólido const Color CHEEVOS_BG_COLOR = stringToColor(options.video.palette, "black"); @@ -381,7 +381,7 @@ void Title::createCheevosTexture() } // Restablece el RenderSurface - Screen::get()->setRenderSurface(nullptr); + Screen::get()->setRenderSurfaceData(nullptr); // Crea el sprite para el listado de logros cheevos_sprite_ = std::make_shared(cheevos_surface_, (GAMECANVAS_WIDTH - cheevos_surface_->getWidth()) / 2, CHEEVOS_TEXTURE_POS_Y, cheevos_surface_->getWidth(), cheevos_surface_->getHeight()); diff --git a/source/utils.cpp b/source/utils.cpp index 1b07999..4709128 100644 --- a/source/utils.cpp +++ b/source/utils.cpp @@ -433,6 +433,7 @@ Uint8 stringToColor(const std::string &str) { // Mapas de colores para cada paleta static const std::unordered_map paletteMap = { + {"transparent", 0}, {"black", 1}, {"bright_black", 2}, {"blue", 3},