diff --git a/src/graphics/GameRenderer.cpp b/src/graphics/GameRenderer.cpp index fd27828..960d663 100644 --- a/src/graphics/GameRenderer.cpp +++ b/src/graphics/GameRenderer.cpp @@ -116,6 +116,79 @@ void GameRenderer::drawSmallPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex } } +// Draw the hold panel (extracted for readability). +static void drawHoldPanel(SDL_Renderer* renderer, + Game* game, + FontAtlas* pixelFont, + SDL_Texture* blocksTex, + SDL_Texture* holdPanelTex, + float scoreX, + float statsW, + float gridY, + float finalBlockSize, + float statsY, + float statsH) { + float holdBlockH = (finalBlockSize * 0.6f) * 4.0f; + // Base panel height; enforce minimum but allow larger to fit texture + float panelH = std::max(holdBlockH + 12.0f, 420.0f); + // Increase height by ~20% of the hold block to give more vertical room + float extraH = holdBlockH * 0.20f; + panelH += extraH; + + const float holdGap = 18.0f; + + // Align X to the bottom score label (`scoreX`) plus an offset to the right + float panelX = scoreX + 30.0f; // move ~30px right to align with score label + float panelW = statsW + 32.0f; + float panelY = gridY - panelH - holdGap; + // Move panel a bit higher for spacing (about half the extra height) + panelY -= extraH * 0.5f; + float labelX = panelX + 40.0f; // shift HOLD label ~30px to the right + float labelY = panelY + 8.0f; + + if (holdPanelTex) { + int texW = 0, texH = 0; + SDL_QueryTexture(holdPanelTex, nullptr, nullptr, &texW, &texH); + if (texW > 0 && texH > 0) { + // Fill panel width and compute destination height from texture aspect ratio + float texAspect = float(texH) / float(texW); + float dstW = panelW; + float dstH = dstW * texAspect; + // If texture height exceeds panel, expand panelH to fit texture comfortably + if (dstH + 12.0f > panelH) { + panelH = dstH + 12.0f; + panelY = gridY - panelH - holdGap; + labelY = panelY + 8.0f; + } + float dstX = panelX; + float dstY = panelY + (panelH - dstH) * 0.5f; + + SDL_FRect panelDst{dstX, dstY, dstW, dstH}; + SDL_SetTextureBlendMode(holdPanelTex, SDL_BLENDMODE_BLEND); + SDL_SetTextureScaleMode(holdPanelTex, SDL_SCALEMODE_LINEAR); + SDL_RenderTexture(renderer, holdPanelTex, nullptr, &panelDst); + } else { + // Fallback to filling panel area if texture metrics unavailable + SDL_SetRenderDrawColor(renderer, 12, 18, 32, 220); + SDL_FRect panelDst{panelX, panelY, panelW, panelH}; + SDL_RenderFillRect(renderer, &panelDst); + } + } else { + SDL_SetRenderDrawColor(renderer, 12, 18, 32, 220); + SDL_FRect panelDst{panelX, panelY, panelW, panelH}; + SDL_RenderFillRect(renderer, &panelDst); + } + + pixelFont->draw(renderer, labelX, labelY, "HOLD", 1.0f, {255, 220, 0, 255}); + + if (game->held().type < PIECE_COUNT) { + float previewW = finalBlockSize * 0.6f * 4.0f; + float previewX = panelX + (panelW - previewW) * 0.5f; + float previewY = panelY + (panelH - holdBlockH) * 0.5f; + drawSmallPiece(renderer, blocksTex, static_cast(game->held().type), previewX, previewY, finalBlockSize * 0.6f); + } +} + void GameRenderer::renderPlayingState( SDL_Renderer* renderer, Game* game, @@ -165,64 +238,8 @@ void GameRenderer::renderPlayingState( const float availableHeight = logicalH - TOP_MARGIN - BOTTOM_MARGIN - NEXT_PIECE_HEIGHT; const float maxBlockSizeW = availableWidth / Game::COLS; - const float maxBlockSizeH = availableHeight / Game::ROWS; - float previewY = rowTop - 4.0f; - const float finalBlockSize = std::max(20.0f, std::min(BLOCK_SIZE, 40.0f)); - - const float GRID_W = Game::COLS * finalBlockSize; - const float GRID_H = Game::ROWS * finalBlockSize; - - // Calculate positions - const float totalContentHeight = NEXT_PIECE_HEIGHT + GRID_H; - const float availableVerticalSpace = logicalH - TOP_MARGIN - BOTTOM_MARGIN; - const float verticalCenterOffset = (availableVerticalSpace - totalContentHeight) * 0.5f; - const float contentStartY = TOP_MARGIN + verticalCenterOffset; - - const float totalLayoutWidth = PANEL_WIDTH + PANEL_SPACING + GRID_W + PANEL_SPACING + PANEL_WIDTH; - const float layoutStartX = (logicalW - totalLayoutWidth) * 0.5f; - float barY = previewY + previewSize + 10.0f; - const float statsX = layoutStartX + contentOffsetX; - const float gridX = layoutStartX + PANEL_WIDTH + PANEL_SPACING + contentOffsetX; - const float scoreX = layoutStartX + PANEL_WIDTH + PANEL_SPACING + GRID_W + PANEL_SPACING + contentOffsetX; - float rowBottom = percY + 14.0f; - SDL_FRect rowBg{ - previewX - 10.0f, - rowTop - 8.0f, - rowWidth + 20.0f, - rowBottom - rowTop - }; - const float nextW = finalBlockSize * 4 + 20; - const float nextH = finalBlockSize * 2 + 20; - const float nextX = gridX + (GRID_W - nextW) * 0.5f; - const float nextY = contentStartY + contentOffsetY; - - // Handle line clearing effects - if (game->hasCompletedLines() && lineEffect && !lineEffect->isActive()) { - auto completedLines = game->getCompletedLines(); - lineEffect->startLineClear(completedLines, static_cast(gridX), static_cast(gridY), static_cast(finalBlockSize)); - } - - // Draw styled game grid border and semi-transparent background so the scene shows through. - SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); - - // Outer glow layers (subtle, increasing spread, decreasing alpha) - drawRectWithOffset(gridX - 8 - contentOffsetX, gridY - 8 - contentOffsetY, GRID_W + 16, GRID_H + 16, {100, 120, 200, 28}); - drawRectWithOffset(gridX - 6 - contentOffsetX, gridY - 6 - contentOffsetY, GRID_W + 12, GRID_H + 12, {100, 120, 200, 40}); - - // Accent border (brighter, thin) - drawRectWithOffset(gridX - 3 - contentOffsetX, gridY - 3 - contentOffsetY, GRID_W + 6, GRID_H + 6, {100, 120, 200, 220}); - drawRectWithOffset(gridX - 1 - contentOffsetX, gridY - 1 - contentOffsetY, GRID_W + 2, GRID_H + 2, {60, 80, 160, 200}); - - // Do NOT fill the interior of the grid so the background shows through. - // (Intentionally leave the playfield interior transparent.) - - // Draw panel backgrounds - SDL_SetRenderDrawColor(renderer, 10, 15, 25, 160); - SDL_FRect lbg{statsX - 16, gridY - 10, statsW + 32, GRID_H + 20}; - SDL_RenderFillRect(renderer, &lbg); - - SDL_FRect rbg{scoreX - 16, gridY - 16, statsW + 32, GRID_H + 32}; - SDL_RenderFillRect(renderer, &rbg); + // Draw hold panel via helper + drawHoldPanel(renderer, game, pixelFont, blocksTex, holdPanelTex, scoreX, statsW, gridY, finalBlockSize, statsY, statsH); // Draw grid lines (solid so grid remains legible over background) SDL_SetRenderDrawColor(renderer, 40, 45, 60, 255); @@ -529,7 +546,7 @@ void GameRenderer::renderPlayingState( SDL_RenderFillRect(renderer, &panelDst); } - pixelFont->draw(renderer, labelX, labelY, "HOLDx", 1.0f, {255, 220, 0, 255}); + pixelFont->draw(renderer, labelX, labelY, "HOLD", 1.0f, {255, 220, 0, 255}); if (game->held().type < PIECE_COUNT) { float previewW = finalBlockSize * 0.6f * 4.0f;