Skip to content
Snippets Groups Projects
NodeBasedRenderer.hpp 6.65 KiB
#pragma once
#include <RadiumNBR/NodeBasedRendererMacro.hpp>
#include <RadiumNBR/RenderPass.hpp>

#include <Core/Resources/Resources.hpp>
#include <Engine/Rendering/Renderer.hpp>

namespace globjects {
class Framebuffer;
}

namespace RadiumNBR {

/// Todo, put this somewhere else. This is needed to locate resources by client applications
extern int NodeBasedRendererMagic;

class UIPass;
class DebugPass;

/** Node based for the Radium Engine
 * This Renderer is fully configurable, either dynamically or programmatically.
 * It implements the Ra::Engine::Rendering/Renderer interface.
 *
 * A NodeBasedRenderer is configured by using the RenderControlFunctor given at construction.
 * A RenderControlFunctor offers the following services :
 *  - configure() : add to the renderer as many RadiumNBR::RenderPass as needed. This method is
 *  called once when initializing the renderer. This method could also initialize internal
 *  resources into the controller that could be used to control the rendering.
 *  - resize() : called each time the renderer output is resized. This will allow modify controller
 *  resources that depends on the size of the output (e.g. internal textures ...)
 *  - update() : Called once before each frame to update the internal state of the renderer.
 *
 * A NodeBasedRenderer defines two textures that might be shared between passes :
 *  - a depth buffer attachable texture, stored with the key "Depth (RadiumNBR)" into the shared
 *  textures collection
 *  - a Linear space RGBA color texture, stored with the key "Linear RGB (RadiumNBR)" into the
 *  shared textures collection
 *
 *  If requested on the base Ra::Engine::Rendering::Renderer, a  NodeBasedRenderer apply a
 *  post-process step on the "Linear RGB (RadiumNBR)" that convert colors from linearRGB to sRGB
 *  color space  before displaying the image.
 *
 *
 * @see rendering.md for description of the renderer
 */
class NodeBasedRenderer_LIBRARY_API NodeBasedRenderer : public Ra::Engine::Rendering::Renderer
{

  public:
    /**
     * Rendering functor prototype
     * @todo make this a concept
     */
    struct RenderControlFunctor {

        RenderControlFunctor()                               = default;
        virtual ~RenderControlFunctor()                      = default;
        RenderControlFunctor( const RenderControlFunctor& )  = delete;
        RenderControlFunctor( const RenderControlFunctor&& ) = delete;
        RenderControlFunctor& operator=( RenderControlFunctor&& ) = delete;
        RenderControlFunctor& operator=( const RenderControlFunctor& ) = delete;

        /// Configuration function.
        /// Called once at the configuration of the renderer
        virtual void configure( NodeBasedRenderer* renderer, int w, int h ){};

        /// Resize function
        /// Called each time the renderer is resized
        virtual void resize( int w, int h ){};
        /// Update function
        /// Called once before each frame to update the internal state of the renderer
        virtual void update( const Ra::Engine::Data::ViewingParameters& renderData ){};
    };

    /// Construct a renderer that has to be configured explicitely
    NodeBasedRenderer();

    /// Construct a renderer configured and managed through the controller
    explicit NodeBasedRenderer( RenderControlFunctor& controller );

    /// The destructor is defaulted
    ~NodeBasedRenderer() override;

    [[nodiscard]] std::string getRendererName() const override { return "Configurable Renderer"; }

    bool buildRenderTechnique( Ra::Engine::Rendering::RenderObject* ro ) const override;

    /** add a pass to be executed at the given rank, and, optionally, is the default pass for the
     * renderer.
     *
     * Passes are executed by increasing rank.
     * [not yet available : If two passes have the same rank, they will be
     * executed in arbitrary order].
     *
     * The default pass (rank 0) might be used for specific render operations.
     *
     * If a pass with the same rank already exists in the Renderer, the given pass is not added nor
     * is changed the default)
     * @return true if the pass is insserted, false if not
     */
    bool addPass( std::shared_ptr<RadiumNBR::RenderPass> pass, int rank, bool defaultPass = false );

    /// Hide or show the UI
    void showUI( bool b );

    /// Hide or show the Debug objects
    void showDebug( bool b );

    /// Access the default light manager
    Ra::Engine::Scene::LightManager* getLightManager() { return m_lightmanagers[0]; }

    /// Access the controler
    RenderControlFunctor& getController() { return m_controller; }

  protected:
    void initializeInternal() override;
    void resizeInternal() override;
    void updateStepInternal( const Ra::Engine::Data::ViewingParameters& renderData ) override;
    void renderInternal( const Ra::Engine::Data::ViewingParameters& renderData ) override;
    void postProcessInternal( const Ra::Engine::Data::ViewingParameters& renderData ) override;
    void debugInternal( const Ra::Engine::Data::ViewingParameters& renderData ) override;
    void uiInternal( const Ra::Engine::Data::ViewingParameters& renderData ) override;

    /** Initialize internal resources for the renderer.
     * The base function creates the depth and final color texture to be shared by the rendering
     * passes that need them.
     */
    virtual void initResources();

  public:
    inline std::map<std::string, std::shared_ptr<Ra::Engine::Data::Texture>>& sharedTextures() {
        return m_sharedTextures;
    }

    inline globjects::Framebuffer* postprocessFbo() { return m_postprocessFbo.get(); }

    inline std::map<int, std::shared_ptr<RenderPass>>& renderPasses() { return m_renderPasses; }

    inline const std::map<int, std::shared_ptr<RenderPass>>& renderPasses() const {
        return m_renderPasses;
    }

    inline std::vector<RenderObjectPtr>* allRenderObjects() { return &m_fancyRenderObjects; }

    inline int defaultPass() const { return m_defaultPass; }

  private:
    /// textures own by the Renderer but shared across passes
    std::map<std::string, std::shared_ptr<Ra::Engine::Data::Texture>> m_sharedTextures;

    /// internal FBO used for post-processing
    std::unique_ptr<globjects::Framebuffer> m_postprocessFbo;

    /// collection of render passes, sorted by precedence (first pass is at key 0)
    std::map<int, std::shared_ptr<RenderPass>> m_renderPasses;

    /// The default pass
    int m_defaultPass{-1};

    /// The configurator functor to use
    RenderControlFunctor& m_controller;

    /// The pass to draw UI object
    std::unique_ptr<UIPass> m_uiPass;
    bool m_showUi{false};

    /// The pass to draw Debug object
    std::unique_ptr<DebugPass> m_debugPass;
    bool m_showDebug{false};
};

} // namespace RadiumNBR