parameters

This commit is contained in:
lovebird 2026-02-03 18:25:25 +01:00
parent 34f99615b2
commit b0ff23aafa
493 changed files with 26772 additions and 62054 deletions

4
.gitignore vendored
View File

@ -8,7 +8,7 @@ bin
*.VC.opendb
*.user
*.ini
*.json
docs/html
docs/docbook
build
node_modules
last-run.log

View File

@ -1,4 +0,0 @@
./docs
./scripts
./tests
./incoming

25
Blueprints.json Normal file
View File

@ -0,0 +1,25 @@
{
"selection": null,
"view":
{
"scroll":
{
"x": 0,
"y": 0
},
"visible_rect":
{
"max":
{
"x": 1000,
"y": 562
},
"min":
{
"x": 0,
"y": 0
}
},
"zoom": 1
}
}

4
BlueprintsGraph.json Normal file
View File

@ -0,0 +1,4 @@
{
"app_links": null,
"app_nodes": null
}

10
Blueprints_window.json Normal file
View File

@ -0,0 +1,10 @@
{
"window": {
"x": -1,
"y": -1,
"width": 1440,
"height": 800,
"monitor": 0,
"maximized": false
}
}

33
CMakeLists.txt Normal file
View File

@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.5)
project(NodeHub)
# ==============================================================================
# Dependencies
# ==============================================================================
include(FetchContent)
# Google Test (for C++ unit tests)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
# Protocol Buffers
FetchContent_Declare(
protobuf
GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git
GIT_TAG v21.9
)
FetchContent_MakeAvailable(protobuf)
# ==============================================================================
# Add subdirectories
# ==============================================================================
add_subdirectory(applications/base)
add_subdirectory(applications/nodehub)
add_subdirectory(applications/protos)
if (BUILD_TESTING)
add_subdirectory(applications/tests)
endif()

View File

@ -1057,7 +1057,7 @@ EXCLUDE = ./build \
./external/stb_image_latest \
./misc \
./NodeEditor/External \
./examples/application
./applications/
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded

View File

