114 lines
3.9 KiB
C#
114 lines
3.9 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Linq;
|
||
|
using System.Reflection;
|
||
|
using UnityEditor.ShaderGraph.Drawing;
|
||
|
using UnityEngine;
|
||
|
using UnityEditor.Graphing;
|
||
|
using UnityEditor.Rendering;
|
||
|
using UnityEngine.Rendering.ShaderGraph;
|
||
|
using UnityEngine.UIElements;
|
||
|
|
||
|
namespace UnityEditor.ShaderGraph
|
||
|
{
|
||
|
class SubGraphOutputNode : AbstractMaterialNode
|
||
|
{
|
||
|
static string s_MissingOutputSlot = "A Sub Graph must have at least one output slot";
|
||
|
static List<ConcreteSlotValueType> s_ValidSlotTypes = new List<ConcreteSlotValueType>()
|
||
|
{
|
||
|
ConcreteSlotValueType.Vector1,
|
||
|
ConcreteSlotValueType.Vector2,
|
||
|
ConcreteSlotValueType.Vector3,
|
||
|
ConcreteSlotValueType.Vector4,
|
||
|
ConcreteSlotValueType.Matrix2,
|
||
|
ConcreteSlotValueType.Matrix3,
|
||
|
ConcreteSlotValueType.Matrix4,
|
||
|
ConcreteSlotValueType.Boolean
|
||
|
};
|
||
|
public bool IsFirstSlotValid = true;
|
||
|
|
||
|
public SubGraphOutputNode()
|
||
|
{
|
||
|
name = "Output";
|
||
|
}
|
||
|
|
||
|
// Link to the Sub Graph overview page instead of the specific Node page, seems more useful
|
||
|
public override string documentationURL => Documentation.GetPageLink("Sub-graph");
|
||
|
|
||
|
void ValidateShaderStage()
|
||
|
{
|
||
|
List<MaterialSlot> slots = new List<MaterialSlot>();
|
||
|
GetInputSlots(slots);
|
||
|
|
||
|
// Reset all input slots back to All, otherwise they'll be incorrectly configured when traversing below
|
||
|
foreach (MaterialSlot slot in slots)
|
||
|
slot.stageCapability = ShaderStageCapability.All;
|
||
|
|
||
|
foreach (var slot in slots)
|
||
|
{
|
||
|
slot.stageCapability = NodeUtils.GetEffectiveShaderStageCapability(slot, true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ValidateSlotName()
|
||
|
{
|
||
|
List<MaterialSlot> slots = new List<MaterialSlot>();
|
||
|
GetInputSlots(slots);
|
||
|
|
||
|
foreach (var slot in slots)
|
||
|
{
|
||
|
var error = NodeUtils.ValidateSlotName(slot.RawDisplayName(), out string errorMessage);
|
||
|
if (error)
|
||
|
{
|
||
|
owner.AddValidationError(objectId, errorMessage);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ValidateSlotType()
|
||
|
{
|
||
|
List<MaterialSlot> slots = new List<MaterialSlot>();
|
||
|
GetInputSlots(slots);
|
||
|
|
||
|
if (!slots.Any())
|
||
|
{
|
||
|
owner.AddValidationError(objectId, s_MissingOutputSlot, ShaderCompilerMessageSeverity.Error);
|
||
|
}
|
||
|
else if (!s_ValidSlotTypes.Contains(slots.FirstOrDefault().concreteValueType))
|
||
|
{
|
||
|
IsFirstSlotValid = false;
|
||
|
owner.AddValidationError(objectId, "Preview can only compile if the first output slot is a Vector, Matrix, or Boolean type. Please adjust slot types.", ShaderCompilerMessageSeverity.Error);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void ValidateNode()
|
||
|
{
|
||
|
base.ValidateNode();
|
||
|
IsFirstSlotValid = true;
|
||
|
ValidateSlotType();
|
||
|
if (IsFirstSlotValid)
|
||
|
ValidateShaderStage();
|
||
|
}
|
||
|
|
||
|
protected override void OnSlotsChanged()
|
||
|
{
|
||
|
base.OnSlotsChanged();
|
||
|
ValidateNode();
|
||
|
}
|
||
|
|
||
|
public int AddSlot(ConcreteSlotValueType concreteValueType)
|
||
|
{
|
||
|
var index = this.GetInputSlots<MaterialSlot>().Count() + 1;
|
||
|
var name = NodeUtils.GetDuplicateSafeNameForSlot(this, index, "Out_" + concreteValueType.ToString());
|
||
|
AddSlot(MaterialSlot.CreateMaterialSlot(concreteValueType.ToSlotValueType(), index, name,
|
||
|
NodeUtils.GetHLSLSafeName(name), SlotType.Input, Vector4.zero));
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
public override bool canDeleteNode => false;
|
||
|
|
||
|
public override bool canCopyNode => false;
|
||
|
}
|
||
|
}
|