Updates to libraries
This commit is contained in:
parent
593760dd92
commit
8a514da303
6
External/open-cpp-utils/CMakeLists.txt
vendored
6
External/open-cpp-utils/CMakeLists.txt
vendored
@ -10,6 +10,12 @@ set(OPENCPPUTILS_HEADERS
|
||||
startup.h
|
||||
template_utils.h
|
||||
unique_id.h
|
||||
dynarray.h
|
||||
redec.h
|
||||
hash_table.h
|
||||
math.h
|
||||
set.h
|
||||
map.h
|
||||
)
|
||||
|
||||
add_library(open-cpp-utils INTERFACE
|
||||
|
7
External/open-cpp-utils/any.h
vendored
7
External/open-cpp-utils/any.h
vendored
@ -65,10 +65,17 @@ public:
|
||||
public:
|
||||
|
||||
// Assignment operators ------------------------------------------------------------------------------------------------
|
||||
|
||||
any& operator=(const any&) = default;
|
||||
any& operator=(any&&) = default;
|
||||
|
||||
|
||||
// Access --------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template<typename V>
|
||||
V& get() { static_assert(std::disjunction<std::is_same<V, T>, std::is_same<V, Rest>...>{}); return static_cast<V&>(*this); }
|
||||
|
||||
|
||||
// Cast operators ------------------------------------------------------------------------------------------------------
|
||||
|
||||
operator reference() { return Value; }
|
||||
|
102
External/open-cpp-utils/directed_tree.h
vendored
102
External/open-cpp-utils/directed_tree.h
vendored
@ -42,7 +42,7 @@ public:
|
||||
class unordered;
|
||||
|
||||
private:
|
||||
struct director;
|
||||
struct Node_;
|
||||
|
||||
|
||||
// Typedefs ============================================================================================================
|
||||
@ -53,7 +53,7 @@ public:
|
||||
using node_queue = std::deque<node>;
|
||||
|
||||
private:
|
||||
using hierarchy = std::vector<director>;
|
||||
using hierarchy = std::vector<Node_>;
|
||||
using storage = std::vector<data_type>;
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ public:
|
||||
// Data Structures =====================================================================================================
|
||||
|
||||
private:
|
||||
struct director
|
||||
struct Node_
|
||||
{
|
||||
enum flags
|
||||
{
|
||||
@ -76,7 +76,7 @@ private:
|
||||
node parent, child, prev_sibling, next_sibling;
|
||||
uint32_t flags, depth;
|
||||
|
||||
director() : parent(0), child(0), prev_sibling(0), next_sibling(0), flags(VALID), depth(0) { }
|
||||
Node_() : parent(0), child(0), prev_sibling(0), next_sibling(0), flags(VALID), depth(0) { }
|
||||
};
|
||||
|
||||
|
||||
@ -89,7 +89,7 @@ public:
|
||||
/**
|
||||
* \brief Default constructor, creates tree with empty root
|
||||
*/
|
||||
directed_tree() : graph_{ director() }, data_{ data_type() }, freed_{ } { }
|
||||
directed_tree() : graph_{ Node_() }, data_{ data_type() }, freed_{ } { }
|
||||
|
||||
|
||||
// Tree Navigation -----------------------------------------------------------------------------------------------------
|
||||
@ -99,7 +99,7 @@ public:
|
||||
* \param id Node id to reference
|
||||
* \return Whether the valid flag is true in the node
|
||||
*/
|
||||
[[nodiscard]] bool valid(node id) const { return graph_[id].flags & director::VALID; }
|
||||
[[nodiscard]] bool valid(node id) const { return graph_[id].flags & Node_::VALID; }
|
||||
|
||||
/**
|
||||
* \brief Get the parent of a node. O(1)
|
||||
@ -115,6 +115,20 @@ public:
|
||||
*/
|
||||
[[nodiscard]] node first_child(node id) const { return graph_[id].child; }
|
||||
|
||||
/**
|
||||
* \brief Get the first child of a node. O(1)
|
||||
* \param id Node id to reference
|
||||
* \return Node id of the first child
|
||||
*/
|
||||
[[nodiscard]] node last_child(node id) const
|
||||
{
|
||||
node c = first_child(id);
|
||||
|
||||
while(c != 0) { if(graph_[c].next_sibling == 0) break; c = graph_[c].next_sibling; }
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the previous sibling of a node. O(1)
|
||||
* \param id Node id to reference
|
||||
@ -164,47 +178,63 @@ public:
|
||||
* \brief Insert a node into the tree as a child of the provided node
|
||||
* \param data Value to insert
|
||||
* \param p_id Id of the parent node
|
||||
* \param last Whether to insert at the back of the array
|
||||
* \return Id of the inserted node
|
||||
*/
|
||||
node insert(const data_type& data, node p_id)
|
||||
node insert(const data_type& data, node p_id, bool last = true)
|
||||
{
|
||||
// If there are no freed nodes, create a new node and mark it as freed
|
||||
if(freed_.empty())
|
||||
{
|
||||
freed_.push_back(static_cast<node>(graph_.size()));
|
||||
graph_.push_back(director()); data_.push_back(data);
|
||||
graph_.push_back(Node_()); data_.push_back(data);
|
||||
}
|
||||
|
||||
// Pop a freed node from the stack
|
||||
node id = freed_.front(); freed_.pop_front();
|
||||
director& node = graph_[id];
|
||||
director& parent = graph_[p_id];
|
||||
Node_& node = graph_[id];
|
||||
Node_& parent = graph_[p_id];
|
||||
|
||||
// If the parent has a child, update the child's references
|
||||
if(parent.child)
|
||||
if(parent.child && !last)
|
||||
{
|
||||
// Update the next child
|
||||
director& nchild = graph_[parent.child];
|
||||
Node_& nchild = graph_[parent.child];
|
||||
node.prev_sibling = nchild.prev_sibling;
|
||||
nchild.prev_sibling = id;
|
||||
|
||||
// If present, update the previous child
|
||||
if(nchild.prev_sibling)
|
||||
{
|
||||
director& pchild = graph_[nchild.prev_sibling];
|
||||
Node_& pchild = graph_[nchild.prev_sibling];
|
||||
pchild.next_sibling = id;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup node
|
||||
node.parent = p_id;
|
||||
node.next_sibling = parent.child;
|
||||
node.next_sibling = last ? 0 : parent.child;
|
||||
node.child = 0;
|
||||
node.flags = director::VALID;
|
||||
node.flags = Node_::VALID;
|
||||
node.depth = parent.depth + 1;
|
||||
|
||||
// Set parent's child
|
||||
if(last)
|
||||
{
|
||||
directed_tree::node idx = last_child(p_id);
|
||||
|
||||
if(idx)
|
||||
{
|
||||
Node_& lchild = graph_[idx];
|
||||
lchild.next_sibling = id;
|
||||
node.prev_sibling = idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.child = id;
|
||||
}
|
||||
}
|
||||
else parent.child = id;
|
||||
|
||||
// Set the data
|
||||
data_[id] = data;
|
||||
@ -221,8 +251,8 @@ public:
|
||||
if(id == 0) return;
|
||||
|
||||
// Mark node as invalid and push it to the freed list
|
||||
director& erased = graph_[id];
|
||||
erased.Flags &= ~director::VALID;
|
||||
Node_& erased = graph_[id];
|
||||
erased.Flags &= ~Node_::VALID;
|
||||
freed_.push_back(id);
|
||||
|
||||
// Update the parent's child
|
||||
@ -237,8 +267,8 @@ public:
|
||||
while(stack.empty() == false)
|
||||
{
|
||||
node next = stack.front(); stack.pop_front();
|
||||
director& child = graph_[next];
|
||||
child.Flags &= ~director::VALID;
|
||||
Node_& child = graph_[next];
|
||||
child.Flags &= ~Node_::VALID;
|
||||
freed_.push_back(next);
|
||||
|
||||
if(child.Sibling) stack.push_front(child.Sibling);
|
||||
@ -326,7 +356,7 @@ public:
|
||||
node operator()(node id)
|
||||
{
|
||||
id = visit_queue_.back(); visit_queue_.pop_back();
|
||||
director& current = graph_.graph_[id];
|
||||
Node_& current = graph_.graph_[id];
|
||||
|
||||
if(current.next_sibling) visit_queue_.push_back(current.next_sibling);
|
||||
if(current.child) visit_queue_.push_front(current.child);
|
||||
@ -351,7 +381,7 @@ public:
|
||||
|
||||
node operator()(node id)
|
||||
{
|
||||
director& current = graph_.graph_[id];
|
||||
Node_& current = graph_.graph_[id];
|
||||
|
||||
if(current.next_sibling) visit_queue_.push_front(current.next_sibling);
|
||||
if(current.child) visit_queue_.push_front(current.child);
|
||||
@ -375,12 +405,12 @@ public:
|
||||
public:
|
||||
in_order(directed_tree& graph) : graph_(graph) { }
|
||||
|
||||
node operator()(node node)
|
||||
node operator()(node id)
|
||||
{
|
||||
if(node == 0) visit_queue_.push_back(graph_.left_most(node));
|
||||
if(id == 0) visit_queue_.push_back(graph_.left_most(id));
|
||||
|
||||
node = visit_queue_.front(); visit_queue_.pop_front();
|
||||
director& current = graph_.graph_[node];
|
||||
id = visit_queue_.front(); visit_queue_.pop_front();
|
||||
Node_& current = graph_.graph_[id];
|
||||
|
||||
if(current.Sibling)
|
||||
{
|
||||
@ -388,7 +418,7 @@ public:
|
||||
visit_queue_.push_back(graph_.left_most(current.Sibling));
|
||||
}
|
||||
|
||||
return node;
|
||||
return id;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -405,17 +435,17 @@ public:
|
||||
public:
|
||||
post_order(directed_tree& graph) : graph_(graph) { }
|
||||
|
||||
node operator()(node node)
|
||||
node operator()(node id)
|
||||
{
|
||||
if(visit_queue_.empty()) visit_queue_.push_back(graph_.left_most(node));
|
||||
if(visit_queue_.empty()) visit_queue_.push_back(graph_.left_most(id));
|
||||
|
||||
node = visit_queue_.front(); visit_queue_.pop_front();
|
||||
if(node == 0) return node;
|
||||
director& current = graph_.graph_[node];
|
||||
id = visit_queue_.front(); visit_queue_.pop_front();
|
||||
if(id == 0) return id;
|
||||
Node_& current = graph_.graph_[id];
|
||||
|
||||
visit_queue_.push_back(current.Sibling ? graph_.left_most(current.Sibling) : graph_.parent(node));
|
||||
visit_queue_.push_back(current.Sibling ? graph_.left_most(current.Sibling) : graph_.parent(id));
|
||||
|
||||
return node;
|
||||
return id;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -438,10 +468,10 @@ public:
|
||||
|
||||
void operator()()
|
||||
{
|
||||
node node = 0;
|
||||
while(node = order_(node))
|
||||
node id = 0;
|
||||
while(id = order_(id))
|
||||
{
|
||||
if(visitor_(graph_[node], node)) break;
|
||||
if(visitor_(graph_[id], id)) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
30
External/open-cpp-utils/dynarray.h
vendored
Normal file
30
External/open-cpp-utils/dynarray.h
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// =====================================================================================================================
|
||||
// Copyright 2024 Medusa Slockbower
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef DYNARRAY_H
|
||||
#define DYNARRAY_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace open_cpp_utils
|
||||
{
|
||||
|
||||
template<typename T, class Alloc = std::allocator<T>>
|
||||
using dynarray = std::vector<T, Alloc>;
|
||||
|
||||
}
|
||||
|
||||
#endif //DYNARRAY_H
|
300
External/open-cpp-utils/hash_table.h
vendored
Normal file
300
External/open-cpp-utils/hash_table.h
vendored
Normal file
@ -0,0 +1,300 @@
|
||||
// =====================================================================================================================
|
||||
// Copyright 2024 Medusa Slockbower
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef HASH_TABLE_H
|
||||
#define HASH_TABLE_H
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "math.h"
|
||||
#include "optional.h"
|
||||
|
||||
namespace open_cpp_utils
|
||||
{
|
||||
|
||||
template<typename T, class Hash = std::hash<T>, class Alloc = std::allocator<T>>
|
||||
class hash_table
|
||||
{
|
||||
// Typedefs ============================================================================================================
|
||||
|
||||
public:
|
||||
friend class iterator;
|
||||
|
||||
private:
|
||||
struct _Node;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
|
||||
using hash_type = Hash;
|
||||
using allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<_Node>;
|
||||
|
||||
using size_type = size_t;
|
||||
using iterator_type = iterator;
|
||||
|
||||
private:
|
||||
using table_type = _Node*;
|
||||
using node = int64_t;
|
||||
static constexpr node nullnode = std::integral_constant<node, -1>{};
|
||||
|
||||
|
||||
// Structs =============================================================================================================
|
||||
|
||||
private:
|
||||
struct _Node
|
||||
{
|
||||
optional<T> value;
|
||||
int psl;
|
||||
|
||||
_Node() : value(), psl(0) { }
|
||||
};
|
||||
|
||||
|
||||
// Functions ===========================================================================================================
|
||||
|
||||
public:
|
||||
|
||||
// Constructors & Destructor -------------------------------------------------------------------------------------------
|
||||
|
||||
hash_table() : table_(nullptr), capacity_(0), size_(0), load_factor_(0.8), hash_(), alloc_() { }
|
||||
hash_table(const hash_table&);
|
||||
hash_table(hash_table&&) = default; // Default Move Constructor should suffice
|
||||
~hash_table() { clear(); }
|
||||
|
||||
// Modifiers -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
void clear();
|
||||
void insert(const_reference x);
|
||||
void erase(const_reference x);
|
||||
bool contains(const_reference x);
|
||||
iterator find(const_reference x) const { node res = _find(x); return iterator(this, res == nullnode ? capacity_ : res); }
|
||||
|
||||
// Modifiers -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] size_type capacity() const { return capacity_; }
|
||||
[[nodiscard]] size_type size() const { return size_; }
|
||||
[[nodiscard]] bool empty() const { return size_ == 0; }
|
||||
[[nodiscard]] double occupancy() const { return size_ / static_cast<double>(capacity_); }
|
||||
|
||||
// Helpers -------------------------------------------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
void _increase_capacity();
|
||||
|
||||
[[nodiscard]] node _hash(const_reference v) const;
|
||||
[[nodiscard]] node _find(const_reference x) const;
|
||||
[[nodiscard]] node _next(node n) const { return (n + 1) % capacity_; }
|
||||
[[nodiscard]] node _prev(node n) const { return (n - 1 + capacity_) % capacity_; }
|
||||
|
||||
static size_type _next_prime(size_type x);
|
||||
static size_type _prev_prime(size_type x);
|
||||
|
||||
|
||||
// Iterators ===========================================================================================================
|
||||
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
iterator(hash_table* table, int idx) : table_(table), idx_(idx) { _next_index(); }
|
||||
iterator(const iterator&) = default;
|
||||
iterator(iterator&&) = default;
|
||||
~iterator() = default;
|
||||
|
||||
iterator& operator++() { ++idx_; _next_index(); return *this; }
|
||||
iterator operator++(int) { iterator ret = *this; ++idx_; _next_index(); return ret; }
|
||||
|
||||
bool operator==(const iterator& o) const = default;
|
||||
bool operator!=(const iterator& o) const = default;
|
||||
|
||||
reference operator*() const { return table_->table_[idx_].value; }
|
||||
pointer operator->() const { return &table_->table_[idx_].value; }
|
||||
|
||||
private:
|
||||
void _next_index() { while(idx_ < table_->capacity_ && table_[idx_].value()) ++idx_; }
|
||||
|
||||
hash_table* table_;
|
||||
int idx_;
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(this, 0); }
|
||||
iterator end() { return iterator(this, capacity_); }
|
||||
|
||||
|
||||
// Variables ===========================================================================================================
|
||||
|
||||
private:
|
||||
table_type table_;
|
||||
size_type capacity_, size_;
|
||||
double load_factor_;
|
||||
hash_type hash_;
|
||||
allocator_type alloc_;
|
||||
};
|
||||
|
||||
template<typename T, class Hash, class Alloc>
|
||||
hash_table<T, Hash, Alloc>::hash_table(const hash_table& other)
|
||||
: table_(nullptr)
|
||||
, capacity_(other.capacity_)
|
||||
, size_(other.size_)
|
||||
, load_factor_(0.8)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename T, class Hash, class Alloc>
|
||||
void hash_table<T, Hash, Alloc>::clear()
|
||||
{
|
||||
alloc_.deallocate(table_, capacity_);
|
||||
capacity_ = size_ = 0;
|
||||
}
|
||||
|
||||
template<typename T, class Hash, class Alloc>
|
||||
void hash_table<T, Hash, Alloc>::insert(const_reference x)
|
||||
{
|
||||
if(occupancy() > load_factor_ || capacity_ == 0) _increase_capacity();
|
||||
|
||||
node idx = _hash(x);
|
||||
int psl = 0;
|
||||
T value = x;
|
||||
|
||||
while(table_[idx].value())
|
||||
{
|
||||
_Node& node = table_[idx];
|
||||
|
||||
if(node.value == x) return;
|
||||
if(psl > node.psl) { std::swap(psl, node.psl); std::swap(value, node.value); }
|
||||
|
||||
idx = _next(idx);
|
||||
++psl;
|
||||
}
|
||||
|
||||
table_[idx].value = value;
|
||||
table_[idx].psl = psl;
|
||||
++size_;
|
||||
}
|
||||
|
||||
template<typename T, class Hash, class Alloc>
|
||||
void hash_table<T, Hash, Alloc>::erase(const_reference x)
|
||||
{
|
||||
node idx = _find(x);
|
||||
if(idx == nullnode) return;
|
||||
|
||||
table_[idx].value.reset();
|
||||
--size_;
|
||||
|
||||
node prev = idx; idx = _next(idx);
|
||||
while(table_[idx].value() && table_[idx].psl > 0)
|
||||
{
|
||||
_Node &a = table_[prev], &b = table_[idx];
|
||||
std::swap(a, b);
|
||||
--a.psl; prev = idx; idx = _next(idx);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, class Hash, class Alloc>
|
||||
bool hash_table<T, Hash, Alloc>::contains(const_reference x)
|
||||
{
|
||||
return _find(x) != nullnode;
|
||||
}
|
||||
|
||||
template<typename T, class Hash, class Alloc>
|
||||
void hash_table<T, Hash, Alloc>::_increase_capacity()
|
||||
{
|
||||
table_type old = table_;
|
||||
size_type old_capacity = capacity_;
|
||||
capacity_ = _next_prime(capacity_);
|
||||
table_ = alloc_.allocate(capacity_);
|
||||
memset(table_, 0, capacity_ * sizeof(_Node));
|
||||
size_ = 0;
|
||||
|
||||
for(node i = 0; i < old_capacity; ++i)
|
||||
{
|
||||
if(old[i].value()) insert(old[i].value);
|
||||
}
|
||||
|
||||
alloc_.deallocate(old, old_capacity);
|
||||
}
|
||||
|
||||
template<typename T, class Hash, class Alloc>
|
||||
typename hash_table<T, Hash, Alloc>::node hash_table<T, Hash, Alloc>::_hash(const_reference v) const
|
||||
{
|
||||
node x = hash_(v);
|
||||
|
||||
x ^= x >> 33U;
|
||||
x *= UINT64_C(0xff51afd7ed558ccd);
|
||||
x ^= x >> 33U;
|
||||
x *= UINT64_C(0xc4ceb9fe1a85ec53);
|
||||
x ^= x >> 33U;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
template<typename T, class Hash, class Alloc>
|
||||
typename hash_table<T, Hash, Alloc>::node hash_table<T, Hash, Alloc>::_find(const_reference x) const
|
||||
{
|
||||
if(capacity_ == 0) return nullnode;
|
||||
node idx = _hash(x);
|
||||
int psl = 0;
|
||||
|
||||
while(table_[idx].value())
|
||||
{
|
||||
_Node& node = table_[idx];
|
||||
|
||||
if(node.psl > psl) return nullnode;
|
||||
if(node.value == x) return idx;
|
||||
|
||||
idx = _next(idx); ++psl;
|
||||
}
|
||||
|
||||
return nullnode;
|
||||
}
|
||||
|
||||
template<typename T, class Hash, class Alloc>
|
||||
typename hash_table<T, Hash, Alloc>::size_type hash_table<T, Hash, Alloc>::_next_prime(size_type x)
|
||||
{
|
||||
size_type n = (x + 1) / 6;
|
||||
n *= 2;
|
||||
|
||||
while(true)
|
||||
{
|
||||
x = (n * 6) - 1;
|
||||
if(!is_prime(x)) x = (n * 6) + 1;
|
||||
if(!is_prime(x)) { ++n; continue; }
|
||||
return std::max(x, 7ull);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, class Hash, class Alloc>
|
||||
typename hash_table<T, Hash, Alloc>::size_type hash_table<T, Hash, Alloc>::_prev_prime(size_type x)
|
||||
{
|
||||
size_type n = (x + 1) / 6;
|
||||
n *= 2;
|
||||
|
||||
while(true)
|
||||
{
|
||||
x = (n * 6) - 1;
|
||||
if(!is_prime(x)) x = (n * 6) + 1;
|
||||
if(!is_prime(x)) { --n; continue; }
|
||||
return std::max(x, 7ull);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //HASH_TABLE_H
|
100
External/open-cpp-utils/map.h
vendored
Normal file
100
External/open-cpp-utils/map.h
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
// =====================================================================================================================
|
||||
// Copyright 2024 Medusa Slockbower
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef MAP_H
|
||||
#define MAP_H
|
||||
#include "set.h"
|
||||
|
||||
namespace open_cpp_utils
|
||||
{
|
||||
|
||||
template<typename Key, typename Value, class Alloc = std::allocator<std::pair<Key, Value>>>
|
||||
class map
|
||||
{
|
||||
// Typedefs ============================================================================================================
|
||||
|
||||
public:
|
||||
struct hash { size_t operator()(const pair_type& pair) const { return std::hash<key_type>{}(pair.first); } };
|
||||
|
||||
using key_type = Key;
|
||||
using value_type = Value;
|
||||
using pair_type = std::pair<key_type, value_type>;
|
||||
using table_type = set<pair_type, hash, Alloc>;
|
||||
|
||||
using key_pointer = key_type*;
|
||||
using const_key_pointer = const key_type*;
|
||||
using key_reference = key_type&;
|
||||
using const_key_reference = const key_type&;
|
||||
|
||||
using value_pointer = value_type*;
|
||||
using const_value_pointer = const value_type*;
|
||||
using value_reference = value_type&;
|
||||
using const_value_reference = const value_type&;
|
||||
|
||||
using iterator = typename table_type::iterator;
|
||||
|
||||
|
||||
// Functions ===========================================================================================================
|
||||
|
||||
// Constructors & Destructor -------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
map() = default;
|
||||
map(const map&) = default;
|
||||
map(map&&) = default;
|
||||
~map() = default;
|
||||
|
||||
void insert(const_key_reference key, const_value_reference value);
|
||||
void erase(const_key_reference key);
|
||||
value_reference& operator[](const_key_reference key);
|
||||
iterator find() { return table_->find(); }
|
||||
bool contains(const_key_reference key) { return table_.contains({ key, value_type() }); }
|
||||
|
||||
iterator begin() { return table_.begin(); }
|
||||
iterator end() { return table_.end(); }
|
||||
|
||||
// Variables ===========================================================================================================
|
||||
|
||||
private:
|
||||
set<pair_type, hash, Alloc> table_;
|
||||
};
|
||||
|
||||
template<typename Key, typename Value, class Alloc>
|
||||
void map<Key, Value, Alloc>::insert(const_key_reference key, const_value_reference value)
|
||||
{
|
||||
iterator it = find({ key, value });
|
||||
if(it != end()) table_.insert({ key, value });
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, class Alloc>
|
||||
void map<Key, Value, Alloc>::erase(const_key_reference key)
|
||||
{
|
||||
table_.erase({ key, value_type() });
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, class Alloc>
|
||||
typename map<Key, Value, Alloc>::value_reference map<Key, Value, Alloc>::operator[](const_key_reference key)
|
||||
{
|
||||
iterator it = table_.find({ key, value_type() });
|
||||
if(it == table_.end())
|
||||
{
|
||||
table_.insert({ key, value_type() });
|
||||
it = table_.find({ key, value_type() });
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //MAP_H
|
42
External/open-cpp-utils/math.h
vendored
Normal file
42
External/open-cpp-utils/math.h
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
// =====================================================================================================================
|
||||
// Copyright 2024 Medusa Slockbower
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef MATH_H
|
||||
#define MATH_H
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace open_cpp_utils
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
bool is_prime(T x)
|
||||
{
|
||||
if(x <= 1) return false;
|
||||
if(x == 2 || x == 3) return true;
|
||||
if(x % 2 == 0 || x % 3 == 0) return false;
|
||||
|
||||
T limit = sqrt(x);
|
||||
for(T i = 5; i <= limit; i += 6)
|
||||
{
|
||||
if(x % i == 0 || x % (i + 2) == 0) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //MATH_H
|
82
External/open-cpp-utils/object_pool.h
vendored
82
External/open-cpp-utils/object_pool.h
vendored
@ -16,18 +16,18 @@
|
||||
#ifndef OBJECT_POOL_H
|
||||
#define OBJECT_POOL_H
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "template_utils.h"
|
||||
#include "dynarray.h"
|
||||
#include "optional.h"
|
||||
|
||||
namespace open_cpp_utils
|
||||
{
|
||||
|
||||
template<typename T, typename _Hash = std::unordered_map<uint64_t, int64_t>>
|
||||
class object_pool
|
||||
/**
|
||||
* \brief
|
||||
* \tparam T
|
||||
*/
|
||||
template<typename T>
|
||||
class object_list
|
||||
{
|
||||
// Typedefs ============================================================================================================
|
||||
|
||||
@ -38,17 +38,10 @@ public:
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
|
||||
using index_type = int64_t;
|
||||
using uuid_type = uint64_t;
|
||||
|
||||
private:
|
||||
using node = std::tuple<value_type, bool>;
|
||||
|
||||
|
||||
// Constants ===========================================================================================================
|
||||
|
||||
public:
|
||||
static constexpr std::integral_constant<index_type, -1> nullidx{};
|
||||
using node = optional<value_type>;
|
||||
|
||||
|
||||
// Functions ===========================================================================================================
|
||||
@ -57,33 +50,62 @@ public:
|
||||
|
||||
// Constructors & Destructor -------------------------------------------------------------------------------------------
|
||||
|
||||
object_pool();
|
||||
object_list() = default;
|
||||
object_list(const object_list& other) = default;
|
||||
object_list(object_list&& other) = default;
|
||||
~object_list() = default;
|
||||
|
||||
void clear();
|
||||
void reset();
|
||||
void cleanup();
|
||||
|
||||
// Modifiers -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
size_t size() { return data_.size(); }
|
||||
|
||||
|
||||
// Modifiers -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
void clear() { data_.clear(); freed_.clear(); }
|
||||
|
||||
uuid_type insert(const_reference& value);
|
||||
void erase(uuid_type id);
|
||||
void erase(index_type idx);
|
||||
|
||||
object_list& operator=(const object_list&) = default;
|
||||
object_list& operator=(object_list&&) = default;
|
||||
|
||||
|
||||
// Accessors -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
reference operator[](uuid_type id);
|
||||
const_reference operator[](uuid_type id) const;
|
||||
bool operator()(uuid_type id) const;
|
||||
reference operator[](uuid_type id) { assert(data_[id]()); return data_[id]; }
|
||||
const_reference operator[](uuid_type id) const { assert(data_[id]()); return data_[id]; }
|
||||
bool operator()(uuid_type id) const { return data_[id](); }
|
||||
|
||||
reference operator[](index_type idx);
|
||||
const_reference operator[](index_type idx) const;
|
||||
bool operator()(index_type idx) const;
|
||||
typename dynarray<node>::iterator begin() { return data_.begin(); }
|
||||
typename dynarray<node>::iterator end() { return data_.end(); }
|
||||
|
||||
|
||||
// Variables ===========================================================================================================
|
||||
|
||||
private:
|
||||
std::vector<node> data_;
|
||||
_Hash map_;
|
||||
std::stack<index_type> freed_;
|
||||
dynarray<node> data_;
|
||||
dynarray<uuid_type> freed_;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
typename object_list<T>::uuid_type object_list<T>::insert(const_reference value)
|
||||
{
|
||||
if(freed_.empty()) { data_.push_back(value); return data_.size() - 1; }
|
||||
|
||||
uuid_type id = freed_.back(); freed_.pop_back();
|
||||
data_[id] = value;
|
||||
return id;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void object_list<T>::erase(uuid_type id)
|
||||
{
|
||||
data_[id].reset();
|
||||
freed_.push_back(id);
|
||||
}
|
||||
|
||||
} // open_cpp_utils
|
||||
|
||||
#endif //OBJECT_POOL_H
|
||||
|
2
External/open-cpp-utils/optional.h
vendored
2
External/open-cpp-utils/optional.h
vendored
@ -26,7 +26,7 @@ namespace open_cpp_utils
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
optional() : data_(), valid_(false) { }
|
||||
optional() : valid_(false) { }
|
||||
optional(const value_type& data) : data_(data), valid_(true) { }
|
||||
optional(value_type&& data) : data_(data), valid_(true) { }
|
||||
optional(const optional& other) = default;
|
||||
|
21
External/open-cpp-utils/redec.h
vendored
Normal file
21
External/open-cpp-utils/redec.h
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// =====================================================================================================================
|
||||
// Copyright 2024 Medusa Slockbower
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef REDEC_H
|
||||
#define REDEC_H
|
||||
|
||||
#include "dynarray.h"
|
||||
|
||||
#endif //REDEC_H
|
28
External/open-cpp-utils/set.h
vendored
Normal file
28
External/open-cpp-utils/set.h
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
// =====================================================================================================================
|
||||
// Copyright 2024 Medusa Slockbower
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef SET_H
|
||||
#define SET_H
|
||||
|
||||
#include "hash_table.h"
|
||||
|
||||
namespace open_cpp_utils
|
||||
{
|
||||
|
||||
template<typename T, class Hash = std::hash<T>, class Alloc = std::allocator<T>> using set = hash_table<T, Hash, Alloc>;
|
||||
|
||||
}
|
||||
|
||||
#endif //SET_H
|
@ -24,33 +24,111 @@ namespace ocu = open_cpp_utils;
|
||||
|
||||
namespace OpenShaderDesigner::Nodes::Math
|
||||
{
|
||||
inline static constexpr ImColor HeaderColor = ImColor(0x92, 0x16, 0x16);
|
||||
// Header Colors =======================================================================================================
|
||||
|
||||
struct Constant : public Node
|
||||
{
|
||||
inline static constexpr ImColor HeaderColor = ImColor(0xA7, 0x62, 0x53);
|
||||
inline static constexpr ImColor HeaderHoveredColor = ImColor(0xC5, 0x79, 0x67);
|
||||
inline static constexpr ImColor HeaderActiveColor = ImColor(0x82, 0x4C, 0x40);
|
||||
|
||||
inline static const std::string HeaderMarker = "\uF3B9 ";
|
||||
|
||||
|
||||
// =====================================================================================================================
|
||||
// Integral
|
||||
// =====================================================================================================================
|
||||
|
||||
struct Integral : public Node
|
||||
{
|
||||
using ValueType = ocu::any<int, unsigned int, float, glm::vec4>;
|
||||
|
||||
Constant(ShaderGraph& graph, ImVec2 pos);
|
||||
virtual ~Constant() = default;
|
||||
Integral(ShaderGraph& graph, ImVec2 pos);
|
||||
virtual ~Integral() = default;
|
||||
|
||||
[[nodiscard]] Node* Copy(ShaderGraph& graph) const override;
|
||||
void Inspect() override;
|
||||
|
||||
ValueType Value;
|
||||
};
|
||||
};
|
||||
|
||||
RegisterNode("Math/Constant", Constant);
|
||||
RegisterNode("Math/Constants/Integral", Integral);
|
||||
|
||||
struct Add : public Node
|
||||
{
|
||||
|
||||
// =====================================================================================================================
|
||||
// Unsigned Integral
|
||||
// =====================================================================================================================
|
||||
|
||||
struct UnsignedIntegral : public Node
|
||||
{
|
||||
using ValueType = ocu::any<int, unsigned int, float, glm::vec4>;
|
||||
|
||||
UnsignedIntegral(ShaderGraph& graph, ImVec2 pos);
|
||||
virtual ~UnsignedIntegral() = default;
|
||||
|
||||
[[nodiscard]] Node* Copy(ShaderGraph& graph) const override;
|
||||
void Inspect() override;
|
||||
|
||||
ValueType Value;
|
||||
};
|
||||
|
||||
RegisterNode("Math/Constants/Unsigned Integral", UnsignedIntegral);
|
||||
|
||||
|
||||
// =====================================================================================================================
|
||||
// Scalar
|
||||
// =====================================================================================================================
|
||||
|
||||
struct Scalar : public Node
|
||||
{
|
||||
using ValueType = ocu::any<int, unsigned int, float, glm::vec4>;
|
||||
|
||||
Scalar(ShaderGraph& graph, ImVec2 pos);
|
||||
virtual ~Scalar() = default;
|
||||
|
||||
[[nodiscard]] Node* Copy(ShaderGraph& graph) const override;
|
||||
void Inspect() override;
|
||||
|
||||
ValueType Value;
|
||||
};
|
||||
|
||||
RegisterNode("Math/Constants/Scalar", Scalar);
|
||||
|
||||
|
||||
// =====================================================================================================================
|
||||
// Vector
|
||||
// =====================================================================================================================
|
||||
|
||||
struct Vector : public Node
|
||||
{
|
||||
using ValueType = ocu::any<int, unsigned int, float, glm::vec4>;
|
||||
|
||||
Vector(ShaderGraph& graph, ImVec2 pos);
|
||||
virtual ~Vector() = default;
|
||||
|
||||
[[nodiscard]] Node* Copy(ShaderGraph& graph) const override;
|
||||
void Inspect() override;
|
||||
|
||||
ValueType Value;
|
||||
};
|
||||
|
||||
RegisterNode("Math/Constants/Vector", Vector);
|
||||
|
||||
|
||||
// =====================================================================================================================
|
||||
// Add
|
||||
// =====================================================================================================================
|
||||
|
||||
|
||||
struct Add : public Node
|
||||
{
|
||||
Add(ShaderGraph& graph, ImVec2 pos);
|
||||
virtual ~Add() = default;
|
||||
|
||||
[[nodiscard]] Node* Copy(ShaderGraph& graph) const override;
|
||||
void Inspect() override;
|
||||
};
|
||||
};
|
||||
|
||||
RegisterNode("Math/Operators/Add", Add);
|
||||
|
||||
RegisterNode("Math/Add", Add);
|
||||
}
|
||||
|
||||
#endif //MATH_H
|
||||
|
@ -29,6 +29,11 @@
|
||||
#include <open-cpp-utils/directed_tree.h>
|
||||
#include <open-cpp-utils/optional.h>
|
||||
|
||||
#include <imnode-graph/imnode_graph.h>
|
||||
|
||||
#include "open-cpp-utils/any.h"
|
||||
#include "open-cpp-utils/object_pool.h"
|
||||
|
||||
namespace ocu = open_cpp_utils;
|
||||
|
||||
#define RegisterNode(Name, Type) \
|
||||
@ -38,67 +43,57 @@ namespace ocu = open_cpp_utils;
|
||||
namespace OpenShaderDesigner
|
||||
{
|
||||
class ShaderGraph;
|
||||
using PinId = uint16_t;
|
||||
using NodeId = uint32_t;
|
||||
|
||||
struct PinPtr
|
||||
using PinType = int;
|
||||
enum PinType_
|
||||
{
|
||||
struct Hash
|
||||
{
|
||||
size_t operator()(const PinPtr& p) const
|
||||
{
|
||||
return p.hash();
|
||||
}
|
||||
PinType_Int = 0
|
||||
, PinType_UInt
|
||||
, PinType_Float
|
||||
, PinType_Vector
|
||||
|
||||
, PinType_Any
|
||||
, PinType_COUNT
|
||||
};
|
||||
|
||||
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 PinFlags = unsigned int;
|
||||
enum PinFlags_
|
||||
{
|
||||
PinFlags_None = 0
|
||||
, PinFlags_NoCollapse = 1 << 0
|
||||
, PinFlags_NoPadding = 1 << 1
|
||||
};
|
||||
|
||||
struct Pin
|
||||
{
|
||||
enum PinType
|
||||
{
|
||||
INT = 0
|
||||
, UINT
|
||||
, FLOAT
|
||||
, VECTOR
|
||||
|
||||
, ANY
|
||||
, COUNT
|
||||
inline const static ImColor Colors[PinType_COUNT] = {
|
||||
ImColor(0x64, 0x94, 0xAA) // Int
|
||||
, ImColor(0x7A, 0x9F, 0x82) // Unsigned Int
|
||||
, ImColor(0xA6, 0x3D, 0x40) // Float
|
||||
, ImColor(0xE9, 0xB8, 0x72) // Vector
|
||||
, ImColor(0xD2, 0xD5, 0xD3) // Any
|
||||
};
|
||||
|
||||
enum PinDirection
|
||||
{
|
||||
INPUT
|
||||
, OUTPUT
|
||||
};
|
||||
|
||||
inline const static ImColor Colors[COUNT] = {
|
||||
ImColor(0xB9, 0xF5, 0x94)
|
||||
, ImColor(0x8C, 0xC0, 0x8C)
|
||||
, ImColor(0x37, 0x95, 0x85)
|
||||
, ImColor(0xE3, 0x7D, 0xDC)
|
||||
// , ImColor(0xD2, 0x6E, 0x46)
|
||||
, ImColor(0xD2, 0xD5, 0xD3)
|
||||
};
|
||||
|
||||
inline const static std::string TypeNames[COUNT] = {
|
||||
inline const static std::string TypeNames[PinType_COUNT] = {
|
||||
"Int"
|
||||
, "Unsigned Int"
|
||||
, "Float"
|
||||
, "Vector"
|
||||
, "Any"
|
||||
};
|
||||
|
||||
using Ambiguous = ocu::any<int, unsigned int, float, ImVec4>;
|
||||
|
||||
std::string Name;
|
||||
PinType Type;
|
||||
PinDirection Direction;
|
||||
PinFlags Flags;
|
||||
Ambiguous Value;
|
||||
|
||||
Pin(const std::string& name, PinType type, PinFlags flags = PinFlags_None)
|
||||
: Name(name)
|
||||
, Type(type)
|
||||
, Flags(flags)
|
||||
{ }
|
||||
};
|
||||
|
||||
struct Node
|
||||
@ -108,31 +103,28 @@ namespace OpenShaderDesigner
|
||||
|
||||
struct
|
||||
{
|
||||
std::string Title = "Node";
|
||||
ImColor Color = Pin::Colors[Pin::VECTOR];
|
||||
bool Enabled = true;
|
||||
std::string Title;
|
||||
ImColor Color, HoveredColor, ActiveColor;
|
||||
bool Enabled;
|
||||
} Header;
|
||||
|
||||
struct
|
||||
{
|
||||
std::vector<Pin> Inputs, Outputs;
|
||||
bool DynamicInputs = false;
|
||||
bool DynamicInputs;
|
||||
} IO;
|
||||
|
||||
struct
|
||||
{
|
||||
ImVec2 Size;
|
||||
bool Const;
|
||||
} Info;
|
||||
|
||||
Node(
|
||||
ShaderGraph& graph, ImVec2 pos
|
||||
, const std::string& title, ImColor color
|
||||
, const std::vector<Pin>& inputs, bool dyn_inputs
|
||||
, const std::vector<Pin>& outputs
|
||||
, bool constant = false);
|
||||
Node(ShaderGraph& graph, ImVec2 pos);
|
||||
~Node() = default;
|
||||
|
||||
void DrawPin(ImGuiID id, Pin& pin, ImPinDirection direction);
|
||||
void Draw(ImGuiID id);
|
||||
|
||||
virtual Node* Copy(ShaderGraph& graph) const = 0;
|
||||
virtual void Inspect() = 0;
|
||||
};
|
||||
@ -143,15 +135,6 @@ namespace OpenShaderDesigner
|
||||
private:
|
||||
friend Node;
|
||||
|
||||
using Connection = std::pair<const PinPtr, PinPtr>;
|
||||
using ConnectionMap = std::unordered_multimap<PinPtr, PinPtr, PinPtr::Hash>;
|
||||
|
||||
struct Line
|
||||
{
|
||||
ImColor Color;
|
||||
float Thickness;
|
||||
};
|
||||
|
||||
using ConstructorPtr = Node*(*)(ShaderGraph&, ImVec2);
|
||||
struct ContextMenuItem
|
||||
{
|
||||
@ -162,9 +145,7 @@ namespace OpenShaderDesigner
|
||||
struct GraphState
|
||||
{
|
||||
ShaderGraph& Parent;
|
||||
std::vector<Node*> Nodes;
|
||||
std::set<PinId> Erased;
|
||||
ConnectionMap Connections;
|
||||
ocu::object_list<Node*> Nodes;
|
||||
|
||||
GraphState(ShaderGraph& parent);
|
||||
GraphState(const GraphState& other);
|
||||
@ -177,49 +158,10 @@ namespace OpenShaderDesigner
|
||||
using ContextID = ContextMenuHierarchy::node;
|
||||
inline static ContextMenuHierarchy ContextMenu;
|
||||
|
||||
// Helper functions
|
||||
float CalculateWidth(Node& node);
|
||||
float CalculateHeight(Node& node);
|
||||
|
||||
// Base Draw and Input functions
|
||||
void HandleInput();
|
||||
void DrawGrid();
|
||||
void DrawNode(Node& node, NodeId id);
|
||||
void DrawPin(NodeId node_id, Pin& pin, PinId pin_id, ImVec2 location, bool input);
|
||||
void DrawContextMenu();
|
||||
|
||||
// Connection functions
|
||||
void DrawConnections();
|
||||
void DrawConnection(const PinPtr& a, const PinPtr& b);
|
||||
auto StartConnection(const PinPtr& ptr) -> void;
|
||||
void StopConnection();
|
||||
void CreateConnection(const PinPtr& a, const PinPtr& b);
|
||||
void EraseConnection(const PinPtr& a, const PinPtr& b);
|
||||
void EraseConnections(const PinPtr& a);
|
||||
|
||||
NodeId AddNode(Node* node);
|
||||
void RemoveNode(NodeId id);
|
||||
|
||||
// Clipboard functionality
|
||||
void ClearClipboard();
|
||||
void Copy();
|
||||
void Paste(const ImVec2& location);
|
||||
void EraseSelection();
|
||||
|
||||
// History Functionality
|
||||
void PushState();
|
||||
void PopState();
|
||||
|
||||
// Helper functions
|
||||
float BezierOffset(const ImVec2& out, const ImVec2& in);
|
||||
bool AABB(const ImVec2& a0, const ImVec2& a1, const ImVec2& b0, const ImVec2& b1);
|
||||
|
||||
ImVec2 GridToScreen(const ImVec2& position);
|
||||
ImVec2 ScreenToGrid(const ImVec2& position);
|
||||
ImVec2 SnapToGrid(const ImVec2& position);
|
||||
|
||||
Pin& GetPin(const PinPtr& ptr);
|
||||
|
||||
public:
|
||||
ShaderGraph();
|
||||
~ShaderGraph();
|
||||
@ -227,6 +169,12 @@ namespace OpenShaderDesigner
|
||||
void OnOpen() override;
|
||||
void DrawWindow() override;
|
||||
|
||||
void DrawContextMenu();
|
||||
|
||||
void Copy();
|
||||
void Erase();
|
||||
void Paste(ImVec2 pos);
|
||||
|
||||
static void Register(const std::filesystem::path& path, ConstructorPtr constructor);
|
||||
|
||||
private:
|
||||
@ -235,83 +183,6 @@ namespace OpenShaderDesigner
|
||||
GraphState State;
|
||||
std::stack<GraphState> History;
|
||||
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
ImColor BackgroundColor;
|
||||
|
||||
struct
|
||||
{
|
||||
Line Thin, Thick;
|
||||
float Padding;
|
||||
} Lines;
|
||||
} Grid;
|
||||
|
||||
struct
|
||||
{
|
||||
float Rounding;
|
||||
Line Border, SelectedBorder;
|
||||
ImColor Content;
|
||||
ImColor Title;
|
||||
|
||||
struct
|
||||
{
|
||||
float Padding;
|
||||
float BorderThickness;
|
||||
ImColor Background;
|
||||
ImColor Text;
|
||||
Line Connections;
|
||||
} Pins;
|
||||
} Nodes;
|
||||
|
||||
struct
|
||||
{
|
||||
ImColor Background;
|
||||
Line Border;
|
||||
} Selection;
|
||||
|
||||
float FontSize;
|
||||
} Style;
|
||||
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
float Rate, Smoothing;
|
||||
} Scroll;
|
||||
} Input;
|
||||
} Settings;
|
||||
|
||||
struct
|
||||
{
|
||||
ImVec2 Location, ScreenLocation, Delta;
|
||||
float Scroll;
|
||||
bool ClickedSomething;
|
||||
|
||||
ocu::optional<NodeId> FocusedNode;
|
||||
std::unordered_map<NodeId, ImVec2> Locks;
|
||||
std::unordered_set<NodeId> DragSelect;
|
||||
bool LocksDragged, NodeHovered;
|
||||
ocu::optional<PinPtr> NewConnection;
|
||||
std::unordered_set<NodeId> Selected;
|
||||
} Mouse;
|
||||
|
||||
struct
|
||||
{
|
||||
ImVec2 Location;
|
||||
float Zoom, Scroll;
|
||||
} Camera;
|
||||
|
||||
struct
|
||||
{
|
||||
std::vector<Node*> Nodes;
|
||||
ConnectionMap Connections;
|
||||
} Clipboard;
|
||||
|
||||
bool Focused;
|
||||
ImVec2 ContextMenuPosition;
|
||||
|
||||
friend class Inspector;
|
||||
|
@ -19,73 +19,131 @@
|
||||
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 } }
|
||||
)
|
||||
|
||||
// =====================================================================================================================
|
||||
// Integral
|
||||
// =====================================================================================================================
|
||||
|
||||
Integral::Integral(ShaderGraph& graph, ImVec2 pos)
|
||||
: Node(graph, pos)
|
||||
{
|
||||
Header.Title = HeaderMarker + "Integral";
|
||||
Header.Color = HeaderColor;
|
||||
Header.HoveredColor = HeaderHoveredColor;
|
||||
Header.ActiveColor = HeaderActiveColor;
|
||||
|
||||
IO.Outputs.emplace_back("Out", PinType_Float, PinFlags_NoCollapse | PinFlags_NoPadding);
|
||||
}
|
||||
|
||||
Node* Constant::Copy(ShaderGraph& graph) const
|
||||
Node* Integral::Copy(ShaderGraph& graph) const
|
||||
{
|
||||
return new Constant(graph, Position);
|
||||
return new Integral(graph, Position);
|
||||
}
|
||||
|
||||
void Constant::Inspect()
|
||||
void Integral::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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// =====================================================================================================================
|
||||
// Scalar
|
||||
// =====================================================================================================================
|
||||
|
||||
UnsignedIntegral::UnsignedIntegral(ShaderGraph& graph, ImVec2 pos)
|
||||
: Node(graph, pos)
|
||||
{
|
||||
Header.Title = HeaderMarker + "Unsigned Integral";
|
||||
Header.Color = HeaderColor;
|
||||
Header.HoveredColor = HeaderHoveredColor;
|
||||
Header.ActiveColor = HeaderActiveColor;
|
||||
|
||||
IO.Outputs.emplace_back("Out", PinType_Float, PinFlags_NoCollapse | PinFlags_NoPadding);
|
||||
}
|
||||
|
||||
Node* UnsignedIntegral::Copy(ShaderGraph& graph) const
|
||||
{
|
||||
return new UnsignedIntegral(graph, Position);
|
||||
}
|
||||
|
||||
void UnsignedIntegral::Inspect()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// =====================================================================================================================
|
||||
// Scalar
|
||||
// =====================================================================================================================
|
||||
|
||||
Scalar::Scalar(ShaderGraph& graph, ImVec2 pos)
|
||||
: Node(graph, pos)
|
||||
{
|
||||
Header.Title = HeaderMarker + "Scalar";
|
||||
Header.Color = HeaderColor;
|
||||
Header.HoveredColor = HeaderHoveredColor;
|
||||
Header.ActiveColor = HeaderActiveColor;
|
||||
|
||||
IO.Outputs.emplace_back("Out", PinType_Float, PinFlags_NoCollapse | PinFlags_NoPadding);
|
||||
}
|
||||
|
||||
Node* Scalar::Copy(ShaderGraph& graph) const
|
||||
{
|
||||
return new Scalar(graph, Position);
|
||||
}
|
||||
|
||||
void Scalar::Inspect()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// =====================================================================================================================
|
||||
// Vector
|
||||
// =====================================================================================================================
|
||||
|
||||
Vector::Vector(ShaderGraph &graph, ImVec2 pos)
|
||||
: Node(graph, pos)
|
||||
{
|
||||
Header.Title = HeaderMarker + "Vector";
|
||||
Header.Color = HeaderColor;
|
||||
Header.HoveredColor = HeaderHoveredColor;
|
||||
Header.ActiveColor = HeaderActiveColor;
|
||||
|
||||
IO.Outputs.emplace_back("Out", PinType_Vector, PinFlags_NoCollapse | PinFlags_NoPadding);
|
||||
|
||||
IO.Outputs[0].Value.get<ImVec4>() = ImVec4(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
Node* Vector::Copy(ShaderGraph &graph) const
|
||||
{
|
||||
return new Vector(graph, Position);
|
||||
}
|
||||
|
||||
void Vector::Inspect()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// =====================================================================================================================
|
||||
// Add
|
||||
// =====================================================================================================================
|
||||
|
||||
Add::Add(ShaderGraph& graph, ImVec2 pos)
|
||||
: Node(
|
||||
graph, pos
|
||||
, "Add", HeaderColor
|
||||
, { { "A", Pin::ANY, Pin::INPUT }, { "B", Pin::ANY, Pin::INPUT } }, true
|
||||
, { { "Out", Pin::ANY, Pin::OUTPUT } }
|
||||
)
|
||||
{ }
|
||||
: Node(graph, pos)
|
||||
{
|
||||
Header.Title = HeaderMarker + "Add";
|
||||
Header.Color = HeaderColor;
|
||||
Header.HoveredColor = HeaderHoveredColor;
|
||||
Header.ActiveColor = HeaderActiveColor;
|
||||
|
||||
IO.Inputs.emplace_back("A", PinType_Any);
|
||||
IO.Inputs.emplace_back("B", PinType_Any);
|
||||
IO.DynamicInputs = true;
|
||||
|
||||
IO.Outputs.emplace_back("B", PinType_Any);
|
||||
}
|
||||
|
||||
Node* Add::Copy(ShaderGraph& graph) const
|
||||
{
|
||||
|
@ -17,15 +17,15 @@
|
||||
#include <filesystem>
|
||||
#include <stack>
|
||||
|
||||
#include <Core/Engine.h>
|
||||
#include <Core/Console.h>
|
||||
#include <Editor/EditorSystem.h>
|
||||
|
||||
#include <glm/common.hpp>
|
||||
#include <Graph/ShaderGraph.h>
|
||||
|
||||
#include <imgui-docking/imgui_internal.h>
|
||||
|
||||
#include <imnode-graph/imnode_graph.h>
|
||||
#include "imgui-extras/imgui_extras.h"
|
||||
|
||||
|
||||
using namespace OpenShaderDesigner;
|
||||
|
||||
@ -41,15 +41,11 @@ ShaderGraph::GraphState::GraphState(ShaderGraph& parent)
|
||||
|
||||
ShaderGraph::GraphState::GraphState(const GraphState& other)
|
||||
: Parent(other.Parent)
|
||||
, Nodes(other.Nodes.size(), nullptr)
|
||||
, Connections(other.Connections)
|
||||
, Erased(other.Erased)
|
||||
, Nodes(other.Nodes)
|
||||
{
|
||||
NodeId id = 0;
|
||||
for(const Node* node : other.Nodes)
|
||||
for(Node*& node : Nodes)
|
||||
{
|
||||
if(node) Nodes[id] = node->Copy(Parent);
|
||||
++id;
|
||||
node = node->Copy(Parent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,153 +59,107 @@ ShaderGraph::GraphState::~GraphState()
|
||||
|
||||
ShaderGraph::GraphState& ShaderGraph::GraphState::operator=(const GraphState& other)
|
||||
{
|
||||
for(Node* node : Nodes)
|
||||
{
|
||||
if(node) delete node;
|
||||
}
|
||||
Nodes = other.Nodes;
|
||||
|
||||
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;
|
||||
for(Node*& node : Nodes) if(node) node = node->Copy(Parent);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
float ShaderGraph::CalculateWidth(Node& node)
|
||||
{
|
||||
const float GridSize = Style.FontSize + Style.Grid.Lines.Padding;
|
||||
const float HeaderHeight = Style.FontSize;
|
||||
const float HeaderWidth = ImGui::CalcTextSize(node.Header.Title.c_str()).x;
|
||||
float InputWidth = 0.0f, OutputWidth = 0.0f;
|
||||
|
||||
// Longest Input Pin
|
||||
for(const Pin& pin : node.IO.Inputs)
|
||||
{
|
||||
InputWidth = glm::max(InputWidth, HeaderHeight + ImGui::CalcTextSize(pin.Name.c_str()).x);
|
||||
}
|
||||
|
||||
// Longest Output Pin
|
||||
for(const Pin& pin : node.IO.Outputs)
|
||||
{
|
||||
OutputWidth = glm::max(OutputWidth, HeaderHeight + ImGui::CalcTextSize(pin.Name.c_str()).x);
|
||||
}
|
||||
|
||||
float Width = glm::max(InputWidth + OutputWidth, HeaderWidth) + HeaderHeight;
|
||||
Width += GridSize - std::fmod(1.0f + Style.Grid.Lines.Padding + Width, GridSize);
|
||||
|
||||
return Width;
|
||||
}
|
||||
|
||||
float ShaderGraph::CalculateHeight(Node& node)
|
||||
{
|
||||
const float HeaderHeight = Style.FontSize;
|
||||
const float PinHeight = HeaderHeight * static_cast<float>(1 + glm::max(node.IO.Inputs.size(), node.IO.Outputs.size()));
|
||||
return glm::max(HeaderHeight + PinHeight, 2 * HeaderHeight);
|
||||
}
|
||||
|
||||
Node::Node(
|
||||
ShaderGraph& graph, ImVec2 pos
|
||||
, const std::string& title, ImColor color
|
||||
, const std::vector<Pin>& inputs, bool dyn_inputs
|
||||
, const std::vector<Pin>& outputs, bool constant)
|
||||
ShaderGraph& graph, ImVec2 pos)
|
||||
: Position(pos)
|
||||
, Header
|
||||
{
|
||||
.Title = title
|
||||
, .Color = color
|
||||
.Title = "Node"
|
||||
, .Color = ImColor(0xA7, 0x62, 0x53)
|
||||
, .HoveredColor = ImColor(0xC5, 0x79, 0x67)
|
||||
, .ActiveColor = ImColor(0x82, 0x4C, 0x40)
|
||||
, .Enabled = true
|
||||
}
|
||||
, IO
|
||||
{
|
||||
.Inputs = inputs
|
||||
, .Outputs = outputs
|
||||
, .DynamicInputs = dyn_inputs
|
||||
.DynamicInputs = false
|
||||
}
|
||||
, Info
|
||||
{
|
||||
.Size = ImVec2(graph.CalculateWidth(*this), graph.CalculateHeight(*this))
|
||||
, .Const = constant
|
||||
.Const = false
|
||||
}
|
||||
{ }
|
||||
|
||||
void Node::DrawPin(ImGuiID id, Pin& pin, ImPinDirection direction)
|
||||
{
|
||||
ImPinFlags flags = 0;
|
||||
if(pin.Flags & PinFlags_NoPadding) flags |= ImPinFlags_NoPadding;
|
||||
|
||||
ImNodeGraph::BeginPin(std::format("{}##{}", pin.Name, id).c_str(), pin.Type, direction, flags);
|
||||
|
||||
bool connected = ImNodeGraph::IsPinConnected();
|
||||
|
||||
if((connected || pin.Type == PinType_Any) && !(pin.Flags & PinFlags_NoCollapse))
|
||||
{
|
||||
ImGui::Text(pin.Name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (pin.Type)
|
||||
{
|
||||
case PinType_Int:
|
||||
ImNodeGraph::PushItemWidth(200.0f);
|
||||
ImGui::InputInt(std::format("##in{}{}", pin.Name, id).c_str(), pin.Value); break;
|
||||
case PinType_UInt:
|
||||
ImNodeGraph::PushItemWidth(200.0f);
|
||||
ImGui::InputUInt(std::format("##in{}{}", pin.Name, id).c_str(), pin.Value); break;
|
||||
case PinType_Float:
|
||||
ImNodeGraph::PushItemWidth(100.0f);
|
||||
ImGui::InputFloat(std::format("##in{}{}", pin.Name, id).c_str(), pin.Value); break;
|
||||
case PinType_Vector:
|
||||
ImGui::BeginGroup();
|
||||
|
||||
// Color Picker
|
||||
ImNodeGraph::PushItemWidth(150.0f);
|
||||
ImGui::ColorPicker4(
|
||||
std::format("##in{}{}", pin.Name, id).c_str(), &pin.Value.get<ImVec4>().x
|
||||
, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_Float
|
||||
);
|
||||
|
||||
ImNodeGraph::PushItemWidth(150.0f);
|
||||
ImGui::ColorPreview(
|
||||
std::format("##invec{}{}", pin.Name, id).c_str(), &pin.Value.get<ImVec4>().x
|
||||
, ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_Float
|
||||
);
|
||||
|
||||
ImGui::EndGroup();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ImNodeGraph::EndPin();
|
||||
}
|
||||
|
||||
void Node::Draw(ImGuiID id)
|
||||
{
|
||||
ImNodeGraph::BeginNode(id, Position);
|
||||
|
||||
if(Header.Enabled)
|
||||
{
|
||||
ImNodeGraph::BeginNodeHeader(id, Header.Color, Header.HoveredColor, Header.ActiveColor);
|
||||
|
||||
ImGui::Text(Header.Title.c_str());
|
||||
|
||||
ImNodeGraph::EndNodeHeader();
|
||||
}
|
||||
|
||||
for(Pin& pin : IO.Inputs) DrawPin(id, pin, ImPinDirection_Input);
|
||||
for(Pin& pin : IO.Outputs) DrawPin(id, pin, ImPinDirection_Output);
|
||||
|
||||
ImNodeGraph::EndNode();
|
||||
}
|
||||
|
||||
ShaderGraph::ShaderGraph()
|
||||
: EditorWindow("\uED46 Shader Graph", 0)
|
||||
, GrabFocus(false)
|
||||
, State(*this)
|
||||
, Style
|
||||
{
|
||||
.Grid
|
||||
{
|
||||
.BackgroundColor = ImColor(0x11, 0x11, 0x11)
|
||||
, .Lines
|
||||
{
|
||||
.Thin
|
||||
{
|
||||
.Color = ImColor(0x44, 0x44, 0x44)
|
||||
, .Thickness = 1.0
|
||||
}
|
||||
, .Thick
|
||||
{
|
||||
.Color = ImColor(0x88, 0x88, 0x88)
|
||||
, .Thickness = 2.0
|
||||
}
|
||||
, .Padding = 2.0f
|
||||
}
|
||||
}
|
||||
, .Nodes
|
||||
{
|
||||
.Rounding = 5.0f
|
||||
, .Border = { ImColor(0x33, 0x33, 0x33), 2.0f }
|
||||
, .SelectedBorder = { ImColor(0xEF, 0xAE, 0x4B), 4.0f }
|
||||
, .Content = ImColor(0x88, 0x88, 0x88)
|
||||
, .Title = ImColor(0xCC, 0xCC, 0xCC)
|
||||
, .Pins
|
||||
{
|
||||
.Padding = 2.0f
|
||||
, .BorderThickness = 3.0f
|
||||
, .Background = ImColor(0x22, 0x22, 0x22)
|
||||
, .Text = ImColor(0x22, 0x22, 0x22)
|
||||
, .Connections
|
||||
{
|
||||
.Color = ImColor(0x00, 0x00, 0x00)
|
||||
, .Thickness = 2.0f
|
||||
}
|
||||
}
|
||||
}
|
||||
, .Selection
|
||||
{
|
||||
.Background = ImColor(0xC9, 0x8E, 0x36, 0x44)
|
||||
, .Border
|
||||
{
|
||||
.Color = ImColor(0xEF, 0xAE, 0x4B, 0xBB)
|
||||
, .Thickness = 2.0f
|
||||
}
|
||||
}
|
||||
, .FontSize = 20.0f
|
||||
}
|
||||
, Settings
|
||||
{
|
||||
.Input
|
||||
{
|
||||
.Scroll
|
||||
{
|
||||
.Rate = 0.2f
|
||||
, .Smoothing = 8.0f
|
||||
}
|
||||
}
|
||||
}
|
||||
, Mouse({ 0, 0 }, { 0, 0 })
|
||||
, Camera({ 0, 0 }, 1)
|
||||
, Focused(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -219,9 +169,6 @@ ShaderGraph::~ShaderGraph()
|
||||
|
||||
void ShaderGraph::OnOpen()
|
||||
{
|
||||
Mouse.Location = ImGui::GetMousePos();
|
||||
Camera.Scroll = Camera.Zoom = 1.0f;
|
||||
|
||||
EditorSystem::Open<Inspector>()->Graph = this;
|
||||
|
||||
GrabFocus = true;
|
||||
@ -230,7 +177,6 @@ void ShaderGraph::OnOpen()
|
||||
|
||||
void ShaderGraph::DrawWindow()
|
||||
{
|
||||
static int test_in, test_out;
|
||||
ImNodeGraph::BeginGraph("ShaderGraph");
|
||||
ImNodeGraph::SetPinColors(Pin::Colors);
|
||||
|
||||
@ -241,56 +187,173 @@ void ShaderGraph::DrawWindow()
|
||||
ImGui::SetNavWindow(ImGui::GetCurrentWindow());
|
||||
}
|
||||
|
||||
// First Test Node
|
||||
for(ImGuiID id = 0; id < State.Nodes.size(); ++id)
|
||||
{
|
||||
ImVec2 pos = { 0, 0 };
|
||||
if(State.Nodes(id) == false) continue;
|
||||
|
||||
ImNodeGraph::BeginNode(0, pos);
|
||||
|
||||
ImNodeGraph::BeginNodeHeader(-1, ImColor(0xA7, 0x62, 0x53), ImColor(0xC5, 0x79, 0x67), ImColor(0x82, 0x4C, 0x40));
|
||||
ImGui::Text("\uf1f5 Hello");
|
||||
ImNodeGraph::EndNodeHeader();
|
||||
|
||||
ImNodeGraph::BeginPin(1, Pin::INT, ImPinDirection_Input);
|
||||
ImGui::PushItemWidth(100 * ImNodeGraph::GetCameraScale());
|
||||
ImGui::InputInt("##In", &test_in, 0);
|
||||
//ImGui::Text("In");
|
||||
ImNodeGraph::EndPin();
|
||||
|
||||
ImNodeGraph::BeginPin(2, Pin::ANY, ImPinDirection_Output);
|
||||
ImGui::Text("Out");
|
||||
ImNodeGraph::EndPin();
|
||||
|
||||
ImNodeGraph::EndNode();
|
||||
State.Nodes[id]->Draw(id);
|
||||
}
|
||||
|
||||
// Second Test Node
|
||||
{
|
||||
ImVec2 pos = { 300, 0 };
|
||||
|
||||
ImNodeGraph::BeginNode(3, pos);
|
||||
|
||||
ImNodeGraph::BeginNodeHeader(-1, ImColor(0xA7, 0x62, 0x53), ImColor(0xC5, 0x79, 0x67), ImColor(0x82, 0x4C, 0x40));
|
||||
ImGui::Text("\uf1f5 Hello");
|
||||
ImNodeGraph::EndNodeHeader();
|
||||
|
||||
ImNodeGraph::BeginPin(4, Pin::INT, ImPinDirection_Input);
|
||||
ImGui::PushItemWidth(100 * ImNodeGraph::GetCameraScale());
|
||||
ImGui::InputInt("##In", &test_in, 0);
|
||||
//ImGui::Text("In");
|
||||
ImNodeGraph::EndPin();
|
||||
|
||||
ImNodeGraph::BeginPin(5, Pin::ANY, ImPinDirection_Output);
|
||||
ImGui::Text("Out");
|
||||
ImNodeGraph::EndPin();
|
||||
|
||||
ImNodeGraph::EndNode();
|
||||
}
|
||||
DrawContextMenu();
|
||||
|
||||
ImNodeGraph::EndGraph();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
void ShaderGraph::DrawContextMenu()
|
||||
{
|
||||
if(ImGui::IsMouseClicked(ImGuiMouseButton_Right))
|
||||
{
|
||||
ContextMenuPosition = ImNodeGraph::ScreenToGrid(ImGui::GetMousePos());
|
||||
}
|
||||
|
||||
if(ImGui::BeginPopupContextWindow())
|
||||
{
|
||||
if(ImGui::MenuItem("Copy", "Ctrl+C", false, false)) Copy();
|
||||
if(ImGui::MenuItem("Cut", "Ctrl+X", false, false))
|
||||
{
|
||||
Copy();
|
||||
Erase();
|
||||
}
|
||||
if(ImGui::MenuItem("Paste", "Ctrl+V", false, false)) Paste(ContextMenuPosition);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Create");
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Create Nodes
|
||||
ImVec2 position = ContextMenuPosition;
|
||||
|
||||
std::stack<ContextID> context; context.push(0);
|
||||
|
||||
struct Visitor
|
||||
{
|
||||
bool operator()(ContextMenuItem& item, ContextID id)
|
||||
{
|
||||
const auto depth = Graph.ContextMenu.depth(id);
|
||||
if(depth > Context.size()) return false;
|
||||
|
||||
while(depth < Context.size())
|
||||
{
|
||||
Context.pop();
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if(Context.top() != Graph.ContextMenu.parent(id)) return false;
|
||||
std::string name = std::format("{}##{}", item.Name, id);
|
||||
|
||||
if(item.Constructor)
|
||||
{
|
||||
if(ImGui::MenuItem(item.Name.c_str()))
|
||||
{
|
||||
Graph.State.Nodes.insert(item.Constructor(Graph, Location));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ImGui::BeginMenu(item.Name.c_str()))
|
||||
{
|
||||
Context.push(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ShaderGraph& Graph;
|
||||
const ImVec2 Location;
|
||||
std::stack<ContextID>& Context;
|
||||
} MenuVisitor
|
||||
{
|
||||
.Graph = *this
|
||||
, .Location = position
|
||||
, .Context = context
|
||||
};
|
||||
|
||||
ContextMenu.traverse<ContextMenuHierarchy::pre_order>(MenuVisitor);
|
||||
|
||||
context.pop();
|
||||
while(context.empty() == false)
|
||||
{
|
||||
ImGui::EndMenu();
|
||||
context.pop();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderGraph::Copy() {}
|
||||
void ShaderGraph::Erase() {}
|
||||
void ShaderGraph::Paste(ImVec2) {}
|
||||
|
||||
void ShaderGraph::Register(const std::filesystem::path& path, ConstructorPtr constructor)
|
||||
{
|
||||
const std::string name = path.filename().string();
|
||||
|
||||
std::stack<std::string> decomp;
|
||||
std::filesystem::path current = path.parent_path();
|
||||
while(current.empty() == false)
|
||||
{
|
||||
decomp.push(current.filename().string());
|
||||
current = current.parent_path();
|
||||
}
|
||||
|
||||
ContextID node = 0;
|
||||
while(decomp.empty() == false)
|
||||
{
|
||||
ContextID child = ContextMenu.first_child(node);
|
||||
|
||||
while(child)
|
||||
{
|
||||
if(ContextMenu[child].Name == decomp.top())
|
||||
{
|
||||
node = child;
|
||||
decomp.pop();
|
||||
break;
|
||||
}
|
||||
|
||||
child = ContextMenu.next_sibling(child);
|
||||
}
|
||||
|
||||
if(node == 0 || node != child)
|
||||
{
|
||||
node = ContextMenu.insert({ decomp.top(), nullptr }, node);
|
||||
decomp.pop();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/** DEPRECATED
|
||||
void ShaderGraph::DrawWindow()
|
||||
{
|
||||
HandleInput();
|
||||
@ -340,7 +403,6 @@ void ShaderGraph::DrawWindow()
|
||||
Mouse.LocksDragged = false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void ShaderGraph::HandleInput()
|
||||
@ -732,98 +794,6 @@ void ShaderGraph::DrawPin(NodeId node_id, Pin& pin, PinId pin_id, ImVec2 locatio
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderGraph::DrawContextMenu()
|
||||
{
|
||||
const float GridSize = (Style.FontSize + Style.Grid.Lines.Padding);
|
||||
|
||||
if(ImGui::IsMouseClicked(ImGuiMouseButton_Right))
|
||||
{
|
||||
ContextMenuPosition = Mouse.Location;
|
||||
}
|
||||
|
||||
if(ImGui::BeginPopupContextWindow())
|
||||
{
|
||||
if(ImGui::MenuItem("Copy", "Ctrl+C", false, !Mouse.Selected.empty())) Copy();
|
||||
if(ImGui::MenuItem("Cut", "Ctrl+X", false, !Mouse.Selected.empty()))
|
||||
{
|
||||
Copy();
|
||||
EraseSelection();
|
||||
}
|
||||
if(ImGui::MenuItem("Paste", "Ctrl+V", false, !Clipboard.Nodes.empty())) Paste(ContextMenuPosition);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Create");
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Create Nodes
|
||||
ImVec2 position = ContextMenuPosition;
|
||||
position = SnapToGrid(position);
|
||||
|
||||
std::stack<ContextID> context; context.push(0);
|
||||
|
||||
struct Visitor
|
||||
{
|
||||
bool operator()(ContextMenuItem& item, ContextID id)
|
||||
{
|
||||
const auto depth = Graph.ContextMenu.depth(id);
|
||||
if(depth > Context.size()) return false;
|
||||
|
||||
while(depth < Context.size())
|
||||
{
|
||||
Context.pop();
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if(Context.top() != Graph.ContextMenu.parent(id)) return false;
|
||||
std::string name = std::format("{}##{}", item.Name, id);
|
||||
|
||||
if(item.Constructor)
|
||||
{
|
||||
if(ImGui::MenuItem(item.Name.c_str()))
|
||||
{
|
||||
Graph.AddNode(item.Constructor(Graph, Location));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ImGui::BeginMenu(item.Name.c_str()))
|
||||
{
|
||||
Context.push(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ShaderGraph& Graph;
|
||||
const ImVec2 Location;
|
||||
std::stack<ContextID>& Context;
|
||||
} MenuVisitor
|
||||
{
|
||||
.Graph = *this
|
||||
, .Location = position
|
||||
, .Context = context
|
||||
};
|
||||
|
||||
ContextMenu.traverse<ContextMenuHierarchy::pre_order>(MenuVisitor);
|
||||
|
||||
context.pop();
|
||||
while(context.empty() == false)
|
||||
{
|
||||
ImGui::EndMenu();
|
||||
context.pop();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderGraph::DrawConnections()
|
||||
{
|
||||
// Vars ============================================================================================================
|
||||
@ -1177,59 +1147,4 @@ 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)
|
||||
{
|
||||
const std::string name = path.filename().string();
|
||||
|
||||
std::stack<std::string> decomp;
|
||||
std::filesystem::path current = path.parent_path();
|
||||
while(current.empty() == false)
|
||||
{
|
||||
decomp.push(current.filename().string());
|
||||
current = current.parent_path();
|
||||
}
|
||||
|
||||
ContextID node = 0;
|
||||
while(decomp.empty() == false)
|
||||
{
|
||||
ContextID child = ContextMenu.first_child(node);
|
||||
|
||||
while(child)
|
||||
{
|
||||
if(ContextMenu[child].Name == decomp.top())
|
||||
{
|
||||
node = child;
|
||||
decomp.pop();
|
||||
break;
|
||||
}
|
||||
|
||||
child = ContextMenu.next_sibling(child);
|
||||
}
|
||||
|
||||
if(node == 0 || node != child)
|
||||
{
|
||||
node = ContextMenu.insert({ decomp.top(), nullptr }, node);
|
||||
decomp.pop();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
*/
|
14
imgui.ini
14
imgui.ini
@ -8,31 +8,31 @@ Size=400,400
|
||||
Collapsed=0
|
||||
|
||||
[Window][Dear ImGui Demo]
|
||||
Pos=359,275
|
||||
Pos=171,229
|
||||
Size=375,341
|
||||
Collapsed=0
|
||||
|
||||
[Window][ Console]
|
||||
Pos=303,905
|
||||
Pos=303,953
|
||||
Size=3137,464
|
||||
Collapsed=0
|
||||
DockId=0x00000004,0
|
||||
|
||||
[Window][ Profiler]
|
||||
Pos=0,905
|
||||
Pos=0,953
|
||||
Size=301,464
|
||||
Collapsed=0
|
||||
DockId=0x00000003,0
|
||||
|
||||
[Window][ Shader Graph]
|
||||
Pos=0,0
|
||||
Size=3068,903
|
||||
Size=3068,951
|
||||
Collapsed=0
|
||||
DockId=0x00000005,0
|
||||
|
||||
[Window][WindowOverViewport_11111111]
|
||||
Pos=0,0
|
||||
Size=3440,1369
|
||||
Size=3440,1417
|
||||
Collapsed=0
|
||||
|
||||
[Window][Example: Custom rendering]
|
||||
@ -65,12 +65,12 @@ Collapsed=0
|
||||
|
||||
[Window][Inspector]
|
||||
Pos=3070,0
|
||||
Size=370,903
|
||||
Size=370,951
|
||||
Collapsed=0
|
||||
DockId=0x00000006,0
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=3440,1369 Split=Y
|
||||
DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=3440,1417 Split=Y
|
||||
DockNode ID=0x00000001 Parent=0x7C6B3D9B SizeRef=3440,974 Split=X
|
||||
DockNode ID=0x00000005 Parent=0x00000001 SizeRef=3068,1417 CentralNode=1 Selected=0xD4C89E35
|
||||
DockNode ID=0x00000006 Parent=0x00000001 SizeRef=370,1417 Selected=0xE7039252
|
||||
|
Loading…
x
Reference in New Issue
Block a user