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.
This commit is contained in:
2025-12-25 17:26:55 +01:00
parent 17cb64c9d4
commit 03bdc82dc1
4 changed files with 141 additions and 55 deletions

View File

@ -1,4 +1,5 @@
#include "GameRenderer.h"
#include "../../renderer/Renderer_iface.h"
#include "SyncLineRenderer.h"
#include "../../gameplay/core/Game.h"
@ -248,9 +249,11 @@ static void updateAndDrawTransport(SDL_Renderer* renderer, SDL_Texture* blocksTe
Uint8 gridAlpha = static_cast<Uint8>(std::lround(255.0f * t));
Uint8 nextAlpha = gridAlpha; // fade new NEXT preview in at same rate as grid
// Create renderer wrapper
auto rwrap = renderer::MakeSDLRenderer(renderer);
// Draw preview fade-out
if (previewAlpha > 0) {
if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, previewAlpha);
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;
@ -259,12 +262,12 @@ static void updateAndDrawTransport(SDL_Renderer* renderer, SDL_Texture* blocksTe
GameRenderer::drawBlockTexturePublic(renderer, blocksTex, px, py, s_transport.tileSize, s_transport.piece.type);
}
}
if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, 255);
if (blocksTex) rwrap->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<int>(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<Uint8>(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) {

View File

@ -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;
};

View File

@ -0,0 +1,27 @@
// Clean renderer interface for local use
#pragma once
#include <memory>
#include <SDL3/SDL.h>
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<Renderer> MakeSDLRenderer(SDL_Renderer* rdr);
} // namespace renderer

View File

@ -1,4 +1,4 @@
#include "Renderer.h"
#include "Renderer_iface.h"
#include <SDL3/SDL.h>
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<float>(src->x); fs.y = static_cast<float>(src->y); fs.w = static_cast<float>(src->w); fs.h = static_cast<float>(src->h); ps = &fs; }
if (dst) { fd.x = static_cast<float>(dst->x); fd.y = static_cast<float>(dst->y); fd.w = static_cast<float>(dst->w); fd.h = static_cast<float>(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_);