void GameBoardScreen::Draw()

in ID@XboxSDK/GameSaveCppWinRT/Xbox/GameLogic/GameBoardScreen.cpp [705:994]


void GameBoardScreen::Draw(float totalTime, float elapsedTime)
{
    auto spriteBatch = Manager()->GetSpriteBatch();
    auto gameFont = Manager()->GetSpriteFont();
    auto blendStates = Manager()->GetCommonStates();
    auto scaleMatrix = DX::GetScaleMatrixForWindow(Manager()->GetWindowBounds());

    // Draw background
    spriteBatch->Begin(SpriteSortMode_Deferred, blendStates->NonPremultiplied(), nullptr, nullptr, nullptr, nullptr, scaleMatrix);
    spriteBatch->Draw(m_background->GetResourceViewTemporary(), XMFLOAT2(0, 0));
    spriteBatch->End();

    if (IsActive() && m_isGameSaveManagerInitialized)
    {
        MenuScreen::Draw(totalTime, elapsedTime);
    }

    if (m_state != ScreenState::Active)
    {
        return;
    }

    GameSaveManager &gameSaveManager = Game->GameSaveManager;
    assert(gameSaveManager.HasActiveBoard());

    std::lock_guard<std::mutex> lock(gameSaveManager.ActiveBoardGameSave()->m_mutex);

    auto activeBoardNum = gameSaveManager.ActiveBoardNumber();
    auto activeBoard = gameSaveManager.ActiveBoard();
    auto activeBoardGameSave = gameSaveManager.ActiveBoardGameSave();
    auto activeBoardMetadata = activeBoardGameSave->m_containerMetadata;

    spriteBatch->Begin(SpriteSortMode_Deferred, blendStates->NonPremultiplied(), nullptr, nullptr, nullptr, nullptr, scaleMatrix);

    // Draw numbers of the visible game boards and highlight the active one
    XMFLOAT2 position = c_saveSlotFirstNumber_TopCenter;
    XMFLOAT2 origin = XMFLOAT2(m_saveSlotNumbers[0]->Width() / 2.0f, 0.0f);

    for (auto i = m_firstSlotToDisplay; i < m_firstSlotToDisplay + 3; ++i)
    {
        if (i == m_firstSlotToDisplay + 2)
            position.x -= 10; // UI correction: 3rd board number is not the same distance from the 2nd as the 2nd is from the 1st

        if (i == activeBoardNum)
        {
            spriteBatch->Draw(m_saveSlotActiveNumbers[i - 1]->GetResourceViewTemporary(), position, nullptr, Colors::White, 0.0f, origin);
        }
        else
        {
            spriteBatch->Draw(m_saveSlotNumbers[i - 1]->GetResourceViewTemporary(), position, nullptr, Colors::White, 0.0f, origin);
        }

        position.x += c_saveSlotNumber_PixelsBetweenCenters;
    }

    // Draw active board title and dirty status
	wchar_t gameBoardTitleStr[100];
    if (activeBoardNum > 0)
    {
		swprintf_s(gameBoardTitleStr, L"WordGame Board %i", activeBoardNum);
    }
    if (gameSaveManager.IsActiveBoardDirty())
    {
		swprintf_s(gameBoardTitleStr, L"WordGame Board*");
    }
    m_gameBoardTitleFont->DrawString(spriteBatch.get(), gameBoardTitleStr, c_gameTitle_UpperLeft);

    // Draw player name
	wchar_t userDisplayStr[100];
	swprintf_s(userDisplayStr, L"User: %s", Game->LiveResources->GetGamertag().c_str());
    m_gameBoardMetadataFont->DrawString(spriteBatch.get(), userDisplayStr, c_playerName_UpperLeft, Colors::White, 0.0f, XMFLOAT2(0, 0), c_playerName_Scale);

    // Draw active board metadata (last save date, current user gamertag)
    std::wstring gameBoardMetadataDisplay;
    if (activeBoardMetadata->m_isGameDataOnDisk)
    {
        gameBoardMetadataDisplay.append(activeBoardGameSave->m_isGameDataLoaded ? L"BOARD LOADED" : L"BOARD NOT LOADED");

        if (activeBoardMetadata->m_needsSync)
        {
            gameBoardMetadataDisplay.append(L"  (NEEDS SYNC)");
        }

		gameBoardMetadataDisplay.append(L"  (Last Modified: ");
		gameBoardMetadataDisplay.append(FormatLocalTimeFromDateTime(activeBoardMetadata->m_lastModified));
		gameBoardMetadataDisplay.append(L")");
    }
    else
    {
        if (gameSaveManager.IsActiveBoardDirty())
        {
            gameBoardMetadataDisplay.append(L"BOARD NOT SAVED");
        }
        else
        {
            gameBoardMetadataDisplay.append(L"BOARD NOT STARTED");
        }
    }
    m_gameBoardMetadataFont->DrawString(spriteBatch.get(), gameBoardMetadataDisplay.c_str(), c_gameSaveMetadata_UpperLeft, Colors::White, 0.0f, XMFLOAT2(0, 0), c_gameSaveMetadata_Scale);

    // Draw active board dev metadata (sync status/mode)
    if (m_isGameSaveManagerInitialized)
    {
        std::wstring devModeMetadata = L"Sync Mode: ";
        if (gameSaveManager.IsSyncOnDemand())
        {
            devModeMetadata.append(L"Sync-On-Demand");
        }
        else
        {
            devModeMetadata.append(L"Full Sync");
        }
		devModeMetadata.append(L"     Remaining Quota: ");
		wchar_t remainingQuotaInBytes[20];
		_i64tow_s(gameSaveManager.RemainingQuotaInBytes(), remainingQuotaInBytes, _countof(remainingQuotaInBytes), 10);
		devModeMetadata.append(remainingQuotaInBytes);
		devModeMetadata.append(L" bytes");
        m_gameBoardMetadataFont->DrawString(spriteBatch.get(), devModeMetadata.c_str(), c_gameSaveAdditionalMetadata_UpperLeft, Colors::White, 0.0f, XMFLOAT2(0, 0), c_gameSaveMetadata_Scale);
    }
    else
    {
        m_gameBoardMetadataFont->DrawString(spriteBatch.get(), L"Sync Status: Not Initialized", c_gameSaveAdditionalMetadata_UpperLeft);
    }

    // Draw current score
    auto scoreColor = m_isOverLimitOnLetters ? Colors::Red : Colors::White;
	wchar_t scoreBuffer[20];
	_itow_s(m_score, scoreBuffer, 10);
    gameFont->DrawString(spriteBatch.get(), scoreBuffer, c_currentScore_UpperLeft, scoreColor, 0.0f, XMFLOAT2(0, 0), c_currentScore_Scale);
    m_gameBoardMetadataFont->DrawString(spriteBatch.get(), L"SCORE", c_currentScoreLabel_UpperLeft);

    // Draw remaining letters count
    if (m_lettersRemaining.size() >= 26)
    {
        XMFLOAT2 letterPosition = c_lettersRemaining_UpperLeft;
        for (wchar_t letter = L'A'; letter <= L'Z'; ++letter)
        {
            auto letterIndex = letter - L'A';
			auto lettersRemaining = m_lettersRemaining[letterIndex];
			wchar_t countStr[30];
			swprintf_s(countStr, L"%c=%i(%i)", letter, m_lettersRemaining[letterIndex], c_letterValues[letterIndex]);
            auto countColor = c_lettersRemaining_Color;
            if (lettersRemaining < 0)
            {
                countColor = Colors::Red;
            }
            else if (lettersRemaining == 0)
            {
                countColor = Colors::Yellow;
            }
            m_gameBoardLettersRemainingFont->DrawString(spriteBatch.get(), countStr, letterPosition, countColor, 0.0f, XMFLOAT2(0, 0), c_lettersRemaining_Scale);

            // Get next letter position
            if ((letterIndex + 1) % 9 == 0)
            {
                letterPosition.x = c_lettersRemaining_UpperLeft.x;
                letterPosition.y += c_lettersRemaining_LetterOffset.y;
            }
            else
            {
                letterPosition.x += c_lettersRemaining_LetterOffset.x;
            }
        }
    }

    // Draw help text for remaining letters section
    winrt::hstring lettersRemainingHelp = L"Letter = X pts (# remaining)";
    XMFLOAT2 lettersRemainingHelpPosition = c_lettersRemainingHelp_Center;
    auto lettersRemainingHelpSize = m_gameBoardLettersRemainingFont->MeasureString(lettersRemainingHelp.c_str());
    XMFLOAT2 lettersRemainingHelpOrigin = XMFLOAT2(XMVectorGetX(lettersRemainingHelpSize) / 2.0f, m_gameBoardLettersRemainingFont->GetLineSpacing() / 2.0f);
    m_gameBoardLettersRemainingFont->DrawString(spriteBatch.get(), lettersRemainingHelp.c_str(), c_lettersRemainingHelp_Center, c_lettersRemaining_Color, 0.0f, lettersRemainingHelpOrigin);

    // Draw tile cursor
    if (!m_menuActive)
    {
        XMFLOAT2 cursorCenter = XMFLOAT2(c_letterTileFirstTile_Center.x + (c_letterTile_CenterOffset.x * m_cursorPosition.x), c_letterTileFirstTile_Center.y + (c_letterTile_CenterOffset.y * m_cursorPosition.y));
        spriteBatch->Draw(m_cursor->GetResourceViewTemporary(), cursorCenter, nullptr, Colors::White, 0.0f, XMFLOAT2(float(m_cursor->Width() / 2), float(m_cursor->Height() / 2)));
    }

    // Draw placed letters
    for (uint32_t j = 0; j < activeBoard.m_boardHeight; ++j)
    {
        for (uint32_t i = 0; i < activeBoard.m_boardWidth; ++i)
        {
            XMFLOAT2 tileCenter = XMFLOAT2(c_letterTileFirstTile_Center.x + (c_letterTile_CenterOffset.x * i), c_letterTileFirstTile_Center.y + (c_letterTile_CenterOffset.y * j));
            auto currentTile = activeBoard.GetGameTile(XMUINT2(i, j));

            if (currentTile.m_placed)
            {
                if (currentTile.m_letter)
                {
                    // draw letter (centered on tile)
					wchar_t letter[2] = { currentTile.m_letter, L'\0' };
                    XMVECTOR letterSize = m_gameBoardTileFont->MeasureString(letter);
                    XMFLOAT2 letterOrigin = XMFLOAT2(XMVectorGetX(letterSize) / 2.0f + 6.0f, XMVectorGetY(letterSize) / 2.0f);
                    if (letter[0] == L'Q')
                    {
                        letterOrigin.x += 2.0f; // correct some display issues
                    }
                    m_gameBoardTileFont->DrawString(spriteBatch.get(), letter, tileCenter, Colors::Pink, 0.0f, letterOrigin, 0.75f);

                    // draw letter value (top-left-justified, offset from tile center)
					wchar_t letterValue[10];
					_itow_s(c_letterValues[letter[0] - L'A'], letterValue, 10);
                    XMFLOAT2 letterValuePosition = XMFLOAT2(tileCenter.x + c_letterTileValue_OffsetFromTileCenter.x, tileCenter.y + c_letterTileValue_OffsetFromTileCenter.y);
                    XMVECTOR letterValueSize = m_gameBoardTileValueFont->MeasureString(letterValue);
                    float letterValueScale = 0.45f;
                    m_gameBoardTileValueFont->DrawString(spriteBatch.get(), letterValue, letterValuePosition, Colors::Yellow, 0.0f, XMFLOAT2(0, 0), letterValueScale);
                }
                else
                {
                    // draw the non-alphabetic texture
                }
            }

            // draw word arrows
            auto trackerTile = GetWordTrackerTile(XMUINT2(i, j));
            if (trackerTile.m_wordRight)
            {
                XMFLOAT2 horizontalWordLinkerCenter = XMFLOAT2(c_wordLinkFirstHorizontal_Center.x + (c_letterTile_CenterOffset.x * i), c_wordLinkFirstHorizontal_Center.y + (c_letterTile_CenterOffset.y * j));
                spriteBatch->Draw(m_hortizontalWordLinker->GetResourceViewTemporary(), horizontalWordLinkerCenter, nullptr, Colors::White, 0.0f, XMFLOAT2(float(m_hortizontalWordLinker->Width() / 2), float(m_hortizontalWordLinker->Height() / 2)));
            }
            if (trackerTile.m_wordDown)
            {
                XMFLOAT2 verticalWordLinkerCenter = XMFLOAT2(c_wordLinkFirstVertical_Center.x + (c_letterTile_CenterOffset.x * i), c_wordLinkFirstVertical_Center.y + (c_letterTile_CenterOffset.y * j));
                spriteBatch->Draw(m_verticalWordLinker->GetResourceViewTemporary(), verticalWordLinkerCenter, nullptr, Colors::White, 0.0f, XMFLOAT2(float(m_verticalWordLinker->Width() / 2), float(m_verticalWordLinker->Height() / 2)));
            }
        }
    }

    // Draw input control help
    bool displayGamepadControls = true;

    // Draw game debug log
    auto logPosition = XMFLOAT2(c_debugLog_Region.X, c_debugLog_Region.Y);
    size_t maxDisplayLines = static_cast<size_t>(c_debugLog_Region.Height / m_logFontHeight);
    auto logIndexSize = Log::g_displayLog.size();
    auto logIndexBegin = size_t(0);
    auto logIndexEnd = logIndexSize - 1;

    if (m_logLineBegin > 0)
    {
        // no auto-scrolling, display starting at requested line number
        logIndexBegin = m_logLineBegin - 1;
        logIndexEnd = std::min(logIndexEnd, logIndexBegin + maxDisplayLines - 1);
    }
    else if (logIndexSize > maxDisplayLines)
    {
        // auto-scroll
        logIndexBegin = logIndexSize - maxDisplayLines;
    }

    for (auto i = logIndexBegin; i <= logIndexEnd; ++i)
    {
        m_logFont->DrawString(spriteBatch.get(), Log::g_displayLog[i].c_str(), logPosition);
        logPosition.y += m_logFontHeight;
    }

    // Draw scroll indicators
    if (logIndexBegin > 0)
    {
        if (displayGamepadControls)
        {
            spriteBatch->Draw(m_logScrollUpControl->GetResourceViewTemporary(), c_debugLogScrollUpIcon_Center, nullptr, Colors::White, 0.0f, XMFLOAT2(float(m_logScrollUpControl->Width() / 2), float(m_logScrollUpControl->Height() / 2)));
        }
        else
        {
            wchar_t logScrollUpKeyString[] = L"PgUp";
            XMVECTOR logScrollUpKeySize = m_gameBoardControlsHelpFont->MeasureString(logScrollUpKeyString);
            XMFLOAT2 logScrollUpKeyOrigin = XMFLOAT2(XMVectorGetX(logScrollUpKeySize) / 2.f, m_gameBoardControlsHelpFont->GetLineSpacing() / 2.f);
            m_gameBoardControlsHelpFont->DrawString(spriteBatch.get(), logScrollUpKeyString, c_debugLogScrollUpIcon_Center, Colors::SandyBrown, 0.0f, logScrollUpKeyOrigin, c_inputControlsHelp_Scale);
        }
    }
    if (m_logLineBegin > 0)
    {
        if (displayGamepadControls)
        {
            spriteBatch->Draw(m_logScrollDownControl->GetResourceViewTemporary(), c_debugLogScrollDownIcon_Center, nullptr, Colors::White, 0.0f, XMFLOAT2(float(m_logScrollDownControl->Width() / 2), float(m_logScrollDownControl->Height() / 2)));
        }
        else
        {
            wchar_t logScrollDownKeyString[] = L"PgDn";
            XMVECTOR logScrollDownKeySize = m_gameBoardControlsHelpFont->MeasureString(logScrollDownKeyString);
            XMFLOAT2 logScrollDownKeyOrigin = XMFLOAT2(XMVectorGetX(logScrollDownKeySize) / 2.f, m_gameBoardControlsHelpFont->GetLineSpacing() / 2.f);
            m_gameBoardControlsHelpFont->DrawString(spriteBatch.get(), logScrollDownKeyString, c_debugLogScrollDownIcon_Center, Colors::SandyBrown, 0.0f, logScrollDownKeyOrigin, c_inputControlsHelp_Scale);
        }
    }

    spriteBatch->End();
}