/// <summary>
        /// Updates the surface graph asset (save new one, discard cached data, reload asset).
        /// </summary>
        /// <returns>True if cannot save it, otherwise false.</returns>
        public static bool SaveSurface(JsonAsset asset, RenderingGraph assetInstance, byte[] surfaceData)
        {
            if (!asset)
            {
                throw new ArgumentNullException(nameof(asset));
            }

            assetInstance.VisjectSurface = surfaceData;
            return(FlaxEditor.Editor.SaveJsonAsset(asset.Path, assetInstance));
        }
        /// <summary>
        /// Tries to load surface graph from the asset.
        /// </summary>
        /// <param name="createDefaultIfMissing">True if create default surface if missing, otherwise won't load anything.</param>
        /// <returns>Loaded surface bytes or null if cannot load it or it's missing.</returns>
        public static byte[] LoadSurface(JsonAsset asset, RenderingGraph assetInstance, bool createDefaultIfMissing)
        {
            if (!asset)
            {
                throw new ArgumentNullException(nameof(asset));
            }
            if (assetInstance == null)
            {
                throw new ArgumentNullException(nameof(assetInstance));
            }

            // Return its data
            if (assetInstance.VisjectSurface?.Length > 0)
            {
                return(assetInstance.VisjectSurface);
            }

            // Create it if it's missing
            if (createDefaultIfMissing)
            {
                // A bit of a hack
                // Create a Visject Graph with a main node and serialize it!
                var surfaceContext = new VisjectSurfaceContext(null, null, new FakeSurfaceContext());

                // Add the main node
                var node = NodeFactory.CreateNode(GetGroupArchetypes(), 1, surfaceContext, MainNodeGroupId, MainNodeTypeId);

                if (node == null)
                {
                    Debug.LogWarning("Failed to create main node.");
                    return(null);
                }
                surfaceContext.Nodes.Add(node);
                node.Location = Vector2.Zero;
                surfaceContext.Save();
                return(surfaceContext.Context.SurfaceData);
            }
            else
            {
                return(null);
            }
        }
        public void CompileSurface(RenderingGraph graph)
        {
            // We're mapping every output box to an index
            // So we can store the node outputs in an array
            var variableIndexGetter = new GraphVariables();

            // Get the parameters
            GetParameterGetterNodeArchetype(out ushort paramNodeGroupId);

            var graphParams = new Dictionary <Guid, GraphParameter>();
            var parameters  = new GraphParameter[Parameters.Count];

            for (int i = 0; i < Parameters.Count; i++)
            {
                var param          = Parameters[i];
                var graphParameter = new GraphParameter(param.Name, param.Value, variableIndexGetter.RegisterVariable());
                graphParams.Add(param.ID, graphParameter);
                parameters[i] = graphParameter;
            }

            var nodes = FindNode(MainNodeGroupId, MainNodeTypeId)
                        .DepthFirstTraversal()
                        .Select <SurfaceNode, RenderingNode>((surfaceNode, index) =>
            {
                int[] inputIndices = surfaceNode.Elements
                                     .OfType <InputBox>()
                                     .Select(inputBox => inputBox.HasAnyConnection ? variableIndexGetter.UseVariable(inputBox) : -1)
                                     .ToArray();
                int[] outputIndices = surfaceNode.Elements
                                      .OfType <OutputBox>()
                                      .Select(outputBox => variableIndexGetter.RegisterVariable(outputBox))
                                      .ToArray();

                int groupId = surfaceNode.GroupArchetype.GroupID;
                int typeId  = surfaceNode.Archetype.TypeID;

                if (groupId == paramNodeGroupId)
                {
                    var graphParam = graphParams[(Guid)surfaceNode.Values[0]];
                    inputIndices   = new int[1] {
                        graphParam.OutputIndex
                    };
                }

                var nodeDefinition = new NodeDefinition()
                {
                    GroupId       = groupId,
                    TypeId        = typeId,
                    Index         = index,
                    Values        = surfaceNode.Values,
                    InputIndices  = inputIndices,
                    OutputIndices = outputIndices
                };

                var nodeFactory = GetNodeFactoryGroup(groupId).GetNodeFactory(typeId);
                return(nodeFactory.Create(nodeDefinition));
            })
                        .ToArray();

            graph.Parameters = parameters;
            graph.Nodes      = nodes;
        }