initial commit

This commit is contained in:
Jo 2025-01-07 02:06:59 +01:00
parent 6715289efe
commit 788c3389af
37645 changed files with 2526849 additions and 80 deletions

View file

@ -0,0 +1,135 @@
using System;
using System.Collections.Generic;
using UnityEditor.ShaderGraph.Internal;
using UnityEngine;
namespace UnityEditor.ShaderGraph
{
class FunctionSource
{
public string code;
public HashSet<AbstractMaterialNode> nodes;
public bool isGeneric;
public int graphPrecisionFlags; // Flags<GraphPrecision>
public int concretePrecisionFlags; // Flags<ConcretePrecision>
}
class FunctionRegistry
{
Dictionary<string, FunctionSource> m_Sources = new Dictionary<string, FunctionSource>();
bool m_Validate = false;
ShaderStringBuilder m_Builder;
IncludeCollection m_Includes;
public FunctionRegistry(ShaderStringBuilder builder, IncludeCollection includes, bool validate = false)
{
m_Builder = builder;
m_Includes = includes;
m_Validate = validate;
}
internal ShaderStringBuilder builder => m_Builder;
public Dictionary<string, FunctionSource> sources => m_Sources;
public void RequiresIncludes(IncludeCollection includes)
{
m_Includes.Add(includes);
}
public void RequiresIncludePath(string includePath)
{
m_Includes.Add(includePath, IncludeLocation.Graph);
}
// this list is somewhat redundant, but it preserves function declaration ordering
// (i.e. when nodes add multiple functions, they require being defined in a certain order)
public List<string> names { get; } = new List<string>();
public void ProvideFunction(string name, GraphPrecision graphPrecision, ConcretePrecision concretePrecision, Action<ShaderStringBuilder> generator)
{
// appends code, construct the standalone code string
var originalIndex = builder.length;
builder.AppendNewLine();
var startIndex = builder.length;
generator(builder);
var length = builder.length - startIndex;
// trim fixes mismatched whitespace issue when nodes come from subgraphs
var code = builder.ToString(startIndex, length).Trim();
// validate some assumptions around generics
bool isGenericName = name.Contains("$");
bool isGenericFunc = code.Contains("$");
bool isGeneric = isGenericName || isGenericFunc;
bool containsFunctionName = code.Contains(name);
var curNode = builder.currentNode;
if (isGenericName != isGenericFunc)
curNode.owner.AddValidationError(curNode.objectId, $"Function {name} provided by node {curNode.name} contains $precision tokens in the name or the code, but not both. This is very likely an error.");
if (!containsFunctionName)
curNode.owner.AddValidationError(curNode.objectId, $"Function {name} provided by node {curNode.name} does not contain the name of the function. This is very likely an error.");
int graphPrecisionFlag = (1 << (int)graphPrecision);
int concretePrecisionFlag = (1 << (int)concretePrecision);
FunctionSource existingSource;
if (m_Sources.TryGetValue(name, out existingSource))
{
// function already provided
existingSource.nodes.Add(builder.currentNode);
// let's check if the requested precision variant has already been provided (or if it's not generic there are no variants)
bool concretePrecisionExists = ((existingSource.concretePrecisionFlags & concretePrecisionFlag) != 0) || !isGeneric;
// if this precision was already added -- remove the duplicate code from the builder
if (concretePrecisionExists)
builder.length -= (builder.length - originalIndex);
// save the flags
existingSource.graphPrecisionFlags = existingSource.graphPrecisionFlags | graphPrecisionFlag;
existingSource.concretePrecisionFlags = existingSource.concretePrecisionFlags | concretePrecisionFlag;
// if validate, we double check that the two function declarations are the same
if (m_Validate)
{
if (code != existingSource.code)
{
var errorMessage = string.Format("Function `{0}` has conflicting implementations:{1}{1}{2}{1}{1}{3}", name, Environment.NewLine, code, existingSource.code);
foreach (var n in existingSource.nodes)
n.owner.AddValidationError(n.objectId, errorMessage);
}
}
}
else
{
var newSource = new FunctionSource
{
code = code,
isGeneric = isGeneric,
graphPrecisionFlags = graphPrecisionFlag,
concretePrecisionFlags = concretePrecisionFlag,
nodes = new HashSet<AbstractMaterialNode> { builder.currentNode }
};
m_Sources.Add(name, newSource);
names.Add(name);
}
// fully concretize any generic code by replacing any precision tokens by the node's concrete precision
if (isGeneric && (builder.length > originalIndex))
{
int start = originalIndex;
int count = builder.length - start;
builder.Replace(PrecisionUtil.Token, concretePrecision.ToShaderString(), start, count);
}
}
public void ProvideFunction(string name, Action<ShaderStringBuilder> generator)
{
ProvideFunction(name, builder.currentNode.graphPrecision, builder.currentNode.concretePrecision, generator);
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7e4fc6f4e30c408f9c0304cbed39a076
timeCreated: 1513609614

View file

@ -0,0 +1,145 @@
using UnityEditor.ShaderGraph.Internal;
using UnityEditor.Graphing;
using UnityEngine;
namespace UnityEditor.ShaderGraph
{
static class GradientUtil
{
public static string GetGradientValue(Gradient gradient, string delimiter = ";")
{
string colorKeys = "";
for (int i = 0; i < 8; i++)
{
if (i < gradient.colorKeys.Length)
colorKeys += $"$precision4({NodeUtils.FloatToShaderValue(gradient.colorKeys[i].color.r)}, " +
$"{NodeUtils.FloatToShaderValue(gradient.colorKeys[i].color.g)}, " +
$"{NodeUtils.FloatToShaderValue(gradient.colorKeys[i].color.b)}, " +
$"{NodeUtils.FloatToShaderValue(gradient.colorKeys[i].time)})";
else
colorKeys += "$precision4(0, 0, 0, 0)";
if (i < 7)
colorKeys += ",";
}
string alphaKeys = "";
for (int i = 0; i < 8; i++)
{
if (i < gradient.alphaKeys.Length)
alphaKeys += $"$precision2({NodeUtils.FloatToShaderValue(gradient.alphaKeys[i].alpha)}, {NodeUtils.FloatToShaderValue(gradient.alphaKeys[i].time)})";
else
alphaKeys += "$precision2(0, 0)";
if (i < 7)
alphaKeys += ",";
}
return $"NewGradient({(int)gradient.mode}, {gradient.colorKeys.Length}, {gradient.alphaKeys.Length}, {colorKeys}, {alphaKeys}){delimiter}";
}
public static string GetGradientForPreview(string name)
{
string colorKeys = "";
for (int i = 0; i < 8; i++)
{
colorKeys += $"{name}_ColorKey{i}";
if (i < 7)
colorKeys += ",";
}
string alphaKeys = "";
for (int i = 0; i < 8; i++)
{
alphaKeys += $"{name}_AlphaKey{i}";
if (i < 7)
alphaKeys += ",";
}
return $"NewGradient({name}_Type, {name}_ColorsLength, {name}_AlphasLength, {colorKeys}, {alphaKeys})";
}
public static void GetGradientPropertiesForPreview(PropertyCollector properties, string name, Gradient value)
{
properties.AddShaderProperty(new Vector1ShaderProperty()
{
overrideReferenceName = $"{name}_Type",
value = (int)value.mode,
generatePropertyBlock = false
});
properties.AddShaderProperty(new Vector1ShaderProperty()
{
overrideReferenceName = $"{name}_ColorsLength",
value = value.colorKeys.Length,
generatePropertyBlock = false
});
properties.AddShaderProperty(new Vector1ShaderProperty()
{
overrideReferenceName = $"{name}_AlphasLength",
value = value.alphaKeys.Length,
generatePropertyBlock = false
});
for (int i = 0; i < 8; i++)
{
properties.AddShaderProperty(new Vector4ShaderProperty()
{
overrideReferenceName = $"{name}_ColorKey{i}",
value = i < value.colorKeys.Length ? GradientUtil.ColorKeyToVector(value.colorKeys[i]) : Vector4.zero,
generatePropertyBlock = false
});
}
for (int i = 0; i < 8; i++)
{
properties.AddShaderProperty(new Vector2ShaderProperty()
{
overrideReferenceName = $"{name}_AlphaKey{i}",
value = i < value.alphaKeys.Length ? GradientUtil.AlphaKeyToVector(value.alphaKeys[i]) : Vector2.zero,
generatePropertyBlock = false
});
}
}
public static bool CheckEquivalency(Gradient A, Gradient B)
{
var currentMode = A.mode;
var currentColorKeys = A.colorKeys;
var currentAlphaKeys = A.alphaKeys;
var newMode = B.mode;
var newColorKeys = B.colorKeys;
var newAlphaKeys = B.alphaKeys;
if (currentMode != newMode || currentColorKeys.Length != newColorKeys.Length || currentAlphaKeys.Length != newAlphaKeys.Length)
{
return false;
}
else
{
for (var i = 0; i < currentColorKeys.Length; i++)
{
if (currentColorKeys[i].color != newColorKeys[i].color || Mathf.Abs(currentColorKeys[i].time - newColorKeys[i].time) > 1e-9)
return false;
}
for (var i = 0; i < currentAlphaKeys.Length; i++)
{
if (Mathf.Abs(currentAlphaKeys[i].alpha - newAlphaKeys[i].alpha) > 1e-9 || Mathf.Abs(currentAlphaKeys[i].time - newAlphaKeys[i].time) > 1e-9)
return false;
}
}
return true;
}
public static Vector4 ColorKeyToVector(GradientColorKey key)
{
return new Vector4(key.color.r, key.color.g, key.color.b, key.time);
}
public static Vector2 AlphaKeyToVector(GradientAlphaKey key)
{
return new Vector2(key.alpha, key.time);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b59f719ccd61c3348bcda608976bd9aa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,437 @@
using System;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor.Graphing;
using UnityEditor.Graphing.Util;
using UnityEditorInternal;
using Debug = UnityEngine.Debug;
using System.Reflection;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using UnityEditor.ProjectWindowCallback;
using UnityEditor.ShaderGraph.Internal;
using UnityEngine;
using UnityEngine.Rendering;
using Object = System.Object;
namespace UnityEditor.ShaderGraph
{
// a structure used to track active variable dependencies in the shader code
// (i.e. the use of uv0 in the pixel shader means we need a uv0 interpolator, etc.)
struct Dependency
{
public string name; // the name of the thing
public string dependsOn; // the thing above depends on this -- it reads it / calls it / requires it to be defined
public Dependency(string name, string dependsOn)
{
this.name = name;
this.dependsOn = dependsOn;
}
};
[System.AttributeUsage(System.AttributeTargets.Struct)]
class InterpolatorPack : System.Attribute
{
public InterpolatorPack()
{
}
}
// attribute used to flag a field as needing an HLSL semantic applied
// i.e. float3 position : POSITION;
// ^ semantic
[System.AttributeUsage(System.AttributeTargets.Field)]
class Semantic : System.Attribute
{
public string semantic;
public Semantic(string semantic)
{
this.semantic = semantic;
}
}
// attribute used to flag a field as being optional
// i.e. if it is not active, then we can omit it from the struct
[System.AttributeUsage(System.AttributeTargets.Field)]
class Optional : System.Attribute
{
public Optional()
{
}
}
// attribute used to override the HLSL type of a field with a custom type string
[System.AttributeUsage(System.AttributeTargets.Field)]
class OverrideType : System.Attribute
{
public string typeName;
public OverrideType(string typeName)
{
this.typeName = typeName;
}
}
// attribute used to force system generated fields to bottom of structs
[System.AttributeUsage(System.AttributeTargets.Field)]
class SystemGenerated : System.Attribute
{
public SystemGenerated()
{
}
}
// attribute used to disable a field using a preprocessor #if
[System.AttributeUsage(System.AttributeTargets.Field)]
class PreprocessorIf : System.Attribute
{
public string conditional;
public PreprocessorIf(string conditional)
{
this.conditional = conditional;
}
}
class NewGraphAction : EndNameEditAction
{
Target[] m_Targets;
public Target[] targets
{
get => m_Targets;
set => m_Targets = value;
}
BlockFieldDescriptor[] m_Blocks;
public BlockFieldDescriptor[] blocks
{
get => m_Blocks;
set => m_Blocks = value;
}
public override void Action(int instanceId, string pathName, string resourceFile)
{
var graph = new GraphData();
graph.AddContexts();
graph.InitializeOutputs(m_Targets, m_Blocks);
graph.path = "Shader Graphs";
FileUtilities.WriteShaderGraphToDisk(pathName, graph);
AssetDatabase.Refresh();
UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath<Shader>(pathName);
Selection.activeObject = obj;
}
}
static class GraphUtil
{
internal static bool CheckForRecursiveDependencyOnPendingSave(string saveFilePath, IEnumerable<SubGraphNode> subGraphNodes, string context = null)
{
var overwriteGUID = AssetDatabase.AssetPathToGUID(saveFilePath);
if (!string.IsNullOrEmpty(overwriteGUID))
{
foreach (var sgNode in subGraphNodes)
{
var asset = sgNode?.asset;
if (asset == null)
{
// cannot read the asset; might be recursive but we can't tell... should we return "maybe"?
// I think to be minimally intrusive to the user we can assume "No" in this case,
// even though this may miss recursions in extraordinary cases.
// it's more important to allow the user to save their files than to catch 100% of recursions
continue;
}
else if ((asset.assetGuid == overwriteGUID) || asset.descendents.Contains(overwriteGUID))
{
if (context != null)
{
Debug.LogWarning(context + " CANCELLED to avoid a generating a reference loop: the SubGraph '" + sgNode.asset.name + "' references the target file '" + saveFilePath + "'");
EditorUtility.DisplayDialog(
context + " CANCELLED",
"Saving the file would generate a reference loop, because the SubGraph '" + sgNode.asset.name + "' references the target file '" + saveFilePath + "'", "Cancel");
}
return true;
}
}
}
return false;
}
internal static string ConvertCamelCase(string text, bool preserveAcronyms)
{
if (string.IsNullOrEmpty(text))
return string.Empty;
StringBuilder newText = new StringBuilder(text.Length * 2);
newText.Append(text[0]);
for (int i = 1; i < text.Length; i++)
{
if (char.IsUpper(text[i]))
if ((text[i - 1] != ' ' && !char.IsUpper(text[i - 1])) ||
(preserveAcronyms && char.IsUpper(text[i - 1]) &&
i < text.Length - 1 && !char.IsUpper(text[i + 1])))
newText.Append(' ');
newText.Append(text[i]);
}
return newText.ToString();
}
public static void CreateNewGraph()
{
var graphItem = ScriptableObject.CreateInstance<NewGraphAction>();
graphItem.targets = null;
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, graphItem,
string.Format("New Shader Graph.{0}", ShaderGraphImporter.Extension), null, null);
}
public static void CreateNewGraphWithOutputs(Target[] targets, BlockFieldDescriptor[] blockDescriptors)
{
var graphItem = ScriptableObject.CreateInstance<NewGraphAction>();
graphItem.targets = targets;
graphItem.blocks = blockDescriptors;
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, graphItem,
string.Format("New Shader Graph.{0}", ShaderGraphImporter.Extension), null, null);
}
public static bool TryGetMetadataOfType<T>(this Shader shader, out T obj) where T : ScriptableObject
{
obj = null;
if (!shader.IsShaderGraphAsset())
return false;
var path = AssetDatabase.GetAssetPath(shader);
foreach (var asset in AssetDatabase.LoadAllAssetsAtPath(path))
{
if (asset is T metadataAsset)
{
obj = metadataAsset;
return true;
}
}
return false;
}
// this will work on ALL shadergraph-built shaders, in memory or asset based
public static bool IsShaderGraph(this Material material)
{
var shaderGraphTag = material.GetTag("ShaderGraphShader", false, null);
return !string.IsNullOrEmpty(shaderGraphTag);
}
// NOTE: this ONLY works for ASSET based Shaders, if you created a temporary shader in memory, it won't work
public static bool IsShaderGraphAsset(this Shader shader)
{
var path = AssetDatabase.GetAssetPath(shader);
var importer = AssetImporter.GetAtPath(path);
return importer is ShaderGraphImporter;
}
[Obsolete("Use IsShaderGraphAsset instead", false)]
public static bool IsShaderGraph(this Shader shader) => shader.IsShaderGraphAsset();
static void Visit(List<AbstractMaterialNode> outputList, Dictionary<string, AbstractMaterialNode> unmarkedNodes, AbstractMaterialNode node)
{
if (!unmarkedNodes.ContainsKey(node.objectId))
return;
foreach (var slot in node.GetInputSlots<MaterialSlot>())
{
foreach (var edge in node.owner.GetEdges(slot.slotReference))
{
var inputNode = edge.outputSlot.node;
Visit(outputList, unmarkedNodes, inputNode);
}
}
unmarkedNodes.Remove(node.objectId);
outputList.Add(node);
}
static Dictionary<SerializationHelper.TypeSerializationInfo, SerializationHelper.TypeSerializationInfo> s_LegacyTypeRemapping;
public static Dictionary<SerializationHelper.TypeSerializationInfo, SerializationHelper.TypeSerializationInfo> GetLegacyTypeRemapping()
{
if (s_LegacyTypeRemapping == null)
{
s_LegacyTypeRemapping = new Dictionary<SerializationHelper.TypeSerializationInfo, SerializationHelper.TypeSerializationInfo>();
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in assembly.GetTypesOrNothing())
{
if (type.IsAbstract)
continue;
foreach (var attribute in type.GetCustomAttributes(typeof(FormerNameAttribute), false))
{
var legacyAttribute = (FormerNameAttribute)attribute;
var serializationInfo = new SerializationHelper.TypeSerializationInfo { fullName = legacyAttribute.fullName };
s_LegacyTypeRemapping[serializationInfo] = SerializationHelper.GetTypeSerializableAsString(type);
}
}
}
}
return s_LegacyTypeRemapping;
}
/// <summary>
/// Sanitizes a supplied string such that it does not collide
/// with any other name in a collection.
/// </summary>
/// <param name="existingNames">
/// A collection of names that the new name should not collide with.
/// </param>
/// <param name="duplicateFormat">
/// The format applied to the name if a duplicate exists.
/// This must be a format string that contains `{0}` and `{1}`
/// once each. An example could be `{0} ({1})`, which will append ` (n)`
/// to the name for the n`th duplicate.
/// </param>
/// <param name="name">
/// The name to be sanitized.
/// </param>
/// <returns>
/// A name that is distinct form any name in `existingNames`.
/// </returns>
internal static string SanitizeName(IEnumerable<string> existingNames, string duplicateFormat, string name, string disallowedPatternRegex = "\"")
{
name = Regex.Replace(name, disallowedPatternRegex, "_");
return DeduplicateName(existingNames, duplicateFormat, name);
}
internal static string SanitizeCategoryName(string categoryName, string disallowedPatternRegex = "\"")
{
return Regex.Replace(categoryName, disallowedPatternRegex, "_");
}
internal static string DeduplicateName(IEnumerable<string> existingNames, string duplicateFormat, string name)
{
if (!existingNames.Contains(name))
return name;
string escapedDuplicateFormat = Regex.Escape(duplicateFormat);
// Escaped format will escape string interpolation, so the escape characters must be removed for these.
escapedDuplicateFormat = escapedDuplicateFormat.Replace(@"\{0}", @"{0}");
escapedDuplicateFormat = escapedDuplicateFormat.Replace(@"\{1}", @"{1}");
var baseRegex = new Regex(string.Format(escapedDuplicateFormat, @"^(.*)", @"(\d+)"));
var baseMatch = baseRegex.Match(name);
if (baseMatch.Success)
name = baseMatch.Groups[1].Value;
string baseNameExpression = string.Format(@"^{0}", Regex.Escape(name));
var regex = new Regex(string.Format(escapedDuplicateFormat, baseNameExpression, @"(\d+)") + "$");
var existingDuplicateNumbers = existingNames.Select(existingName => regex.Match(existingName)).Where(m => m.Success).Select(m => int.Parse(m.Groups[1].Value)).Where(n => n > 0).Distinct().ToList();
var duplicateNumber = 1;
existingDuplicateNumbers.Sort();
if (existingDuplicateNumbers.Any() && existingDuplicateNumbers.First() == 1)
{
duplicateNumber = existingDuplicateNumbers.Last() + 1;
for (var i = 1; i < existingDuplicateNumbers.Count; i++)
{
if (existingDuplicateNumbers[i - 1] != existingDuplicateNumbers[i] - 1)
{
duplicateNumber = existingDuplicateNumbers[i - 1] + 1;
break;
}
}
}
return string.Format(duplicateFormat, name, duplicateNumber);
}
public static bool WriteToFile(string path, string content)
{
try
{
File.WriteAllText(path, content);
return true;
}
catch (Exception e)
{
Debug.LogError(e);
return false;
}
}
public static void OpenFile(string path)
{
string filePath = Path.GetFullPath(path);
if (!File.Exists(filePath))
{
Debug.LogError(string.Format("Path {0} doesn't exists", path));
return;
}
string externalScriptEditor = ScriptEditorUtility.GetExternalScriptEditor();
if (externalScriptEditor != "internal")
{
InternalEditorUtility.OpenFileAtLineExternal(filePath, 0);
}
else
{
Process p = new Process();
p.StartInfo.FileName = filePath;
p.EnableRaisingEvents = true;
p.Exited += (Object obj, EventArgs args) =>
{
if (p.ExitCode != 0)
Debug.LogWarningFormat("Unable to open {0}: Check external editor in preferences", filePath);
};
p.Start();
}
}
//
// Find all nodes of the given type downstream from the given node
// Returns a unique list. So even if a node can be reached through different paths it will be present only once.
//
public static List<NodeType> FindDownStreamNodesOfType<NodeType>(AbstractMaterialNode node) where NodeType : AbstractMaterialNode
{
// Should never be called without a node
Debug.Assert(node != null);
HashSet<AbstractMaterialNode> visitedNodes = new HashSet<AbstractMaterialNode>();
List<NodeType> vtNodes = new List<NodeType>();
Queue<AbstractMaterialNode> nodeStack = new Queue<AbstractMaterialNode>();
nodeStack.Enqueue(node);
visitedNodes.Add(node);
while (nodeStack.Count > 0)
{
AbstractMaterialNode visit = nodeStack.Dequeue();
// Flood fill through all the nodes
foreach (var slot in visit.GetInputSlots<MaterialSlot>())
{
foreach (var edge in visit.owner.GetEdges(slot.slotReference))
{
var inputNode = edge.outputSlot.node;
if (!visitedNodes.Contains(inputNode))
{
nodeStack.Enqueue(inputNode);
visitedNodes.Add(inputNode);
}
}
}
// Extract vt node
if (visit is NodeType)
{
NodeType vtNode = visit as NodeType;
vtNodes.Add(vtNode);
}
}
return vtNodes;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 130a64d32c054c5fb51b1e5e13f93fc2
timeCreated: 1513590591

View file

@ -0,0 +1,37 @@
namespace UnityEditor.ShaderGraph
{
struct Identifier
{
uint m_Version;
int m_Index;
public Identifier(int index, uint version = 1)
{
m_Version = version;
m_Index = index;
}
public void IncrementVersion()
{
if (m_Version == uint.MaxValue)
m_Version = 1;
else
m_Version++;
}
public uint version
{
get { return m_Version; }
}
public int index
{
get { return m_Index; }
}
public bool valid
{
get { return m_Version != 0; }
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 084958a703164b0fa26e0667aaa1767f
timeCreated: 1513937833

View file

@ -0,0 +1,99 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor.ShaderGraph.Internal;
namespace UnityEditor.ShaderGraph
{
class KeywordCollector
{
public readonly List<ShaderKeyword> keywords;
public readonly List<List<KeyValuePair<ShaderKeyword, int>>> permutations;
public KeywordCollector()
{
keywords = new List<ShaderKeyword>();
permutations = new List<List<KeyValuePair<ShaderKeyword, int>>>();
}
public void AddShaderKeyword(ShaderKeyword chunk)
{
if (keywords.Any(x => x.referenceName == chunk.referenceName))
return;
keywords.Add(chunk);
}
public void GetKeywordsDeclaration(ShaderStringBuilder builder, GenerationMode mode)
{
if (keywords.Count == 0)
return;
// Declare keywords
foreach (var keyword in keywords)
{
// Hardcode active keywords in preview to reduce compiled variants
if (mode == GenerationMode.Preview)
{
string declaration = keyword.GetKeywordPreviewDeclarationString();
if (!string.IsNullOrEmpty(declaration))
{
builder.AppendLine(declaration);
}
}
else
{
keyword.AppendKeywordDeclarationStrings(builder);
}
}
// Declare another keyword per permutation for simpler if/defs in the graph code
builder.AppendNewLine();
KeywordUtil.GetKeywordPermutationDeclarations(builder, permutations);
builder.AppendNewLine();
}
public void CalculateKeywordPermutations()
{
permutations.Clear();
// Initialize current permutation
List<KeyValuePair<ShaderKeyword, int>> currentPermutation = new List<KeyValuePair<ShaderKeyword, int>>();
for (int i = 0; i < keywords.Count; i++)
{
currentPermutation.Add(new KeyValuePair<ShaderKeyword, int>(keywords[i], 0));
}
// Recursively permute keywords
PermuteKeywords(keywords, currentPermutation, 0);
}
void PermuteKeywords(List<ShaderKeyword> keywords, List<KeyValuePair<ShaderKeyword, int>> currentPermutation, int currentIndex)
{
if (currentIndex == keywords.Count)
return;
// Iterate each possible keyword at the current index
int entryCount = keywords[currentIndex].keywordType == KeywordType.Enum ? keywords[currentIndex].entries.Count : 2;
for (int i = 0; i < entryCount; i++)
{
// Set the index in the current permutation to the correct value
currentPermutation[currentIndex] = new KeyValuePair<ShaderKeyword, int>(keywords[currentIndex], i);
// If the current index is the last keyword we are finished with this permutation
if (currentIndex == keywords.Count - 1)
{
permutations.Add(currentPermutation);
}
// Otherwise we continue adding keywords to this permutation
else
{
PermuteKeywords(keywords, currentPermutation, currentIndex + 1);
}
// Duplicate current permutation
currentPermutation = currentPermutation.Select(item => item).ToList();
}
}
}
}

View file

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ea731ae969f51e948bdc8eb82a6542e1
timeCreated: 1469695793
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,87 @@
using System.Collections.Generic;
using System.Linq;
namespace UnityEditor.ShaderGraph.Internal
{
public static class KeywordDependentCollection
{
public enum KeywordPermutationInstanceType
{
Base,
Permutation,
}
public interface ISet<IInstance>
{
int instanceCount { get; }
IEnumerable<IInstance> instances { get; }
}
public interface IInstance
{
KeywordPermutationInstanceType type { get; }
int permutationIndex { get; }
}
}
public abstract class KeywordDependentCollection<TStorage, TAll, TAllPermutations, TForPermutation, TBase, TIInstance, TISet>
where TAll : TISet
where TAllPermutations : TISet
where TForPermutation : TISet, TIInstance
where TBase : TISet, TIInstance
where TISet : KeywordDependentCollection.ISet<TIInstance>
where TIInstance : KeywordDependentCollection.IInstance
where TStorage : new()
{
TStorage m_Base = new TStorage();
List<TStorage> m_PerPermutationIndex = new List<TStorage>();
public int permutationCount => m_PerPermutationIndex.Count;
public TForPermutation this[int index]
{
get
{
GetOrCreateForPermutationIndex(index);
return CreateForPermutationSmartPointer(index);
}
}
public TAll all => CreateAllSmartPointer();
public TAllPermutations allPermutations => CreateAllPermutationsSmartPointer();
/// <summary>
/// All permutation will inherit from base's active fields
/// </summary>
public TBase baseInstance => CreateBaseSmartPointer();
protected TStorage baseStorage
{
get => m_Base;
set => m_Base = value;
}
protected IEnumerable<TStorage> permutationStorages => m_PerPermutationIndex;
protected TStorage GetOrCreateForPermutationIndex(int index)
{
while (index >= m_PerPermutationIndex.Count)
m_PerPermutationIndex.Add(new TStorage());
return m_PerPermutationIndex[index];
}
protected void SetForPermutationIndex(int index, TStorage value)
{
while (index >= m_PerPermutationIndex.Count)
m_PerPermutationIndex.Add(new TStorage());
m_PerPermutationIndex[index] = value;
}
protected abstract TAll CreateAllSmartPointer();
protected abstract TAllPermutations CreateAllPermutationsSmartPointer();
protected abstract TForPermutation CreateForPermutationSmartPointer(int index);
protected abstract TBase CreateBaseSmartPointer();
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 34772c0f4dfcde7428f8bacfb0ce0552
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,274 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor.ShaderGraph.Drawing;
using UnityEngine;
using UnityEditor.ShaderGraph.Internal;
namespace UnityEditor.ShaderGraph
{
static class BuiltinKeyword
{
[BuiltinKeyword]
public static KeywordDescriptor QualityKeyword()
{
return new KeywordDescriptor()
{
displayName = "Material Quality",
referenceName = "MATERIAL_QUALITY",
type = KeywordType.Enum,
definition = KeywordDefinition.MultiCompile,
scope = KeywordScope.Global,
value = 0,
entries = new KeywordEntry[]
{
new KeywordEntry("High", "HIGH"),
new KeywordEntry("Medium", "MEDIUM"),
new KeywordEntry("Low", "LOW"),
},
stages = KeywordShaderStage.All,
};
}
}
static class KeywordUtil
{
public static IEnumerable<KeywordDescriptor> GetBuiltinKeywordDescriptors() =>
TypeCache.GetMethodsWithAttribute<BuiltinKeywordAttribute>()
.Where(method => method.IsStatic && method.ReturnType == typeof(KeywordDescriptor))
.Select(method =>
(KeywordDescriptor)method.Invoke(null, new object[0] { }));
public static ConcreteSlotValueType ToConcreteSlotValueType(this KeywordType keywordType)
{
switch (keywordType)
{
case KeywordType.Boolean:
return ConcreteSlotValueType.Boolean;
case KeywordType.Enum:
return ConcreteSlotValueType.Vector1;
default:
throw new ArgumentOutOfRangeException();
}
}
public static string ToDeclarationSuffix(this KeywordScope scope)
{
switch (scope)
{
case KeywordScope.Local:
return "_local";
default:
return string.Empty;
}
}
public static string ToDeclarationString(this KeywordDefinition keywordDefinition)
{
switch (keywordDefinition)
{
case KeywordDefinition.MultiCompile:
return "multi_compile";
case KeywordDefinition.ShaderFeature:
return "shader_feature";
default:
return string.Empty;
}
}
static void GenerateKeywordPragmaStrings(
string keywordReferenceName,
KeywordDefinition keywordDefinition,
KeywordScope keywordScope,
KeywordShaderStage keywordStages,
string keywordVariantsString,
Action<string> PragmaStringAction)
{
string definitionString = keywordDefinition.ToDeclarationString();
string scopeString = keywordScope.ToDeclarationSuffix();
// check the active shader stages
if ((keywordStages == KeywordShaderStage.All) || (keywordStages == 0)) // 0 is a default, so assume that means ALL
{
PragmaStringAction($"#pragma {definitionString}{scopeString} {keywordVariantsString}");
}
else
{
// have to process each stage separately
for (int shaderStage = (int)KeywordShaderStage.Vertex; shaderStage <= (int)keywordStages; shaderStage = shaderStage * 2)
{
if (((int)keywordStages & shaderStage) != 0)
{
var keywordStage = (KeywordShaderStage)shaderStage;
var stageString = keywordStage.ToKeywordStagesString();
PragmaStringAction($"#pragma {definitionString}{scopeString}{stageString} {keywordVariantsString}");
}
}
}
}
public static void GenerateEnumKeywordPragmaStrings(
string keywordReferenceName,
KeywordDefinition keywordDefinition,
KeywordScope keywordScope,
KeywordShaderStage keywordStages,
IEnumerable<KeywordEntry> keywordEntries,
Action<string> pragmaStringAction)
{
if (keywordDefinition != KeywordDefinition.Predefined)
{
var entryStrings = keywordEntries.Select(x => $"{keywordReferenceName}_{x.referenceName}");
string variantsString = string.Join(" ", entryStrings);
GenerateKeywordPragmaStrings(keywordReferenceName, keywordDefinition, keywordScope, keywordStages, variantsString, pragmaStringAction);
}
}
public static void GenerateBooleanKeywordPragmaStrings(
string keywordReferenceName,
KeywordDefinition keywordDefinition,
KeywordScope keywordScope,
KeywordShaderStage keywordStages,
Action<string> pragmaStringAction)
{
if (keywordDefinition != KeywordDefinition.Predefined)
{
string variantsString = $"_ {keywordReferenceName}";
GenerateKeywordPragmaStrings(keywordReferenceName, keywordDefinition, keywordScope, keywordStages, variantsString, pragmaStringAction);
}
}
public static string ToKeywordStagesString(this KeywordShaderStage stages)
{
string outString = "";
if (stages == KeywordShaderStage.All)
return outString;
if (stages == KeywordShaderStage.Vertex)
outString += "_vertex";
if (stages == KeywordShaderStage.Fragment)
outString += "_fragment";
if (stages == KeywordShaderStage.Geometry)
outString += "_geometry";
if (stages == KeywordShaderStage.Hull)
outString += "_hull";
if (stages == KeywordShaderStage.Domain)
outString += "_domain";
if (stages == KeywordShaderStage.RayTracing)
outString += "_raytracing";
return outString;
}
public static string ToDefineString(this KeywordDescriptor keyword, int value)
{
switch (keyword.type)
{
case KeywordType.Boolean:
return value == 1 ? $"#define {keyword.referenceName} 1" : string.Empty;
case KeywordType.Enum:
return $"#define {keyword.referenceName}_{keyword.entries[value].referenceName}";
default:
throw new ArgumentOutOfRangeException();
}
}
public static string GetKeywordPermutationSetConditional(List<int> permutationSet)
{
StringBuilder sb = new StringBuilder();
sb.Append("#if ");
for (int i = 0; i < permutationSet.Count; i++)
{
// Subsequent permutation predicates require ||
if (i != 0)
sb.Append(" || ");
// Append permutation
sb.Append($"defined(KEYWORD_PERMUTATION_{permutationSet[i]})");
}
return sb.ToString();
}
public static string GetKeywordPermutationConditional(int permutation)
{
return $"#if defined(KEYWORD_PERMUTATION_{permutation})";
}
public static void GetKeywordPermutationDeclarations(ShaderStringBuilder sb, List<List<KeyValuePair<ShaderKeyword, int>>> permutations)
{
if (permutations.Count == 0)
return;
for (int p = 0; p < permutations.Count; p++)
{
// ShaderStringBuilder.Append doesnt apply indentation
sb.TryAppendIndentation();
// Append correct if
bool isLast = false;
if (p == 0)
{
sb.Append("#if ");
}
else if (p == permutations.Count - 1)
{
sb.Append("#else");
isLast = true;
}
else
{
sb.Append("#elif ");
}
// Last permutation is always #else
if (!isLast)
{
// Track whether && is required
bool appendAnd = false;
// Iterate all keywords that are part of the permutation
for (int i = 0; i < permutations[p].Count; i++)
{
// When previous keyword was inserted subsequent requires &&
string and = appendAnd ? " && " : string.Empty;
switch (permutations[p][i].Key.keywordType)
{
case KeywordType.Enum:
{
sb.Append($"{and}defined({permutations[p][i].Key.referenceName}_{permutations[p][i].Key.entries[permutations[p][i].Value].referenceName})");
appendAnd = true;
break;
}
case KeywordType.Boolean:
{
// HLSL does not support a !value predicate
if (permutations[p][i].Value != 0)
{
continue;
}
sb.Append($"{and}defined({permutations[p][i].Key.referenceName})");
appendAnd = true;
break;
}
default:
throw new ArgumentOutOfRangeException();
}
}
}
sb.AppendNewLine();
// Define the matching permutation keyword
sb.IncreaseIndent();
sb.AppendLine($"#define KEYWORD_PERMUTATION_{p}");
sb.DecreaseIndent();
}
// End statement
sb.AppendLine("#endif");
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 19fef5ded8573c34a80cf81ed0f9c56a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,19 @@
using System;
using UnityEngine;
namespace UnityEditor.Graphing
{
class ConsoleLogHandler : ILogHandler
{
public void LogFormat(LogType logType, UnityEngine.Object context, string format, params object[] args)
{
var formatted = string.Format(format, args);
Console.WriteLine("{0}:{1} - {2}", logType, context, formatted);
}
public void LogException(Exception exception, UnityEngine.Object context)
{
Console.WriteLine("{0} - {1}", context, exception);
}
}
}

View file

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ffca76f71e6326344ad2ff5e823d02f9
timeCreated: 1464264926
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using UnityEngine.Assertions;
namespace UnityEditor.ShaderGraph
{
class PooledHashSet<T> : HashSet<T>, IDisposable
{
static Stack<PooledHashSet<T>> s_Pool = new Stack<PooledHashSet<T>>();
bool m_Active;
PooledHashSet() { }
public static PooledHashSet<T> Get()
{
if (s_Pool.Count == 0)
{
return new PooledHashSet<T> { m_Active = true };
}
var list = s_Pool.Pop();
list.m_Active = true;
#if DEBUG
GC.ReRegisterForFinalize(list);
#endif
return list;
}
public void Dispose()
{
Assert.IsTrue(m_Active);
m_Active = false;
Clear();
s_Pool.Push(this);
#if DEBUG
GC.SuppressFinalize(this);
#endif
}
// Destructor causes some GC alloc so only do this sanity check in debug build
#if DEBUG
~PooledHashSet()
{
throw new InvalidOperationException($"{nameof(PooledHashSet<T>)} must be disposed manually.");
}
#endif
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 11c00f8215374c368941cd4c06242ed7
timeCreated: 1582812009

View file

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using UnityEngine.Assertions;
namespace UnityEditor.ShaderGraph
{
class PooledList<T> : List<T>, IDisposable
{
static Stack<PooledList<T>> s_Pool = new Stack<PooledList<T>>();
bool m_Active;
PooledList() { }
public static PooledList<T> Get()
{
if (s_Pool.Count == 0)
{
return new PooledList<T> { m_Active = true };
}
var list = s_Pool.Pop();
list.m_Active = true;
#if DEBUG
GC.ReRegisterForFinalize(list);
#endif
return list;
}
public void Dispose()
{
Assert.IsTrue(m_Active);
m_Active = false;
Clear();
s_Pool.Push(this);
#if DEBUG
GC.SuppressFinalize(this);
#endif
}
// Destructor causes some GC alloc so only do this sanity check in debug build
#if DEBUG
~PooledList()
{
throw new InvalidOperationException($"{nameof(PooledList<T>)} must be disposed manually.");
}
#endif
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9f3065ccf1f64e219d8039d355a788a1
timeCreated: 1579171175

View file

@ -0,0 +1,85 @@
using UnityEditor.ShaderGraph.Internal;
namespace UnityEditor.ShaderGraph
{
internal static class PrecisionUtil
{
internal const string Token = "$precision";
internal static string ToShaderString(this ConcretePrecision precision)
{
switch (precision)
{
case ConcretePrecision.Single:
return "float";
case ConcretePrecision.Half:
return "half";
default:
return "float";
}
}
internal static string ToGenericString(this GraphPrecision precision)
{
switch (precision)
{
case GraphPrecision.Single:
return "float";
case GraphPrecision.Half:
return "half";
default:
return Token;
}
}
internal static ConcretePrecision ToConcrete(this Precision precision, ConcretePrecision InheritPrecision, ConcretePrecision GraphPrecision)
{
switch (precision)
{
case Precision.Single:
return ConcretePrecision.Single;
case Precision.Half:
return ConcretePrecision.Half;
case Precision.Inherit:
return InheritPrecision;
default:
return GraphPrecision;
}
}
internal static GraphPrecision ToGraphPrecision(this Precision precision, GraphPrecision inheritPrecision)
{
switch (precision)
{
case Precision.Single:
return GraphPrecision.Single;
case Precision.Half:
return GraphPrecision.Half;
case Precision.Graph:
return GraphPrecision.Graph;
default:
return inheritPrecision;
}
}
internal static ConcretePrecision ToConcrete(this GraphPrecision precision, ConcretePrecision graphPrecision)
{
switch (precision)
{
case GraphPrecision.Single:
return ConcretePrecision.Single;
case GraphPrecision.Half:
return ConcretePrecision.Half;
default:
return graphPrecision;
}
}
internal static GraphPrecision GraphFallback(this GraphPrecision precision, GraphPrecision graphFallback)
{
if (precision == GraphPrecision.Graph)
return graphFallback;
return precision;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 501418e118466ec499de0e77616e5e00
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,50 @@
using System;
using UnityEngine;
using UnityEditor.ShaderGraph.Internal;
namespace UnityEditor.ShaderGraph
{
static class PropertyUtil
{
public static ConcreteSlotValueType ToConcreteShaderValueType(this PropertyType propertyType)
{
switch (propertyType)
{
case PropertyType.SamplerState:
return ConcreteSlotValueType.SamplerState;
case PropertyType.Matrix4:
return ConcreteSlotValueType.Matrix4;
case PropertyType.Matrix3:
return ConcreteSlotValueType.Matrix3;
case PropertyType.Matrix2:
return ConcreteSlotValueType.Matrix2;
case PropertyType.Texture2D:
return ConcreteSlotValueType.Texture2D;
case PropertyType.Texture2DArray:
return ConcreteSlotValueType.Texture2DArray;
case PropertyType.Texture3D:
return ConcreteSlotValueType.Texture3D;
case PropertyType.Cubemap:
return ConcreteSlotValueType.Cubemap;
case PropertyType.Gradient:
return ConcreteSlotValueType.Gradient;
case PropertyType.Vector4:
return ConcreteSlotValueType.Vector4;
case PropertyType.Vector3:
return ConcreteSlotValueType.Vector3;
case PropertyType.Vector2:
return ConcreteSlotValueType.Vector2;
case PropertyType.Float:
return ConcreteSlotValueType.Vector1;
case PropertyType.Boolean:
return ConcreteSlotValueType.Boolean;
case PropertyType.Color:
return ConcreteSlotValueType.Vector4;
case PropertyType.VirtualTexture:
return ConcreteSlotValueType.VirtualTexture;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e284d5ec141b1b24a8509176d21b1d3f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,28 @@
namespace UnityEditor.ShaderGraph
{
enum ScreenSpaceType
{
Default,
Raw,
Center,
Tiled
};
static class ScreenSpaceTypeExtensions
{
public static string ToValueAsVariable(this ScreenSpaceType screenSpaceType)
{
switch (screenSpaceType)
{
case ScreenSpaceType.Raw:
return string.Format("IN.{0}", ShaderGeneratorNames.ScreenPosition);
case ScreenSpaceType.Center:
return string.Format("$precision4(IN.{0}.xy / IN.{0}.w * 2 - 1, 0, 0)", ShaderGeneratorNames.ScreenPosition);
case ScreenSpaceType.Tiled:
return string.Format("frac($precision4((IN.{0}.x / IN.{0}.w * 2 - 1) * _ScreenParams.x / _ScreenParams.y, IN.{0}.y / IN.{0}.w * 2 - 1, 0, 0))", ShaderGeneratorNames.ScreenPosition);
default:
return string.Format("$precision4(IN.{0}.xy / IN.{0}.w, 0, 0)", ShaderGeneratorNames.ScreenPosition);
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d296e8d1103ed5c49a267d57be0f4d96
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,195 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using UnityEditor.ShaderGraph.Serialization;
using UnityEngine;
namespace UnityEditor.Graphing
{
static class SerializationHelper
{
[Serializable]
public struct TypeSerializationInfo
{
[SerializeField]
public string fullName;
public bool IsValid()
{
return !string.IsNullOrEmpty(fullName);
}
}
[Serializable]
public struct JSONSerializedElement
{
[SerializeField]
public TypeSerializationInfo typeInfo;
[SerializeField]
public string JSONnodeData;
}
public static JSONSerializedElement nullElement
{
get
{
return new JSONSerializedElement();
}
}
public static TypeSerializationInfo GetTypeSerializableAsString(Type type)
{
return new TypeSerializationInfo
{
fullName = type.FullName
};
}
static Type GetTypeFromSerializedString(TypeSerializationInfo typeInfo)
{
if (!typeInfo.IsValid())
return null;
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
var type = assembly.GetType(typeInfo.fullName);
if (type != null)
return type;
}
return null;
}
public static JSONSerializedElement Serialize<T>(T item)
{
if (item is JsonObject jsonObject)
return new JSONSerializedElement() { JSONnodeData = jsonObject.Serialize() };
if (item == null)
throw new ArgumentNullException("item", "Can not serialize null element");
//check if unknownnode type - if so, return saved metadata
//unknown node type will need onbeforeserialize to set guid and edges and all the things
var typeInfo = GetTypeSerializableAsString(item.GetType());
var data = JsonUtility.ToJson(item, true);
if (string.IsNullOrEmpty(data))
throw new ArgumentException(string.Format("Can not serialize {0}", item));
return new JSONSerializedElement
{
typeInfo = typeInfo,
JSONnodeData = data
};
}
static TypeSerializationInfo DoTypeRemap(TypeSerializationInfo info, Dictionary<TypeSerializationInfo, TypeSerializationInfo> remapper)
{
TypeSerializationInfo foundInfo;
if (remapper.TryGetValue(info, out foundInfo))
return foundInfo;
return info;
}
public static T Deserialize<T>(JSONSerializedElement item, Dictionary<TypeSerializationInfo, TypeSerializationInfo> remapper, params object[] constructorArgs) where T : class
{
T instance;
if (typeof(T) == typeof(JsonObject) || typeof(T).IsSubclassOf(typeof(JsonObject)))
{
try
{
var culture = CultureInfo.CurrentCulture;
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
instance = Activator.CreateInstance(typeof(T), flags, null, constructorArgs, culture) as T;
}
catch (Exception e)
{
throw new Exception(string.Format("Could not construct instance of: {0}", typeof(T)), e);
}
MultiJson.Deserialize(instance as JsonObject, item.JSONnodeData);
return instance;
}
if (!item.typeInfo.IsValid() || string.IsNullOrEmpty(item.JSONnodeData))
throw new ArgumentException(string.Format("Can not deserialize {0}, it is invalid", item));
TypeSerializationInfo info = item.typeInfo;
info.fullName = info.fullName.Replace("UnityEngine.MaterialGraph", "UnityEditor.ShaderGraph");
info.fullName = info.fullName.Replace("UnityEngine.Graphing", "UnityEditor.Graphing");
if (remapper != null)
info = DoTypeRemap(info, remapper);
var type = GetTypeFromSerializedString(info);
//if type is null but T is an abstract material node, instead we create an unknowntype node
if (type == null)
{
throw new ArgumentException(string.Format("Can not deserialize ({0}), type is invalid", info.fullName));
}
try
{
var culture = CultureInfo.CurrentCulture;
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
instance = Activator.CreateInstance(type, flags, null, constructorArgs, culture) as T;
}
catch (Exception e)
{
throw new Exception(string.Format("Could not construct instance of: {0}", type), e);
}
if (instance != null)
{
JsonUtility.FromJsonOverwrite(item.JSONnodeData, instance);
return instance;
}
Debug.Log("UhOh");
return null;
}
public static List<JSONSerializedElement> Serialize<T>(IEnumerable<T> list)
{
var result = new List<JSONSerializedElement>();
if (list == null)
return result;
foreach (var element in list)
{
try
{
result.Add(Serialize(element));
}
catch (Exception e)
{
Debug.LogException(e);
}
}
return result;
}
public static List<T> Deserialize<T>(IEnumerable<JSONSerializedElement> list, Dictionary<TypeSerializationInfo, TypeSerializationInfo> remapper, params object[] constructorArgs) where T : class
{
var result = new List<T>();
if (list == null)
return result;
foreach (var element in list)
{
try
{
result.Add(Deserialize<T>(element, remapper));
}
catch (Exception e)
{
Debug.LogException(e);
Debug.LogError(element.JSONnodeData);
}
}
return result;
}
}
}

View file

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f6657676e9fd9cd4bbcb26b0771df3ac
timeCreated: 1464079585
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,132 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor.ShaderGraph;
namespace UnityEditor.ShaderGraph.Internal
{
sealed class ShaderGraphRequirementsPerKeyword : KeywordDependentCollection<
ShaderGraphRequirements,
ShaderGraphRequirementsPerKeyword.All,
ShaderGraphRequirementsPerKeyword.AllPermutations,
ShaderGraphRequirementsPerKeyword.ForPermutationIndex,
ShaderGraphRequirementsPerKeyword.Base,
ShaderGraphRequirementsPerKeyword.IRequirements,
ShaderGraphRequirementsPerKeyword.IRequirementsSet
>
{
public interface IRequirements : KeywordDependentCollection.IInstance, KeywordDependentCollection.ISet<IRequirements>
{
void SetRequirements(ShaderGraphRequirements value);
ShaderGraphRequirements requirements { get; set; }
}
public interface IRequirementsSet : KeywordDependentCollection.ISet<IRequirements>
{
}
public struct ForPermutationIndex : IRequirements, IRequirementsSet
{
private ShaderGraphRequirementsPerKeyword m_Source;
private int m_PermutationIndex;
public KeywordDependentCollection.KeywordPermutationInstanceType type => KeywordDependentCollection.KeywordPermutationInstanceType.Permutation;
public IEnumerable<IRequirements> instances => Enumerable.Repeat<IRequirements>(this, 1);
public int instanceCount => 1;
public int permutationIndex => m_PermutationIndex;
public ShaderGraphRequirements requirements
{
get => m_Source.GetOrCreateForPermutationIndex(m_PermutationIndex);
set => m_Source.SetForPermutationIndex(m_PermutationIndex, value);
}
public void SetRequirements(ShaderGraphRequirements value) => requirements = value;
internal ForPermutationIndex(ShaderGraphRequirementsPerKeyword source, int index)
{
m_Source = source;
m_PermutationIndex = index;
}
}
public struct Base : IRequirements, IRequirementsSet
{
private ShaderGraphRequirementsPerKeyword m_Source;
public int instanceCount => 1;
public int permutationIndex => -1;
public KeywordDependentCollection.KeywordPermutationInstanceType type => KeywordDependentCollection.KeywordPermutationInstanceType.Base;
public IEnumerable<IRequirements> instances => Enumerable.Repeat<IRequirements>(this, 1);
public ShaderGraphRequirements requirements
{
get => m_Source.baseStorage;
set => m_Source.baseStorage = value;
}
public void SetRequirements(ShaderGraphRequirements value) => requirements = value;
internal Base(ShaderGraphRequirementsPerKeyword source)
{
m_Source = source;
}
}
public struct All : IRequirementsSet
{
private ShaderGraphRequirementsPerKeyword m_Source;
public int instanceCount => m_Source.permutationCount + 1;
internal All(ShaderGraphRequirementsPerKeyword source)
{
m_Source = source;
}
public IEnumerable<IRequirements> instances
{
get
{
var self = this;
return m_Source.permutationStorages
.Select((v, i) => new ForPermutationIndex(self.m_Source, i) as IRequirements)
.Union(Enumerable.Repeat((IRequirements)m_Source.baseInstance, 1));
}
}
}
public struct AllPermutations : IRequirementsSet
{
private ShaderGraphRequirementsPerKeyword m_Source;
public int instanceCount => m_Source.permutationCount;
internal AllPermutations(ShaderGraphRequirementsPerKeyword source)
{
m_Source = source;
}
public IEnumerable<IRequirements> instances
{
get
{
var self = this;
return m_Source.permutationStorages
.Select((v, i) => new ForPermutationIndex(self.m_Source, i) as IRequirements);
}
}
}
public void UnionWith(ShaderGraphRequirementsPerKeyword other)
{
baseStorage = baseStorage.Union(other.baseStorage);
for (var i = 0; i < other.permutationCount; ++i)
SetForPermutationIndex(i,
GetOrCreateForPermutationIndex(i).Union(other.GetOrCreateForPermutationIndex(i)));
}
protected override All CreateAllSmartPointer() => new All(this);
protected override AllPermutations CreateAllPermutationsSmartPointer() => new AllPermutations(this);
protected override ForPermutationIndex CreateForPermutationSmartPointer(int index) => new ForPermutationIndex(this, index);
protected override Base CreateBaseSmartPointer() => new Base(this);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7d59a0bb237356a4f8f2284efb092c15
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,202 @@
using System;
using UnityEditor.ShaderGraph.Internal;
using UnityEngine;
namespace UnityEditor.ShaderGraph
{
static class SlotValueTypeUtil
{
public static SlotValueType ToSlotValueType(this ConcreteSlotValueType concreteValueType)
{
switch (concreteValueType)
{
case ConcreteSlotValueType.SamplerState:
return SlotValueType.SamplerState;
case ConcreteSlotValueType.Matrix4:
return SlotValueType.Matrix4;
case ConcreteSlotValueType.Matrix3:
return SlotValueType.Matrix3;
case ConcreteSlotValueType.Matrix2:
return SlotValueType.Matrix2;
case ConcreteSlotValueType.Texture2D:
return SlotValueType.Texture2D;
case ConcreteSlotValueType.Texture2DArray:
return SlotValueType.Texture2DArray;
case ConcreteSlotValueType.Texture3D:
return SlotValueType.Texture3D;
case ConcreteSlotValueType.Cubemap:
return SlotValueType.Cubemap;
case ConcreteSlotValueType.Gradient:
return SlotValueType.Gradient;
case ConcreteSlotValueType.Vector4:
return SlotValueType.Vector4;
case ConcreteSlotValueType.Vector3:
return SlotValueType.Vector3;
case ConcreteSlotValueType.Vector2:
return SlotValueType.Vector2;
case ConcreteSlotValueType.Vector1:
return SlotValueType.Vector1;
case ConcreteSlotValueType.Boolean:
return SlotValueType.Boolean;
case ConcreteSlotValueType.VirtualTexture:
return SlotValueType.VirtualTexture;
case ConcreteSlotValueType.PropertyConnectionState:
return SlotValueType.PropertyConnectionState;
default:
throw new ArgumentOutOfRangeException();
}
}
public static ConcreteSlotValueType ToConcreteSlotValueType(this SlotValueType slotValueType)
{
switch (slotValueType)
{
case SlotValueType.SamplerState:
return ConcreteSlotValueType.SamplerState;
case SlotValueType.Matrix2:
return ConcreteSlotValueType.Matrix2;
case SlotValueType.Matrix3:
return ConcreteSlotValueType.Matrix3;
case SlotValueType.Matrix4:
return ConcreteSlotValueType.Matrix4;
case SlotValueType.Texture2D:
return ConcreteSlotValueType.Texture2D;
case SlotValueType.Texture2DArray:
return ConcreteSlotValueType.Texture2DArray;
case SlotValueType.Texture3D:
return ConcreteSlotValueType.Texture3D;
case SlotValueType.Cubemap:
return ConcreteSlotValueType.Cubemap;
case SlotValueType.Gradient:
return ConcreteSlotValueType.Gradient;
case SlotValueType.Vector4:
return ConcreteSlotValueType.Vector4;
case SlotValueType.Vector3:
return ConcreteSlotValueType.Vector3;
case SlotValueType.Vector2:
return ConcreteSlotValueType.Vector2;
case SlotValueType.Vector1:
return ConcreteSlotValueType.Vector1;
case SlotValueType.Boolean:
return ConcreteSlotValueType.Boolean;
case SlotValueType.VirtualTexture:
return ConcreteSlotValueType.VirtualTexture;
case SlotValueType.PropertyConnectionState:
return ConcreteSlotValueType.PropertyConnectionState;
default:
throw new ArgumentOutOfRangeException();
}
}
public static PropertyType ToPropertyType(this ConcreteSlotValueType concreteValueType)
{
switch (concreteValueType)
{
case ConcreteSlotValueType.SamplerState:
return PropertyType.SamplerState;
case ConcreteSlotValueType.Matrix4:
return PropertyType.Matrix4;
case ConcreteSlotValueType.Matrix3:
return PropertyType.Matrix3;
case ConcreteSlotValueType.Matrix2:
return PropertyType.Matrix2;
case ConcreteSlotValueType.Texture2D:
return PropertyType.Texture2D;
case ConcreteSlotValueType.Texture2DArray:
return PropertyType.Texture2DArray;
case ConcreteSlotValueType.Texture3D:
return PropertyType.Texture3D;
case ConcreteSlotValueType.Cubemap:
return PropertyType.Cubemap;
case ConcreteSlotValueType.Gradient:
return PropertyType.Gradient;
case ConcreteSlotValueType.Vector4:
return PropertyType.Vector4;
case ConcreteSlotValueType.Vector3:
return PropertyType.Vector3;
case ConcreteSlotValueType.Vector2:
return PropertyType.Vector2;
case ConcreteSlotValueType.Vector1:
return PropertyType.Float;
case ConcreteSlotValueType.Boolean:
return PropertyType.Boolean;
case ConcreteSlotValueType.VirtualTexture:
return PropertyType.VirtualTexture;
case ConcreteSlotValueType.PropertyConnectionState:
return PropertyType.PropertyConnectionState;
default:
throw new ArgumentOutOfRangeException();
}
}
public static string ToShaderString(this ConcreteSlotValueType type, ConcretePrecision concretePrecision)
{
string precisionString = concretePrecision.ToShaderString();
return type.ToShaderString(precisionString);
}
public static string ToShaderString(this ConcreteSlotValueType type, string precisionToken = PrecisionUtil.Token)
{
switch (type)
{
case ConcreteSlotValueType.SamplerState:
return "UnitySamplerState";
case ConcreteSlotValueType.Matrix4:
return precisionToken + "4x4";
case ConcreteSlotValueType.Matrix3:
return precisionToken + "3x3";
case ConcreteSlotValueType.Matrix2:
return precisionToken + "2x2";
case ConcreteSlotValueType.Texture2D:
return "UnityTexture2D";
case ConcreteSlotValueType.Texture2DArray:
return "UnityTexture2DArray";
case ConcreteSlotValueType.Texture3D:
return "UnityTexture3D";
case ConcreteSlotValueType.Cubemap:
return "UnityTextureCube";
case ConcreteSlotValueType.Gradient:
return "Gradient";
case ConcreteSlotValueType.Vector4:
return precisionToken + "4";
case ConcreteSlotValueType.Vector3:
return precisionToken + "3";
case ConcreteSlotValueType.Vector2:
return precisionToken + "2";
case ConcreteSlotValueType.Vector1:
return precisionToken;
case ConcreteSlotValueType.Boolean:
return precisionToken;
case ConcreteSlotValueType.PropertyConnectionState:
return "bool";
default:
return "Error";
}
}
public static string ToClassName(this ConcreteSlotValueType type)
{
return k_ConcreteSlotValueTypeClassNames[(int)type];
}
static readonly string[] k_ConcreteSlotValueTypeClassNames =
{
null,
"typeMatrix",
"typeMatrix",
"typeMatrix",
"typeTexture2D",
"typeTexture2DArray",
"typeTexture3D",
"typeCubemap",
"typeGradient",
"typeFloat4",
"typeFloat3",
"typeFloat2",
"typeFloat1",
"typeBoolean",
"typeVirtualTexture",
"typePropertyConnectionState"
};
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e28cefa3fa391ed48a67c0b476a0a95c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,21 @@
using System.Collections.Generic;
using UnityEngine.Pool;
namespace UnityEditor.Graphing
{
static class StackPool<T>
{
// Object pool to avoid allocations.
static readonly ObjectPool<Stack<T>> k_StackPool = new ObjectPool<Stack<T>>(() => new Stack<T>(), null, l => l.Clear());
public static Stack<T> Get()
{
return k_StackPool.Get();
}
public static void Release(Stack<T> toRelease)
{
k_StackPool.Release(toRelease);
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 93c41a4331c94d09a7561ea6b4983439
timeCreated: 1505275069

View file

@ -0,0 +1,12 @@
using System.Text.RegularExpressions;
namespace UnityEditor.ShaderGraph
{
public static class TextUtil
{
public static string PascalToLabel(this string pascalString)
{
return Regex.Replace(pascalString, "(\\B[A-Z])", " $1");
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c5dad4902719d054ba79ba0b3108591a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,12 @@
using System;
namespace UnityEditor.ShaderGraph.Internal
{
public enum UVChannel
{
UV0 = 0,
UV1 = 1,
UV2 = 2,
UV3 = 3,
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d77363d2f0df1f544b21d9e8a05f01a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: