Documentation and Updated LICENSE
This commit is contained in:
parent
80b428ad14
commit
d6a7d43d24
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,4 +9,5 @@ install_manifest.txt
|
|||||||
compile_commands.json
|
compile_commands.json
|
||||||
CTestTestfile.cmake
|
CTestTestfile.cmake
|
||||||
_deps
|
_deps
|
||||||
/Build/
|
Build
|
||||||
|
.idea
|
||||||
|
@ -33,6 +33,15 @@ endif()
|
|||||||
include_directories(Include)
|
include_directories(Include)
|
||||||
include_directories(External)
|
include_directories(External)
|
||||||
|
|
||||||
|
# Configure ImGui
|
||||||
|
set(IMGUI_BACKEND_SDL2 ON)
|
||||||
|
set(IMGUI_BACKEND_OPENGL ON)
|
||||||
|
set(IMGUI_STDLIB ON)
|
||||||
|
set(IMGUI_FREETYPE ON)
|
||||||
|
|
||||||
|
# Add ImGui and any extensions
|
||||||
|
add_subdirectory(External/imgui-docking)
|
||||||
|
|
||||||
add_executable(OpenShaderDesigner
|
add_executable(OpenShaderDesigner
|
||||||
Source/Entry.cpp
|
Source/Entry.cpp
|
||||||
|
|
||||||
@ -54,24 +63,42 @@ add_executable(OpenShaderDesigner
|
|||||||
|
|
||||||
# Nodes
|
# Nodes
|
||||||
Source/Graph/Nodes/Math.cpp
|
Source/Graph/Nodes/Math.cpp
|
||||||
|
|
||||||
# ImGui
|
|
||||||
External/imgui-docking/imgui_demo.cpp
|
|
||||||
External/imgui-docking/imgui_draw.cpp
|
|
||||||
External/imgui-docking/imgui_tables.cpp
|
|
||||||
External/imgui-docking/imgui.cpp
|
|
||||||
External/imgui-docking/imgui_widgets.cpp
|
|
||||||
External/imgui-docking/backends/imgui_impl_sdl2.cpp
|
|
||||||
External/imgui-docking/backends/imgui_impl_opengl3.cpp
|
|
||||||
External/imgui-docking/misc/cpp/imgui_stdlib.cpp
|
|
||||||
External/imgui-docking/misc/freetype/imgui_freetype.cpp
|
|
||||||
Include/OpenGL/BufferObject.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
target_link_libraries(OpenShaderDesigner PRIVATE
|
target_link_libraries(OpenShaderDesigner PRIVATE
|
||||||
Freetype::Freetype
|
Freetype::Freetype
|
||||||
GLEW::GLEW
|
GLEW::GLEW
|
||||||
OpenGL::GL
|
OpenGL::GL
|
||||||
${SDL2_LIBRARIES}
|
${SDL2_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# DOXYGEN ==============================================================================================================
|
||||||
|
# https://vicrucann.github.io/tutorials/quick-cmake-doxygen/
|
||||||
|
|
||||||
|
find_package(Doxygen)
|
||||||
|
|
||||||
|
if(DOXYGEN_FOUND)
|
||||||
|
set(DOXYGEN_CONFIG_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
|
||||||
|
set(DOXYGEN_CONFIG_OUT ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile)
|
||||||
|
|
||||||
|
configure_file(${DOXYGEN_CONFIG_IN} ${DOXYGEN_CONFIG_OUT} @ONLY)
|
||||||
|
message("Doxygen Build Started.")
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
add_custom_target(doxygen ALL
|
||||||
|
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_CONFIG_OUT}
|
||||||
|
COMMAND start firefox "${CMAKE_CURRENT_SOURCE_DIR}/Documentation/html/index.html"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
COMMENT "Generating Doxygen Documentation"
|
||||||
|
VERBATIM)
|
||||||
|
else()
|
||||||
|
add_custom_target(doxygen ALL
|
||||||
|
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_CONFIG_OUT}
|
||||||
|
COMMAND firefox "${CMAKE_CURRENT_SOURCE_DIR}/Documentation/html/index.html"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
COMMENT "Generating Doxygen Documentation"
|
||||||
|
VERBATIM)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message("Doxygen not found.")
|
||||||
|
endif()
|
@ -95,8 +95,8 @@
|
|||||||
|
|
||||||
// SDL
|
// SDL
|
||||||
// (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended)
|
// (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended)
|
||||||
#include <SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <SDL_syswm.h>
|
#include <SDL2/SDL_syswm.h>
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
#include <TargetConditionals.h>
|
#include <TargetConditionals.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,15 +16,36 @@
|
|||||||
#ifndef MATH_H
|
#ifndef MATH_H
|
||||||
#define MATH_H
|
#define MATH_H
|
||||||
|
|
||||||
|
#include <glm/vec4.hpp>
|
||||||
#include <Graph/ShaderGraph.h>
|
#include <Graph/ShaderGraph.h>
|
||||||
|
#include <Utility/Any.h>
|
||||||
|
|
||||||
namespace OpenShaderDesigner
|
namespace OpenShaderDesigner::Nodes::Math
|
||||||
{
|
{
|
||||||
|
inline static constexpr ImColor HeaderColor = ImColor(0x92, 0x16, 0x16);
|
||||||
|
|
||||||
|
struct Constant : public Node
|
||||||
|
{
|
||||||
|
using ValueType = Any<int, unsigned int, float, glm::vec4>;
|
||||||
|
|
||||||
|
Constant(ShaderGraph& graph, ImVec2 pos);
|
||||||
|
virtual ~Constant() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] Node* Copy(ShaderGraph& graph) const override;
|
||||||
|
void Inspect() override;
|
||||||
|
|
||||||
|
ValueType Value;
|
||||||
|
};
|
||||||
|
|
||||||
|
RegisterNode("Math/Constant", Constant);
|
||||||
|
|
||||||
struct Add : public Node
|
struct Add : public Node
|
||||||
{
|
{
|
||||||
Add(ShaderGraph& graph, ImVec2 pos);
|
Add(ShaderGraph& graph, ImVec2 pos);
|
||||||
|
virtual ~Add() = default;
|
||||||
|
|
||||||
[[nodiscard]] Node* Copy(ShaderGraph& graph) const override;
|
[[nodiscard]] Node* Copy(ShaderGraph& graph) const override;
|
||||||
|
void Inspect() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
RegisterNode("Math/Add", Add);
|
RegisterNode("Math/Add", Add);
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
#include <Utility/DirectedGraph.h>
|
#include <Utility/DirectedGraph.h>
|
||||||
#include <Utility/Optional.h>
|
#include <Utility/Optional.h>
|
||||||
@ -37,6 +38,26 @@ namespace OpenShaderDesigner
|
|||||||
using PinId = uint16_t;
|
using PinId = uint16_t;
|
||||||
using NodeId = uint32_t;
|
using NodeId = uint32_t;
|
||||||
|
|
||||||
|
struct PinPtr
|
||||||
|
{
|
||||||
|
struct Hash
|
||||||
|
{
|
||||||
|
size_t operator()(const PinPtr& p) const
|
||||||
|
{
|
||||||
|
return p.hash();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NodeId Node;
|
||||||
|
PinId Pin;
|
||||||
|
bool Input;
|
||||||
|
|
||||||
|
size_t hash() const { return (Input ? 0 : 0x8000000) | static_cast<size_t>(Node) << 32 | static_cast<size_t>(Pin & 0x7FFFFFFF); }
|
||||||
|
|
||||||
|
bool operator<(const PinPtr& o) const { return hash() < o.hash(); }
|
||||||
|
bool operator==(const PinPtr& o) const { return hash() == o.hash(); }
|
||||||
|
};
|
||||||
|
|
||||||
struct Pin
|
struct Pin
|
||||||
{
|
{
|
||||||
enum PinType
|
enum PinType
|
||||||
@ -45,9 +66,8 @@ namespace OpenShaderDesigner
|
|||||||
, UINT
|
, UINT
|
||||||
, FLOAT
|
, FLOAT
|
||||||
, VECTOR
|
, VECTOR
|
||||||
, TEXTURE
|
|
||||||
, ANY
|
|
||||||
|
|
||||||
|
, ANY
|
||||||
, COUNT
|
, COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,10 +82,17 @@ namespace OpenShaderDesigner
|
|||||||
, ImColor(0x8C, 0xC0, 0x8C)
|
, ImColor(0x8C, 0xC0, 0x8C)
|
||||||
, ImColor(0x37, 0x95, 0x85)
|
, ImColor(0x37, 0x95, 0x85)
|
||||||
, ImColor(0xE3, 0x7D, 0xDC)
|
, ImColor(0xE3, 0x7D, 0xDC)
|
||||||
, ImColor(0xD2, 0x6E, 0x46)
|
// , ImColor(0xD2, 0x6E, 0x46)
|
||||||
, ImColor(0xD2, 0xD5, 0xD3)
|
, ImColor(0xD2, 0xD5, 0xD3)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline const static std::string TypeNames[COUNT] = {
|
||||||
|
"Int"
|
||||||
|
, "Unsigned Int"
|
||||||
|
, "Float"
|
||||||
|
, "Vector"
|
||||||
|
};
|
||||||
|
|
||||||
std::string Name;
|
std::string Name;
|
||||||
PinType Type;
|
PinType Type;
|
||||||
PinDirection Direction;
|
PinDirection Direction;
|
||||||
@ -73,6 +100,7 @@ namespace OpenShaderDesigner
|
|||||||
|
|
||||||
struct Node
|
struct Node
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
ImVec2 Position = { 0, 0 };
|
ImVec2 Position = { 0, 0 };
|
||||||
|
|
||||||
struct
|
struct
|
||||||
@ -91,7 +119,7 @@ namespace OpenShaderDesigner
|
|||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
ImVec2 Size;
|
ImVec2 Size;
|
||||||
bool Const;
|
bool Const;
|
||||||
} Info;
|
} Info;
|
||||||
|
|
||||||
Node(
|
Node(
|
||||||
@ -100,8 +128,10 @@ namespace OpenShaderDesigner
|
|||||||
, const std::vector<Pin>& inputs, bool dyn_inputs
|
, const std::vector<Pin>& inputs, bool dyn_inputs
|
||||||
, const std::vector<Pin>& outputs
|
, const std::vector<Pin>& outputs
|
||||||
, bool constant = false);
|
, bool constant = false);
|
||||||
|
~Node() = default;
|
||||||
|
|
||||||
virtual Node* Copy(ShaderGraph& graph) const = 0;
|
virtual Node* Copy(ShaderGraph& graph) const = 0;
|
||||||
|
virtual void Inspect() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShaderGraph
|
class ShaderGraph
|
||||||
@ -109,25 +139,6 @@ namespace OpenShaderDesigner
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
friend Node;
|
friend Node;
|
||||||
struct PinPtr
|
|
||||||
{
|
|
||||||
struct Hash
|
|
||||||
{
|
|
||||||
size_t operator()(const PinPtr& p) const
|
|
||||||
{
|
|
||||||
return p.hash();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
NodeId Node;
|
|
||||||
PinId Pin;
|
|
||||||
bool Input;
|
|
||||||
|
|
||||||
size_t hash() const { return (Input ? 0 : 0x8000000) | static_cast<size_t>(Node) << 32 | static_cast<size_t>(Pin & 0x7FFFFFFF); }
|
|
||||||
|
|
||||||
bool operator<(const PinPtr& o) const { return hash() < o.hash(); }
|
|
||||||
bool operator==(const PinPtr& o) const { return hash() == o.hash(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
using Connection = std::pair<const PinPtr, PinPtr>;
|
using Connection = std::pair<const PinPtr, PinPtr>;
|
||||||
using ConnectionMap = std::unordered_multimap<PinPtr, PinPtr, PinPtr::Hash>;
|
using ConnectionMap = std::unordered_multimap<PinPtr, PinPtr, PinPtr::Hash>;
|
||||||
@ -145,6 +156,20 @@ namespace OpenShaderDesigner
|
|||||||
ConstructorPtr Constructor;
|
ConstructorPtr Constructor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GraphState
|
||||||
|
{
|
||||||
|
ShaderGraph& Parent;
|
||||||
|
std::vector<Node*> Nodes;
|
||||||
|
std::unordered_set<PinId> Erased;
|
||||||
|
ConnectionMap Connections;
|
||||||
|
|
||||||
|
GraphState(ShaderGraph& parent);
|
||||||
|
GraphState(const GraphState& other);
|
||||||
|
~GraphState();
|
||||||
|
|
||||||
|
GraphState& operator=(const GraphState& other);
|
||||||
|
};
|
||||||
|
|
||||||
using ContextMenuHierarchy = DirectedGraph<ContextMenuItem>;
|
using ContextMenuHierarchy = DirectedGraph<ContextMenuItem>;
|
||||||
using ContextID = ContextMenuHierarchy::Node;
|
using ContextID = ContextMenuHierarchy::Node;
|
||||||
inline static ContextMenuHierarchy ContextMenu;
|
inline static ContextMenuHierarchy ContextMenu;
|
||||||
@ -178,12 +203,19 @@ namespace OpenShaderDesigner
|
|||||||
void Paste(const ImVec2& location);
|
void Paste(const ImVec2& location);
|
||||||
void EraseSelection();
|
void EraseSelection();
|
||||||
|
|
||||||
|
// History Functionality
|
||||||
|
void PushState();
|
||||||
|
void PopState();
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
float BezierOffset(const ImVec2& out, const ImVec2& in);
|
float BezierOffset(const ImVec2& out, const ImVec2& in);
|
||||||
bool AABB(const ImVec2& a0, const ImVec2& a1, const ImVec2& b0, const ImVec2& b1);
|
bool AABB(const ImVec2& a0, const ImVec2& a1, const ImVec2& b0, const ImVec2& b1);
|
||||||
|
|
||||||
ImVec2 GridToScreen(const ImVec2& position);
|
ImVec2 GridToScreen(const ImVec2& position);
|
||||||
ImVec2 ScreenToGrid(const ImVec2& position);
|
ImVec2 ScreenToGrid(const ImVec2& position);
|
||||||
|
ImVec2 SnapToGrid(const ImVec2& position);
|
||||||
|
|
||||||
|
Pin& GetPin(const PinPtr& ptr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ShaderGraph();
|
ShaderGraph();
|
||||||
@ -194,12 +226,9 @@ namespace OpenShaderDesigner
|
|||||||
|
|
||||||
static void Register(const std::filesystem::path& path, ConstructorPtr constructor);
|
static void Register(const std::filesystem::path& path, ConstructorPtr constructor);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Node*> Nodes;
|
GraphState State;
|
||||||
std::unordered_set<PinId> Erased;
|
std::stack<GraphState> History;
|
||||||
ConnectionMap Connections;
|
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@ -279,6 +308,22 @@ namespace OpenShaderDesigner
|
|||||||
|
|
||||||
bool Focused;
|
bool Focused;
|
||||||
ImVec2 ContextMenuPosition;
|
ImVec2 ContextMenuPosition;
|
||||||
|
|
||||||
|
friend class Inspector;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Inspector
|
||||||
|
: public EditorWindow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Inspector();
|
||||||
|
|
||||||
|
void DrawWindow() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ShaderGraph* Graph;
|
||||||
|
|
||||||
|
friend class ShaderGraph;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
LICENSE
2
LICENSE
@ -186,7 +186,7 @@
|
|||||||
same "printed page" as the copyright notice for easier
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
Copyright 2024 Medusa Slockbower
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -56,8 +56,12 @@ Window::Window(const Configuration& config)
|
|||||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 16);
|
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 16);
|
||||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 16);
|
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 16);
|
||||||
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 16);
|
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 16);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_FLOATBUFFERS, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
|
||||||
|
|
||||||
Context = SDL_GL_CreateContext(Handle);
|
Context = SDL_GL_CreateContext(Handle);
|
||||||
|
|
||||||
if(Context == nullptr)
|
if(Context == nullptr)
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <Core/Console.h>
|
#include <Core/Console.h>
|
||||||
#include <Editor/EditorSystem.h>
|
#include <Editor/EditorSystem.h>
|
||||||
#include <Core/Engine.h>
|
#include <Core/Engine.h>
|
||||||
|
#include <imgui-docking/imgui_internal.h>
|
||||||
|
|
||||||
#include <imgui-docking/backends/imgui_impl_sdl2.h>
|
#include <imgui-docking/backends/imgui_impl_sdl2.h>
|
||||||
#include <imgui-docking/backends/imgui_impl_opengl3.h>
|
#include <imgui-docking/backends/imgui_impl_opengl3.h>
|
||||||
@ -117,12 +118,12 @@ void EditorSystem::Initialize()
|
|||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
io.Fonts->AddFontFromFileTTF("./Assets/Fonts/FiraMono-Regular.ttf", 20.0f);
|
|
||||||
static ImWchar ranges[] = { 0x1, static_cast<ImWchar>(0x1FFFF), 0 };
|
static ImWchar ranges[] = { 0x1, static_cast<ImWchar>(0x1FFFF), 0 };
|
||||||
static ImFontConfig cfg;
|
static ImFontConfig cfg;
|
||||||
cfg.OversampleH = cfg.OversampleV = 1;
|
cfg.OversampleH = cfg.OversampleV = 2;
|
||||||
cfg.MergeMode = true;
|
cfg.MergeMode = true;
|
||||||
cfg.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_LoadColor;
|
cfg.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_LoadColor;
|
||||||
|
io.Fonts->AddFontFromFileTTF("./Assets/Fonts/FiraMono-Regular.ttf", 20.0f);
|
||||||
io.Fonts->AddFontFromFileTTF("./Assets/Fonts/remixicon.ttf", 18.0f, &cfg, ranges);
|
io.Fonts->AddFontFromFileTTF("./Assets/Fonts/remixicon.ttf", 18.0f, &cfg, ranges);
|
||||||
|
|
||||||
|
|
||||||
@ -139,8 +140,8 @@ void EditorSystem::Initialize()
|
|||||||
void EditorSystem::Draw()
|
void EditorSystem::Draw()
|
||||||
{
|
{
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
|
||||||
ImGui_ImplSDL2_NewFrame();
|
ImGui_ImplSDL2_NewFrame();
|
||||||
|
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode);
|
ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode);
|
||||||
|
|
||||||
|
@ -14,13 +14,74 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
#include <Graph/Nodes/Math.h>
|
#include <Graph/Nodes/Math.h>
|
||||||
|
#include <imgui-extras/imgui_extras.h>
|
||||||
|
|
||||||
using namespace OpenShaderDesigner;
|
using namespace OpenShaderDesigner;
|
||||||
|
using namespace OpenShaderDesigner::Nodes::Math;
|
||||||
|
|
||||||
|
Constant::Constant(ShaderGraph& graph, ImVec2 pos)
|
||||||
|
: Node(
|
||||||
|
graph, pos
|
||||||
|
, "Constant", HeaderColor
|
||||||
|
, { }, false
|
||||||
|
, { { "Out", Pin::FLOAT, Pin::OUTPUT } }
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* Constant::Copy(ShaderGraph& graph) const
|
||||||
|
{
|
||||||
|
return new Constant(graph, Position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Constant::Inspect()
|
||||||
|
{
|
||||||
|
Pin::PinType& Type = IO.Outputs[0].Type;
|
||||||
|
|
||||||
|
if(ImGui::BeginCombo("Type", Pin::TypeNames[Type].c_str()))
|
||||||
|
{
|
||||||
|
for(int i = 0; i < Pin::ANY; ++i)
|
||||||
|
{
|
||||||
|
Pin::PinType t = static_cast<Pin::PinType>(i);
|
||||||
|
|
||||||
|
if(ImGui::Selectable(Pin::TypeNames[t].c_str(), t == Type))
|
||||||
|
{
|
||||||
|
Type = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec4& v = Value;
|
||||||
|
|
||||||
|
switch(Type)
|
||||||
|
{
|
||||||
|
case Pin::INT:
|
||||||
|
ImGui::InputInt("Value", Value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Pin::UINT:
|
||||||
|
ImGui::InputUInt("Value", Value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Pin::FLOAT:
|
||||||
|
ImGui::InputFloat("Value", Value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Pin::VECTOR:
|
||||||
|
ImGui::ColorEdit4("Value", &v.x);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Add::Add(ShaderGraph& graph, ImVec2 pos)
|
Add::Add(ShaderGraph& graph, ImVec2 pos)
|
||||||
: Node(
|
: Node(
|
||||||
graph, pos
|
graph, pos
|
||||||
, "Add", ImColor(0x92, 0x16, 0x16)
|
, "Add", HeaderColor
|
||||||
, { { "A", Pin::ANY, Pin::INPUT }, { "B", Pin::ANY, Pin::INPUT } }, true
|
, { { "A", Pin::ANY, Pin::INPUT }, { "B", Pin::ANY, Pin::INPUT } }, true
|
||||||
, { { "Out", Pin::ANY, Pin::OUTPUT } }
|
, { { "Out", Pin::ANY, Pin::OUTPUT } }
|
||||||
)
|
)
|
||||||
@ -30,3 +91,8 @@ Node* Add::Copy(ShaderGraph& graph) const
|
|||||||
{
|
{
|
||||||
return new Add(graph, Position);
|
return new Add(graph, Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Add::Inspect()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <Core/Engine.h>
|
#include <Core/Engine.h>
|
||||||
#include <Core/Console.h>
|
#include <Core/Console.h>
|
||||||
|
#include <Editor/EditorSystem.h>
|
||||||
|
|
||||||
#include <glm/common.hpp>
|
#include <glm/common.hpp>
|
||||||
#include <Graph/ShaderGraph.h>
|
#include <Graph/ShaderGraph.h>
|
||||||
@ -31,6 +32,56 @@ ImColor operator*(const ImColor& c, float f)
|
|||||||
return ImVec4(c.Value.x * f, c.Value.y * f, c.Value.z * f, c.Value.w);
|
return ImVec4(c.Value.x * f, c.Value.y * f, c.Value.z * f, c.Value.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShaderGraph::GraphState::GraphState(ShaderGraph& parent)
|
||||||
|
: Parent(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderGraph::GraphState::GraphState(const GraphState& other)
|
||||||
|
: Parent(other.Parent)
|
||||||
|
, Nodes(other.Nodes.size(), nullptr)
|
||||||
|
, Connections(other.Connections)
|
||||||
|
, Erased(other.Erased)
|
||||||
|
{
|
||||||
|
NodeId id = 0;
|
||||||
|
for(const Node* node : other.Nodes)
|
||||||
|
{
|
||||||
|
if(node) Nodes[id] = node->Copy(Parent);
|
||||||
|
++id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderGraph::GraphState::~GraphState()
|
||||||
|
{
|
||||||
|
for(Node* node : Nodes)
|
||||||
|
{
|
||||||
|
if(node) delete node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderGraph::GraphState& ShaderGraph::GraphState::operator=(const GraphState& other)
|
||||||
|
{
|
||||||
|
for(Node* node : Nodes)
|
||||||
|
{
|
||||||
|
if(node) delete node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Nodes.clear();
|
||||||
|
Nodes.resize(other.Nodes.size(), nullptr);
|
||||||
|
|
||||||
|
NodeId id = 0;
|
||||||
|
for(const Node* node : other.Nodes)
|
||||||
|
{
|
||||||
|
if(node) Nodes[id] = node->Copy(Parent);
|
||||||
|
++id;
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections = other.Connections;
|
||||||
|
Erased = other.Erased;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
float ShaderGraph::CalculateWidth(Node& node)
|
float ShaderGraph::CalculateWidth(Node& node)
|
||||||
{
|
{
|
||||||
const float GridSize = Style.FontSize + Style.Grid.Lines.Padding;
|
const float GridSize = Style.FontSize + Style.Grid.Lines.Padding;
|
||||||
@ -50,7 +101,7 @@ float ShaderGraph::CalculateWidth(Node& node)
|
|||||||
OutputWidth = glm::max(OutputWidth, HeaderHeight + ImGui::CalcTextSize(pin.Name.c_str()).x);
|
OutputWidth = glm::max(OutputWidth, HeaderHeight + ImGui::CalcTextSize(pin.Name.c_str()).x);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Width = glm::max(InputWidth, HeaderWidth) + OutputWidth + 1 * HeaderHeight;
|
float Width = glm::max(InputWidth + OutputWidth, HeaderWidth) + HeaderHeight;
|
||||||
Width += GridSize - std::fmod(1.0f + Style.Grid.Lines.Padding + Width, GridSize);
|
Width += GridSize - std::fmod(1.0f + Style.Grid.Lines.Padding + Width, GridSize);
|
||||||
|
|
||||||
return Width;
|
return Width;
|
||||||
@ -90,6 +141,7 @@ Node::Node(
|
|||||||
|
|
||||||
ShaderGraph::ShaderGraph()
|
ShaderGraph::ShaderGraph()
|
||||||
: EditorWindow("\uED46 Shader Graph", 0)
|
: EditorWindow("\uED46 Shader Graph", 0)
|
||||||
|
, State(*this)
|
||||||
, Style
|
, Style
|
||||||
{
|
{
|
||||||
.Grid
|
.Grid
|
||||||
@ -166,6 +218,8 @@ void ShaderGraph::OnOpen()
|
|||||||
{
|
{
|
||||||
Mouse.Location = ImGui::GetMousePos();
|
Mouse.Location = ImGui::GetMousePos();
|
||||||
Camera.Scroll = Camera.Zoom = 1.0f;
|
Camera.Scroll = Camera.Zoom = 1.0f;
|
||||||
|
|
||||||
|
EditorSystem::Open<Inspector>()->Graph = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderGraph::DrawWindow()
|
void ShaderGraph::DrawWindow()
|
||||||
@ -175,8 +229,9 @@ void ShaderGraph::DrawWindow()
|
|||||||
|
|
||||||
DrawGrid();
|
DrawGrid();
|
||||||
|
|
||||||
|
|
||||||
NodeId uid = 0;
|
NodeId uid = 0;
|
||||||
for(Node* node : Nodes)
|
for(Node* node : State.Nodes)
|
||||||
{
|
{
|
||||||
if(node == nullptr) { ++uid; continue; }
|
if(node == nullptr) { ++uid; continue; }
|
||||||
DrawNode(*node, uid++);
|
DrawNode(*node, uid++);
|
||||||
@ -344,26 +399,23 @@ void ShaderGraph::DrawNode(Node& node, NodeId id)
|
|||||||
ImDrawList& DrawList = *ImGui::GetWindowDrawList();
|
ImDrawList& DrawList = *ImGui::GetWindowDrawList();
|
||||||
|
|
||||||
// Draw Vars
|
// Draw Vars
|
||||||
const float HeaderHeight = Style.FontSize;
|
const float HeaderHeight = Style.FontSize;
|
||||||
const ImVec2 Padding = { Style.Grid.Lines.Padding, Style.Grid.Lines.Padding };
|
const ImVec2 Padding = { Style.Grid.Lines.Padding, Style.Grid.Lines.Padding };
|
||||||
const ImVec2 NodePos = node.Position + Padding;
|
const ImVec2 NodePos = node.Position + Padding;
|
||||||
const ImVec2 NodeRoot = GridToScreen(NodePos);
|
const ImVec2 NodeRoot = GridToScreen(NodePos);
|
||||||
const ImVec2 NodeEdge = GridToScreen(NodePos + node.Info.Size);
|
const ImVec2 NodeEdge = GridToScreen(NodePos + node.Info.Size);
|
||||||
const ImVec2 HeaderEdge = GridToScreen(NodePos + ImVec2(node.Info.Size.x, HeaderHeight));
|
const ImVec2 HeaderEdge = GridToScreen(NodePos + ImVec2(node.Info.Size.x, HeaderHeight));
|
||||||
const ImVec2 HeaderText = GridToScreen(NodePos + ImVec2(Style.Nodes.Rounding, 0) + Padding * 0.5f);
|
const ImVec2 HeaderText = GridToScreen(NodePos + ImVec2(Style.Nodes.Rounding, 0) + Padding * 0.5f);
|
||||||
const ImVec2 InputRoot = GridToScreen(NodePos + ImVec2(Style.Nodes.Pins.Padding, HeaderHeight));
|
const ImVec2 InputRoot = GridToScreen(NodePos + ImVec2(Style.Nodes.Pins.Padding, HeaderHeight));
|
||||||
const ImVec2 OutputRoot = GridToScreen(NodePos + ImVec2(node.Info.Size.x - HeaderHeight - Style.Nodes.Pins.Padding, HeaderHeight));
|
const ImVec2 OutputRoot = GridToScreen(NodePos + ImVec2(node.Info.Size.x - HeaderHeight - Style.Nodes.Pins.Padding, HeaderHeight));
|
||||||
|
const bool HasLock = Mouse.FocusedNode();
|
||||||
const bool HasLock = Mouse.FocusedNode();
|
const bool NodeHovered = ImGui::IsMouseHoveringRect(NodeRoot, NodeEdge);
|
||||||
const bool NodeHovered = ImGui::IsMouseHoveringRect(NodeRoot, NodeEdge);
|
const bool HeaderHovered = ImGui::IsMouseHoveringRect(NodeRoot, HeaderEdge);
|
||||||
const bool HeaderHovered = ImGui::IsMouseHoveringRect(NodeRoot, HeaderEdge);
|
const ImColor HeaderColor = node.Header.Color * (HeaderHovered || HasLock ? 1.2f : 1.0f) * (HasLock ? 0.8f : 1.0f);
|
||||||
const ImColor HeaderColor = node.Header.Color * (HeaderHovered || HasLock ? 1.2f : 1.0f) * (HasLock ? 0.8f : 1.0f);
|
const float Rounding = Style.Nodes.Rounding / Camera.Zoom;
|
||||||
|
const float PinSpacing = HeaderHeight / Camera.Zoom;
|
||||||
const float Rounding = Style.Nodes.Rounding / Camera.Zoom;
|
|
||||||
const float PinSpacing = HeaderHeight / Camera.Zoom;
|
|
||||||
const float BorderThickness = Style.Nodes.Border.Thickness / Camera.Zoom;
|
const float BorderThickness = Style.Nodes.Border.Thickness / Camera.Zoom;
|
||||||
|
|
||||||
const float GridSize = (Style.FontSize + Style.Grid.Lines.Padding);
|
|
||||||
const bool Ctrl = ImGui::IsKeyDown(ImGuiKey_ModCtrl);
|
const bool Ctrl = ImGui::IsKeyDown(ImGuiKey_ModCtrl);
|
||||||
const bool Shift = ImGui::IsKeyDown(ImGuiKey_ModShift);
|
const bool Shift = ImGui::IsKeyDown(ImGuiKey_ModShift);
|
||||||
|
|
||||||
@ -387,7 +439,7 @@ void ShaderGraph::DrawNode(Node& node, NodeId id)
|
|||||||
|
|
||||||
for(NodeId selected : Mouse.Selected)
|
for(NodeId selected : Mouse.Selected)
|
||||||
{
|
{
|
||||||
Mouse.Locks.emplace(selected, Mouse.Location - Nodes[selected]->Position);
|
Mouse.Locks.emplace(selected, Mouse.Location - State.Nodes[selected]->Position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -407,14 +459,16 @@ void ShaderGraph::DrawNode(Node& node, NodeId id)
|
|||||||
Mouse.Selected.insert(id);
|
Mouse.Selected.insert(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin selection
|
// Begin Dragging
|
||||||
if(Mouse.FocusedNode() && Mouse.Selected.contains(id) && !(Ctrl || Shift))
|
if(Mouse.FocusedNode() && Mouse.Selected.contains(id) && !(Ctrl || Shift))
|
||||||
{
|
{
|
||||||
|
if(Mouse.LocksDragged == false) PushState();
|
||||||
|
|
||||||
Mouse.LocksDragged = true;
|
Mouse.LocksDragged = true;
|
||||||
|
|
||||||
for(NodeId selected : Mouse.Selected)
|
for(NodeId selected : Mouse.Selected)
|
||||||
{
|
{
|
||||||
Mouse.Locks.emplace(selected, Mouse.Location - Nodes[selected]->Position);
|
Mouse.Locks.emplace(selected, Mouse.Location - State.Nodes[selected]->Position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,7 +549,7 @@ void ShaderGraph::DrawNode(Node& node, NodeId id)
|
|||||||
if(Mouse.Locks.contains(id))
|
if(Mouse.Locks.contains(id))
|
||||||
{
|
{
|
||||||
node.Position = Mouse.Location - Mouse.Locks[id];
|
node.Position = Mouse.Location - Mouse.Locks[id];
|
||||||
node.Position = ImFloor(node.Position / GridSize + ImVec2(0.5f, 0.5f)) * GridSize;
|
node.Position = SnapToGrid(node.Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Content =========================================================================================================
|
// Content =========================================================================================================
|
||||||
@ -511,7 +565,7 @@ void ShaderGraph::DrawNode(Node& node, NodeId id)
|
|||||||
DrawList.AddText(NULL, Style.FontSize / Camera.Zoom, HeaderText, Style.Nodes.Title, node.Header.Title.c_str());
|
DrawList.AddText(NULL, Style.FontSize / Camera.Zoom, HeaderText, Style.Nodes.Title, node.Header.Title.c_str());
|
||||||
DrawList.PopClipRect();
|
DrawList.PopClipRect();
|
||||||
|
|
||||||
DrawList.AddLine(InputRoot, HeaderEdge, Style.Nodes.Border.Color, BorderThickness);
|
DrawList.AddLine(ImVec2(NodeRoot.x, HeaderEdge.y), HeaderEdge, Style.Nodes.Border.Color, BorderThickness);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Border ==========================================================================================================
|
// Border ==========================================================================================================
|
||||||
@ -551,26 +605,45 @@ void ShaderGraph::DrawPin(NodeId node_id, Pin& pin, PinId pin_id, ImVec2 locatio
|
|||||||
const ImVec2 PinCenter = PinRoot + Offset;
|
const ImVec2 PinCenter = PinRoot + Offset;
|
||||||
const float PinPadding = Style.Nodes.Pins.Padding / Camera.Zoom;
|
const float PinPadding = Style.Nodes.Pins.Padding / Camera.Zoom;
|
||||||
const float BorderThickness = Style.Nodes.Pins.BorderThickness / Camera.Zoom;
|
const float BorderThickness = Style.Nodes.Pins.BorderThickness / Camera.Zoom;
|
||||||
const float PinRadius = (HeaderHeight - PinPadding - 2.0f * Style.Nodes.Pins.BorderThickness) * 0.5f;
|
const float PinRadius = (HeaderHeight - PinPadding - 2.0f * BorderThickness) * 0.5f;
|
||||||
const bool Hovered = ImGui::IsMouseHoveringRect(PinRoot, PinEdge);
|
const bool Hovered = ImGui::IsMouseHoveringRect(PinRoot, PinEdge);
|
||||||
|
const bool MouseDown = ImGui::IsMouseDown(ImGuiMouseButton_Left);
|
||||||
|
const bool MouseClicked = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
|
||||||
|
|
||||||
// Pin =============================================================================================================
|
// Pin =============================================================================================================
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
if(ImGui::IsMouseClicked(ImGuiMouseButton_Left) && Hovered && !Mouse.NewConnection() && !ImGui::IsKeyDown(ImGuiKey_ModAlt))
|
if(MouseClicked && Hovered && !Mouse.NewConnection() && !ImGui::IsKeyDown(ImGuiKey_ModAlt))
|
||||||
{
|
{
|
||||||
StartConnection({ node_id, pin_id, input });
|
StartConnection({ node_id, pin_id, input });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Circle
|
// Circle
|
||||||
PinPtr ptr = { node_id, pin_id, input };
|
PinPtr ptr = { node_id, pin_id, input };
|
||||||
auto it = Connections.find(ptr);
|
auto it = State.Connections.find(ptr);
|
||||||
if(Mouse.NewConnection() && *Mouse.NewConnection == ptr) DrawList.AddCircleFilled(PinCenter, PinRadius, Pin::Colors[pin.Type]);
|
const bool Connected = (it != State.Connections.end());
|
||||||
else if(!input && it != Connections.end()) DrawList.AddCircleFilled(PinCenter, PinRadius, Pin::Colors[pin.Type] * (Hovered ? 0.8f : 1.0f));
|
const bool NewConnectionRoot = Mouse.NewConnection() && *Mouse.NewConnection == ptr;
|
||||||
else if(it != Connections.end()) DrawList.AddCircleFilled(PinCenter, PinRadius, Pin::Colors[Nodes[it->second.Node]->IO.Outputs[it->second.Pin].Type] * (Hovered ? 0.8f : 1.0f));
|
const bool NewConnectionNext = Mouse.NewConnection() && *Mouse.NewConnection != ptr && Hovered;
|
||||||
else if(Hovered) DrawList.AddCircleFilled(PinCenter, PinRadius, Pin::Colors[pin.Type]);
|
const bool Pressed = Hovered && MouseDown;
|
||||||
else DrawList.AddCircleFilled(PinCenter, PinRadius, Style.Nodes.Pins.Background);
|
const bool Filled = Hovered || Connected || NewConnectionRoot || NewConnectionNext;
|
||||||
DrawList.AddCircle(PinCenter, PinRadius, Pin::Colors[pin.Type], 0, BorderThickness);
|
ImColor pinColor = Pin::Colors[pin.Type];
|
||||||
|
ImColor fillColor = Style.Nodes.Pins.Background;
|
||||||
|
|
||||||
|
if(input)
|
||||||
|
{
|
||||||
|
if(Connected) pinColor = Pin::Colors[GetPin(it->second).Type];
|
||||||
|
else if(NewConnectionNext)
|
||||||
|
{
|
||||||
|
Pin& Next = GetPin(*Mouse.NewConnection);
|
||||||
|
if(pin.Type == Next.Type || pin.Type == Pin::ANY) pinColor = Pin::Colors[Next.Type];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Pressed && !NewConnectionNext) pinColor = pinColor * 0.8f;
|
||||||
|
if(Filled) fillColor = pinColor;
|
||||||
|
|
||||||
|
DrawList.AddCircleFilled(PinCenter, PinRadius, fillColor);
|
||||||
|
DrawList.AddCircle(PinCenter, PinRadius, pinColor, 0, BorderThickness);
|
||||||
|
|
||||||
// Text
|
// Text
|
||||||
const ImVec2 TextOffset = location + ImVec2((input ? HeaderHeight : -ImGui::CalcTextSize(pin.Name.c_str()).x / Camera.Zoom), 0);
|
const ImVec2 TextOffset = location + ImVec2((input ? HeaderHeight : -ImGui::CalcTextSize(pin.Name.c_str()).x / Camera.Zoom), 0);
|
||||||
@ -615,7 +688,7 @@ void ShaderGraph::DrawContextMenu()
|
|||||||
|
|
||||||
// Create Nodes
|
// Create Nodes
|
||||||
ImVec2 position = ContextMenuPosition;
|
ImVec2 position = ContextMenuPosition;
|
||||||
position = ImFloor(position / GridSize) * GridSize;
|
position = SnapToGrid(position);
|
||||||
|
|
||||||
std::stack<ContextID> context; context.push(0);
|
std::stack<ContextID> context; context.push(0);
|
||||||
|
|
||||||
@ -694,32 +767,39 @@ void ShaderGraph::DrawConnections()
|
|||||||
|
|
||||||
// Connections =============================================================================================================
|
// Connections =============================================================================================================
|
||||||
|
|
||||||
for(const Connection& connection : Connections)
|
for(const Connection& connection : State.Connections)
|
||||||
{
|
{
|
||||||
DrawConnection(connection.first, connection.second);
|
DrawConnection(connection.first, connection.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Mouse.NewConnection())
|
if(Mouse.NewConnection())
|
||||||
{
|
{
|
||||||
const Node& Node = *Nodes[Mouse.NewConnection->Node];
|
const Node& Node = *State.Nodes[Mouse.NewConnection->Node];
|
||||||
const Pin& Pin = Mouse.NewConnection->Input ? Node.IO.Inputs[Mouse.NewConnection->Pin] : Node.IO.Outputs[Mouse.NewConnection->Pin];
|
const Pin& Pin = Mouse.NewConnection->Input ? Node.IO.Inputs[Mouse.NewConnection->Pin] : Node.IO.Outputs[Mouse.NewConnection->Pin];
|
||||||
|
const auto Connection = State.Connections.find(*Mouse.NewConnection);
|
||||||
|
const bool Connected = Connection != State.Connections.end();
|
||||||
|
|
||||||
const ImVec2 NodePos = Node.Position + Padding;
|
const ImVec2 NodePos = Node.Position + Padding;
|
||||||
const ImVec2 InputRoot = GridToScreen(NodePos + ImVec2(Style.Nodes.Pins.Padding, HeaderHeight));
|
const ImVec2 InputRoot = GridToScreen(NodePos + ImVec2(Style.Nodes.Pins.Padding, HeaderHeight));
|
||||||
const ImVec2 OutputRoot = GridToScreen(NodePos + ImVec2(Node.Info.Size.x - HeaderHeight - Style.Nodes.Pins.Padding, HeaderHeight));
|
const ImVec2 OutputRoot = GridToScreen(NodePos + ImVec2(Node.Info.Size.x - HeaderHeight - Style.Nodes.Pins.Padding, HeaderHeight));
|
||||||
|
|
||||||
const ImVec2 Root = (Mouse.NewConnection->Input ? InputRoot : OutputRoot) + ImVec2(0, HeaderHeight) * (Mouse.NewConnection->Pin + 0.5f);
|
const ImVec2 Root = (Mouse.NewConnection->Input ? InputRoot : OutputRoot) + ImVec2(0, HeaderHeight) * (Mouse.NewConnection->Pin + 0.5f);
|
||||||
|
|
||||||
const ImVec2 A = Root + Offset + ImVec2(Mouse.NewConnection->Input ? -PinRadius : PinRadius, 0);
|
const ImVec2 PinLoc = Root + Offset + ImVec2(Mouse.NewConnection->Input ? -PinRadius : PinRadius, 0);
|
||||||
const ImVec2 D = ImGui::GetMousePos();
|
const ImVec2 MouseLoc = ImGui::GetMousePos();
|
||||||
|
|
||||||
|
const ImVec2 A = Mouse.NewConnection->Input ? MouseLoc : PinLoc;
|
||||||
|
const ImVec2 D = Mouse.NewConnection->Input ? PinLoc : MouseLoc;
|
||||||
const float Off = BezierOffset(A, D);
|
const float Off = BezierOffset(A, D);
|
||||||
|
|
||||||
const ImVec2 B = ImVec2(A.x + (Mouse.NewConnection->Input ? -Off : Off), A.y);
|
const ImVec2 B = ImVec2(A.x + Off, A.y);
|
||||||
const ImVec2 C = ImVec2(D.x + (Mouse.NewConnection->Input ? Off : -Off), D.y);
|
const ImVec2 C = ImVec2(D.x - Off, D.y);
|
||||||
|
|
||||||
|
const ImColor Color = Mouse.NewConnection->Input && Connected
|
||||||
|
? Pin::Colors[GetPin(Connection->second).Type] : Pin::Colors[Pin.Type];
|
||||||
|
|
||||||
DrawList.AddBezierCubic(
|
DrawList.AddBezierCubic(
|
||||||
A, B, C, D
|
A, B, C, D
|
||||||
, Pin::Colors[Pin.Type], Style.Nodes.Pins.Connections.Thickness / Camera.Zoom
|
, Color, Style.Nodes.Pins.Connections.Thickness / Camera.Zoom
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -751,12 +831,12 @@ void ShaderGraph::DrawConnection(const PinPtr& a, const PinPtr& b)
|
|||||||
const PinPtr& In = a.Input ? a : b;
|
const PinPtr& In = a.Input ? a : b;
|
||||||
const PinPtr& Out = a.Input ? b : a;
|
const PinPtr& Out = a.Input ? b : a;
|
||||||
|
|
||||||
const Node& OutNode = *Nodes[Out.Node];
|
const Node& OutNode = *State.Nodes[Out.Node];
|
||||||
const ImVec2 OutSize = OutNode.Info.Size / Camera.Zoom;
|
const ImVec2 OutSize = OutNode.Info.Size / Camera.Zoom;
|
||||||
const ImVec2 OutPosition = CanvasCenter - Camera.Location + OutNode.Position / Camera.Zoom + Padding;
|
const ImVec2 OutPosition = CanvasCenter - Camera.Location + OutNode.Position / Camera.Zoom + Padding;
|
||||||
const ImVec2 OutputLoc = OutPosition + ImVec2(OutSize.x - HeaderHeight - Style.Nodes.Pins.Padding / Camera.Zoom, HeaderHeight);
|
const ImVec2 OutputLoc = OutPosition + ImVec2(OutSize.x - HeaderHeight - Style.Nodes.Pins.Padding / Camera.Zoom, HeaderHeight);
|
||||||
|
|
||||||
const Node& InNode = *Nodes[In.Node];
|
const Node& InNode = *State.Nodes[In.Node];
|
||||||
const ImVec2 InPosition = CanvasCenter - Camera.Location + InNode.Position / Camera.Zoom + Padding;
|
const ImVec2 InPosition = CanvasCenter - Camera.Location + InNode.Position / Camera.Zoom + Padding;
|
||||||
const ImVec2 InputLoc = InPosition + ImVec2(Style.Nodes.Pins.Padding / Camera.Zoom, HeaderHeight);
|
const ImVec2 InputLoc = InPosition + ImVec2(Style.Nodes.Pins.Padding / Camera.Zoom, HeaderHeight);
|
||||||
|
|
||||||
@ -794,11 +874,11 @@ void ShaderGraph::CreateConnection(const PinPtr& a, const PinPtr& b)
|
|||||||
if(a.Node == b.Node) return;
|
if(a.Node == b.Node) return;
|
||||||
|
|
||||||
const PinPtr& In = a.Input ? a : b;
|
const PinPtr& In = a.Input ? a : b;
|
||||||
const Node& InNode = *Nodes[In.Node];
|
const Node& InNode = *State.Nodes[In.Node];
|
||||||
const Pin& InPin = InNode.IO.Inputs[In.Pin];
|
const Pin& InPin = InNode.IO.Inputs[In.Pin];
|
||||||
|
|
||||||
const PinPtr& Out = a.Input ? b : a;
|
const PinPtr& Out = a.Input ? b : a;
|
||||||
const Node& OutNode = *Nodes[Out.Node];
|
const Node& OutNode = *State.Nodes[Out.Node];
|
||||||
const Pin& OutPin = OutNode.IO.Outputs[Out.Pin];
|
const Pin& OutPin = OutNode.IO.Outputs[Out.Pin];
|
||||||
|
|
||||||
// Make sure valid typing
|
// Make sure valid typing
|
||||||
@ -809,28 +889,28 @@ void ShaderGraph::CreateConnection(const PinPtr& a, const PinPtr& b)
|
|||||||
if(b.Input) EraseConnections(b);
|
if(b.Input) EraseConnections(b);
|
||||||
|
|
||||||
// Add New Connections
|
// Add New Connections
|
||||||
Connections.emplace(a, b);
|
State.Connections.emplace(a, b);
|
||||||
Connections.emplace(b, a);
|
State.Connections.emplace(b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderGraph::EraseConnection(const PinPtr& a, const PinPtr& b)
|
void ShaderGraph::EraseConnection(const PinPtr& a, const PinPtr& b)
|
||||||
{
|
{
|
||||||
auto range = Connections.equal_range(a);
|
auto range = State.Connections.equal_range(a);
|
||||||
for(auto it = range.first; it != range.second; ++it)
|
for(auto it = range.first; it != range.second; ++it)
|
||||||
{
|
{
|
||||||
if(it->second == b)
|
if(it->second == b)
|
||||||
{
|
{
|
||||||
Connections.erase(it);
|
State.Connections.erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
range = Connections.equal_range(b);
|
range = State.Connections.equal_range(b);
|
||||||
for(auto it = range.first; it != range.second; ++it)
|
for(auto it = range.first; it != range.second; ++it)
|
||||||
{
|
{
|
||||||
if(it->second == a)
|
if(it->second == a)
|
||||||
{
|
{
|
||||||
Connections.erase(it);
|
State.Connections.erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -838,41 +918,41 @@ void ShaderGraph::EraseConnection(const PinPtr& a, const PinPtr& b)
|
|||||||
|
|
||||||
void ShaderGraph::EraseConnections(const PinPtr& a)
|
void ShaderGraph::EraseConnections(const PinPtr& a)
|
||||||
{
|
{
|
||||||
auto it = Connections.find(a);
|
auto it = State.Connections.find(a);
|
||||||
while(it != Connections.end())
|
while(it != State.Connections.end())
|
||||||
{
|
{
|
||||||
auto range = Connections.equal_range(it->second);
|
auto range = State.Connections.equal_range(it->second);
|
||||||
for(auto match = range.first; match != range.second; ++match)
|
for(auto match = range.first; match != range.second; ++match)
|
||||||
{
|
{
|
||||||
if(match->second == a)
|
if(match->second == a)
|
||||||
{
|
{
|
||||||
Connections.erase(match);
|
State.Connections.erase(match);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections.erase(it);
|
State.Connections.erase(it);
|
||||||
it = Connections.find(a);
|
it = State.Connections.find(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeId ShaderGraph::AddNode(Node* node)
|
NodeId ShaderGraph::AddNode(Node* node)
|
||||||
{
|
{
|
||||||
if(Erased.empty())
|
if(State.Erased.empty())
|
||||||
{
|
{
|
||||||
Nodes.push_back(node);
|
State.Nodes.push_back(node);
|
||||||
return static_cast<NodeId>(Nodes.size() - 1);
|
return static_cast<NodeId>(State.Nodes.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeId id = *Erased.begin();
|
NodeId id = *State.Erased.begin();
|
||||||
Nodes[id] = node;
|
State.Nodes[id] = node;
|
||||||
Erased.erase(id);
|
State.Erased.erase(id);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderGraph::RemoveNode(NodeId id)
|
void ShaderGraph::RemoveNode(NodeId id)
|
||||||
{
|
{
|
||||||
Node* node = Nodes[id];
|
Node* node = State.Nodes[id];
|
||||||
if(node->Info.Const) return;
|
if(node->Info.Const) return;
|
||||||
|
|
||||||
PinId i = 0;
|
PinId i = 0;
|
||||||
@ -881,9 +961,9 @@ void ShaderGraph::RemoveNode(NodeId id)
|
|||||||
i = 0;
|
i = 0;
|
||||||
for(const auto& pin : node->IO.Outputs) EraseConnections({ id, i++, false });
|
for(const auto& pin : node->IO.Outputs) EraseConnections({ id, i++, false });
|
||||||
|
|
||||||
Erased.insert(id);
|
State.Erased.insert(id);
|
||||||
delete node;
|
delete node;
|
||||||
Nodes[id] = nullptr;
|
State.Nodes[id] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderGraph::ClearClipboard()
|
void ShaderGraph::ClearClipboard()
|
||||||
@ -899,7 +979,7 @@ void ShaderGraph::Copy()
|
|||||||
|
|
||||||
// Helper for connections
|
// Helper for connections
|
||||||
std::unordered_map<NodeId, NodeId> clipboardTransform;
|
std::unordered_map<NodeId, NodeId> clipboardTransform;
|
||||||
ImVec2 min = Nodes[*Mouse.Selected.begin()]->Position;
|
ImVec2 min = State.Nodes[*Mouse.Selected.begin()]->Position;
|
||||||
|
|
||||||
// Reset Clipboard
|
// Reset Clipboard
|
||||||
ClearClipboard();
|
ClearClipboard();
|
||||||
@ -908,7 +988,7 @@ void ShaderGraph::Copy()
|
|||||||
// Copy nodes
|
// Copy nodes
|
||||||
for(auto id : Mouse.Selected)
|
for(auto id : Mouse.Selected)
|
||||||
{
|
{
|
||||||
Node* node = Nodes[id];
|
Node* node = State.Nodes[id];
|
||||||
clipboardTransform[id] = static_cast<NodeId>(Clipboard.Nodes.size());
|
clipboardTransform[id] = static_cast<NodeId>(Clipboard.Nodes.size());
|
||||||
Clipboard.Nodes.push_back(node->Copy(*this));
|
Clipboard.Nodes.push_back(node->Copy(*this));
|
||||||
min = ImMin(node->Position, min);
|
min = ImMin(node->Position, min);
|
||||||
@ -921,7 +1001,7 @@ void ShaderGraph::Copy()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy connections
|
// Copy connections
|
||||||
for(const Connection& connection : Connections)
|
for(const Connection& connection : State.Connections)
|
||||||
{
|
{
|
||||||
if(!(Mouse.Selected.contains(connection.first.Node) && Mouse.Selected.contains(connection.second.Node))) continue;
|
if(!(Mouse.Selected.contains(connection.first.Node) && Mouse.Selected.contains(connection.second.Node))) continue;
|
||||||
|
|
||||||
@ -939,7 +1019,7 @@ void ShaderGraph::Paste(const ImVec2& location)
|
|||||||
// Helper for connections
|
// Helper for connections
|
||||||
const float GridSize = (Style.FontSize + Style.Grid.Lines.Padding);
|
const float GridSize = (Style.FontSize + Style.Grid.Lines.Padding);
|
||||||
std::unordered_map<NodeId, NodeId> clipboardTransform;
|
std::unordered_map<NodeId, NodeId> clipboardTransform;
|
||||||
ImVec2 root = ImFloor(location / GridSize + ImVec2(0.5f, 0.5f)) * GridSize;
|
ImVec2 root = SnapToGrid(location);
|
||||||
Mouse.Selected.clear();
|
Mouse.Selected.clear();
|
||||||
|
|
||||||
// Paste the nodes
|
// Paste the nodes
|
||||||
@ -947,7 +1027,7 @@ void ShaderGraph::Paste(const ImVec2& location)
|
|||||||
for(Node* node : Clipboard.Nodes)
|
for(Node* node : Clipboard.Nodes)
|
||||||
{
|
{
|
||||||
NodeId index = clipboardTransform[id++] = AddNode(node->Copy(*this));
|
NodeId index = clipboardTransform[id++] = AddNode(node->Copy(*this));
|
||||||
Nodes[index]->Position += root;
|
State.Nodes[index]->Position += root;
|
||||||
Mouse.Selected.insert(index);
|
Mouse.Selected.insert(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -970,6 +1050,17 @@ void ShaderGraph::EraseSelection()
|
|||||||
Mouse.Selected.clear();
|
Mouse.Selected.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShaderGraph::PushState()
|
||||||
|
{
|
||||||
|
History.push(State);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderGraph::PopState()
|
||||||
|
{
|
||||||
|
State = History.top();
|
||||||
|
History.pop();
|
||||||
|
}
|
||||||
|
|
||||||
float ShaderGraph::BezierOffset(const ImVec2& out, const ImVec2& in)
|
float ShaderGraph::BezierOffset(const ImVec2& out, const ImVec2& in)
|
||||||
{
|
{
|
||||||
const float HeaderHeight = Style.FontSize / Camera.Zoom;
|
const float HeaderHeight = Style.FontSize / Camera.Zoom;
|
||||||
@ -1004,6 +1095,18 @@ ImVec2 ShaderGraph::ScreenToGrid(const ImVec2& position)
|
|||||||
return (position - CanvasCenter + Camera.Location) * Camera.Zoom;
|
return (position - CanvasCenter + Camera.Location) * Camera.Zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImVec2 ShaderGraph::SnapToGrid(const ImVec2& position)
|
||||||
|
{
|
||||||
|
const float GridSize = (Style.FontSize + Style.Grid.Lines.Padding);
|
||||||
|
return ImFloor(position / GridSize) * GridSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pin& ShaderGraph::GetPin(const PinPtr &ptr)
|
||||||
|
{
|
||||||
|
Node* node = State.Nodes[ptr.Node];
|
||||||
|
return (ptr.Input ? node->IO.Inputs : node->IO.Outputs)[ptr.Pin];
|
||||||
|
}
|
||||||
|
|
||||||
void ShaderGraph::Register(const std::filesystem::path& path, ConstructorPtr constructor)
|
void ShaderGraph::Register(const std::filesystem::path& path, ConstructorPtr constructor)
|
||||||
{
|
{
|
||||||
const std::string name = path.filename().string();
|
const std::string name = path.filename().string();
|
||||||
@ -1042,3 +1145,20 @@ void ShaderGraph::Register(const std::filesystem::path& path, ConstructorPtr con
|
|||||||
|
|
||||||
ContextMenu.Insert({ name, constructor }, node);
|
ContextMenu.Insert({ name, constructor }, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Inspector::Inspector()
|
||||||
|
: EditorWindow("Inspector", 0)
|
||||||
|
, Graph(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inspector::DrawWindow()
|
||||||
|
{
|
||||||
|
if(Graph->Mouse.Selected.size() != 1)
|
||||||
|
{
|
||||||
|
ImGui::Text("Selected %d nodes.", Graph->Mouse.Selected.size());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Graph->State.Nodes[*Graph->Mouse.Selected.begin()]->Inspect();
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user