From 03bdc82dc11c25aed78c46145bf099b9cf3819ac Mon Sep 17 00:00:00 2001 From: Gregor Klevze Date: Thu, 25 Dec 2025 17:26:55 +0100 Subject: [PATCH] Updated renderer Added Renderer_iface.h as a clean interface. Replaced usages of old/ambiguous SDL calls in SDLRenderer.cpp to call SDL3 APIs: SDL_RenderTexture, SDL_RenderFillRect, SDL_RenderRect, SDL_RenderLine. Converted copy() to call SDL_RenderTexture by converting integer rects to float rects. Updated GameRenderer.cpp to include the new clean interface. --- src/graphics/renderers/GameRenderer.cpp | 116 +++++++++++++----------- src/renderer/Renderer.h | 11 +++ src/renderer/Renderer_iface.h | 27 ++++++ src/renderer/SDLRenderer.cpp | 42 ++++++++- 4 files changed, 141 insertions(+), 55 deletions(-) create mode 100644 src/renderer/Renderer_iface.h diff --git a/src/graphics/renderers/GameRenderer.cpp b/src/graphics/renderers/GameRenderer.cpp index ddd4c94..575947b 100644 --- a/src/graphics/renderers/GameRenderer.cpp +++ b/src/graphics/renderers/GameRenderer.cpp @@ -1,4 +1,5 @@ #include "GameRenderer.h" +#include "../../renderer/Renderer_iface.h" #include "SyncLineRenderer.h" #include "../../gameplay/core/Game.h" @@ -248,23 +249,25 @@ static void updateAndDrawTransport(SDL_Renderer* renderer, SDL_Texture* blocksTe Uint8 gridAlpha = static_cast(std::lround(255.0f * t)); Uint8 nextAlpha = gridAlpha; // fade new NEXT preview in at same rate as grid - // Draw preview fade-out - if (previewAlpha > 0) { - if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, previewAlpha); - for (int cy = 0; cy < 4; ++cy) { - for (int cx = 0; cx < 4; ++cx) { - if (!Game::cellFilled(s_transport.piece, cx, cy)) continue; - float px = s_transport.startX + static_cast(cx) * s_transport.tileSize; - float py = s_transport.startY + static_cast(cy) * s_transport.tileSize; - GameRenderer::drawBlockTexturePublic(renderer, blocksTex, px, py, s_transport.tileSize, s_transport.piece.type); + // Create renderer wrapper + auto rwrap = renderer::MakeSDLRenderer(renderer); + // Draw preview fade-out + if (previewAlpha > 0) { + if (blocksTex) rwrap->setTextureAlphaMod(blocksTex, previewAlpha); + for (int cy = 0; cy < 4; ++cy) { + for (int cx = 0; cx < 4; ++cx) { + if (!Game::cellFilled(s_transport.piece, cx, cy)) continue; + float px = s_transport.startX + static_cast(cx) * s_transport.tileSize; + float py = s_transport.startY + static_cast(cy) * s_transport.tileSize; + GameRenderer::drawBlockTexturePublic(renderer, blocksTex, px, py, s_transport.tileSize, s_transport.piece.type); + } } + if (blocksTex) rwrap->setTextureAlphaMod(blocksTex, 255); } - if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, 255); - } // Draw grid fade-in (same intensity as next preview fade-in) if (gridAlpha > 0) { - if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, gridAlpha); + if (blocksTex) rwrap->setTextureAlphaMod(blocksTex, gridAlpha); for (int cy = 0; cy < 4; ++cy) { for (int cx = 0; cx < 4; ++cx) { if (!Game::cellFilled(s_transport.piece, cx, cy)) continue; @@ -273,12 +276,12 @@ static void updateAndDrawTransport(SDL_Renderer* renderer, SDL_Texture* blocksTe GameRenderer::drawBlockTexturePublic(renderer, blocksTex, gx, gy, s_transport.tileSize, s_transport.piece.type); } } - if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, 255); + if (blocksTex) rwrap->setTextureAlphaMod(blocksTex, 255); } // Draw new NEXT preview fade-in (simultaneous) if (nextAlpha > 0) { - if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, nextAlpha); + if (blocksTex) rwrap->setTextureAlphaMod(blocksTex, nextAlpha); for (int cy = 0; cy < 4; ++cy) { for (int cx = 0; cx < 4; ++cx) { if (!Game::cellFilled(s_transport.nextPiece, cx, cy)) continue; @@ -287,7 +290,7 @@ static void updateAndDrawTransport(SDL_Renderer* renderer, SDL_Texture* blocksTe GameRenderer::drawBlockTexturePublic(renderer, blocksTex, nx, ny, s_transport.tileSize, s_transport.nextPiece.type); } } - if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, 255); + if (blocksTex) rwrap->setTextureAlphaMod(blocksTex, 255); } if (t >= 1.0f) { @@ -308,16 +311,18 @@ static const SDL_Color COLORS[] = { }; void GameRenderer::drawRect(SDL_Renderer* renderer, float x, float y, float w, float h, SDL_Color c) { - SDL_SetRenderDrawColor(renderer, c.r, c.g, c.b, c.a); + auto rwrap = renderer::MakeSDLRenderer(renderer); + rwrap->setDrawColor(c); SDL_FRect fr{x, y, w, h}; - SDL_RenderFillRect(renderer, &fr); + rwrap->fillRectF(&fr); } static void drawAsteroid(SDL_Renderer* renderer, SDL_Texture* asteroidTex, float x, float y, float size, const AsteroidCell& cell) { auto outlineGravity = [&](float inset, SDL_Color color) { - SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); + auto rwrap = renderer::MakeSDLRenderer(renderer); + rwrap->setDrawColor(color); SDL_FRect glow{ x + inset, y + inset, size - inset * 2.0f, size - inset * 2.0f }; - SDL_RenderRect(renderer, &glow); + rwrap->drawRectF(&glow); }; if (asteroidTex) { @@ -330,9 +335,10 @@ static void drawAsteroid(SDL_Renderer* renderer, SDL_Texture* asteroidTex, float case AsteroidType::Core: col = 3; break; } int row = std::clamp(cell.visualState, 0, 2); + auto rwrap = renderer::MakeSDLRenderer(renderer); SDL_FRect src{ col * SPRITE_SIZE, row * SPRITE_SIZE, SPRITE_SIZE, SPRITE_SIZE }; SDL_FRect dst{ x, y, size, size }; - SDL_RenderTexture(renderer, asteroidTex, &src, &dst); + rwrap->renderTexture(asteroidTex, &src, &dst); if (cell.gravityEnabled) { outlineGravity(2.0f, SDL_Color{255, 230, 120, 180}); @@ -355,15 +361,16 @@ static void drawAsteroid(SDL_Renderer* renderer, SDL_Texture* asteroidTex, float static_cast(base.b * hpScale + 40 * (1.0f - hpScale)), 255 }; - SDL_SetRenderDrawColor(renderer, fill.r, fill.g, fill.b, fill.a); + auto rwrap = renderer::MakeSDLRenderer(renderer); + rwrap->setDrawColor(fill); SDL_FRect body{x, y, size - 1.0f, size - 1.0f}; - SDL_RenderFillRect(renderer, &body); + rwrap->fillRectF(&body); SDL_Color outline = base; outline.a = 220; SDL_FRect border{x + 1.0f, y + 1.0f, size - 2.0f, size - 2.0f}; - SDL_SetRenderDrawColor(renderer, outline.r, outline.g, outline.b, outline.a); - SDL_RenderRect(renderer, &border); + rwrap->setDrawColor(outline); + rwrap->drawRectF(&border); if (cell.gravityEnabled) { outlineGravity(2.0f, SDL_Color{255, 230, 120, 180}); } @@ -387,7 +394,8 @@ void GameRenderer::drawBlockTexture(SDL_Renderer* renderer, SDL_Texture* blocksT SDL_FRect srcRect = {srcX, srcY, srcW, srcH}; SDL_FRect dstRect = {x, y, size, size}; - SDL_RenderTexture(renderer, blocksTex, &srcRect, &dstRect); + auto rwrap = renderer::MakeSDLRenderer(renderer); + rwrap->renderTexture(blocksTex, &srcRect, &dstRect); } void GameRenderer::drawPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex, const Game::Piece& piece, float ox, float oy, float tileSize, bool isGhost, float pixelOffsetX, float pixelOffsetY) { @@ -403,14 +411,17 @@ void GameRenderer::drawPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex, con SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); // Draw ghost piece as barely visible gray outline - SDL_SetRenderDrawColor(renderer, 180, 180, 180, 20); // Very faint gray + auto rwrap = renderer::MakeSDLRenderer(renderer); + // Draw ghost fill + SDL_Color ghostFill{180,180,180,20}; + rwrap->setDrawColor(ghostFill); SDL_FRect rect = {px + 2, py + 2, tileSize - 4, tileSize - 4}; - SDL_RenderFillRect(renderer, &rect); - + rwrap->fillRectF(&rect); // Draw thin gray border - SDL_SetRenderDrawColor(renderer, 180, 180, 180, 30); + SDL_Color ghostBorder{180,180,180,30}; + rwrap->setDrawColor(ghostBorder); SDL_FRect border = {px + 1, py + 1, tileSize - 2, tileSize - 2}; - SDL_RenderRect(renderer, &border); + rwrap->drawRectF(&border); } else { drawBlockTexture(renderer, blocksTex, px, py, tileSize, piece.type); } @@ -426,6 +437,7 @@ void GameRenderer::drawBlockTexturePublic(SDL_Renderer* renderer, SDL_Texture* b void GameRenderer::drawSmallPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex, PieceType pieceType, float x, float y, float tileSize) { if (pieceType >= PIECE_COUNT) return; + auto rwrap = renderer::MakeSDLRenderer(renderer); // Use the first rotation (index 0) for preview Game::Piece previewPiece; @@ -461,7 +473,7 @@ void GameRenderer::drawSmallPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex // Use semi-transparent alpha for preview blocks Uint8 previewAlpha = 180; if (blocksTex) { - SDL_SetTextureAlphaMod(blocksTex, previewAlpha); + rwrap->setTextureAlphaMod(blocksTex, previewAlpha); } for (int cy = 0; cy < 4; ++cy) { @@ -476,7 +488,7 @@ void GameRenderer::drawSmallPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex // Reset alpha if (blocksTex) { - SDL_SetTextureAlphaMod(blocksTex, 255); + rwrap->setTextureAlphaMod(blocksTex, 255); } } @@ -496,6 +508,8 @@ void GameRenderer::renderNextPanel( return; } + auto rwrap = renderer::MakeSDLRenderer(renderer); + const SDL_Color gridBorderColor{60, 80, 160, 255}; // matches main grid outline const SDL_Color bayColor{8, 12, 24, 235}; const SDL_Color bayOutline{25, 62, 86, 220}; @@ -505,25 +519,24 @@ void GameRenderer::renderNextPanel( // the panel rectangle and skip the custom background/frame drawing. if (nextPanelTex) { SDL_FRect dst{panelX, panelY, panelW, panelH}; - SDL_RenderTexture(renderer, nextPanelTex, nullptr, &dst); - // Draw the panel label over the texture — user requested visible label + rwrap->renderTexture(nextPanelTex, nullptr, &dst); const float labelPad = tileSize * 0.25f; pixelFont->draw(renderer, panelX + labelPad, panelY + labelPad * 0.5f, "NEXT", 0.9f, labelColor); } else { SDL_FRect bayRect{panelX, panelY, panelW, panelH}; - SDL_SetRenderDrawColor(renderer, bayColor.r, bayColor.g, bayColor.b, bayColor.a); - SDL_RenderFillRect(renderer, &bayRect); + rwrap->setDrawColor(bayColor); + rwrap->fillRectF(&bayRect); SDL_FRect thinOutline{panelX - 1.0f, panelY - 1.0f, panelW + 2.0f, panelH + 2.0f}; auto drawOutlineNoBottom = [&](const SDL_FRect& rect, SDL_Color color) { - SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); + rwrap->setDrawColor(color); const float left = rect.x; const float top = rect.y; const float right = rect.x + rect.w; const float bottom = rect.y + rect.h; - SDL_RenderLine(renderer, left, top, right, top); // top edge - SDL_RenderLine(renderer, left, top, left, bottom); // left edge - SDL_RenderLine(renderer, right, top, right, bottom); // right edge + rwrap->renderLine(left, top, right, top); // top edge + rwrap->renderLine(left, top, left, bottom); // left edge + rwrap->renderLine(right, top, right, bottom); // right edge }; drawOutlineNoBottom(thinOutline, gridBorderColor); @@ -641,11 +654,12 @@ void GameRenderer::renderPlayingState( float contentOffsetX = (winW - contentW) * 0.5f / contentScale; float contentOffsetY = (winH - contentH) * 0.5f / contentScale; - // Helper lambda for drawing rectangles with content offset + // Renderer wrapper and helper lambda for drawing rectangles with content offset + auto rwrap = renderer::MakeSDLRenderer(renderer); auto drawRectWithOffset = [&](float x, float y, float w, float h, SDL_Color c) { - SDL_SetRenderDrawColor(renderer, c.r, c.g, c.b, c.a); + rwrap->setDrawColor(c); SDL_FRect fr{x + contentOffsetX, y + contentOffsetY, w, h}; - SDL_RenderFillRect(renderer, &fr); + rwrap->fillRectF(&fr); }; // Responsive layout that scales with window size while maintaining margins @@ -747,28 +761,28 @@ void GameRenderer::renderPlayingState( scaledW, scaledH }; - SDL_RenderTexture(renderer, statisticsPanelTex, nullptr, &dstF); + rwrap->renderTexture(statisticsPanelTex, nullptr, &dstF); } } else { // Fallback: render entire texture stretched to panel - SDL_RenderTexture(renderer, statisticsPanelTex, nullptr, &blocksPanelBg); + rwrap->renderTexture(statisticsPanelTex, nullptr, &blocksPanelBg); } } else if (scorePanelTex) { - SDL_RenderTexture(renderer, scorePanelTex, nullptr, &blocksPanelBg); + rwrap->renderTexture(scorePanelTex, nullptr, &blocksPanelBg); } else { - SDL_SetRenderDrawColor(renderer, 12, 18, 32, 205); - SDL_RenderFillRect(renderer, &blocksPanelBg); + rwrap->setDrawColor(SDL_Color{12, 18, 32, 205}); + rwrap->fillRectF(&blocksPanelBg); } // Draw grid lines - SDL_SetRenderDrawColor(renderer, 40, 45, 60, 255); + rwrap->setDrawColor(SDL_Color{40, 45, 60, 255}); for (int x = 1; x < Game::COLS; ++x) { float lineX = gridX + x * finalBlockSize; - SDL_RenderLine(renderer, lineX, gridY, lineX, gridY + GRID_H); + rwrap->renderLine(lineX, gridY, lineX, gridY + GRID_H); } for (int y = 1; y < Game::ROWS; ++y) { float lineY = gridY + y * finalBlockSize; - SDL_RenderLine(renderer, gridX, lineY, gridX + GRID_W, lineY); + rwrap->renderLine(gridX, lineY, gridX + GRID_W, lineY); } if (!s_starfieldInitialized) { diff --git a/src/renderer/Renderer.h b/src/renderer/Renderer.h index e23e0a5..5a4f5e2 100644 --- a/src/renderer/Renderer.h +++ b/src/renderer/Renderer.h @@ -15,8 +15,19 @@ public: virtual void destroyTexture(SDL_Texture* tex) = 0; // Draw operations (minimal) + // Copy a texture (integer rects) virtual void copy(SDL_Texture* tex, const SDL_Rect* src, const SDL_Rect* dst) = 0; + // Copy a texture using floating-point rects (SDL_FRect) + virtual void renderTexture(SDL_Texture* tex, const SDL_FRect* src, const SDL_FRect* dst) = 0; + // Set alpha modulation on a texture + virtual void setTextureAlphaMod(SDL_Texture* tex, Uint8 a) = 0; + // Draw a line (floating-point coordinates) + virtual void renderLine(float x1, float y1, float x2, float y2) = 0; + // Set draw color and draw filled/floating rects virtual void clear(const SDL_Color& color) = 0; + virtual void setDrawColor(const SDL_Color& color) = 0; + virtual void fillRectF(const SDL_FRect* rect) = 0; + virtual void drawRectF(const SDL_FRect* rect) = 0; virtual void present() = 0; }; diff --git a/src/renderer/Renderer_iface.h b/src/renderer/Renderer_iface.h new file mode 100644 index 0000000..8aa98dd --- /dev/null +++ b/src/renderer/Renderer_iface.h @@ -0,0 +1,27 @@ +// Clean renderer interface for local use +#pragma once + +#include +#include + +namespace renderer { + +class Renderer { +public: + virtual ~Renderer() = default; + virtual SDL_Texture* createTextureFromSurface(SDL_Surface* surf) = 0; + virtual void destroyTexture(SDL_Texture* tex) = 0; + virtual void copy(SDL_Texture* tex, const SDL_Rect* src, const SDL_Rect* dst) = 0; + virtual void renderTexture(SDL_Texture* tex, const SDL_FRect* src, const SDL_FRect* dst) = 0; + virtual void setTextureAlphaMod(SDL_Texture* tex, Uint8 a) = 0; + virtual void renderLine(float x1, float y1, float x2, float y2) = 0; + virtual void clear(const SDL_Color& color) = 0; + virtual void setDrawColor(const SDL_Color& color) = 0; + virtual void fillRectF(const SDL_FRect* rect) = 0; + virtual void drawRectF(const SDL_FRect* rect) = 0; + virtual void present() = 0; +}; + +std::unique_ptr MakeSDLRenderer(SDL_Renderer* rdr); + +} // namespace renderer diff --git a/src/renderer/SDLRenderer.cpp b/src/renderer/SDLRenderer.cpp index e66e199..accd957 100644 --- a/src/renderer/SDLRenderer.cpp +++ b/src/renderer/SDLRenderer.cpp @@ -1,4 +1,4 @@ -#include "Renderer.h" +#include "Renderer_iface.h" #include namespace renderer { @@ -16,11 +16,25 @@ public: void destroyTexture(SDL_Texture* tex) override { if (tex) SDL_DestroyTexture(tex); } - void copy(SDL_Texture* tex, const SDL_Rect* src, const SDL_Rect* dst) override { if (!rdr_ || !tex) return; - // SDL_RenderCopy mapping differs across SDL versions; defer to existing renderers - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "SDLRenderer::copy called — fallback no-op (use RenderManager for real draws)"); + // Convert integer rects to float rects and call SDL_RenderTexture (SDL3 API) + SDL_FRect fs{}; SDL_FRect fd{}; + const SDL_FRect* ps = nullptr; + const SDL_FRect* pd = nullptr; + if (src) { fs.x = static_cast(src->x); fs.y = static_cast(src->y); fs.w = static_cast(src->w); fs.h = static_cast(src->h); ps = &fs; } + if (dst) { fd.x = static_cast(dst->x); fd.y = static_cast(dst->y); fd.w = static_cast(dst->w); fd.h = static_cast(dst->h); pd = &fd; } + SDL_RenderTexture(rdr_, tex, ps, pd); + } + + void renderTexture(SDL_Texture* tex, const SDL_FRect* src, const SDL_FRect* dst) override { + if (!rdr_ || !tex) return; + SDL_RenderTexture(rdr_, tex, src, dst); + } + + void setTextureAlphaMod(SDL_Texture* tex, Uint8 a) override { + if (!tex) return; + SDL_SetTextureAlphaMod(tex, a); } void clear(const SDL_Color& color) override { @@ -29,6 +43,26 @@ public: SDL_RenderClear(rdr_); } + void setDrawColor(const SDL_Color& color) override { + if (!rdr_) return; + SDL_SetRenderDrawColor(rdr_, color.r, color.g, color.b, color.a); + } + + void fillRectF(const SDL_FRect* rect) override { + if (!rdr_ || !rect) return; + SDL_RenderFillRect(rdr_, rect); + } + + void drawRectF(const SDL_FRect* rect) override { + if (!rdr_ || !rect) return; + SDL_RenderRect(rdr_, rect); + } + + void renderLine(float x1, float y1, float x2, float y2) override { + if (!rdr_) return; + SDL_RenderLine(rdr_, x1, y1, x2, y2); + } + void present() override { if (!rdr_) return; SDL_RenderPresent(rdr_);