using System; using System.Linq; using Unity.GraphToolkit.Editor; using UnityEditor; using UnityEngine; namespace Unity.GraphToolkit.Samples.TextureMaker.Editor { /// /// Represents the Texture Maker graph. /// /// This is the entry point for the Texture Maker tool, it represents a Texture Maker graph. /// This class extends the Graph Toolkit class, which provides a range of default behaviors, /// reducing the amount of code required to quickly implement a basic graph tool. /// It also provides customization by allowing you to override specific methods and can be decorated by attributes to /// tailor the tool's functionality. /// For example, in this class, we override the OnGraphChanged method to add our custom handling for graph errors and warnings. /// We also decorated it with the , which specifies the asset extension. /// [Graph(AssetExtension)] [Serializable] internal class TextureMakerGraph : Graph { /// /// The file extension for Texture Maker graph assets. /// /// In Unity, the extension is used to select the right importer, so it must be unique. internal const string AssetExtension = "texmkr"; /// /// Create a texture maker asset file. /// [MenuItem("Assets/Create/Graph Toolkit Samples/Texture Maker Graph", false)] static void CreateAssetFile() { GraphDatabase.PromptInProjectBrowserToCreateNewAsset(); } /// /// Checks the graph for errors and warnings and adds them to the result object. /// /// Object implementing interface and containing /// collected errors and warnings /// Errors and warnings are reported by adding them to the GraphLogger object, /// which is the default reporting mechanism for a Graph Toolkit tool. private void CheckGraphErrors(GraphLogger infos) { // Get all CreateTextureNode instances in the graph var createTextureNodes = GetNodes().OfType().ToList(); switch (createTextureNodes.Count) { case 0: // This is a tool design choice to log an error if no CreateTextureNode is found in the graph. // This will result in an error message being logged in the console. infos.LogError("Add a CreateTextureNode in your Texture graph."); break; case > 1: { foreach (var createTextureNode in createTextureNodes.Skip(1)) { // This will result in a warning message being logged in the console and a warning marker being displayed on the node infos.LogWarning($"TextureMaker only supports one {nameof(CreateTextureNode)} by graph. " + "Only the first created one will be used.", createTextureNode); } break; } } } /// /// Called when the graph changes. /// /// The GraphLogger object to which errors and warnings are added. /// /// This method is triggered whenever the graph is modified. It calls `CheckGraphErrors` to validate the graph /// and report any issues. /// public override void OnGraphChanged(GraphLogger infos) { CheckGraphErrors(infos); } /// /// Resolves the value from the given port by determining the type of node connected. /// For constant, variable, and texture evaluator nodes, it extracts the corresponding value. /// If no connected source is available, it attempts to resolve an embedded value from the port. /// /// The expected type of the port value. /// The port from which to resolve the value. /// /// The resolved value of type if successful; otherwise, the default value of . /// public static T ResolvePortValue(IPort port) { // Get the source port providing input to "port" (null if no connection exists) var sourcePort = port.firstConnectedPort; switch (sourcePort?.GetNode()) { case IConstantNode node: node.TryGetValue(out T constantValue); return constantValue; case IVariableNode node: node.variable.TryGetDefaultValue(out T variableValue); return variableValue; case ITextureEvaluatorNode textureEvaluatorNode: if (typeof(T).IsAssignableFrom(typeof(Texture2D))) { return (T)(object)textureEvaluatorNode.EvaluateTexturePort(sourcePort); } break; case null: // If no connection exists, try to get "port" 's embedded value (returns type default if unavailable) port.TryGetValue(out T embeddedValue); return embeddedValue; } return default; } } }