mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
more separation between node UI logic and editor, working Studio format support
This commit is contained in:
parent
6c4ffbbd62
commit
a6dbc90b78
19 changed files with 536 additions and 340 deletions
|
|
@ -90,6 +90,7 @@ set(BUILD_SHARED_LIBS TRUE)
|
||||||
set(SDL_STATIC TRUE)
|
set(SDL_STATIC TRUE)
|
||||||
FetchContent_MakeAvailable(sdl3)
|
FetchContent_MakeAvailable(sdl3)
|
||||||
include_directories(${sdl3_SOURCE_DIR}/include)
|
include_directories(${sdl3_SOURCE_DIR}/include)
|
||||||
|
# add_subdirectory(${sdl3_SOURCE_DIR})
|
||||||
|
|
||||||
# =========================================================================================================================
|
# =========================================================================================================================
|
||||||
# SDL3-Image
|
# SDL3-Image
|
||||||
|
|
@ -127,20 +128,25 @@ set(SRCS
|
||||||
src/main_window.cpp
|
src/main_window.cpp
|
||||||
src/main_window.h
|
src/main_window.h
|
||||||
|
|
||||||
src/node_editor_window.cpp
|
|
||||||
src/node_editor_window.h
|
|
||||||
|
|
||||||
src/library_window.cpp
|
src/library_window.cpp
|
||||||
src/library_window.h
|
src/library_window.h
|
||||||
|
|
||||||
src/media_node.h
|
|
||||||
src/media_node.cpp
|
|
||||||
|
|
||||||
src/platform_folders.cpp
|
src/platform_folders.cpp
|
||||||
src/platform_folders.h
|
src/platform_folders.h
|
||||||
|
|
||||||
src/base_node.h
|
src/node_engine/base_node.h
|
||||||
src/base_node.cpp
|
src/node_engine/base_node.cpp
|
||||||
|
src/node_engine/connection.cpp
|
||||||
|
src/node_engine/connection.h
|
||||||
|
|
||||||
|
|
||||||
|
src/node_editor/media_node.h
|
||||||
|
src/node_editor/media_node.cpp
|
||||||
|
src/node_editor/base_node_widget.h
|
||||||
|
src/node_editor/base_node_widget.cpp
|
||||||
|
src/node_editor/node_editor_window.h
|
||||||
|
src/node_editor/node_editor_window.cpp
|
||||||
|
|
||||||
src/resources_window.cpp
|
src/resources_window.cpp
|
||||||
src/resources_window.h
|
src/resources_window.h
|
||||||
|
|
@ -154,9 +160,6 @@ set(SRCS
|
||||||
src/code_editor.cpp
|
src/code_editor.cpp
|
||||||
src/code_editor.h
|
src/code_editor.h
|
||||||
|
|
||||||
src/connection.cpp
|
|
||||||
src/connection.h
|
|
||||||
|
|
||||||
src/media_converter.cpp
|
src/media_converter.cpp
|
||||||
src/media_converter.h
|
src/media_converter.h
|
||||||
|
|
||||||
|
|
@ -234,6 +237,8 @@ target_include_directories(${STORY_EDITOR_PROJECT} PUBLIC
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/src
|
${CMAKE_SOURCE_DIR}/src
|
||||||
${CMAKE_SOURCE_DIR}/src/importers
|
${CMAKE_SOURCE_DIR}/src/importers
|
||||||
|
${CMAKE_SOURCE_DIR}/src/node_editor
|
||||||
|
${CMAKE_SOURCE_DIR}/src/node_engine
|
||||||
|
|
||||||
../firmware/library
|
../firmware/library
|
||||||
../firmware/chip32
|
../firmware/chip32
|
||||||
|
|
@ -271,15 +276,16 @@ target_compile_definitions(${STORY_EDITOR_PROJECT} PUBLIC "$<$<CONFIG:DEBUG>:DEB
|
||||||
|
|
||||||
target_link_directories(${STORY_EDITOR_PROJECT} PUBLIC ${sdl3_BINARY_DIR} ${curl_BINARY_DIR} ${CMAKE_BINARY_DIR}/libs/SDL_image)
|
target_link_directories(${STORY_EDITOR_PROJECT} PUBLIC ${sdl3_BINARY_DIR} ${curl_BINARY_DIR} ${CMAKE_BINARY_DIR}/libs/SDL_image)
|
||||||
|
|
||||||
|
# On est obligé de passer par une variable pour injecter
|
||||||
set(SDL2_BIN_DIR ${sdl3_BINARY_DIR})
|
# certaines informations à CPACK
|
||||||
|
set(SDL_BIN_DIR ${sdl3_BINARY_DIR})
|
||||||
|
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
target_link_libraries(${STORY_EDITOR_PROJECT}
|
target_link_libraries(${STORY_EDITOR_PROJECT}
|
||||||
pthread
|
pthread
|
||||||
OpenGL::GL
|
OpenGL::GL
|
||||||
dl
|
dl
|
||||||
SDL3
|
SDL3::SDL3
|
||||||
SDL3_image
|
SDL3_image
|
||||||
libcurl_static
|
libcurl_static
|
||||||
OpenSSL::SSL OpenSSL::Crypto
|
OpenSSL::SSL OpenSSL::Crypto
|
||||||
|
|
@ -313,21 +319,19 @@ install_files("." FILES "${CMAKE_SOURCE_DIR}/LICENSE")
|
||||||
install_files("." FILES "${CMAKE_SOURCE_DIR}/tools/imgui.ini")
|
install_files("." FILES "${CMAKE_SOURCE_DIR}/tools/imgui.ini")
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
install_files("." FILES "${SDL2_BIN_DIR}/SDL2.dll")
|
install_files("." FILES "${SDL_BIN_DIR}/SDL3.dll")
|
||||||
install_files("." FILES "/usr/lib/gcc/x86_64-w64-mingw32/10-posix/libstdc++-6.dll")
|
install_files("." FILES "/usr/lib/gcc/x86_64-w64-mingw32/10-posix/libstdc++-6.dll")
|
||||||
install_files("." FILES "/usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll")
|
install_files("." FILES "/usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll")
|
||||||
install_files("." FILES "/usr/lib/gcc/x86_64-w64-mingw32/10-posix/libgcc_s_seh-1.dll")
|
install_files("." FILES "/usr/lib/gcc/x86_64-w64-mingw32/10-posix/libgcc_s_seh-1.dll")
|
||||||
endif()
|
|
||||||
|
|
||||||
# Personnaliser l'icône pour les installateurs Windows
|
# Personnaliser l'icône pour les installateurs Windows
|
||||||
if(WIN32)
|
set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/story-editor-logo.ico")
|
||||||
set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/story-editor-logo.ico")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(CPACK_GENERATOR "DragNDrop")
|
set(CPACK_GENERATOR "DragNDrop")
|
||||||
set(MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/bundle.plist.in)
|
set(MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/bundle.plist.in)
|
||||||
install_files("." FILES "${SDL2_BIN_DIR}/libSDL2-2.0.0.dylib")
|
install_files("." FILES "${SDL_BIN_DIR}/libSDL2-2.0.0.dylib")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(CPack)
|
include(CPack)
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,8 @@ public:
|
||||||
|
|
||||||
// Node interaction
|
// Node interaction
|
||||||
virtual void Build() = 0;
|
virtual void Build() = 0;
|
||||||
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(unsigned long nodeId) = 0;
|
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(const std::string &nodeId) = 0;
|
||||||
virtual std::string GetNodeEntryLabel(unsigned long nodeId) = 0;
|
virtual std::string GetNodeEntryLabel(const std::string &nodeId) = 0;
|
||||||
virtual void Play() = 0;
|
virtual void Play() = 0;
|
||||||
virtual void Ok() = 0;
|
virtual void Ok() = 0;
|
||||||
virtual void Pause() = 0;
|
virtual void Pause() = 0;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,3 @@
|
||||||
#include "pack_archive.h"
|
|
||||||
#include "ni_parser.h"
|
|
||||||
#include "json.hpp"
|
|
||||||
#include "serializers.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
@ -10,6 +5,15 @@
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
|
|
||||||
|
#include "pack_archive.h"
|
||||||
|
#include "ni_parser.h"
|
||||||
|
#include "json.hpp"
|
||||||
|
#include "serializers.h"
|
||||||
|
#include "story_project.h"
|
||||||
|
#include "resource_manager.h"
|
||||||
|
#include "uuid.h"
|
||||||
|
|
||||||
PackArchive::PackArchive()
|
PackArchive::PackArchive()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -411,6 +415,123 @@ std::string PackArchive::OpenImage(const std::string &fileName)
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PackArchive::ImportStudioFormat(const std::string &fileName, const std::string &outputDir)
|
||||||
|
{
|
||||||
|
auto uuid = UUID().String();
|
||||||
|
std::string basePath = outputDir + "/" + uuid;
|
||||||
|
Unzip(fileName, basePath);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
// STUDIO format
|
||||||
|
std::ifstream f(basePath + "/story.json");
|
||||||
|
nlohmann::json j = nlohmann::json::parse(f);
|
||||||
|
StoryProject proj;
|
||||||
|
ResourceManager res;
|
||||||
|
nlohmann::json model;
|
||||||
|
|
||||||
|
if (j.contains("title"))
|
||||||
|
{
|
||||||
|
proj.New(uuid, outputDir);
|
||||||
|
proj.SetName(j["title"].get<std::string>());
|
||||||
|
|
||||||
|
// Create resources, scan asset files
|
||||||
|
std::filesystem::path directoryPath(basePath + "/assets");
|
||||||
|
if (std::filesystem::exists(directoryPath) && std::filesystem::is_directory(directoryPath))
|
||||||
|
{
|
||||||
|
for (const auto& entry : std::filesystem::directory_iterator(directoryPath))
|
||||||
|
{
|
||||||
|
if (std::filesystem::is_regular_file(entry.path()))
|
||||||
|
{
|
||||||
|
// Si c'est un sous-répertoire, récursivement scanner le contenu
|
||||||
|
auto rData = std::make_shared<Resource>();
|
||||||
|
|
||||||
|
rData->file = entry.path().filename();
|
||||||
|
rData->type = ResourceManager::ExtentionInfo(entry.path().extension(), 1);
|
||||||
|
rData->format = ResourceManager::ExtentionInfo(entry.path().extension(), 0);
|
||||||
|
res.Add(rData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key: actionNode, value: Stage UUID
|
||||||
|
std::map<std::string, std::string> stageActionLink;
|
||||||
|
|
||||||
|
nlohmann::json jnodes = nlohmann::json::array();
|
||||||
|
for (const auto & n : j["stageNodes"])
|
||||||
|
{
|
||||||
|
nlohmann::json node;
|
||||||
|
|
||||||
|
auto node_uuid = n["uuid"].get<std::string>();
|
||||||
|
node["uuid"] = node_uuid;
|
||||||
|
node["type"] = "media-node";
|
||||||
|
node["position"] = n["position"];
|
||||||
|
|
||||||
|
nlohmann::json internalData;
|
||||||
|
auto img = n["image"];
|
||||||
|
internalData["image"] = img.is_string() ? img.get<std::string>() : "";
|
||||||
|
auto audio = n["audio"];
|
||||||
|
internalData["sound"] = audio.is_string() ? audio.get<std::string>() : "";
|
||||||
|
|
||||||
|
node["internal-data"] = internalData;
|
||||||
|
|
||||||
|
stageActionLink[n["okTransition"]["actionNode"]] = node_uuid;
|
||||||
|
/*
|
||||||
|
"okTransition":{
|
||||||
|
"actionNode":"19d7328f-d0d2-4443-a7a2-25270dafe52c",
|
||||||
|
"optionIndex":0
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
|
jnodes.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
model["nodes"] = jnodes;
|
||||||
|
|
||||||
|
nlohmann::json connections = nlohmann::json::array();
|
||||||
|
|
||||||
|
for (const auto & n : j["actionNodes"])
|
||||||
|
{
|
||||||
|
std::string action_node_uuid = n["id"].get<std::string>(); // le champs est "id" et non pas "uuid", pénible
|
||||||
|
|
||||||
|
if (stageActionLink.count(action_node_uuid) > 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (const auto & m : n["options"])
|
||||||
|
{
|
||||||
|
nlohmann::json c;
|
||||||
|
|
||||||
|
c["outNodeId"] = stageActionLink[action_node_uuid];
|
||||||
|
c["outPortIndex"] = i;
|
||||||
|
c["inNodeId"] = m; // On prend le stage node;
|
||||||
|
c["inPortIndex"] = 0;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
connections.push_back(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "ActionNode UUID not found" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model["connections"] = connections;
|
||||||
|
|
||||||
|
// Save on disk
|
||||||
|
proj.Save(model, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(std::exception &e)
|
||||||
|
{
|
||||||
|
std::cout << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::string PackArchive::GetImage(const std::string &fileName)
|
std::string PackArchive::GetImage(const std::string &fileName)
|
||||||
{
|
{
|
||||||
//"C8B39950DE174EAA8E852A07FC468267/rf/000/05FB5530"
|
//"C8B39950DE174EAA8E852A07FC468267/rf/000/05FB5530"
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ public:
|
||||||
|
|
||||||
bool Load(const std::string &filePath);
|
bool Load(const std::string &filePath);
|
||||||
std::string OpenImage(const std::string &fileName);
|
std::string OpenImage(const std::string &fileName);
|
||||||
|
|
||||||
|
bool ImportStudioFormat(const std::string &fileName, const std::string &outputDir);
|
||||||
|
|
||||||
std::string CurrentImage();
|
std::string CurrentImage();
|
||||||
std::string CurrentSound();
|
std::string CurrentSound();
|
||||||
std::string CurrentSoundName();
|
std::string CurrentSoundName();
|
||||||
|
|
|
||||||
|
|
@ -235,8 +235,6 @@ void MainWindow::DrawStatusBar()
|
||||||
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking;
|
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking;
|
||||||
ImGui::Begin("StatusBar", nullptr, windowFlags);
|
ImGui::Begin("StatusBar", nullptr, windowFlags);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (true)
|
if (true)
|
||||||
{
|
{
|
||||||
float dy = ImGui::GetFontSize() * 0.15f;
|
float dy = ImGui::GetFontSize() * 0.15f;
|
||||||
|
|
@ -657,117 +655,7 @@ void MainWindow::ImportProject(const std::string &fileName, int format)
|
||||||
{
|
{
|
||||||
PackArchive archive;
|
PackArchive archive;
|
||||||
|
|
||||||
Log("Decompressing " + fileName);
|
archive.ImportStudioFormat(fileName, m_libraryManager.LibraryPath());
|
||||||
auto uuid = UUID().String();
|
|
||||||
|
|
||||||
std::string basePath = m_libraryManager.LibraryPath() + "/" + uuid;
|
|
||||||
|
|
||||||
archive.Unzip(fileName, basePath);
|
|
||||||
|
|
||||||
// Ok try to convert the archive into our format
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
// STUDIO format
|
|
||||||
std::ifstream f(basePath + "/story.json");
|
|
||||||
nlohmann::json j = nlohmann::json::parse(f);
|
|
||||||
StoryProject proj;
|
|
||||||
ResourceManager res;
|
|
||||||
nlohmann::json model;
|
|
||||||
|
|
||||||
if (j.contains("title"))
|
|
||||||
{
|
|
||||||
proj.New(uuid, m_libraryManager.LibraryPath());
|
|
||||||
proj.SetName(j["title"].get<std::string>());
|
|
||||||
|
|
||||||
// Create resources, scan asset files
|
|
||||||
std::filesystem::path directoryPath(basePath + "/assets");
|
|
||||||
if (std::filesystem::exists(directoryPath) && std::filesystem::is_directory(directoryPath))
|
|
||||||
{
|
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(directoryPath))
|
|
||||||
{
|
|
||||||
if (std::filesystem::is_regular_file(entry.path()))
|
|
||||||
{
|
|
||||||
// Si c'est un sous-répertoire, récursivement scanner le contenu
|
|
||||||
std::string asset = entry.path().filename();
|
|
||||||
auto rData = std::make_shared<Resource>();
|
|
||||||
|
|
||||||
rData->type = ResourceManager::ExtentionInfo(entry.path().extension(), 1);
|
|
||||||
rData->format = ResourceManager::ExtentionInfo(entry.path().extension(), 0);
|
|
||||||
res.Add(rData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create model
|
|
||||||
|
|
||||||
int ids = 1;
|
|
||||||
nlohmann::json nodes = nlohmann::json::array();
|
|
||||||
for (const auto & n : j["stageNodes"])
|
|
||||||
{
|
|
||||||
nlohmann::json node;
|
|
||||||
node["id"] = ids++;
|
|
||||||
node["uuid"] = n["uuid"].get<std::string>();
|
|
||||||
node["type"] = "media-node";
|
|
||||||
|
|
||||||
auto type = n["type"].get<std::string>();
|
|
||||||
|
|
||||||
int outPortCount = 1;
|
|
||||||
int inPortCount = 1;
|
|
||||||
|
|
||||||
if (type == "stage") {
|
|
||||||
outPortCount = 1;
|
|
||||||
inPortCount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
node["outPortCount"] = outPortCount;
|
|
||||||
node["inPortCount"] = inPortCount;
|
|
||||||
node["position"] = n["position"];
|
|
||||||
|
|
||||||
nlohmann::json internalData;
|
|
||||||
auto img = n["image"];
|
|
||||||
internalData["image"] = img.is_string() ? img.get<std::string>() : "";
|
|
||||||
auto audio = n["audio"];
|
|
||||||
internalData["sound"] = audio.is_string() ? audio.get<std::string>() : "";
|
|
||||||
|
|
||||||
node["internal-data"] = internalData;
|
|
||||||
nodes.push_back(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
model["nodes"] = nodes;
|
|
||||||
|
|
||||||
// Save links
|
|
||||||
nlohmann::json connections = nlohmann::json::array();
|
|
||||||
|
|
||||||
/*
|
|
||||||
for (const auto& linkInfo : m_links)
|
|
||||||
{
|
|
||||||
|
|
||||||
nlohmann::json c;
|
|
||||||
|
|
||||||
Connection cnx = LinkToModel(linkInfo->ed_link->InputId, linkInfo->ed_link->OutputId);
|
|
||||||
|
|
||||||
c["outNodeId"] = cnx.outNodeId;
|
|
||||||
c["outPortIndex"] = cnx.outPortIndex;
|
|
||||||
c["inNodeId"] = cnx.inNodeId;
|
|
||||||
c["inPortIndex"] = cnx.inPortIndex;
|
|
||||||
|
|
||||||
connections.push_back(c);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
model["connections"] = connections;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save on disk
|
|
||||||
proj.Save(model, res);
|
|
||||||
}
|
|
||||||
catch(std::exception &e)
|
|
||||||
{
|
|
||||||
std::cout << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -923,12 +811,12 @@ void MainWindow::Build()
|
||||||
ConvertResources();
|
ConvertResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string MainWindow::GetNodeEntryLabel(unsigned long nodeId)
|
std::string MainWindow::GetNodeEntryLabel(const std::string &nodeId)
|
||||||
{
|
{
|
||||||
return m_nodeEditorWindow.GetNodeEntryLabel(nodeId);
|
return m_nodeEditorWindow.GetNodeEntryLabel(nodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<Connection>> MainWindow::GetNodeConnections(unsigned long nodeId)
|
std::list<std::shared_ptr<Connection>> MainWindow::GetNodeConnections(const std::string &nodeId)
|
||||||
{
|
{
|
||||||
return m_nodeEditorWindow.GetNodeConnections(nodeId);
|
return m_nodeEditorWindow.GetNodeConnections(nodeId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -135,8 +135,8 @@ private:
|
||||||
virtual std::pair<FilterIterator, FilterIterator> Resources() override;
|
virtual std::pair<FilterIterator, FilterIterator> Resources() override;
|
||||||
virtual void DeleteResource(FilterIterator &it) override;
|
virtual void DeleteResource(FilterIterator &it) override;
|
||||||
virtual void Build() override;
|
virtual void Build() override;
|
||||||
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(unsigned long nodeId) override;
|
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(const std::string &nodeId) override;
|
||||||
virtual std::string GetNodeEntryLabel(unsigned long nodeId) override;
|
virtual std::string GetNodeEntryLabel(const std::string &nodeId) override;
|
||||||
virtual void Play() override;
|
virtual void Play() override;
|
||||||
virtual void Ok() override;
|
virtual void Ok() override;
|
||||||
virtual void Pause() override;
|
virtual void Pause() override;
|
||||||
|
|
|
||||||
|
|
@ -157,3 +157,101 @@ int MediaConverter::Mp3ToWav(const std::string &inputFileName, const std::string
|
||||||
|
|
||||||
return cSuccess;
|
return cSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
OGG TO WAV
|
||||||
|
|
||||||
|
#define STB_VORBIS_HEADER_ONLY
|
||||||
|
#include "stb_vorbis.c"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// Function to read the entire contents of a file into memory
|
||||||
|
unsigned char* read_entire_file(const char* filename, int* length) {
|
||||||
|
FILE* f = fopen(filename, "rb");
|
||||||
|
if (!f) return NULL;
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long size = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
unsigned char* buffer = (unsigned char*)malloc(size);
|
||||||
|
if (!buffer) {
|
||||||
|
fclose(f);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fread(buffer, 1, size, f);
|
||||||
|
fclose(f);
|
||||||
|
if (length) *length = (int)size;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
if (argc != 3) {
|
||||||
|
printf("Usage: %s input.ogg output.wav\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* input_filename = argv[1];
|
||||||
|
const char* output_filename = argv[2];
|
||||||
|
|
||||||
|
int ogg_length;
|
||||||
|
unsigned char* ogg_data = read_entire_file(input_filename, &ogg_length);
|
||||||
|
if (!ogg_data) {
|
||||||
|
printf("Failed to read input file %s\n", input_filename);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int channels, sample_rate;
|
||||||
|
short* samples = stb_vorbis_decode_memory(ogg_data, ogg_length, &channels, &sample_rate);
|
||||||
|
if (!samples) {
|
||||||
|
printf("Failed to decode OGG file %s\n", input_filename);
|
||||||
|
free(ogg_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write WAV file header
|
||||||
|
FILE* wav_file = fopen(output_filename, "wb");
|
||||||
|
if (!wav_file) {
|
||||||
|
printf("Failed to create output file %s\n", output_filename);
|
||||||
|
free(ogg_data);
|
||||||
|
free(samples);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fwrite("RIFF", 1, 4, wav_file);
|
||||||
|
int total_size = 36 + channels * (sample_rate * sizeof(short));
|
||||||
|
fwrite(&total_size, 4, 1, wav_file);
|
||||||
|
fwrite("WAVEfmt ", 1, 8, wav_file);
|
||||||
|
int format_size = 16;
|
||||||
|
fwrite(&format_size, 4, 1, wav_file);
|
||||||
|
short format_type = 1; // PCM
|
||||||
|
fwrite(&format_type, 2, 1, wav_file);
|
||||||
|
fwrite(&channels, 2, 1, wav_file);
|
||||||
|
fwrite(&sample_rate, 4, 1, wav_file);
|
||||||
|
int byte_rate = sample_rate * channels * sizeof(short);
|
||||||
|
fwrite(&byte_rate, 4, 1, wav_file);
|
||||||
|
short block_align = channels * sizeof(short);
|
||||||
|
fwrite(&block_align, 2, 1, wav_file);
|
||||||
|
short bits_per_sample = 16;
|
||||||
|
fwrite(&bits_per_sample, 2, 1, wav_file);
|
||||||
|
fwrite("data", 1, 4, wav_file);
|
||||||
|
int data_size = channels * (sample_rate * sizeof(short));
|
||||||
|
fwrite(&data_size, 4, 1, wav_file);
|
||||||
|
|
||||||
|
// Write sample data
|
||||||
|
fwrite(samples, sizeof(short), sample_rate * channels, wav_file);
|
||||||
|
|
||||||
|
fclose(wav_file);
|
||||||
|
|
||||||
|
free(ogg_data);
|
||||||
|
free(samples);
|
||||||
|
|
||||||
|
printf("Conversion complete. WAV file saved as %s\n", output_filename);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,24 @@
|
||||||
#include "base_node.h"
|
#include "base_node_widget.h"
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
|
|
||||||
#include "IconsMaterialDesignIcons.h"
|
#include "IconsMaterialDesignIcons.h"
|
||||||
|
|
||||||
unsigned long BaseNode::s_nextId = 1;
|
unsigned long BaseNodeWidget::s_nextId = 1;
|
||||||
|
|
||||||
BaseNode::BaseNode(const std::string &title, IStoryManager &proj)
|
BaseNodeWidget::BaseNodeWidget(const std::string &type, IStoryManager &proj)
|
||||||
: m_story(proj)
|
: BaseNode(type)
|
||||||
|
, m_story(proj)
|
||||||
{
|
{
|
||||||
// m_id = UUID().String();
|
// m_id = UUID().String();
|
||||||
|
m_node = std::make_unique<Node>(GetNextId(), ""); // ImGui internal ID
|
||||||
m_id = -1; // Story Project Node ID
|
|
||||||
m_node = std::make_unique<Node>(GetNextId(), title.c_str()); // ImGui internal ID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseNode::AddInput()
|
void BaseNodeWidget::AddInput()
|
||||||
{
|
{
|
||||||
m_node->Inputs.emplace_back(GetNextId(), "", PinType::Flow);
|
m_node->Inputs.emplace_back(GetNextId(), "", PinType::Flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseNode::AddOutputs(int num)
|
void BaseNodeWidget::AddOutputs(int num)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < num; i++)
|
for (int i = 0; i < num; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -27,7 +26,7 @@ void BaseNode::AddOutputs(int num)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseNode::SetOutputs(uint32_t num)
|
void BaseNodeWidget::SetOutputs(uint32_t num)
|
||||||
{
|
{
|
||||||
if (num > Outputs())
|
if (num > Outputs())
|
||||||
{
|
{
|
||||||
|
|
@ -42,35 +41,38 @@ void BaseNode::SetOutputs(uint32_t num)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseNode::DeleteOutput()
|
void BaseNodeWidget::DeleteOutput()
|
||||||
{
|
{
|
||||||
m_node->Outputs.pop_back();
|
m_node->Outputs.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseNode::SetPosition(float x, float y)
|
|
||||||
|
void BaseNodeWidget::Initialize()
|
||||||
{
|
{
|
||||||
m_pos.x = x;
|
m_firstFrame = true;
|
||||||
m_pos.y = y;
|
|
||||||
m_firstFrame = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseNode::FrameStart()
|
|
||||||
|
void BaseNodeWidget::FrameStart()
|
||||||
{
|
{
|
||||||
ed::BeginNode(m_node->ID);
|
ed::BeginNode(m_node->ID);
|
||||||
|
|
||||||
if (m_firstFrame)
|
if (m_firstFrame)
|
||||||
{
|
{
|
||||||
ed::SetNodePosition(m_node->ID, ImVec2(m_pos.x, m_pos.y));
|
// Use the parent node position, the one saved in the JSON project
|
||||||
|
// FIXME: find a better way to do that?
|
||||||
|
ed::SetNodePosition(m_node->ID, ImVec2(BaseNode::GetX(), BaseNode::GetY()));
|
||||||
}
|
}
|
||||||
m_firstFrame = false;
|
m_firstFrame = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseNode::FrameEnd()
|
void BaseNodeWidget::FrameEnd()
|
||||||
{
|
{
|
||||||
ed::EndNode();
|
ed::EndNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseNode::DrawPins()
|
void BaseNodeWidget::DrawPins()
|
||||||
{
|
{
|
||||||
static const char *str = "#1 >";
|
static const char *str = "#1 >";
|
||||||
static float textWidth = ImGui::CalcTextSize(str).x;
|
static float textWidth = ImGui::CalcTextSize(str).x;
|
||||||
|
|
@ -94,13 +96,13 @@ void BaseNode::DrawPins()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float BaseNode::GetX() const
|
float BaseNodeWidget::GetX() const
|
||||||
{
|
{
|
||||||
auto pos = GetNodePosition(m_node->ID);
|
auto pos = GetNodePosition(m_node->ID);
|
||||||
return pos.x;
|
return pos.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
float BaseNode::GetY() const
|
float BaseNodeWidget::GetY() const
|
||||||
{
|
{
|
||||||
auto pos = GetNodePosition(m_node->ID);
|
auto pos = GetNodePosition(m_node->ID);
|
||||||
return pos.y;
|
return pos.y;
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "json.hpp"
|
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
#include "i_story_manager.h"
|
#include "i_story_manager.h"
|
||||||
|
#include "base_node.h"
|
||||||
|
|
||||||
#include <imgui_node_editor.h>
|
#include <imgui_node_editor.h>
|
||||||
namespace ed = ax::NodeEditor;
|
namespace ed = ax::NodeEditor;
|
||||||
|
|
@ -91,8 +91,11 @@ struct Link
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
class BaseNode
|
* @brief Basically a wrapper class around ImGuiNodeEditor Node structure
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class BaseNodeWidget : public BaseNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct NodePosition
|
struct NodePosition
|
||||||
|
|
@ -101,8 +104,9 @@ public:
|
||||||
float y;
|
float y;
|
||||||
};
|
};
|
||||||
|
|
||||||
BaseNode(const std::string &title, IStoryManager &proj);
|
BaseNodeWidget(const std::string &type, IStoryManager &proj);
|
||||||
|
|
||||||
|
virtual void Initialize();
|
||||||
|
|
||||||
virtual void Draw() = 0;
|
virtual void Draw() = 0;
|
||||||
virtual void DrawProperties() = 0;
|
virtual void DrawProperties() = 0;
|
||||||
|
|
@ -110,45 +114,20 @@ public:
|
||||||
virtual std::string Build() = 0;
|
virtual std::string Build() = 0;
|
||||||
virtual std::string GetEntryLabel() = 0;
|
virtual std::string GetEntryLabel() = 0;
|
||||||
|
|
||||||
void SetPosition(float x, float y);
|
|
||||||
|
|
||||||
void FrameStart();
|
void FrameStart();
|
||||||
void FrameEnd();
|
void FrameEnd();
|
||||||
|
|
||||||
void DrawPins();
|
void DrawPins();
|
||||||
|
|
||||||
float GetX() const;
|
virtual float GetX() const;
|
||||||
float GetY() const;
|
virtual float GetY() const;
|
||||||
|
|
||||||
|
|
||||||
uint32_t Inputs() const { return m_node->Inputs.size(); }
|
uint32_t Inputs() const { return m_node->Inputs.size(); }
|
||||||
uint32_t Outputs() const { return m_node->Outputs.size(); }
|
uint32_t Outputs() const { return m_node->Outputs.size(); }
|
||||||
|
|
||||||
void SetType(const std::string &type)
|
|
||||||
{
|
|
||||||
m_type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetType() const
|
|
||||||
{
|
|
||||||
return m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetId(unsigned long id) { m_id = id; }
|
|
||||||
unsigned long GetId() const { return m_id; }
|
|
||||||
unsigned long GetInternalId() const { return m_node->ID.Get(); }
|
unsigned long GetInternalId() const { return m_node->ID.Get(); }
|
||||||
|
|
||||||
void SeTitle(const std::string &title) { m_title = title; }
|
|
||||||
std::string GetTitle() const { return m_title; }
|
|
||||||
|
|
||||||
virtual void FromJson(const nlohmann::json &) = 0;
|
|
||||||
virtual void ToJson(nlohmann::json &) = 0;
|
|
||||||
|
|
||||||
virtual nlohmann::json ToJson() const {
|
|
||||||
nlohmann::json j;
|
|
||||||
|
|
||||||
j["type"] = m_type;
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned long GetNextId()
|
static unsigned long GetNextId()
|
||||||
{
|
{
|
||||||
|
|
@ -227,16 +206,9 @@ private:
|
||||||
|
|
||||||
std::unique_ptr<Node> m_node;
|
std::unique_ptr<Node> m_node;
|
||||||
|
|
||||||
std::string m_title{"Base node"};
|
|
||||||
std::string m_type;
|
|
||||||
unsigned long m_id;
|
|
||||||
NodePosition m_pos;
|
|
||||||
bool m_firstFrame{true};
|
bool m_firstFrame{true};
|
||||||
|
|
||||||
static unsigned long s_nextId;
|
static unsigned long s_nextId;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -7,7 +7,7 @@ namespace ed = ax::NodeEditor;
|
||||||
#include "story_project.h"
|
#include "story_project.h"
|
||||||
|
|
||||||
MediaNode::MediaNode(const std::string &title, IStoryManager &proj)
|
MediaNode::MediaNode(const std::string &title, IStoryManager &proj)
|
||||||
: BaseNode(title, proj)
|
: BaseNodeWidget(title, proj)
|
||||||
, m_story(proj)
|
, m_story(proj)
|
||||||
{
|
{
|
||||||
// Create defaut one input and one output
|
// Create defaut one input and one output
|
||||||
|
|
@ -22,7 +22,7 @@ MediaNode::MediaNode(const std::string &title, IStoryManager &proj)
|
||||||
|
|
||||||
void MediaNode::Draw()
|
void MediaNode::Draw()
|
||||||
{
|
{
|
||||||
BaseNode::FrameStart();
|
BaseNodeWidget::FrameStart();
|
||||||
|
|
||||||
|
|
||||||
static ImGuiTableFlags flags = ImGuiTableFlags_Borders |
|
static ImGuiTableFlags flags = ImGuiTableFlags_Borders |
|
||||||
|
|
@ -69,11 +69,11 @@ void MediaNode::Draw()
|
||||||
uint32_t counter = Outputs();
|
uint32_t counter = Outputs();
|
||||||
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
|
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
|
||||||
ImGui::PushButtonRepeat(true);
|
ImGui::PushButtonRepeat(true);
|
||||||
std::string leftSingle = "##left" + std::to_string(GetId());
|
std::string leftSingle = "##left" + GetId();
|
||||||
if (ImGui::ArrowButton(leftSingle.c_str(), ImGuiDir_Left)) { if (counter > 1) counter--; }
|
if (ImGui::ArrowButton(leftSingle.c_str(), ImGuiDir_Left)) { if (counter > 1) counter--; }
|
||||||
ImGui::SameLine(0.0f, spacing);
|
ImGui::SameLine(0.0f, spacing);
|
||||||
|
|
||||||
std::string rightSingle = "##right" + std::to_string(GetId());
|
std::string rightSingle = "##right" + GetId();
|
||||||
if (ImGui::ArrowButton(rightSingle.c_str(), ImGuiDir_Right))
|
if (ImGui::ArrowButton(rightSingle.c_str(), ImGuiDir_Right))
|
||||||
{
|
{
|
||||||
counter++;
|
counter++;
|
||||||
|
|
@ -86,7 +86,7 @@ void MediaNode::Draw()
|
||||||
|
|
||||||
DrawPins();
|
DrawPins();
|
||||||
|
|
||||||
BaseNode::FrameEnd();
|
BaseNodeWidget::FrameEnd();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,18 +96,22 @@ void MediaNode::Draw()
|
||||||
"image": "fairy.png",
|
"image": "fairy.png",
|
||||||
"sound": "la_fee_luminelle.mp3"
|
"sound": "la_fee_luminelle.mp3"
|
||||||
},
|
},
|
||||||
|
|
||||||
*/
|
*/
|
||||||
void MediaNode::FromJson(const nlohmann::json &j)
|
void MediaNode::Initialize()
|
||||||
{
|
{
|
||||||
|
BaseNodeWidget::Initialize();
|
||||||
|
nlohmann::json j = GetInternalData();
|
||||||
SetImage(j["image"].get<std::string>());
|
SetImage(j["image"].get<std::string>());
|
||||||
SetSound(j["sound"].get<std::string>());
|
SetSound(j["sound"].get<std::string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaNode::ToJson(nlohmann::json &j)
|
void MediaNode::StoreInternalData()
|
||||||
{
|
{
|
||||||
|
nlohmann::json j;
|
||||||
j["image"] = m_image.name;
|
j["image"] = m_image.name;
|
||||||
j["sound"] = m_soundName;
|
j["sound"] = m_soundName;
|
||||||
|
|
||||||
|
SetInternalData(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaNode::DrawProperties()
|
void MediaNode::DrawProperties()
|
||||||
|
|
@ -186,12 +190,14 @@ void MediaNode::SetImage(const std::string &f)
|
||||||
{
|
{
|
||||||
m_image.name = f;
|
m_image.name = f;
|
||||||
m_image.Load(m_story.BuildFullAssetsPath(f));
|
m_image.Load(m_story.BuildFullAssetsPath(f));
|
||||||
|
StoreInternalData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaNode::SetSound(const std::string &f)
|
void MediaNode::SetSound(const std::string &f)
|
||||||
{
|
{
|
||||||
m_soundName = f;
|
m_soundName = f;
|
||||||
m_soundPath = m_story.BuildFullAssetsPath(m_soundName);
|
m_soundPath = m_story.BuildFullAssetsPath(m_soundName);
|
||||||
|
StoreInternalData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -5,35 +5,36 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "base_node.h"
|
#include "base_node_widget.h"
|
||||||
#include "i_story_manager.h"
|
#include "i_story_manager.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include <imgui_node_editor.h>
|
#include <imgui_node_editor.h>
|
||||||
|
|
||||||
|
|
||||||
class MediaNode : public BaseNode
|
class MediaNode : public BaseNodeWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MediaNode(const std::string &title, IStoryManager &proj);
|
MediaNode(const std::string &title, IStoryManager &proj);
|
||||||
|
|
||||||
void Draw() override;
|
void Draw() override;
|
||||||
|
|
||||||
virtual void FromJson(const nlohmann::json &j) override;
|
|
||||||
virtual void ToJson(nlohmann::json &j) override;
|
|
||||||
virtual void DrawProperties() override;
|
virtual void DrawProperties() override;
|
||||||
virtual std::string Build() override;
|
virtual std::string Build() override;
|
||||||
virtual std::string GetEntryLabel() override;
|
virtual std::string GetEntryLabel() override;
|
||||||
virtual std::string GenerateConstants() override;
|
virtual std::string GenerateConstants() override;
|
||||||
|
|
||||||
|
virtual void Initialize() override;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IStoryManager &m_story;
|
IStoryManager &m_story;
|
||||||
Gui::Image m_image;
|
Gui::Image m_image;
|
||||||
std::string m_soundName;
|
std::string m_soundName;
|
||||||
std::string m_soundPath;
|
std::string m_soundPath;
|
||||||
|
|
||||||
std::string m_id;
|
|
||||||
|
|
||||||
std::string m_buttonUniqueName;
|
std::string m_buttonUniqueName;
|
||||||
|
|
||||||
void SetImage(const std::string &f);
|
void SetImage(const std::string &f);
|
||||||
void SetSound(const std::string &f);
|
void SetSound(const std::string &f);
|
||||||
std::string ChoiceLabel() const;
|
std::string ChoiceLabel() const;
|
||||||
|
void StoreInternalData();
|
||||||
};
|
};
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "media_node.h"
|
#include "media_node.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
#include "uuid.h"
|
||||||
|
|
||||||
#include <stdexcept> // for std::runtime_error
|
#include <stdexcept> // for std::runtime_error
|
||||||
#define JSON_ASSERT(x) \
|
#define JSON_ASSERT(x) \
|
||||||
|
|
@ -45,59 +46,15 @@ void NodeEditorWindow::Initialize()
|
||||||
void NodeEditorWindow::Clear()
|
void NodeEditorWindow::Clear()
|
||||||
{
|
{
|
||||||
m_nodes.clear();
|
m_nodes.clear();
|
||||||
m_ids.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string NodeEditorWindow::GenerateNodeId()
|
||||||
|
|
||||||
void NodeEditorWindow::LoadNode(const nlohmann::json &nodeJson)
|
|
||||||
{
|
{
|
||||||
try
|
return UUID().String();
|
||||||
{
|
|
||||||
int restoredNodeId = nodeJson["id"].get<int>();
|
|
||||||
nlohmann::json internalDataJson = nodeJson["internal-data"];
|
|
||||||
std::string type = nodeJson["type"].get<std::string>();
|
|
||||||
|
|
||||||
auto n = createNode(type, "", m_story);
|
|
||||||
if (n)
|
|
||||||
{
|
|
||||||
n->SetType(type); // FIXME: set type in createNode factory?
|
|
||||||
n->SetId(restoredNodeId);
|
|
||||||
nlohmann::json posJson = nodeJson["position"];
|
|
||||||
n->SetOutputs(nodeJson["outPortCount"].get<int>());
|
|
||||||
n->SetPosition(posJson["x"].get<double>(), posJson["y"].get<double>());
|
|
||||||
n->FromJson(internalDataJson);
|
|
||||||
|
|
||||||
m_ids.insert(restoredNodeId);
|
|
||||||
|
|
||||||
m_nodes.push_back(n);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw std::logic_error(std::string("No registered model with name ") + type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (std::exception& e)
|
|
||||||
{
|
|
||||||
std::cout << "ERROR: " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int NodeEditorWindow::GenerateNodeId()
|
|
||||||
{
|
|
||||||
int max = 1;
|
|
||||||
if (m_ids.size() > 0)
|
|
||||||
{
|
|
||||||
auto max = *m_ids.rbegin();
|
|
||||||
max++;
|
|
||||||
m_ids.insert(max);
|
|
||||||
}
|
|
||||||
return max;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ed::PinId NodeEditorWindow::GetInputPin(unsigned long modelNodeId, int pinIndex)
|
ed::PinId NodeEditorWindow::GetInputPin(const std::string &modelNodeId, int pinIndex)
|
||||||
{
|
{
|
||||||
ed::PinId id = 0;
|
ed::PinId id = 0;
|
||||||
|
|
||||||
|
|
@ -106,18 +63,19 @@ ed::PinId NodeEditorWindow::GetInputPin(unsigned long modelNodeId, int pinIndex)
|
||||||
if (n->GetId() == modelNodeId)
|
if (n->GetId() == modelNodeId)
|
||||||
{
|
{
|
||||||
id = n->GetInputPinAt(pinIndex);
|
id = n->GetInputPinAt(pinIndex);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id.Get() == 0)
|
if (id.Get() == 0)
|
||||||
{
|
{
|
||||||
std::cout << "Invalid Id, input pin not found" << std::endl;
|
std::cout << "Invalid Id: " << modelNodeId << " input pin: " << pinIndex <<" not found" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
ed::PinId NodeEditorWindow::GetOutputPin(unsigned long modelNodeId, int pinIndex)
|
ed::PinId NodeEditorWindow::GetOutputPin(const std::string &modelNodeId, int pinIndex)
|
||||||
{
|
{
|
||||||
ed::PinId id = 0;
|
ed::PinId id = 0;
|
||||||
|
|
||||||
|
|
@ -126,12 +84,13 @@ ed::PinId NodeEditorWindow::GetOutputPin(unsigned long modelNodeId, int pinIndex
|
||||||
if (n->GetId() == modelNodeId)
|
if (n->GetId() == modelNodeId)
|
||||||
{
|
{
|
||||||
id = n->GetOutputPinAt(pinIndex);
|
id = n->GetOutputPinAt(pinIndex);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id.Get() == 0)
|
if (id.Get() == 0)
|
||||||
{
|
{
|
||||||
std::cout << "Invalid Id, output pin not found" << std::endl;
|
std::cout << "Invalid Id: " << modelNodeId << " output pin: " << pinIndex <<" not found" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
|
|
@ -141,15 +100,27 @@ void NodeEditorWindow::Load(const nlohmann::json &model)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
||||||
nlohmann::json nodesJsonArray = model["nodes"];
|
nlohmann::json nodesJsonArray = model["nodes"];
|
||||||
|
|
||||||
BaseNode::InitId();
|
BaseNodeWidget::InitId();
|
||||||
m_nodes.clear();
|
m_nodes.clear();
|
||||||
m_links.clear();
|
m_links.clear();
|
||||||
|
|
||||||
for (auto& element : nodesJsonArray) {
|
for (auto& element : nodesJsonArray) {
|
||||||
LoadNode(element);
|
|
||||||
|
std::string type = element["type"].get<std::string>();
|
||||||
|
|
||||||
|
auto n = createNode(type, m_story);
|
||||||
|
if (n)
|
||||||
|
{
|
||||||
|
n->FromJson(element);
|
||||||
|
n->Initialize();
|
||||||
|
m_nodes.push_back(n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::logic_error(std::string("No registered model with name ") + type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << model.dump(4) << std::endl;
|
std::cout << model.dump(4) << std::endl;
|
||||||
|
|
@ -160,20 +131,47 @@ void NodeEditorWindow::Load(const nlohmann::json &model)
|
||||||
{
|
{
|
||||||
nlohmann::json connectionJsonArray = model["connections"];
|
nlohmann::json connectionJsonArray = model["connections"];
|
||||||
|
|
||||||
|
// key: node UUID, value: output counts
|
||||||
|
std::map<std::string, int> outputCounts;
|
||||||
|
|
||||||
for (auto& connection : connectionJsonArray)
|
for (auto& connection : connectionJsonArray)
|
||||||
{
|
{
|
||||||
Connection model = connection.get<Connection>();
|
Connection model = connection.get<Connection>();
|
||||||
|
|
||||||
|
|
||||||
|
if (outputCounts.count(model.outNodeId) > 0)
|
||||||
|
{
|
||||||
|
outputCounts[model.outNodeId]++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outputCounts[model.outNodeId] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust the number of outputs for all nodes
|
||||||
|
for (auto n : m_nodes)
|
||||||
|
{
|
||||||
|
if (outputCounts.count(n->GetId()) > 0)
|
||||||
|
{
|
||||||
|
n->SetOutputs(outputCounts[n->GetId()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CreateLink(model,
|
CreateLink(model,
|
||||||
GetInputPin(model.inNodeId, model.inPortIndex),
|
GetInputPin(model.inNodeId, model.inPortIndex),
|
||||||
GetOutputPin(model.outNodeId, model.outPortIndex));
|
GetOutputPin(model.outNodeId, model.outPortIndex));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_loaded = true;
|
m_loaded = true;
|
||||||
}
|
}
|
||||||
catch(std::exception &e)
|
catch(std::exception &e)
|
||||||
{
|
{
|
||||||
std::cout << e.what() << std::endl;
|
std::cout << "(NodeEditorWindow::Load) " << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -186,7 +184,7 @@ void NodeEditorWindow::CreateLink(const Connection &model, ed::PinId inId, ed::P
|
||||||
*conn->model = model;
|
*conn->model = model;
|
||||||
|
|
||||||
// ImGui stuff for links
|
// ImGui stuff for links
|
||||||
conn->ed_link->Id = BaseNode::GetNextId();
|
conn->ed_link->Id = BaseNodeWidget::GetNextId();
|
||||||
conn->ed_link->InputId = inId;
|
conn->ed_link->InputId = inId;
|
||||||
conn->ed_link->OutputId = outId;
|
conn->ed_link->OutputId = outId;
|
||||||
|
|
||||||
|
|
@ -202,23 +200,7 @@ void NodeEditorWindow::Save(nlohmann::json &model)
|
||||||
nlohmann::json nodes = nlohmann::json::array();
|
nlohmann::json nodes = nlohmann::json::array();
|
||||||
for (const auto & n : m_nodes)
|
for (const auto & n : m_nodes)
|
||||||
{
|
{
|
||||||
nlohmann::json node;
|
nodes.push_back(n->ToJson());
|
||||||
node["id"] = n->GetId();
|
|
||||||
node["type"] = n->GetType();
|
|
||||||
node["outPortCount"] = n->Outputs();
|
|
||||||
node["inPortCount"] = n->Inputs();
|
|
||||||
|
|
||||||
nlohmann::json position;
|
|
||||||
position["x"] = n->GetX();
|
|
||||||
position["y"] = n->GetY();
|
|
||||||
|
|
||||||
nlohmann::json internalData;
|
|
||||||
|
|
||||||
n->ToJson(internalData);
|
|
||||||
|
|
||||||
node["position"] = position;
|
|
||||||
node["internal-data"] = internalData;
|
|
||||||
nodes.push_back(node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
model["nodes"] = nodes;
|
model["nodes"] = nodes;
|
||||||
|
|
@ -227,7 +209,6 @@ void NodeEditorWindow::Save(nlohmann::json &model)
|
||||||
nlohmann::json connections = nlohmann::json::array();
|
nlohmann::json connections = nlohmann::json::array();
|
||||||
for (const auto& linkInfo : m_links)
|
for (const auto& linkInfo : m_links)
|
||||||
{
|
{
|
||||||
|
|
||||||
nlohmann::json c;
|
nlohmann::json c;
|
||||||
|
|
||||||
Connection cnx = LinkToModel(linkInfo->ed_link->InputId, linkInfo->ed_link->OutputId);
|
Connection cnx = LinkToModel(linkInfo->ed_link->InputId, linkInfo->ed_link->OutputId);
|
||||||
|
|
@ -266,9 +247,9 @@ Connection NodeEditorWindow::LinkToModel(ed::PinId InputId, ed::PinId OutputId)
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t NodeEditorWindow::FindFirstNode() const
|
std::string NodeEditorWindow::FindFirstNode() const
|
||||||
{
|
{
|
||||||
uint32_t id = 0;
|
std::string id;
|
||||||
|
|
||||||
// First node is the one without connection on its input port
|
// First node is the one without connection on its input port
|
||||||
|
|
||||||
|
|
@ -286,7 +267,7 @@ uint32_t NodeEditorWindow::FindFirstNode() const
|
||||||
if (!foundConnection)
|
if (!foundConnection)
|
||||||
{
|
{
|
||||||
id = n->GetId();
|
id = n->GetId();
|
||||||
m_story.Log("First node is: " + std::to_string(id));
|
m_story.Log("First node is: " + id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -302,7 +283,7 @@ std::string NodeEditorWindow::Build()
|
||||||
|
|
||||||
std::stringstream chip32;
|
std::stringstream chip32;
|
||||||
|
|
||||||
uint32_t firstNode = FindFirstNode();
|
std::string firstNode = FindFirstNode();
|
||||||
|
|
||||||
code << "\tjump " << GetNodeEntryLabel(firstNode) << "\r\n";
|
code << "\tjump " << GetNodeEntryLabel(firstNode) << "\r\n";
|
||||||
|
|
||||||
|
|
@ -321,13 +302,13 @@ std::string NodeEditorWindow::Build()
|
||||||
return code.str();
|
return code.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<Connection>> NodeEditorWindow::GetNodeConnections(unsigned long nodeId)
|
std::list<std::shared_ptr<Connection>> NodeEditorWindow::GetNodeConnections(const std::string &nodeId)
|
||||||
{
|
{
|
||||||
std::list<std::shared_ptr<Connection>> c;
|
std::list<std::shared_ptr<Connection>> c;
|
||||||
ed::SetCurrentEditor(m_context);
|
ed::SetCurrentEditor(m_context);
|
||||||
|
|
||||||
for (const auto & l : m_links)
|
for (const auto & l : m_links)
|
||||||
{
|
{
|
||||||
if (l->model->outNodeId == nodeId)
|
if (l->model->outNodeId == nodeId)
|
||||||
{
|
{
|
||||||
c.push_back(l->model);
|
c.push_back(l->model);
|
||||||
|
|
@ -338,7 +319,7 @@ std::list<std::shared_ptr<Connection>> NodeEditorWindow::GetNodeConnections(unsi
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string NodeEditorWindow::GetNodeEntryLabel(unsigned long nodeId)
|
std::string NodeEditorWindow::GetNodeEntryLabel(const std::string &nodeId)
|
||||||
{
|
{
|
||||||
std::string label;
|
std::string label;
|
||||||
ed::SetCurrentEditor(m_context);
|
ed::SetCurrentEditor(m_context);
|
||||||
|
|
@ -357,9 +338,9 @@ std::string NodeEditorWindow::GetNodeEntryLabel(unsigned long nodeId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<BaseNode> NodeEditorWindow::GetSelectedNode()
|
std::shared_ptr<BaseNodeWidget> NodeEditorWindow::GetSelectedNode()
|
||||||
{
|
{
|
||||||
std::shared_ptr<BaseNode> selected;
|
std::shared_ptr<BaseNodeWidget> selected;
|
||||||
|
|
||||||
ed::SetCurrentEditor(m_context);
|
ed::SetCurrentEditor(m_context);
|
||||||
if (ed::GetSelectedObjectCount() > 0)
|
if (ed::GetSelectedObjectCount() > 0)
|
||||||
|
|
@ -485,21 +466,16 @@ void NodeEditorWindow::Draw()
|
||||||
Node* node = nullptr;
|
Node* node = nullptr;
|
||||||
if (ImGui::MenuItem("Media Node"))
|
if (ImGui::MenuItem("Media Node"))
|
||||||
{
|
{
|
||||||
auto n = createNode("media-node", "", m_story);
|
auto n = createNode("media-node", m_story);
|
||||||
if (n)
|
if (n)
|
||||||
{
|
{
|
||||||
n->SetType("media-node"); // FIXME: set type in createNode factory?
|
|
||||||
n->SetId(GenerateNodeId());
|
n->SetId(GenerateNodeId());
|
||||||
n->SetPosition(newNodePostion.x, newNodePostion.y);
|
n->SetPosition(newNodePostion.x, newNodePostion.y);
|
||||||
|
n->Initialize();
|
||||||
m_nodes.push_back(n);
|
m_nodes.push_back(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (node)
|
|
||||||
// {
|
|
||||||
// ed::SetNodePosition(node->ID, newNodePostion);
|
|
||||||
// }
|
|
||||||
|
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include <imgui_node_editor.h>
|
#include <imgui_node_editor.h>
|
||||||
#include "base_node.h"
|
#include "base_node_widget.h"
|
||||||
#include "window_base.h"
|
#include "window_base.h"
|
||||||
#include "i_story_manager.h"
|
#include "i_story_manager.h"
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
|
|
@ -55,10 +55,10 @@ public:
|
||||||
void Load(const nlohmann::json &model);
|
void Load(const nlohmann::json &model);
|
||||||
void Save(nlohmann::json &model);
|
void Save(nlohmann::json &model);
|
||||||
std::string Build();
|
std::string Build();
|
||||||
std::list<std::shared_ptr<Connection> > GetNodeConnections(unsigned long nodeId);
|
std::list<std::shared_ptr<Connection> > GetNodeConnections(const std::string &nodeId);
|
||||||
std::string GetNodeEntryLabel(unsigned long nodeId);
|
std::string GetNodeEntryLabel(const std::string &nodeId);
|
||||||
|
|
||||||
std::shared_ptr<BaseNode> GetSelectedNode();
|
std::shared_ptr<BaseNodeWidget> GetSelectedNode();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IStoryManager &m_story;
|
IStoryManager &m_story;
|
||||||
|
|
@ -68,12 +68,10 @@ private:
|
||||||
bool m_loaded{false};
|
bool m_loaded{false};
|
||||||
|
|
||||||
// key: Id
|
// key: Id
|
||||||
std::list<std::shared_ptr<BaseNode>> m_nodes;
|
std::list<std::shared_ptr<BaseNodeWidget>> m_nodes;
|
||||||
std::list<std::shared_ptr<LinkInfo>> m_links; // List of live links. It is dynamic unless you want to create read-only view over nodes.
|
std::list<std::shared_ptr<LinkInfo>> m_links; // List of live links. It is dynamic unless you want to create read-only view over nodes.
|
||||||
void ToolbarUI();
|
void ToolbarUI();
|
||||||
|
|
||||||
std::set<int> m_ids;
|
|
||||||
|
|
||||||
void BuildNode(Node* node)
|
void BuildNode(Node* node)
|
||||||
{
|
{
|
||||||
for (auto& input : node->Inputs)
|
for (auto& input : node->Inputs)
|
||||||
|
|
@ -91,12 +89,12 @@ private:
|
||||||
|
|
||||||
template<class NodeType>
|
template<class NodeType>
|
||||||
struct Factory {
|
struct Factory {
|
||||||
static std::shared_ptr<BaseNode> create_func(const std::string &title, IStoryManager &proj) {
|
static std::shared_ptr<BaseNodeWidget> create_func(const std::string &type, IStoryManager &proj) {
|
||||||
return std::make_shared<NodeType>(title, proj);
|
return std::make_shared<NodeType>(type, proj);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<BaseNode> (*GenericCreator)(const std::string &title, IStoryManager &proj);
|
typedef std::shared_ptr<BaseNodeWidget> (*GenericCreator)(const std::string &type, IStoryManager &proj);
|
||||||
typedef std::map<std::string, GenericCreator> Registry;
|
typedef std::map<std::string, GenericCreator> Registry;
|
||||||
Registry m_registry;
|
Registry m_registry;
|
||||||
|
|
||||||
|
|
@ -105,20 +103,23 @@ private:
|
||||||
m_registry.insert(typename Registry::value_type(key, Factory<Derived>::create_func));
|
m_registry.insert(typename Registry::value_type(key, Factory<Derived>::create_func));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<BaseNode> createNode(const std::string& key, const std::string &title, IStoryManager &proj) {
|
std::shared_ptr<BaseNodeWidget> createNode(const std::string& key, IStoryManager &proj) {
|
||||||
typename Registry::const_iterator i = m_registry.find(key);
|
typename Registry::const_iterator i = m_registry.find(key);
|
||||||
if (i == m_registry.end()) {
|
if (i == m_registry.end()) {
|
||||||
throw std::invalid_argument(std::string(__PRETTY_FUNCTION__) +
|
throw std::invalid_argument(std::string(__PRETTY_FUNCTION__) +
|
||||||
": key not registered");
|
": key not registered");
|
||||||
}
|
}
|
||||||
else return i->second(title, proj);
|
else
|
||||||
|
{
|
||||||
|
return i->second(key, proj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadNode(const nlohmann::json &nodeJson);
|
|
||||||
ed::PinId GetInputPin(unsigned long modelNodeId, int pinIndex);
|
ed::PinId GetInputPin(const std::string &modelNodeId, int pinIndex);
|
||||||
ed::PinId GetOutputPin(unsigned long modelNodeId, int pinIndex);
|
ed::PinId GetOutputPin(const std::string &modelNodeId, int pinIndex);
|
||||||
uint32_t FindFirstNode() const;
|
std::string FindFirstNode() const;
|
||||||
int GenerateNodeId();
|
std::string GenerateNodeId();
|
||||||
void CreateLink(const Connection &model, ed::PinId inId, ed::PinId outId);
|
void CreateLink(const Connection &model, ed::PinId inId, ed::PinId outId);
|
||||||
Connection LinkToModel(ed::PinId InputId, ed::PinId OutputId);
|
Connection LinkToModel(ed::PinId InputId, ed::PinId OutputId);
|
||||||
};
|
};
|
||||||
70
story-editor/src/node_engine/base_node.cpp
Normal file
70
story-editor/src/node_engine/base_node.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
#include "base_node.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
BaseNode::BaseNode(const std::string &type)
|
||||||
|
{
|
||||||
|
m_type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseNode::FromJson(const nlohmann::json &j)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_uuid = j["uuid"].get<std::string>();
|
||||||
|
m_internal_data = j["internal-data"];
|
||||||
|
m_type = j["type"].get<std::string>();
|
||||||
|
m_title = j.value("title", "Default node");
|
||||||
|
nlohmann::json posJson = j["position"];
|
||||||
|
SetPosition(posJson["x"].get<double>(), posJson["y"].get<double>());
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cout << "ERROR: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
nlohmann::json BaseNode::ToJson() const
|
||||||
|
{
|
||||||
|
nlohmann::json node;
|
||||||
|
node["uuid"] = GetId();
|
||||||
|
node["type"] = GetType();
|
||||||
|
|
||||||
|
nlohmann::json position;
|
||||||
|
position["x"] = GetX();
|
||||||
|
position["y"] = GetY();
|
||||||
|
|
||||||
|
node["position"] = position;
|
||||||
|
node["internal-data"] = m_internal_data;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BaseNode::SetInternalData(const nlohmann::json &j)
|
||||||
|
{
|
||||||
|
m_internal_data = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json BaseNode::GetInternalData() const
|
||||||
|
{
|
||||||
|
return m_internal_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseNode::SetPosition(float x, float y)
|
||||||
|
{
|
||||||
|
m_pos.x = x;
|
||||||
|
m_pos.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BaseNode::GetX() const
|
||||||
|
{
|
||||||
|
return m_pos.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BaseNode::GetY() const
|
||||||
|
{
|
||||||
|
return m_pos.y;
|
||||||
|
}
|
||||||
55
story-editor/src/node_engine/base_node.h
Normal file
55
story-editor/src/node_engine/base_node.h
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include "json.hpp"
|
||||||
|
#include <random>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "json.hpp"
|
||||||
|
|
||||||
|
class BaseNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct NodePosition
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
};
|
||||||
|
|
||||||
|
BaseNode(const std::string &type);
|
||||||
|
|
||||||
|
void SetPosition(float x, float y);
|
||||||
|
|
||||||
|
// make this virtual so that graphical node override the behavior
|
||||||
|
virtual float GetX() const;
|
||||||
|
virtual float GetY() const;
|
||||||
|
|
||||||
|
std::string GetType() const
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetId(const std::string &id) { m_uuid = id; }
|
||||||
|
std::string GetId() const { return m_uuid; }
|
||||||
|
|
||||||
|
void SeTitle(const std::string &title) { m_title = title; }
|
||||||
|
std::string GetTitle() const { return m_title; }
|
||||||
|
|
||||||
|
void FromJson(const nlohmann::json &);
|
||||||
|
nlohmann::json ToJson() const;
|
||||||
|
|
||||||
|
|
||||||
|
void SetInternalData(const nlohmann::json &j);
|
||||||
|
nlohmann::json GetInternalData() const;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_title{"Default title"};
|
||||||
|
std::string m_type;
|
||||||
|
std::string m_uuid;
|
||||||
|
NodePosition m_pos;
|
||||||
|
|
||||||
|
nlohmann::json m_internal_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -2,16 +2,17 @@
|
||||||
|
|
||||||
void to_json(nlohmann::json &j, const Connection &p) {
|
void to_json(nlohmann::json &j, const Connection &p) {
|
||||||
j = nlohmann::json{
|
j = nlohmann::json{
|
||||||
{"outNodeId", static_cast<int64_t>(p.outNodeId)},
|
{"outNodeId", p.outNodeId },
|
||||||
{"outPortIndex", static_cast<int64_t>(p.outPortIndex)},
|
{"outPortIndex", static_cast<int64_t>(p.outPortIndex)},
|
||||||
{"inNodeId", static_cast<int64_t>(p.inNodeId)},
|
{"inNodeId", p.inNodeId},
|
||||||
{"inPortIndex", static_cast<int64_t>(p.inPortIndex)},
|
{"inPortIndex", static_cast<int64_t>(p.inPortIndex)},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void from_json(const nlohmann::json &j, Connection &p) {
|
void from_json(const nlohmann::json &j, Connection &p) {
|
||||||
j.at("outNodeId").get_to(p.outNodeId);
|
|
||||||
j.at("outPortIndex").get_to(p.outPortIndex);
|
p.outNodeId = j["outNodeId"].get<std::string>();
|
||||||
j.at("inNodeId").get_to(p.inNodeId);
|
p.inNodeId = j["inNodeId"].get<std::string>();
|
||||||
j.at("inPortIndex").get_to(p.inPortIndex);
|
p.outPortIndex = j["outPortIndex"].get<int>();
|
||||||
|
p.inPortIndex = j["inPortIndex"].get<int>();
|
||||||
}
|
}
|
||||||
|
|
@ -6,9 +6,7 @@
|
||||||
struct Connection
|
struct Connection
|
||||||
{
|
{
|
||||||
Connection()
|
Connection()
|
||||||
: outNodeId(0)
|
: outPortIndex(0)
|
||||||
, outPortIndex(0)
|
|
||||||
, inNodeId(0)
|
|
||||||
, inPortIndex(0)
|
, inPortIndex(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -18,9 +16,9 @@ struct Connection
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int outNodeId{0};
|
std::string outNodeId;
|
||||||
unsigned int outPortIndex{0};
|
unsigned int outPortIndex{0};
|
||||||
unsigned int inNodeId{0};
|
std::string inNodeId;
|
||||||
unsigned int inPortIndex{0};
|
unsigned int inPortIndex{0};
|
||||||
|
|
||||||
Connection(const Connection &other){
|
Connection(const Connection &other){
|
||||||
|
|
@ -25,14 +25,14 @@ void PropertiesWindow::Draw()
|
||||||
if (m_selectedNode)
|
if (m_selectedNode)
|
||||||
{
|
{
|
||||||
static char buf1[32] = ""; ImGui::InputText("Title", buf1, 32);
|
static char buf1[32] = ""; ImGui::InputText("Title", buf1, 32);
|
||||||
ImGui::Text("Node ID: %lu", m_selectedNode->GetId());
|
ImGui::Text("Node ID: %s", m_selectedNode->GetId().data());
|
||||||
m_selectedNode->DrawProperties();
|
m_selectedNode->DrawProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowBase::EndDraw();
|
WindowBase::EndDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropertiesWindow::SetSelectedNode(std::shared_ptr<BaseNode> node)
|
void PropertiesWindow::SetSelectedNode(std::shared_ptr<BaseNodeWidget> node)
|
||||||
{
|
{
|
||||||
m_selectedNode = node;
|
m_selectedNode = node;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include "window_base.h"
|
#include "window_base.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
|
||||||
#include "base_node.h"
|
#include "base_node_widget.h"
|
||||||
|
|
||||||
class PropertiesWindow : public WindowBase
|
class PropertiesWindow : public WindowBase
|
||||||
{
|
{
|
||||||
|
|
@ -13,10 +13,10 @@ public:
|
||||||
void Initialize();
|
void Initialize();
|
||||||
virtual void Draw() override;
|
virtual void Draw() override;
|
||||||
|
|
||||||
void SetSelectedNode(std::shared_ptr<BaseNode> node);
|
void SetSelectedNode(std::shared_ptr<BaseNodeWidget> node);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<BaseNode> m_selectedNode;
|
std::shared_ptr<BaseNodeWidget> m_selectedNode;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue