Skip to content
Snippets Groups Projects
Node.hpp 9.25 KiB
#pragma once
#include <RadiumNBR/NodeBasedRendererMacro.hpp>
#include <RadiumNBR/NodeGraph/EditableParameter.hpp>
#include <RadiumNBR/NodeGraph/Port.hpp>

#include <RadiumNBR/externals/json.hpp>

#include <uuid.h>

#include <cstdint>
#include <iostream>
#include <memory>
#include <string>
#include <typeinfo>
#include <vector>

enum class TextureType { COLOR, DEPTH, STENCIL };

template <class T>
constexpr std::string_view type_name() {
#ifdef __clang__
    std::string_view p = __PRETTY_FUNCTION__;
    return std::string_view( p.data() + 34, p.size() - 34 - 1 );
#elif defined( __GNUC__ )
    std::string_view p = __PRETTY_FUNCTION__;
#    if __cplusplus < 201402
    return std::string_view( p.data() + 36, p.size() - 36 - 1 );
#    else
    return std::string_view( p.data() + 49, p.find( ';', 49 ) - 49 );
#    endif
#elif defined( _MSC_VER )
    std::string_view p = __FUNCSIG__;
    return std::string_view( p.data() + 84, p.size() - 84 - 7 );
#else
    return type_id( T ).type_name();
#endif
}

inline std::size_t
replace_all_in_string( std::string& inout, std::string_view what, std::string_view with ) {
    std::size_t count{};
    for ( std::string::size_type pos{};
          inout.npos != ( pos = inout.find( what.data(), pos, what.length() ) );
          pos += with.length(), ++count )
    { inout.replace( pos, what.length(), with.data(), with.length() ); }
    return count;
}

inline std::size_t remove_all_in_string( std::string& inout, std::string_view what ) {
    return replace_all_in_string( inout, what, "" );
}

#include <Core/Utils/Color.hpp>
#include <Engine/Data/ShaderProgramManager.hpp>
#include <Engine/Data/Texture.hpp>
#include <Engine/Data/ViewingParameters.hpp>
#include <Engine/Rendering/RenderObject.hpp>
#include <Engine/Scene/Light.hpp>

using NodeTypeRenderObject = std::shared_ptr<Ra::Engine::Rendering::RenderObject>;
using NodeTypeLight        = const Ra::Engine::Scene::Light*;
using NodeTypeCamera       = Ra::Engine::Data::ViewingParameters;
using NodeTypeColor        = Ra::Core::Utils::Color;
using NodeTypeTexture      = Ra::Engine::Data::Texture;

class NodeBasedRenderer_LIBRARY_API Node
{
  public:
    /// Constructor.
    Node()              = delete;
    Node( const Node& ) = delete;
    Node& operator=( const Node& ) = delete;
    virtual ~Node()                = default;

    /// The init() function is called once at the start of the application.
    /// Its goal is to initialize the node's internal data.
    virtual void init() = 0;
    /// The update() function is called once per frame.
    /// Its goal is to update the node's internal data.
    virtual void update() = 0;
    /// The execute() function is called once per frame.
    /// Its goal is to execute a treatment to the output data.
    virtual void execute() = 0;
    /// The destroy() function is called once at the end of the application.
    /// Its goal is to free the internal data that have been allocated.
    virtual void destroy() = 0;
    /// The resize(uint32_t width, uint32_t height) function is called when the application gets
    /// resized. Its goal is to resize the potential internal textures if needed.
    /// @param width The new width of the surface.
    /// @param height The new height of the surface.
    virtual void resize( uint32_t width, uint32_t height ) = 0;

    /// TODO : specify the json format for nodes and what is expected from the following ethods

    /// return the json representation of the concrete node
    void toJson( nlohmann::json& data ) const;

    /// Fill the node from its json description
    void fromJson( const nlohmann::json& data );

    /// Give access to extra json data stored on the node by external application components
    nlohmann::json& getExtraJsonData() { return m_extraJsonData; }

    /// Build a render technic per material.
    /// @param ro The render object to get the material from
    /// @param rt The render technic to build
    virtual void buildRenderTechnique( const Ra::Engine::Rendering::RenderObject* ro,
                                       Ra::Engine::Rendering::RenderTechnique& rt ) const {}

    /// Gets the name of the node.
    const std::string& getTypeName() const { return m_typeName; }

    /// Gets the instance name of the node.
    const std::string& getInstanceName() const { return m_instanceName; }

    /// Generates the uuid of the node
    void generateUuid();
    /// Gets the UUID of the node as a string
    std::string getUuid() const;

