|
|
|
@@ -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) {
|
|
|
|
|