void Viewer::drawEvent()

in src/utils/viewer/viewer.cpp [1417:1591]


void Viewer::drawEvent() {
  // Wrap profiler measurements around all methods to render images from
  // RenderCamera
  profiler_.beginFrame();
  Mn::GL::defaultFramebuffer.clear(Mn::GL::FramebufferClear::Color |
                                   Mn::GL::FramebufferClear::Depth);

  // Agent actions should occur at a fixed rate per second
  timeSinceLastSimulation += timeline_.previousFrameDuration();
  int numAgentActions = timeSinceLastSimulation * agentActionsPerSecond;
  moveAndLook(numAgentActions);

  // occasionally a frame will pass quicker than 1/60 seconds
  if (timeSinceLastSimulation >= 1.0 / 60.0) {
    if (simulating_ || simulateSingleStep_) {
      // step physics at a fixed rate
      // In the interest of frame rate, only a single step is taken,
      // even if timeSinceLastSimulation is quite large
      simulator_->stepWorld(1.0 / 60.0);
      simulateSingleStep_ = false;
      const auto recorder = simulator_->getGfxReplayManager()->getRecorder();
      if (recorder) {
        recorder->saveKeyframe();
      }
    }
    // reset timeSinceLastSimulation, accounting for potential overflow
    timeSinceLastSimulation = fmod(timeSinceLastSimulation, 1.0 / 60.0);
  }

  uint32_t visibles = renderCamera_->getPreviousNumVisibleDrawables();

  if ((visualizeMode_ == VisualizeMode::RGBA) &&
      (sensorMode_ == VisualSensorMode::Camera)) {
    // Visualizing RGBA pinhole camera
    if (mouseGrabber_ != nullptr) {
      mouseGrabber_->renderDebugLines();
    }

    // ============= regular RGB with object picking =================
    // using polygon offset to increase mesh depth to avoid z-fighting with
    // debug draw (since lines will not respond to offset).
    Mn::GL::Renderer::enable(Mn::GL::Renderer::Feature::PolygonOffsetFill);
    Mn::GL::Renderer::setPolygonOffset(1.0f, 0.1f);

    // ONLY draw the content to the frame buffer but not immediately blit the
    // result to the default main buffer
    // (this is the reason we do not call displayObservation)
    simulator_->drawObservation(defaultAgentId_, sensorVisID_);

    Mn::GL::Renderer::setDepthFunction(
        Mn::GL::Renderer::DepthFunction::LessOrEqual);
    if (debugBullet_) {
      Mn::Matrix4 camM(renderCamera_->cameraMatrix());
      Mn::Matrix4 projM(renderCamera_->projectionMatrix());

      simulator_->physicsDebugDraw(projM * camM);
    }
    Mn::GL::Renderer::setDepthFunction(Mn::GL::Renderer::DepthFunction::Less);
    Mn::GL::Renderer::setPolygonOffset(0.0f, 0.0f);
    Mn::GL::Renderer::disable(Mn::GL::Renderer::Feature::PolygonOffsetFill);

    visibles = renderCamera_->getPreviousNumVisibleDrawables();
    esp::gfx::RenderTarget* sensorRenderTarget =
        simulator_->getRenderTarget(defaultAgentId_, sensorVisID_);
    CORRADE_ASSERT(sensorRenderTarget,
                   "Error in Viewer::drawEvent: sensor's rendering target "
                   "cannot be nullptr.", );
    if (objectPickingHelper_->isObjectPicked()) {
      // we need to immediately draw picked object to the SAME frame buffer
      // so bind it first
      // bind the framebuffer
      sensorRenderTarget->renderReEnter();

      // setup blending function
      Mn::GL::Renderer::enable(Mn::GL::Renderer::Feature::Blending);

      // render the picked object on top of the existing contents
      esp::gfx::RenderCamera::Flags flags;
      if (simulator_->isFrustumCullingEnabled()) {
        flags |= esp::gfx::RenderCamera::Flag::FrustumCulling;
      }
      renderCamera_->draw(objectPickingHelper_->getDrawables(), flags);

      Mn::GL::Renderer::disable(Mn::GL::Renderer::Feature::Blending);
    }
    sensorRenderTarget->blitRgbaToDefault();
  } else {
    // Depth Or Semantic, or Non-pinhole RGBA
    simulator_->drawObservation(defaultAgentId_, sensorVisID_);
    esp::gfx::RenderTarget* sensorRenderTarget =
        simulator_->getRenderTarget(defaultAgentId_, sensorVisID_);
    CORRADE_ASSERT(sensorRenderTarget,
                   "Error in Viewer::drawEvent: sensor's rendering target "
                   "cannot be nullptr.", );
    if (visualizeMode_ == VisualizeMode::Depth) {
      simulator_->visualizeObservation(defaultAgentId_, sensorVisID_,
                                       1.0f / 512.0f,  // colorMapOffset
                                       1.0f / 12.0f);  // colorMapScale
    } else if (visualizeMode_ == VisualizeMode::Semantic) {
      simulator_->visualizeObservation(defaultAgentId_, sensorVisID_);
    }
    sensorRenderTarget->blitRgbaToDefault();
  }

  // Immediately bind the main buffer back so that the "imgui" below can work
  // properly
  Mn::GL::defaultFramebuffer.bind();

  // Do not include ImGui content drawing in per frame profiler measurements
  profiler_.endFrame();

  imgui_.newFrame();
  ImGui::SetNextWindowPos(ImVec2(10, 10));
  if (showFPS_) {
    ImGui::Begin("main", NULL,
                 ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground |
                     ImGuiWindowFlags_AlwaysAutoResize);
    ImGui::SetWindowFontScale(1.5);
    ImGui::Text("%.1f FPS", Mn::Double(ImGui::GetIO().Framerate));
    uint32_t total = activeSceneGraph_->getDrawables().size();
    ImGui::Text("%u drawables", total);
    if (sensorMode_ == VisualSensorMode::Camera) {
      ImGui::Text("%u culled", total - visibles);
    }
    auto& cam = getAgentCamera();

    switch (sensorMode_) {
      case VisualSensorMode::Camera:
        if (cam.getCameraType() == esp::sensor::SensorSubType::Orthographic) {
          ImGui::Text("Orthographic camera sensor");
        } else if (cam.getCameraType() == esp::sensor::SensorSubType::Pinhole) {
          ImGui::Text("Pinhole camera sensor");
        };
        break;
      case VisualSensorMode::Fisheye:
        ImGui::Text("Fisheye sensor");
        break;
      case VisualSensorMode::Equirectangular:
        ImGui::Text("Equirectangular sensor");
        break;

      default:
        break;
    }
    ImGui::Text("%s", profiler_.statistics().c_str());
    std::string modeText =
        "Mouse Interaction Mode: " + mouseModeNames.at(mouseInteractionMode);
    ImGui::Text("%s", modeText.c_str());
    if (!semanticTag_.empty()) {
      ImGui::Text("Semantic %s", semanticTag_.c_str());
    }
    ImGui::End();
  }

  /* Set appropriate states. If you only draw ImGui, it is sufficient to
     just enable blending and scissor test in the constructor. */
  Mn::GL::Renderer::enable(Mn::GL::Renderer::Feature::Blending);
  Mn::GL::Renderer::enable(Mn::GL::Renderer::Feature::ScissorTest);
  Mn::GL::Renderer::disable(Mn::GL::Renderer::Feature::FaceCulling);
  Mn::GL::Renderer::disable(Mn::GL::Renderer::Feature::DepthTest);

  imgui_.drawFrame();

  /* Reset state. Only needed if you want to draw something else with
     different state after. */

  Mn::GL::Renderer::enable(Mn::GL::Renderer::Feature::DepthTest);
  Mn::GL::Renderer::enable(Mn::GL::Renderer::Feature::FaceCulling);
  Mn::GL::Renderer::disable(Mn::GL::Renderer::Feature::ScissorTest);
  Mn::GL::Renderer::disable(Mn::GL::Renderer::Feature::Blending);

  swapBuffers();
  timeline_.nextFrame();
  redraw();
}  // Viewer::drawEvent()