diff --git a/drape/overlay_tree.hpp b/drape/overlay_tree.hpp index 9f9818a3f1..e40bd7e419 100644 --- a/drape/overlay_tree.hpp +++ b/drape/overlay_tree.hpp @@ -47,6 +47,8 @@ class OverlayTree : public m4::Tree, detail::OverlayTrait using TBase = m4::Tree, detail::OverlayTraits>; public: + using HandlesCache = unordered_set, detail::OverlayHasher>; + OverlayTree(); bool Frame(); @@ -57,6 +59,8 @@ public: void Remove(ref_ptr handle); void EndOverlayPlacing(); + HandlesCache const & GetHandlesCache() const { return m_handlesCache; } + void Select(m2::RectD const & rect, TOverlayContainer & result) const; void Select(m2::PointD const & glbPoint, TOverlayContainer & result) const; @@ -94,7 +98,7 @@ private: int m_frameCounter; array>, dp::OverlayRanksCount> m_handles; - unordered_set, detail::OverlayHasher> m_handlesCache; + HandlesCache m_handlesCache; bool m_followingMode; bool m_isDisplacementEnabled; diff --git a/drape_frontend/CMakeLists.txt b/drape_frontend/CMakeLists.txt index 693dbe216f..0094079022 100644 --- a/drape_frontend/CMakeLists.txt +++ b/drape_frontend/CMakeLists.txt @@ -129,6 +129,8 @@ set( navigator.hpp overlay_batcher.cpp overlay_batcher.hpp + overlays_tracker.cpp + overlays_tracker.hpp path_symbol_shape.cpp path_symbol_shape.hpp path_text_shape.cpp diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index 253b28fd6b..51d8415a1c 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -25,7 +25,7 @@ namespace df { -BackendRenderer::BackendRenderer(Params const & params) +BackendRenderer::BackendRenderer(Params && params) : BaseRenderer(ThreadsCommutator::ResourceUploadThread, params) , m_model(params.m_model) , m_readManager(make_unique_dp(params.m_commutator, m_model, @@ -431,9 +431,13 @@ void BackendRenderer::AcceptMessage(ref_ptr message) case Message::SetCustomSymbols: { ref_ptr msg = message; - m_readManager->UpdateCustomSymbols(msg->AcceptSymbols()); + CustomSymbols customSymbols = msg->AcceptSymbols(); + std::vector features; + for (auto const & symbol : customSymbols) + features.push_back(symbol.first); + m_readManager->UpdateCustomSymbols(std::move(customSymbols)); m_commutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(CustomSymbols()), + make_unique_dp(std::move(features)), MessagePriority::Normal); break; } diff --git a/drape_frontend/backend_renderer.hpp b/drape_frontend/backend_renderer.hpp index b8b1f8a417..6365c263eb 100644 --- a/drape_frontend/backend_renderer.hpp +++ b/drape_frontend/backend_renderer.hpp @@ -57,7 +57,7 @@ public: bool m_simplifiedTrafficColors; }; - BackendRenderer(Params const & params); + BackendRenderer(Params && params); ~BackendRenderer() override; void Teardown(); diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index 2f5e4d6e90..c4d8dbd32e 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -49,19 +49,20 @@ DrapeEngine::DrapeEngine(Params && params) bind(&DrapeEngine::TapEvent, this, _1), bind(&DrapeEngine::UserPositionChanged, this, _1), bind(&DrapeEngine::MyPositionModeChanged, this, _1, _2), - mode, make_ref(m_requestedTiles), timeInBackground, + mode, make_ref(m_requestedTiles), + move(params.m_showEventCallback), timeInBackground, params.m_allow3dBuildings, params.m_trafficEnabled, params.m_blockTapEvents, params.m_isFirstLaunch, params.m_isRoutingActive, params.m_isAutozoomEnabled); - m_frontend = make_unique_dp(frParams); + m_frontend = make_unique_dp(move(frParams)); BackendRenderer::Params brParams(frParams.m_commutator, frParams.m_oglContextFactory, frParams.m_texMng, params.m_model, params.m_model.UpdateCurrentCountryFn(), make_ref(m_requestedTiles), params.m_allow3dBuildings, params.m_trafficEnabled, params.m_simplifiedTrafficColors); - m_backend = make_unique_dp(brParams); + m_backend = make_unique_dp(move(brParams)); m_widgetsInfo = move(params.m_info); diff --git a/drape_frontend/drape_engine.hpp b/drape_frontend/drape_engine.hpp index 28eb82c943..abcb70c001 100644 --- a/drape_frontend/drape_engine.hpp +++ b/drape_frontend/drape_engine.hpp @@ -5,6 +5,7 @@ #include "drape_frontend/custom_symbol.hpp" #include "drape_frontend/frontend_renderer.hpp" #include "drape_frontend/route_shape.hpp" +#include "drape_frontend/overlays_tracker.hpp" #include "drape_frontend/scenario_manager.hpp" #include "drape_frontend/selection_shape.hpp" #include "drape_frontend/threads_commutator.hpp" @@ -56,7 +57,8 @@ public: bool firstLaunch, bool isRoutingActive, bool isAutozoomEnabled, - bool simplifiedTrafficColors) + bool simplifiedTrafficColors, + OverlayShowEventCallback && showEventCallback) : m_factory(factory) , m_stringsBundle(stringBundle) , m_viewport(viewport) @@ -75,6 +77,7 @@ public: , m_isRoutingActive(isRoutingActive) , m_isAutozoomEnabled(isAutozoomEnabled) , m_simplifiedTrafficColors(simplifiedTrafficColors) + , m_showEventCallback(move(showEventCallback)) {} ref_ptr m_factory; @@ -95,6 +98,7 @@ public: bool m_isRoutingActive; bool m_isAutozoomEnabled; bool m_simplifiedTrafficColors; + OverlayShowEventCallback m_showEventCallback; }; DrapeEngine(Params && params); diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro index 15c1b4572b..9010a1bbe8 100755 --- a/drape_frontend/drape_frontend.pro +++ b/drape_frontend/drape_frontend.pro @@ -64,6 +64,7 @@ SOURCES += \ my_position_controller.cpp \ navigator.cpp \ overlay_batcher.cpp \ + overlays_tracker.cpp \ path_symbol_shape.cpp \ path_text_shape.cpp \ poi_symbol_shape.cpp \ @@ -171,6 +172,7 @@ HEADERS += \ my_position_controller.hpp \ navigator.hpp \ overlay_batcher.hpp \ + overlays_tracker.hpp \ path_symbol_shape.hpp \ path_text_shape.hpp \ poi_symbol_shape.hpp \ diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 6f989572de..3cfb29892c 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -13,7 +13,6 @@ #include "drape_frontend/visual_params.hpp" #include "drape_frontend/user_mark_shapes.hpp" - #include "drape/debug_rect_renderer.hpp" #include "drape/shader_def.hpp" #include "drape/support_manager.hpp" @@ -114,7 +113,7 @@ struct RemoveTilePredicate } // namespace -FrontendRenderer::FrontendRenderer(Params const & params) +FrontendRenderer::FrontendRenderer(Params && params) : BaseRenderer(ThreadsCommutator::RenderThread, params) , m_gpuProgramManager(new dp::GpuProgramManager()) , m_routeRenderer(new RouteRenderer()) @@ -138,6 +137,8 @@ FrontendRenderer::FrontendRenderer(Params const & params) , m_needRestoreSize(false) , m_needRegenerateTraffic(false) , m_trafficEnabled(params.m_trafficEnabled) + , m_overlaysTracker(new OverlaysTracker()) + , m_showEventCallback(move(params.m_showEventCallback)) #ifdef SCENARIO_ENABLE , m_scenarioManager(new ScenarioManager(this)) #endif @@ -776,8 +777,10 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) break; } - case Message::SetCustomSymbols: + case Message::UpdateCustomSymbols: { + ref_ptr msg = message; + m_overlaysTracker->Init(msg->AcceptSymbolsFeatures()); ScreenBase const & screen = m_userEventStream.GetCurrentScreen(); InvalidateRect(screen.ClipRect()); break; @@ -1076,7 +1079,20 @@ void FrontendRenderer::UpdateOverlayTree(ScreenBase const & modelView, drape_ptr void FrontendRenderer::EndUpdateOverlayTree() { if (m_overlayTree->IsNeedUpdate()) + { m_overlayTree->EndOverlayPlacing(); + + // Track overlays. + if (m_overlaysTracker->StartTracking(m_currentZoomLevel)) + { + for (auto const & handle : m_overlayTree->GetHandlesCache()) + { + if (handle->IsVisible()) + m_overlaysTracker->Track(handle->GetOverlayID().m_featureId); + } + m_overlaysTracker->FinishTracking(); + } + } } void FrontendRenderer::RenderScene(ScreenBase const & modelView) @@ -1702,9 +1718,11 @@ void FrontendRenderer::Routine::Do() m_renderer.OnContextCreate(); double const kMaxInactiveSeconds = 2.0; + double const kShowOverlaysEventsPeriod = 5.0; my::Timer timer; my::Timer activityTimer; + my::Timer showOverlaysEventsTimer; double frameTime = 0.0; bool modelViewChanged = true; @@ -1772,15 +1790,25 @@ void FrontendRenderer::Routine::Do() // Limit fps in following mode. double constexpr kFrameTime = 1.0 / 30.0; - if (isValidFrameTime && m_renderer.m_myPositionController->IsRouteFollowingActive() && frameTime < kFrameTime) + if (isValidFrameTime && + m_renderer.m_myPositionController->IsRouteFollowingActive() && frameTime < kFrameTime) { uint32_t const ms = static_cast((kFrameTime - frameTime) * 1000); this_thread::sleep_for(milliseconds(ms)); } + if (m_renderer.m_overlaysTracker->IsValid() && + showOverlaysEventsTimer.ElapsedSeconds() > kShowOverlaysEventsPeriod) + { + m_renderer.CollectShowOverlaysEvents(); + showOverlaysEventsTimer.Reset(); + } + m_renderer.CheckRenderingEnabled(); } + m_renderer.CollectShowOverlaysEvents(); + #ifdef RENDER_DEBUG_RECTS dp::DebugRectRenderer::Instance().Destroy(); #endif @@ -1913,6 +1941,12 @@ drape_ptr const & FrontendRenderer::GetScenarioManager() const return m_scenarioManager; } +void FrontendRenderer::CollectShowOverlaysEvents() +{ + ASSERT(m_showEventCallback != nullptr, ()); + m_showEventCallback(m_overlaysTracker->Collect()); +} + FrontendRenderer::RenderLayer::RenderLayerID FrontendRenderer::RenderLayer::GetLayerID(dp::GLState const & state) { if (state.GetDepthLayer() == dp::GLState::OverlayLayer) diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index e06ee32451..9a6512c084 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -10,6 +10,7 @@ #include "drape_frontend/gps_track_renderer.hpp" #include "drape_frontend/my_position_controller.hpp" #include "drape_frontend/navigator.hpp" +#include "drape_frontend/overlays_tracker.hpp" #include "drape_frontend/render_group.hpp" #include "drape_frontend/requested_tiles.hpp" #include "drape_frontend/route_renderer.hpp" @@ -79,6 +80,7 @@ public: location::TMyPositionModeChanged myPositionModeCallback, location::EMyPositionMode initMode, ref_ptr requestedTiles, + OverlayShowEventCallback && showEventCallback, double timeInBackground, bool allow3dBuildings, bool trafficEnabled, @@ -94,6 +96,7 @@ public: , m_myPositionModeCallback(myPositionModeCallback) , m_initMyPositionMode(initMode) , m_requestedTiles(requestedTiles) + , m_showEventCallback(move(showEventCallback)) , m_timeInBackground(timeInBackground) , m_allow3dBuildings(allow3dBuildings) , m_trafficEnabled(trafficEnabled) @@ -110,6 +113,7 @@ public: location::TMyPositionModeChanged m_myPositionModeCallback; location::EMyPositionMode m_initMyPositionMode; ref_ptr m_requestedTiles; + OverlayShowEventCallback m_showEventCallback; double m_timeInBackground; bool m_allow3dBuildings; bool m_trafficEnabled; @@ -119,7 +123,7 @@ public: bool m_isAutozoomEnabled; }; - FrontendRenderer(Params const & params); + FrontendRenderer(Params && params); ~FrontendRenderer() override; void Teardown(); @@ -241,6 +245,8 @@ private: void OnCacheRouteArrows(int routeIndex, vector const & borders); + void CollectShowOverlaysEvents(); + drape_ptr m_gpuProgramManager; struct RenderLayer @@ -330,6 +336,9 @@ private: bool m_needRegenerateTraffic; bool m_trafficEnabled; + drape_ptr m_overlaysTracker; + OverlayShowEventCallback m_showEventCallback; + drape_ptr m_scenarioManager; #ifdef DEBUG diff --git a/drape_frontend/message.hpp b/drape_frontend/message.hpp index ba6b5bde98..7c615e1674 100644 --- a/drape_frontend/message.hpp +++ b/drape_frontend/message.hpp @@ -76,6 +76,7 @@ public: DrapeApiRemove, DrapeApiFlush, SetCustomSymbols, + UpdateCustomSymbols, }; virtual ~Message() {} diff --git a/drape_frontend/message_subclasses.hpp b/drape_frontend/message_subclasses.hpp index a15245bd88..1052847afd 100644 --- a/drape_frontend/message_subclasses.hpp +++ b/drape_frontend/message_subclasses.hpp @@ -1155,7 +1155,7 @@ class SetCustomSymbolsMessage : public Message { public: explicit SetCustomSymbolsMessage(CustomSymbols && symbols) - : m_symbols(move(symbols)) + : m_symbols(std::move(symbols)) {} Type GetType() const override { return Message::SetCustomSymbols; } @@ -1166,4 +1166,19 @@ private: CustomSymbols m_symbols; }; +class UpdateCustomSymbolsMessage : public Message +{ +public: + explicit UpdateCustomSymbolsMessage(std::vector && symbolsFeatures) + : m_symbolsFeatures(std::move(symbolsFeatures)) + {} + + Type GetType() const override { return Message::UpdateCustomSymbols; } + + std::vector && AcceptSymbolsFeatures() { return std::move(m_symbolsFeatures); } + +private: + std::vector m_symbolsFeatures; +}; + } // namespace df diff --git a/drape_frontend/overlays_tracker.cpp b/drape_frontend/overlays_tracker.cpp new file mode 100644 index 0000000000..416fd5ec5e --- /dev/null +++ b/drape_frontend/overlays_tracker.cpp @@ -0,0 +1,74 @@ +#include "drape_frontend/overlays_tracker.hpp" + +namespace df +{ +void OverlaysTracker::Init(std::vector && ids) +{ + m_data.clear(); + for (auto const & fid : ids) + m_data.insert(std::make_pair(fid, OverlayInfo())); +} + +bool OverlaysTracker::StartTracking(int zoomLevel) +{ + if (zoomLevel < kMinZoomLevel) + { + for (auto & p : m_data) + p.second.m_status = OverlayStatus::Invisible; + return false; + } + + m_zoomLevel = zoomLevel; + for (auto & p : m_data) + p.second.m_tracked = false; + + return true; +} + +void OverlaysTracker::Track(FeatureID const & fid) +{ + ASSERT_GREATER_OR_EQUAL(m_zoomLevel, kMinZoomLevel, ()); + + auto it = m_data.find(fid); + if (it == m_data.end()) + return; + + it->second.m_tracked = true; + if (it->second.m_status == OverlayStatus::Invisible) + { + it->second.m_status = OverlayStatus::Visible; + m_events.emplace_back(it->first, m_zoomLevel, std::chrono::system_clock::now()); + } +} + +void OverlaysTracker::FinishTracking() +{ + ASSERT_GREATER_OR_EQUAL(m_zoomLevel, kMinZoomLevel, ()); + + for (auto & p : m_data) + { + if (p.second.m_status == OverlayStatus::Visible && !p.second.m_tracked) + { + p.second.m_status = OverlayStatus::InvisibleCandidate; + p.second.m_timestamp = std::chrono::steady_clock::now(); + } + else if (p.second.m_status == OverlayStatus::InvisibleCandidate) + { + // Here we add some delay to avoid false events appearance. + static auto const kDelay = std::chrono::milliseconds(500); + if (p.second.m_tracked) + p.second.m_status = OverlayStatus::Visible; + else if (std::chrono::steady_clock::now() - p.second.m_timestamp > kDelay) + p.second.m_status = OverlayStatus::Invisible; + } + } + m_zoomLevel = -1; +} + +std::list OverlaysTracker::Collect() +{ + std::list events; + std::swap(m_events, events); + return events; +} +} // namespace df diff --git a/drape_frontend/overlays_tracker.hpp b/drape_frontend/overlays_tracker.hpp new file mode 100644 index 0000000000..b09b1923e5 --- /dev/null +++ b/drape_frontend/overlays_tracker.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "indexer/feature_decl.hpp" + +#include +#include +#include +#include +#include + +namespace df +{ +struct OverlayShowEvent +{ + FeatureID m_feature; + int m_zoomLevel; + std::chrono::system_clock::time_point m_timestamp; + OverlayShowEvent(FeatureID const & feature, int zoomLevel, + std::chrono::system_clock::time_point const & timestamp) + : m_feature(feature) + , m_zoomLevel(zoomLevel) + , m_timestamp(timestamp) + {} +}; + +using OverlayShowEventCallback = std::function &&)>; + +int constexpr kMinZoomLevel = 10; + +class OverlaysTracker +{ +public: + OverlaysTracker() = default; + + void Init(std::vector && ids); + + bool StartTracking(int zoomLevel); + void Track(FeatureID const & fid); + void FinishTracking(); + + std::list Collect(); + + bool IsValid() const { return !m_data.empty(); } + +private: + enum class OverlayStatus + { + Invisible, + InvisibleCandidate, + Visible, + }; + + struct OverlayInfo + { + std::chrono::steady_clock::time_point m_timestamp; + OverlayStatus m_status = OverlayStatus::Invisible; + bool m_tracked = false; + }; + + std::map m_data; + std::list m_events; + int m_zoomLevel = -1; +}; + +} // namespace df diff --git a/map/framework.cpp b/map/framework.cpp index d95f1707b9..610c6350be 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1673,6 +1673,13 @@ void Framework::CreateDrapeEngine(ref_ptr contextFactory, }); }; + auto showOverlaysEventFn = [](std::list && events) + { + // TODO: implement sending events. This callback is called on a render thread, + // so placing here not lightweight code is strictly prohibited! The best option is + // redirection events to another thread. + }; + auto isCountryLoadedByNameFn = bind(&Framework::IsCountryLoadedByName, this, _1); auto updateCurrentCountryFn = bind(&Framework::OnUpdateCurrentCountry, this, _1, _2); @@ -1697,7 +1704,7 @@ void Framework::CreateDrapeEngine(ref_ptr contextFactory, move(myPositionModeChangedFn), allow3dBuildings, trafficEnabled, params.m_isChoosePositionMode, params.m_isChoosePositionMode, GetSelectedFeatureTriangles(), params.m_isFirstLaunch, m_routingSession.IsActive() && m_routingSession.IsFollowing(), isAutozoomEnabled, - simplifiedTrafficColors); + simplifiedTrafficColors, showOverlaysEventFn); m_drapeEngine = make_unique_dp(move(p)); m_drapeEngine->SetModelViewListener([this](ScreenBase const & screen) diff --git a/platform/platform_mac.mm b/platform/platform_mac.mm index 02af7a74fc..278de9c535 100644 --- a/platform/platform_mac.mm +++ b/platform/platform_mac.mm @@ -54,6 +54,12 @@ Platform::Platform() dataPath = "../../../../../../omim/data/"; if (IsFileExistsByFullPath(m_resourcesDir + dataPath)) m_writableDir = m_resourcesDir + dataPath; + if (m_writableDir.empty()) + { + auto p = m_resourcesDir.find("/omim/"); + if (p != std::string::npos) + m_writableDir = m_resourcesDir.substr(0, p) + "/omim/data/"; + } } if (m_writableDir.empty())