initial commit
This commit is contained in:
parent
6715289efe
commit
788c3389af
37645 changed files with 2526849 additions and 80 deletions
|
@ -0,0 +1,299 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Experimental.GraphView;
|
||||
using UnityEditor.Graphing;
|
||||
using UnityEditor.ShaderGraph.Internal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
using UnityEngine.UIElements;
|
||||
using GraphDataStore = UnityEditor.ShaderGraph.DataStore<UnityEditor.ShaderGraph.GraphData>;
|
||||
using BlackboardItem = UnityEditor.ShaderGraph.Internal.ShaderInput;
|
||||
using BlackboardItemController = UnityEditor.ShaderGraph.Drawing.ShaderInputViewController;
|
||||
|
||||
namespace UnityEditor.ShaderGraph.Drawing
|
||||
{
|
||||
class MoveShaderInputAction : IGraphDataAction
|
||||
{
|
||||
void MoveShaderInput(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out MoveShaderInputAction");
|
||||
AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out MoveShaderInputAction");
|
||||
graphData.owner.RegisterCompleteObjectUndo("Move Graph Input");
|
||||
graphData.MoveItemInCategory(shaderInputReference, newIndexValue, associatedCategoryGuid);
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => MoveShaderInput;
|
||||
|
||||
internal string associatedCategoryGuid { get; set; }
|
||||
|
||||
// Reference to the shader input being modified
|
||||
internal ShaderInput shaderInputReference { get; set; }
|
||||
|
||||
internal int newIndexValue { get; set; }
|
||||
}
|
||||
|
||||
class DeleteCategoryAction : IGraphDataAction
|
||||
{
|
||||
void RemoveCategory(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out DeleteCategoryAction");
|
||||
AssertHelpers.IsNotNull(categoriesToRemoveGuids, "CategoryToRemove is null while carrying out DeleteCategoryAction");
|
||||
|
||||
// This is called by MaterialGraphView currently, no need to repeat it here, though ideally it would live here
|
||||
//graphData.owner.RegisterCompleteObjectUndo("Delete Category");
|
||||
|
||||
foreach (var categoryGUID in categoriesToRemoveGuids)
|
||||
{
|
||||
graphData.RemoveCategory(categoryGUID);
|
||||
}
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => RemoveCategory;
|
||||
|
||||
// Reference to the guid(s) of categories being deleted
|
||||
public HashSet<string> categoriesToRemoveGuids { get; set; } = new HashSet<string>();
|
||||
}
|
||||
|
||||
class ChangeCategoryIsExpandedAction : IGraphDataAction
|
||||
{
|
||||
internal const string kEditorPrefKey = ".isCategoryExpanded";
|
||||
|
||||
void ChangeIsExpanded(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeIsExpanded on Category");
|
||||
foreach (var catid in categoryGuids)
|
||||
{
|
||||
var key = $"{editorPrefsBaseKey}.{catid}.{kEditorPrefKey}";
|
||||
var currentValue = EditorPrefs.GetBool(key, true);
|
||||
|
||||
if (currentValue != isExpanded)
|
||||
{
|
||||
EditorPrefs.SetBool(key, isExpanded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string editorPrefsBaseKey;
|
||||
public List<string> categoryGuids { get; set; }
|
||||
public bool isExpanded { get; set; }
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => ChangeIsExpanded;
|
||||
}
|
||||
|
||||
class ChangeCategoryNameAction : IGraphDataAction
|
||||
{
|
||||
void ChangeCategoryName(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeCategoryNameAction");
|
||||
graphData.owner.RegisterCompleteObjectUndo("Change Category Name");
|
||||
graphData.ChangeCategoryName(categoryGuid, newCategoryNameValue);
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => ChangeCategoryName;
|
||||
|
||||
// Guid of the category being modified
|
||||
public string categoryGuid { get; set; }
|
||||
|
||||
internal string newCategoryNameValue { get; set; }
|
||||
}
|
||||
|
||||
class BlackboardCategoryController : SGViewController<CategoryData, BlackboardCategoryViewModel>
|
||||
{
|
||||
internal SGBlackboardCategory blackboardCategoryView => m_BlackboardCategoryView;
|
||||
SGBlackboardCategory m_BlackboardCategoryView;
|
||||
Dictionary<string, BlackboardItemController> m_BlackboardItemControllers = new Dictionary<string, ShaderInputViewController>();
|
||||
SGBlackboard blackboard { get; set; }
|
||||
|
||||
internal BlackboardCategoryController(CategoryData categoryData, BlackboardCategoryViewModel categoryViewModel, GraphDataStore dataStore)
|
||||
: base(categoryData, categoryViewModel, dataStore)
|
||||
{
|
||||
m_BlackboardCategoryView = new SGBlackboardCategory(categoryViewModel, this);
|
||||
blackboard = categoryViewModel.parentView as SGBlackboard;
|
||||
if (blackboard == null)
|
||||
return;
|
||||
|
||||
blackboard.Add(m_BlackboardCategoryView);
|
||||
// These make sure that the drag indicators are disabled whenever a drag action is cancelled without completing a drop
|
||||
blackboard.RegisterCallback<MouseUpEvent>(evt =>
|
||||
{
|
||||
m_BlackboardCategoryView.OnDragActionCanceled();
|
||||
});
|
||||
blackboard.hideDragIndicatorAction += m_BlackboardCategoryView.OnDragActionCanceled;
|
||||
|
||||
foreach (var categoryItem in categoryData.Children)
|
||||
{
|
||||
if (categoryItem == null)
|
||||
{
|
||||
AssertHelpers.Fail("Failed to insert blackboard row into category due to shader input being null.");
|
||||
continue;
|
||||
}
|
||||
InsertBlackboardRow(categoryItem);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RequestModelChange(IGraphDataAction changeAction)
|
||||
{
|
||||
DataStore.Dispatch(changeAction);
|
||||
}
|
||||
|
||||
// Called by GraphDataStore.Subscribe after the model has been changed
|
||||
protected override void ModelChanged(GraphData graphData, IGraphDataAction changeAction)
|
||||
{
|
||||
// If categoryData associated with this controller is removed by an operation, destroy controller and views associated
|
||||
if (graphData.ContainsCategory(Model) == false)
|
||||
{
|
||||
this.Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (changeAction)
|
||||
{
|
||||
case AddShaderInputAction addBlackboardItemAction:
|
||||
if (addBlackboardItemAction.shaderInputReference != null && IsInputInCategory(addBlackboardItemAction.shaderInputReference))
|
||||
{
|
||||
var blackboardRow = FindBlackboardRow(addBlackboardItemAction.shaderInputReference);
|
||||
if (blackboardRow == null)
|
||||
blackboardRow = InsertBlackboardRow(addBlackboardItemAction.shaderInputReference);
|
||||
// Rows should auto-expand when an input is first added
|
||||
// blackboardRow.expanded = true;
|
||||
var propertyView = blackboardRow.Q<SGBlackboardField>();
|
||||
if (addBlackboardItemAction.addInputActionType == AddShaderInputAction.AddActionSource.AddMenu)
|
||||
propertyView.OpenTextEditor();
|
||||
}
|
||||
break;
|
||||
|
||||
case CopyShaderInputAction copyShaderInputAction:
|
||||
// In the specific case of only-one keywords like Material Quality and Raytracing, they can get copied, but because only one can exist, the output copied value is null
|
||||
if (copyShaderInputAction.copiedShaderInput != null && IsInputInCategory(copyShaderInputAction.copiedShaderInput))
|
||||
{
|
||||
var blackboardRow = InsertBlackboardRow(copyShaderInputAction.copiedShaderInput, copyShaderInputAction.insertIndex);
|
||||
if (blackboardRow != null)
|
||||
{
|
||||
var graphView = ViewModel.parentView.GetFirstAncestorOfType<MaterialGraphView>();
|
||||
var propertyView = blackboardRow.Q<SGBlackboardField>();
|
||||
graphView?.AddToSelectionNoUndoRecord(propertyView);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AddItemToCategoryAction addItemToCategoryAction:
|
||||
// If item was added to category that this controller manages, then add blackboard row to represent that item
|
||||
if (addItemToCategoryAction.itemToAdd != null && addItemToCategoryAction.categoryGuid == ViewModel.associatedCategoryGuid)
|
||||
{
|
||||
InsertBlackboardRow(addItemToCategoryAction.itemToAdd, addItemToCategoryAction.indexToAddItemAt);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the added input has been added to a category other than this one, and it used to belong to this category,
|
||||
// Then cleanup the controller and view that used to represent that input
|
||||
foreach (var key in m_BlackboardItemControllers.Keys)
|
||||
{
|
||||
var blackboardItemController = m_BlackboardItemControllers[key];
|
||||
if (blackboardItemController.Model == addItemToCategoryAction.itemToAdd)
|
||||
{
|
||||
RemoveBlackboardRow(addItemToCategoryAction.itemToAdd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DeleteCategoryAction deleteCategoryAction:
|
||||
if (deleteCategoryAction.categoriesToRemoveGuids.Contains(ViewModel.associatedCategoryGuid))
|
||||
{
|
||||
this.Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ChangeCategoryIsExpandedAction changeIsExpandedAction:
|
||||
if (changeIsExpandedAction.categoryGuids.Contains(ViewModel.associatedCategoryGuid))
|
||||
{
|
||||
ViewModel.isExpanded = changeIsExpandedAction.isExpanded;
|
||||
m_BlackboardCategoryView.TryDoFoldout(changeIsExpandedAction.isExpanded);
|
||||
}
|
||||
break;
|
||||
|
||||
case ChangeCategoryNameAction changeCategoryNameAction:
|
||||
if (changeCategoryNameAction.categoryGuid == ViewModel.associatedCategoryGuid)
|
||||
{
|
||||
ViewModel.name = Model.name;
|
||||
m_BlackboardCategoryView.title = ViewModel.name;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsInputInCategory(ShaderInput shaderInput)
|
||||
{
|
||||
return Model != null && Model.IsItemInCategory(shaderInput);
|
||||
}
|
||||
|
||||
internal SGBlackboardRow FindBlackboardRow(ShaderInput shaderInput)
|
||||
{
|
||||
m_BlackboardItemControllers.TryGetValue(shaderInput.objectId, out var associatedController);
|
||||
return associatedController?.BlackboardItemView;
|
||||
}
|
||||
|
||||
// Creates controller, view and view model for a blackboard item and adds the view to the specified index in the category
|
||||
// By default adds it to the end of the list if no insertionIndex specified
|
||||
internal SGBlackboardRow InsertBlackboardRow(BlackboardItem shaderInput, int insertionIndex = -1)
|
||||
{
|
||||
var shaderInputViewModel = new ShaderInputViewModel()
|
||||
{
|
||||
model = shaderInput,
|
||||
parentView = blackboardCategoryView,
|
||||
};
|
||||
var blackboardItemController = new BlackboardItemController(shaderInput, shaderInputViewModel, DataStore);
|
||||
|
||||
m_BlackboardItemControllers.TryGetValue(shaderInput.objectId, out var existingItemController);
|
||||
if (existingItemController == null)
|
||||
{
|
||||
m_BlackboardItemControllers.Add(shaderInput.objectId, blackboardItemController);
|
||||
// If no index specified, add to end of category
|
||||
if (insertionIndex == -1)
|
||||
blackboardCategoryView.Add(blackboardItemController.BlackboardItemView);
|
||||
else
|
||||
blackboardCategoryView.Insert(insertionIndex, blackboardItemController.BlackboardItemView);
|
||||
|
||||
blackboardCategoryView.MarkDirtyRepaint();
|
||||
|
||||
return blackboardItemController.BlackboardItemView;
|
||||
}
|
||||
else
|
||||
{
|
||||
AssertHelpers.Fail("Tried to add blackboard item that already exists to category.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal void RemoveBlackboardRow(BlackboardItem shaderInput)
|
||||
{
|
||||
m_BlackboardItemControllers.TryGetValue(shaderInput.objectId, out var associatedBlackboardItemController);
|
||||
if (associatedBlackboardItemController != null)
|
||||
{
|
||||
associatedBlackboardItemController.Destroy();
|
||||
m_BlackboardItemControllers.Remove(shaderInput.objectId);
|
||||
}
|
||||
else
|
||||
AssertHelpers.Fail("Failed to find associated blackboard item controller for shader input that was just deleted. Cannot clean up view associated with input.");
|
||||
}
|
||||
|
||||
void ClearBlackboardRows()
|
||||
{
|
||||
foreach (var shaderInputViewController in m_BlackboardItemControllers.Values)
|
||||
shaderInputViewController.Destroy();
|
||||
|
||||
m_BlackboardItemControllers.Clear();
|
||||
}
|
||||
|
||||
public override void Destroy()
|
||||
{
|
||||
Cleanup();
|
||||
m_BlackboardCategoryView?.RemoveFromHierarchy();
|
||||
ClearBlackboardRows();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 415e66e3c4ba4ffd834a7d90349db989
|
||||
timeCreated: 1612206426
|
|
@ -0,0 +1,818 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEditor.Experimental.GraphView;
|
||||
using UnityEngine.UIElements;
|
||||
using System;
|
||||
using UnityEditor.Graphing;
|
||||
using UnityEditor.ShaderGraph.Internal;
|
||||
using GraphDataStore = UnityEditor.ShaderGraph.DataStore<UnityEditor.ShaderGraph.GraphData>;
|
||||
using BlackboardItem = UnityEditor.ShaderGraph.Internal.ShaderInput;
|
||||
|
||||
namespace UnityEditor.ShaderGraph.Drawing
|
||||
{
|
||||
struct BlackboardShaderInputOrder
|
||||
{
|
||||
public bool isKeyword;
|
||||
public bool isDropdown;
|
||||
public KeywordType keywordType;
|
||||
public ShaderKeyword builtInKeyword;
|
||||
public string deprecatedPropertyName;
|
||||
public int version;
|
||||
}
|
||||
class BlackboardShaderInputFactory
|
||||
{
|
||||
static public ShaderInput GetShaderInput(BlackboardShaderInputOrder order)
|
||||
{
|
||||
ShaderInput output;
|
||||
if (order.isKeyword)
|
||||
{
|
||||
if (order.builtInKeyword == null)
|
||||
{
|
||||
output = new ShaderKeyword(order.keywordType);
|
||||
}
|
||||
else
|
||||
{
|
||||
output = order.builtInKeyword;
|
||||
}
|
||||
}
|
||||
else if (order.isDropdown)
|
||||
{
|
||||
output = new ShaderDropdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (order.deprecatedPropertyName)
|
||||
{
|
||||
case "Color":
|
||||
output = new ColorShaderProperty(order.version);
|
||||
break;
|
||||
default:
|
||||
output = null;
|
||||
AssertHelpers.Fail("BlackboardShaderInputFactory: Unknown deprecated property type.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
class AddShaderInputAction : IGraphDataAction
|
||||
{
|
||||
public enum AddActionSource
|
||||
{
|
||||
Default,
|
||||
AddMenu
|
||||
}
|
||||
|
||||
void AddShaderInput(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out AddShaderInputAction");
|
||||
|
||||
// If type property is valid, create instance of that type
|
||||
if (blackboardItemType != null && blackboardItemType.IsSubclassOf(typeof(BlackboardItem)))
|
||||
{
|
||||
shaderInputReference = (BlackboardItem)Activator.CreateInstance(blackboardItemType, true);
|
||||
}
|
||||
else if (m_ShaderInputReferenceGetter != null)
|
||||
{
|
||||
shaderInputReference = m_ShaderInputReferenceGetter();
|
||||
}
|
||||
// If type is null a direct override object must have been provided or else we are in an error-state
|
||||
else if (shaderInputReference == null)
|
||||
{
|
||||
AssertHelpers.Fail("BlackboardController: Unable to complete Add Shader Input action.");
|
||||
return;
|
||||
}
|
||||
|
||||
shaderInputReference.generatePropertyBlock = shaderInputReference.isExposable;
|
||||
|
||||
if (graphData.owner != null)
|
||||
graphData.owner.RegisterCompleteObjectUndo("Add Shader Input");
|
||||
else
|
||||
AssertHelpers.Fail("GraphObject is null while carrying out AddShaderInputAction");
|
||||
|
||||
graphData.AddGraphInput(shaderInputReference);
|
||||
|
||||
// If no categoryToAddItemToGuid is provided, add the input to the default category
|
||||
if (categoryToAddItemToGuid == String.Empty)
|
||||
{
|
||||
var defaultCategory = graphData.categories.FirstOrDefault();
|
||||
AssertHelpers.IsNotNull(defaultCategory, "Default category reference is null.");
|
||||
if (defaultCategory != null)
|
||||
{
|
||||
var addItemToCategoryAction = new AddItemToCategoryAction();
|
||||
addItemToCategoryAction.categoryGuid = defaultCategory.categoryGuid;
|
||||
addItemToCategoryAction.itemToAdd = shaderInputReference;
|
||||
graphData.owner.graphDataStore.Dispatch(addItemToCategoryAction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var addItemToCategoryAction = new AddItemToCategoryAction();
|
||||
addItemToCategoryAction.categoryGuid = categoryToAddItemToGuid;
|
||||
addItemToCategoryAction.itemToAdd = shaderInputReference;
|
||||
graphData.owner.graphDataStore.Dispatch(addItemToCategoryAction);
|
||||
}
|
||||
}
|
||||
|
||||
public static AddShaderInputAction AddDeprecatedPropertyAction(BlackboardShaderInputOrder order)
|
||||
{
|
||||
return new() { shaderInputReference = BlackboardShaderInputFactory.GetShaderInput(order), addInputActionType = AddShaderInputAction.AddActionSource.AddMenu };
|
||||
}
|
||||
|
||||
public static AddShaderInputAction AddDropdownAction(BlackboardShaderInputOrder order)
|
||||
{
|
||||
return new() { shaderInputReference = BlackboardShaderInputFactory.GetShaderInput(order), addInputActionType = AddShaderInputAction.AddActionSource.AddMenu };
|
||||
}
|
||||
|
||||
public static AddShaderInputAction AddKeywordAction(BlackboardShaderInputOrder order)
|
||||
{
|
||||
return new() { shaderInputReference = BlackboardShaderInputFactory.GetShaderInput(order), addInputActionType = AddShaderInputAction.AddActionSource.AddMenu };
|
||||
}
|
||||
|
||||
public static AddShaderInputAction AddPropertyAction(Type shaderInputType)
|
||||
{
|
||||
return new() { blackboardItemType = shaderInputType, addInputActionType = AddShaderInputAction.AddActionSource.AddMenu };
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => AddShaderInput;
|
||||
// If this is a subclass of ShaderInput and is not null, then an object of this type is created to add to blackboard
|
||||
// If the type field above is null and this is provided, then it is directly used as the item to add to blackboard
|
||||
public BlackboardItem shaderInputReference { get; set; }
|
||||
public AddActionSource addInputActionType { get; set; }
|
||||
public string categoryToAddItemToGuid { get; set; } = String.Empty;
|
||||
|
||||
Type blackboardItemType { get; set; }
|
||||
|
||||
Func<BlackboardItem> m_ShaderInputReferenceGetter = null;
|
||||
}
|
||||
|
||||
class ChangeGraphPathAction : IGraphDataAction
|
||||
{
|
||||
void ChangeGraphPath(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeGraphPathAction");
|
||||
graphData.path = NewGraphPath;
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => ChangeGraphPath;
|
||||
|
||||
public string NewGraphPath { get; set; }
|
||||
}
|
||||
|
||||
class CopyShaderInputAction : IGraphDataAction
|
||||
{
|
||||
void CopyShaderInput(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out CopyShaderInputAction");
|
||||
AssertHelpers.IsNotNull(shaderInputToCopy, "ShaderInputToCopy is null while carrying out CopyShaderInputAction");
|
||||
|
||||
// Don't handle undo here as there are different contexts in which this action is used, that define the undo action
|
||||
// TODO: Perhaps a sign that each of those need to be made their own actions instead of conflating intent into a single action
|
||||
|
||||
switch (shaderInputToCopy)
|
||||
{
|
||||
case AbstractShaderProperty property:
|
||||
insertIndex = Mathf.Clamp(insertIndex, -1, graphData.properties.Count() - 1);
|
||||
|
||||
var copiedProperty = (AbstractShaderProperty)graphData.AddCopyOfShaderInput(property, insertIndex);
|
||||
if (copiedProperty != null) // some property types cannot be duplicated (unknown types)
|
||||
{
|
||||
// Update the property nodes that depends on the copied node
|
||||
foreach (var node in dependentNodeList)
|
||||
{
|
||||
if (node is PropertyNode propertyNode)
|
||||
{
|
||||
propertyNode.owner = graphData;
|
||||
propertyNode.property = copiedProperty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
copiedShaderInput = copiedProperty;
|
||||
break;
|
||||
|
||||
case ShaderKeyword shaderKeyword:
|
||||
// InsertIndex gets passed in relative to the blackboard position of an item overall,
|
||||
// and not relative to the array sizes of the properties/keywords/dropdowns
|
||||
var keywordInsertIndex = insertIndex - graphData.properties.Count();
|
||||
keywordInsertIndex = Mathf.Clamp(keywordInsertIndex, -1, graphData.keywords.Count() - 1);
|
||||
|
||||
// Don't duplicate built-in keywords within the same graph
|
||||
if (shaderKeyword.isBuiltIn && graphData.keywords.Any(p => p.referenceName == shaderInputToCopy.referenceName))
|
||||
return;
|
||||
|
||||
var copiedKeyword = (ShaderKeyword)graphData.AddCopyOfShaderInput(shaderKeyword, keywordInsertIndex);
|
||||
|
||||
// Update the keyword nodes that depends on the copied node
|
||||
foreach (var node in dependentNodeList)
|
||||
{
|
||||
if (node is KeywordNode propertyNode)
|
||||
{
|
||||
propertyNode.owner = graphData;
|
||||
propertyNode.keyword = copiedKeyword;
|
||||
}
|
||||
}
|
||||
|
||||
copiedShaderInput = copiedKeyword;
|
||||
break;
|
||||
|
||||
case ShaderDropdown shaderDropdown:
|
||||
// InsertIndex gets passed in relative to the blackboard position of an item overall,
|
||||
// and not relative to the array sizes of the properties/keywords/dropdowns
|
||||
var dropdownInsertIndex = insertIndex - graphData.properties.Count() - graphData.keywords.Count();
|
||||
dropdownInsertIndex = Mathf.Clamp(dropdownInsertIndex, -1, graphData.dropdowns.Count() - 1);
|
||||
|
||||
var copiedDropdown = (ShaderDropdown)graphData.AddCopyOfShaderInput(shaderDropdown, dropdownInsertIndex);
|
||||
|
||||
// Update the dropdown nodes that depends on the copied node
|
||||
foreach (var node in dependentNodeList)
|
||||
{
|
||||
if (node is DropdownNode propertyNode)
|
||||
{
|
||||
propertyNode.owner = graphData;
|
||||
propertyNode.dropdown = copiedDropdown;
|
||||
}
|
||||
}
|
||||
|
||||
copiedShaderInput = copiedDropdown;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (copiedShaderInput != null)
|
||||
{
|
||||
// If specific category to copy to is provided, find and use it
|
||||
foreach (var category in graphData.categories)
|
||||
{
|
||||
if (category.categoryGuid == containingCategoryGuid)
|
||||
{
|
||||
// Ensures that the new item gets added after the item it was duplicated from
|
||||
insertIndex += 1;
|
||||
// If the source item was already the last item in list, just add to end of list
|
||||
if (insertIndex >= category.childCount)
|
||||
insertIndex = -1;
|
||||
graphData.InsertItemIntoCategory(category.objectId, copiedShaderInput, insertIndex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Else, add to default category
|
||||
graphData.categories.First().InsertItemIntoCategory(copiedShaderInput);
|
||||
}
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => CopyShaderInput;
|
||||
|
||||
public IEnumerable<AbstractMaterialNode> dependentNodeList { get; set; } = new List<AbstractMaterialNode>();
|
||||
|
||||
public BlackboardItem shaderInputToCopy { get; set; }
|
||||
|
||||
public BlackboardItem copiedShaderInput { get; set; }
|
||||
|
||||
public string containingCategoryGuid { get; set; }
|
||||
|
||||
public int insertIndex { get; set; } = -1;
|
||||
}
|
||||
|
||||
class AddCategoryAction : IGraphDataAction
|
||||
{
|
||||
void AddCategory(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out AddCategoryAction");
|
||||
graphData.owner.RegisterCompleteObjectUndo("Add Category");
|
||||
// If categoryDataReference is not null, directly add it to graphData
|
||||
if (categoryDataReference == null)
|
||||
categoryDataReference = new CategoryData(categoryName, childObjects);
|
||||
graphData.AddCategory(categoryDataReference);
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => AddCategory;
|
||||
|
||||
// Direct reference to the categoryData to use if it is specified
|
||||
public CategoryData categoryDataReference { get; set; }
|
||||
public string categoryName { get; set; } = String.Empty;
|
||||
public List<ShaderInput> childObjects { get; set; }
|
||||
}
|
||||
|
||||
class MoveCategoryAction : IGraphDataAction
|
||||
{
|
||||
void MoveCategory(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out MoveCategoryAction");
|
||||
graphData.owner.RegisterCompleteObjectUndo("Move Category");
|
||||
// Handling for out of range moves is slightly different, but otherwise we need to reverse for insertion order.
|
||||
var guids = newIndexValue >= graphData.categories.Count() ? categoryGuids : categoryGuids.Reverse<string>();
|
||||
foreach (var guid in categoryGuids)
|
||||
{
|
||||
var cat = graphData.categories.FirstOrDefault(c => c.categoryGuid == guid);
|
||||
graphData.MoveCategory(cat, newIndexValue);
|
||||
}
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => MoveCategory;
|
||||
|
||||
// Reference to the shader input being modified
|
||||
internal List<string> categoryGuids { get; set; }
|
||||
|
||||
internal int newIndexValue { get; set; }
|
||||
}
|
||||
|
||||
class AddItemToCategoryAction : IGraphDataAction
|
||||
{
|
||||
public enum AddActionSource
|
||||
{
|
||||
Default,
|
||||
DragDrop
|
||||
}
|
||||
|
||||
void AddItemsToCategory(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out AddItemToCategoryAction");
|
||||
graphData.owner.RegisterCompleteObjectUndo("Add Item to Category");
|
||||
graphData.InsertItemIntoCategory(categoryGuid, itemToAdd, indexToAddItemAt);
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => AddItemsToCategory;
|
||||
|
||||
public string categoryGuid { get; set; }
|
||||
|
||||
public ShaderInput itemToAdd { get; set; }
|
||||
|
||||
// By default an item is always added to the end of a category, if this value is set to something other than -1, will insert the item at that position within the category
|
||||
public int indexToAddItemAt { get; set; } = -1;
|
||||
|
||||
public AddActionSource addActionSource { get; set; }
|
||||
}
|
||||
|
||||
class CopyCategoryAction : IGraphDataAction
|
||||
{
|
||||
void CopyCategory(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out CopyCategoryAction");
|
||||
AssertHelpers.IsNotNull(categoryToCopyReference, "CategoryToCopyReference is null while carrying out CopyCategoryAction");
|
||||
|
||||
// This is called by MaterialGraphView currently, no need to repeat it here, though ideally it would live here
|
||||
//graphData.owner.RegisterCompleteObjectUndo("Copy Category");
|
||||
|
||||
newCategoryDataReference = graphData.CopyCategory(categoryToCopyReference);
|
||||
}
|
||||
|
||||
// Reference to the new category created as a copy
|
||||
public CategoryData newCategoryDataReference { get; set; }
|
||||
|
||||
// After category has been copied, store reference to it
|
||||
public CategoryData categoryToCopyReference { get; set; }
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => CopyCategory;
|
||||
}
|
||||
|
||||
class ShaderVariantLimitAction : IGraphDataAction
|
||||
{
|
||||
public int currentVariantCount { get; set; } = 0;
|
||||
public int maxVariantCount { get; set; } = 0;
|
||||
|
||||
public ShaderVariantLimitAction(int currentVariantCount, int maxVariantCount)
|
||||
{
|
||||
this.maxVariantCount = maxVariantCount;
|
||||
this.currentVariantCount = currentVariantCount;
|
||||
}
|
||||
|
||||
// There's no action actually performed on the graph, but we need to implement this as a valid function
|
||||
public Action<GraphData> modifyGraphDataAction => Empty;
|
||||
|
||||
void Empty(GraphData graphData)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class BlackboardController : SGViewController<GraphData, BlackboardViewModel>
|
||||
{
|
||||
// Type changes (adds/removes of Types) only happen after a full assembly reload so its safe to make this static
|
||||
static IList<Type> s_ShaderInputTypes;
|
||||
|
||||
static BlackboardController()
|
||||
{
|
||||
var shaderInputTypes = TypeCache.GetTypesWithAttribute<BlackboardInputInfo>().ToList();
|
||||
// Sort the ShaderInput by priority using the BlackboardInputInfo attribute
|
||||
shaderInputTypes.Sort((s1, s2) =>
|
||||
{
|
||||
var info1 = Attribute.GetCustomAttribute(s1, typeof(BlackboardInputInfo)) as BlackboardInputInfo;
|
||||
var info2 = Attribute.GetCustomAttribute(s2, typeof(BlackboardInputInfo)) as BlackboardInputInfo;
|
||||
|
||||
if (info1.priority == info2.priority)
|
||||
return (info1.name ?? s1.Name).CompareTo(info2.name ?? s2.Name);
|
||||
else
|
||||
return info1.priority.CompareTo(info2.priority);
|
||||
});
|
||||
|
||||
s_ShaderInputTypes = shaderInputTypes.ToList();
|
||||
}
|
||||
|
||||
BlackboardCategoryController m_DefaultCategoryController = null;
|
||||
Dictionary<string, BlackboardCategoryController> m_BlackboardCategoryControllers = new Dictionary<string, BlackboardCategoryController>();
|
||||
|
||||
SGBlackboard m_Blackboard;
|
||||
|
||||
internal SGBlackboard blackboard
|
||||
{
|
||||
get => m_Blackboard;
|
||||
private set => m_Blackboard = value;
|
||||
}
|
||||
public string GetFirstSelectedCategoryGuid()
|
||||
{
|
||||
if (m_Blackboard == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
var copiedSelectionList = new List<ISelectable>(m_Blackboard.selection);
|
||||
var selectedCategories = new List<SGBlackboardCategory>();
|
||||
var selectedCategoryGuid = String.Empty;
|
||||
for (int i = 0; i < copiedSelectionList.Count; i++)
|
||||
{
|
||||
var selectable = copiedSelectionList[i];
|
||||
if (selectable is SGBlackboardCategory category)
|
||||
{
|
||||
selectedCategories.Add(selectable as SGBlackboardCategory);
|
||||
}
|
||||
}
|
||||
if (selectedCategories.Any())
|
||||
{
|
||||
selectedCategoryGuid = selectedCategories[0].viewModel.associatedCategoryGuid;
|
||||
}
|
||||
return selectedCategoryGuid;
|
||||
}
|
||||
|
||||
void InitializeViewModel(bool useDropdowns)
|
||||
{
|
||||
// Clear the view model
|
||||
ViewModel.ResetViewModelData();
|
||||
ViewModel.subtitle = BlackboardUtils.FormatPath(Model.path);
|
||||
BlackboardShaderInputOrder propertyTypesOrder = new BlackboardShaderInputOrder();
|
||||
|
||||
// Property data first
|
||||
foreach (var shaderInputType in s_ShaderInputTypes)
|
||||
{
|
||||
if (shaderInputType.IsAbstract)
|
||||
continue;
|
||||
|
||||
var info = Attribute.GetCustomAttribute(shaderInputType, typeof(BlackboardInputInfo)) as BlackboardInputInfo;
|
||||
string name = info?.name ?? ObjectNames.NicifyVariableName(shaderInputType.Name.Replace("ShaderProperty", ""));
|
||||
|
||||
// QUICK FIX TO DEAL WITH DEPRECATED COLOR PROPERTY
|
||||
if (name.Equals("Color", StringComparison.InvariantCultureIgnoreCase) && ShaderGraphPreferences.allowDeprecatedBehaviors)
|
||||
{
|
||||
propertyTypesOrder.isKeyword = false;
|
||||
propertyTypesOrder.deprecatedPropertyName = name;
|
||||
propertyTypesOrder.version = ColorShaderProperty.deprecatedVersion;
|
||||
ViewModel.propertyNameToAddActionMap.Add("Color (Deprecated)", AddShaderInputAction.AddDeprecatedPropertyAction(propertyTypesOrder));
|
||||
ViewModel.propertyNameToAddActionMap.Add(name, AddShaderInputAction.AddPropertyAction(shaderInputType));
|
||||
}
|
||||
else
|
||||
ViewModel.propertyNameToAddActionMap.Add(name, AddShaderInputAction.AddPropertyAction(shaderInputType));
|
||||
}
|
||||
|
||||
// Default Keywords next
|
||||
BlackboardShaderInputOrder keywordTypesOrder = new BlackboardShaderInputOrder();
|
||||
keywordTypesOrder.isKeyword = true;
|
||||
keywordTypesOrder.keywordType = KeywordType.Boolean;
|
||||
ViewModel.defaultKeywordNameToAddActionMap.Add("Boolean", AddShaderInputAction.AddKeywordAction(keywordTypesOrder));
|
||||
keywordTypesOrder.keywordType = KeywordType.Enum;
|
||||
ViewModel.defaultKeywordNameToAddActionMap.Add("Enum", AddShaderInputAction.AddKeywordAction(keywordTypesOrder));
|
||||
|
||||
// Built-In Keywords after that
|
||||
foreach (var builtinKeywordDescriptor in KeywordUtil.GetBuiltinKeywordDescriptors())
|
||||
{
|
||||
var keyword = ShaderKeyword.CreateBuiltInKeyword(builtinKeywordDescriptor);
|
||||
// Do not allow user to add built-in keywords that conflict with user-made keywords that have the same reference name or display name
|
||||
if (Model.keywords.Any(x => x.referenceName == keyword.referenceName || x.displayName == keyword.displayName))
|
||||
{
|
||||
ViewModel.disabledKeywordNameList.Add(keyword.displayName);
|
||||
}
|
||||
else
|
||||
{
|
||||
keywordTypesOrder.builtInKeyword = (ShaderKeyword)keyword.Copy();
|
||||
ViewModel.builtInKeywordNameToAddActionMap.Add(keyword.displayName, AddShaderInputAction.AddKeywordAction(keywordTypesOrder));
|
||||
}
|
||||
}
|
||||
|
||||
if (useDropdowns)
|
||||
{
|
||||
BlackboardShaderInputOrder dropdownsOrder = new BlackboardShaderInputOrder();
|
||||
dropdownsOrder.isDropdown = true;
|
||||
ViewModel.defaultDropdownNameToAdd = new Tuple<string, IGraphDataAction>("Dropdown", AddShaderInputAction.AddDropdownAction(dropdownsOrder));
|
||||
}
|
||||
|
||||
// Category data last
|
||||
var defaultNewCategoryReference = new CategoryData("Category");
|
||||
ViewModel.addCategoryAction = new AddCategoryAction() { categoryDataReference = defaultNewCategoryReference };
|
||||
|
||||
ViewModel.requestModelChangeAction = this.RequestModelChange;
|
||||
ViewModel.categoryInfoList.AddRange(DataStore.State.categories.ToList());
|
||||
}
|
||||
|
||||
internal BlackboardController(GraphData model, BlackboardViewModel inViewModel, GraphDataStore graphDataStore)
|
||||
: base(model, inViewModel, graphDataStore)
|
||||
{
|
||||
// TODO: hide this more generically for category types.
|
||||
bool useDropdowns = model.isSubGraph;
|
||||
InitializeViewModel(useDropdowns);
|
||||
|
||||
blackboard = new SGBlackboard(ViewModel, this);
|
||||
|
||||
// Add default category at the top of the blackboard (create it if it doesn't exist already)
|
||||
var existingDefaultCategory = DataStore.State.categories.FirstOrDefault();
|
||||
if (existingDefaultCategory != null && existingDefaultCategory.IsNamedCategory() == false)
|
||||
{
|
||||
AddBlackboardCategory(graphDataStore, existingDefaultCategory);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Any properties that don't already have a category (for example, if this graph is being loaded from an older version that doesn't have category data)
|
||||
var uncategorizedBlackboardItems = new List<ShaderInput>();
|
||||
foreach (var shaderProperty in DataStore.State.properties)
|
||||
if (IsInputUncategorized(shaderProperty))
|
||||
uncategorizedBlackboardItems.Add(shaderProperty);
|
||||
|
||||
foreach (var shaderKeyword in DataStore.State.keywords)
|
||||
if (IsInputUncategorized(shaderKeyword))
|
||||
uncategorizedBlackboardItems.Add(shaderKeyword);
|
||||
|
||||
if (useDropdowns)
|
||||
{
|
||||
foreach (var shaderDropdown in DataStore.State.dropdowns)
|
||||
if (IsInputUncategorized(shaderDropdown))
|
||||
uncategorizedBlackboardItems.Add(shaderDropdown);
|
||||
}
|
||||
|
||||
var addCategoryAction = new AddCategoryAction();
|
||||
addCategoryAction.categoryDataReference = CategoryData.DefaultCategory(uncategorizedBlackboardItems);
|
||||
graphDataStore.Dispatch(addCategoryAction);
|
||||
}
|
||||
|
||||
// Get the reference to default category controller after its been added
|
||||
m_DefaultCategoryController = m_BlackboardCategoryControllers.Values.FirstOrDefault();
|
||||
AssertHelpers.IsNotNull(m_DefaultCategoryController, "Failed to instantiate default category.");
|
||||
|
||||
// Handle loaded-in categories from graph first, skipping the first/default category
|
||||
foreach (var categoryData in ViewModel.categoryInfoList.Skip(1))
|
||||
{
|
||||
AddBlackboardCategory(graphDataStore, categoryData);
|
||||
}
|
||||
}
|
||||
|
||||
internal string editorPrefsBaseKey => "unity.shadergraph." + DataStore.State.objectId;
|
||||
|
||||
BlackboardCategoryController AddBlackboardCategory(GraphDataStore graphDataStore, CategoryData categoryInfo)
|
||||
{
|
||||
var blackboardCategoryViewModel = new BlackboardCategoryViewModel();
|
||||
blackboardCategoryViewModel.parentView = blackboard;
|
||||
blackboardCategoryViewModel.requestModelChangeAction = ViewModel.requestModelChangeAction;
|
||||
blackboardCategoryViewModel.name = categoryInfo.name;
|
||||
blackboardCategoryViewModel.associatedCategoryGuid = categoryInfo.categoryGuid;
|
||||
blackboardCategoryViewModel.isExpanded = EditorPrefs.GetBool($"{editorPrefsBaseKey}.{categoryInfo.categoryGuid}.{ChangeCategoryIsExpandedAction.kEditorPrefKey}", true);
|
||||
|
||||
var blackboardCategoryController = new BlackboardCategoryController(categoryInfo, blackboardCategoryViewModel, graphDataStore);
|
||||
if (m_BlackboardCategoryControllers.ContainsKey(categoryInfo.categoryGuid) == false)
|
||||
{
|
||||
m_BlackboardCategoryControllers.Add(categoryInfo.categoryGuid, blackboardCategoryController);
|
||||
}
|
||||
else
|
||||
{
|
||||
AssertHelpers.Fail("Failed to add category controller due to category with same GUID already having been added.");
|
||||
return null;
|
||||
}
|
||||
return blackboardCategoryController;
|
||||
}
|
||||
|
||||
// Creates controller, view and view model for a blackboard item and adds the view to the specified index in the category
|
||||
SGBlackboardRow InsertBlackboardRow(BlackboardItem shaderInput, int insertionIndex = -1)
|
||||
{
|
||||
return m_DefaultCategoryController.InsertBlackboardRow(shaderInput, insertionIndex);
|
||||
}
|
||||
|
||||
public void UpdateBlackboardTitle(string newTitle)
|
||||
{
|
||||
ViewModel.title = newTitle;
|
||||
blackboard.title = ViewModel.title;
|
||||
}
|
||||
|
||||
protected override void RequestModelChange(IGraphDataAction changeAction)
|
||||
{
|
||||
DataStore.Dispatch(changeAction);
|
||||
}
|
||||
|
||||
// Called by GraphDataStore.Subscribe after the model has been changed
|
||||
protected override void ModelChanged(GraphData graphData, IGraphDataAction changeAction)
|
||||
{
|
||||
// Reconstruct view-model first
|
||||
// TODO: hide this more generically for category types.
|
||||
bool useDropdowns = graphData.isSubGraph;
|
||||
InitializeViewModel(useDropdowns);
|
||||
|
||||
var graphView = ViewModel.parentView as MaterialGraphView;
|
||||
|
||||
switch (changeAction)
|
||||
{
|
||||
// If newly added input doesn't belong to any of the user-made categories, add it to the default category at top of blackboard
|
||||
case AddShaderInputAction addBlackboardItemAction:
|
||||
if (IsInputUncategorized(addBlackboardItemAction.shaderInputReference))
|
||||
{
|
||||
var blackboardRow = InsertBlackboardRow(addBlackboardItemAction.shaderInputReference);
|
||||
if (blackboardRow != null)
|
||||
{
|
||||
var propertyView = blackboardRow.Q<SGBlackboardField>();
|
||||
if (addBlackboardItemAction.addInputActionType == AddShaderInputAction.AddActionSource.AddMenu)
|
||||
propertyView.OpenTextEditor();
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Need to handle deletion of shader inputs here as opposed to BlackboardCategoryController, as currently,
|
||||
// once removed from the categories there is no way to associate an input with the category that owns it
|
||||
case DeleteShaderInputAction deleteShaderInputAction:
|
||||
foreach (var shaderInput in deleteShaderInputAction.shaderInputsToDelete)
|
||||
RemoveInputFromBlackboard(shaderInput);
|
||||
break;
|
||||
|
||||
case HandleUndoRedoAction handleUndoRedoAction:
|
||||
ClearBlackboardCategories();
|
||||
|
||||
foreach (var categoryData in graphData.addedCategories)
|
||||
AddBlackboardCategory(DataStore, categoryData);
|
||||
|
||||
m_DefaultCategoryController = m_BlackboardCategoryControllers.Values.FirstOrDefault();
|
||||
|
||||
break;
|
||||
case CopyShaderInputAction copyShaderInputAction:
|
||||
// In the specific case of only-one keywords like Material Quality and Raytracing, they can get copied, but because only one can exist, the output copied value is null
|
||||
if (copyShaderInputAction.copiedShaderInput != null && IsInputUncategorized(copyShaderInputAction.copiedShaderInput))
|
||||
{
|
||||
var blackboardRow = InsertBlackboardRow(copyShaderInputAction.copiedShaderInput, copyShaderInputAction.insertIndex);
|
||||
var propertyView = blackboardRow.Q<SGBlackboardField>();
|
||||
graphView?.AddToSelectionNoUndoRecord(propertyView);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AddCategoryAction addCategoryAction:
|
||||
AddBlackboardCategory(DataStore, addCategoryAction.categoryDataReference);
|
||||
// Iterate through anything that is selected currently
|
||||
foreach (var selectedElement in blackboard.selection.ToList())
|
||||
{
|
||||
if (selectedElement is SGBlackboardField { userData: ShaderInput shaderInput })
|
||||
{
|
||||
// If a blackboard item is selected, first remove it from the blackboard
|
||||
RemoveInputFromBlackboard(shaderInput);
|
||||
|
||||
// Then add input to the new category
|
||||
var addItemToCategoryAction = new AddItemToCategoryAction();
|
||||
addItemToCategoryAction.categoryGuid = addCategoryAction.categoryDataReference.categoryGuid;
|
||||
addItemToCategoryAction.itemToAdd = shaderInput;
|
||||
DataStore.Dispatch(addItemToCategoryAction);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DeleteCategoryAction deleteCategoryAction:
|
||||
// Clean up deleted categories
|
||||
foreach (var categoryGUID in deleteCategoryAction.categoriesToRemoveGuids)
|
||||
{
|
||||
RemoveBlackboardCategory(categoryGUID);
|
||||
}
|
||||
break;
|
||||
|
||||
case MoveCategoryAction moveCategoryAction:
|
||||
ClearBlackboardCategories();
|
||||
foreach (var categoryData in ViewModel.categoryInfoList)
|
||||
AddBlackboardCategory(graphData.owner.graphDataStore, categoryData);
|
||||
break;
|
||||
|
||||
case CopyCategoryAction copyCategoryAction:
|
||||
var blackboardCategory = AddBlackboardCategory(graphData.owner.graphDataStore, copyCategoryAction.newCategoryDataReference);
|
||||
if (blackboardCategory != null)
|
||||
graphView?.AddToSelectionNoUndoRecord(blackboardCategory.blackboardCategoryView);
|
||||
break;
|
||||
case ShaderVariantLimitAction shaderVariantLimitAction:
|
||||
blackboard.SetCurrentVariantUsage(shaderVariantLimitAction.currentVariantCount, shaderVariantLimitAction.maxVariantCount);
|
||||
break;
|
||||
}
|
||||
|
||||
// Lets all event handlers this controller owns/manages know that the model has changed
|
||||
// Usually this is to update views and make them reconstruct themself from updated view-model
|
||||
//NotifyChange(changeAction);
|
||||
|
||||
// Let child controllers know about changes to this controller so they may update themselves in turn
|
||||
//ApplyChanges();
|
||||
}
|
||||
|
||||
void RemoveInputFromBlackboard(ShaderInput shaderInput)
|
||||
{
|
||||
// Check if input is in one of the categories
|
||||
foreach (var controller in m_BlackboardCategoryControllers.Values)
|
||||
{
|
||||
var blackboardRow = controller.FindBlackboardRow(shaderInput);
|
||||
if (blackboardRow != null)
|
||||
{
|
||||
controller.RemoveBlackboardRow(shaderInput);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsInputUncategorized(ShaderInput shaderInput)
|
||||
{
|
||||
// Skip the first category controller as that is guaranteed to be the default category
|
||||
foreach (var categoryController in m_BlackboardCategoryControllers.Values.Skip(1))
|
||||
{
|
||||
if (categoryController.IsInputInCategory(shaderInput))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public SGBlackboardCategory GetBlackboardCategory(string inputGuid)
|
||||
{
|
||||
foreach (var categoryController in m_BlackboardCategoryControllers.Values)
|
||||
{
|
||||
if (categoryController.Model.categoryGuid == inputGuid)
|
||||
return categoryController.blackboardCategoryView;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public SGBlackboardRow GetBlackboardRow(ShaderInput blackboardItem)
|
||||
{
|
||||
foreach (var categoryController in m_BlackboardCategoryControllers.Values)
|
||||
{
|
||||
var blackboardRow = categoryController.FindBlackboardRow(blackboardItem);
|
||||
if (blackboardRow != null)
|
||||
return blackboardRow;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
int numberOfCategories => m_BlackboardCategoryControllers.Count;
|
||||
|
||||
// Gets the index after the currently selected shader input for pasting properties into this graph
|
||||
internal int GetInsertionIndexForPaste()
|
||||
{
|
||||
if (blackboard?.selection == null || blackboard.selection.Count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
foreach (ISelectable selection in blackboard.selection)
|
||||
{
|
||||
if (selection is SGBlackboardField blackboardPropertyView)
|
||||
{
|
||||
SGBlackboardRow row = blackboardPropertyView.GetFirstAncestorOfType<SGBlackboardRow>();
|
||||
SGBlackboardCategory category = blackboardPropertyView.GetFirstAncestorOfType<SGBlackboardCategory>();
|
||||
if (row == null || category == null)
|
||||
continue;
|
||||
int blackboardFieldIndex = category.IndexOf(row);
|
||||
|
||||
return blackboardFieldIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RemoveBlackboardCategory(string categoryGUID)
|
||||
{
|
||||
m_BlackboardCategoryControllers.TryGetValue(categoryGUID, out var blackboardCategoryController);
|
||||
if (blackboardCategoryController != null)
|
||||
{
|
||||
blackboardCategoryController.Destroy();
|
||||
m_BlackboardCategoryControllers.Remove(categoryGUID);
|
||||
}
|
||||
else
|
||||
AssertHelpers.Fail("Tried to remove a category that doesn't exist. ");
|
||||
}
|
||||
|
||||
void ClearBlackboardCategories()
|
||||
{
|
||||
foreach (var categoryController in m_BlackboardCategoryControllers.Values)
|
||||
{
|
||||
categoryController.Destroy();
|
||||
}
|
||||
m_BlackboardCategoryControllers.Clear();
|
||||
}
|
||||
|
||||
// Meant to be used by UI testing in order to clear blackboard state
|
||||
internal void ResetBlackboardState()
|
||||
{
|
||||
ClearBlackboardCategories();
|
||||
var addCategoryAction = new AddCategoryAction();
|
||||
addCategoryAction.categoryDataReference = CategoryData.DefaultCategory();
|
||||
DataStore.Dispatch(addCategoryAction);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8b25321bfcc6454b9c673c127a84bb0c
|
||||
timeCreated: 1608602455
|
|
@ -0,0 +1,199 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UnityEditor.ShaderGraph.Drawing;
|
||||
|
||||
using GraphDataStore = UnityEditor.ShaderGraph.DataStore<UnityEditor.ShaderGraph.GraphData>;
|
||||
|
||||
namespace UnityEditor.ShaderGraph
|
||||
{
|
||||
class DummyChangeAction : IGraphDataAction
|
||||
{
|
||||
void OnDummyChangeAction(GraphData m_GraphData)
|
||||
{
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => OnDummyChangeAction;
|
||||
}
|
||||
|
||||
struct SGControllerChangedEvent
|
||||
{
|
||||
public ISGControlledElement target;
|
||||
public SGController controller;
|
||||
public IGraphDataAction change;
|
||||
|
||||
private bool m_PropagationStopped;
|
||||
void StopPropagation()
|
||||
{
|
||||
m_PropagationStopped = true;
|
||||
}
|
||||
|
||||
public bool isPropagationStopped => m_PropagationStopped;
|
||||
}
|
||||
|
||||
class SGControllerEvent
|
||||
{
|
||||
ISGControlledElement target = null;
|
||||
|
||||
SGControllerEvent(ISGControlledElement controlledTarget)
|
||||
{
|
||||
target = controlledTarget;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SGController
|
||||
{
|
||||
public bool m_DisableCalled = false;
|
||||
|
||||
protected IGraphDataAction DummyChange = new DummyChangeAction();
|
||||
|
||||
public virtual void OnDisable()
|
||||
{
|
||||
if (m_DisableCalled)
|
||||
Debug.LogError(GetType().Name + ".Disable called twice");
|
||||
|
||||
m_DisableCalled = true;
|
||||
foreach (var element in allChildren)
|
||||
{
|
||||
UnityEngine.Profiling.Profiler.BeginSample(element.GetType().Name + ".OnDisable");
|
||||
element.OnDisable();
|
||||
UnityEngine.Profiling.Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
|
||||
internal void RegisterHandler(ISGControlledElement handler)
|
||||
{
|
||||
//Debug.Log("RegisterHandler of " + handler.GetType().Name + " on " + GetType().Name );
|
||||
|
||||
if (m_EventHandlers.Contains(handler))
|
||||
Debug.LogError("Handler registered twice");
|
||||
else
|
||||
{
|
||||
m_EventHandlers.Add(handler);
|
||||
|
||||
NotifyEventHandler(handler, DummyChange);
|
||||
}
|
||||
}
|
||||
|
||||
internal void UnregisterHandler(ISGControlledElement handler)
|
||||
{
|
||||
m_EventHandlers.Remove(handler);
|
||||
}
|
||||
|
||||
protected void NotifyChange(IGraphDataAction changeAction)
|
||||
{
|
||||
var eventHandlers = m_EventHandlers.ToArray(); // Some notification may trigger Register/Unregister so duplicate the collection.
|
||||
|
||||
foreach (var eventHandler in eventHandlers)
|
||||
{
|
||||
UnityEngine.Profiling.Profiler.BeginSample("NotifyChange:" + eventHandler.GetType().Name);
|
||||
NotifyEventHandler(eventHandler, changeAction);
|
||||
UnityEngine.Profiling.Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyEventHandler(ISGControlledElement eventHandler, IGraphDataAction changeAction)
|
||||
{
|
||||
SGControllerChangedEvent e = new SGControllerChangedEvent();
|
||||
e.controller = this;
|
||||
e.target = eventHandler;
|
||||
e.change = changeAction;
|
||||
eventHandler.OnControllerChanged(ref e);
|
||||
if (e.isPropagationStopped)
|
||||
return;
|
||||
if (eventHandler is VisualElement)
|
||||
{
|
||||
var element = eventHandler as VisualElement;
|
||||
eventHandler = element.GetFirstOfType<ISGControlledElement>();
|
||||
while (eventHandler != null)
|
||||
{
|
||||
eventHandler.OnControllerChanged(ref e);
|
||||
if (e.isPropagationStopped)
|
||||
break;
|
||||
eventHandler = (eventHandler as VisualElement).GetFirstAncestorOfType<ISGControlledElement>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SendEvent(SGControllerEvent e)
|
||||
{
|
||||
var eventHandlers = m_EventHandlers.ToArray(); // Some notification may trigger Register/Unregister so duplicate the collection.
|
||||
|
||||
foreach (var eventHandler in eventHandlers)
|
||||
{
|
||||
eventHandler.OnControllerEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void ApplyChanges();
|
||||
|
||||
public virtual IEnumerable<SGController> allChildren
|
||||
{
|
||||
get { return Enumerable.Empty<SGController>(); }
|
||||
}
|
||||
|
||||
List<ISGControlledElement> m_EventHandlers = new List<ISGControlledElement>();
|
||||
}
|
||||
|
||||
abstract class SGController<T> : SGController
|
||||
{
|
||||
GraphDataStore m_DataStore;
|
||||
protected GraphDataStore DataStore => m_DataStore;
|
||||
|
||||
protected SGController(T model, GraphDataStore dataStore)
|
||||
{
|
||||
m_Model = model;
|
||||
m_DataStore = dataStore;
|
||||
DataStore.Subscribe += ModelChanged;
|
||||
}
|
||||
|
||||
protected abstract void RequestModelChange(IGraphDataAction changeAction);
|
||||
|
||||
protected abstract void ModelChanged(GraphData graphData, IGraphDataAction changeAction);
|
||||
|
||||
T m_Model;
|
||||
public T Model => m_Model;
|
||||
|
||||
// Cleanup delegate association before destruction
|
||||
public void Cleanup()
|
||||
{
|
||||
DataStore.Subscribe -= ModelChanged;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SGViewController<ModelType, ViewModelType> : SGController<ModelType>
|
||||
{
|
||||
protected SGViewController(ModelType model, ViewModelType viewModel, GraphDataStore graphDataStore) : base(model, graphDataStore)
|
||||
{
|
||||
m_ViewModel = viewModel;
|
||||
try
|
||||
{
|
||||
// Need ViewModel to be initialized before we call ModelChanged() [as view model might need to update]
|
||||
ModelChanged(DataStore.State, DummyChange);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Log("Failed to initialize View Controller of type: " + this.GetType() + " due to exception: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// Holds data specific to the views this controller is responsible for
|
||||
ViewModelType m_ViewModel;
|
||||
public ViewModelType ViewModel => m_ViewModel;
|
||||
|
||||
public override void ApplyChanges()
|
||||
{
|
||||
foreach (var controller in allChildren)
|
||||
{
|
||||
controller.ApplyChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Destroy() { }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1dae36c782bd4d8babb267707f7596f3
|
||||
timeCreated: 1608256298
|
|
@ -0,0 +1,355 @@
|
|||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Graphing;
|
||||
using UnityEditor.ShaderGraph.Drawing.Controls;
|
||||
using UnityEditor.ShaderGraph.Internal;
|
||||
using UnityEngine.Assertions;
|
||||
using UnityEngine.UIElements;
|
||||
using GraphDataStore = UnityEditor.ShaderGraph.DataStore<UnityEditor.ShaderGraph.GraphData>;
|
||||
|
||||
namespace UnityEditor.ShaderGraph.Drawing
|
||||
{
|
||||
class ChangeExposedFlagAction : IGraphDataAction
|
||||
{
|
||||
internal ChangeExposedFlagAction(ShaderInput shaderInput, bool newIsExposed)
|
||||
{
|
||||
this.shaderInputReference = shaderInput;
|
||||
this.newIsExposedValue = newIsExposed;
|
||||
this.oldIsExposedValue = shaderInput.generatePropertyBlock;
|
||||
}
|
||||
|
||||
void ChangeExposedFlag(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeExposedFlagAction");
|
||||
AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out ChangeExposedFlagAction");
|
||||
// The Undos are currently handled in ShaderInputPropertyDrawer but we want to move that out from there and handle here
|
||||
//graphData.owner.RegisterCompleteObjectUndo("Change Exposed Toggle");
|
||||
shaderInputReference.generatePropertyBlock = newIsExposedValue;
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => ChangeExposedFlag;
|
||||
|
||||
// Reference to the shader input being modified
|
||||
internal ShaderInput shaderInputReference { get; private set; }
|
||||
|
||||
// New value of whether the shader input should be exposed to the material inspector
|
||||
internal bool newIsExposedValue { get; private set; }
|
||||
internal bool oldIsExposedValue { get; private set; }
|
||||
}
|
||||
|
||||
class ChangePropertyValueAction : IGraphDataAction
|
||||
{
|
||||
void ChangePropertyValue(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangePropertyValueAction");
|
||||
AssertHelpers.IsNotNull(shaderInputReference, "ShaderPropertyReference is null while carrying out ChangePropertyValueAction");
|
||||
// The Undos are currently handled in ShaderInputPropertyDrawer but we want to move that out from there and handle here
|
||||
//graphData.owner.RegisterCompleteObjectUndo("Change Property Value");
|
||||
switch (shaderInputReference)
|
||||
{
|
||||
case BooleanShaderProperty booleanProperty:
|
||||
booleanProperty.value = ((ToggleData)newShaderInputValue).isOn;
|
||||
break;
|
||||
case Vector1ShaderProperty vector1Property:
|
||||
vector1Property.value = (float)newShaderInputValue;
|
||||
break;
|
||||
case Vector2ShaderProperty vector2Property:
|
||||
vector2Property.value = (Vector2)newShaderInputValue;
|
||||
break;
|
||||
case Vector3ShaderProperty vector3Property:
|
||||
vector3Property.value = (Vector3)newShaderInputValue;
|
||||
break;
|
||||
case Vector4ShaderProperty vector4Property:
|
||||
vector4Property.value = (Vector4)newShaderInputValue;
|
||||
break;
|
||||
case ColorShaderProperty colorProperty:
|
||||
colorProperty.value = (Color)newShaderInputValue;
|
||||
break;
|
||||
case Texture2DShaderProperty texture2DProperty:
|
||||
texture2DProperty.value.texture = (Texture)newShaderInputValue;
|
||||
break;
|
||||
case Texture2DArrayShaderProperty texture2DArrayProperty:
|
||||
texture2DArrayProperty.value.textureArray = (Texture2DArray)newShaderInputValue;
|
||||
break;
|
||||
case Texture3DShaderProperty texture3DProperty:
|
||||
texture3DProperty.value.texture = (Texture3D)newShaderInputValue;
|
||||
break;
|
||||
case CubemapShaderProperty cubemapProperty:
|
||||
cubemapProperty.value.cubemap = (Cubemap)newShaderInputValue;
|
||||
break;
|
||||
case Matrix2ShaderProperty matrix2Property:
|
||||
matrix2Property.value = (Matrix4x4)newShaderInputValue;
|
||||
break;
|
||||
case Matrix3ShaderProperty matrix3Property:
|
||||
matrix3Property.value = (Matrix4x4)newShaderInputValue;
|
||||
break;
|
||||
case Matrix4ShaderProperty matrix4Property:
|
||||
matrix4Property.value = (Matrix4x4)newShaderInputValue;
|
||||
break;
|
||||
case SamplerStateShaderProperty samplerStateProperty:
|
||||
samplerStateProperty.value = (TextureSamplerState)newShaderInputValue;
|
||||
break;
|
||||
case GradientShaderProperty gradientProperty:
|
||||
gradientProperty.value = (Gradient)newShaderInputValue;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => ChangePropertyValue;
|
||||
|
||||
// Reference to the shader input being modified
|
||||
internal ShaderInput shaderInputReference { get; set; }
|
||||
|
||||
// New value of the shader property
|
||||
|
||||
internal object newShaderInputValue { get; set; }
|
||||
}
|
||||
|
||||
class ChangeDisplayNameAction : IGraphDataAction
|
||||
{
|
||||
void ChangeDisplayName(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeDisplayNameAction");
|
||||
AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out ChangeDisplayNameAction");
|
||||
graphData.owner.RegisterCompleteObjectUndo("Change Display Name");
|
||||
if (newDisplayNameValue != shaderInputReference.displayName)
|
||||
{
|
||||
shaderInputReference.SetDisplayNameAndSanitizeForGraph(graphData, newDisplayNameValue);
|
||||
}
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => ChangeDisplayName;
|
||||
|
||||
// Reference to the shader input being modified
|
||||
internal ShaderInput shaderInputReference { get; set; }
|
||||
|
||||
internal string newDisplayNameValue { get; set; }
|
||||
}
|
||||
|
||||
class ChangeReferenceNameAction : IGraphDataAction
|
||||
{
|
||||
void ChangeReferenceName(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeReferenceNameAction");
|
||||
AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out ChangeReferenceNameAction");
|
||||
// The Undos are currently handled in ShaderInputPropertyDrawer but we want to move that out from there and handle here
|
||||
//graphData.owner.RegisterCompleteObjectUndo("Change Reference Name");
|
||||
if (newReferenceNameValue != shaderInputReference.overrideReferenceName)
|
||||
{
|
||||
graphData.SanitizeGraphInputReferenceName(shaderInputReference, newReferenceNameValue);
|
||||
}
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => ChangeReferenceName;
|
||||
|
||||
// Reference to the shader input being modified
|
||||
internal ShaderInput shaderInputReference { get; set; }
|
||||
|
||||
internal string newReferenceNameValue { get; set; }
|
||||
}
|
||||
|
||||
class ResetReferenceNameAction : IGraphDataAction
|
||||
{
|
||||
void ResetReferenceName(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ResetReferenceNameAction");
|
||||
AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out ResetReferenceNameAction");
|
||||
graphData.owner.RegisterCompleteObjectUndo("Reset Reference Name");
|
||||
shaderInputReference.overrideReferenceName = null;
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => ResetReferenceName;
|
||||
|
||||
// Reference to the shader input being modified
|
||||
internal ShaderInput shaderInputReference { get; set; }
|
||||
}
|
||||
|
||||
class DeleteShaderInputAction : IGraphDataAction
|
||||
{
|
||||
void DeleteShaderInput(GraphData graphData)
|
||||
{
|
||||
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out DeleteShaderInputAction");
|
||||
AssertHelpers.IsNotNull(shaderInputsToDelete, "ShaderInputsToDelete is null while carrying out DeleteShaderInputAction");
|
||||
// This is called by MaterialGraphView currently, no need to repeat it here, though ideally it would live here
|
||||
//graphData.owner.RegisterCompleteObjectUndo("Delete Graph Input(s)");
|
||||
|
||||
foreach (var shaderInput in shaderInputsToDelete)
|
||||
{
|
||||
graphData.RemoveGraphInput(shaderInput);
|
||||
}
|
||||
}
|
||||
|
||||
public Action<GraphData> modifyGraphDataAction => DeleteShaderInput;
|
||||
|
||||
// Reference to the shader input(s) being deleted
|
||||
internal IList<ShaderInput> shaderInputsToDelete { get; set; } = new List<ShaderInput>();
|
||||
}
|
||||
|
||||
class ShaderInputViewController : SGViewController<ShaderInput, ShaderInputViewModel>
|
||||
{
|
||||
// Exposed for PropertyView
|
||||
internal GraphData graphData => DataStore.State;
|
||||
|
||||
internal ShaderInputViewController(ShaderInput shaderInput, ShaderInputViewModel inViewModel, GraphDataStore graphDataStore)
|
||||
: base(shaderInput, inViewModel, graphDataStore)
|
||||
{
|
||||
InitializeViewModel();
|
||||
|
||||
m_SgBlackboardField = new SGBlackboardField(ViewModel);
|
||||
m_SgBlackboardField.controller = this;
|
||||
|
||||
m_BlackboardRowView = new SGBlackboardRow(m_SgBlackboardField, null);
|
||||
m_BlackboardRowView.expanded = SessionState.GetBool($"Unity.ShaderGraph.Input.{shaderInput.objectId}.isExpanded", false);
|
||||
}
|
||||
|
||||
void InitializeViewModel()
|
||||
{
|
||||
if (Model == null)
|
||||
{
|
||||
AssertHelpers.Fail("Could not initialize shader input view model as shader input was null.");
|
||||
return;
|
||||
}
|
||||
ViewModel.model = Model;
|
||||
ViewModel.isSubGraph = DataStore.State.isSubGraph;
|
||||
ViewModel.isInputExposed = (DataStore.State.isSubGraph || (Model.isExposable && Model.generatePropertyBlock));
|
||||
ViewModel.inputName = Model.displayName;
|
||||
switch (Model)
|
||||
{
|
||||
case AbstractShaderProperty shaderProperty:
|
||||
ViewModel.inputTypeName = shaderProperty.GetPropertyTypeString();
|
||||
// Handles upgrade fix for deprecated old Color property
|
||||
shaderProperty.onBeforeVersionChange += (_) => graphData.owner.RegisterCompleteObjectUndo($"Change {shaderProperty.displayName} Version");
|
||||
break;
|
||||
case ShaderKeyword shaderKeyword:
|
||||
ViewModel.inputTypeName = shaderKeyword.keywordType + " Keyword";
|
||||
ViewModel.inputTypeName = shaderKeyword.isBuiltIn ? "Built-in " + ViewModel.inputTypeName : ViewModel.inputTypeName;
|
||||
break;
|
||||
case ShaderDropdown shaderDropdown:
|
||||
ViewModel.inputTypeName = "Dropdown";
|
||||
break;
|
||||
}
|
||||
|
||||
ViewModel.requestModelChangeAction = this.RequestModelChange;
|
||||
}
|
||||
|
||||
SGBlackboardRow m_BlackboardRowView;
|
||||
SGBlackboardField m_SgBlackboardField;
|
||||
|
||||
internal SGBlackboardRow BlackboardItemView => m_BlackboardRowView;
|
||||
|
||||
protected override void RequestModelChange(IGraphDataAction changeAction)
|
||||
{
|
||||
DataStore.Dispatch(changeAction);
|
||||
}
|
||||
|
||||
// Called by GraphDataStore.Subscribe after the model has been changed
|
||||
protected override void ModelChanged(GraphData graphData, IGraphDataAction changeAction)
|
||||
{
|
||||
switch (changeAction)
|
||||
{
|
||||
case ChangeExposedFlagAction changeExposedFlagAction:
|
||||
// ModelChanged is called overzealously on everything
|
||||
// but we only care if the action pertains to our Model
|
||||
if (changeExposedFlagAction.shaderInputReference == Model)
|
||||
{
|
||||
ViewModel.isInputExposed = Model.generatePropertyBlock;
|
||||
if (changeExposedFlagAction.oldIsExposedValue != changeExposedFlagAction.newIsExposedValue)
|
||||
DirtyNodes(ModificationScope.Graph);
|
||||
m_SgBlackboardField.UpdateFromViewModel();
|
||||
}
|
||||
break;
|
||||
|
||||
case ChangePropertyValueAction changePropertyValueAction:
|
||||
if (changePropertyValueAction.shaderInputReference == Model)
|
||||
{
|
||||
DirtyNodes(ModificationScope.Graph);
|
||||
m_SgBlackboardField.MarkDirtyRepaint();
|
||||
}
|
||||
break;
|
||||
|
||||
case ResetReferenceNameAction resetReferenceNameAction:
|
||||
if (resetReferenceNameAction.shaderInputReference == Model)
|
||||
{
|
||||
DirtyNodes(ModificationScope.Graph);
|
||||
}
|
||||
break;
|
||||
|
||||
case ChangeReferenceNameAction changeReferenceNameAction:
|
||||
if (changeReferenceNameAction.shaderInputReference == Model)
|
||||
{
|
||||
DirtyNodes(ModificationScope.Graph);
|
||||
}
|
||||
break;
|
||||
|
||||
case ChangeDisplayNameAction changeDisplayNameAction:
|
||||
if (changeDisplayNameAction.shaderInputReference == Model)
|
||||
{
|
||||
ViewModel.inputName = Model.displayName;
|
||||
DirtyNodes(ModificationScope.Topological);
|
||||
m_SgBlackboardField.UpdateFromViewModel();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This should communicate to node controllers instead of searching for the nodes themselves everytime, but that's going to take a while...
|
||||
internal void DirtyNodes(ModificationScope modificationScope = ModificationScope.Node)
|
||||
{
|
||||
switch (Model)
|
||||
{
|
||||
case AbstractShaderProperty property:
|
||||
var graphEditorView = m_BlackboardRowView.GetFirstAncestorOfType<GraphEditorView>();
|
||||
if (graphEditorView == null)
|
||||
return;
|
||||
var colorManager = graphEditorView.colorManager;
|
||||
var nodes = graphEditorView.graphView.Query<MaterialNodeView>().ToList();
|
||||
|
||||
colorManager.SetNodesDirty(nodes);
|
||||
colorManager.UpdateNodeViews(nodes);
|
||||
|
||||
foreach (var node in DataStore.State.GetNodes<PropertyNode>())
|
||||
{
|
||||
node.Dirty(modificationScope);
|
||||
}
|
||||
break;
|
||||
case ShaderKeyword keyword:
|
||||
foreach (var node in DataStore.State.GetNodes<KeywordNode>())
|
||||
{
|
||||
node.UpdateNode();
|
||||
node.Dirty(modificationScope);
|
||||
}
|
||||
|
||||
// Cant determine if Sub Graphs contain the keyword so just update them
|
||||
foreach (var node in DataStore.State.GetNodes<SubGraphNode>())
|
||||
{
|
||||
node.Dirty(modificationScope);
|
||||
}
|
||||
break;
|
||||
case ShaderDropdown dropdown:
|
||||
foreach (var node in DataStore.State.GetNodes<DropdownNode>())
|
||||
{
|
||||
node.UpdateNode();
|
||||
node.Dirty(modificationScope);
|
||||
}
|
||||
|
||||
// Cant determine if Sub Graphs contain the dropdown so just update them
|
||||
foreach (var node in DataStore.State.GetNodes<SubGraphNode>())
|
||||
{
|
||||
node.Dirty(modificationScope);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Destroy()
|
||||
{
|
||||
Cleanup();
|
||||
BlackboardItemView.RemoveFromHierarchy();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8e48f61a99c146b1a223fe8ad61a6b55
|
||||
timeCreated: 1611265477
|
Loading…
Add table
Add a link
Reference in a new issue