bool CheckMinScale(ScreenBase const & screen) { m2::RectD const & r = screen.ClipRect(); m2::RectD const & worldR = df::GetWorldRect(); return (r.SizeX() <= worldR.SizeX() || r.SizeY() <= worldR.SizeY()); }
bool CheckBorders(ScreenBase const & screen) { m2::RectD const & r = screen.ClipRect(); m2::RectD const & worldR = df::GetWorldRect(); return (r.IsRectInside(worldR) || worldR.IsRectInside(r)); }
bool Navigator::CheckBorders(ScreenBase const & screen) const { m2::RectD const & r = screen.ClipRect(); m2::RectD const & worldR = m_scales.GetWorldRect(); return (r.IsRectInside(worldR) || worldR.IsRectInside(r)); }
bool Navigator::CheckMinScale(ScreenBase const & screen) const { m2::RectD const & r = screen.ClipRect(); m2::RectD const & worldR = m_scales.GetWorldRect(); return (r.SizeX() <= worldR.SizeX() || r.SizeY() <= worldR.SizeY()); }
ScreenBase const ScaleInto(ScreenBase const & screen, m2::RectD boundRect) { ReduceRectHack(boundRect); ScreenBase res = screen; double scale = 1; m2::RectD clipRect = res.ClipRect(); ASSERT(boundRect.IsPointInside(clipRect.Center()), ("center point should be inside boundRect")); if (clipRect.minX() < boundRect.minX()) { double k = (boundRect.minX() - clipRect.Center().x) / (clipRect.minX() - clipRect.Center().x); scale /= k; clipRect.Scale(k); } if (clipRect.maxX() > boundRect.maxX()) { double k = (boundRect.maxX() - clipRect.Center().x) / (clipRect.maxX() - clipRect.Center().x); scale /= k; clipRect.Scale(k); } if (clipRect.minY() < boundRect.minY()) { double k = (boundRect.minY() - clipRect.Center().y) / (clipRect.minY() - clipRect.Center().y); scale /= k; clipRect.Scale(k); } if (clipRect.maxY() > boundRect.maxY()) { double k = (boundRect.maxY() - clipRect.Center().y) / (clipRect.maxY() - clipRect.Center().y); scale /= k; clipRect.Scale(k); } res.Scale(scale); res.SetOrg(clipRect.Center()); return res; }
ScreenBase const ShrinkInto(ScreenBase const & screen, m2::RectD boundRect) { ReduceRectHack(boundRect); ScreenBase res = screen; m2::RectD clipRect = res.ClipRect(); if (clipRect.minX() < boundRect.minX()) clipRect.Offset(boundRect.minX() - clipRect.minX(), 0); if (clipRect.maxX() > boundRect.maxX()) clipRect.Offset(boundRect.maxX() - clipRect.maxX(), 0); if (clipRect.minY() < boundRect.minY()) clipRect.Offset(0, boundRect.minY() - clipRect.minY()); if (clipRect.maxY() > boundRect.maxY()) clipRect.Offset(0, boundRect.maxY() - clipRect.maxY()); res.SetOrg(clipRect.Center()); // This assert fails near x = 180 (Philipines). //ASSERT ( boundRect.IsRectInside(res.ClipRect()), (clipRect, res.ClipRect()) ); return res; }
void BackendRenderer::AcceptMessage(ref_ptr<Message> message) { switch (message->GetType()) { case Message::UpdateReadManager: { TTilesCollection tiles = m_requestedTiles->GetTiles(); if (!tiles.empty()) { ScreenBase const screen = m_requestedTiles->GetScreen(); m_readManager->UpdateCoverage(screen, tiles, m_texMng); gui::CountryStatusHelper & helper = gui::DrapeGui::Instance().GetCountryStatusHelper(); if ((*tiles.begin()).m_zoomLevel > scales::GetUpperWorldScale()) m_model.UpdateCountryIndex(helper.GetCountryIndex(), screen.ClipRect().Center()); else helper.Clear(); } break; } case Message::InvalidateReadManagerRect: { ref_ptr<InvalidateReadManagerRectMessage> msg = message; m_readManager->Invalidate(msg->GetTilesForInvalidate()); break; } case Message::CountryStatusRecache: { RecacheCountryStatus(); break; } case Message::GuiRecache: { ref_ptr<GuiRecacheMessage> msg = message; RecacheGui(msg->GetInitInfo(), msg->GetSizeInfoMap()); break; } case Message::GuiLayerLayout: { ref_ptr<GuiLayerLayoutMessage> msg = message; m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<GuiLayerLayoutMessage>(msg->AcceptLayoutInfo()), MessagePriority::Normal); RecacheCountryStatus(); break; } case Message::TileReadStarted: { m_batchersPool->ReserveBatcher(static_cast<ref_ptr<BaseTileMessage>>(message)->GetKey()); break; } case Message::TileReadEnded: { ref_ptr<TileReadEndMessage> msg = message; m_batchersPool->ReleaseBatcher(msg->GetKey()); break; } case Message::FinishReading: { ref_ptr<FinishReadingMessage> msg = message; m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<FinishReadingMessage>(move(msg->MoveTiles())), MessagePriority::Normal); break; } case Message::MapShapeReaded: { ref_ptr<MapShapeReadedMessage> msg = message; auto const & tileKey = msg->GetKey(); if (m_requestedTiles->CheckTileKey(tileKey) && m_readManager->CheckTileKey(tileKey)) { ref_ptr<dp::Batcher> batcher = m_batchersPool->GetTileBatcher(tileKey); for (drape_ptr<MapShape> const & shape : msg->GetShapes()) shape->Draw(batcher, m_texMng); } break; } case Message::UpdateUserMarkLayer: { ref_ptr<UpdateUserMarkLayerMessage> msg = message; TileKey const & key = msg->GetKey(); UserMarksProvider const * marksProvider = msg->StartProcess(); if (marksProvider->IsDirty()) { m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<ClearUserMarkLayerMessage>(key), MessagePriority::Normal); m_batchersPool->ReserveBatcher(key); CacheUserMarks(marksProvider, m_batchersPool->GetTileBatcher(key), m_texMng); m_batchersPool->ReleaseBatcher(key); } msg->EndProcess(); break; } case Message::CountryInfoUpdate: { ref_ptr<CountryInfoUpdateMessage> msg = message; gui::CountryStatusHelper & helper = gui::DrapeGui::Instance().GetCountryStatusHelper(); if (!msg->NeedShow()) { // Country is already loaded, so there is no need to show status GUI // even if this country is updating. helper.Clear(); } else { gui::CountryInfo const & info = msg->GetCountryInfo(); if (msg->IsCurrentCountry() || helper.GetCountryIndex() == info.m_countryIndex) { helper.SetCountryInfo(info); } } break; } case Message::AddRoute: { ref_ptr<AddRouteMessage> msg = message; m_routeBuilder->Build(msg->GetRoutePolyline(), msg->GetTurns(), msg->GetColor(), m_texMng); break; } case Message::CacheRouteSign: { ref_ptr<CacheRouteSignMessage> msg = message; m_routeBuilder->BuildSign(msg->GetPosition(), msg->IsStart(), msg->IsValid(), m_texMng); break; } case Message::RemoveRoute: { ref_ptr<RemoveRouteMessage> msg = message; // we have to resend the message to FR, because it guaranties that // RemoveRouteMessage will be precessed after FlushRouteMessage m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<RemoveRouteMessage>(msg->NeedDeactivateFollowing()), MessagePriority::Normal); break; } case Message::InvalidateTextures: { m_texMng->Invalidate(VisualParams::Instance().GetResourcePostfix()); RecacheMyPosition(); break; } case Message::StopRendering: { ProcessStopRenderingMessage(); break; } default: ASSERT(false, ()); break; } }
void BackendRenderer::AcceptMessage(ref_ptr<Message> message) { switch (message->GetType()) { case Message::UpdateReadManager: { TTilesCollection tiles = m_requestedTiles->GetTiles(); if (!tiles.empty()) { ScreenBase const screen = m_requestedTiles->GetScreen(); bool const have3dBuildings = m_requestedTiles->Have3dBuildings(); m_readManager->UpdateCoverage(screen, have3dBuildings, tiles, m_texMng); m_updateCurrentCountryFn(screen.ClipRect().Center(), (*tiles.begin()).m_zoomLevel); } break; } case Message::InvalidateReadManagerRect: { ref_ptr<InvalidateReadManagerRectMessage> msg = message; if (msg->NeedInvalidateAll()) m_readManager->InvalidateAll(); else m_readManager->Invalidate(msg->GetTilesForInvalidate()); break; } case Message::ShowChoosePositionMark: { RecacheChoosePositionMark(); break; } case Message::GuiRecache: { ref_ptr<GuiRecacheMessage> msg = message; RecacheGui(msg->GetInitInfo(), msg->NeedResetOldGui()); #ifdef RENRER_DEBUG_INFO_LABELS RecacheDebugLabels(); #endif break; } case Message::GuiLayerLayout: { ref_ptr<GuiLayerLayoutMessage> msg = message; m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<GuiLayerLayoutMessage>(msg->AcceptLayoutInfo()), MessagePriority::Normal); break; } case Message::TileReadStarted: { ref_ptr<TileReadStartMessage> msg = message; m_batchersPool->ReserveBatcher(msg->GetKey()); break; } case Message::TileReadEnded: { ref_ptr<TileReadEndMessage> msg = message; m_batchersPool->ReleaseBatcher(msg->GetKey()); break; } case Message::FinishTileRead: { ref_ptr<FinishTileReadMessage> msg = message; m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<FinishTileReadMessage>(msg->MoveTiles()), MessagePriority::Normal); break; } case Message::FinishReading: { TOverlaysRenderData overlays; overlays.swap(m_overlays); if (!overlays.empty()) { m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<FlushOverlaysMessage>(move(overlays)), MessagePriority::Normal); } break; } case Message::MapShapesRecache: { RecacheMapShapes(); break; } case Message::MapShapeReaded: { ref_ptr<MapShapeReadedMessage> msg = message; auto const & tileKey = msg->GetKey(); if (m_requestedTiles->CheckTileKey(tileKey) && m_readManager->CheckTileKey(tileKey)) { ref_ptr<dp::Batcher> batcher = m_batchersPool->GetTileBatcher(tileKey); for (drape_ptr<MapShape> const & shape : msg->GetShapes()) { batcher->SetFeatureMinZoom(shape->GetFeatureMinZoom()); shape->Draw(batcher, m_texMng); } } break; } case Message::OverlayMapShapeReaded: { ref_ptr<OverlayMapShapeReadedMessage> msg = message; auto const & tileKey = msg->GetKey(); if (m_requestedTiles->CheckTileKey(tileKey) && m_readManager->CheckTileKey(tileKey)) { CleanupOverlays(tileKey); OverlayBatcher batcher(tileKey); for (drape_ptr<MapShape> const & shape : msg->GetShapes()) batcher.Batch(shape, m_texMng); TOverlaysRenderData renderData; batcher.Finish(renderData); if (!renderData.empty()) { m_overlays.reserve(m_overlays.size() + renderData.size()); move(renderData.begin(), renderData.end(), back_inserter(m_overlays)); } } break; } case Message::UpdateUserMarkLayer: { ref_ptr<UpdateUserMarkLayerMessage> msg = message; UserMarksProvider const * marksProvider = msg->StartProcess(); if (marksProvider->IsDirty()) { size_t const layerId = msg->GetLayerId(); m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<ClearUserMarkLayerMessage>(layerId), MessagePriority::Normal); TUserMarkShapes shapes = CacheUserMarks(marksProvider, m_texMng); m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<FlushUserMarksMessage>(layerId, move(shapes)), MessagePriority::Normal); } msg->EndProcess(); break; } case Message::AddRoute: { ref_ptr<AddRouteMessage> msg = message; m_routeBuilder->Build(msg->GetRoutePolyline(), msg->GetTurns(), msg->GetColor(), msg->GetPattern(), m_texMng, msg->GetRecacheId()); break; } case Message::CacheRouteSign: { ref_ptr<CacheRouteSignMessage> msg = message; m_routeBuilder->BuildSign(msg->GetPosition(), msg->IsStart(), msg->IsValid(), m_texMng, msg->GetRecacheId()); break; } case Message::CacheRouteArrows: { ref_ptr<CacheRouteArrowsMessage> msg = message; m_routeBuilder->BuildArrows(msg->GetRouteIndex(), msg->GetBorders(), m_texMng, msg->GetRecacheId()); break; } case Message::RemoveRoute: { ref_ptr<RemoveRouteMessage> msg = message; m_routeBuilder->ClearRouteCache(); // We have to resend the message to FR, because it guaranties that // RemoveRouteMessage will be processed after FlushRouteMessage. m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<RemoveRouteMessage>(msg->NeedDeactivateFollowing()), MessagePriority::Normal); break; } case Message::InvalidateTextures: { m_texMng->Invalidate(VisualParams::Instance().GetResourcePostfix()); RecacheMapShapes(); break; } case Message::CacheGpsTrackPoints: { ref_ptr<CacheGpsTrackPointsMessage> msg = message; drape_ptr<GpsTrackRenderData> data = make_unique_dp<GpsTrackRenderData>(); data->m_pointsCount = msg->GetPointsCount(); GpsTrackShape::Draw(m_texMng, *data.get()); m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<FlushGpsTrackPointsMessage>(move(data)), MessagePriority::Normal); break; } case Message::Allow3dBuildings: { ref_ptr<Allow3dBuildingsMessage> msg = message; m_readManager->Allow3dBuildings(msg->Allow3dBuildings()); break; } case Message::RequestSymbolsSize: { ref_ptr<RequestSymbolsSizeMessage> msg = message; auto const & symbols = msg->GetSymbols(); vector<m2::PointU> sizes(symbols.size()); for (size_t i = 0; i < symbols.size(); i++) { dp::TextureManager::SymbolRegion region; m_texMng->GetSymbolRegion(symbols[i], region); sizes[i] = region.GetPixelSize(); } msg->InvokeCallback(sizes); break; } case Message::AddTrafficSegments: { ref_ptr<AddTrafficSegmentsMessage> msg = message; for (auto const & segment : msg->GetSegments()) m_trafficGenerator->AddSegment(segment.first, segment.second); break; } case Message::UpdateTraffic: { ref_ptr<UpdateTrafficMessage> msg = message; auto segments = m_trafficGenerator->GetSegmentsToUpdate(msg->GetSegmentsData()); if (!segments.empty()) { m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<UpdateTrafficMessage>(segments), MessagePriority::Normal); } if (segments.size() < msg->GetSegmentsData().size()) { vector<TrafficRenderData> data; m_trafficGenerator->GetTrafficGeom(m_texMng, msg->GetSegmentsData(), data); m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<FlushTrafficDataMessage>(move(data)), MessagePriority::Normal); if (m_trafficGenerator->IsColorsCacheRefreshed()) { auto texCoords = m_trafficGenerator->ProcessCacheRefreshing(); m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<SetTrafficTexCoordsMessage>(move(texCoords)), MessagePriority::Normal); } } break; } case Message::DrapeApiAddLines: { ref_ptr<DrapeApiAddLinesMessage> msg = message; vector<drape_ptr<DrapeApiRenderProperty>> properties; m_drapeApiBuilder->BuildLines(msg->GetLines(), m_texMng, properties); m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<DrapeApiFlushMessage>(move(properties)), MessagePriority::Normal); break; } case Message::DrapeApiRemove: { ref_ptr<DrapeApiRemoveMessage> msg = message; m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp<DrapeApiRemoveMessage>(msg->GetId(), msg->NeedRemoveAll()), MessagePriority::Normal); break; } default: ASSERT(false, ()); break; } }
bool CanShrinkInto(ScreenBase const & screen, m2::RectD const & boundRect) { m2::RectD clipRect = screen.ClipRect(); return (boundRect.SizeX() >= clipRect.SizeX()) && (boundRect.SizeY() >= clipRect.SizeY()); }
ScreenBase const ShrinkAndScaleInto(ScreenBase const & screen, m2::RectD boundRect) { ReduceRectHack(boundRect); ScreenBase res = screen; m2::RectD globalRect = res.ClipRect(); m2::PointD newOrg = res.GetOrg(); double scale = 1; double offs = 0; if (globalRect.minX() < boundRect.minX()) { offs = boundRect.minX() - globalRect.minX(); globalRect.Offset(offs, 0); newOrg.x += offs; if (globalRect.maxX() > boundRect.maxX()) { double k = boundRect.SizeX() / globalRect.SizeX(); scale /= k; /// scaling always occur pinpointed to the rect center... globalRect.Scale(k); /// ...so we should shift a rect after scale globalRect.Offset(boundRect.minX() - globalRect.minX(), 0); } } if (globalRect.maxX() > boundRect.maxX()) { offs = boundRect.maxX() - globalRect.maxX(); globalRect.Offset(offs, 0); newOrg.x += offs; if (globalRect.minX() < boundRect.minX()) { double k = boundRect.SizeX() / globalRect.SizeX(); scale /= k; globalRect.Scale(k); globalRect.Offset(boundRect.maxX() - globalRect.maxX(), 0); } } if (globalRect.minY() < boundRect.minY()) { offs = boundRect.minY() - globalRect.minY(); globalRect.Offset(0, offs); newOrg.y += offs; if (globalRect.maxY() > boundRect.maxY()) { double k = boundRect.SizeY() / globalRect.SizeY(); scale /= k; globalRect.Scale(k); globalRect.Offset(0, boundRect.minY() - globalRect.minY()); } } if (globalRect.maxY() > boundRect.maxY()) { offs = boundRect.maxY() - globalRect.maxY(); globalRect.Offset(0, offs); newOrg.y += offs; if (globalRect.minY() < boundRect.minY()) { double k = boundRect.SizeY() / globalRect.SizeY(); scale /= k; globalRect.Scale(k); globalRect.Offset(0, boundRect.maxY() - globalRect.maxY()); } } res.SetOrg(globalRect.Center()); res.Scale(scale); return res; }
void FrontendRenderer::AcceptMessage(ref_ptr<Message> message) { switch (message->GetType()) { case Message::FlushTile: { ref_ptr<FlushRenderBucketMessage> msg = message; dp::GLState const & state = msg->GetState(); TileKey const & key = msg->GetKey(); drape_ptr<dp::RenderBucket> bucket = msg->AcceptBuffer(); ref_ptr<dp::GpuProgram> program = m_gpuProgramManager->GetProgram(state.GetProgramIndex()); ref_ptr<dp::GpuProgram> program3d = m_gpuProgramManager->GetProgram(state.GetProgram3dIndex()); bool const isPerspective = m_userEventStream.GetCurrentScreen().isPerspective(); if (isPerspective) program3d->Bind(); else program->Bind(); bucket->GetBuffer()->Build(isPerspective ? program3d : program); if (!IsUserMarkLayer(key)) { if (CheckTileGenerations(key)) m_tileTree->ProcessTile(key, GetCurrentZoomLevelForData(), state, move(bucket)); } else { m_userMarkRenderGroups.emplace_back(make_unique_dp<UserMarkRenderGroup>(state, key, move(bucket))); m_userMarkRenderGroups.back()->SetRenderParams(program, program3d, make_ref(&m_generalUniforms)); } break; } case Message::FinishReading: { ref_ptr<FinishReadingMessage> msg = message; for (auto const & tileKey : msg->GetTiles()) CheckTileGenerations(tileKey); m_tileTree->FinishTiles(msg->GetTiles(), GetCurrentZoomLevelForData()); break; } case Message::InvalidateRect: { ref_ptr<InvalidateRectMessage> m = message; TTilesCollection tiles; ScreenBase screen = m_userEventStream.GetCurrentScreen(); m2::RectD rect = m->GetRect(); if (rect.Intersect(screen.ClipRect())) { m_tileTree->Invalidate(); ResolveTileKeys(rect, tiles); auto eraseFunction = [&tiles](vector<drape_ptr<RenderGroup>> & groups) { vector<drape_ptr<RenderGroup> > newGroups; for (drape_ptr<RenderGroup> & group : groups) { if (tiles.find(group->GetTileKey()) == tiles.end()) newGroups.push_back(move(group)); } swap(groups, newGroups); }; eraseFunction(m_renderGroups); eraseFunction(m_deferredRenderGroups); BaseBlockingMessage::Blocker blocker; m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<InvalidateReadManagerRectMessage>(blocker, tiles), MessagePriority::High); blocker.Wait(); m_requestedTiles->Set(screen, m_isIsometry || screen.isPerspective(), move(tiles)); m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<UpdateReadManagerMessage>(), MessagePriority::UberHighSingleton); } break; } case Message::ClearUserMarkLayer: { TileKey const & tileKey = ref_ptr<ClearUserMarkLayerMessage>(message)->GetKey(); auto const functor = [&tileKey](drape_ptr<UserMarkRenderGroup> const & g) { return g->GetTileKey() == tileKey; }; auto const iter = remove_if(m_userMarkRenderGroups.begin(), m_userMarkRenderGroups.end(), functor); m_userMarkRenderGroups.erase(iter, m_userMarkRenderGroups.end()); break; } case Message::ChangeUserMarkLayerVisibility: { ref_ptr<ChangeUserMarkLayerVisibilityMessage> m = message; TileKey const & key = m->GetKey(); if (m->IsVisible()) m_userMarkVisibility.insert(key); else m_userMarkVisibility.erase(key); break; } case Message::GuiLayerRecached: { ref_ptr<GuiLayerRecachedMessage> msg = message; drape_ptr<gui::LayerRenderer> renderer = move(msg->AcceptRenderer()); renderer->Build(make_ref(m_gpuProgramManager)); if (m_guiRenderer == nullptr) m_guiRenderer = move(renderer); else m_guiRenderer->Merge(make_ref(renderer)); break; } case Message::GuiLayerLayout: { ASSERT(m_guiRenderer != nullptr, ()); m_guiRenderer->SetLayout(ref_ptr<GuiLayerLayoutMessage>(message)->GetLayoutInfo()); break; } case Message::StopRendering: { ProcessStopRenderingMessage(); break; } case Message::MyPositionShape: { ref_ptr<MyPositionShapeMessage> msg = message; m_myPositionController->SetRenderShape(msg->AcceptShape()); m_selectionShape = msg->AcceptSelection(); } break; case Message::ChangeMyPostitionMode: { ref_ptr<ChangeMyPositionModeMessage> msg = message; switch (msg->GetChangeType()) { case ChangeMyPositionModeMessage::TYPE_NEXT: m_myPositionController->NextMode(msg->GetPreferredZoomLevel()); break; case ChangeMyPositionModeMessage::TYPE_STOP_FOLLOW: m_myPositionController->StopLocationFollow(); break; case ChangeMyPositionModeMessage::TYPE_INVALIDATE: m_myPositionController->Invalidate(); break; case ChangeMyPositionModeMessage::TYPE_CANCEL: m_myPositionController->TurnOff(); break; default: ASSERT(false, ("Unknown change type:", static_cast<int>(msg->GetChangeType()))); break; } break; } case Message::CompassInfo: { ref_ptr<CompassInfoMessage> msg = message; m_myPositionController->OnCompassUpdate(msg->GetInfo(), m_userEventStream.GetCurrentScreen()); break; } case Message::GpsInfo: { ref_ptr<GpsInfoMessage> msg = message; m_myPositionController->OnLocationUpdate(msg->GetInfo(), msg->IsNavigable(), m_userEventStream.GetCurrentScreen()); location::RouteMatchingInfo const & info = msg->GetRouteInfo(); if (info.HasDistanceFromBegin()) m_routeRenderer->UpdateDistanceFromBegin(info.GetDistanceFromBegin()); break; } case Message::FindVisiblePOI: { ref_ptr<FindVisiblePOIMessage> msg = message; ScreenBase const & screen = m_userEventStream.GetCurrentScreen(); msg->SetFeatureID(GetVisiblePOI(screen.isPerspective() ? screen.PtoP3d(screen.GtoP(msg->GetPoint())) : screen.GtoP(msg->GetPoint()))); break; } case Message::SelectObject: { ref_ptr<SelectObjectMessage> msg = message; if (m_selectionShape == nullptr) break; if (msg->IsDismiss()) { m_selectionShape->Hide(); } else { double offsetZ = 0.0; if (m_userEventStream.GetCurrentScreen().isPerspective()) { dp::OverlayTree::TSelectResult selectResult; m_overlayTree->Select(msg->GetPosition(), selectResult); for (ref_ptr<dp::OverlayHandle> handle : selectResult) offsetZ = max(offsetZ, handle->GetPivotZ()); } m_selectionShape->Show(msg->GetSelectedObject(), msg->GetPosition(), offsetZ, msg->IsAnim()); } break; } case Message::GetSelectedObject: { ref_ptr<GetSelectedObjectMessage> msg = message; if (m_selectionShape != nullptr) msg->SetSelectedObject(m_selectionShape->GetSelectedObject()); else msg->SetSelectedObject(SelectionShape::OBJECT_EMPTY); break; } case Message::GetMyPosition: { ref_ptr<GetMyPositionMessage> msg = message; msg->SetMyPosition(m_myPositionController->IsModeHasPosition(), m_myPositionController->Position()); break; } case Message::FlushRoute: { ref_ptr<FlushRouteMessage> msg = message; drape_ptr<RouteData> routeData = msg->AcceptRouteData(); m2::PointD const startPoint = routeData->m_sourcePolyline.Front(); m2::PointD const finishPoint = routeData->m_sourcePolyline.Back(); m_routeRenderer->SetRouteData(move(routeData), make_ref(m_gpuProgramManager)); if (!m_routeRenderer->GetStartPoint()) { m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<CacheRouteSignMessage>(startPoint, true /* isStart */, true /* isValid */), MessagePriority::High); } if (!m_routeRenderer->GetFinishPoint()) { m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<CacheRouteSignMessage>(finishPoint, false /* isStart */, true /* isValid */), MessagePriority::High); } m_myPositionController->ActivateRouting(); break; } case Message::FlushRouteSign: { ref_ptr<FlushRouteSignMessage> msg = message; drape_ptr<RouteSignData> routeSignData = msg->AcceptRouteSignData(); m_routeRenderer->SetRouteSign(move(routeSignData), make_ref(m_gpuProgramManager)); break; } case Message::RemoveRoute: { ref_ptr<RemoveRouteMessage> msg = message; m_routeRenderer->Clear(); if (msg->NeedDeactivateFollowing()) { m_myPositionController->DeactivateRouting(); m_overlayTree->SetFollowingMode(false); if (m_enablePerspectiveInNavigation) DisablePerspective(); } break; } case Message::FollowRoute: { ref_ptr<FollowRouteMessage> const msg = message; m_myPositionController->NextMode(!m_enablePerspectiveInNavigation ? msg->GetPreferredZoomLevel() : msg->GetPreferredZoomLevelIn3d()); m_overlayTree->SetFollowingMode(true); if (m_enablePerspectiveInNavigation) { bool immediatelyStart = !m_myPositionController->IsRotationActive(); AddUserEvent(EnablePerspectiveEvent(msg->GetRotationAngle(), msg->GetAngleFOV(), true /* animated */, immediatelyStart)); } break; } case Message::DeactivateRouteFollowing: { m_myPositionController->DeactivateRouting(); m_overlayTree->SetFollowingMode(false); if (m_enablePerspectiveInNavigation) DisablePerspective(); break; } case Message::UpdateMapStyle: { // Clear tile tree. m_tileTree->Invalidate(); // Get new tiles. TTilesCollection tiles; ScreenBase screen = m_userEventStream.GetCurrentScreen(); ResolveTileKeys(screen.ClipRect(), tiles); // Clear all graphics. m_renderGroups.clear(); m_deferredRenderGroups.clear(); // Invalidate read manager. { BaseBlockingMessage::Blocker blocker; m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<InvalidateReadManagerRectMessage>(blocker, tiles), MessagePriority::High); blocker.Wait(); } // Invalidate textures and wait for completion. { BaseBlockingMessage::Blocker blocker; m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<InvalidateTexturesMessage>(blocker), MessagePriority::High); blocker.Wait(); } // Invalidate route. if (m_routeRenderer->GetStartPoint()) { m2::PointD const & position = m_routeRenderer->GetStartPoint()->m_position; m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<CacheRouteSignMessage>(position, true /* isStart */, true /* isValid */), MessagePriority::High); } if (m_routeRenderer->GetFinishPoint()) { m2::PointD const & position = m_routeRenderer->GetFinishPoint()->m_position; m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<CacheRouteSignMessage>(position, false /* isStart */, true /* isValid */), MessagePriority::High); } auto const & routeData = m_routeRenderer->GetRouteData(); if (routeData != nullptr) { auto recacheRouteMsg = make_unique_dp<AddRouteMessage>(routeData->m_sourcePolyline, routeData->m_sourceTurns, routeData->m_color); m_routeRenderer->Clear(true /* keepDistanceFromBegin */); m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, move(recacheRouteMsg), MessagePriority::Normal); } // Request new tiles. m_requestedTiles->Set(screen, m_isIsometry || screen.isPerspective(), move(tiles)); m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, make_unique_dp<UpdateReadManagerMessage>(), MessagePriority::UberHighSingleton); break; } case Message::EnablePerspective: { ref_ptr<EnablePerspectiveMessage> const msg = message; AddUserEvent(EnablePerspectiveEvent(msg->GetRotationAngle(), msg->GetAngleFOV(), false /* animated */, true /* immediately start */)); break; } case Message::Allow3dMode: { ref_ptr<Allow3dModeMessage> const msg = message; bool const isPerspective = m_userEventStream.GetCurrentScreen().isPerspective(); #ifdef OMIM_OS_DESKTOP if (m_enablePerspectiveInNavigation == msg->AllowPerspective() && m_enablePerspectiveInNavigation != isPerspective) { if (m_enablePerspectiveInNavigation) AddUserEvent(EnablePerspectiveEvent(msg->GetRotationAngle(), msg->GetAngleFOV(), false /* animated */, true /* immediately start */)); else AddUserEvent(DisablePerspectiveEvent()); } #endif m_enablePerspectiveInNavigation = msg->AllowPerspective(); m_enable3dBuildings = msg->Allow3dBuildings(); if (m_myPositionController->IsInRouting()) { if (m_enablePerspectiveInNavigation && !isPerspective && !m_perspectiveDiscarded) { AddUserEvent(EnablePerspectiveEvent(msg->GetRotationAngle(), msg->GetAngleFOV(), true /* animated */, true /* immediately start */)); } else if (!m_enablePerspectiveInNavigation && (isPerspective || m_perspectiveDiscarded)) { DisablePerspective(); } } break; } case Message::Invalidate: { // Do nothing here, new frame will be rendered because of this message processing. break; } default: ASSERT(false, ()); } }