    /// return the deletable status of the node
    /// Default is true. If a node must not be deleted (e.g. RenderObjectSource Node in the rendergraph), override this method.
    bool isDeletable() { return m_isDeletable;}
    // Set the deletable status of the node
    void setDeletableStatus( bool deletable = true ) { m_isDeletable = deletable; }

    /// Gets the in ports of the node.
    std::vector<std::unique_ptr<PortBase>>& getInputs() { return m_inputs; }
    /// Gets the out ports of the node.
    std::vector<std::unique_ptr<PortBase>>& getOutputs() { return m_outputs; }
    /// Gets the editable parameters of the node.
    std::vector<std::unique_ptr<EditableParameterBase>>& getEditableParameters() {
        return m_editableParameters;
    }

    /// Sets the filesystem (real or virtual) location for the pass resources
    inline void setResourcesDir( std::string resourcesRootDir ) {
        m_resourceDir = std::move( resourcesRootDir );
    }
    /// Sets node index for render technique
    void setIndex( const int idx ) { m_idx = idx; }

    /// Sets the shader program manager
    void setShaderProgramManager( Ra::Engine::Data::ShaderProgramManager* shaderMngr ) {
        m_shaderMngr = shaderMngr;
    }

    /// Flag that checks if the node is already initialized
    bool m_initialized{ false };

    /// Two nodes are considered equal if there names are the same.
    bool operator==( const Node& o_node ) { return m_typeName == o_node.getTypeName(); }

  protected:
    /// @param instanceName The name of the node
    /// @param typeName The type name of the node
    Node( const std::string& instanceName, const std::string& typeName );

    /// internal json representation of the Node.
    /// Must be implemented by inheriting classes.
    /// Be careful with template specialization and function member overriding when implementing this method.
    virtual void fromJsonInternal( const nlohmann::json& data ) {
        std::cout << "virtual void fromJsonInternal : MUST NOT BE CALLED on a " << typeid(*this).name() << "\n";
    }//= 0;

    /// internal json representation of the Node.
    /// Must be implemented by inheriting classes.
    /// Be careful with template specialization and function member overriding when implementing this method.
    virtual void toJsonInternal( nlohmann::json& data ) const {} //= 0;

    /// Adds an in port to the node.
    /// This function checks if there is no in port with the same name already associated with this
    /// node.
    /// @param in The in port to add.
    template <typename T>
    void addInput( PortIn<T>* in ) {
        bool found = false;
        for ( auto& input : m_inputs )
        {
            if ( input->getName() == in->getName() ) { found = true; }
        }
        if ( !found ) { m_inputs.emplace_back( in ); }
    }

    /// Adds an out port to the node and the data associated with it.
    /// This function checks if there is no out port with the same name already associated with this
    /// node.
    /// @param out The in port to add.
    /// @param data The data associated with the port.
    template <typename T>
    void addOutput( PortOut<T>* out, T* data ) {
        bool found = false;
        for ( auto& output : m_outputs )
        {
            if ( output->getName() == out->getName() ) { found = true; }
        }
        if ( !found )
        {
            m_outputs.emplace_back( out );
            out->setData( data );
        }
    }

    /// Adds an editable parameter to the node.
    /// @param editableParameter The editable parameter to add.
    template <typename T>
    void addEditableParameter( EditableParameter<T>* editableParameter ) {
        m_editableParameters.emplace_back( editableParameter );
    }

    /// The uuid of the node (TODO, use https://github.com/mariusbancila/stduuid instead of a
    /// string)
    //std::string m_uuid;
    uuids::uuid m_uuid;
    /// The deletable status of the node
    bool m_isDeletable {true};
    /// The type name of the node
    std::string m_typeName;
    /// The instance name of the node
    std::string m_instanceName;
    /// The in ports of the node
    std::vector<std::unique_ptr<PortBase>> m_inputs;
    /// The out ports of the node
    std::vector<std::unique_ptr<PortBase>> m_outputs;
    /// The editable parameters of the node
    std::vector<std::unique_ptr<EditableParameterBase>> m_editableParameters;
    /// The index of the node in the render technique description
    Ra::Core::Utils::Index m_idx;
    /// The base resources directory
    std::string m_resourceDir{ "./" };
    /// The renderer's shader program manager
    Ra::Engine::Data::ShaderProgramManager* m_shaderMngr;

    /// Additional data on the node, added by application or gui or ...
    nlohmann::json m_extraJsonData;

    /// generator for uuid
    static bool s_uuidGeneratorInitialized;
    static uuids::uuid_random_generator* s_uidGenerator;
    static void createUuidGenerator();
};