// This switches the renderer for the main pass between rasterizer and raytracer.
void SceneRendererPipeline::setSceneRenderer(const dp::sg::ui::SceneRendererSharedPtr &sceneRenderer)
{
  m_sceneRenderer = sceneRenderer;
  // Do not separate the ViewState camera another time during the render() call issued inside the SceneRendererPipeline.
  m_sceneRenderer->setStereoViewStateProvider(m_monoViewStateProvider);

  if ( GetApp()->isBackdropEnabled() )
  {
    updateEnvironment();
  }

  // If the renderer is a SceneRendererGL2 reuse it for the highlighting to keep the number of RenderLists small.
  if ( m_sceneRenderer.isPtrTo<dp::sg::renderer::rix::gl::SceneRenderer>() )
  {
    m_sceneRendererHighlight = m_sceneRenderer.staticCast<dp::sg::renderer::rix::gl::SceneRenderer>();
  }
  else
  {
    Viewer* viewer = GetApp();
    m_sceneRendererHighlight = dp::sg::renderer::rix::gl::SceneRenderer::create( viewer->getRenderEngine().c_str(),
                                                                                 viewer->getShaderManagerType(),
                                                                                 viewer->getCullingMode(),
                                                                                 dp::sg::renderer::rix::gl::TransparencyMode::SORTED_BLENDED );
  }
}
// This is called from initializeGL().
bool SceneRendererPipeline::init(const dp::gl::RenderContextSharedPtr &renderContext,
                                 const dp::gl::RenderTargetSharedPtr  &renderTarget)
{
  m_renderTarget = renderTarget;

  DP_ASSERT( m_sceneRenderer );
  m_sceneRenderer->setRenderTarget( renderTarget );
  m_sceneRenderer->setEnvironmentRenderingEnabled( GetApp()->getPreferences()->getEnvironmentEnabled() );

  // Create an FBO with 2D texture color attachment and depth stencil render buffers.
  // This one remains monoscopic, SceneRendererPipeline::doRender() works per eye.
  m_highlightFBO = dp::gl::RenderTargetFBO::create( renderContext );

  // Set the defaults for the render pass.
  // This clear color actually doesn't take effect when using a SceneRenderer. The scene background color has precedence.
  m_highlightFBO->setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  m_highlightFBO->setClearDepth(1.0);
  m_highlightFBO->setClearStencil(0);

  // Make the OpenGL context on the renderContext current. It's needed for the create() operations.
  dp::gl::RenderContextStack rcglstack;
  rcglstack.push(renderContext);

  // Render to 2D texture.
  m_highlightFBO->setAttachment(dp::gl::RenderTargetFBO::AttachmentTarget::COLOR0,
                                dp::gl::Texture2D::create(GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE));
  // Depth and Stencil are Renderbuffers.
  dp::gl::RenderbufferSharedPtr depthStencil(dp::gl::Renderbuffer::create(GL_DEPTH24_STENCIL8)); // Shared depth stencil buffer between the tonemap and hightlight FBOs.
  m_highlightFBO->setAttachment(dp::gl::RenderTargetFBO::AttachmentTarget::DEPTH,   depthStencil);
  m_highlightFBO->setAttachment(dp::gl::RenderTargetFBO::AttachmentTarget::STENCIL, depthStencil);

  std::vector<dp::gl::RenderTargetFBO::AttachmentTarget> drawBuffers;
  drawBuffers.push_back(dp::gl::RenderTargetFBO::AttachmentTarget::COLOR0);
  m_highlightFBO->setDrawBuffers(drawBuffers);

  rcglstack.pop();

  // If there hasn't been a setSceneRender() we cannot reuse the m_sceneRenderer for the highlight rasterization.
  // Create the SceneRenderer used to render the highlighted objects of the scene into the highlightFBO stencil buffer.
  if (!m_sceneRendererHighlight)
  {
    Viewer * viewer = GetApp();
    m_sceneRendererHighlight = dp::sg::renderer::rix::gl::SceneRenderer::create( viewer->getRenderEngine().c_str(),
                                                                                 viewer->getShaderManagerType(),
                                                                                 viewer->getCullingMode(),
                                                                                 dp::sg::renderer::rix::gl::TransparencyMode::SORTED_BLENDED );
  }

  if ( GetApp()->isTonemapperEnabled() )
  {
    initTonemapper();
  }
  if ( GetApp()->getPreferences()->getEnvironmentEnabled() )
  {
    initBackdrop();
  }

  // Create a full screen quad renderer for the stencil buffer to color attachment migration.
  m_rendererStencilToColor = dp::sg::renderer::rix::gl::FSQRenderer::create(m_highlightFBO);
  m_rendererStencilToColor->setPipeline( dp::sg::core::PipelineData::create( EffectLibrary::instance()->getEffectSpec( std::string("stencilToColor") ) ) );

  // Create a full screen quad renderer for the final texture to framebuffer operation rendering the highlight outline.
  m_rendererHighlight = dp::sg::renderer::rix::gl::FSQRenderer::create(renderTarget);
  m_rendererHighlight->setPipeline( dp::sg::core::PipelineData::create( EffectLibrary::instance()->getEffectSpec( std::string("highlight") ) ) );

  // m_rendererHighlight uses the previously rendered texture rectangle as input for the shader.
  const dp::gl::RenderTargetFBO::SharedAttachment &attachment = m_highlightFBO->getAttachment(dp::gl::RenderTargetFBO::AttachmentTarget::COLOR0);
  const dp::gl::RenderTargetFBO::SharedAttachmentTexture &texAtt = attachment.inplaceCast<dp::gl::RenderTargetFBO::AttachmentTexture>();
  if (texAtt)
  {
    const dp::sg::gl::TextureGLSharedPtr texGL = dp::sg::gl::TextureGL::create( texAtt->getTexture() );
    dp::sg::core::SamplerSharedPtr sampler = dp::sg::core::Sampler::create( texGL );
    sampler->setWrapModes( dp::sg::core::TextureWrapMode::CLAMP_TO_EDGE, dp::sg::core::TextureWrapMode::CLAMP_TO_EDGE, dp::sg::core::TextureWrapMode::CLAMP_TO_EDGE );
    sampler->setMagFilterMode( dp::sg::core::TextureMagFilterMode::NEAREST );
    sampler->setMinFilterMode( dp::sg::core::TextureMinFilterMode::NEAREST );

    m_rendererHighlight->setSamplerByName( "selection", sampler );
  }

  return true;
}