You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

354 lines
13 KiB

using UnityEditor.Experimental.GraphView;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using System;
namespace UnityEditor.VFX.UI
{
class VFXOperatorController : VFXNodeController
{
protected override VFXDataAnchorController AddDataAnchor(VFXSlot slot, bool input, bool hidden)
{
VFXOperatorAnchorController anchor;
if (input)
{
anchor = new VFXInputOperatorAnchorController(slot, this, hidden);
}
else
{
anchor = new VFXOutputOperatorAnchorController(slot, this, hidden);
}
anchor.portType = slot.property.type;
return anchor;
}
public VFXOperatorController(VFXOperator model, VFXViewController viewController) : base(model, viewController)
{
if (model is VFXSubgraphOperator subgraphOperator)
{
// Prevent breaking the editor opening.
try
{
subgraphOperator.RecreateCopy();
model.ResyncSlots(false);
model.MarkOutputExpressionsAsOutOfDate();
model.UpdateOutputExpressionsIfNeeded();
}
catch (Exception e)
{
Debug.LogException(e);
}
}
}
public new VFXOperator model
{
get
{
return base.model as VFXOperator;
}
}
public virtual bool isEditable
{
get { return false; }
}
public VFXParameter ConvertToProperty(bool exposed = false)
{
var desc = VFXLibrary.GetParameters().FirstOrDefault(t => t.modelType == ((VFXInlineOperator)model).type);
if (desc == null)
return null;
var param = viewController.AddVFXParameter(Vector2.zero, desc.variant, false); // parameters should have zero for position, position is help by the nodes
param.SetSettingValue("m_Exposed", exposed);
VFXSlot.CopyLinks(param.GetOutputSlot(0), model.GetOutputSlot(0), false);
viewController.AddVFXModel(Vector2.zero, param);
param.CreateDefaultNode(position);
viewController.LightApplyChanges();
var paramController = viewController.GetParameterController(param);
paramController.value = inputPorts[0].value;
var paramNodeController = paramController.nodes.FirstOrDefault();
if (paramNodeController != null)
{
viewController.PutInSameGroupNodeAs(paramNodeController, this);
viewController.RemoveElement(this);
}
return param;
}
}
class VFXVariableOperatorController : VFXOperatorController
{
public VFXVariableOperatorController(VFXOperator model, VFXViewController viewController) : base(model, viewController)
{
}
public new VFXOperatorDynamicOperand model
{
get
{
return base.model as VFXOperatorDynamicOperand;
}
}
protected override bool CouldLinkMyInputTo(VFXDataAnchorController myInput, VFXDataAnchorController otherOutput, VFXDataAnchorController.CanLinkCache cache)
{
if (otherOutput.direction == myInput.direction)
return false;
if (!myInput.CanLinkToNode(otherOutput.sourceNode, cache))
return false;
return model.GetBestAffinityType(otherOutput.portType) != null;
}
public override bool isEditable
{
get { return true; }
}
}
class VFXUnifiedOperatorControllerBase<T> : VFXVariableOperatorController where T : VFXOperatorNumeric, IVFXOperatorNumericUnified
{
public VFXUnifiedOperatorControllerBase(VFXOperator model, VFXViewController viewController) : base(model, viewController)
{
}
public new T model
{
get
{
return base.model as T;
}
}
public override void WillCreateLink(ref VFXSlot myInput, ref VFXSlot otherOutput, bool revertTypeConstraint)
{
if (!myInput.IsMasterSlot())
return;
var bestAffinityType = revertTypeConstraint
? model.GetBestAffinityType(myInput.property.type)
: model.GetBestAffinityType(otherOutput.property.type);
if (bestAffinityType != null)
{
int index = model.GetSlotIndex(myInput);
model.SetOperandType(index, bestAffinityType);
myInput = model.GetInputSlot(index);
}
}
}
class VFXUnifiedOperatorController : VFXUnifiedOperatorControllerBase<VFXOperatorNumericUnified>
{
public VFXUnifiedOperatorController(VFXOperator model, VFXViewController viewController) : base(model, viewController)
{
}
}
class VFXUnifiedConstraintOperatorController : VFXUnifiedOperatorController
{
public VFXUnifiedConstraintOperatorController(VFXOperator model, VFXViewController viewController) : base(model, viewController)
{
}
protected override bool CouldLinkMyInputTo(VFXDataAnchorController myInput, VFXDataAnchorController otherOutput, VFXDataAnchorController.CanLinkCache cache)
{
if (!myInput.model.IsMasterSlot())
return false;
if (otherOutput.direction == myInput.direction)
return false;
if (!myInput.CanLinkToNode(otherOutput.sourceNode, cache))
return false;
int inputIndex = model.GetSlotIndex(myInput.model);
IVFXOperatorNumericUnifiedConstrained constraintInterface = model as IVFXOperatorNumericUnifiedConstrained;
var bestAffinityType = model.GetBestAffinityType(otherOutput.portType);
if (bestAffinityType == null)
return false;
if (constraintInterface.slotIndicesThatCanBeScalar.Contains(inputIndex))
{
if (VFXTypeUtility.GetComponentCount(otherOutput.model) != 0) // If it is a vector or float type, then conversion to float exists
return true;
}
return model.GetBestAffinityType(otherOutput.portType) != null;
}
public static Type GetMatchingScalar(Type otherType)
{
return VFXExpression.GetMatchingScalar(otherType);
}
public override void WillCreateLink(ref VFXSlot myInput, ref VFXSlot otherOutput, bool revertTypeConstaint = false)
{
if (!myInput.IsMasterSlot())
return;
int inputIndex = model.GetSlotIndex(myInput);
IVFXOperatorNumericUnifiedConstrained constraintInterface = model as IVFXOperatorNumericUnifiedConstrained;
if (!constraintInterface.slotIndicesThatMustHaveSameType.Contains(inputIndex))
{
base.WillCreateLink(ref myInput, ref otherOutput, revertTypeConstaint);
return;
}
bool scalar = constraintInterface.slotIndicesThatCanBeScalar.Contains(inputIndex);
if (scalar)
{
var bestAffinityType = revertTypeConstaint
? model.GetBestAffinityType(myInput.property.type)
: model.GetBestAffinityType(otherOutput.property.type);
VFXSlot otherSlotWithConstraint = model.inputSlots.Where((t, i) => constraintInterface.slotIndicesThatMustHaveSameType.Contains(i)).FirstOrDefault();
if (otherSlotWithConstraint == null || otherSlotWithConstraint.property.type == bestAffinityType)
{
model.SetOperandType(inputIndex, bestAffinityType);
myInput = model.GetInputSlot(inputIndex);
}
else if (!myInput.CanLink(otherOutput) || !otherOutput.CanLink(myInput)) // if the link is invalid if we don't change the type, change the type to the matching scalar
{
var bestScalarAffinityType = revertTypeConstaint
? model.GetBestAffinityType(GetMatchingScalar(myInput.property.type))
: model.GetBestAffinityType(GetMatchingScalar(otherOutput.property.type));
if (bestScalarAffinityType != null)
{
model.SetOperandType(inputIndex, bestScalarAffinityType);
myInput = model.GetInputSlot(inputIndex);
}
}
return; // never change the type of other constraint if the linked slot is scalar
}
VFXSlot input = myInput;
bool hasLinks = model.inputSlots.Where((t, i) => t != input && t.HasLink(true) && constraintInterface.slotIndicesThatMustHaveSameType.Contains(i) && !constraintInterface.slotIndicesThatCanBeScalar.Contains(i)).Count() > 0;
bool linkPossible = myInput.CanLink(otherOutput) && otherOutput.CanLink(myInput);
if (!hasLinks || !linkPossible) //Change the type if other type having the same constraint have no link or if the link will fail if we don't
{
var bestAffinityType = model.GetBestAffinityType(otherOutput.property.type);
if (bestAffinityType != null)
{
foreach (int slotIndex in constraintInterface.slotIndicesThatMustHaveSameType)
{
if (!constraintInterface.slotIndicesThatCanBeScalar.Contains(slotIndex) || GetMatchingScalar(bestAffinityType) != model.GetInputSlot(slotIndex).property.type)
model.SetOperandType(slotIndex, bestAffinityType);
}
myInput = model.GetInputSlot(inputIndex);
}
}
}
}
class VFXCascadedOperatorController : VFXUnifiedOperatorControllerBase<VFXOperatorNumericCascadedUnified>
{
public VFXCascadedOperatorController(VFXOperator model, VFXViewController viewController) : base(model, viewController)
{
}
VFXUpcommingDataAnchorController m_UpcommingDataAnchor;
protected override void NewInputSet(List<VFXDataAnchorController> newInputs)
{
if (m_UpcommingDataAnchor == null)
{
m_UpcommingDataAnchor = new VFXUpcommingDataAnchorController(this, false);
}
newInputs.Add(m_UpcommingDataAnchor);
}
public override void OnEdgeFromInputGoingToBeRemoved(VFXDataAnchorController myInput)
{
base.OnEdgeFromInputGoingToBeRemoved(myInput);
RemoveOperand(myInput);
}
public bool CanRemove()
{
return model.operandCount > model.MinimalOperandCount;
}
public void RemoveOperand(VFXDataAnchorController myInput)
{
var slotIndex = model.GetSlotIndex(myInput.model);
if (slotIndex != -1)
RemoveOperand(slotIndex);
}
public void RemoveOperand(int index)
{
if (CanRemove())
{
model.RemoveOperand(index);
}
}
}
class VFXUniformOperatorController<T> : VFXVariableOperatorController where T : VFXOperatorDynamicOperand, IVFXOperatorUniform
{
public VFXUniformOperatorController(VFXOperator model, VFXViewController viewController) : base(model, viewController)
{
}
public new T model
{
get
{
return base.model as T;
}
}
public override void WillCreateLink(ref VFXSlot myInput, ref VFXSlot otherOutput, bool revertTypeConstraint = false)
{
if (!myInput.IsMasterSlot())
return;
//Since every input will change at the same time the metric to change is :
// if we have no input links yet
var myInputCopy = myInput;
bool hasLink = inputPorts.Any(t => t.model != myInputCopy && t.model.HasLink());
int index = model.GetSlotIndex(myInput);
if (model.staticSlotIndex.Contains(index))
return;
// The new link is impossible if we don't change (case of a vector3 trying to be linked to a vector4)
bool linkImpossibleNow = !myInput.CanLink(otherOutput) || !otherOutput.CanLink(myInput);
var bestAffinity = revertTypeConstraint
? model.GetBestAffinityType(myInput.property.type)
: model.GetBestAffinityType(otherOutput.property.type);
if ((!hasLink || linkImpossibleNow) && bestAffinity != null)
{
model.SetOperandType(bestAffinity);
myInput = model.GetInputSlot(index);
}
}
}
class VFXNumericUniformOperatorController : VFXUniformOperatorController<VFXOperatorNumericUniform>
{
public VFXNumericUniformOperatorController(VFXOperator model, VFXViewController viewController) : base(model, viewController)
{
}
}
class VFXDynamicTypeOperatorController : VFXUniformOperatorController<VFXOperatorDynamicType>
{
public VFXDynamicTypeOperatorController(VFXOperator model, VFXViewController viewController) : base(model, viewController)
{
}
}
}