// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Core/Types/Variant.h" #include "Engine/Core/Collections/Array.h" #include "Engine/Visject/VisjectMeta.h" template class GraphNode; #define GRAPH_NODE_MAKE_TYPE(groupID, typeID) ((groupID) << 16 | (typeID)) #define GRAPH_NODE_MAX_VALUES 32 /// /// Represents single box of the graph node /// class GraphBox { public: /// /// The parent node /// void* Parent; /// /// Unique box ID within single node /// byte ID; /// /// The box type. /// VariantType Type; /// /// List with all connections to other boxes /// Array> Connections; public: GraphBox() : Parent(nullptr) , ID(0) { } /// /// Init /// /// Parent node /// Unique box id /// Connections type GraphBox(void* parent, byte id, const VariantType::Types type) : Parent(parent) , ID(id) , Type(type) { } /// /// Init /// /// Parent node /// Unique box id /// Connections type GraphBox(void* parent, byte id, const VariantType& type) : Parent(parent) , ID(id) , Type(type) { } public: /// /// Gets the parent node. /// template FORCE_INLINE NodeType* GetParent() const { return static_cast(Parent); } /// /// Returns true if box has one or more connections. /// FORCE_INLINE bool HasConnection() const { return Connections.HasItems(); } }; /// /// Visject graph node base /// template class GraphNode { public: typedef BoxType Box; typedef GraphNode Node; public: /// /// Unique node ID (within a graph). /// uint32 ID; union { struct { uint16 TypeID; uint16 GroupID; }; uint32 Type; }; /// /// List of all node values. Array size and value types are constant over time. Only value data can change. /// Array> Values; /// /// Node boxes cache. Array index matches the box ID (for fast O(1) lookups). /// Array Boxes; /// /// Additional metadata. /// VisjectMeta Meta; public: GraphNode() : ID(0) , Type(0) { } /// /// Destructor /// ~GraphNode() { } public: /// /// Gets all the valid boxes. /// /// The result container. template void GetBoxes(Array& result) { result.Clear(); for (int32 i = 0; i < Boxes.Count(); i++) { if (Boxes[i].Parent == this) { result.Add(&Boxes[i]); } } } /// /// Gets all the valid boxes. /// /// The result container. template void GetBoxes(Array& result) const { result.Clear(); for (int32 i = 0; i < Boxes.Count(); i++) { if (Boxes[i].Parent == this) { result.Add(&Boxes[i]); } } } /// /// Get box by ID /// /// Box ID /// Box Box* GetBox(int32 id) { ASSERT(Boxes.HasItems() && Boxes.Count() > id && Boxes[id].ID == id && Boxes[id].Parent == this); return &Boxes[id]; } /// /// Get box by ID, returns null if missing. /// /// Box ID /// Box Box* TryGetBox(int32 id) { if (id >= 0 && id < Boxes.Count() && Boxes[id].ID == id && Boxes[id].Parent == this) return &Boxes[id]; return nullptr; } /// /// Get box by ID /// /// Box ID /// Box const Box* GetBox(int32 id) const { ASSERT(Boxes.HasItems() && Boxes.Count() > id && Boxes[id].ID == id && Boxes[id].Parent == this); return &Boxes[id]; } };