238 lines
9.1 KiB
C++
238 lines
9.1 KiB
C++
#pragma once
|
|
|
|
#include "../commons.h"
|
|
|
|
#include "../utilities/node_renderer_base.h"
|
|
#include <string>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <functional>
|
|
#include <imgui.h>
|
|
|
|
// Pin icon offset constants
|
|
namespace BlockPinOffsets {
|
|
// Y offset for input parameter pins (moves pins higher on top edge)
|
|
static constexpr float INPUT_PARAM_Y = -8.0f;
|
|
// Y offset for output parameter pins (moves pins lower on bottom edge)
|
|
static constexpr float OUTPUT_PARAM_Y = 8; // Negated (12.0f)
|
|
|
|
// Parameter node specific output offset (can be different from general blocks)
|
|
static constexpr float PARAM_NODE_OUTPUT_Y = 0.0f;
|
|
|
|
// Combined ImVec2 offsets for convenience
|
|
static const ImVec2 INPUT_PARAM(0.0f, -15);
|
|
static const ImVec2 OUTPUT_PARAM(0.0f, OUTPUT_PARAM_Y);
|
|
static const ImVec2 PARAM_NODE_OUTPUT(0.0f, PARAM_NODE_OUTPUT_Y);
|
|
|
|
static const ImVec2 GROUP_INPUT_PARAM(0.0f, -15.0f);
|
|
}
|
|
|
|
// Block style constants
|
|
namespace BlockStyle {
|
|
// Node appearance constants
|
|
static constexpr float ROUNDING = 1.0f;
|
|
static constexpr float BORDER_WIDTH = 1.0f;
|
|
static constexpr float PADDING = 0.0f;
|
|
|
|
// Group block specific (more rounded, slightly thicker border)
|
|
static constexpr float GROUP_ROUNDING = 1.0f;
|
|
static constexpr float GROUP_BORDER_WIDTH = 1.0f;
|
|
|
|
// Parameter node constants (standardized across all display modes)
|
|
static constexpr float PARAM_ROUNDING = 0.0f;
|
|
static constexpr float PARAM_BORDER_WIDTH = 1.0f;
|
|
static constexpr float PARAM_BORDER_WIDTH_SOURCE = 2.0f; // Thicker for source nodes
|
|
static constexpr float PARAM_BORDER_WIDTH_NAME_AND_VALUE = 1.5f; // Slightly thicker for name+value mode
|
|
static constexpr float PARAM_BORDER_WIDTH_SOURCE_NAME_AND_VALUE = 2.5f; // Source in name+value mode
|
|
|
|
// Parameter node padding (ImVec4 for per-edge control)
|
|
static const ImVec4 PARAM_PADDING_NAME_ONLY(4.0f, 2.0f, 4.0f, 2.0f);
|
|
static const ImVec4 PARAM_PADDING_NAME_AND_VALUE(8.0f, 4.0f, 8.0f, 4.0f);
|
|
static const ImVec4 PARAM_PADDING_SMALL_BOX(2.0f, 2.0f, 2.0f, 2.0f);
|
|
static const ImVec4 PARAM_PADDING_MINIMAL(4.0f, 4.0f, 4.0f, 4.0f);
|
|
}
|
|
|
|
|
|
|
|
// Forward declarations
|
|
class App;
|
|
class Container;
|
|
namespace crude_json { struct value; }
|
|
|
|
class Block
|
|
{
|
|
public:
|
|
Block(int id, const char* name)
|
|
: m_ID(id)
|
|
, m_Name(name)
|
|
, m_Type(NodeType::Blueprint)
|
|
, m_Color(ImColor(255, 255, 255))
|
|
, m_bFlags(NHBEHAVIOR_NONE)
|
|
{
|
|
}
|
|
|
|
virtual ~Block() = default;
|
|
|
|
// Core identification
|
|
int GetID() const { return m_ID; }
|
|
const char* GetName() const { return m_Name.c_str(); }
|
|
const char* GetTypeName() const { return m_TypeName.c_str(); }
|
|
NH_BEHAVIOR_FLAGS GetFlags() const { return m_bFlags; }
|
|
|
|
// Node building (like NHBehavior's CreateInput/CreateOutput)
|
|
virtual void Build(Node& node, App* app) = 0;
|
|
|
|
// Rendering (each block renders itself)
|
|
virtual void Render(Node& node, App* app, Pin* newLinkPin) = 0;
|
|
|
|
// Serialization support
|
|
virtual const char* GetBlockType() const = 0; // Unique type identifier
|
|
|
|
// State save/load callbacks (optional - subclasses can override to save/load custom state)
|
|
// These are called from App::SaveGraph() / App::LoadGraph()
|
|
virtual void SaveState(Node& node, crude_json::value& nodeData, const Container* container, App* app) {}
|
|
virtual void LoadState(Node& node, const crude_json::value& nodeData, Container* container, App* app) {}
|
|
|
|
// Parameter management (like NHBehavior)
|
|
virtual int GetInputParameterCount() const { return 0; }
|
|
virtual int GetOutputParameterCount() const { return 0; }
|
|
virtual int GetInputCount() const { return 0; } // Flow inputs (triggers)
|
|
virtual int GetOutputCount() const { return 0; } // Flow outputs (events)
|
|
|
|
// Execution (stub: returns E_OK = 0)
|
|
virtual int Run(Node& node, App* app) { return E_OK; }
|
|
|
|
// Activation API (for flow control)
|
|
virtual void ActivateOutput(int pos, bool active = true);
|
|
virtual bool IsOutputActive(int pos) const;
|
|
virtual void ActivateInput(int pos, bool active = true);
|
|
virtual bool IsInputActive(int pos) const;
|
|
|
|
// Context menu hook - add custom menu items
|
|
virtual void OnMenu(Node& node, App* app) {}
|
|
|
|
// Edit dialog UI hook - add custom UI elements to block edit dialog
|
|
// Called from RenderBlockEditDialog() to allow blocks to append their own settings
|
|
virtual void RenderEditUI(Node& node, App* app) {}
|
|
|
|
// Flow handling
|
|
virtual bool ShouldAutoActivateDefaultOutput() const { return true; }
|
|
|
|
protected:
|
|
// Activation state (stored per-block instance)
|
|
std::vector<bool> m_OutputActive; // Output activation states
|
|
std::vector<bool> m_InputActive; // Input activation states
|
|
int m_ID;
|
|
std::string m_Name;
|
|
std::string m_TypeName;
|
|
NodeType m_Type;
|
|
ImColor m_Color;
|
|
NH_BEHAVIOR_FLAGS m_bFlags; // Behavior flags
|
|
};
|
|
|
|
// Extended block with parameters - like NHBehavior with params
|
|
class ParameterizedBlock : public Block, public ax::NodeRendering::NodeRendererBase
|
|
{
|
|
public:
|
|
ParameterizedBlock(int id, const char* name)
|
|
: Block(id, name)
|
|
{
|
|
}
|
|
|
|
virtual ~ParameterizedBlock() = default;
|
|
|
|
// Parameter creation helpers (like NHBehavior::CreateInputParameter)
|
|
void AddInputParameter(App* app, Node& node, const char* name, PinType type);
|
|
void AddOutputParameter(App* app, Node& node, const char* name, PinType type);
|
|
|
|
// I/O creation (flow control)
|
|
void AddInput(App* app, Node& node, const char* name);
|
|
void AddOutput(App* app, Node& node, const char* name);
|
|
|
|
int GetInputParameterCount() const override { return (int)m_InputParams.size(); }
|
|
int GetOutputParameterCount() const override { return (int)m_OutputParams.size(); }
|
|
int GetInputCount() const override { return (int)m_Inputs.size(); }
|
|
int GetOutputCount() const override { return (int)m_Outputs.size(); }
|
|
|
|
// Default Virtools-style rendering
|
|
void Render(Node& node, App* app, Pin* newLinkPin) override;
|
|
|
|
// Context menu hook - default implementation for parameterized blocks
|
|
void OnMenu(Node& node, App* app) override;
|
|
|
|
// State save/load - override to save/load unconnected parameter input values
|
|
void SaveState(Node& node, crude_json::value& nodeData, const Container* container, App* app) override;
|
|
void LoadState(Node& node, const crude_json::value& nodeData, Container* container, App* app) override;
|
|
|
|
protected:
|
|
// Parameter value helpers (for use in Run() implementations)
|
|
// Get input parameter value - reads from connected parameter node or default value
|
|
static int GetInputParamValueInt(const Pin& pin, Node& node, App* app, int defaultValue = 0);
|
|
static float GetInputParamValueFloat(const Pin& pin, Node& node, App* app, float defaultValue = 0.0f);
|
|
static bool GetInputParamValueBool(const Pin& pin, Node& node, App* app, bool defaultValue = false);
|
|
static std::string GetInputParamValueString(const Pin& pin, Node& node, App* app, const std::string& defaultValue = "");
|
|
|
|
// Set output parameter value - stores value and propagates to connected parameter nodes
|
|
static void SetOutputParamValueInt(const Pin& pin, Node& node, App* app, int value);
|
|
static void SetOutputParamValueFloat(const Pin& pin, Node& node, App* app, float value);
|
|
static void SetOutputParamValueBool(const Pin& pin, Node& node, App* app, bool value);
|
|
static void SetOutputParamValueString(const Pin& pin, Node& node, App* app, const std::string& value);
|
|
|
|
std::vector<int> m_InputParams; // Parameter pin IDs (top)
|
|
std::vector<int> m_OutputParams; // Parameter pin IDs (bottom)
|
|
std::vector<int> m_Inputs; // Flow input IDs (left)
|
|
std::vector<int> m_Outputs; // Flow output IDs (right)
|
|
};
|
|
|
|
// Block factory function signature
|
|
using BlockFactory = std::function<Block*(int id)>;
|
|
|
|
// Block registry - like Virtools' behavior manager
|
|
class BlockRegistry
|
|
{
|
|
public:
|
|
static BlockRegistry& Instance()
|
|
{
|
|
static BlockRegistry instance;
|
|
return instance;
|
|
}
|
|
|
|
void RegisterBlock(const char* typeName, BlockFactory factory)
|
|
{
|
|
m_Factories[typeName] = factory;
|
|
}
|
|
|
|
Block* CreateBlock(const char* typeName, int id)
|
|
{
|
|
auto it = m_Factories.find(typeName);
|
|
if (it != m_Factories.end())
|
|
return it->second(id);
|
|
return nullptr;
|
|
}
|
|
|
|
std::vector<std::string> GetRegisteredTypes() const
|
|
{
|
|
std::vector<std::string> types;
|
|
for (const auto& pair : m_Factories)
|
|
types.push_back(pair.first);
|
|
return types;
|
|
}
|
|
|
|
private:
|
|
BlockRegistry() = default;
|
|
std::map<std::string, BlockFactory> m_Factories;
|
|
};
|
|
|
|
// Helper macro for auto-registration
|
|
#define REGISTER_BLOCK(ClassName, TypeName) \
|
|
namespace { \
|
|
struct ClassName##_Registrar { \
|
|
ClassName##_Registrar() { \
|
|
BlockRegistry::Instance().RegisterBlock(TypeName, \
|
|
[](int id) -> Block* { return new ClassName(id); }); \
|
|
} \
|
|
}; \
|
|
static ClassName##_Registrar g_##ClassName##_Registrar; \
|
|
}
|
|
|