// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Core/Log.h" #include "Engine/Core/Collections/Array.h" #include "VisjectMeta.h" #include "GraphNode.h" #include "GraphParameter.h" #include "Engine/Serialization/ReadStream.h" #include "Engine/Serialization/WriteStream.h" // [Deprecated on 31.07.2020, expires on 31.07.2022] extern FLAXENGINE_API void ReadOldGraphParamValue_Deprecated(byte graphParamType, ReadStream* stream, GraphParameter* param); extern FLAXENGINE_API void ReadOldGraphNodeValue_Deprecated(ReadStream* stream, Variant& result); extern FLAXENGINE_API void ReadOldGraphBoxType_Deprecated(uint32 connectionType, VariantType& type); extern FLAXENGINE_API StringView GetGraphFunctionTypeName_Deprecated(const Variant& v); /// /// Visject graph /// template class Graph { public: typedef Graph GraphType; typedef NodeType Node; typedef BoxType Box; typedef ParameterType Parameter; private: struct TmpConnectionHint { Node* Node; byte BoxID; }; public: NON_COPYABLE(Graph); /// /// All graph nodes /// Array Nodes; /// /// All graph parameters /// Array Parameters; /// /// Metadata for whole graph /// VisjectMeta Meta; public: /// /// Initializes a new instance of the class. /// Graph() { } /// /// Finalizes an instance of the class. /// virtual ~Graph() { } public: /// /// Save graph to the stream /// /// Output stream /// True if save all loaded metadata /// True if cannot save data, otherwise false virtual bool Save(WriteStream* stream, bool saveMeta) const { // Magic Code stream->WriteInt32(1963542358); // Version stream->WriteInt32(7000); // Nodes count stream->WriteInt32(Nodes.Count()); // Parameters count stream->WriteInt32(Parameters.Count()); // For each node for (int32 i = 0; i < Nodes.Count(); i++) { auto node = &Nodes[i]; stream->WriteUint32(node->ID); stream->WriteUint32(node->Type); } // For each param for (int32 i = 0; i < Parameters.Count(); i++) { const Parameter* param = &Parameters[i]; stream->WriteVariantType(param->Type); stream->Write(param->Identifier); stream->WriteString(param->Name, 97); stream->WriteBool(param->IsPublic); stream->WriteVariant(param->Value); if (param->Meta.Save(stream, saveMeta)) return true; } // For each node Array> boxes; for (int32 i = 0; i < Nodes.Count(); i++) { const Node* node = &Nodes[i]; // Values stream->WriteInt32(node->Values.Count()); for (int32 j = 0; j < node->Values.Count(); j++) stream->WriteVariant(node->Values[j]); // Boxes node->GetBoxes(boxes); stream->WriteUint16(boxes.Count()); for (int32 j = 0; j < boxes.Count(); j++) { const Box* box = boxes[j]; stream->WriteByte(box->ID); stream->WriteVariantType(box->Type); stream->WriteUint16(box->Connections.Count()); for (int32 k = 0; k < box->Connections.Count(); k++) { auto targetBox = box->Connections[k]; if (targetBox == nullptr) return true; stream->WriteUint32(targetBox->template GetParent()->ID); stream->WriteByte(targetBox->ID); } } // Meta if (node->Meta.Save(stream, saveMeta)) return true; } // Meta if (Meta.Save(stream, saveMeta)) return true; // Ending char stream->WriteByte('\t'); return false; } /// /// Load graph from the stream /// /// Input stream /// True if load all saved metadata /// True if cannot load data, otherwise false virtual bool Load(ReadStream* stream, bool loadMeta) { // Clear previous data Clear(); // Magic Code int32 tmp; stream->ReadInt32(&tmp); if (tmp != 1963542358) { LOG(Warning, "Invalid data."); return true; } // Version uint32 version; stream->ReadUint32(&version); Array tmpHints; if (version < 7000) { // [Deprecated on 31.07.2020, expires on 31.07.2022] // Time saved int64 timeSaved; stream->ReadInt64(&timeSaved); // Nodes count int32 nodesCount; stream->ReadInt32(&nodesCount); Nodes.Resize(nodesCount, false); // Parameters count int32 parametersCount; stream->ReadInt32(¶metersCount); Parameters.Resize(parametersCount, false); // For each node for (int32 i = 0; i < nodesCount; i++) { auto node = &Nodes[i]; // ID stream->ReadUint32(&node->ID); // Type stream->ReadUint32(&node->Type); if (onNodeCreated(node)) return true; } // For each param for (int32 i = 0; i < parametersCount; i++) { // Create param auto param = &Parameters[i]; // Properties auto type = stream->ReadByte(); stream->Read(param->Identifier); stream->ReadString(¶m->Name, 97); param->IsPublic = stream->ReadBool(); bool isStatic = stream->ReadBool(); bool isUIVisible = stream->ReadBool(); bool isUIEditable = stream->ReadBool(); // References [Deprecated] int32 refsCount; stream->ReadInt32(&refsCount); for (int32 j = 0; j < refsCount; j++) { uint32 refID; stream->ReadUint32(&refID); } // Value ReadOldGraphParamValue_Deprecated(type, stream, param); // Meta if (param->Meta.Load(stream, loadMeta)) return true; if (onParamCreated(param)) return true; } // For each node for (int32 i = 0; i < nodesCount; i++) { auto node = &Nodes[i]; // Values int32 valuesCnt; stream->ReadInt32(&valuesCnt); node->Values.Resize(valuesCnt); for (int32 j = 0; j < valuesCnt; j++) ReadOldGraphNodeValue_Deprecated(stream, node->Values[j]); // Boxes uint16 boxesCount; stream->ReadUint16(&boxesCount); node->Boxes.Clear(); for (int32 j = 0; j < boxesCount; j++) { byte boxID = stream->ReadByte(); node->Boxes.Resize(node->Boxes.Count() > boxID + 1 ? node->Boxes.Count() : boxID + 1); Box* box = &node->Boxes[boxID]; box->Parent = node; box->ID = boxID; uint32 connectionType; stream->ReadUint32((uint32*)&connectionType); ReadOldGraphBoxType_Deprecated(connectionType, box->Type); uint16 connectionsCount; stream->ReadUint16(&connectionsCount); box->Connections.Resize(connectionsCount); for (int32 k = 0; k < connectionsCount; k++) { uint32 targetNodeID; stream->ReadUint32(&targetNodeID); byte targetBoxID = stream->ReadByte(); TmpConnectionHint hint; hint.Node = GetNode(targetNodeID); if (hint.Node == nullptr) return true; hint.BoxID = targetBoxID; box->Connections[k] = (Box*)(intptr)tmpHints.Count(); tmpHints.Add(hint); } } // Meta if (node->Meta.Load(stream, loadMeta)) return true; if (onNodeLoaded(node)) return true; } // Visject Meta if (Meta.Load(stream, loadMeta)) return true; // Setup connections for (int32 i = 0; i < Nodes.Count(); i++) { auto node = &Nodes[i]; for (int32 j = 0; j < node->Boxes.Count(); j++) { Box* box = &node->Boxes[j]; if (box->Parent == nullptr) continue; for (int32 k = 0; k < box->Connections.Count(); k++) { int32 hintIndex = (int32)(intptr)box->Connections[k]; TmpConnectionHint hint = tmpHints[hintIndex]; box->Connections[k] = hint.Node->GetBox(hint.BoxID); } } } // Ending char byte end; stream->ReadByte(&end); if (end != '\t') { return true; } } else if (version == 7000) { // Nodes count int32 nodesCount; stream->ReadInt32(&nodesCount); Nodes.Resize(nodesCount, false); // Parameters count int32 parametersCount; stream->ReadInt32(¶metersCount); Parameters.Resize(parametersCount, false); // For each node for (int32 i = 0; i < nodesCount; i++) { auto node = &Nodes[i]; stream->ReadUint32(&node->ID); stream->ReadUint32(&node->Type); if (onNodeCreated(node)) return true; } // For each param for (int32 i = 0; i < parametersCount; i++) { auto param = &Parameters[i]; stream->ReadVariantType(¶m->Type); stream->Read(param->Identifier); stream->ReadString(¶m->Name, 97); param->IsPublic = stream->ReadBool(); stream->ReadVariant(¶m->Value); if (param->Meta.Load(stream, loadMeta)) return true; if (onParamCreated(param)) return true; } // For each node for (int32 i = 0; i < nodesCount; i++) { auto node = &Nodes[i]; // Values int32 valuesCnt; stream->ReadInt32(&valuesCnt); node->Values.Resize(valuesCnt); for (int32 j = 0; j < valuesCnt; j++) stream->ReadVariant(&node->Values[j]); // Boxes uint16 boxesCount; stream->ReadUint16(&boxesCount); node->Boxes.Clear(); for (int32 j = 0; j < boxesCount; j++) { byte boxID = stream->ReadByte(); node->Boxes.Resize(node->Boxes.Count() > boxID + 1 ? node->Boxes.Count() : boxID + 1); Box* box = &node->Boxes[boxID]; box->Parent = node; box->ID = boxID; stream->ReadVariantType(&box->Type); uint16 connectionsCount; stream->ReadUint16(&connectionsCount); box->Connections.Resize(connectionsCount); for (int32 k = 0; k < connectionsCount; k++) { uint32 targetNodeID; stream->ReadUint32(&targetNodeID); byte targetBoxID = stream->ReadByte(); TmpConnectionHint hint; hint.Node = GetNode(targetNodeID); if (hint.Node == nullptr) return true; hint.BoxID = targetBoxID; box->Connections[k] = (Box*)(intptr)tmpHints.Count(); tmpHints.Add(hint); } } // Meta if (node->Meta.Load(stream, loadMeta)) return true; if (onNodeLoaded(node)) return true; } // Visject Meta if (Meta.Load(stream, loadMeta)) return true; // Setup connections for (int32 i = 0; i < Nodes.Count(); i++) { auto node = &Nodes[i]; for (int32 j = 0; j < node->Boxes.Count(); j++) { Box* box = &node->Boxes[j]; if (box->Parent == nullptr) continue; for (int32 k = 0; k < box->Connections.Count(); k++) { int32 hintIndex = (int32)(intptr)box->Connections[k]; TmpConnectionHint hint = tmpHints[hintIndex]; box->Connections[k] = hint.Node->GetBox(hint.BoxID); } } } // Ending char byte end; stream->ReadByte(&end); if (end != '\t') return true; } return false; } public: /// /// Find node by ID /// /// Node ID /// Node or null if cannot find it Node* GetNode(uint32 id) { Node* result = nullptr; for (int32 i = 0; i < Nodes.Count(); i++) { if (Nodes[i].ID == id) { result = &Nodes[i]; break; } } return result; } /// /// Find parameter by ID /// /// Parameter ID /// Parameter or null if cannot find it Parameter* GetParameter(const Guid& id) { Parameter* result = nullptr; for (int32 i = 0; i < Parameters.Count(); i++) { if (Parameters[i].Identifier == id) { result = &Parameters[i]; break; } } return result; } /// /// Find parameter by ID /// /// Parameter ID /// Parameter index /// Parameter or null if cannot find it Parameter* GetParameter(const Guid& id, int32& outIndex) { Parameter* result = nullptr; outIndex = INVALID_INDEX; for (int32 i = 0; i < Parameters.Count(); i++) { if (Parameters[i].Identifier == id) { result = &Parameters[i]; outIndex = i; break; } } return result; } /// /// Clear whole graph data /// virtual void Clear() { Nodes.Resize(0); Parameters.Resize(0); Meta.Release(); } public: #if USE_EDITOR /// /// Gets the asset references. /// /// /// The output collection of the asset ids referenced by this object. virtual void GetReferences(Array& output) const { for (int32 i = 0; i < Parameters.Count(); i++) { const auto& p = Parameters[i]; const Guid id = (Guid)p.Value; if (id.IsValid()) output.Add(id); } for (int32 i = 0; i < Nodes.Count(); i++) { const auto& n = Nodes[i]; for (int32 j = 0; j < n.Values.Count(); j++) { const Guid id = (Guid)n.Values[j]; if (id.IsValid()) output.Add(id); } } } #endif protected: virtual bool onNodeCreated(Node* n) { return false; } virtual bool onNodeLoaded(Node* n) { return false; } virtual bool onParamCreated(Parameter* p) { return false; } uint32 getFreeNodeID() const { uint32 result = 1; while (true) { bool valid = true; for (int32 i = 0; i < Nodes.Count(); i++) { if (Nodes[i].Identifier == result) { result++; valid = false; break; } } if (valid) break; } return result; } };