diff --git a/src/graphics/GameRenderer.cpp b/src/graphics/GameRenderer.cpp index 960d663..fcac0a9 100644 --- a/src/graphics/GameRenderer.cpp +++ b/src/graphics/GameRenderer.cpp @@ -189,6 +189,96 @@ static void drawHoldPanel(SDL_Renderer* renderer, } } +// Draw next piece panel (border/texture + preview) +static void drawNextPanel(SDL_Renderer* renderer, + FontAtlas* pixelFont, + SDL_Texture* nextPanelTex, + SDL_Texture* blocksTex, + Game* game, + float nextX, + float nextY, + float nextW, + float nextH, + float contentOffsetX, + float contentOffsetY, + float finalBlockSize) { + if (nextPanelTex) { + SDL_FRect dst{ nextX - contentOffsetX, nextY - contentOffsetY, nextW, nextH }; + SDL_SetTextureBlendMode(nextPanelTex, SDL_BLENDMODE_BLEND); + SDL_RenderTexture(renderer, nextPanelTex, nullptr, &dst); + } else { + // Draw bordered panel as before + SDL_SetRenderDrawColor(renderer, 100, 120, 200, 255); + SDL_FRect outer{ nextX - 3 - contentOffsetX, nextY - 3 - contentOffsetY, nextW + 6, nextH + 6 }; + SDL_RenderFillRect(renderer, &outer); + SDL_SetRenderDrawColor(renderer, 30, 35, 50, 255); + SDL_FRect inner{ nextX - contentOffsetX, nextY - contentOffsetY, nextW, nextH }; + SDL_RenderFillRect(renderer, &inner); + } + + // Label and small preview + pixelFont->draw(renderer, nextX + 10, nextY - 20, "NEXT", 1.0f, {255, 220, 0, 255}); + if (game->next().type < PIECE_COUNT) { + drawSmallPiece(renderer, blocksTex, static_cast(game->next().type), nextX + 10, nextY + 5, finalBlockSize * 0.6f); + } +} + +// Draw score panel (right side) +static void drawScorePanel(SDL_Renderer* renderer, + FontAtlas* pixelFont, + Game* game, + float scoreX, + float gridY, + float GRID_H, + float finalBlockSize) { + const float contentTopOffset = 0.0f; + const float contentBottomOffset = 290.0f; + const float contentPad = 36.0f; + float scoreContentH = (contentBottomOffset - contentTopOffset) + contentPad; + float baseY = gridY + (GRID_H - scoreContentH) * 0.5f; + + pixelFont->draw(renderer, scoreX, baseY + 0, "SCORE", 1.0f, {255, 220, 0, 255}); + char scoreStr[32]; + snprintf(scoreStr, sizeof(scoreStr), "%d", game->score()); + pixelFont->draw(renderer, scoreX, baseY + 25, scoreStr, 0.9f, {255, 255, 255, 255}); + + pixelFont->draw(renderer, scoreX, baseY + 70, "LINES", 1.0f, {255, 220, 0, 255}); + char linesStr[16]; + snprintf(linesStr, sizeof(linesStr), "%03d", game->lines()); + pixelFont->draw(renderer, scoreX, baseY + 95, linesStr, 0.9f, {255, 255, 255, 255}); + + pixelFont->draw(renderer, scoreX, baseY + 140, "LEVEL", 1.0f, {255, 220, 0, 255}); + char levelStr[16]; + snprintf(levelStr, sizeof(levelStr), "%02d", game->level()); + pixelFont->draw(renderer, scoreX, baseY + 165, levelStr, 0.9f, {255, 255, 255, 255}); + + // Next level progress + int startLv = game->startLevelBase(); + int firstThreshold = (startLv + 1) * 10; + int linesDone = game->lines(); + int nextThreshold = 0; + if (linesDone < firstThreshold) { + nextThreshold = firstThreshold; + } else { + int blocksPast = linesDone - firstThreshold; + nextThreshold = firstThreshold + ((blocksPast / 10) + 1) * 10; + } + int linesForNext = std::max(0, nextThreshold - linesDone); + pixelFont->draw(renderer, scoreX, baseY + 200, "NEXT LVL", 1.0f, {255, 220, 0, 255}); + char nextStr[32]; + snprintf(nextStr, sizeof(nextStr), "%d LINES", linesForNext); + pixelFont->draw(renderer, scoreX, baseY + 225, nextStr, 0.9f, {80, 255, 120, 255}); + + // Time display + pixelFont->draw(renderer, scoreX, baseY + 265, "TIME", 1.0f, {255, 220, 0, 255}); + int totalSecs = static_cast(game->elapsed()); + int mins = totalSecs / 60; + int secs = totalSecs % 60; + char timeStr[16]; + snprintf(timeStr, sizeof(timeStr), "%02d:%02d", mins, secs); + pixelFont->draw(renderer, scoreX, baseY + 290, timeStr, 0.9f, {255, 255, 255, 255}); +} + void GameRenderer::renderPlayingState( SDL_Renderer* renderer, Game* game, @@ -262,18 +352,9 @@ void GameRenderer::renderPlayingState( drawRectWithOffset(statsX - 3 - contentOffsetX, statsY - 3 - contentOffsetY, statsW + 6, statsH + 6, {100, 120, 200, 255}); drawRectWithOffset(statsX - contentOffsetX, statsY - contentOffsetY, statsW, statsH, {30, 35, 50, 255}); - // Draw next piece preview panel border - // If a NEXT panel texture was provided, draw it instead of the custom - // background/outline. The texture will be scaled to fit the panel area. - if (nextPanelTex) { - SDL_FRect dst{ nextX - contentOffsetX, nextY - contentOffsetY, nextW, nextH }; - SDL_SetTextureBlendMode(nextPanelTex, SDL_BLENDMODE_BLEND); - SDL_RenderTexture(renderer, nextPanelTex, nullptr, &dst); - } else { - drawRectWithOffset(nextX - 3 - contentOffsetX, nextY - 3 - contentOffsetY, nextW + 6, nextH + 6, {100, 120, 200, 255}); - drawRectWithOffset(nextX - contentOffsetX, nextY - contentOffsetY, nextW, nextH, {30, 35, 50, 255}); - } - + // Draw next piece panel + drawNextPanel(renderer, pixelFont, nextPanelTex, blocksTex, game, nextX, nextY, nextW, nextH, contentOffsetX, contentOffsetY, finalBlockSize); + // Draw the game board const auto &board = game->boardRef(); for (int y = 0; y < Game::ROWS; ++y) { @@ -429,53 +510,8 @@ void GameRenderer::renderPlayingState( yCursor = rowBottom + rowSpacing; } - // Draw score panel (right side) - const float contentTopOffset = 0.0f; - const float contentBottomOffset = 290.0f; - const float contentPad = 36.0f; - float scoreContentH = (contentBottomOffset - contentTopOffset) + contentPad; - float baseY = gridY + (GRID_H - scoreContentH) * 0.5f; - - pixelFont->draw(renderer, scoreX, baseY + 0, "SCORE", 1.0f, {255, 220, 0, 255}); - char scoreStr[32]; - snprintf(scoreStr, sizeof(scoreStr), "%d", game->score()); - pixelFont->draw(renderer, scoreX, baseY + 25, scoreStr, 0.9f, {255, 255, 255, 255}); - - pixelFont->draw(renderer, scoreX, baseY + 70, "LINES", 1.0f, {255, 220, 0, 255}); - char linesStr[16]; - snprintf(linesStr, sizeof(linesStr), "%03d", game->lines()); - pixelFont->draw(renderer, scoreX, baseY + 95, linesStr, 0.9f, {255, 255, 255, 255}); - - pixelFont->draw(renderer, scoreX, baseY + 140, "LEVEL", 1.0f, {255, 220, 0, 255}); - char levelStr[16]; - snprintf(levelStr, sizeof(levelStr), "%02d", game->level()); - pixelFont->draw(renderer, scoreX, baseY + 165, levelStr, 0.9f, {255, 255, 255, 255}); - - // Next level progress - int startLv = game->startLevelBase(); - int firstThreshold = (startLv + 1) * 10; - int linesDone = game->lines(); - int nextThreshold = 0; - if (linesDone < firstThreshold) { - nextThreshold = firstThreshold; - } else { - int blocksPast = linesDone - firstThreshold; - nextThreshold = firstThreshold + ((blocksPast / 10) + 1) * 10; - } - int linesForNext = std::max(0, nextThreshold - linesDone); - pixelFont->draw(renderer, scoreX, baseY + 200, "NEXT LVL", 1.0f, {255, 220, 0, 255}); - char nextStr[32]; - snprintf(nextStr, sizeof(nextStr), "%d LINES", linesForNext); - pixelFont->draw(renderer, scoreX, baseY + 225, nextStr, 0.9f, {80, 255, 120, 255}); - - // Time display - pixelFont->draw(renderer, scoreX, baseY + 265, "TIME", 1.0f, {255, 220, 0, 255}); - int totalSecs = static_cast(game->elapsed()); - int mins = totalSecs / 60; - int secs = totalSecs % 60; - char timeStr[16]; - snprintf(timeStr, sizeof(timeStr), "%02d:%02d", mins, secs); - pixelFont->draw(renderer, scoreX, baseY + 290, timeStr, 0.9f, {255, 255, 255, 255}); + // Draw score panel + drawScorePanel(renderer, pixelFont, game, scoreX, gridY, GRID_H, finalBlockSize); // Gravity HUD char gms[64];