diff --git a/drape/batcher.cpp b/drape/batcher.cpp index c8bc1b548a..1f4cdc1ea9 100644 --- a/drape/batcher.cpp +++ b/drape/batcher.cpp @@ -283,9 +283,7 @@ IndicesRange Batcher::InsertPrimitives(GLState const & state, ref_ptr 0.0) + { + color.rgb = mix(color.rgb, vec3(1.0, 1.0, 1.0), step(kOutlineThreshold1, abs(v_halfLength))); + color.rgb = mix(color.rgb, vec3(1.0, 1.0, 1.0), smoothstep(kOutlineThreshold2, kOutlineThreshold1, abs(v_halfLength))); + } gl_FragColor = color; } else diff --git a/drape_frontend/apply_feature_functors.cpp b/drape_frontend/apply_feature_functors.cpp index 74688951a0..802a6b874a 100644 --- a/drape_frontend/apply_feature_functors.cpp +++ b/drape_frontend/apply_feature_functors.cpp @@ -802,4 +802,9 @@ void ApplyLineFeature::Finish() } } +m2::PolylineD ApplyLineFeature::GetPolyline() const +{ + return HasGeometry() ? m2::PolylineD(m_spline->GetPath()) : m2::PolylineD(); +} + } // namespace df diff --git a/drape_frontend/apply_feature_functors.hpp b/drape_frontend/apply_feature_functors.hpp index a88792e0e4..b52b20fe9d 100644 --- a/drape_frontend/apply_feature_functors.hpp +++ b/drape_frontend/apply_feature_functors.hpp @@ -9,6 +9,7 @@ #include "indexer/point_to_int64.hpp" #include "geometry/point2d.hpp" +#include "geometry/polyline2d.hpp" #include "geometry/spline.hpp" #include "std/unordered_map.hpp" @@ -144,6 +145,8 @@ public: void ProcessRule(Stylist::TRuleWrapper const & rule); void Finish(); + m2::PolylineD GetPolyline() const; + private: m2::SharedSpline m_spline; vector m_clippedSplines; diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index d81d0c3bac..c3e187c372 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -27,7 +27,8 @@ namespace df BackendRenderer::BackendRenderer(Params const & params) : BaseRenderer(ThreadsCommutator::ResourceUploadThread, params) , m_model(params.m_model) - , m_readManager(make_unique_dp(params.m_commutator, m_model, params.m_allow3dBuildings)) + , m_readManager(make_unique_dp(params.m_commutator, m_model, + params.m_allow3dBuildings, params.m_trafficEnabled)) , m_trafficGenerator(make_unique_dp(bind(&BackendRenderer::FlushTrafficRenderData, this, _1))) , m_requestedTiles(params.m_requestedTiles) , m_updateCurrentCountryFn(params.m_updateCurrentCountryFn) @@ -331,37 +332,38 @@ void BackendRenderer::AcceptMessage(ref_ptr message) break; } - case Message::CacheTrafficSegments: + case Message::EnableTraffic: { - ref_ptr msg = message; - for (auto const & segment : msg->GetSegments()) - m_trafficGenerator->AddSegment(segment.first, segment.second); + ref_ptr msg = message; + m_readManager->SetTrafficEnabled(msg->IsTrafficEnabled()); + m_commutator->PostMessage(ThreadsCommutator::RenderThread, + make_unique_dp(msg->IsTrafficEnabled()), + MessagePriority::Normal); + break; + } + + case Message::FlushTrafficGeometry: + { + ref_ptr msg = message; + m_trafficGenerator->FlushSegmentsGeometry(msg->GetKey(), msg->GetSegments(), m_texMng); break; } case Message::UpdateTraffic: { ref_ptr msg = message; - auto segments = m_trafficGenerator->GetSegmentsToUpdate(msg->GetSegmentsColoring()); - if (!segments.empty()) + bool const needInvalidate = m_trafficGenerator->UpdateColoring(msg->GetSegmentsColoring()); + if (m_trafficGenerator->IsColorsCacheRefreshed()) { + auto texCoords = m_trafficGenerator->ProcessCacheRefreshing(); m_commutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(segments), + make_unique_dp(move(texCoords)), MessagePriority::Normal); } - - if (segments.size() < msg->GetSegmentsColoring().size()) - { - m_trafficGenerator->GetTrafficGeom(m_texMng, msg->GetSegmentsColoring()); - - if (m_trafficGenerator->IsColorsCacheRefreshed()) - { - auto texCoords = m_trafficGenerator->ProcessCacheRefreshing(); - m_commutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(move(texCoords)), - MessagePriority::Normal); - } - } + m_commutator->PostMessage(ThreadsCommutator::RenderThread, + make_unique_dp(move(msg->GetSegmentsColoring()), + needInvalidate), + MessagePriority::Normal); break; } case Message::ClearTrafficData: @@ -456,8 +458,10 @@ void BackendRenderer::Routine::Do() void BackendRenderer::InitGLDependentResource() { + int constexpr kBatchSize = 5000; m_batchersPool = make_unique_dp>(ReadManager::ReadCount(), - bind(&BackendRenderer::FlushGeometry, this, _1, _2, _3)); + bind(&BackendRenderer::FlushGeometry, this, _1, _2, _3), + kBatchSize, kBatchSize); m_trafficGenerator->Init(); dp::TextureManager::Params params; diff --git a/drape_frontend/backend_renderer.hpp b/drape_frontend/backend_renderer.hpp index 6f8f08796e..15d138e0a3 100644 --- a/drape_frontend/backend_renderer.hpp +++ b/drape_frontend/backend_renderer.hpp @@ -38,18 +38,21 @@ public: Params(ref_ptr commutator, ref_ptr factory, ref_ptr texMng, MapDataProvider const & model, TUpdateCurrentCountryFn const & updateCurrentCountryFn, - ref_ptr requestedTiles, bool allow3dBuildings) + ref_ptr requestedTiles, bool allow3dBuildings, + bool trafficEnabled) : BaseRenderer::Params(commutator, factory, texMng) , m_model(model) , m_updateCurrentCountryFn(updateCurrentCountryFn) , m_requestedTiles(requestedTiles) , m_allow3dBuildings(allow3dBuildings) + , m_trafficEnabled(trafficEnabled) {} MapDataProvider const & m_model; TUpdateCurrentCountryFn m_updateCurrentCountryFn; ref_ptr m_requestedTiles; bool m_allow3dBuildings; + bool m_trafficEnabled; }; BackendRenderer(Params const & params); diff --git a/drape_frontend/batchers_pool.hpp b/drape_frontend/batchers_pool.hpp index d9586b46bf..8b14fb09fe 100644 --- a/drape_frontend/batchers_pool.hpp +++ b/drape_frontend/batchers_pool.hpp @@ -19,9 +19,10 @@ class BatchersPool public: using TFlushFn = function && buffer)>; - BatchersPool(int initBatchersCount, TFlushFn const & flushFn) + BatchersPool(int initBatchersCount, TFlushFn const & flushFn, + uint32_t indexBufferSize, uint32_t vertexBufferSize) : m_flushFn(flushFn) - , m_pool(initBatchersCount, dp::BatcherFactory()) + , m_pool(initBatchersCount, dp::BatcherFactory(indexBufferSize, vertexBufferSize)) {} ~BatchersPool() diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index 782bfcc390..d81085387e 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -71,7 +71,8 @@ DrapeEngine::DrapeEngine(Params && params) 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); + make_ref(m_requestedTiles), params.m_allow3dBuildings, + params.m_trafficEnabled); m_backend = make_unique_dp(brParams); m_widgetsInfo = move(params.m_info); @@ -533,13 +534,10 @@ void DrapeEngine::RequestSymbolsSize(vector const & symbols, MessagePriority::Normal); } -void DrapeEngine::CacheTrafficSegmentsGeometry(TrafficSegmentsGeometry const & segments) +void DrapeEngine::EnableTraffic(bool trafficEnabled) { - if (segments.empty()) - return; - m_threadCommutator->PostMessage(ThreadsCommutator::ResourceUploadThread, - make_unique_dp(segments), + make_unique_dp(trafficEnabled), MessagePriority::Normal); } diff --git a/drape_frontend/drape_engine.hpp b/drape_frontend/drape_engine.hpp index 00d5445224..ec90aea5f5 100644 --- a/drape_frontend/drape_engine.hpp +++ b/drape_frontend/drape_engine.hpp @@ -44,6 +44,7 @@ public: gui::TWidgetsInitInfo && info, pair const & initialMyPositionMode, bool allow3dBuildings, + bool trafficEnabled, bool blockTapEvents, bool showChoosePositionMark, vector && boundAreaTriangles, @@ -58,6 +59,7 @@ public: , m_info(move(info)) , m_initialMyPositionMode(initialMyPositionMode) , m_allow3dBuildings(allow3dBuildings) + , m_trafficEnabled(trafficEnabled) , m_blockTapEvents(blockTapEvents) , m_showChoosePositionMark(showChoosePositionMark) , m_boundAreaTriangles(move(boundAreaTriangles)) @@ -74,6 +76,7 @@ public: gui::TWidgetsInitInfo m_info; pair m_initialMyPositionMode; bool m_allow3dBuildings; + bool m_trafficEnabled; bool m_blockTapEvents; bool m_showChoosePositionMark; vector m_boundAreaTriangles; @@ -162,7 +165,7 @@ public: void RequestSymbolsSize(vector const & symbols, TRequestSymbolsSizeCallback const & callback); - void CacheTrafficSegmentsGeometry(TrafficSegmentsGeometry const & segments); + void EnableTraffic(bool trafficEnabled); void UpdateTraffic(TrafficSegmentsColoring const & segmentsColoring); void ClearTrafficCache(MwmSet::MwmId const & mwmId); diff --git a/drape_frontend/engine_context.cpp b/drape_frontend/engine_context.cpp index 3f6ac8cc97..ff864cf128 100644 --- a/drape_frontend/engine_context.cpp +++ b/drape_frontend/engine_context.cpp @@ -35,6 +35,11 @@ void EngineContext::FlushOverlays(TMapShapes && shapes) PostMessage(make_unique_dp(m_tileKey, move(shapes))); } +void EngineContext::FlushTrafficGeometry(TrafficSegmentsGeometry && geometry) +{ + PostMessage(make_unique_dp(m_tileKey, move(geometry))); +} + void EngineContext::EndReadTile() { PostMessage(make_unique_dp(m_tileKey)); diff --git a/drape_frontend/engine_context.hpp b/drape_frontend/engine_context.hpp index 54a66dd12c..febfc6189a 100644 --- a/drape_frontend/engine_context.hpp +++ b/drape_frontend/engine_context.hpp @@ -3,6 +3,7 @@ #include "drape_frontend/map_shape.hpp" #include "drape_frontend/tile_utils.hpp" #include "drape_frontend/threads_commutator.hpp" +#include "drape_frontend/traffic_generator.hpp" #include "drape/pointers.hpp" @@ -29,6 +30,7 @@ public: void BeginReadTile(); void Flush(TMapShapes && shapes); void FlushOverlays(TMapShapes && shapes); + void FlushTrafficGeometry(TrafficSegmentsGeometry && geometry); void EndReadTile(); private: diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index fa99a26b2c..b7b9bdd8de 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -290,9 +290,11 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) } } } - if (changed) UpdateCanBeDeletedStatus(); + + if (m_notFinishedTiles.empty()) + m_trafficRenderer->OnGeometryReady(m_currentZoomLevel); break; } @@ -739,10 +741,23 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) break; } + case Message::EnableTraffic: + { + ref_ptr msg = message; + if (msg->IsTrafficEnabled()) + InvalidateRect(m_userEventStream.GetCurrentScreen().ClipRect()); + else + m_trafficRenderer->ClearGLDependentResources(); + break; + } + case Message::UpdateTraffic: { ref_ptr msg = message; - m_trafficRenderer->UpdateTraffic(msg->GetSegmentsColoring()); + if (msg->NeedInvalidate()) + InvalidateRect(m_userEventStream.GetCurrentScreen().ClipRect()); + else + m_trafficRenderer->UpdateTraffic(msg->GetSegmentsColoring()); break; } @@ -1584,6 +1599,8 @@ TTilesCollection FrontendRenderer::ResolveTileKeys(ScreenBase const & screen) return group->GetTileKey().m_zoomLevel != m_currentZoomLevel; }); + m_trafficRenderer->OnUpdateViewport(result, m_currentZoomLevel, tilesToDelete); + return tiles; } diff --git a/drape_frontend/message.hpp b/drape_frontend/message.hpp index 6c9cd7a07c..19d4850a08 100644 --- a/drape_frontend/message.hpp +++ b/drape_frontend/message.hpp @@ -65,7 +65,8 @@ public: RequestSymbolsSize, RecoverGLResources, SetVisibleViewport, - CacheTrafficSegments, + EnableTraffic, + FlushTrafficGeometry, SetTrafficTexCoords, UpdateTraffic, FlushTrafficData, diff --git a/drape_frontend/message_subclasses.hpp b/drape_frontend/message_subclasses.hpp index 3ac7db418c..c460b16c6e 100644 --- a/drape_frontend/message_subclasses.hpp +++ b/drape_frontend/message_subclasses.hpp @@ -996,16 +996,32 @@ private: TRequestSymbolsSizeCallback m_callback; }; -class CacheTrafficSegmentsMessage : public Message +class EnableTrafficMessage : public Message { public: - explicit CacheTrafficSegmentsMessage(TrafficSegmentsGeometry const & segments) - : m_segments(segments) + explicit EnableTrafficMessage(bool trafficEnabled) + : m_trafficEnabled(trafficEnabled) {} - Type GetType() const override { return Message::CacheTrafficSegments; } + Type GetType() const override { return Message::EnableTraffic; } - TrafficSegmentsGeometry const & GetSegments() const { return m_segments; } + bool IsTrafficEnabled() const { return m_trafficEnabled; } + +private: + bool const m_trafficEnabled; +}; + +class FlushTrafficGeometryMessage : public BaseTileMessage +{ +public: + FlushTrafficGeometryMessage(TileKey const & tileKey, TrafficSegmentsGeometry && segments) + : BaseTileMessage(tileKey) + , m_segments(move(segments)) + {} + + Type GetType() const override { return Message::FlushTrafficGeometry; } + + TrafficSegmentsGeometry & GetSegments() { return m_segments; } private: TrafficSegmentsGeometry m_segments; @@ -1032,15 +1048,23 @@ class UpdateTrafficMessage : public Message public: explicit UpdateTrafficMessage(TrafficSegmentsColoring const & segmentsColoring) : m_segmentsColoring(segmentsColoring) + , m_needInvalidate(false) + {} + + UpdateTrafficMessage(TrafficSegmentsColoring && segmentsColoring, bool needInvalidate) + : m_segmentsColoring(move(segmentsColoring)) + , m_needInvalidate(needInvalidate) {} Type GetType() const override { return Message::UpdateTraffic; } bool IsGLContextDependent() const override { return true; } - TrafficSegmentsColoring const & GetSegmentsColoring() const { return m_segmentsColoring; } + TrafficSegmentsColoring & GetSegmentsColoring() { return m_segmentsColoring; } + bool NeedInvalidate() const { return m_needInvalidate; } private: TrafficSegmentsColoring m_segmentsColoring; + bool const m_needInvalidate; }; class FlushTrafficDataMessage : public Message diff --git a/drape_frontend/read_manager.cpp b/drape_frontend/read_manager.cpp index e8a50861e6..a8fcae7570 100755 --- a/drape_frontend/read_manager.cpp +++ b/drape_frontend/read_manager.cpp @@ -36,12 +36,14 @@ struct LessCoverageCell } // namespace -ReadManager::ReadManager(ref_ptr commutator, MapDataProvider & model, bool allow3dBuildings) +ReadManager::ReadManager(ref_ptr commutator, MapDataProvider & model, + bool allow3dBuildings, bool trafficEnabled) : m_commutator(commutator) , m_model(model) , m_pool(make_unique_dp(ReadCount(), bind(&ReadManager::OnTaskFinished, this, _1))) , m_have3dBuildings(false) , m_allow3dBuildings(allow3dBuildings) + , m_trafficEnabled(trafficEnabled) , m_modeChanged(false) , myPool(64, ReadMWMTaskFactory(m_model)) , m_counter(0) @@ -202,6 +204,7 @@ void ReadManager::PushTaskBackForTileKey(TileKey const & tileKey, ref_ptr tileInfo(new TileInfo(make_unique_dp(TileKey(tileKey, m_generationCounter), m_commutator, texMng))); tileInfo->Set3dBuildings(m_have3dBuildings && m_allow3dBuildings); + tileInfo->SetTrafficEnabled(m_trafficEnabled); m_tileInfos.insert(tileInfo); ReadMWMTask * task = myPool.Get(); @@ -267,4 +270,13 @@ void ReadManager::Allow3dBuildings(bool allow3dBuildings) } } +void ReadManager::SetTrafficEnabled(bool trafficEnabled) +{ + if (m_trafficEnabled != trafficEnabled) + { + m_modeChanged = true; + m_trafficEnabled = trafficEnabled; + } +} + } // namespace df diff --git a/drape_frontend/read_manager.hpp b/drape_frontend/read_manager.hpp index 22eb7119da..b4ea123851 100755 --- a/drape_frontend/read_manager.hpp +++ b/drape_frontend/read_manager.hpp @@ -27,7 +27,8 @@ class CoverageUpdateDescriptor; class ReadManager { public: - ReadManager(ref_ptr commutator, MapDataProvider & model, bool allow3dBuildings); + ReadManager(ref_ptr commutator, MapDataProvider & model, + bool allow3dBuildings, bool trafficEnabled); void UpdateCoverage(ScreenBase const & screen, bool have3dBuildings, TTilesCollection const & tiles, ref_ptr texMng); @@ -38,6 +39,8 @@ public: bool CheckTileKey(TileKey const & tileKey) const; void Allow3dBuildings(bool allow3dBuildings); + void SetTrafficEnabled(bool trafficEnabled); + static size_t ReadCount(); private: @@ -56,6 +59,7 @@ private: ScreenBase m_currentViewport; bool m_have3dBuildings; bool m_allow3dBuildings; + bool m_trafficEnabled; bool m_modeChanged; struct LessByTileInfo diff --git a/drape_frontend/rule_drawer.cpp b/drape_frontend/rule_drawer.cpp index ce9fa8fe10..3ada0a3f72 100644 --- a/drape_frontend/rule_drawer.cpp +++ b/drape_frontend/rule_drawer.cpp @@ -1,7 +1,8 @@ #include "drape_frontend/rule_drawer.hpp" -#include "drape_frontend/stylist.hpp" -#include "drape_frontend/engine_context.hpp" + #include "drape_frontend/apply_feature_functors.hpp" +#include "drape_frontend/engine_context.hpp" +#include "drape_frontend/stylist.hpp" #include "drape_frontend/visual_params.hpp" #include "indexer/feature.hpp" @@ -24,8 +25,8 @@ #include "base/string_utils.hpp" #endif -namespace { - +namespace +{ df::BaseApplyFeature::HotelData ExtractHotelData(FeatureType const & f) { df::BaseApplyFeature::HotelData result; @@ -39,7 +40,29 @@ df::BaseApplyFeature::HotelData ExtractHotelData(FeatureType const & f) return result; } -} // namespace +void ExtractTrafficGeometry(FeatureType const & f, df::RoadClass const & roadClass, m2::PolylineD const & polyline, + df::TrafficSegmentsGeometry & geometry) +{ + df::TrafficSegmentsGeometry output; + if (polyline.GetSize() < 2) + return; + + static vector directions = {traffic::TrafficInfo::RoadSegmentId::kForwardDirection, + traffic::TrafficInfo::RoadSegmentId::kReverseDirection}; + auto & segments = geometry[f.GetID().m_mwmId]; + segments.reserve(segments.size() + directions.size() * (polyline.GetSize() - 1)); + for (uint16_t segmentIndex = 0; segmentIndex + 1 < static_cast(polyline.GetSize()); ++segmentIndex) + { + for (size_t dirIndex = 0; dirIndex < directions.size(); ++dirIndex) + { + auto const sid = traffic::TrafficInfo::RoadSegmentId(f.GetID().m_index, segmentIndex, directions[dirIndex]); + bool const isReversed = (directions[dirIndex] == traffic::TrafficInfo::RoadSegmentId::kReverseDirection); + segments.emplace_back(sid, df::TrafficSegmentGeometry(polyline.ExtractSegment(segmentIndex, isReversed), roadClass)); + } + } +} + +} // namespace namespace df { @@ -47,12 +70,14 @@ namespace df RuleDrawer::RuleDrawer(TDrawerCallback const & fn, TCheckCancelledCallback const & checkCancelled, TIsCountryLoadedByNameFn const & isLoadedFn, - ref_ptr context, bool is3dBuildings) + ref_ptr context, + bool is3dBuildings, bool trafficEnabled) : m_callback(fn) , m_checkCancelled(checkCancelled) , m_isLoadedFn(isLoadedFn) , m_context(context) , m_is3dBuidings(is3dBuildings) + , m_trafficEnabled(trafficEnabled) , m_wasCancelled(false) { ASSERT(m_callback != nullptr, ()); @@ -85,6 +110,8 @@ RuleDrawer::~RuleDrawer() overlayShapes.swap(m_mapShapes[df::OverlayType]); m_context->FlushOverlays(move(overlayShapes)); } + + m_context->FlushTrafficGeometry(move(m_trafficGeometry)); } bool RuleDrawer::CheckCancelled() @@ -245,6 +272,34 @@ void RuleDrawer::operator()(FeatureType const & f) if (apply.HasGeometry()) s.ForEachRule(bind(&ApplyLineFeature::ProcessRule, &apply, _1)); apply.Finish(); + + if (m_trafficEnabled && zoomLevel >= kRoadClass0ZoomLevel) + { + vector points; + points.reserve(f.GetPointsCount()); + f.ForEachPoint([&points](m2::PointD const & p) { points.emplace_back(p); }, FeatureType::BEST_GEOMETRY); + m2::PolylineD const polyline(points); + + struct Checker + { + vector m_highwayClasses; + int m_zoomLevel; + df::RoadClass m_roadClass; + }; + static Checker const checkers[] = { + {{ftypes::HighwayClass::Trunk, ftypes::HighwayClass::Primary}, kRoadClass0ZoomLevel, df::RoadClass::Class0}, + {{ftypes::HighwayClass::Secondary, ftypes::HighwayClass::Tertiary}, kRoadClass1ZoomLevel, df::RoadClass::Class1}, + {{ftypes::HighwayClass::LivingStreet, ftypes::HighwayClass::Service}, kRoadClass2ZoomLevel, df::RoadClass::Class2} + }; + + auto const highwayClass = ftypes::GetHighwayClass(f); + for (size_t i = 0; i < ARRAY_SIZE(checkers); ++i) + { + auto const & classes = checkers[i].m_highwayClasses; + if (find(classes.begin(), classes.end(), highwayClass) != classes.end() && zoomLevel >= checkers[i].m_zoomLevel) + ExtractTrafficGeometry(f, checkers[i].m_roadClass, polyline, m_trafficGeometry); + } + } } else { diff --git a/drape_frontend/rule_drawer.hpp b/drape_frontend/rule_drawer.hpp index 4af2842783..4b1c9c293d 100644 --- a/drape_frontend/rule_drawer.hpp +++ b/drape_frontend/rule_drawer.hpp @@ -2,6 +2,7 @@ #include "drape_frontend/map_shape.hpp" #include "drape_frontend/tile_key.hpp" +#include "drape_frontend/traffic_generator.hpp" #include "drape/pointers.hpp" @@ -29,7 +30,8 @@ public: using TIsCountryLoadedByNameFn = function; RuleDrawer(TDrawerCallback const & drawerFn, TCheckCancelledCallback const & checkCancelled, - TIsCountryLoadedByNameFn const & isLoadedFn, ref_ptr context, bool is3dBuildings); + TIsCountryLoadedByNameFn const & isLoadedFn, ref_ptr context, + bool is3dBuildings, bool trafficEnabled); ~RuleDrawer(); void operator() (FeatureType const & f); @@ -47,6 +49,9 @@ private: bool const m_is3dBuidings; + bool const m_trafficEnabled; + TrafficSegmentsGeometry m_trafficGeometry; + array m_mapShapes; bool m_wasCancelled; }; diff --git a/drape_frontend/tile_info.cpp b/drape_frontend/tile_info.cpp index 66ae5e59c4..b8ffbc54c3 100644 --- a/drape_frontend/tile_info.cpp +++ b/drape_frontend/tile_info.cpp @@ -17,6 +17,7 @@ namespace df TileInfo::TileInfo(drape_ptr && context) : m_context(move(context)) , m_is3dBuildings(false) + , m_trafficEnabled(false) , m_isCanceled(false) { } @@ -69,7 +70,7 @@ void TileInfo::ReadFeatures(MapDataProvider const & model) RuleDrawer drawer(bind(&TileInfo::InitStylist, this, _1, _2), bind(&TileInfo::IsCancelled, this), model.m_isCountryLoadedByName, - make_ref(m_context), m_is3dBuildings); + make_ref(m_context), m_is3dBuildings, m_trafficEnabled); model.ReadFeatures(bind(ref(drawer), _1), m_featureInfo); } } diff --git a/drape_frontend/tile_info.hpp b/drape_frontend/tile_info.hpp index 3920662275..1c43d6e640 100644 --- a/drape_frontend/tile_info.hpp +++ b/drape_frontend/tile_info.hpp @@ -34,6 +34,9 @@ public: void Set3dBuildings(bool buildings3d) { m_is3dBuildings = buildings3d; } bool Get3dBuildings() const { return m_is3dBuildings; } + void SetTrafficEnabled(bool trafficEnabled) { m_trafficEnabled = trafficEnabled; } + bool GetTrafficEnabled() const { return m_trafficEnabled; } + m2::RectD GetGlobalRect() const; TileKey const & GetTileKey() const { return m_context->GetTileKey(); } bool operator <(TileInfo const & other) const { return GetTileKey() < other.GetTileKey(); } @@ -50,6 +53,7 @@ private: drape_ptr m_context; vector m_featureInfo; bool m_is3dBuildings; + bool m_trafficEnabled; atomic m_isCanceled; }; diff --git a/drape_frontend/traffic_generator.cpp b/drape_frontend/traffic_generator.cpp index f23bcf007b..a692852b2b 100644 --- a/drape_frontend/traffic_generator.cpp +++ b/drape_frontend/traffic_generator.cpp @@ -85,12 +85,15 @@ void GenerateCapTriangles(glsl::vec3 const & pivot, vector const & n } // namespace -TrafficHandle::TrafficHandle(TrafficSegmentID const & segmentId, glsl::vec2 const & texCoord, - size_t verticesCount) +TrafficHandle::TrafficHandle(traffic::TrafficInfo::RoadSegmentId const & segmentId, RoadClass const & roadClass, + m2::RectD const & boundingBox, glsl::vec2 const & texCoord, size_t verticesCount) : OverlayHandle(FeatureID(), dp::Anchor::Center, 0, false) , m_segmentId(segmentId) + , m_roadClass(roadClass) + , m_boundingBox(boundingBox) , m_needUpdate(false) { + ASSERT_NOT_EQUAL(verticesCount, 0, ()); m_buffer.resize(verticesCount); for (size_t i = 0; i < m_buffer.size(); i++) m_buffer[i] = texCoord; @@ -148,16 +151,28 @@ void TrafficHandle::SetTexCoord(glsl::vec2 const & texCoord) m_needUpdate = true; } -TrafficSegmentID TrafficHandle::GetSegmentId() const +traffic::TrafficInfo::RoadSegmentId const & TrafficHandle::GetSegmentId() const { return m_segmentId; } +RoadClass const & TrafficHandle::GetRoadClass() const +{ + return m_roadClass; +} + +m2::RectD const & TrafficHandle::GetBoundingBox() const +{ + return m_boundingBox; +} + void TrafficGenerator::Init() { - int const kBatchersCount = 3; + int constexpr kBatchersCount = 3; + int constexpr kBatchSize = 65000; m_batchersPool = make_unique_dp>( - kBatchersCount, bind(&TrafficGenerator::FlushGeometry, this, _1, _2, _3)); + kBatchersCount, bind(&TrafficGenerator::FlushGeometry, this, _1, _2, _3), + kBatchSize, kBatchSize); } void TrafficGenerator::ClearGLDependentResources() @@ -166,51 +181,8 @@ void TrafficGenerator::ClearGLDependentResources() m_batchersPool.reset(); } -void TrafficGenerator::AddSegment(TrafficSegmentID const & segmentId, m2::PolylineD const & polyline) -{ - m_segments.insert(make_pair(segmentId, polyline)); -} - -void TrafficGenerator::ClearCache() -{ - m_colorsCacheValid = false; - m_segmentsCache.clear(); -} - -void TrafficGenerator::ClearCache(MwmSet::MwmId const & mwmId) -{ - auto it = m_segmentsCache.begin(); - while (it != m_segmentsCache.end()) - { - if (it->m_mwmId == mwmId) - it = m_segmentsCache.erase(it); - else - ++it; - } -} - -TrafficSegmentsColoring TrafficGenerator::GetSegmentsToUpdate(TrafficSegmentsColoring const & trafficColoring) const -{ - TrafficSegmentsColoring result; - for (auto const & segment : trafficColoring) - { - if (m_segmentsCache.find(segment.m_id) != m_segmentsCache.end()) - result.push_back(segment); - } - return result; -} - -void TrafficGenerator::FlushGeometry(TrafficBatcherKey const & key, dp::GLState const & state, drape_ptr && buffer) -{ - TrafficRenderData renderData(state); - renderData.m_bucket = move(buffer); - renderData.m_mwmId = key.m_mwmId; - renderData.m_tileKey = key.m_tileKey; - m_flushRenderDataFn(move(renderData)); -} - -void TrafficGenerator::GetTrafficGeom(ref_ptr textures, - TrafficSegmentsColoring const & trafficColoring) +void TrafficGenerator::FlushSegmentsGeometry(TileKey const & tileKey, TrafficSegmentsGeometry const & geom, + ref_ptr textures) { FillColorsCache(textures); @@ -219,70 +191,93 @@ void TrafficGenerator::GetTrafficGeom(ref_ptr textures, state.SetColorTexture(m_colorsCache[static_cast(traffic::SpeedGroup::G0)].GetTexture()); state.SetMaskTexture(textures->GetTrafficArrowTexture()); - int const kZoomLevel = 10; + static vector roadClasses = {RoadClass::Class0, RoadClass::Class1, RoadClass::Class2}; - using TSegIter = TSegmentCollection::iterator; - map>> segmentsByTiles; - for (auto const & segment : trafficColoring) + for (auto geomIt = geom.begin(); geomIt != geom.end(); ++geomIt) { - // Check if a segment hasn't been added. - auto it = m_segments.find(segment.m_id); - if (it == m_segments.end()) - continue; - - // Check if a segment has already generated. - if (m_segmentsCache.find(segment.m_id) != m_segmentsCache.end()) - continue; - - m_segmentsCache.insert(segment.m_id); - TileKey const tileKey = GetTileKeyByPoint(it->second.GetLimitRect().Center(), kZoomLevel); - segmentsByTiles[tileKey].emplace_back(make_pair(it, segment.m_speedGroup)); - } - - for (auto const & s : segmentsByTiles) - { - TileKey const & tileKey = s.first; - - for (auto const & segmentPair : s.second) + auto coloringIt = m_coloring.find(geomIt->first); + if (coloringIt != m_coloring.end()) { - TSegIter it = segmentPair.first; + for (auto const & roadClass : roadClasses) + m_batchersPool->ReserveBatcher(TrafficBatcherKey(geomIt->first, tileKey, roadClass)); - TrafficBatcherKey bk(it->first.m_mwmId, tileKey); + auto & coloring = coloringIt->second; + for (size_t i = 0; i < geomIt->second.size(); i++) + { + traffic::TrafficInfo::RoadSegmentId const & sid = geomIt->second[i].first; + auto segmentColoringIt = coloring.find(sid); + if (segmentColoringIt != coloring.end()) + { + TrafficSegmentGeometry const & g = geomIt->second[i].second; + ref_ptr batcher = m_batchersPool->GetBatcher(TrafficBatcherKey(geomIt->first, tileKey, g.m_roadClass)); - m_batchersPool->ReserveBatcher(bk); - ref_ptr batcher = m_batchersPool->GetBatcher(bk); + ASSERT(m_colorsCacheValid, ()); + dp::TextureManager::ColorRegion const & colorRegion = m_colorsCache[static_cast(segmentColoringIt->second)]; - ASSERT(m_colorsCacheValid, ()); - dp::TextureManager::ColorRegion const & colorRegion = m_colorsCache[static_cast(segmentPair.second)]; - m2::PolylineD const & polyline = it->second; + vector staticGeometry; + vector dynamicGeometry; + bool const generateCaps = (tileKey.m_zoomLevel > kOutlineMinZoomLevel); + GenerateSegment(colorRegion, g.m_polyline, tileKey.GetGlobalRect().Center(), generateCaps, staticGeometry, dynamicGeometry); + ASSERT_EQUAL(staticGeometry.size(), dynamicGeometry.size(), ()); - vector staticGeometry; - vector dynamicGeometry; - GenerateSegment(colorRegion, polyline, tileKey.GetGlobalRect().Center(), staticGeometry, dynamicGeometry); - ASSERT_EQUAL(staticGeometry.size(), dynamicGeometry.size(), ()); + if ((staticGeometry.size() + dynamicGeometry.size()) == 0) + continue; - if ((staticGeometry.size() + dynamicGeometry.size()) == 0) - continue; + glsl::vec2 const uv = glsl::ToVec2(colorRegion.GetTexRect().Center()); + drape_ptr handle = make_unique_dp(sid, g.m_roadClass, g.m_polyline.GetLimitRect(), uv, + staticGeometry.size()); - glsl::vec2 const uv = glsl::ToVec2(colorRegion.GetTexRect().Center()); - drape_ptr handle = make_unique_dp(it->first, uv, staticGeometry.size()); + dp::AttributeProvider provider(2 /* stream count */, staticGeometry.size()); + provider.InitStream(0 /* stream index */, GetTrafficStaticBindingInfo(), make_ref(staticGeometry.data())); + provider.InitStream(1 /* stream index */, GetTrafficDynamicBindingInfo(), make_ref(dynamicGeometry.data())); + batcher->InsertTriangleList(state, make_ref(&provider), move(handle)); + } + } - dp::AttributeProvider provider(2 /* stream count */, staticGeometry.size()); - provider.InitStream(0 /* stream index */, GetTrafficStaticBindingInfo(), make_ref(staticGeometry.data())); - provider.InitStream(1 /* stream index */, GetTrafficDynamicBindingInfo(), make_ref(dynamicGeometry.data())); - batcher->InsertTriangleList(state, make_ref(&provider), move(handle)); + for (auto const & roadClass : roadClasses) + m_batchersPool->ReleaseBatcher(TrafficBatcherKey(geomIt->first, tileKey, roadClass)); } - - for (auto const & segmentPair : s.second) - m_batchersPool->ReleaseBatcher(TrafficBatcherKey(segmentPair.first->first.m_mwmId, tileKey)); } GLFunctions::glFlush(); } +bool TrafficGenerator::UpdateColoring(TrafficSegmentsColoring const & coloring) +{ + bool hasNew = false; + for (auto it = coloring.begin(); it != coloring.end(); ++it) + { + if (!hasNew && m_coloring.find(it->first) == m_coloring.end()) + hasNew = true; + m_coloring[it->first] = it->second; + } + return hasNew; +} + +void TrafficGenerator::ClearCache() +{ + m_colorsCacheValid = false; + m_coloring.clear(); +} + +void TrafficGenerator::ClearCache(MwmSet::MwmId const & mwmId) +{ + m_coloring.erase(mwmId); +} + +void TrafficGenerator::FlushGeometry(TrafficBatcherKey const & key, dp::GLState const & state, + drape_ptr && buffer) +{ + TrafficRenderData renderData(state); + renderData.m_bucket = move(buffer); + renderData.m_mwmId = key.m_mwmId; + renderData.m_tileKey = key.m_tileKey; + m_flushRenderDataFn(move(renderData)); +} + void TrafficGenerator::GenerateSegment(dp::TextureManager::ColorRegion const & colorRegion, m2::PolylineD const & polyline, m2::PointD const & tileCenter, - vector & staticGeometry, + bool generateCaps, vector & staticGeometry, vector & dynamicGeometry) { vector const & path = polyline.GetPoints(); @@ -339,7 +334,7 @@ void TrafficGenerator::GenerateSegment(dp::TextureManager::ColorRegion const & c } // Generate caps. - if (firstFilled) + if (generateCaps && firstFilled) { int const kSegmentsCount = 4; vector normals; diff --git a/drape_frontend/traffic_generator.hpp b/drape_frontend/traffic_generator.hpp index 9b4bb35d4b..3703285bc6 100644 --- a/drape_frontend/traffic_generator.hpp +++ b/drape_frontend/traffic_generator.hpp @@ -26,6 +26,18 @@ namespace df { +enum class RoadClass : uint8_t +{ + Class0, + Class1, + Class2 +}; + +int constexpr kRoadClass0ZoomLevel = 10; +int constexpr kRoadClass1ZoomLevel = 12; +int constexpr kRoadClass2ZoomLevel = 14; +int constexpr kOutlineMinZoomLevel = 13; + struct TrafficSegmentID { MwmSet::MwmId m_mwmId; @@ -52,20 +64,22 @@ struct TrafficSegmentID inline bool operator!=(TrafficSegmentID const & r) const { return !(*this == r); } }; -using TrafficSegmentsGeometry = vector>; - -struct TrafficSegmentColoring +struct TrafficSegmentGeometry { - TrafficSegmentID m_id; - traffic::SpeedGroup m_speedGroup; + m2::PolylineD m_polyline; + RoadClass m_roadClass; - TrafficSegmentColoring(TrafficSegmentID const & id, traffic::SpeedGroup const & speedGroup) - : m_id(id) - , m_speedGroup(speedGroup) + TrafficSegmentGeometry(m2::PolylineD && polyline, RoadClass const & roadClass) + : m_polyline(move(polyline)) + , m_roadClass(roadClass) {} }; -using TrafficSegmentsColoring = vector; +using TrafficSegmentsGeometry = map>>; +using TrafficSegmentsColoring = map; + +class TrafficHandle; struct TrafficRenderData { @@ -73,6 +87,9 @@ struct TrafficRenderData drape_ptr m_bucket; TileKey m_tileKey; MwmSet::MwmId m_mwmId; + m2::RectD m_boundingBox; + vector m_handles; + TrafficRenderData(dp::GLState const & state) : m_state(state) {} }; @@ -108,7 +125,9 @@ class TrafficHandle : public dp::OverlayHandle using TBase = dp::OverlayHandle; public: - TrafficHandle(TrafficSegmentID const & segmentId, glsl::vec2 const & texCoord, size_t verticesCount); + TrafficHandle(traffic::TrafficInfo::RoadSegmentId const & segmentId, RoadClass const & roadClass, + m2::RectD const & boundingBox, glsl::vec2 const & texCoord, + size_t verticesCount); void GetAttributeMutation(ref_ptr mutator) const override; bool Update(ScreenBase const & screen) override; @@ -117,11 +136,15 @@ public: void GetPixelShape(ScreenBase const & screen, bool perspective, Rects & rects) const override; void SetTexCoord(glsl::vec2 const & texCoord); - TrafficSegmentID GetSegmentId() const; + traffic::TrafficInfo::RoadSegmentId const & GetSegmentId() const; + RoadClass const & GetRoadClass() const; + m2::RectD const & GetBoundingBox() const; private: - TrafficSegmentID m_segmentId; + traffic::TrafficInfo::RoadSegmentId m_segmentId; + RoadClass m_roadClass; vector m_buffer; + m2::RectD m_boundingBox; mutable bool m_needUpdate; }; @@ -139,12 +162,9 @@ public: void Init(); void ClearGLDependentResources(); - void AddSegment(TrafficSegmentID const & segmentId, m2::PolylineD const & polyline); - - TrafficSegmentsColoring GetSegmentsToUpdate(TrafficSegmentsColoring const & trafficColoring) const; - - void GetTrafficGeom(ref_ptr textures, - TrafficSegmentsColoring const & trafficColoring); + void FlushSegmentsGeometry(TileKey const & tileKey, TrafficSegmentsGeometry const & geom, + ref_ptr textures); + bool UpdateColoring(TrafficSegmentsColoring const & coloring); void ClearCache(); void ClearCache(MwmSet::MwmId const & mwmId); @@ -156,13 +176,15 @@ private: struct TrafficBatcherKey { TrafficBatcherKey() = default; - TrafficBatcherKey(MwmSet::MwmId const & mwmId, TileKey const & tileKey) + TrafficBatcherKey(MwmSet::MwmId const & mwmId, TileKey const & tileKey, RoadClass const & roadClass) : m_mwmId(mwmId) , m_tileKey(tileKey) + , m_roadClass(roadClass) {} MwmSet::MwmId m_mwmId; TileKey m_tileKey; + RoadClass m_roadClass; }; struct TrafficBatcherKeyComparator @@ -170,24 +192,26 @@ private: bool operator() (TrafficBatcherKey const & lhs, TrafficBatcherKey const & rhs) const { if (lhs.m_mwmId == rhs.m_mwmId) - return lhs.m_tileKey < rhs.m_tileKey; + { + if (lhs.m_tileKey.EqualStrict(rhs.m_tileKey)) + return lhs.m_roadClass < rhs.m_roadClass; + return lhs.m_tileKey.LessStrict(rhs.m_tileKey); + } return lhs.m_mwmId < rhs.m_mwmId; } }; - using TSegmentCollection = map; - void GenerateSegment(dp::TextureManager::ColorRegion const & colorRegion, m2::PolylineD const & polyline, m2::PointD const & tileCenter, - vector & staticGeometry, + bool generateCaps, vector & staticGeometry, vector & dynamicGeometry); void FillColorsCache(ref_ptr textures); - void FlushGeometry(TrafficBatcherKey const & key, dp::GLState const & state, drape_ptr && buffer); + void FlushGeometry(TrafficBatcherKey const & key, dp::GLState const & state, + drape_ptr && buffer); - TSegmentCollection m_segments; + TrafficSegmentsColoring m_coloring; - set m_segmentsCache; array(traffic::SpeedGroup::Count)> m_colorsCache; bool m_colorsCacheValid = false; bool m_colorsCacheRefreshed = false; diff --git a/drape_frontend/traffic_renderer.cpp b/drape_frontend/traffic_renderer.cpp index 70864ea21d..7d9ed2b914 100644 --- a/drape_frontend/traffic_renderer.cpp +++ b/drape_frontend/traffic_renderer.cpp @@ -19,8 +19,8 @@ namespace df namespace { -int const kMinVisibleZoomLevel = 10; int const kMinVisibleArrowZoomLevel = 16; +int const kRoadClass2MinVisibleArrowZoomLevel = 17; float const kTrafficArrowAspect = 24.0f / 8.0f; @@ -29,63 +29,133 @@ float const kLeftWidthInPixel[] = // 1 2 3 4 5 6 7 8 9 10 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, //11 12 13 14 15 16 17 18 19 20 - 0.75f, 0.75f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 5.0f, 8.0f + 0.75f, 0.75f, 0.75f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 5.0f, 8.0f }; float const kRightWidthInPixel[] = { // 1 2 3 4 5 6 7 8 9 10 - 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 4.0f, 4.0f, + 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 3.0f, 4.0f, //11 12 13 14 15 16 17 18 19 20 4.0f, 4.0f, 4.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 5.0f, 8.0f }; -float CalculateHalfWidth(ScreenBase const & screen, bool left) +float const kRoadClass1WidthScalar[] = +{ + // 1 2 3 4 5 6 7 8 9 10 + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + //11 12 13 14 15 16 17 18 19 20 + 0.0f, 0.2f, 0.3f, 0.6f, 0.8f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f +}; + +float const kRoadClass2WidthScalar[] = +{ + // 1 2 3 4 5 6 7 8 9 10 + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + //11 12 13 14 15 16 17 18 19 20 + 0.0f, 0.0f, 0.0f, 0.2f, 0.3f, 0.5f, 0.7f, 0.8f, 0.9f, 1.0f +}; + +float CalculateHalfWidth(ScreenBase const & screen, RoadClass const & roadClass, bool left) { double const zoomLevel = GetZoomLevel(screen.GetScale()); double zoom = trunc(zoomLevel); int const index = zoom - 1.0; float const lerpCoef = zoomLevel - zoom; + float const * widthScalar = nullptr; + if (roadClass == RoadClass::Class1) + widthScalar = kRoadClass1WidthScalar; + else if (roadClass == RoadClass::Class2) + widthScalar = kRoadClass2WidthScalar; + float const * halfWidth = left ? kLeftWidthInPixel : kRightWidthInPixel; float radius = 0.0f; if (index < scales::UPPER_STYLE_SCALE) + { radius = halfWidth[index] + lerpCoef * (halfWidth[index + 1] - halfWidth[index]); + if (widthScalar != nullptr) + radius *= (widthScalar[index] + lerpCoef * (widthScalar[index + 1] - widthScalar[index])); + } else + { radius = halfWidth[scales::UPPER_STYLE_SCALE]; + if (widthScalar != nullptr) + radius *= widthScalar[scales::UPPER_STYLE_SCALE]; + } return radius * VisualParams::Instance().GetVisualScale(); } } // namespace -void TrafficRenderer::AddRenderData(ref_ptr mng, - TrafficRenderData && renderData) +void TrafficRenderer::AddRenderData(ref_ptr mng, TrafficRenderData && renderData) { - m_renderData.emplace_back(move(renderData)); - - ref_ptr program = mng->GetProgram(m_renderData.back().m_state.GetProgramIndex()); - program->Bind(); - m_renderData.back().m_bucket->GetBuffer()->Build(program); - - for (size_t j = 0; j < m_renderData.back().m_bucket->GetOverlayHandlesCount(); j++) + // Remove obsolete render data. + TileKey const tileKey(renderData.m_tileKey); + m_renderData.erase(remove_if(m_renderData.begin(), m_renderData.end(), [&tileKey](TrafficRenderData const & rd) { - TrafficHandle * handle = static_cast(m_renderData.back().m_bucket->GetOverlayHandle(j).get()); - m_handles.insert(make_pair(handle->GetSegmentId(), handle)); + return tileKey == rd.m_tileKey && rd.m_tileKey.m_generation < tileKey.m_generation; + }), m_renderData.end()); + + // Add new render data. + m_renderData.emplace_back(move(renderData)); + TrafficRenderData & rd = m_renderData.back(); + + ref_ptr program = mng->GetProgram(rd.m_state.GetProgramIndex()); + program->Bind(); + rd.m_bucket->GetBuffer()->Build(program); + + rd.m_handles.reserve(rd.m_bucket->GetOverlayHandlesCount()); + for (size_t j = 0; j < rd.m_bucket->GetOverlayHandlesCount(); j++) + { + TrafficHandle * handle = static_cast(rd.m_bucket->GetOverlayHandle(j).get()); + rd.m_handles.emplace_back(handle); + rd.m_boundingBox.Add(handle->GetBoundingBox()); } } +void TrafficRenderer::OnUpdateViewport(CoverageResult const & coverage, int currentZoomLevel, + buffer_vector const & tilesToDelete) +{ + m_renderData.erase(remove_if(m_renderData.begin(), m_renderData.end(), + [&coverage, ¤tZoomLevel, &tilesToDelete](TrafficRenderData const & rd) + { + return rd.m_tileKey.m_zoomLevel == currentZoomLevel && + (rd.m_tileKey.m_x < coverage.m_minTileX || rd.m_tileKey.m_x >= coverage.m_maxTileX || + rd.m_tileKey.m_y < coverage.m_minTileY || rd.m_tileKey.m_y >= coverage.m_maxTileY || + find(tilesToDelete.begin(), tilesToDelete.end(), rd.m_tileKey) != tilesToDelete.end()); + }), m_renderData.end()); +} + +void TrafficRenderer::OnGeometryReady(int currentZoomLevel) +{ + m_renderData.erase(remove_if(m_renderData.begin(), m_renderData.end(), + [¤tZoomLevel](TrafficRenderData const & rd) + { + return rd.m_tileKey.m_zoomLevel != currentZoomLevel; + }), m_renderData.end()); +} + void TrafficRenderer::UpdateTraffic(TrafficSegmentsColoring const & trafficColoring) { - for (auto const & segment : trafficColoring) + for (TrafficRenderData & renderData : m_renderData) { - auto it = m_texCoords.find(static_cast(segment.m_speedGroup)); - if (it == m_texCoords.end()) + auto coloringIt = trafficColoring.find(renderData.m_mwmId); + if (coloringIt == trafficColoring.end()) continue; - auto handleIt = m_handles.find(segment.m_id); - if (handleIt != m_handles.end()) - handleIt->second->SetTexCoord(it->second); + for (size_t i = 0; i < renderData.m_handles.size(); i++) + { + auto it = coloringIt->second.find(renderData.m_handles[i]->GetSegmentId()); + if (it != coloringIt->second.end()) + { + auto texCoordIt = m_texCoords.find(static_cast(it->second)); + if (texCoordIt == m_texCoords.end()) + continue; + renderData.m_handles[i]->SetTexCoord(texCoordIt->second); + } + } } } @@ -93,15 +163,55 @@ void TrafficRenderer::RenderTraffic(ScreenBase const & screen, int zoomLevel, ref_ptr mng, dp::UniformValuesStorage const & commonUniforms) { - if (m_renderData.empty() || zoomLevel < kMinVisibleZoomLevel) + if (m_renderData.empty() || zoomLevel < kRoadClass0ZoomLevel) return; - float const pixelHalfWidth = CalculateHalfWidth(screen, true /* left */); - float const invPixelLength = 1.0f / (2.0f * pixelHalfWidth * kTrafficArrowAspect); + m2::RectD const clipRect = screen.ClipRect(); GLFunctions::glClearDepth(); for (TrafficRenderData & renderData : m_renderData) { + if (!clipRect.IsIntersect(renderData.m_boundingBox)) + continue; + + // Filter by road class. + float leftPixelHalfWidth = 0.0f; + float invLeftPixelLength = 0.0f; + float rightPixelHalfWidth = 0.0f; + int minVisibleArrowZoomLevel = kMinVisibleArrowZoomLevel; + float outline = 0.0f; + + if (renderData.m_bucket->GetOverlayHandlesCount() > 0) + { + TrafficHandle * handle = static_cast(renderData.m_bucket->GetOverlayHandle(0).get()); + ASSERT(handle != nullptr, ()); + + int visibleZoomLevel = kRoadClass0ZoomLevel; + if (handle->GetRoadClass() == RoadClass::Class0) + { + outline = (zoomLevel <= kOutlineMinZoomLevel ? 1.0 : 0.0); + } + else if (handle->GetRoadClass() == RoadClass::Class1) + { + visibleZoomLevel = kRoadClass1ZoomLevel; + } + else if (handle->GetRoadClass() == RoadClass::Class2) + { + visibleZoomLevel = kRoadClass2ZoomLevel; + minVisibleArrowZoomLevel = kRoadClass2MinVisibleArrowZoomLevel; + } + + if (zoomLevel < visibleZoomLevel) + continue; + + leftPixelHalfWidth = CalculateHalfWidth(screen, handle->GetRoadClass(), true /* left */); + invLeftPixelLength = 1.0f / (2.0f * leftPixelHalfWidth * kTrafficArrowAspect); + rightPixelHalfWidth = CalculateHalfWidth(screen, handle->GetRoadClass(), false /* left */); + float const kEps = 1e-5; + if (fabs(leftPixelHalfWidth) < kEps && fabs(rightPixelHalfWidth) < kEps) + continue; + } + ref_ptr program = mng->GetProgram(renderData.m_state.GetProgramIndex()); program->Bind(); dp::ApplyState(renderData.m_state, program); @@ -110,8 +220,9 @@ void TrafficRenderer::RenderTraffic(ScreenBase const & screen, int zoomLevel, math::Matrix const mv = renderData.m_tileKey.GetTileBasedModelView(screen); uniforms.SetMatrix4x4Value("modelView", mv.m_data); uniforms.SetFloatValue("u_opacity", 1.0f); - uniforms.SetFloatValue("u_trafficParams", pixelHalfWidth, CalculateHalfWidth(screen, false /* left */), - invPixelLength, zoomLevel >= kMinVisibleArrowZoomLevel ? 1.0f : 0.0f); + uniforms.SetFloatValue("u_outline", outline); + uniforms.SetFloatValue("u_trafficParams", leftPixelHalfWidth, rightPixelHalfWidth, + invLeftPixelLength, zoomLevel >= minVisibleArrowZoomLevel ? 1.0f : 0.0f); dp::ApplyUniforms(uniforms, program); renderData.m_bucket->Render(renderData.m_state.GetDrawAsLine()); @@ -126,7 +237,6 @@ void TrafficRenderer::SetTexCoords(TrafficTexCoords && texCoords) void TrafficRenderer::ClearGLDependentResources() { m_renderData.clear(); - m_handles.clear(); m_texCoords.clear(); } diff --git a/drape_frontend/traffic_renderer.hpp b/drape_frontend/traffic_renderer.hpp index d7d38af220..4544d1a9ce 100644 --- a/drape_frontend/traffic_renderer.hpp +++ b/drape_frontend/traffic_renderer.hpp @@ -1,6 +1,7 @@ #pragma once #include "drape_frontend/traffic_generator.hpp" +#include "drape_frontend/tile_utils.hpp" #include "drape/gpu_program_manager.hpp" #include "drape/pointers.hpp" @@ -9,7 +10,6 @@ #include "geometry/screenbase.hpp" #include "geometry/spline.hpp" -#include "std/map.hpp" #include "std/vector.hpp" namespace df @@ -34,10 +34,13 @@ public: void ClearGLDependentResources(); void Clear(MwmSet::MwmId const & mwmId); + void OnUpdateViewport(CoverageResult const & coverage, int currentZoomLevel, + buffer_vector const & tilesToDelete); + void OnGeometryReady(int currentZoomLevel); + private: vector m_renderData; TrafficTexCoords m_texCoords; - map m_handles; }; } // namespace df diff --git a/geometry/polyline2d.hpp b/geometry/polyline2d.hpp index 86dfe69972..abe2459ebe 100644 --- a/geometry/polyline2d.hpp +++ b/geometry/polyline2d.hpp @@ -115,7 +115,7 @@ public: return m_points.back(); } - Polyline ExtractSegment(size_t segmentIndex, bool reversed) + Polyline ExtractSegment(size_t segmentIndex, bool reversed) const { if (segmentIndex + 1 >= m_points.size()) return Polyline(); diff --git a/map/framework.cpp b/map/framework.cpp index bb334c421b..5b1f751771 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -121,6 +121,7 @@ char const kMapStyleKey[] = "MapStyleKeyV1"; char const kAllow3dKey[] = "Allow3d"; char const kAllow3dBuildingsKey[] = "Buildings3d"; char const kAllowAutoZoom[] = "AutoZoom"; +char const kTrafficEnabledKey[] = "TrafficEnabled"; double const kDistEqualQueryMeters = 100.0; @@ -343,8 +344,7 @@ Framework::Framework() , m_isRenderingEnabled(true) , m_trackingReporter(platform::CreateSocket(), TRACKING_REALTIME_HOST, TRACKING_REALTIME_PORT, tracking::Reporter::kPushDelayMs) - , m_trafficManager(m_model.GetIndex(), bind(&Framework::GetMwmsByRect, this, _1), - kMaxTrafficCacheSizeBytes) + , m_trafficManager(bind(&Framework::GetMwmsByRect, this, _1), kMaxTrafficCacheSizeBytes) , m_displacementModeManager([this](bool show) { int const mode = show ? dp::displacement::kHotelMode : dp::displacement::kDefaultMode; CallDrapeFunction(bind(&df::DrapeEngine::SetDisplacementMode, _1, mode)); @@ -1605,6 +1605,8 @@ void Framework::CreateDrapeEngine(ref_ptr contextFactory, Load3dMode(allow3d, allow3dBuildings); bool const isAutozoomEnabled = LoadAutoZoom(); + bool const trafficEnabled = LoadTrafficEnabled(); + m_trafficManager.SetEnabled(trafficEnabled); df::DrapeEngine::Params p(contextFactory, make_ref(&m_stringsBundle), @@ -1612,7 +1614,7 @@ void Framework::CreateDrapeEngine(ref_ptr contextFactory, df::MapDataProvider(idReadFn, featureReadFn, isCountryLoadedByNameFn, updateCurrentCountryFn), params.m_visualScale, move(params.m_widgetsInitInfo), make_pair(params.m_initialMyPositionState, params.m_hasMyPositionState), - allow3dBuildings, params.m_isChoosePositionMode, + allow3dBuildings, trafficEnabled, params.m_isChoosePositionMode, params.m_isChoosePositionMode, GetSelectedFeatureTriangles(), params.m_isFirstLaunch, m_routingSession.IsActive() && m_routingSession.IsFollowing(), isAutozoomEnabled); @@ -2646,6 +2648,18 @@ void Framework::Load3dMode(bool & allow3d, bool & allow3dBuildings) allow3dBuildings = true; } +bool Framework::LoadTrafficEnabled() +{ + bool enabled = true; //TODO(@rokuz): temporary. It has to be false by default. + settings::Get(kTrafficEnabledKey, enabled); + return enabled; +} + +void Framework::SaveTrafficEnabled(bool trafficEnabled) +{ + settings::Set(kTrafficEnabledKey, trafficEnabled); +} + bool Framework::LoadAutoZoom() { bool allowAutoZoom = true; diff --git a/map/framework.hpp b/map/framework.hpp index 338eacc328..4f5f689e41 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -773,6 +773,9 @@ public: void AllowAutoZoom(bool allowAutoZoom); void SaveAutoZoom(bool allowAutoZoom); + bool LoadTrafficEnabled(); + void SaveTrafficEnabled(bool trafficEnabled); + /// \returns true if altitude information along |m_route| is available and /// false otherwise. bool HasRouteAltitude() const; diff --git a/map/traffic_manager.cpp b/map/traffic_manager.cpp index a614608094..bd3ff9fdd9 100644 --- a/map/traffic_manager.cpp +++ b/map/traffic_manager.cpp @@ -5,20 +5,16 @@ #include "drape_frontend/drape_engine.hpp" #include "drape_frontend/visual_params.hpp" +#include "indexer/ftypes_matcher.hpp" #include "indexer/scales.hpp" namespace { auto const kUpdateInterval = minutes(1); - -int const kMinTrafficZoom = 10; - } // namespace -TrafficManager::TrafficManager(Index const & index, GetMwmsByRectFn const & getMwmsByRectFn, - size_t maxCacheSizeBytes) - : m_isEnabled(true) // TODO: true is temporary - , m_index(index) +TrafficManager::TrafficManager(GetMwmsByRectFn const & getMwmsByRectFn, size_t maxCacheSizeBytes) + : m_isEnabled(false) , m_getMwmsByRectFn(getMwmsByRectFn) , m_maxCacheSizeBytes(maxCacheSizeBytes) , m_currentCacheSizeBytes(0) @@ -41,6 +37,8 @@ TrafficManager::~TrafficManager() void TrafficManager::SetEnabled(bool enabled) { m_isEnabled = enabled; + if (m_drapeEngine != nullptr) + m_drapeEngine->EnableTraffic(enabled); } void TrafficManager::SetDrapeEngine(ref_ptr engine) @@ -63,7 +61,7 @@ void TrafficManager::UpdateViewport(ScreenBase const & screen) if (!m_isEnabled) return; - if (df::GetZoomLevel(screen.GetScale()) < kMinTrafficZoom) + if (df::GetZoomLevel(screen.GetScale()) < df::kRoadClass0ZoomLevel) return; // Request traffic. @@ -97,57 +95,6 @@ void TrafficManager::UpdateMyPosition(MyPosition const & myPosition) // 3. Do all routing stuff. } -void TrafficManager::CalculateSegmentsGeometry(traffic::TrafficInfo const & trafficInfo, - df::TrafficSegmentsGeometry & output) const -{ - size_t const coloringSize = trafficInfo.GetColoring().size(); - output.reserve(coloringSize); - - vector features; - features.reserve(coloringSize); - for (auto const & c : trafficInfo.GetColoring()) - features.emplace_back(trafficInfo.GetMwmId(), c.first.m_fid); - - int constexpr kScale = scales::GetUpperScale(); - unordered_map polylines; - auto featureReader = [&polylines](FeatureType & ft) - { - uint32_t const fid = ft.GetID().m_index; - if (polylines.find(fid) != polylines.end()) - return; - - if (routing::IsRoad(feature::TypesHolder(ft))) - { - m2::PolylineD polyline; - ft.ForEachPoint([&polyline](m2::PointD const & pt) { polyline.Add(pt); }, kScale); - if (polyline.GetSize() > 1) - polylines[fid] = polyline; - } - }; - m_index.ReadFeatures(featureReader, features); - - for (auto const & c : trafficInfo.GetColoring()) - { - auto it = polylines.find(c.first.m_fid); - if (it == polylines.end()) - continue; - bool const isReversed = (c.first.m_dir == traffic::TrafficInfo::RoadSegmentId::kReverseDirection); - m2::PolylineD polyline = it->second.ExtractSegment(c.first.m_idx, isReversed); - if (polyline.GetSize() > 1) - output.emplace_back(df::TrafficSegmentID(trafficInfo.GetMwmId(), c.first), move(polyline)); - } -} - -void TrafficManager::CalculateSegmentsColoring(traffic::TrafficInfo const & trafficInfo, - df::TrafficSegmentsColoring & output) const -{ - for (auto const & c : trafficInfo.GetColoring()) - { - df::TrafficSegmentID const sid (trafficInfo.GetMwmId(), c.first); - output.emplace_back(sid, c.second); - } -} - void TrafficManager::ThreadRoutine() { vector mwms; @@ -227,25 +174,17 @@ void TrafficManager::OnTrafficDataResponse(traffic::TrafficInfo const & info) if (it == m_mwmInfos.end()) return; - // Cache geometry for rendering if it's necessary. - if (!it->second.m_isLoaded) - { - df::TrafficSegmentsGeometry geometry; - CalculateSegmentsGeometry(info, geometry); - it->second.m_isLoaded = true; - m_drapeEngine->CacheTrafficSegmentsGeometry(geometry); - } + // Update cache. + size_t constexpr kElementSize = sizeof(traffic::TrafficInfo::RoadSegmentId) + sizeof(traffic::SpeedGroup); + size_t const dataSize = info.GetColoring().size() * kElementSize; + it->second.m_isLoaded = true; + m_currentCacheSizeBytes += (dataSize - it->second.m_dataSize); + it->second.m_dataSize = dataSize; + CheckCacheSize(); // Update traffic colors. df::TrafficSegmentsColoring coloring; - CalculateSegmentsColoring(info, coloring); - - size_t dataSize = coloring.size() * sizeof(df::TrafficSegmentColoring); - it->second.m_dataSize = dataSize; - m_currentCacheSizeBytes += dataSize; - - CheckCacheSize(); - + coloring[info.GetMwmId()] = info.GetColoring(); m_drapeEngine->UpdateTraffic(coloring); } diff --git a/map/traffic_manager.hpp b/map/traffic_manager.hpp index 9a209fe8a0..ae7838251c 100644 --- a/map/traffic_manager.hpp +++ b/map/traffic_manager.hpp @@ -42,8 +42,7 @@ public: using GetMwmsByRectFn = function(m2::RectD const &)>; - TrafficManager(Index const & index, GetMwmsByRectFn const & getMwmsByRectFn, - size_t maxCacheSizeBytes); + TrafficManager(GetMwmsByRectFn const & getMwmsByRectFn, size_t maxCacheSizeBytes); ~TrafficManager(); void SetEnabled(bool enabled); @@ -56,11 +55,6 @@ public: void SetDrapeEngine(ref_ptr engine); private: - void CalculateSegmentsGeometry(traffic::TrafficInfo const & trafficInfo, - df::TrafficSegmentsGeometry & output) const; - void CalculateSegmentsColoring(traffic::TrafficInfo const & trafficInfo, - df::TrafficSegmentsColoring & output) const; - void ThreadRoutine(); bool WaitForRequest(vector & mwms); void RequestTrafficData(); @@ -70,7 +64,6 @@ private: bool m_isEnabled; - Index const & m_index; GetMwmsByRectFn m_getMwmsByRectFn; ref_ptr m_drapeEngine;