@ -1,31 +1,117 @@
cmake_minimum_required(VERSION 3.12)
# Set up vcpkg toolchain
if(DEFINED CMAKE_TOOLCHAIN_FILE AND EXISTS "${CMAKE_TOOLCHAIN_FILE}")
include(${CMAKE_TOOLCHAIN_FILE})
endif()
#------------------------------------------------------------------------------
# ImGui Node Editor examples build configuration.
# - `get_filename_component(... ABSOLUTE CACHE)` resolves the project root to
# an absolute path and stores it in CMake's cache so re-configures reuse it.
# - `USE_FOLDERS` enables logical IDE folders for generated projects.
# - `BUILD_CONSOLE_VARIANTS` toggles additional Win32 console builds.
# - `USE_CONSOLE_AS_STARTUP` selects which target Visual Studio launches.
# - `EXAMPLES_NO_WARNING_FLAGS` holds warning overrides (set to `/W0` on MSVC).
#------------------------------------------------------------------------------
cmake_minimum_required(VERSION 3.5)
# Root project that pulls in the node editor and builds the sample apps.
project(imgui-node-editor)
# Enable testing capabilities with CTest
enable_testing()
# Fetch Google Test framework
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
# Enforce the same compiler settings for gtest as for our project
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
# Option to enable/disable protobuf support (default: ON)
option(ENABLE_PROTOBUF "Enable Protocol Buffers support" ON)
# Protocol Buffers support (optional, via vcpkg)
if (ENABLE_PROTOBUF)
# Try CONFIG mode first (modern protobuf CMake, works with vcpkg)
find_package(protobuf CONFIG QUIET)
if (protobuf_FOUND)
message(STATUS "Protocol Buffers: ENABLED (found via CONFIG mode)")
# Create an interface library to propagate protobuf settings
add_library(protobuf_interface INTERFACE)
target_link_libraries(protobuf_interface INTERFACE
protobuf::libprotobuf
protobuf::libprotoc
)
target_compile_definitions(protobuf_interface INTERFACE ENABLE_PROTOBUF=1)
else()
# Fallback to MODULE mode (legacy FindProtobuf)
find_package(Protobuf QUIET)
if (Protobuf_FOUND)
message(STATUS "Protocol Buffers: ENABLED (found via MODULE mode)")
# Create an interface library to propagate protobuf settings
add_library(protobuf_interface INTERFACE)
target_link_libraries(protobuf_interface INTERFACE ${Protobuf_LIBRARIES})
target_include_directories(protobuf_interface INTERFACE ${Protobuf_INCLUDE_DIRS})
target_compile_definitions(protobuf_interface INTERFACE ENABLE_PROTOBUF=1)
else()
message(WARNING "Protocol Buffers: ENABLED but not found. Install via 'vcpkg install protobuf[zlib] protobuf[zlib]:x64-windows' or set ENABLE_PROTOBUF=OFF")
message(WARNING " To use vcpkg, configure CMake with: -DCMAKE_TOOLCHAIN_FILE=[path to vcpkg]/scripts/buildsystems/vcpkg.cmake")
endif()
endif()
else()
message(STATUS "Protocol Buffers: DISABLED")
endif()
# Define IMGUI_NODE_EDITOR_ROOT_DIR pointing to project root directory
get_filename_component(IMGUI_NODE_EDITOR_ROOT_DIR ${CMAKE_SOURCE_DIR}/.. ABSOLUTE CACHE)
# Define IMGUI_NODE_EDITOR_ROOT_DIR pointing to project root directory
get_filename_component(ROOT_DIR ${CMAKE_SOURCE_DIR}/.. ABSOLUTE CACHE)
# Ensure IDE generators expose logical folder groupings instead of a flat list.
# Enable solution folders in Visual Studio and Folders in Xcode
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# Extend the module search path so `find_package(imgui_node_editor)` locates the
# custom `Findimgui_node_editor.cmake` bundled with this repository.
# Point CMake where to look for module files.
list(APPEND CMAKE_MODULE_PATH ${IMGUI_NODE_EDITOR_ROOT_DIR}/misc/cmake-modules)
# Central place to tweak warning configuration for all example targets.
if (MSVC)
set(EXAMPLES_NO_WARNING_FLAGS "/W0" CACHE STRING "Compiler warning overrides applied to all example targets" FORCE)
elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
set(EXAMPLES_NO_WARNING_FLAGS "-w" CACHE STRING "Compiler warning overrides applied to all example targets" FORCE)
else()
set(EXAMPLES_NO_WARNING_FLAGS "" CACHE STRING "Compiler warning overrides applied to all example targets" FORCE)
endif()
# Examples use C++17 features (structured bindings, custom unordered_map hash).
# Node editor use C++17 (required for structured bindings and unordered_map with custom hash)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
# Make it easy to toggle console builds without editing the file.
# Option to also build console variants on Windows
option(BUILD_CONSOLE_VARIANTS "Also build console variants of applications on Windows" ON)
# option(BUILD_CONSOLE_VARIANTS "Also build console variants of applications on Windows" ON)
# Let developers choose which target Visual Studio launches by default.
# Option to set console variant as default VS startup project
option(USE_CONSOLE_AS_STARTUP "Set console variant as Visual Studio startup project" ON)
# option(USE_CONSOLE_AS_STARTUP "Set console variant as Visual Studio startup project" ON)
# Macro that will configure an example application
macro(add_example_executable name)
# Start a nested project for each example so properties such as versioning
# remain isolated.
project(${name})
# Collect all sources provided by the caller.
set(_Example_Sources
${ARGN}
)
@ -37,24 +123,26 @@ macro(add_example_executable name)
# Group example sources under their tree
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${ARGN})
# Group entry_point.cpp separately since it's from application directory
source_group("application" FILES ${APPLICATION_ENTRY_POINT_SOURCE})
source_group("base" FILES ${APPLICATION_ENTRY_POINT_SOURCE})
file(GLOB _Example_CommonResources CONFIGURE_DEPENDS "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/data/*")
file(GLOB _Nodehub_CommonResources CONFIGURE_DEPENDS "${IMGUI_NODE_EDITOR_ROOT_DIR}/applications/nodehub/data/*")
file(GLOB _Example_CommonResources CONFIGURE_DEPENDS "${IMGUI_NODE_EDITOR_ROOT_DIR}/applications/base/data/*")
file(GLOB _Example_Resources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/data/*")
#message(FATAL_ERROR "_Example_Resources = ${_Example_Resources}")
# Choose bundle/executable type depending on platform.
set(_Example_Type)
if (WIN32)
set(_Example_Type WIN32)
set(ApplicationIcon ${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/Application/Support/Icon.ico)
set(ApplicationIcon ${IMGUI_NODE_EDITOR_ROOT_DIR}/applications/base/support/Icon.ico)
file(TO_NATIVE_PATH "${ApplicationIcon}" ApplicationIcon)
string(REPLACE "\\" "\\\\" ApplicationIcon "${ApplicationIcon}")
configure_file(
${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/Application/Support/Resource.rc.in
${IMGUI_NODE_EDITOR_ROOT_DIR}/applications/base/support/Resource.rc.in
${CMAKE_CURRENT_BINARY_DIR}/Resource.rc
)
source_group(TREE "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples" FILES ${_Example_CommonResources})
source_group(TREE "${IMGUI_NODE_EDITOR_ROOT_DIR}/applications/base" FILES ${_Example_CommonResources})
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${_Example_Resources})
list(APPEND _Example_Resources
${CMAKE_CURRENT_BINARY_DIR}/Resource.rc
@ -67,7 +155,7 @@ macro(add_example_executable name)
set_source_files_properties(${_Example_Resources} ${_Example_CommonResources} PROPERTIES
MACOSX_PACKAGE_LOCATION "Resources/data"
)
set(_Example_Icon "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/application/support/Icon.icns")
set(_Example_Icon "${IMGUI_NODE_EDITOR_ROOT_DIR}/applications/base/support/Icon.icns")
list(APPEND _Example_Resources ${_Example_Icon})
set_source_files_properties(${_Example_Icon} PROPERTIES
MACOSX_PACKAGE_LOCATION "Resources"
@ -76,6 +164,10 @@ macro(add_example_executable name)
add_executable(${name} ${_Example_Type} ${_Example_Sources} ${_Example_Resources} ${_Example_CommonResources})
if (EXAMPLES_NO_WARNING_FLAGS)
target_compile_options(${name} PRIVATE ${EXAMPLES_NO_WARNING_FLAGS})
endif()
# Add /FS flag for MSVC to prevent PDB locking issues during parallel builds
if (WIN32 AND MSVC)
target_compile_options(${name} PRIVATE /FS)
@ -83,12 +175,17 @@ macro(add_example_executable name)
find_package(imgui REQUIRED)
find_package(imgui_node_editor REQUIRED)
target_link_libraries(${name} PRIVATE imgui imgui_node_editor application)
target_link_libraries(${name} PRIVATE imgui imgui_node_editor base)
# Link protobuf if available
if (ENABLE_PROTOBUF AND TARGET protobuf_interface)
target_link_libraries(${name} PRIVATE protobuf_interface)
endif()
set(_ExampleBinDir ${CMAKE_BINARY_DIR}/bin)
set_target_properties(${name} PROPERTIES
FOLDER "examples"
FOLDER "applications"
RUNTIME_OUTPUT_DIRECTORY "${_ExampleBinDir}"
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${_ExampleBinDir}"
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${_ExampleBinDir}"
@ -98,7 +195,7 @@ macro(add_example_executable name)
RELWITHDEBINGO_POSTFIX _rd
MINSIZEREL_POSTFIX _r
VS_DEBUGGER_WORKING_DIRECTORY ${_ExampleBinDir}
MACOSX_BUNDLE_INFO_PLIST "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/application/support/Info.plist.in"
MACOSX_BUNDLE_INFO_PLIST "${IMGUI_NODE_EDITOR_ROOT_DIR}/applications/base/support/Info.plist.in"
MACOSX_BUNDLE_BUNDLE_NAME "${PACKAGE_NAME}"
MACOSX_BUNDLE_GUI_IDENTIFIER "com.sandbox.collisions"
MACOSX_BUNDLE_LONG_VERSION_STRING "${PACKAGE_VERSION}"
@ -106,6 +203,7 @@ macro(add_example_executable name)
MACOSX_BUNDLE_ICON_FILE Icon.icns
)
# Ensure the runtime data directory exists before copying anything in.
add_custom_command(
TARGET ${name}
PRE_BUILD
@ -113,7 +211,9 @@ macro(add_example_executable name)
)
set(_ResourceRoot ${CMAKE_CURRENT_SOURCE_DIR})
foreach(_Resource ROOT "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/data" ${_Example_CommonResources} ROOT "${CMAKE_CURRENT_SOURCE_DIR}/data" ${_Example_Resources})
# Copy both shared and example-specific data into the runtime folder while
# preserving relative paths.
foreach(_Resource ROOT "${IMGUI_NODE_EDITOR_ROOT_DIR}/applications/base/data" ${_Example_CommonResources} ROOT "${CMAKE_CURRENT_SOURCE_DIR}/data" ${_Example_Resources})
if (_Resource STREQUAL ROOT)
set(_ResourceRoot FALSE)
continue()
@ -144,6 +244,10 @@ macro(add_example_executable name)
# Create console executable (without WIN32 flag)
add_executable(${_ConsoleTargetName} ${_Example_Sources} ${_Example_Resources} ${_Example_CommonResources})
if (EXAMPLES_NO_WARNING_FLAGS)
target_compile_options(${_ConsoleTargetName} PRIVATE ${EXAMPLES_NO_WARNING_FLAGS})
endif()
# Define _CONSOLE to use main() instead of WinMain()
target_compile_definitions(${_ConsoleTargetName} PRIVATE _CONSOLE)
@ -157,6 +261,11 @@ macro(add_example_executable name)
find_package(imgui_node_editor REQUIRED)
target_link_libraries(${_ConsoleTargetName} PRIVATE imgui imgui_node_editor application)
# Link protobuf if available
if (ENABLE_PROTOBUF AND TARGET protobuf_interface)
target_link_libraries(${_ConsoleTargetName} PRIVATE protobuf_interface)
endif()
# Set the same properties as the GUI version
set_target_properties(${_ConsoleTargetName} PROPERTIES
FOLDER "examples"
@ -178,7 +287,7 @@ macro(add_example_executable name)
COMMAND ${CMAKE_COMMAND} -E make_directory ARGS ${_ExampleBinDir}/data
)
foreach(_Resource ROOT "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/data" ${_Example_CommonResources} ROOT "${CMAKE_CURRENT_SOURCE_DIR}/data" ${_Example_Resources})
foreach(_Resource ROOT "${IMGUI_NODE_EDITOR_ROOT_DIR}/applications/base/data" ${_Example_CommonResources} ROOT "${CMAKE_CURRENT_SOURCE_DIR}/data" ${_Example_Resources})
if (_Resource STREQUAL ROOT)
set(_ResourceRoot FALSE)
continue()
@ -193,6 +302,7 @@ macro(add_example_executable name)
file(RELATIVE_PATH _RelResource ${_ResourceRoot} ${_Resource})
# Reuse the resource copying logic for the console binary.
add_custom_command(
TARGET ${_ConsoleTargetName}
PRE_BUILD
@ -203,14 +313,16 @@ macro(add_example_executable name)
endmacro()
add_subdirectory(application)
add_subdirectory(blueprints-example)
# Build the shared application support code and individual examples.
add_subdirectory(base)
add_subdirectory(nodehub)
add_subdirectory(tests)
# Set the default Visual Studio startup project
if (WIN32 AND BUILD_CONSOLE_VARIANTS AND USE_CONSOLE_AS_STARTUP)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT blueprints-example-console)
message(STATUS "Visual Studio startup project: blueprints-example-console")
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT nodehub-console)
message(STATUS "Visual Studio startup project: nodehub-console")
else()
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT blueprints-example)
message(STATUS "Visual Studio startup project: blueprints-example")
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT nodehub)
message(STATUS "Visual Studio startup project: nodehub")
endif()

View File

@ -1,8 +1,9 @@
project(application)
cmake_minimum_required(VERSION 3.5)
project(base)
set(_Application_Sources
include/application.h
source/application.cpp
set(_base_Sources
include/base.h
source/base.cpp
source/entry_point.cpp
source/imgui_extra_keys.h
source/config.h.in
@ -18,23 +19,23 @@ set(_Application_Sources
# entry_point.cpp is not included in the library because it has
# conditional compilation for WinMain() vs main() based on _CONSOLE define.
# It will be added directly to each executable target instead.
set(APPLICATION_ENTRY_POINT_SOURCE
set(base_ENTRY_POINT_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/source/entry_point.cpp
CACHE INTERNAL ""
)
add_library(application STATIC)
add_library(base STATIC)
target_include_directories(application PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_include_directories(base PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
find_package(imgui REQUIRED)
find_package(stb_image REQUIRED)
find_package(ScopeGuard REQUIRED)
target_link_libraries(application PUBLIC imgui)
target_link_libraries(application PRIVATE stb_image ScopeGuard)
target_link_libraries(base PUBLIC imgui)
target_link_libraries(base PRIVATE stb_image ScopeGuard)
if (WIN32)
list(APPEND _Application_Sources
list(APPEND _base_Sources
source/imgui_impl_dx11.cpp
source/imgui_impl_dx11.h
source/imgui_impl_win32.cpp
@ -59,13 +60,13 @@ if (WIN32)
INTERFACE_LINK_LIBRARIES "$<$<CONFIG:Debug>:dxerr>"
)
target_link_libraries(application PRIVATE d3d11.lib d3dcompiler.lib d3dx11)
target_link_libraries(base PRIVATE d3d11.lib d3dcompiler.lib d3dx11)
else()
find_package(OpenGL REQUIRED)
find_package(glfw3 3 REQUIRED)
if (APPLE)
target_link_libraries(application PRIVATE
target_link_libraries(base PRIVATE
"-framework CoreFoundation"
"-framework Cocoa"
"-framework IOKit"
@ -77,9 +78,9 @@ endif()
if (OpenGL_FOUND)
set(HAVE_OPENGL YES)
target_include_directories(application PRIVATE ${OPENGL_INCLUDE_DIR})
target_link_libraries(application PRIVATE ${OPENGL_gl_LIBRARY})
list(APPEND _Application_Sources
target_include_directories(base PRIVATE ${OPENGL_INCLUDE_DIR})
target_link_libraries(base PRIVATE ${OPENGL_gl_LIBRARY})
list(APPEND _base_Sources
source/imgui_impl_opengl3.cpp
source/imgui_impl_opengl3.h
source/imgui_impl_opengl3_loader.h
@ -89,11 +90,11 @@ endif()
if (glfw3_FOUND)
set(HAVE_GLFW3 YES)
list(APPEND _Application_Sources
list(APPEND _base_Sources
source/imgui_impl_glfw.cpp
source/imgui_impl_glfw.h
)
target_link_libraries(application PRIVATE
target_link_libraries(base PRIVATE
glfw
)
endif()
@ -103,16 +104,16 @@ configure_file(
${CMAKE_CURRENT_BINARY_DIR}/source/config.h
)
target_compile_definitions(application PRIVATE
target_compile_definitions(base PRIVATE
#BACKEND_CONFIG=IMGUI_GLFW
#RENDERER_CONFIG=IMGUI_OGL3
)
# Make config.h include directory PUBLIC since entry_point.cpp (which needs it) is now compiled in executables
target_include_directories(application PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/source)
target_include_directories(base PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/source)
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${_Application_Sources})
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${_base_Sources})
target_sources(application PRIVATE ${_Application_Sources})
target_sources(base PRIVATE ${_base_Sources})
set_property(TARGET application PROPERTY FOLDER "examples")
set_property(TARGET base PROPERTY FOLDER "applications")

View File

@ -0,0 +1,33 @@
#ifndef APP_TYPES_H
#define APP_TYPES_H
# include <string>
# include <memory>
# include <map>
# include <vector>
#include <string>
struct ArgValue
{
enum class Type { Empty, Bool, Int, Double, String };
Type Type = Type::Empty;
bool Bool = false;
long long Int = 0;
double Double = 0.0;
std::string String;
ArgValue() = default;
ArgValue(bool value) : Type(Type::Bool), Bool(value) {}
ArgValue(int value) : Type(Type::Int), Int(value) {}
ArgValue(long long value) : Type(Type::Int), Int(value) {}
ArgValue(float value) : Type(Type::Double), Double(value) {}
ArgValue(double value) : Type(Type::Double), Double(value) {}
ArgValue(const char* value) : Type(Type::String), String(value) {}
ArgValue(std::string value) : Type(Type::String), String(std::move(value)) {}
};
using ArgsMap = std::map<std::string, ArgValue>;
#endif

View File

@ -5,6 +5,9 @@
# include <map>
# include <vector>
# include "app-types.h"
struct WindowState
{
int x = -1;
@ -15,29 +18,6 @@ struct WindowState
bool maximized = false;
};
struct ArgValue
{
enum class Type { Empty, Bool, Int, Double, String };
Type Type = Type::Empty;
bool Bool = false;
long long Int = 0;
double Double = 0.0;
std::string String;
ArgValue() = default;
ArgValue(bool value) : Type(Type::Bool), Bool(value) {}
ArgValue(int value) : Type(Type::Int), Int(value) {}
ArgValue(long long value) : Type(Type::Int), Int(value) {}
ArgValue(float value) : Type(Type::Double), Double(value) {}
ArgValue(double value) : Type(Type::Double), Double(value) {}
ArgValue(const char* value) : Type(Type::String), String(value) {}
ArgValue(std::string value) : Type(Type::String), String(std::move(value)) {}
};
using ArgsMap = std::map<std::string, ArgValue>;
struct Platform;
struct Renderer;

View File

@ -1,4 +1,4 @@
# include "application.h"
# include "base.h"
# include "setup.h"
# include "platform.h"
# include "renderer.h"
@ -14,6 +14,71 @@
# include <cstdio>
#endif
namespace {
#ifdef _WIN32
static inline std::string WideToUtf8(const wchar_t* wstr) {
if (!wstr) return {};
// Ask for required size (includes NUL)
const int n = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
if (n <= 0) return {};
std::string out;
out.resize(n - 1); // we store without the trailing NUL
#if __cplusplus >= 201703L
// C++17: string::data() is char*
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, out.data(), n, nullptr, nullptr);
#else
// C++11/14: use &out[0] to get char*
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &out[0], n, nullptr, nullptr);
#endif
// The call above wrote a NUL at the end because we passed length n.
// Keep size at n-1 (already set via resize).
return out;
}
static std::string GetExecutableDir()
{
wchar_t exe_path_buffer[MAX_PATH] = { 0 };
if (GetModuleFileNameW(NULL, exe_path_buffer, MAX_PATH) == 0)
return "";
std::wstring exe_path(exe_path_buffer);
size_t last_slash = exe_path.find_last_of(L"\\/");
if (last_slash == std::wstring::npos)
return "";
return WideToUtf8(exe_path.substr(0, last_slash).c_str());
}
#else
static std::string GetExecutableDir()
{
// Implementation for other platforms (e.g., Linux, macOS) would go here.
return "";
}
#endif
static std::string ResolveResourcePath(const std::string& relativePath)
{
static const std::string exeDir = GetExecutableDir();
if (!exeDir.empty())
{
std::string exePath = exeDir + "/" + relativePath;
std::ifstream f(exePath);
if (f.good())
{
return exePath;
}
}
// Fallback to CWD
return relativePath;
}
} // namespace
extern "C" {
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_STATIC
@ -22,11 +87,7 @@ extern "C" {
Application::Application(const char* name)
: Application(name, {})
{
int d = 2;
d++;
}
: Application(name, {}){}
Application::Application(const char* name, const ArgsMap& args)
: m_Name(name)
@ -170,8 +231,8 @@ void Application::RecreateFontAtlas()
config.OversampleV = 4;
config.PixelSnapH = false;
m_DefaultFont = io.Fonts->AddFontFromFileTTF("data/Play-Regular.ttf", 18.0f, &config);
m_HeaderFont = io.Fonts->AddFontFromFileTTF("data/Cuprum-Bold.ttf", 20.0f, &config);
m_DefaultFont = io.Fonts->AddFontFromFileTTF(ResolveResourcePath("data/Play-Regular.ttf").c_str(), 18.0f, &config);
m_HeaderFont = io.Fonts->AddFontFromFileTTF(ResolveResourcePath("data/Cuprum-Bold.ttf").c_str(), 20.0f, &config);
io.Fonts->Build();
}
@ -273,7 +334,7 @@ ImFont* Application::HeaderFont() const
ImTextureID Application::LoadTexture(const char* path)
{
int width = 0, height = 0, component = 0;
if (auto data = stbi_load(path, &width, &height, &component, 4))
if (auto data = stbi_load(ResolveResourcePath(path).c_str(), &width, &height, &component, 4))
{
auto texture = CreateTexture(data, width, height);
stbi_image_free(data);

View File

@ -0,0 +1,4 @@
# pragma once
# define HAVE_GLFW3 0
# define HAVE_OPENGL 0

View File

@ -1,6 +1,6 @@
#define _CRT_SECURE_NO_WARNINGS
# include "application.h"
# include "base.h"
# include "platform.h"
# include <map>
# include <vector>
@ -44,7 +44,7 @@ public:
// Runtime execution options
app.add_flag("--run", "Execute the graph runtime (used with --headless and --graph)");
app.add_option("--log", "Logging options (all, blocks, links, none)")->capture_default_str();
app.add_option("--log", "Path to log file (absolute or relative)")->capture_default_str();
app.add_option("--log-level", "Minimum logging level (trace, debug, info, warn, error, critical, off)")->capture_default_str();
// Manual pre-check for help flag because allow_extras() interferes with normal help handling
@ -68,9 +68,16 @@ public:
for (const CLI::Option* option : app.get_options())
{
if(option->count() > 0 && !option->get_lnames().empty() && !option->results().empty())
if(option->count() > 0 && !option->get_lnames().empty())
{
(*args_map)[option->get_lnames()[0]] = ParseValue(option->results()[0]);
if (!option->results().empty())
{
(*args_map)[option->get_lnames()[0]] = ParseValue(option->results()[0]);
}
else
{
(*args_map)[option->get_lnames()[0]] = ArgValue(true);
}
}
}

View File

@ -3,7 +3,7 @@
# if BACKEND(IMGUI_WIN32)
# include "application.h"
# include "base.h"
# include "renderer.h"
# define NOMINMAX

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

View File

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

Before

Width:  |  Height:  |  Size: 332 B

After

Width:  |  Height:  |  Size: 332 B

View File

Before

Width:  |  Height:  |  Size: 168 B

After

Width:  |  Height:  |  Size: 168 B

View File

@ -0,0 +1,112 @@
cmake_minimum_required(VERSION 3.5)
add_example_executable(nodehub
main.cpp
types.h
app.h
app.cpp
app-logic.cpp
app-render.cpp
app-screenshot.cpp
app-runtime.cpp
containers/container.h
containers/container.cpp
containers/root_container.h
containers/root_container.cpp
core/graph_state.h
core/graph_state.cpp
core/Object.h
core/Object.cpp
core/Parameter.h
core/Parameter.cpp
core/ParameterIn.h
core/ParameterIn.cpp
core/ParameterOut.h
core/ParameterOut.cpp
core/ParameterManager.h
core/ParameterManager.cpp
core/BaseManager.h
core/BaseManager.cpp
core/Context.h
core/Context.cpp
blocks/NodeEx.h
blocks/NodeEx.cpp
blocks/block.h
blocks/block.cpp
blocks/math_blocks.h
blocks/math_blocks.cpp
blocks/logic_blocks.h
blocks/logic_blocks.cpp
blocks/start_block.h
blocks/start_block.cpp
blocks/log_block.h
blocks/log_block.cpp
blocks/parameter_operation.h
blocks/parameter_operation.cpp
blocks/group_block.h
blocks/group_block.cpp
blocks/parameter_node.h
blocks/parameter_node.cpp
blocks/block_edit_dialog.h
blocks/block_edit_dialog.cpp
blocks/parameter_edit_dialog.h
blocks/parameter_edit_dialog.cpp
utilities/node_renderer_base.h
utilities/pathfinding.h
utilities/edge_editing.h
utilities/pin_renderer.h
utilities/style_manager.h
utilities/uuid_generator.h
utilities/uuid_id_manager.h
utilities/node_renderer_base.cpp
utilities/pathfinding.cpp
utilities/edge_editing.cpp
utilities/pin_renderer.cpp
utilities/style_manager.cpp
utilities/uuid_generator.cpp
utilities/uuid_id_manager.cpp
Logging.h
Logging.cpp
stats.cpp
)
target_include_directories(nodehub PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../application/include")
target_include_directories(nodehub PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../nodehub/core")
target_include_directories(nodehub PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../nodehub/blocks")
# Add local spdlog include directory (we copied it into our project)
target_include_directories(nodehub PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/external")
target_compile_definitions(nodehub PRIVATE FMT_HEADER_ONLY=1)
# Add /utf-8 compiler flag for spdlog on MSVC
if (MSVC)
target_compile_options(nodehub PRIVATE /utf-8)
endif()
# Link protobuf if available
if (PROTOBUF_AVAILABLE AND TARGET protobuf_interface)
target_link_libraries(nodehub PRIVATE protobuf_interface)
endif()
# Also add to console variant if it exists
if (WIN32 AND BUILD_CONSOLE_VARIANTS)
target_include_directories(nodehub-console PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../application/include")
target_include_directories(nodehub-console PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/external")
target_compile_definitions(nodehub-console PRIVATE FMT_HEADER_ONLY=1)
if (MSVC)
target_compile_options(nodehub-console PRIVATE /utf-8)
endif()
# Link protobuf to console variant if available
if (PROTOBUF_AVAILABLE AND TARGET protobuf_interface)
target_link_libraries(nodehub-console PRIVATE protobuf_interface)
endif()
endif()
file(GLOB NodeHubResources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/data/*")
add_custom_command(
TARGET nodehub
PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_CURRENT_SOURCE_DIR}/data"
"$<TARGET_FILE_DIR:nodehub>/data"
)

View File

@ -0,0 +1,14 @@
#pragma once
// v2
#include "commons.h"
#include "core/Object.h"
#include "core/Parameter.h"
#include "utilities/uuid_generator.h"
//legacy blocks - v1
#include "blocks/block.h"
#include "blocks/parameter_node.h"
#include "blocks/parameter_operation.h"

View File

@ -482,19 +482,6 @@ void App::SaveGraph(const std::string& filename, RootContainer* container)
continue;
}
// Validate node pointer is not corrupted
uintptr_t nodePtrValue = reinterpret_cast<uintptr_t>(nodePtr);
if (nodePtrValue < 0x1000 ||
nodePtrValue == 0xFFFFFFFFFFFFFFFFULL ||
nodePtrValue == 0xDDDDDDDDDDDDDDDDULL ||
nodePtrValue == 0xCDCDCDCDCDCDCDCDULL)
{
LOG_WARN("[SAVE] SaveGraph: Skipping corrupted node pointer: 0x{:016X}",
static_cast<unsigned long long>(nodePtrValue));
orphanedNodes.push_back(const_cast<Node*>(nodePtr));
continue;
}
// Safe access to node type
NodeType nodeType;
try {

View File

@ -447,4 +447,5 @@ bool App::ExecuteRuntimeStep()
return didAnyWork;
}
return false;
}

View File

@ -4,38 +4,6 @@
#include <string>
#include <ctime>
// Helper function to log to blueprints-log.md
static void LogToFile(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
// Always log to stdout/console
vprintf(fmt, args);
printf("\n");
fflush(stdout);
// Log to blueprints-log.md (in the same directory as the executable)
// The app runs from build/bin/, so just use relative path
static FILE* logFile = nullptr;
if (!logFile)
{
logFile = fopen("blueprints-log.md", "a");
if (logFile)
{
fprintf(logFile, "\n");
}
}
if (logFile)
{
vfprintf(logFile, fmt, args);
fprintf(logFile, "\n");
fflush(logFile);
}
va_end(args);
}
void App::TakeScreenshot(const char* filename)
{
@ -58,8 +26,6 @@ void App::TakeScreenshot(const char* filename)
printf("App::TakeScreenshot - Using provided filename: %s\n", fname.c_str());
}
LogToFile("Screenshot: Starting screenshot capture...");
LogToFile("Screenshot: Using filename: %s", fname.c_str());
// Delegate to Application base class which calls the renderer
bool success = Application::TakeScreenshot(fname.c_str());
@ -71,13 +37,13 @@ void App::TakeScreenshot(const char* filename)
{
m_ScreenshotMessage = "Screenshot saved: " + fname;
m_ScreenshotMessageTime = 5.0f;
LogToFile("Screenshot: SUCCESS - Screenshot saved to: %s", fname.c_str());
}
else
{
m_ScreenshotMessage = "Failed to save screenshot: " + fname;
m_ScreenshotMessageTime = 5.0f;
LogToFile("Screenshot: FAILED - Could not save screenshot");
}
}

View File

@ -1,16 +1,39 @@
#define IMGUI_DEFINE_MATH_OPERATORS
#include "app.h"
#include "nodes.h"
#include "containers/root_container.h"
#include "Logging.h"
#include <imgui_node_editor.h>
#include <imgui_node_editor_internal.h>
#include <app-types.h>
namespace ed = ax::NodeEditor;
ed::EditorContext* m_Editor = nullptr;
void App::OnStart()
App::App(const char* name) : Application(name){
m_Context = new NH_Context();
initLogger();
// m_Context->SetParameterManager(new NH_ParameterManager(m_Context));
}
App::App(const char* name, const ArgsMap& args) : Application(name, args){
m_Context = new NH_Context();
initLogger();
}
App::App() : Application("Blueprints"){
m_Context = new NH_Context();
initLogger();
}
NH_Context* App::GetContext()
{
return m_Context;
}
void App::initLogger()
{
// Determine desired log level from CLI args
std::string logLevelArg = "debug";
@ -35,9 +58,10 @@ void App::OnStart()
{
LOG_WARN("Unknown log level '{}', defaulting to 'debug'", logLevelArg);
}
}
LOG_TRACE("[CHECKPOINT] OnStart: Beginning");
void App::OnStart()
{
// Get graph filename from CLI args (--graph), default to BlueprintsGraph.json
// Supports both relative and absolute paths
auto it = m_Args.find("graph");
@ -51,7 +75,7 @@ void App::OnStart()
LOG_INFO("Using default graph file: {}", m_GraphFilename);
}
LOG_TRACE("[CHECKPOINT] OnStart: About to create root container");
// Create default root container from graph filename
AddRootContainer(m_GraphFilename);
@ -196,7 +220,11 @@ void App::OnStart()
BuildNodes();
LOG_TRACE("[CHECKPOINT] OnStart: Nodes built, about to load textures");
LOG_TRACE("[CHECKPOINT] OnStart: Nodes built, about to initialize context");
m_Context->init(this);
LOG_TRACE("[CHECKPOINT] OnStart: Context initialized, about to load textures");
m_HeaderBackground = LoadTexture("data/BlueprintBackground.png");
m_SaveIcon = LoadTexture("data/ic_save_white_24dp.png");

View File

@ -1,5 +1,5 @@
#pragma once
#include <application.h>
#include <base.h>
#include "types.h"
#include "blocks/parameter_node.h"
#include "utilities/edge_editing.h"
@ -11,11 +11,20 @@
#include "core/graph_state.h"
#include <map>
#include "app-types.h"
#include "core/Context.h"
namespace ed = ax::NodeEditor;
class App: public Application
{
public:
App();
App(const char* name);
App(const char* name, const ArgsMap& args);
using Application::Application;
// Application lifecycle
@ -159,7 +168,10 @@ public:
// Made public so blocks can access it for visualization
std::map<ed::NodeId, float, NodeIdLess> m_RunningNodes; // Node ID -> expiration time
NH_Context* GetContext();
private:
void initLogger();
// Container management delegated to GraphState - see m_GraphState
// Link highlighting for Run() visualization
std::map<ed::LinkId, float, LinkIdLess> m_HighlightedLinks; // Link ID -> expiration time
@ -184,5 +196,8 @@ private:
Pin* m_NewLinkPin = nullptr;
float m_LeftPaneWidth = 400.0f;
float m_RightPaneWidth = 800.0f;
NH_Context *m_Context;
};

View File

@ -1,14 +1,16 @@
#define IMGUI_DEFINE_MATH_OPERATORS
#include <crude_json.h>
#include "block.h"
#include "../app.h"
#include "../utilities/node_renderer_base.h"
#include "../containers/container.h"
#include "../../crude_json.h"
#include "NodeEx.h"
#include "constants.h"
#include <imgui_node_editor.h>
#include <imgui_internal.h>
#include <set>
#include "../Logging.h"
namespace ed = ax::NodeEditor;
using namespace ax::NodeRendering;
@ -41,7 +43,7 @@ static void RenderFlowPin(ImDrawList* drawList, const ImVec2& center, const ImVe
void ParameterizedBlock::Render(Node& node, App* app, Pin* newLinkPin)
{
// Check if node is currently running (for red border visualization)
float currentTime = ImGui::GetTime();
double currentTime = (double)ImGui::GetTime();
bool isRunning = false;
auto runningIt = app->m_RunningNodes.find(node.ID);
if (runningIt != app->m_RunningNodes.end())
@ -234,7 +236,7 @@ void ParameterizedBlock::Render(Node& node, App* app, Pin* newLinkPin)
// NodeStyleScope destructor handles cleanup automatically
}
void ParameterizedBlock::AddInputParameter(App* app, Node& node, const char* name, PinType type)
void ParameterizedBlock::AddInputParameter(App* app, Node& node, NH_CSTRING name, PinType type)
{
int pinId = app->GetNextId();
m_InputParams.push_back(pinId);
@ -242,7 +244,7 @@ void ParameterizedBlock::AddInputParameter(App* app, Node& node, const char* nam
node.Inputs.emplace_back(pinId, name, type);
}
void ParameterizedBlock::AddOutputParameter(App* app, Node& node, const char* name, PinType type)
void ParameterizedBlock::AddOutputParameter(App* app, Node& node, NH_CSTRING name, PinType type)
{
int pinId = app->GetNextId();
m_OutputParams.push_back(pinId);
@ -250,19 +252,19 @@ void ParameterizedBlock::AddOutputParameter(App* app, Node& node, const char* na
node.Outputs.emplace_back(pinId, name, type);
}
void ParameterizedBlock::AddInput(App* app, Node& node, const char* name)
void ParameterizedBlock::AddInput(App* app, Node& node, NH_CSTRING name)
{
int pinId = app->GetNextId();
m_Inputs.push_back(pinId);
const char* displayName = (name && *name) ? name : "";
NH_CSTRING displayName = (name && *name) ? name : "";
node.Inputs.emplace_back(pinId, displayName, PinType::Flow);
}
void ParameterizedBlock::AddOutput(App* app, Node& node, const char* name)
void ParameterizedBlock::AddOutput(App* app, Node& node, NH_CSTRING name)
{
int pinId = app->GetNextId();
m_Outputs.push_back(pinId);
const char* displayName = (name && *name) ? name : "";
NH_CSTRING displayName = (name && *name) ? name : "";
node.Outputs.emplace_back(pinId, displayName, PinType::Flow);
}
@ -321,10 +323,7 @@ void ParameterizedBlock::OnMenu(Node& node, App* app)
if (ImGui::MenuItem("Run (R)"))
{
int result = Run(node, app);
printf("Block '%s' (ID: %d) Run() returned: %d\n",
node.Name.c_str(), node.ID.Get(), result);
ax::NodeEditor::AddInAppLog("Block '%s' (ID: %d) Run() returned: %d\n",
node.Name.c_str(), node.ID.Get(), result);
// LOG_INFO("Block '{}' (ID: {}) Run() returned: {}", node.Name.c_str(), node.ID.Get(), result);
}
}
@ -347,7 +346,7 @@ int ParameterizedBlock::GetInputParamValueInt(const Pin& pin, Node& node, App* a
else if (sourcePin->Node->IsBlockBased())
{
// Source is a block output - read from UnconnectedParamValues
int sourcePinId = sourcePin->ID.Get();
const int sourcePinId = ToRuntimeId(sourcePin->ID);
auto& sourceParamValues = sourcePin->Node->UnconnectedParamValues;
if (sourceParamValues.find(sourcePinId) != sourceParamValues.end())
{
@ -362,7 +361,7 @@ int ParameterizedBlock::GetInputParamValueInt(const Pin& pin, Node& node, App* a
}
// Not connected, use default value from UnconnectedParamValues
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
auto& paramValues = node.UnconnectedParamValues;
if (paramValues.find(pinId) != paramValues.end())
{
@ -394,7 +393,7 @@ float ParameterizedBlock::GetInputParamValueFloat(const Pin& pin, Node& node, Ap
else if (sourcePin->Node->IsBlockBased())
{
// Source is a block output - read from UnconnectedParamValues
int sourcePinId = sourcePin->ID.Get();
const int sourcePinId = ToRuntimeId(sourcePin->ID);
auto& sourceParamValues = sourcePin->Node->UnconnectedParamValues;
if (sourceParamValues.find(sourcePinId) != sourceParamValues.end())
{
@ -409,7 +408,7 @@ float ParameterizedBlock::GetInputParamValueFloat(const Pin& pin, Node& node, Ap
}
// Not connected, use default value from UnconnectedParamValues
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
auto& paramValues = node.UnconnectedParamValues;
if (paramValues.find(pinId) != paramValues.end())
{
@ -441,7 +440,7 @@ bool ParameterizedBlock::GetInputParamValueBool(const Pin& pin, Node& node, App*
else if (sourcePin->Node->IsBlockBased())
{
// Source is a block output - read from UnconnectedParamValues
int sourcePinId = sourcePin->ID.Get();
const int sourcePinId = ToRuntimeId(sourcePin->ID);
auto& sourceParamValues = sourcePin->Node->UnconnectedParamValues;
if (sourceParamValues.find(sourcePinId) != sourceParamValues.end())
{
@ -456,7 +455,7 @@ bool ParameterizedBlock::GetInputParamValueBool(const Pin& pin, Node& node, App*
}
// Not connected, use default value from UnconnectedParamValues
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
auto& paramValues = node.UnconnectedParamValues;
if (paramValues.find(pinId) != paramValues.end())
{
@ -488,7 +487,7 @@ std::string ParameterizedBlock::GetInputParamValueString(const Pin& pin, Node& n
else if (sourcePin->Node->IsBlockBased())
{
// Source is a block output - read from UnconnectedParamValues
int sourcePinId = sourcePin->ID.Get();
const int sourcePinId = ToRuntimeId(sourcePin->ID);
auto& sourceParamValues = sourcePin->Node->UnconnectedParamValues;
auto it = sourceParamValues.find(sourcePinId);
if (it != sourceParamValues.end())
@ -500,7 +499,7 @@ std::string ParameterizedBlock::GetInputParamValueString(const Pin& pin, Node& n
}
// Not connected, use default value from UnconnectedParamValues
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
auto& paramValues = node.UnconnectedParamValues;
auto it = paramValues.find(pinId);
if (it != paramValues.end())
@ -514,7 +513,7 @@ std::string ParameterizedBlock::GetInputParamValueString(const Pin& pin, Node& n
void ParameterizedBlock::SetOutputParamValueInt(const Pin& pin, Node& node, App* app, int value)
{
// Store output value in node's UnconnectedParamValues (output pins can be read by connected nodes)
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
node.UnconnectedParamValues[pinId] = std::to_string(value);
// Propagate to ALL connected parameter nodes (iterate through all links from active container)
@ -542,7 +541,7 @@ void ParameterizedBlock::SetOutputParamValueInt(const Pin& pin, Node& node, App*
void ParameterizedBlock::SetOutputParamValueFloat(const Pin& pin, Node& node, App* app, float value)
{
// Store output value in node's UnconnectedParamValues
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
char buf[32];
snprintf(buf, sizeof(buf), "%.6g", value);
node.UnconnectedParamValues[pinId] = buf;
@ -571,7 +570,7 @@ void ParameterizedBlock::SetOutputParamValueFloat(const Pin& pin, Node& node, Ap
void ParameterizedBlock::SetOutputParamValueBool(const Pin& pin, Node& node, App* app, bool value)
{
// Store output value in node's UnconnectedParamValues
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
node.UnconnectedParamValues[pinId] = value ? "true" : "false";
// Propagate to ALL connected parameter nodes (iterate through all links from active container)
@ -599,7 +598,7 @@ void ParameterizedBlock::SetOutputParamValueBool(const Pin& pin, Node& node, App
void ParameterizedBlock::SetOutputParamValueString(const Pin& pin, Node& node, App* app, const std::string& value)
{
// Store output value in node's UnconnectedParamValues
int pinId = pin.ID.Get();
int pinId = ToRuntimeId(pin.ID);
node.UnconnectedParamValues[pinId] = value;
// Propagate to ALL connected parameter nodes (iterate through all links from active container)
@ -638,7 +637,7 @@ void ParameterizedBlock::SaveState(Node& node, crude_json::value& nodeData, cons
if (pin.Type == PinType::Flow)
continue;
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
auto& paramValues = node.UnconnectedParamValues;
auto it = paramValues.find(pinId);
@ -672,7 +671,7 @@ void ParameterizedBlock::SaveState(Node& node, crude_json::value& nodeData, cons
if (pin.Type == PinType::Flow)
continue;
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
auto& paramValues = node.UnconnectedParamValues;
auto it = paramValues.find(pinId);

View File

@ -1,7 +1,7 @@
#pragma once
#include "../commons.h"
#include "../core/Object.h"
#include "../utilities/node_renderer_base.h"
#include <string>
#include <vector>
@ -9,75 +9,32 @@
#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
class Block : public NH_Object
{
public:
Block(int id, const char* name)
: m_ID(id)
, m_Name(name)
Block(int id, NH_CSTRING name)
: NH_Object(id, 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; }
int GetID() const { return NH_Object::GetID(); }
NH_CSTRING GetName() const { return NH_Object::GetName(); }
NH_CSTRING GetTypeName() const { return NH_Object::GetTypeName(); }
NH_BEHAVIOR_FLAGS GetFlags() const { return GetBehaviorFlags(); }
void SetFlags(NH_BEHAVIOR_FLAGS flags) { SetBehaviorFlags(flags); }
void AddFlags(NH_BEHAVIOR_FLAGS flags) { AddBehaviorFlags(flags); }
void RemoveFlags(NH_BEHAVIOR_FLAGS flags) { RemoveBehaviorFlags(flags); }
// Node building (like NHBehavior's CreateInput/CreateOutput)
virtual void Build(Node& node, App* app) = 0;
@ -86,7 +43,7 @@ public:
virtual void Render(Node& node, App* app, Pin* newLinkPin) = 0;
// Serialization support
virtual const char* GetBlockType() const = 0; // Unique type identifier
virtual NH_CSTRING 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()
@ -122,19 +79,15 @@ 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)
ParameterizedBlock(int id, NH_CSTRING name)
: Block(id, name)
{
}
@ -142,12 +95,12 @@ public:
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);
void AddInputParameter(App* app, Node& node, NH_CSTRING name, PinType type);
void AddOutputParameter(App* app, Node& node, NH_CSTRING 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);
void AddInput(App* app, Node& node, NH_CSTRING name);
void AddOutput(App* app, Node& node, NH_CSTRING name);
int GetInputParameterCount() const override { return (int)m_InputParams.size(); }
int GetOutputParameterCount() const override { return (int)m_OutputParams.size(); }
@ -197,12 +150,12 @@ public:
return instance;
}
void RegisterBlock(const char* typeName, BlockFactory factory)
void RegisterBlock(NH_CSTRING typeName, BlockFactory factory)
{
m_Factories[typeName] = factory;
}
Block* CreateBlock(const char* typeName, int id)
Block* CreateBlock(NH_CSTRING typeName, int id)
{
auto it = m_Factories.find(typeName);
if (it != m_Factories.end())

View File

@ -106,7 +106,7 @@ void RenderBlockEditDialog()
ImGui::SameLine();
ImGui::PushItemWidth(200.0f);
static std::map<int, std::string> nodeNameBuffers; // Per-node name buffers
int nodeId = s_EditingNode->ID.Get();
int nodeId = ToRuntimeId(s_EditingNode->ID);
if (nodeNameBuffers.find(nodeId) == nodeNameBuffers.end())
{
nodeNameBuffers[nodeId] = s_EditingNode->Name;
@ -159,7 +159,7 @@ void RenderBlockEditDialog()
// Editable flow input name
ImGui::PushItemWidth(150.0f);
static std::map<int, std::string> flowInputNameBuffers;
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
if (flowInputNameBuffers.find(pinId) == flowInputNameBuffers.end())
{
flowInputNameBuffers[pinId] = pin.Name;
@ -250,7 +250,7 @@ void RenderBlockEditDialog()
// Editable parameter name
ImGui::PushItemWidth(150.0f);
static std::map<int, std::string> nameBuffers; // Per-pin name buffers
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
if (nameBuffers.find(pinId) == nameBuffers.end())
{
nameBuffers[pinId] = pin.Name;
@ -411,7 +411,7 @@ void RenderBlockEditDialog()
case PinType::String:
{
static std::map<int, std::string> stringBuffers; // Per-pin buffers
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
if (stringBuffers.find(pinId) == stringBuffers.end())
{
stringBuffers[pinId] = paramNode->StringValue;
@ -455,7 +455,7 @@ void RenderBlockEditDialog()
ImGui::PushItemWidth(150.0f);
// Get or create default value
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
auto& paramValues = s_EditingNode->UnconnectedParamValues;
if (paramValues.find(pinId) == paramValues.end())
{
@ -586,7 +586,7 @@ void RenderBlockEditDialog()
// Editable flow output name
ImGui::PushItemWidth(150.0f);
static std::map<int, std::string> flowOutputNameBuffers;
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
if (flowOutputNameBuffers.find(pinId) == flowOutputNameBuffers.end())
{
flowOutputNameBuffers[pinId] = pin.Name;
@ -677,7 +677,7 @@ void RenderBlockEditDialog()
// Editable parameter name
ImGui::PushItemWidth(150.0f);
static std::map<int, std::string> outputNameBuffers; // Per-pin name buffers for outputs
int pinId = pin.ID.Get();
const int pinId = ToRuntimeId(pin.ID);
if (outputNameBuffers.find(pinId) == outputNameBuffers.end())
{
outputNameBuffers[pinId] = pin.Name;
@ -708,7 +708,7 @@ void RenderBlockEditDialog()
// Editable parameter type (combo) for outputs
ImGui::PushItemWidth(100.0f);
static std::map<int, int> outputTypeIndices; // Per-pin type index buffers for outputs
int outputPinId = pin.ID.Get();
const int outputPinId = ToRuntimeId(pin.ID);
const char* outputTypeItems[] = { "Bool", "Int", "Float", "String", "Object", "Function", "Delegate" };
PinType outputTypeValues[] = { PinType::Bool, PinType::Int, PinType::Float, PinType::String, PinType::Object, PinType::Function, PinType::Delegate };

View File

@ -1,7 +1,7 @@
#pragma once
// Forward declarations
class Node;
struct Node;
class App;
void OpenBlockEditDialog(Node* node, App* app);

View File

@ -1,9 +1,9 @@
#define IMGUI_DEFINE_MATH_OPERATORS
#include <crude_json.h>
#include "group_block.h"
#include "../app.h"
#include "block.h"
#include "../utilities/node_renderer_base.h"
#include "../../crude_json.h"
#include "NodeEx.h"
#include "constants.h"
#include "../Logging.h"
@ -317,7 +317,7 @@ void GroupBlock::RenderExpanded(Node& node, App* app, Pin* newLinkPin)
static std::map<int, ImVec2> resizeStartSize;
static std::map<int, ImVec2> resizeStartMouseCanvas;
int nodeId = node.ID.Get();
const int nodeId = ToRuntimeId(node.ID);
if (ImGui::IsItemActive())
{
@ -377,12 +377,12 @@ void GroupBlock::RebuildPins(Node& node, App* app)
for (const auto& input : node.Inputs)
{
if (input.UUID.IsValid())
oldPinUuids[input.ID.Get()] = input.UUID;
oldPinUuids[ToRuntimeId(input.ID)] = input.UUID;
}
for (const auto& output : node.Outputs)
{
if (output.UUID.IsValid())
oldPinUuids[output.ID.Get()] = output.UUID;
oldPinUuids[ToRuntimeId(output.ID)] = output.UUID;
}
LOG_DEBUG("[GroupBlock::RebuildPins] Preserved {} pin UUIDs before rebuild", oldPinUuids.size());
@ -399,7 +399,7 @@ void GroupBlock::RebuildPins(Node& node, App* app)
// Restore or generate UUIDs for pins
for (auto& input : node.Inputs)
{
int pinId = input.ID.Get();
const int pinId = ToRuntimeId(input.ID);
// Try to restore old UUID if this pin ID existed before
auto it = oldPinUuids.find(pinId);
@ -425,7 +425,7 @@ void GroupBlock::RebuildPins(Node& node, App* app)
for (auto& output : node.Outputs)
{
int pinId = output.ID.Get();
const int pinId = ToRuntimeId(output.ID);
// Try to restore old UUID if this pin ID existed before
auto it = oldPinUuids.find(pinId);
@ -863,7 +863,7 @@ void GroupBlock::LoadState(Node& node, const crude_json::value& nodeData, Contai
RebuildPins(node, app);
LOG_DEBUG("[GroupBlock::LoadState] Rebuilt node {} with {} inputs, {} outputs",
node.ID.Get(), node.Inputs.size(), node.Outputs.size());
ToRuntimeId(node.ID), node.Inputs.size(), node.Outputs.size());
// Call base class to load parameter values (after rebuilding structure)
ParameterizedBlock::LoadState(node, nodeData, container, app);

View File

@ -29,19 +29,19 @@ class GroupBlock : public ParameterizedBlock
public:
GroupBlock(int id) : ParameterizedBlock(id, "Group")
{
m_TypeName = "Group";
SetTypeName("Group");
m_Type = NodeType::Group;
m_Color = ImColor(200, 150, 200); // Purple-ish color for groups
m_bFlags = static_cast<NH_BEHAVIOR_FLAGS>(
SetFlags(static_cast<NH_BEHAVIOR_FLAGS>(
NHBEHAVIOR_SCRIPT | NHBEHAVIOR_VARIABLEINPUTS | NHBEHAVIOR_VARIABLEOUTPUTS |
NHBEHAVIOR_VARIABLEPARAMETERINPUTS | NHBEHAVIOR_VARIABLEPARAMETEROUTPUTS);
NHBEHAVIOR_VARIABLEPARAMETERINPUTS | NHBEHAVIOR_VARIABLEPARAMETEROUTPUTS));
m_DisplayMode = GroupDisplayMode::Expanded; // Default to expanded
m_CollapsedSize = ImVec2(150.0f, 80.0f); // Default collapsed size
}
void Build(Node& node, App* app) override;
int Run(Node& node, App* app) override;
const char* GetBlockType() const override { return "Group"; }
NH_CSTRING GetBlockType() const override { return "Group"; }
// Rendering (uses base class rendering like any other block)
void Render(Node& node, App* app, Pin* newLinkPin) override;

View File

@ -1,11 +1,10 @@
#include <crude_json.h>
#include "log_block.h"
#include "../app.h"
#include "../../crude_json.h"
#include "../Logging.h"
#include <fstream>
#include <ctime>
#include <sstream>
#include <map>
#ifdef _WIN32
#include <direct.h>

View File

@ -14,17 +14,17 @@ class LogBlock : public ParameterizedBlock
public:
LogBlock(int id) : ParameterizedBlock(id, "Log")
{
m_TypeName = "Log";
SetTypeName("Log");
m_Type = NodeType::Blueprint;
m_Color = ImColor(255, 200, 100);
m_bFlags = static_cast<NH_BEHAVIOR_FLAGS>(
SetFlags(static_cast<NH_BEHAVIOR_FLAGS>(
NHBEHAVIOR_SCRIPT |
NHBEHAVIOR_VARIABLEINPUTS);
NHBEHAVIOR_VARIABLEINPUTS));
}
void Build(Node& node, App* app) override;
int Run(Node& node, App* app) override;
const char* GetBlockType() const override { return "Log"; }
NH_CSTRING GetBlockType() const override { return "Log"; }
// State save/load to persist variable parameters
void SaveState(Node& node, crude_json::value& nodeData, const Container* container, App* app) override;
@ -56,7 +56,7 @@ private:
// Log settings
template <typename... Args>
void LogWithConfiguredLevel(const char* fmt, Args&&... args) const
void LogWithConfiguredLevel(NH_CSTRING fmt, Args&&... args) const
{
if (m_LogLevel == spdlog::level::off || !g_logger)
return;

View File

@ -2,7 +2,7 @@
#include "../app.h"
#include "../Logging.h"
#include "../../crude_json.h"
#include <crude_json.h>
#include <imgui.h>
#include <map>
#include <string>
@ -32,7 +32,7 @@ LogicTestBlock::LogicTestBlock(int id)
, m_FlowOutputIds({-1, -1})
, m_ValueParamIds({-1, -1})
{
m_TypeName = "Logic.Test";
SetTypeName("Logic.Test");
m_Type = NodeType::Blueprint;
m_Color = ImColor(230, 180, 95);
}
@ -130,7 +130,7 @@ int LogicTestBlock::Run(Node& node, App* app)
if (!valuePins[0] || !valuePins[1])
{
LOG_WARN("[Logic.Test] Missing parameter inputs on node {}", node.ID.Get());
LOG_WARN("[Logic.Test] Missing parameter inputs on node {}", ToRuntimeId(node.ID));
ActivateOutput(0, false);
ActivateOutput(1, false);
return E_OK;
@ -171,7 +171,7 @@ int LogicTestBlock::Run(Node& node, App* app)
}
default:
{
LOG_WARN("[Logic.Test] Unsupported parameter type on node {}", node.ID.Get());
LOG_WARN("[Logic.Test] Unsupported parameter type on node {}", ToRuntimeId(node.ID));
comparisonResult = false;
break;
}
@ -180,7 +180,7 @@ int LogicTestBlock::Run(Node& node, App* app)
ActivateOutput(0, comparisonResult);
ActivateOutput(1, !comparisonResult);
LOG_DEBUG("[Logic.Test] Node {} result={} (operator={})", node.ID.Get(), comparisonResult ? "true" : "false", ToString(m_Operator));
LOG_DEBUG("[Logic.Test] Node {} result={} (operator={})", ToRuntimeId(node.ID), comparisonResult ? "true" : "false", ToString(m_Operator));
return E_OK;
}
@ -230,7 +230,7 @@ void LogicTestBlock::RebuildPins(Node& node, App* app)
std::map<int, Uuid64> oldPinUuids;
for (const auto& input : node.Inputs)
{
int pinId = input.ID.Get();
const int pinId = ToRuntimeId(input.ID);
if (input.UUID.IsValid())
{
oldPinUuids[pinId] = input.UUID;
@ -240,7 +240,7 @@ void LogicTestBlock::RebuildPins(Node& node, App* app)
{
if (output.UUID.IsValid())
{
oldPinUuids[output.ID.Get()] = output.UUID;
oldPinUuids[ToRuntimeId(output.ID)] = output.UUID;
}
}
@ -255,7 +255,7 @@ void LogicTestBlock::RebuildPins(Node& node, App* app)
for (auto& input : node.Inputs)
{
int pinId = input.ID.Get();
const int pinId = ToRuntimeId(input.ID);
auto it = oldPinUuids.find(pinId);
if (it != oldPinUuids.end())
{
@ -273,7 +273,7 @@ void LogicTestBlock::RebuildPins(Node& node, App* app)
for (auto& output : node.Outputs)
{
int pinId = output.ID.Get();
const int pinId = ToRuntimeId(output.ID);
auto it = oldPinUuids.find(pinId);
if (it != oldPinUuids.end())
{
@ -328,7 +328,7 @@ void LogicTestBlock::LoadState(Node& node, const crude_json::value& nodeData, Co
// If IDs were not saved (backward compatibility), capture current IDs from node
if (m_FlowInputId < 0 && !node.Inputs.empty())
m_FlowInputId = node.Inputs.front().ID.Get();
m_FlowInputId = ToRuntimeId(node.Inputs.front().ID);
int paramCounter = 0;
for (const auto& pin : node.Inputs)
@ -338,7 +338,7 @@ void LogicTestBlock::LoadState(Node& node, const crude_json::value& nodeData, Co
int valueIndex = paramCounter;
if (valueIndex < 2 && m_ValueParamIds[valueIndex] < 0)
m_ValueParamIds[valueIndex] = pin.ID.Get();
m_ValueParamIds[valueIndex] = ToRuntimeId(pin.ID);
++paramCounter;
}
@ -350,7 +350,7 @@ void LogicTestBlock::LoadState(Node& node, const crude_json::value& nodeData, Co
continue;
if (flowOutCounter < 2 && m_FlowOutputIds[flowOutCounter] < 0)
{
m_FlowOutputIds[flowOutCounter] = pin.ID.Get();
m_FlowOutputIds[flowOutCounter] = ToRuntimeId(pin.ID);
}
++flowOutCounter;
}

View File

@ -24,7 +24,7 @@ public:
void Build(Node& node, App* app) override;
int Run(Node& node, App* app) override;
const char* GetBlockType() const override { return "Logic.Test"; }
NH_CSTRING GetBlockType() const override { return "Logic.Test"; }
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;
void OnMenu(Node& node, App* app) override;

View File

@ -9,14 +9,14 @@ class AddBlock : public ParameterizedBlock
public:
AddBlock(int id) : ParameterizedBlock(id, "Add")
{
m_TypeName = "Math.Add";
SetTypeName("Math.Add");
m_Type = NodeType::Blueprint;
m_Color = ImColor(128, 195, 248);
}
void Build(Node& node, App* app) override;
int Run(Node& node, App* app) override;
const char* GetBlockType() const override { return "Math.Add"; }
NH_CSTRING GetBlockType() const override { return "Math.Add"; }
};
class MultiplyBlock : public ParameterizedBlock
@ -24,14 +24,14 @@ class MultiplyBlock : public ParameterizedBlock
public:
MultiplyBlock(int id) : ParameterizedBlock(id, "Multiply")
{
m_TypeName = "Math.Multiply";
SetTypeName("Math.Multiply");
m_Type = NodeType::Blueprint;
m_Color = ImColor(128, 195, 248);
}
void Build(Node& node, App* app) override;
int Run(Node& node, App* app) override;
const char* GetBlockType() const override { return "Math.Multiply"; }
NH_CSTRING GetBlockType() const override { return "Math.Multiply"; }
};
class CompareBlock : public ParameterizedBlock
@ -39,13 +39,13 @@ class CompareBlock : public ParameterizedBlock
public:
CompareBlock(int id) : ParameterizedBlock(id, "Compare")
{
m_TypeName = "Math.Compare";
SetTypeName("Math.Compare");
m_Type = NodeType::Blueprint;
m_Color = ImColor(128, 195, 248);
}
void Build(Node& node, App* app) override;
int Run(Node& node, App* app) override;
const char* GetBlockType() const override { return "Math.Compare"; }
NH_CSTRING GetBlockType() const override { return "Math.Compare"; }
};

View File

@ -1,10 +1,13 @@
#define IMGUI_DEFINE_MATH_OPERATORS
#include <crude_json.h>
#include "../all.h"
#include "parameter_node.h"
#include "../app.h"
#include "block.h" // For BlockStyle constants (legacy)
#include "block.h"
#include "../utilities/node_renderer_base.h"
#include "../containers/container.h"
#include "../../crude_json.h"
#include "NodeEx.h"
#include "constants.h"
#include <imgui_internal.h>
@ -251,7 +254,7 @@ int ParameterNode::RunInternal(Node& node, App* app, int depth)
{
// Source doesn't exist - orphaned shortcut, clear reference
printf("[RUN] Parameter node %d: Source node %d not found, clearing shortcut reference\n",
node.ID.Get(), m_SourceID);
ToRuntimeId(node.ID), m_SourceID);
m_SourceID = 0;
m_IsSource = false;
}
@ -333,7 +336,7 @@ int ParameterNode::RunInternal(Node& node, App* app, int depth)
{
// Source is a block output - read value from block's output parameter
// Block outputs store their values in UnconnectedParamValues
int sourcePinId = sourcePin->ID.Get();
const int sourcePinId = ToRuntimeId(sourcePin->ID);
auto& paramValues = sourceNode->UnconnectedParamValues;
if (paramValues.find(sourcePinId) != paramValues.end())
@ -998,10 +1001,6 @@ void ParameterNode::OnMenu(Node& node, App* app)
if (ImGui::MenuItem("Run (R)"))
{
int result = Run(node, app);
printf("Parameter '%s' (ID: %d) Run() returned: %d\n",
node.Name.c_str(), node.ID.Get(), result);
ax::NodeEditor::AddInAppLog("Parameter '%s' (ID: %d) Run() returned: %d\n",
node.Name.c_str(), node.ID.Get(), result);
}
// Source/Shortcut management
@ -1125,8 +1124,6 @@ void ParameterNode::LoadState(Node& node, const crude_json::value& nodeData, Con
else
{
// Source doesn't exist - orphaned shortcut, clear reference
printf("[LOAD] Parameter node %d: Source node %d not found, clearing shortcut reference\n",
node.ID.Get(), sourceId);
m_SourceID = 0;
m_IsSource = false;
}
@ -1198,14 +1195,14 @@ Node* ParameterNode::CreateShortcut(Node& sourceNode, App* app)
ed::SetNodePosition(shortcutNode->ID, shortcutPos);
printf("[SHORTCUT] Created shortcut node %d for source %d at (%.1f, %.1f)\n",
shortcutNode->ID.Get(), m_ID, shortcutPos.x, shortcutPos.y);
ToRuntimeId(shortcutNode->ID), m_ID, shortcutPos.x, shortcutPos.y);
return shortcutNode;
}
ParameterNode* ParameterRegistry::CreateParameter(PinType type, int id, const char* name)
ParameterNode* ParameterRegistry::CreateParameter(PinType type, int id, NH_CSTRING name)
{
const char* defaultName = nullptr;
NH_CSTRING defaultName = nullptr;
switch (type)
{
case PinType::Bool: defaultName = "Bool"; break;

View File

@ -1,6 +1,8 @@
#pragma once
#include "../commons.h"
#include "../types.h"
#include "../utilities/node_renderer_base.h"
#include "../core/Object.h"
#include <string>
#include <vector>
@ -20,12 +22,11 @@ enum class ParameterDisplayMode
};
// Base parameter node class
class ParameterNode : public ax::NodeRendering::NodeRendererBase
class ParameterNode : public NH_Object, public ax::NodeRendering::NodeRendererBase
{
public:
ParameterNode(int id, const char* name, PinType type)
: m_ID(id)
, m_Name(name)
ParameterNode(int id, NH_CSTRING name, PinType type)
: NH_Object(id, name)
, m_Type(type)
, m_DisplayMode(ParameterDisplayMode::NameAndValue)
, m_IsSource(false)
@ -37,9 +38,9 @@ public:
virtual ~ParameterNode() = default;
// Core properties
int GetID() const { return m_ID; }
const char* GetName() const { return m_Name.c_str(); }
void SetName(const char* name) { m_Name = name; }
int GetID() const { return NH_Object::GetID(); }
NH_CSTRING GetName() const { return NH_Object::GetName(); }
void SetName(NH_CSTRING name) { NH_Object::SetName(name); }
PinType GetType() const { return m_Type; }
void SetType(PinType type) { m_Type = type; InitializeDefaultValue(); }
@ -113,8 +114,6 @@ protected:
void RenderMinimal(Node& node, App* app, Pin* newLinkPin);
void RenderMinimalLinks(Node& node, App* app, Pin* newLinkPin);
int m_ID;
std::string m_Name;
PinType m_Type;
ParameterDisplayMode m_DisplayMode;
@ -141,7 +140,7 @@ public:
return instance;
}
ParameterNode* CreateParameter(PinType type, int id, const char* name = nullptr);
ParameterNode* CreateParameter(PinType type, int id, NH_CSTRING name = nullptr);
private:
ParameterRegistry() = default;

View File

@ -3,7 +3,7 @@
#include "../app.h"
#include "../utilities/node_renderer_base.h"
#include "NodeEx.h"
#include "../../crude_json.h"
#include <crude_json.h>
#include <imgui.h>
#include <imgui_node_editor.h>
@ -227,7 +227,7 @@ int ParameterOperationBlock::Run(Node& node, App* app)
void ParameterOperationBlock::Render(Node& node, App* app, Pin* newLinkPin)
{
// Check if node is currently running (for red border visualization)
float currentTime = ImGui::GetTime();
double currentTime = (double)ImGui::GetTime();
bool isRunning = false;
auto runningIt = app->m_RunningNodes.find(node.ID);
if (runningIt != app->m_RunningNodes.end())

View File

@ -47,10 +47,10 @@ class ParameterOperationBlock : public ParameterizedBlock
public:
ParameterOperationBlock(int id) : ParameterizedBlock(id, "ParamOp")
{
m_TypeName = "ParamOp";
SetTypeName("ParamOp");
m_Type = NodeType::Blueprint;
m_Color = ImColor(180, 200, 180); // Light green
m_bFlags = static_cast<NH_BEHAVIOR_FLAGS>(NHBEHAVIOR_SCRIPT);
SetFlags(static_cast<NH_BEHAVIOR_FLAGS>(NHBEHAVIOR_SCRIPT));
// Default types
m_InputAType = PinType::Int;
@ -62,7 +62,7 @@ public:
void Build(Node& node, App* app) override;
int Run(Node& node, App* app) override;
void Render(Node& node, App* app, Pin* newLinkPin) override;
const char* GetBlockType() const override { return "ParamOp"; }
NH_CSTRING GetBlockType() const override { return "ParamOp"; }
void OnMenu(Node& node, App* app) override;

View File

@ -9,13 +9,13 @@ class StartBlock : public ParameterizedBlock
public:
StartBlock(int id) : ParameterizedBlock(id, "Start")
{
m_TypeName = "Start";
SetTypeName("Start");
m_Type = NodeType::Blueprint;
m_Color = ImColor(100, 255, 100);
}
void Build(Node& node, App* app) override;
int Run(Node& node, App* app) override;
const char* GetBlockType() const override { return "Start"; }
NH_CSTRING GetBlockType() const override { return "Start"; }
};

View File

@ -0,0 +1,36 @@
#pragma once
#include <string>
#include <vector>
#include <map>
#include <set>
#include <functional>
#include "./enums.h"
#include "./utilities/uuid_generator.h"
#ifndef NH_CSTRING
#define NH_CSTRING const char*
#endif
typedef char* NH_STRING;
typedef char NH_CHAR;
typedef unsigned short* NH_USTRING;
typedef unsigned short NH_UCHAR;
typedef int NH_BOOL;
typedef unsigned char NH_BYTE;
typedef unsigned int NH_DWORD;
typedef unsigned short NH_WORD;
typedef int NH_ERROR;
typedef int NH_PARAMETER_TYPE;
typedef int NH_OPERATION_TYPE;
typedef int NH_MESSAGE_TYPE;
typedef int NH_ATTRIBUTE_TYPE;
typedef int NH_ATTRIBUTE_CATEGORY;
typedef Uuid64 NH_GUID;
typedef unsigned int NH_ID;
typedef unsigned int NH_CLASS_ID;

View File

@ -0,0 +1,8 @@
#ifndef CONFIG_H
#define CONFIG_H
#ifndef NH_GUI
#define NH_GUI
#endif
#endif

View File

@ -181,7 +181,7 @@ void Container::RemoveNode(Node* node)
int nodeId = -1;
try {
nodeId = node->ID.Get();
nodeId = ToRuntimeId(node->ID);
} catch (...) {
printf("[DELETE] Container::RemoveNode: Cannot access node ID (corrupted pointer %p)\n", (void*)node);
fflush(stdout);
@ -216,10 +216,12 @@ void Container::AddLink(Link* link)
return;
}
const int linkId = ToRuntimeId(link->ID);
if (ContainsLink(link->ID))
{
printf("[LINK_DRAG] Container::AddLink: Link ID %lld already exists in container, REJECTING!\n",
(long long)link->ID.Get());
static_cast<long long>(linkId));
printf("[LINK_DRAG] Container::AddLink: Current link IDs in container: ");
for (auto id : m_LinkIds)
printf("%lld ", (long long)id.Get());
@ -228,7 +230,7 @@ void Container::AddLink(Link* link)
return;
}
printf("[LINK_DRAG] Container::AddLink: Adding link ID=%lld to container\n", (long long)link->ID.Get());
printf("[LINK_DRAG] Container::AddLink: Adding link ID=%lld to container\n", static_cast<long long>(linkId));
fflush(stdout);
// Store ID - actual link is stored in RootContainer::m_Links

View File

@ -112,9 +112,6 @@ Pin* RootContainer::FindPin(ed::PinId id, App* app)
// Ensure pin's Node pointer is correct (should be set by BuildNode after AddNode)
if (pin.Node != &node)
{
printf("[FindPin] FIXING pin %d - Node pointer incorrect (was %p, setting to %p)\n",
id.Get(), (void*)pin.Node, (void*)&node);
fflush(stdout);
pin.Node = &node; // Fix to point to actual node in container
}
return &pin;

View File

@ -7,7 +7,7 @@
namespace ed = ax::NodeEditor;
class App;
class Pin;
struct Pin;
/**
* RootContainer - Owns actual Node and Link objects for its graph

View File

@ -0,0 +1 @@
#include "BaseManager.h"

View File

@ -0,0 +1,33 @@
#ifndef NH_BASE_MANAGER_H
#define NH_BASE_MANAGER_H
#include "../commons.h"
#include "../types.h"
class NH_Context;
class NH_BaseManager {
public:
NH_BaseManager() {}
virtual ~NH_BaseManager() = default;
virtual NH_ERROR OnInit() { return E_OK; }
NH_Context* GetContext() { return m_Context; }
void SetContext(NH_Context* context) { m_Context = context; }
Uuid64 GetGuid() { return m_Guid; }
std::string GetName() { return m_Name; }
void SetName(std::string name) { m_Name = name; }
void SetGuid(Uuid64 guid) { m_Guid = guid; }
protected:
NH_Context* m_Context;
Uuid64 m_Guid;
std::string m_Name;
};
#endif

View File

@ -0,0 +1,38 @@
#include "Context.h"
#include "../logging.h"
#include "ParameterManager.h"
#include "ParameterIn.h"
#include "ParameterOut.h"
#include "../utilities/uuid_generator.h"
NH_Context::NH_Context() : m_ParameterManager(nullptr), m_App(nullptr) {}
NH_Context::~NH_Context()
{
delete m_ParameterManager;
}
NH_ERROR NH_Context::init(App *app)
{
m_App = app;
m_ParameterManager = new NH_ParameterManager(this);
m_ParameterManager->OnInit();
LOG_INFO("Context initialized");
return E_OK;
}
NH_ParameterIn* NH_Context::CreateParameterIn(NH_CSTRING name, const Uuid64& guid)
{
// A proper implementation would use an object manager to handle IDs and memory.
auto* param = new NH_ParameterIn(0, name);
// TODO: Set the parameter type based on the GUID by looking it up in the ParameterManager.
return param;
}
NH_ParameterOut* NH_Context::CreateParameterOut(NH_CSTRING name, const Uuid64& guid)
{
// A proper implementation would use an object manager.
auto* param = new NH_ParameterOut(0, name);
// TODO: Set the parameter type based on the GUID.
return param;
}

View File

@ -0,0 +1,41 @@
#ifndef NH_CONTEXT_H
#define NH_CONTEXT_H
#include "../commons.h"
#include "../types.h"
class App;
class NH_ParameterManager;
class NH_ParameterIn;
class NH_ParameterOut;
struct Uuid64;
class NH_Context {
public:
NH_Context();
virtual ~NH_Context();
NH_ParameterManager* GetParameterManager() { return m_ParameterManager; }
void SetParameterManager(NH_ParameterManager* parameterManager) { m_ParameterManager = parameterManager; }
App* GetApp() { return m_App; }
void SetApp(App* app) { m_App = app; }
//-----------------------------------------
// Lifecycle
//-----------------------------------------
NH_ERROR init(App *app);
// Object Management
NH_ParameterIn* CreateParameterIn(NH_CSTRING name, const Uuid64& guid);
NH_ParameterOut* CreateParameterOut(NH_CSTRING name, const Uuid64& guid);
protected:
NH_ParameterManager* m_ParameterManager;
// legacy support
App* m_App;
};
#endif

View File

@ -0,0 +1 @@
#include "Object.h"

View File

@ -0,0 +1,111 @@
#pragma once
#include "../commons.h"
#include "../utilities/uuid_generator.h"
#include <string>
class App;
class Container;
namespace crude_json { struct value; }
class NH_Object
{
public:
NH_Object()
: m_ID(0)
, m_Name("")
, m_TypeName("")
, m_Parent(nullptr)
, m_BehaviorFlags(NHBEHAVIOR_NONE)
, m_ObjectFlags(NH_OBJECT_DYNAMIC)
{}
NH_Object(int id, NH_CSTRING name, NH_CSTRING typeName = nullptr)
: NH_Object()
{
m_ID = id;
if (name)
m_Name = name;
if (typeName)
m_TypeName = typeName;
}
virtual ~NH_Object() = default;
// Core identification
int GetID() const { return m_ID; }
void SetID(int id) { m_ID = id; }
NH_CSTRING GetName() const { return m_Name.c_str(); }
const std::string& GetNameString() const { return m_Name; }
void SetName(NH_CSTRING name)
{
m_Name = name ? name : "";
}
NH_CSTRING GetTypeName() const { return m_TypeName.c_str(); }
void SetTypeName(NH_CSTRING typeName)
{
m_TypeName = typeName ? typeName : "";
}
NH_Object* GetParent() const { return m_Parent; }
void SetParent(NH_Object* parent) { m_Parent = parent; }
// Behavior flags (Virtools-style)
NH_BEHAVIOR_FLAGS GetBehaviorFlags() const { return m_BehaviorFlags; }
void SetBehaviorFlags(NH_BEHAVIOR_FLAGS flags) { m_BehaviorFlags = flags; }
void AddBehaviorFlags(NH_BEHAVIOR_FLAGS flags)
{
m_BehaviorFlags = static_cast<NH_BEHAVIOR_FLAGS>(
static_cast<int>(m_BehaviorFlags) | static_cast<int>(flags));
}
void RemoveBehaviorFlags(NH_BEHAVIOR_FLAGS flags)
{
m_BehaviorFlags = static_cast<NH_BEHAVIOR_FLAGS>(
static_cast<int>(m_BehaviorFlags) & ~static_cast<int>(flags));
}
// Object flags (base Virtools object flags)
NH_OBJECT_FLAGS GetObjectFlags() const
{
return static_cast<NH_OBJECT_FLAGS>(m_ObjectFlags);
}
void SetObjectFlags(NH_OBJECT_FLAGS flags)
{
m_ObjectFlags = static_cast<NH_DWORD>(flags);
}
void AddObjectFlags(NH_OBJECT_FLAGS flags)
{
m_ObjectFlags |= static_cast<NH_DWORD>(flags);
}
void ClearObjectFlags(NH_OBJECT_FLAGS flags)
{
m_ObjectFlags &= ~static_cast<NH_DWORD>(flags);
}
// Serialization hooks (mirror block/parameter APIs)
virtual void SaveState(crude_json::value& data, const Container* container, App* app) {}
virtual void LoadState(const crude_json::value& data, Container* container, App* app) {}
Uuid64 m_UUID;
void SetUUID(Uuid64 uuid) { m_UUID = uuid; }
Uuid64 GetUUID() const { return m_UUID; }
NH_STRING GetClassName();
// Class Registering
static NH_STRING m_ClassName;
virtual NH_CLASS_ID GetClassID() { return NHCID_PARAMETER; }
protected:
int m_ID;
std::string m_Name;
std::string m_TypeName;
NH_Object* m_Parent;
NH_BEHAVIOR_FLAGS m_BehaviorFlags;
NH_DWORD m_ObjectFlags;
NH_CLASS_ID m_ClassID;
};

View File

@ -0,0 +1,68 @@
#include "Parameter.h"
#include "Context.h"
#include "ParameterManager.h"
#include <cstring>
NH_Parameter::NH_Parameter(int id, NH_CSTRING name) : NH_Object(id, name) {
m_Owner = nullptr;
m_AllocatedSize = 0;
m_Buffer = nullptr;
m_ParamType = nullptr;
}
NH_Parameter::~NH_Parameter() {
if (m_Buffer) {
delete[] m_Buffer;
m_Buffer = nullptr;
}
}
NH_ERROR NH_Parameter::GetValue(void *buf, NH_BOOL update) {
if (!buf || !m_Buffer) return E_FAIL;
memcpy(buf, m_Buffer, m_DataSize);
return E_OK;
}
NH_ERROR NH_Parameter::SetValue(const void *buf, int size) {
if (!buf) return E_FAIL;
int dataSize = size;
if (dataSize == 0 && m_ParamType) {
dataSize = m_ParamType->DefaultSize;
}
if (dataSize == 0) return E_FAIL;
if (m_AllocatedSize < dataSize) {
if (m_Buffer) {
delete[] m_Buffer;
}
m_Buffer = new NH_BYTE[dataSize];
m_AllocatedSize = dataSize;
}
memcpy(m_Buffer, buf, dataSize);
m_DataSize = dataSize;
return E_OK;
}
NH_ERROR NH_Parameter::CopyValue(NH_Parameter *param, NH_BOOL UpdateParam) {
return E_NOTIMPL;
}
void *NH_Parameter::GetReadDataPtr(NH_BOOL update) {
return m_Buffer;
}
void *NH_Parameter::GetWriteDataPtr() {
return nullptr;
}
NH_ERROR NH_Parameter::SetStringValue(NH_STRING Value) {
return E_NOTIMPL;
}
int NH_Parameter::GetStringValue(NH_STRING Value, NH_BOOL update) {
return E_NOTIMPL;
}

View File

@ -0,0 +1,59 @@
#ifndef NH_PARAMETER_H
#define NH_PARAMETER_H
#include "../commons.h"
#include "../types.h"
#include "./Object.h"
class NH_Parameter : public NH_Object {
public:
NH_Parameter(int id, NH_CSTRING name);
virtual ~NH_Parameter();
NH_PARAMETER_TYPE GetType();
void SetType(NH_PARAMETER_TYPE type);
NH_CLASS_ID GetParameterClassID();
virtual NH_CLASS_ID GetClassID() { return NHCID_PARAMETER; }
void SetOwner(NH_Object *owner) { m_Owner = owner; }
NH_Object *GetOwner() { return m_Owner; }
NH_ParameterTypeDesc *GetParameterType() { return m_ParamType; }
// Convertion from / to string
virtual NH_ERROR SetStringValue(NH_STRING Value);
virtual int GetStringValue(NH_STRING Value, NH_BOOL update = true);
//--------------------------------------------
// Value
NH_Object *GetValueObject(NH_BOOL update = true);
virtual NH_ERROR GetValue(void *buf, NH_BOOL update = true);
virtual NH_ERROR SetValue(const void *buf, int size = 0);
virtual NH_ERROR CopyValue(NH_Parameter *param, NH_BOOL UpdateParam = true);
NH_BOOL IsCompatibleWith(NH_Parameter *param);
//--------------------------------------------
// Data pointer
int GetDataSize();
virtual void *GetReadDataPtr(NH_BOOL update = true);
virtual void *GetWriteDataPtr();
protected:
NH_Object *m_Owner;
union {
int m_DataSize;
int m_AllocatedSize;
};
union {
NH_BYTE *m_Buffer;
NH_DWORD m_Value;
};
NH_ParameterTypeDesc *m_ParamType;
};
#endif

View File

@ -0,0 +1,81 @@
#include "./ParameterIn.h"
#include "./Context.h"
#include "ParameterManager.h"
NH_ParameterIn::NH_ParameterIn(int id, NH_CSTRING name) : NH_Parameter(id, name) {
m_ObjectFlags &= ~NH_PARAMETERIN_SHARED;
m_DirectSource = nullptr;
}
NH_Parameter* NH_ParameterIn::GetRealSource() {
if (m_ObjectFlags & NH_PARAMETERIN_SHARED) {
if (m_SharedSource) return m_SharedSource->GetRealSource();
} else {
return m_DirectSource;
}
return nullptr;
}
NH_Parameter* NH_ParameterIn::GetDirectSource() {
if (m_ObjectFlags & NH_PARAMETERIN_SHARED) return nullptr;
return m_DirectSource;
}
NH_ERROR NH_ParameterIn::SetDirectSource(NH_Parameter* param) {
m_ObjectFlags &= ~NH_PARAMETERIN_SHARED;
m_DirectSource = param;
return E_OK;
}
NH_ParameterIn* NH_ParameterIn::GetSharedSource() {
if (!(m_ObjectFlags & NH_PARAMETERIN_SHARED)) return nullptr;
return m_SharedSource;
}
NH_ERROR NH_ParameterIn::ShareSourceWith(NH_ParameterIn* param) {
m_ObjectFlags |= NH_PARAMETERIN_SHARED;
m_SharedSource = param;
return E_OK;
}
NH_ERROR NH_ParameterIn::GetValue(void* buf, NH_BOOL update) {
// Stub implementation
NH_Parameter* src = GetRealSource();
if (!src) return E_FAIL;
return src->GetValue(buf, update);
}
void* NH_ParameterIn::GetReadDataPtr(NH_BOOL update) {
// Stub implementation
NH_Parameter* src = GetRealSource();
if (!src) return nullptr;
return src->GetReadDataPtr(update);
}
NH_ERROR NH_ParameterIn::SetValue(const void* buf, int size) {
// Input parameters are read-only
return E_ACCESSDENIED;
}
void* NH_ParameterIn::GetWriteDataPtr() {
// Input parameters are read-only
return nullptr;
}
NH_ERROR NH_ParameterIn::CopyValue(NH_Parameter* param, NH_BOOL UpdateParam) {
NH_Parameter* src = GetRealSource();
if (!src || !param) return E_FAIL;
return src->CopyValue(param, UpdateParam);
}
NH_ERROR NH_ParameterIn::SetStringValue(NH_STRING Value) {
NH_Parameter* src = GetRealSource();
if (!src) return E_FAIL;
return src->SetStringValue(Value);
}
int NH_ParameterIn::GetStringValue(NH_STRING Value, NH_BOOL update) {
NH_Parameter* src = GetRealSource();
if (!src) return E_FAIL;
return src->GetStringValue(Value, update);
}

View File

@ -0,0 +1,45 @@
#ifndef NH_PARAMETER_IN_H
#define NH_PARAMETER_IN_H
#include "./Parameter.h"
// Forward declaration
class NH_ParameterIn;
class NH_ParameterIn : public NH_Parameter {
public:
NH_ParameterIn(int id, NH_CSTRING name);
virtual ~NH_ParameterIn() = default;
// Source management
NH_Parameter *GetRealSource();
NH_Parameter *GetDirectSource();
NH_ERROR SetDirectSource(NH_Parameter *param);
NH_ParameterIn *GetSharedSource();
NH_ERROR ShareSourceWith(NH_ParameterIn *param);
// Overridden value accessors
virtual NH_ERROR GetValue(void *buf, NH_BOOL update = true) override;
virtual void *GetReadDataPtr(NH_BOOL update = true) override;
// Disable writing
virtual NH_ERROR SetValue(const void *buf, int size = 0) override;
virtual NH_ERROR CopyValue(NH_Parameter *param, NH_BOOL UpdateParam = true) override;
virtual void *GetWriteDataPtr() override;
// String conversion
virtual NH_ERROR SetStringValue(NH_STRING Value) override;
virtual int GetStringValue(NH_STRING Value, NH_BOOL update = true) override;
virtual NH_CLASS_ID GetClassID() override { return NHCID_PARAMETERIN; }
protected:
union {
NH_Parameter *m_DirectSource;
NH_ParameterIn *m_SharedSource;
};
};
#endif // NH_PARAMETER_IN_H

View File

@ -0,0 +1,64 @@
#include "ParameterManager.h"
#include <string>
NH_ParameterManager::NH_ParameterManager(NH_Context *context) : NH_BaseManager() {
SetContext(context);
}
NH_ERROR NH_ParameterManager::OnInit() {
NH_ParameterTypeDesc pdesc;
// Float
pdesc.Guid = NHP_GUID_FLOAT;
pdesc.TypeName = "Float";
pdesc.DefaultSize = sizeof(float);
RegisterParameterType(&pdesc);
// Int
pdesc.Guid = NHP_GUID_INT;
pdesc.TypeName = "Int";
pdesc.DefaultSize = sizeof(int);
RegisterParameterType(&pdesc);
// Bool
pdesc.Guid = NHP_GUID_BOOL;
pdesc.TypeName = "Bool";
pdesc.DefaultSize = sizeof(bool);
RegisterParameterType(&pdesc);
// String
pdesc.Guid = NHP_GUID_STRING;
pdesc.TypeName = "String";
pdesc.DefaultSize = sizeof(char*);
RegisterParameterType(&pdesc);
// Vector
pdesc.Guid = NHP_GUID_VECTOR;
pdesc.TypeName = "Vector";
pdesc.DefaultSize = sizeof(float) * 3;
RegisterParameterType(&pdesc);
return E_OK;
}
NH_ERROR
NH_ParameterManager::RegisterParameterType(NH_ParameterTypeDesc *parameterType) {
if (!parameterType)
return E_FAIL;
// Check if GUID is valid
if (!parameterType->Guid.IsValid())
return E_FAIL;
// Check if GUID already exists
if (m_ParameterGuids.find(parameterType->Guid) != m_ParameterGuids.end()) {
return E_OK; // Or an error for duplicate
}
m_ParameterTypes.push_back(*parameterType);
int newIndex = m_ParameterTypes.size() - 1;
m_ParameterTypes.back().Index = newIndex;
m_ParameterGuids[parameterType->Guid] = newIndex;
return E_OK;
}

View File

@ -0,0 +1,26 @@
#ifndef NH_PARAMETER_MANAGER_H
#define NH_PARAMETER_MANAGER_H
#include "../commons.h"
#include "../enums.h"
#include "../types.h"
#include "./BaseManager.h"
#include "./Parameter.h"
#include <map>
#include <vector>
class NH_ParameterManager : public NH_BaseManager {
public:
NH_ParameterManager(NH_Context *context);
virtual ~NH_ParameterManager() = default;
virtual NH_ERROR OnInit() override;
NH_ERROR RegisterParameterType(NH_ParameterTypeDesc *parameterType);
protected:
std::vector<NH_ParameterTypeDesc> m_ParameterTypes;
std::map<Uuid64, int> m_ParameterGuids;
};
#endif

View File

@ -0,0 +1,39 @@
#include "ParameterOut.h"
NH_ERROR NH_ParameterOut::GetValue(void* buf, NH_BOOL update) {
return NH_Parameter::GetValue(buf, update);
}
NH_ERROR NH_ParameterOut::SetValue(const void* buf, int size) {
return NH_Parameter::SetValue(buf, size);
}
NH_ERROR NH_ParameterOut::CopyValue(NH_Parameter* param, NH_BOOL UpdateParam) {
return NH_Parameter::CopyValue(param, UpdateParam);
}
void* NH_ParameterOut::GetReadDataPtr(NH_BOOL update) {
return NH_Parameter::GetReadDataPtr(update);
}
int NH_ParameterOut::GetStringValue(NH_STRING Value, NH_BOOL update) {
return NH_Parameter::GetStringValue(Value, update);
}
void NH_ParameterOut::DataChanged() {}
NH_ERROR NH_ParameterOut::AddDestination(NH_Parameter* param, NH_BOOL CheckType) {
return E_NOTIMPL;
}
void NH_ParameterOut::RemoveDestination(NH_Parameter* param) {}
int NH_ParameterOut::GetDestinationCount() {
return 0;
}
NH_Parameter* NH_ParameterOut::GetDestination(int pos) {
return nullptr;
}
void NH_ParameterOut::RemoveAllDestinations() {}

View File

@ -0,0 +1,79 @@
#ifndef NH_PARAMETER_OUT_H
#define NH_PARAMETER_OUT_H
#include "../commons.h"
#include "./Parameter.h"
/**************************************************************************
Name: CKParameterOut
Summary: Output parameter providing a value
Remarks:
{Image:ParameterOut}
+ The type of the parameter defines the type of the data provided. These
types are maintained by the parameter manager. It defines the size of the buffer
to use, and also decides what can be plugged onto the output parameter. To have
the list and definition of predefined parameter types see CKParameterManager.
+ An output parameter may have destinations to which it pushes the data
each time it is changed. These destinations are other output parameters, which
for example provide their value out of the enclosing behavior, or local
parameters which provide values to other parts of the graph of sub-behaviors.
These destinations are managed using the AddDestination and related methods.
When the data of the output parameter changes, it pushes the new value down to
its destinations.
+ An output parameter will probably also be plugged into input
parameters. These input parameters will pull the value from the output parameter
when needed.
+ An output parameter usually knows how to write its data from and to a
string. This is useful for display and debugging purposes. When you define a new
type of parameter, you can specify the function that converts to and from
strings.
+ An output parameter can also have an edition window. When you define a
new type of parameter, you can specify the function that will create the edition
window when needed by the interface.
+ A NH_ParameterOut is created with CKBehavior::CreateOutputParameter or
CKContext::CreateCKParameterOut.
+ The class id of NH_ParameterOut is NHCID_PARAMETEROUT.
See also: NH_ParameterIn, NH_ParameterOperation
**********************************************************************************/
class NH_ParameterOut : public NH_Parameter {
public:
NH_ParameterOut(int id, NH_CSTRING name) : NH_Parameter(id, name) {}
virtual ~NH_ParameterOut() = default;
virtual NH_CLASS_ID GetClassID() override { return NHCID_PARAMETEROUT; }
//--------------------------------------------
// Value
virtual NH_ERROR GetValue(void *buf, NH_BOOL update = true);
virtual NH_ERROR SetValue(const void *buf, int size = 0);
virtual NH_ERROR CopyValue(NH_Parameter *param, NH_BOOL UpdateParam = true);
virtual void *GetReadDataPtr(NH_BOOL update = true);
virtual int GetStringValue(NH_STRING Value, NH_BOOL update = true);
// void CheckClass(CKParameterTypeDesc* iType);
//--------------------------------------------
// Destinations
void DataChanged();
NH_ERROR AddDestination(NH_Parameter *param, NH_BOOL CheckType = true);
void RemoveDestination(NH_Parameter *param);
int GetDestinationCount();
NH_Parameter *GetDestination(int pos);
void RemoveAllDestinations();
};
#endif

View File

@ -0,0 +1,574 @@
/*************************************************************************/
/* File : XClassArray.h */
/* Author : Aymeric Bard */
/* */
/* Virtools SDK */
/* Copyright (c) Virtools 2000, All Rights Reserved. */
/*************************************************************************/
#ifndef _XCLASSARRAY_H_
#define _XCLASSARRAY_H_ "$Id:$"
#include "XUtil.h"
#ifdef _WIN32
#pragma warning(disable : 4786)
#endif
/************************************************
{filename:XClassArray}
Name: XClassArray
Summary: Class representation of an array.
Remarks:
This array is designed to hold structure or class
which have something specific to do on the construction,
deletion or recopy, like allocating/destroying pointers.
See Also : XArray, XSArray
************************************************/
template <class T>
class XClassArray
{
public:
typedef T* Iterator;
/************************************************
Summary: Constructors.
Input Arguments:
ss: Default number of reserved elements.
a: An array to copy from.
************************************************/
XClassArray(int ss=0)
{
// Allocated
if(ss>0) {
m_Begin = Allocate(ss);
m_End = m_Begin;
m_AllocatedEnd = m_Begin+ss;
} else {
m_AllocatedEnd = 0;
m_Begin = m_End = 0;
}
}
XClassArray(const XClassArray<T>& a)
{
// the resize
int size = a.Size();
m_Begin = Allocate(size);
m_End = m_Begin+size;
m_AllocatedEnd = m_End;
// The copy
XCopy(m_Begin,a.m_Begin,a.m_End);
}
/************************************************
Summary: Destructor.
Remarks:
Release the elements contained in the array. If
you were storing pointers, you need first to iterate
on the array and call delete on each pointer.
************************************************/
~XClassArray()
{
Clear();
}
/************************************************
Summary: Affectation operator.
Remarks:
The content of the array is enterely overwritten
by the given array.
************************************************/
XClassArray<T>& operator = (const XClassArray<T>& a)
{
if(this != &a) {
if (Allocated() >= a.Size()) { // No need to allocate
// The copy
XCopy(m_Begin,a.m_Begin,a.m_End);
m_End = m_Begin + a.Size();
} else {
Free();
// the resize
int size = a.Size();
m_Begin = Allocate(size);
m_End = m_Begin+size;
m_AllocatedEnd = m_End;
// The copy
XCopy(m_Begin,a.m_Begin,a.m_End);
}
}
return *this;
}
/************************************************
Summary: Removes all the elements from an array.
Remarks:
There is no more space reserved after this call.
************************************************/
void Clear()
{
Free();
m_Begin = 0;
m_End = 0;
m_AllocatedEnd = 0;
}
/************************************************
Summary: Reserves n elements for an array.
Remarks:
The elements beyond the reserved limit are
discarded.
************************************************/
void Reserve(int size)
{
// allocation of new size
T* newdata = Allocate(size);
// Recopy of old elements
T* last = XMin(m_Begin+size,m_End);
XCopy(newdata,m_Begin,last);
// new Pointers
Free();
m_End = newdata+(last-m_Begin);
m_Begin = newdata;
m_AllocatedEnd = newdata+size;
}
/************************************************
Summary: Resizes th elements numbers of an array.
Remarks:
If the size is greater than the reserved size,
the array is reallocated at the exact needed size.
If not, there is no reallocation at all. Resize(0)
is faster than Clear() if you know you will probably
push some more elements after.
************************************************/
void Resize(int size)
{
// we check if the array has enough capacity
int oldsize = (m_AllocatedEnd-m_Begin);
// If not, we allocate extra data
if(size > oldsize) Reserve(size);
// We set the end cursor
m_End = m_Begin+size;
}
/************************************************
Summary: Inserts an element at the end of an array.
Input Arguments:
o: object to insert.
************************************************/
void PushBack(const T& o)
{
XInsert(m_End,o);
}
/************************************************
Summary: Expands an array of e elements.
Input Arguments:
e: size to expand.
************************************************/
void Expand(int e = 1)
{
// we check if the array has enough capacity
// If not, we allocate extra data
while (Size()+e > Allocated()) {
Reserve(Allocated()?Allocated()*2:2);
}
// We set the end cursor
m_End += e;
}
/************************************************
Summary: Inserts an element at the start of an array.
Input Arguments:
o: object to insert.
************************************************/
void PushFront(const T& o)
{
XInsert(m_Begin,o);
}
/************************************************
Summary: Inserts an element before another one.
Input Arguments:
i: iterator on the element to insert before.
pos: position to insert the object
o: object to insert.
Remarks:
The element to insert before is given as
an iterator on it, i.e. a pointer on it in
this case.
************************************************/
void Insert(T* i, const T& o)
{
// TODO : s'assurer que i est dans les limites...
if(i<m_Begin || i>m_End) return;
// The Call
XInsert(i,o);
}
void Insert(int pos, const T& o)
{
Insert(m_Begin+pos,o);
}
/************************************************
Summary: Removes the last element of an array.
************************************************/
void PopBack()
{
// we remove the last element only if it exists
if(m_End > m_Begin) XRemove(m_End-1);
}
/************************************************
Summary: Removes the first element of an array.
************************************************/
void PopFront()
{
// we remove the first element only if it exists
if(m_Begin != m_End) XRemove(m_Begin);
}
/************************************************
Summary: Removes an element.
Input Arguments:
i: iterator on the element to remove.
pos: position of the object to remove.
Return Value: an iterator on the next
element after the element removed (to go on with
an iteration).
Remarks:
The elements are given by iterators on them,
i.e. pointer on them in this case.
************************************************/
T* Remove(T* i)
{
// we ensure i is in boundary...
if(i<m_Begin || i>=m_End) return 0;
// the Call
return XRemove(i);
}
T* RemoveAt(int pos)
{
// we ensure i is in boundary...
if (pos >= Size()) return NULL;
// the Call
return XRemove(m_Begin+pos);
}
void FastRemove(const T& o)
{
FastRemove(Find(o));
}
void FastRemove(const Iterator& iT)
{
// we ensure i is in boundary...
if(iT<m_Begin || iT>=m_End)
return;
m_End--;
if (iT < m_End)
*iT = *m_End;
}
/************************************************
Summary: Access to an array element.
Input Arguments:
i: index of the element to access.
Return Value: a reference on the object accessed.
Remarks:
No test are provided on i.
************************************************/
T& operator [](int i) const
{
XASSERT(i>=0 && i<Size());
return *(m_Begin+i);
}
/************************************************
Summary: Access to an array element.
Input Arguments:
i: index of the element to access.
Return Value: a pointer on the object accessed.
Remarks:
End() is returned if i is outside the array
limits.
************************************************/
T* At(unsigned int i) const
{
if (i >= (unsigned int)Size()) return m_End;
return m_Begin+i;
}
/************************************************
Summary: Swaps two items in array.
Input Arguments:
pos1: position of first item to swap
pos2: position of second item to swap.
************************************************/
void Swap(int pos1,int pos2)
{
char buffer[sizeof(T)];
memcpy(buffer,m_Begin+pos1,sizeof(T));
memcpy(m_Begin+pos1,m_Begin+pos2,sizeof(T));
memcpy(m_Begin+pos2,buffer,sizeof(T));
}
/************************************************
Summary: Swaps two arrays.
Input Arguments:
o: second array to swap.
************************************************/
void Swap(XClassArray<T>& a)
{
XSwap(m_Begin,a.m_Begin);
XSwap(m_End,a.m_End);
XSwap(m_AllocatedEnd,a.m_AllocatedEnd);
}
/************************************************
Summary: Returns the last element of an array.
Remarks:
No test are provided to see if there is an
element.
************************************************/
T& Back() {return *(End()-1);}
const T& Back() const {return *(End()-1);}
/************************************************
Summary: Returns an iterator on the first element.
Example:
Typically, an algorithm iterating on an array
looks like:
for(T* t = a.Begin(); t != a.End(); ++t) {
// do something with *t
}
************************************************/
T* Begin() const {return m_Begin;}
/************************************************
Summary: Returns an iterator after the last element.
************************************************/
T* End() const {return m_End;}
/************************************************
Summary: Returns the elements number.
************************************************/
int Size() const {return m_End-m_Begin;}
/************************************************
Summary: Returns the elements allocated.
************************************************/
int Allocated() const {return m_AllocatedEnd-m_Begin;}
/************************************************
Summary: Returns the occupied size in memory in bytes
Parameters:
addstatic: TRUE if you want to add the size occupied
by the class itself.
************************************************/
int GetMemoryOccupation(XBOOL addstatic=FALSE) const {
return Allocated()*sizeof(T)+(addstatic?sizeof(*this):0);
}
/************************************************
Summary: Finds an element.
Input Arguments:
o: element to find.
Return Value: a pointer on the first object found
or End() if the object is not found.
************************************************/
T* Find(const T& o) const
{
// If the array is empty
if(!(m_End - m_Begin)) return m_End;
T* t = m_Begin;
while(t < m_End && *t != o)
++t;
return t;
}
/************************************************
Summary: Returns the position of an element.
Input Arguments:
o: element to find.
Return Value: position or -1 if not found.
************************************************/
int GetPosition(const T& o) const
{
T* t = Find(o);
// If the element is not found
if(t == m_End) return -1;
// else return the position
return t-m_Begin;
}
static
int XCompare(const void *elem1, const void *elem2 )
{
return *(T*)elem1 - *(T*)elem2;
}
/************************************************
Summary: Sorts an array with a quick sort.
Input Arguments:
compare: The function comparing two elements.
Remarks:
Two sorts algorithm are available : BubbleSort
and (quick)Sort.
************************************************/
void Sort( VxSortFunc Fct = XCompare)
{
qsort(m_Begin,Size(),sizeof(T),Fct);
}
protected:
///
// Methods
void XCopy(T* dest, T* start, T* end)
{
while(start != end) {
*dest = *start;
start++;
dest++;
}
}
void XMove(T* dest, T* start, T* end)
{
if (dest>start)
{
dest += end-start;
while(start != end) {
--dest;
--end;
*dest = *end;
}
} else XCopy(dest,start,end);
}
void XInsert(T* i, const T& o)
{
// Test For Reallocation
if(m_End+1 > m_AllocatedEnd) {
int newsize = (m_AllocatedEnd-m_Begin)*2;//+m_AllocationSize;
if(!newsize) newsize = 1;
T* newdata = Allocate(newsize);
// copy before insertion point
XCopy(newdata,m_Begin,i);
// copy the new element
T* insertionpoint = newdata+(i-m_Begin);
*(insertionpoint) = o;
// copy after insertion point
XCopy(insertionpoint+1,i,m_End);
// New Pointers
m_End = newdata+(m_End-m_Begin);
Free();
m_Begin = newdata;
m_AllocatedEnd = newdata+newsize;
} else {
// copy after insertion point
XMove(i+1,i,m_End);
// copy the new element
*i = o;
}
m_End++;
}
T* XRemove(T* i)
{
// copy after insertion point
XMove(i,i+1,m_End);
m_End--;
return i;
}
///
// Allocation and deallocation methods : to be override for alignement purposes
T* Allocate(int size)
{
if(size) return new T[size];
else return 0;
}
void Free()
{
delete [] m_Begin;
}
///
// Members
T* m_Begin;
T* m_End;
T* m_AllocatedEnd;
};
#endif

Some files were not shown because too many files have changed in this diff Show More