Example #1
0
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, ());
  }
}