#include #include namespace XCEngine { namespace UI { namespace Runtime { namespace { std::size_t FindTopInputLayerIndex( const std::vector& layerOptions, std::size_t lowestPresentedIndex) { if (layerOptions.empty() || lowestPresentedIndex >= layerOptions.size()) { return static_cast(-1); } for (std::size_t index = layerOptions.size(); index-- > lowestPresentedIndex;) { if (layerOptions[index].visible && layerOptions[index].acceptsInput) { return index; } } return static_cast(-1); } std::size_t FindLowestPresentedLayerIndex(const std::vector& layerOptions) { if (layerOptions.empty()) { return 0u; } for (std::size_t index = layerOptions.size(); index-- > 0u;) { if (layerOptions[index].visible && layerOptions[index].blocksLayersBelow) { return index; } } return 0u; } } // namespace UISystem::UISystem(IUIScreenDocumentHost& documentHost) : m_documentHost(&documentHost) { } UIScreenPlayer& UISystem::CreatePlayer(const UIScreenLayerOptions& options) { m_players.push_back(std::make_unique(*m_documentHost)); m_layerIds.push_back(m_nextLayerId++); m_layerOptions.push_back(options); return *m_players.back(); } UIScreenLayerId UISystem::PushScreen( const UIScreenAsset& asset, const UIScreenLayerOptions& options) { UIScreenPlayer& player = CreatePlayer(options); if (!player.Load(asset)) { m_players.pop_back(); m_layerIds.pop_back(); m_layerOptions.pop_back(); return 0; } return m_layerIds.back(); } bool UISystem::RemoveLayer(UIScreenLayerId layerId) { const std::size_t index = FindLayerIndex(layerId); if (index >= m_players.size()) { return false; } m_players.erase(m_players.begin() + static_cast(index)); m_layerIds.erase(m_layerIds.begin() + static_cast(index)); m_layerOptions.erase(m_layerOptions.begin() + static_cast(index)); return true; } bool UISystem::SetLayerVisibility(UIScreenLayerId layerId, bool visible) { const std::size_t index = FindLayerIndex(layerId); if (index >= m_layerOptions.size()) { return false; } m_layerOptions[index].visible = visible; return true; } bool UISystem::SetLayerOptions(UIScreenLayerId layerId, const UIScreenLayerOptions& options) { const std::size_t index = FindLayerIndex(layerId); if (index >= m_layerOptions.size()) { return false; } m_layerOptions[index] = options; return true; } const UIScreenLayerOptions* UISystem::FindLayerOptions(UIScreenLayerId layerId) const { const std::size_t index = FindLayerIndex(layerId); return index < m_layerOptions.size() ? &m_layerOptions[index] : nullptr; } UIScreenLayerId UISystem::GetLayerId(std::size_t index) const { return index < m_layerIds.size() ? m_layerIds[index] : 0; } void UISystem::DestroyAllPlayers() { m_players.clear(); m_layerIds.clear(); m_layerOptions.clear(); m_lastFrame = {}; } std::size_t UISystem::GetPlayerCount() const { return m_players.size(); } std::size_t UISystem::GetLayerCount() const { return m_layerIds.size(); } const UISystemFrameResult& UISystem::Update(const UIScreenFrameInput& input) { m_lastFrame = {}; m_lastFrame.frameIndex = input.frameIndex; m_lastFrame.viewportRect = input.viewportRect; m_lastFrame.submittedInputEventCount = input.events.size(); m_lastFrame.deltaTimeSeconds = input.deltaTimeSeconds; m_lastFrame.focused = input.focused; if (m_players.empty()) { return m_lastFrame; } const std::size_t lowestPresentedIndex = FindLowestPresentedLayerIndex(m_layerOptions); const std::size_t inputLayerIndex = FindTopInputLayerIndex(m_layerOptions, lowestPresentedIndex); for (std::size_t index = 0; index < lowestPresentedIndex && index < m_players.size(); ++index) { ++m_lastFrame.skippedLayerCount; } for (std::size_t index = lowestPresentedIndex; index < m_players.size(); ++index) { if (!m_layerOptions[index].visible) { ++m_lastFrame.skippedLayerCount; continue; } UIScreenFrameInput layerInput = input; if (index != inputLayerIndex) { layerInput.events.clear(); layerInput.focused = false; } const UIScreenFrameResult& layerFrame = m_players[index]->Update(layerInput); for (const UIDrawList& drawList : layerFrame.drawData.GetDrawLists()) { m_lastFrame.drawData.AddDrawList(drawList); } UISystemPresentedLayer presentedLayer = {}; presentedLayer.layerId = m_layerIds[index]; if (const UIScreenAsset* asset = m_players[index]->GetAsset(); asset != nullptr) { presentedLayer.asset = *asset; } presentedLayer.options = m_layerOptions[index]; presentedLayer.stats = layerFrame.stats; m_lastFrame.layers.push_back(std::move(presentedLayer)); ++m_lastFrame.presentedLayerCount; if (m_lastFrame.errorMessage.empty() && !layerFrame.errorMessage.empty()) { m_lastFrame.errorMessage = layerFrame.errorMessage; } } return m_lastFrame; } void UISystem::Tick(const UIScreenFrameInput& input) { Update(input); } const UISystemFrameResult& UISystem::GetLastFrame() const { return m_lastFrame; } UISystemFrameResult UISystem::ConsumeLastFrame() { UISystemFrameResult frame = std::move(m_lastFrame); m_lastFrame = {}; return frame; } const std::vector>& UISystem::GetPlayers() const { return m_players; } std::size_t UISystem::FindLayerIndex(UIScreenLayerId layerId) const { for (std::size_t index = 0; index < m_layerIds.size(); ++index) { if (m_layerIds[index] == layerId) { return index; } } return static_cast(-1); } } // namespace Runtime } // namespace UI } // namespace XCEngine