You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3045482 on 2016/07/11 by Zabir.Hoque DX12 Quries need to individually track their syncpoints. Only when resolving a query on the same frame should be stall. Change 3045929 on 2016/07/12 by Simon.Tovey Removing some deprecated node types from Niagara Change 3045951 on 2016/07/12 by Ben.Woodhouse D3D11 Log detailed live device info on shutdown if the debug layer is enabled (including resource types) Change3046019on 2016/07/12 by Chris.Bunner Fixed typo in material input name. #jira UE-5575 Change 3046053 on 2016/07/12 by Rolando.Caloca DR - Fix GL4 shutdown #jira UE-32799 Change 3046055 on 2016/07/12 by Rolando.Caloca DR - vk - Fix NumInstances=0 Change 3046063 on 2016/07/12 by Rolando.Caloca DR - vk - Added flat to uint layouts per glslang - Fix bad extension on dumped shaders Change 3046067 on 2016/07/12 by Rolando.Caloca DR - vk - Fix check when not using color RT - Added queue submit & present counters Change3046088on 2016/07/12 by Ben.Woodhouse Live GPU stats A non-hierarchical realtime high level GPU profiler with support for cumulative stat recording. Stats are added with SCOPED_GPU_STAT macros, e.g. SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Distortion) The bulk of the files in this change are simply instrumentation for the renderer. The core changes are in SceneUtils.cpp/h and D3D11Query.cpp (this is the XB1/DX11X implementation of timestamp RHI queries, which was missing) Note: this is currently disabled by default. Enable with the cvar r.gpustatsenabled Tested on PC, XB1, PS4 Change 3046128 on 2016/07/12 by Olaf.Piesche Max draw distance and fade range for lights, requested by JonL Change 3046183 on 2016/07/12 by Ben.Woodhouse PR #2532: Fix SSAO being applied in unlit viewmode (Contributed by nick-penwarden) Change 3046223 on 2016/07/12 by Luke.Thatcher Fix Scene Cube Captures. SceneCaptureSource flag on the ViewFamily was not set for cube components. #jira UE-32345 Change 3046228 on 2016/07/12 by Marc.Olano Add Voronoi noise to Noise material node. Four versions with differing speed/quality levels accessed through the Quality value in the material node. Tooltips give estimates of the cost of each. Also includes spiffy new Rand3DPCG16 and Rand3DPCG32 int3 to int3 hash functions, and a 20% improvement on the computed gradient noise. Change 3046269 on 2016/07/12 by Rolando.Caloca DR - Skip flush on RHIDiscardRenderTargets and only use it on platforms that need it (ie OpenGL) Change 3046294 on 2016/07/12 by Rolando.Caloca DR - Fix static analyisis warning C6326: Potential comparison of a constant with another constant. Change 3046295 on 2016/07/12 by Rolando.Caloca DR - Fix the previous fix Change 3046731 on 2016/07/12 by Marc.Olano Fix typo in shader random number constant: repeated extra digit made it too big. Change 3046796 on 2016/07/12 by Uriel.Doyon The texture streaming manager now keeps a set of all valid textures. This is used to prevent from indirecting deleted memory upon SetTexturesRemovedTimestamp. #jira UE-33048 Change 3046800 on 2016/07/12 by Rolando.Caloca DR - vk - Added create image & renderpass dump Change 3046845 on 2016/07/12 by John.Billon Forgot to apply MaxGPUSkinBones Cvar access changes in a few locations. Change 3047023 on 2016/07/12 by Olaf.Piesche Niagara: -a bit of cleanup -now store and double buffer attributes individually, eliminating unnecessary copy of unused attributes -removed FNiagaraConstantMap, replaced with an instance of FNiagaraConstants -some code simplification -removed some deprecated structs and code used only by old content Change 3047052 on 2016/07/12 by Zabir.Hoque Unshelved from pending changelist '3044062': PR #2588: Adding blend mode BLEND_AlphaComposite (4.12) (Contributed by moritz-wundke) Change 3047727 on 2016/07/13 by Luke.Thatcher Fix Scene Capture Components only updating every other frame. #jira UE-32581 Change 3047919 on 2016/07/13 by Olaf.Piesche CMask decode, use in deferred decals, for PS4 Change 3047921 on 2016/07/13 by Uriel.Doyon "Build Texture Streaming" will now remove duplicate error msg when computing texcoord scales. Also, several texture messages are packed on the same line if they relate to the same material. Change 3047952 on 2016/07/13 by Rolando.Caloca DR - vk - Initial prep pass for separating combined images & samplers Change 3048648 on 2016/07/13 by Marcus.Wassmer Fix rare GPU hang when asynctexture reallocs would overlap with EndFrame Change 3049058 on 2016/07/13 by Rolando.Caloca DR - vk - timestamps Change 3049725 on 2016/07/14 by Marcus.Wassmer Fix autosdk bug where not having a platform directory sync'd at all would break manual SDK detection Change 3049742 on 2016/07/14 by Rolando.Caloca DR - Fix warning Change 3049902 on 2016/07/14 by Rolando.Caloca DR - Fix typo Change 3050345 on 2016/07/14 by Olaf.Piesche UE-23925 Clamping noise tessellation for beams at a high but sensible value; also making sure during beam index buffer building that we never get over 2^16 indices; this is a bit hokey, but there are so many variables that can influence triangle/index count, that this is the only way to be sure (short of nuking the entire site from orbit). Change 3050409 on 2016/07/14 by Olaf.Piesche Replicating 3049049; missing break and check for active particles when resolving a source point to avoid a potential crash Change 3050809 on 2016/07/14 by Rolando.Caloca DR - vk - Remove redundant validation layers Change 3051319 on 2016/07/15 by Ben.Woodhouse Fix for world space camera position not being exposed in decal pixel shaders; also fixes decal lighting missing spec and reflection The fix was to calculate ResolvedView at the top of the shader. Previously this was not initialized #jira UE-31976 Change 3051692 on 2016/07/15 by Rolando.Caloca DR - vk - Enable RHI thread by default Change 3052103 on 2016/07/15 by Uriel.Doyon Disabled depth offset in depth only pixel shaders when using debug view shaders (to prevent Z fighting). #jira UE-32765 Change 3052140 on 2016/07/15 by Rolando.Caloca DR - vk - Fix shader snafu Change 3052495 on 2016/07/15 by Rolando.Caloca DR - Fix for Win32 compile #jira UE-33349 Change 3052536 on 2016/07/15 by Uriel.Doyon Fixed texture streaming overbudget warning when using per texture bias. [CL 3054554 by Gil Gribb in Main branch]
655 lines
22 KiB
C++
655 lines
22 KiB
C++
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "NiagaraEditorPrivatePCH.h"
|
|
#include "NiagaraScript.h"
|
|
#include "NiagaraComponent.h"
|
|
#include "CompilerResultsLog.h"
|
|
#include "EdGraphUtilities.h"
|
|
#include "VectorVM.h"
|
|
#include "ComponentReregisterContext.h"
|
|
#include "NiagaraCompiler_VectorVM.h"
|
|
#include "NiagaraEditorCommon.h"
|
|
#include "NiagaraNodeFunctionCall.h"
|
|
#include "NiagaraNodeInput.h"
|
|
#include "NiagaraNodeOutput.h"
|
|
|
|
#include "EdGraphSchema_Niagara.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "NiagaraCompiler"
|
|
|
|
DEFINE_LOG_CATEGORY_STATIC(LogNiagaraCompiler, All, All);
|
|
|
|
void FNiagaraEditorModule::CompileScript(UNiagaraScript* ScriptToCompile)
|
|
{
|
|
check(ScriptToCompile != NULL);
|
|
if (ScriptToCompile->Source == NULL)
|
|
{
|
|
UE_LOG(LogNiagaraCompiler, Error, TEXT("No source for Niagara script: %s"), *ScriptToCompile->GetPathName());
|
|
return;
|
|
}
|
|
|
|
TComponentReregisterContext<UNiagaraComponent> ComponentReregisterContext;
|
|
|
|
FNiagaraCompiler_VectorVM Compiler;
|
|
Compiler.CompileScript(ScriptToCompile);
|
|
|
|
//Compile for compute here too?
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
/** Expression that gets an input attribute. */
|
|
class FNiagaraExpression_GetAttribute : public FNiagaraExpression
|
|
{
|
|
public:
|
|
|
|
FNiagaraExpression_GetAttribute(class FNiagaraCompiler* InCompiler, const FNiagaraVariableInfo& InAttribute)
|
|
: FNiagaraExpression(InCompiler, InAttribute)
|
|
{
|
|
ResultLocation = ENiagaraExpressionResultLocation::InputData;
|
|
}
|
|
|
|
virtual bool Process()override
|
|
{
|
|
check(ResultLocation == ENiagaraExpressionResultLocation::InputData);
|
|
ResultIndex = Compiler->GetAttributeIndex(Result);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
/** Expression that gets a constant. */
|
|
class FNiagaraExpression_GetConstant : public FNiagaraExpression
|
|
{
|
|
public:
|
|
|
|
FNiagaraExpression_GetConstant(class FNiagaraCompiler* InCompiler, const FNiagaraVariableInfo& InConstant, bool bIsInternal)
|
|
: FNiagaraExpression(InCompiler, InConstant)
|
|
, bInternal(bIsInternal)
|
|
{
|
|
ResultLocation = ENiagaraExpressionResultLocation::Constants;
|
|
//For matrix constants we must add 4 input expressions that will be filled in as the constant is processed.
|
|
//They must at least exist now so that other expressions can reference them.
|
|
if (Result.Type == ENiagaraDataType::Matrix)
|
|
{
|
|
static const FName ResultName(TEXT("MatrixComponent"));
|
|
SourceExpressions.Add(MakeShareable(new FNiagaraExpression(InCompiler, FNiagaraVariableInfo(ResultName, ENiagaraDataType::Vector))));
|
|
SourceExpressions.Add(MakeShareable(new FNiagaraExpression(InCompiler, FNiagaraVariableInfo(ResultName, ENiagaraDataType::Vector))));
|
|
SourceExpressions.Add(MakeShareable(new FNiagaraExpression(InCompiler, FNiagaraVariableInfo(ResultName, ENiagaraDataType::Vector))));
|
|
SourceExpressions.Add(MakeShareable(new FNiagaraExpression(InCompiler, FNiagaraVariableInfo(ResultName, ENiagaraDataType::Vector))));
|
|
}
|
|
}
|
|
|
|
virtual bool Process()override
|
|
{
|
|
check(ResultLocation == ENiagaraExpressionResultLocation::Constants);
|
|
//Get the index of the constant. Also gets a component index if this is for a packed scalar constant.
|
|
Compiler->GetConstantResultIndex(Result, bInternal, ResultIndex);
|
|
|
|
if (Result.Type == ENiagaraDataType::Matrix)
|
|
{
|
|
check(SourceExpressions.Num() == 4);
|
|
TNiagaraExprPtr Src0 = GetSourceExpression(0);
|
|
TNiagaraExprPtr Src1 = GetSourceExpression(1);
|
|
TNiagaraExprPtr Src2 = GetSourceExpression(2);
|
|
TNiagaraExprPtr Src3 = GetSourceExpression(3);
|
|
Src0->ResultLocation = ENiagaraExpressionResultLocation::Constants;
|
|
Src0->ResultIndex = ResultIndex;
|
|
Src1->ResultLocation = ENiagaraExpressionResultLocation::Constants;
|
|
Src1->ResultIndex = ResultIndex + 1;
|
|
Src2->ResultLocation = ENiagaraExpressionResultLocation::Constants;
|
|
Src2->ResultIndex = ResultIndex + 2;
|
|
Src3->ResultLocation = ENiagaraExpressionResultLocation::Constants;
|
|
Src3->ResultIndex = ResultIndex + 3;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool bInternal;
|
|
};
|
|
|
|
/** Expression that just collects some other expressions together. E.g for a matrix. */
|
|
class FNiagaraExpression_Collection : public FNiagaraExpression
|
|
{
|
|
public:
|
|
|
|
FNiagaraExpression_Collection(class FNiagaraCompiler* InCompiler, const FNiagaraVariableInfo& Result, TArray<TNiagaraExprPtr>& InSourceExpressions)
|
|
: FNiagaraExpression(InCompiler, Result)
|
|
{
|
|
SourceExpressions = InSourceExpressions;
|
|
}
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
bool FNiagaraCompiler::CheckInputs(FName OpName, TArray<TNiagaraExprPtr>& Inputs)
|
|
{
|
|
//check the types of the input expressions.
|
|
const FNiagaraOpInfo* OpInfo = FNiagaraOpInfo::GetOpInfo(OpName);
|
|
check(OpInfo);
|
|
int32 NumInputs = Inputs.Num();
|
|
check(OpInfo->Inputs.Num() == NumInputs);
|
|
bool bError = false;
|
|
for (int32 i = 0; i < NumInputs ; ++i)
|
|
{
|
|
check(Inputs[i].IsValid());
|
|
if (OpInfo->Inputs[i].DataType != Inputs[i]->Result.Type)
|
|
{
|
|
bError = true;
|
|
FText ErrorText = FText::Format(LOCTEXT("Expression {0} has incorrect inputs!\nExpected: {1} - Actual: {2}", ""),
|
|
FText::FromString(OpName.ToString()),
|
|
FText::AsNumber((int32)OpInfo->Inputs[i].DataType),
|
|
FText::AsNumber((int32)((TNiagaraExprPtr)Inputs[i])->Result.Type.GetValue()));
|
|
MessageLog.Error(*ErrorText.ToString());
|
|
}
|
|
}
|
|
return bError;
|
|
}
|
|
|
|
bool FNiagaraCompiler::CheckOutputs(FName OpName, TArray<TNiagaraExprPtr>& Outputs)
|
|
{
|
|
//check the types of the input expressions.
|
|
const FNiagaraOpInfo* OpInfo = FNiagaraOpInfo::GetOpInfo(OpName);
|
|
check(OpInfo);
|
|
int32 NumOutputs = Outputs.Num();
|
|
bool bError = false;
|
|
check(OpInfo->Outputs.Num() == NumOutputs);
|
|
for (int32 i = 0; i < NumOutputs; ++i)
|
|
{
|
|
check(Outputs[i].IsValid());
|
|
if (OpInfo->Outputs[i].DataType != Outputs[i]->Result.Type)
|
|
{
|
|
bError = true;
|
|
FText ErrorText = FText::Format(LOCTEXT("Expression {0} has incorrect inputs!\nExpected: {1} - Actual: {2}", ""),
|
|
FText::FromString(OpName.ToString()),
|
|
FText::AsNumber((int32)OpInfo->Outputs[i].DataType),
|
|
FText::AsNumber((int32)((TNiagaraExprPtr)Outputs[i])->Result.Type.GetValue()));
|
|
MessageLog.Error(*ErrorText.ToString());
|
|
}
|
|
}
|
|
return bError;
|
|
}
|
|
|
|
void FNiagaraCompiler::Error(FText ErrorText, UNiagaraNode* Node, UEdGraphPin* Pin)
|
|
{
|
|
if (Pin)
|
|
{
|
|
FString ErrorString = FString::Printf(TEXT("Node: @@ - Pin: @@ - %s"), *ErrorText.ToString());
|
|
MessageLog.Error(*ErrorString, Node, Pin);
|
|
}
|
|
else
|
|
{
|
|
FString ErrorString = FString::Printf(TEXT("Node: @@ - %s"), *ErrorText.ToString());
|
|
MessageLog.Error(*ErrorString, Node);
|
|
}
|
|
}
|
|
|
|
void FNiagaraCompiler::Warning(FText WarningText, UNiagaraNode* Node, UEdGraphPin* Pin)
|
|
{
|
|
FString WarnString = FString::Printf(TEXT("Node: @@ - Pin: @@ - %s"), *WarningText.ToString());
|
|
MessageLog.Warning(*WarnString, Node, Pin);
|
|
}
|
|
|
|
int32 FNiagaraCompiler::GetAttributeIndex(const FNiagaraVariableInfo& Attr)const
|
|
{
|
|
return SourceGraph->GetAttributeIndex(Attr);
|
|
}
|
|
|
|
FNiagaraDataSetProperties* FNiagaraCompiler::GetSharedDataIndex(FNiagaraDataSetID DataSet, bool bForRead, int32& OutIndex)
|
|
{
|
|
//Shared data is laid out:
|
|
//EventReceivers
|
|
//EventGenerators
|
|
|
|
int32 SetIndex = 0;
|
|
FNiagaraDataSetProperties* Ret = NULL;
|
|
auto SearchSharedArea = [&](TArray<FNiagaraDataSetProperties>& SharedSetGroup) -> FNiagaraDataSetProperties*
|
|
{
|
|
for (FNiagaraDataSetProperties& Props : SharedSetGroup)
|
|
{
|
|
if (DataSet == Props.ID)
|
|
{
|
|
OutIndex = SetIndex;
|
|
return &Props;
|
|
}
|
|
++SetIndex;
|
|
}
|
|
return NULL;
|
|
};
|
|
|
|
if (bForRead)
|
|
{
|
|
Ret = SearchSharedArea(EventReceivers);
|
|
}
|
|
else
|
|
{
|
|
SetIndex = EventReceivers.Num();
|
|
Ret = SearchSharedArea(EventGenerators);
|
|
}
|
|
check(Ret);
|
|
return Ret;
|
|
}
|
|
|
|
int32 FNiagaraCompiler::GetSharedDataVariableIndex(FNiagaraDataSetProperties* SharedDataSet, const FNiagaraVariableInfo& Variable)
|
|
{
|
|
check(SharedDataSet);
|
|
|
|
for (int32 i = 0; i < SharedDataSet->Variables.Num(); ++i)
|
|
{
|
|
if (SharedDataSet->Variables[i] == Variable)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return INDEX_NONE;
|
|
}
|
|
|
|
TNiagaraExprPtr FNiagaraCompiler::CompileOutputPin(UEdGraphPin* Pin)
|
|
{
|
|
check(Pin->Direction == EGPD_Output);
|
|
|
|
TNiagaraExprPtr Ret;
|
|
|
|
TNiagaraExprPtr* Expr = PinToExpression.Find(Pin);
|
|
if (Expr)
|
|
{
|
|
Ret = *Expr; //We've compiled this pin before. Return it's expression.
|
|
}
|
|
else
|
|
{
|
|
//Otherwise we need to compile the node to get its output pins.
|
|
UNiagaraNode* Node = Cast<UNiagaraNode>(Pin->GetOwningNode());
|
|
TArray<FNiagaraNodeResult> Outputs;
|
|
Node->Compile(this, Outputs);
|
|
for (int32 i = 0; i < Outputs.Num(); ++i)
|
|
{
|
|
PinToExpression.Add(Outputs[i].OutputPin, Outputs[i].Expression);
|
|
//We also grab the expression for the pin we're currently interested in. Otherwise we'd have to search the map for it.
|
|
Ret = Outputs[i].OutputPin == Pin ? Outputs[i].Expression : Ret;
|
|
}
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
TNiagaraExprPtr FNiagaraCompiler::CompilePin(UEdGraphPin* Pin)
|
|
{
|
|
check(Pin);
|
|
TNiagaraExprPtr Ret;
|
|
if (Pin->Direction == EGPD_Input)
|
|
{
|
|
if (Pin->LinkedTo.Num() > 0)
|
|
{
|
|
//If we link to a function call, merge it's graph in.
|
|
TArray<UNiagaraScript*> Stack;
|
|
UNiagaraNodeFunctionCall* Function = Cast<UNiagaraNodeFunctionCall>(Pin->LinkedTo[0]->GetOwningNode());
|
|
while(Function)
|
|
{
|
|
if (!MergeFunctionIntoMainGraph(Function, Stack))
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
Function = Cast<UNiagaraNodeFunctionCall>(Pin->LinkedTo[0]->GetOwningNode());
|
|
}
|
|
//Any functon calls linked to this pin are now merged into the main graph, compile it.
|
|
Ret = CompileOutputPin(Pin->LinkedTo[0]);
|
|
}
|
|
else if (!Pin->bDefaultValueIsIgnored)
|
|
{
|
|
//No connections to this input so add the default as a const expression.
|
|
const UEdGraphSchema_Niagara* Schema = Cast<const UEdGraphSchema_Niagara>(Pin->GetSchema());
|
|
ENiagaraDataType PinType = Schema->GetPinDataType(Pin);
|
|
|
|
FString ConstString = Pin->GetDefaultAsString();
|
|
FName ConstName(*ConstString);
|
|
|
|
FNiagaraVariableInfo Var(ConstName, PinType);
|
|
|
|
switch (PinType)
|
|
{
|
|
case ENiagaraDataType::Scalar:
|
|
{
|
|
float Default;
|
|
Schema->GetPinDefaultValue(Pin, Default);
|
|
ConstantData.SetOrAddInternal(Var, Default);
|
|
}
|
|
break;
|
|
case ENiagaraDataType::Vector:
|
|
{
|
|
FVector4 Default;
|
|
Schema->GetPinDefaultValue(Pin, Default);
|
|
ConstantData.SetOrAddInternal(Var, Default);
|
|
}
|
|
break;
|
|
case ENiagaraDataType::Matrix:
|
|
{
|
|
FMatrix Default;
|
|
Schema->GetPinDefaultValue(Pin, Default);
|
|
ConstantData.SetOrAddInternal(Var, Default);
|
|
}
|
|
break;
|
|
}
|
|
Ret = Expression_GetInternalConstant(Var);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Ret = CompileOutputPin(Pin);
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
void FNiagaraCompiler::GetParticleAttributes(TArray<FNiagaraVariableInfo>& OutAttributes)const
|
|
{
|
|
check(SourceGraph);
|
|
SourceGraph->GetAttributes(OutAttributes);
|
|
}
|
|
|
|
TNiagaraExprPtr FNiagaraCompiler::Expression_GetAttribute(const FNiagaraVariableInfo& Attribute)
|
|
{
|
|
Usage.bReadsAttriubteData = true;
|
|
|
|
int32 Index = Expressions.Add(MakeShareable(new FNiagaraExpression_GetAttribute(this, Attribute)));
|
|
return Expressions[Index];
|
|
}
|
|
|
|
TNiagaraExprPtr FNiagaraCompiler::Expression_GetExternalConstant(const FNiagaraVariableInfo& Constant)
|
|
{
|
|
int32 Index = Expressions.Add(MakeShareable(new FNiagaraExpression_GetConstant(this, Constant, false)));
|
|
return Expressions[Index];
|
|
}
|
|
|
|
TNiagaraExprPtr FNiagaraCompiler::Expression_GetInternalConstant(const FNiagaraVariableInfo& Constant)
|
|
{
|
|
int32 Index = Expressions.Add(MakeShareable(new FNiagaraExpression_GetConstant(this, Constant, true)));
|
|
return Expressions[Index];
|
|
}
|
|
|
|
TNiagaraExprPtr FNiagaraCompiler::Expression_Collection(TArray<TNiagaraExprPtr>& SourceExpressions)
|
|
{
|
|
//Todo - Collection expressions are just to collect parts of a matrix currently. Its a crappy way to do things that should be replaced.
|
|
//Definitely don't start using it for collections of other things.
|
|
int32 Index = Expressions.Add(MakeShareable(new FNiagaraExpression_Collection(this, FNiagaraVariableInfo(NAME_None, ENiagaraDataType::Vector), SourceExpressions)));
|
|
return Expressions[Index];
|
|
}
|
|
|
|
TNiagaraExprPtr FNiagaraCompiler::GetAttribute(const FNiagaraVariableInfo& Attribute)
|
|
{
|
|
return Expression_GetAttribute(Attribute);
|
|
}
|
|
|
|
TNiagaraExprPtr FNiagaraCompiler::GetExternalConstant(const FNiagaraVariableInfo& Constant, float Default)
|
|
{
|
|
SetOrAddConstant(false, Constant, Default);
|
|
return Expression_GetExternalConstant(Constant);
|
|
}
|
|
TNiagaraExprPtr FNiagaraCompiler::GetExternalConstant(const FNiagaraVariableInfo& Constant, const FVector4& Default)
|
|
{
|
|
SetOrAddConstant(false, Constant, Default);
|
|
return Expression_GetExternalConstant(Constant);
|
|
}
|
|
TNiagaraExprPtr FNiagaraCompiler::GetExternalConstant(const FNiagaraVariableInfo& Constant, const FMatrix& Default)
|
|
{
|
|
SetOrAddConstant(false, Constant, Default);
|
|
return Expression_GetExternalConstant(Constant);
|
|
}
|
|
TNiagaraExprPtr FNiagaraCompiler::GetInternalConstant(const FNiagaraVariableInfo& Constant, float Default)
|
|
{
|
|
SetOrAddConstant(true, Constant, Default);
|
|
return Expression_GetInternalConstant(Constant);
|
|
}
|
|
TNiagaraExprPtr FNiagaraCompiler::GetInternalConstant(const FNiagaraVariableInfo& Constant, const FVector4& Default)
|
|
{
|
|
SetOrAddConstant(true, Constant, Default);
|
|
return Expression_GetInternalConstant(Constant);
|
|
}
|
|
TNiagaraExprPtr FNiagaraCompiler::GetInternalConstant(const FNiagaraVariableInfo& Constant, const FMatrix& Default)
|
|
{
|
|
SetOrAddConstant(true, Constant, Default);
|
|
return Expression_GetInternalConstant(Constant);
|
|
}
|
|
|
|
bool FNiagaraCompiler::MergeFunctionIntoMainGraph(UNiagaraNodeFunctionCall* FunctionNode, TArray<UNiagaraScript*>& FunctionStack)
|
|
{
|
|
struct FReconnectionInfo
|
|
{
|
|
public:
|
|
UEdGraphPin* From;
|
|
TArray<UEdGraphPin*> To;
|
|
|
|
//Fallback default value if an input connection is not connected.
|
|
FString FallbackDefault;
|
|
|
|
FReconnectionInfo()
|
|
: From(NULL)
|
|
{}
|
|
};
|
|
|
|
if (UNiagaraScript* FuncScript = FunctionNode->FunctionScript)
|
|
{
|
|
//Check for reentrance.
|
|
if (FunctionStack.Find(FuncScript) != INDEX_NONE)
|
|
{
|
|
FString Callstack;
|
|
Callstack.Append(FuncScript->GetPathName()); Callstack.Append(TEXT("\n"));
|
|
for (UNiagaraScript* StackScript : FunctionStack)
|
|
{
|
|
Callstack.Append(StackScript->GetPathName()); Callstack.Append(TEXT("\n"));
|
|
}
|
|
MessageLog.Error(*FString::Printf(TEXT("Reentrant function call!\n%s"), *Callstack));
|
|
return false;
|
|
}
|
|
FunctionStack.Add(FuncScript);
|
|
|
|
// Clone the source graph so we can modify it as needed; merging in the child graphs
|
|
UNiagaraScriptSource* FuncSource = CastChecked<UNiagaraScriptSource>(FuncScript->Source);
|
|
UNiagaraGraph* FuncGraph = CastChecked<UNiagaraGraph>(FEdGraphUtilities::CloneGraph(FuncSource->NodeGraph, NULL, &MessageLog));
|
|
FEdGraphUtilities::MergeChildrenGraphsIn(FuncGraph, FuncGraph, /*bRequireSchemaMatch=*/ true);
|
|
|
|
//Copies the function graph into the main graph.
|
|
//Removes the Function call in the main graph and the input and output nodes in the function graph, reconnecting their pins appropriately.
|
|
//auto MergeFunctionIntoMainGraph = [&](UNiagaraNodeFunctionCall* InFunc, UNiagaraGraph* FuncGraph)
|
|
|
|
TMap<FName, FReconnectionInfo> InputConnections;
|
|
TMap<FName, FReconnectionInfo> OutputConnections;
|
|
TArray<class UEdGraphPin*> FuncCallInputPins;
|
|
TArray<class UEdGraphPin*> FuncCallOutputPins;
|
|
|
|
//Get all the pins that are connected to the inputs of the function call node in the main graph.
|
|
FunctionNode->GetInputPins(FuncCallInputPins);
|
|
for (UEdGraphPin* FuncCallInputPin : FuncCallInputPins)
|
|
{
|
|
FName InputName(*FuncCallInputPin->PinName);
|
|
FReconnectionInfo& InputConnection = InputConnections.FindOrAdd(InputName);
|
|
if (FuncCallInputPin->LinkedTo.Num() > 0)
|
|
{
|
|
check(FuncCallInputPin->LinkedTo.Num() == 1);
|
|
UEdGraphPin* LinkFrom = FuncCallInputPin->LinkedTo[0];
|
|
check(LinkFrom->Direction == EGPD_Output);
|
|
InputConnection.From = LinkFrom;
|
|
}
|
|
else
|
|
{
|
|
//This input has no link so we need the default value from the pin.
|
|
InputConnection.FallbackDefault = FuncCallInputPin->GetDefaultAsString();
|
|
}
|
|
}
|
|
//Get all the pins that are connected to the outputs of the function call node in the main graph.
|
|
FunctionNode->GetOutputPins(FuncCallOutputPins);
|
|
for (UEdGraphPin* FuncCallOutputPin : FuncCallOutputPins)
|
|
{
|
|
FName OutputName(*FuncCallOutputPin->PinName);
|
|
for (UEdGraphPin* LinkTo : FuncCallOutputPin->LinkedTo)
|
|
{
|
|
if (LinkTo)
|
|
{
|
|
check(LinkTo->Direction == EGPD_Input);
|
|
FReconnectionInfo& OutputConnection = OutputConnections.FindOrAdd(OutputName);
|
|
OutputConnection.To.Add(LinkTo);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Remove the function call node from the graph now that we have everything we need from it.
|
|
SourceGraph->RemoveNode(FunctionNode);
|
|
UNiagaraNodeOutput* SourceGraphOuputNode = SourceGraph->FindOutputNode();
|
|
check(SourceGraphOuputNode);
|
|
|
|
//Keep a list of the Input and Output nodes we see in the function graph so that we can remove (most of) them later.
|
|
TArray<UEdGraphNode*, TInlineAllocator<64>> ToRemove;
|
|
|
|
//For each input node in the function graph, get all the LinkTo connections for reconnecting to the main graph later.
|
|
TArray <UNiagaraNodeInput*> FuncGraphInputNodes;
|
|
FuncGraph->FindInputNodes(FuncGraphInputNodes);
|
|
for (UNiagaraNodeInput* FuncGraphInputNode : FuncGraphInputNodes)
|
|
{
|
|
check(FuncGraphInputNode && FuncGraphInputNode->Pins.Num() == 1);
|
|
//Get an array of "To" pins from one or more input nodes referencing each named input.
|
|
FReconnectionInfo& InputConnection = InputConnections.FindOrAdd(FuncGraphInputNode->Input.Name);
|
|
if (InputConnection.From)
|
|
{
|
|
//We have a connection from the function call so remove the input node and connect to that.
|
|
ToRemove.Add(FuncGraphInputNode);
|
|
}
|
|
else
|
|
{
|
|
//This input has no connection from the function call so what do we do here?
|
|
//For now we just leave the input node and connect back to it.
|
|
//This will mean unconnected pins from the function call will look for constants or attributes.
|
|
//In some cases we may want to just take the default value from the function call pin instead?
|
|
//Maybe have some properties on the function call defining that.
|
|
InputConnection.From = FuncGraphInputNode->Pins[0];
|
|
}
|
|
|
|
TArray<UEdGraphPin*>& LinkToPins = FuncGraphInputNode->Pins[0]->LinkedTo;
|
|
for (UEdGraphPin* ToPin : LinkToPins)
|
|
{
|
|
check(ToPin->Direction == EGPD_Input);
|
|
UEdGraphNode* OwningNode = ToPin->GetOwningNode();
|
|
if (!OwningNode->IsA(UNiagaraNodeOutput::StaticClass()))
|
|
{
|
|
//As long as the owning node will survive into the source graph, connect directly to it.
|
|
//Otherwise, we handle the connection in the OutputConnections.
|
|
InputConnection.To.Add(ToPin);
|
|
}
|
|
}
|
|
}
|
|
|
|
//For each output of the output node in the function graph, get the "From" pin to be reconnected later.
|
|
{
|
|
UNiagaraNodeOutput* FuncGraphOutputNode = FuncGraph->FindOutputNode();
|
|
check(FuncGraphOutputNode);
|
|
|
|
//Unlike the input nodes, we don't have the option of keeping these if there is no "From" pin. The default values from the node pins should be used.
|
|
ToRemove.Add(FuncGraphOutputNode);
|
|
|
|
for (int32 OutputIdx = 0; OutputIdx < FuncGraphOutputNode->Outputs.Num(); ++OutputIdx)
|
|
{
|
|
FName OutputName = FuncGraphOutputNode->Outputs[OutputIdx].Name;
|
|
|
|
UEdGraphPin* OutputNodePin = FuncGraphOutputNode->Pins[OutputIdx];
|
|
check(OutputNodePin->LinkedTo.Num() <= 1);
|
|
FReconnectionInfo& OutputConnection = OutputConnections.FindOrAdd(OutputName);
|
|
UEdGraphPin* LinkFromPin = OutputNodePin->LinkedTo.Num() == 1 ? OutputNodePin->LinkedTo[0] : NULL;
|
|
|
|
if (LinkFromPin)
|
|
{
|
|
UEdGraphNode* OwningNode = LinkFromPin->GetOwningNode();
|
|
if (UNiagaraNodeInput* InputNode = Cast<UNiagaraNodeInput>(OwningNode))
|
|
{
|
|
//We are connected directly to an input node so we must find the corresponding input connection and connect to that.
|
|
if (FReconnectionInfo* InputConnection = InputConnections.Find(InputNode->Input.Name))
|
|
{
|
|
LinkFromPin = InputConnection->From;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (LinkFromPin)
|
|
{
|
|
check(LinkFromPin->Direction == EGPD_Output);
|
|
OutputConnection.From = LinkFromPin;
|
|
}
|
|
else
|
|
{
|
|
//This output is not connected so links to it in the main graph must use it's default value.
|
|
OutputConnection.FallbackDefault = OutputNodePin->GetDefaultAsString();
|
|
}
|
|
}
|
|
}
|
|
|
|
//Remove all the In and Out nodes from the function graph.
|
|
for (UEdGraphNode* Remove : ToRemove)
|
|
{
|
|
FuncGraph->RemoveNode(Remove);
|
|
}
|
|
|
|
TArray<UEdGraphNode*> FuncNodes = FuncGraph->Nodes;
|
|
TArray<UEdGraphNode*> ExistingNodes = SourceGraph->Nodes;
|
|
//Copy the nodes from the function graph over into the main graph.
|
|
FuncGraph->MoveNodesToAnotherGraph(SourceGraph, false);
|
|
|
|
FIntPoint FuncNodePos(FunctionNode->NodePosX, FunctionNode->NodePosY);
|
|
FIntRect Bounds = FEdGraphUtilities::CalculateApproximateNodeBoundaries(FuncNodes);
|
|
FIntPoint Center;
|
|
FIntPoint Extents;
|
|
Bounds.GetCenterAndExtents(Center, Extents);
|
|
|
|
FIntPoint Offset = FuncNodePos - Center;
|
|
for (UEdGraphNode* FuncNode : FuncNodes)
|
|
{
|
|
FuncNode->NodePosX += Offset.X;
|
|
FuncNode->NodePosY += Offset.Y;
|
|
}
|
|
|
|
for (UEdGraphNode* Node : ExistingNodes)
|
|
{
|
|
if (Node->NodePosX < FuncNodePos.X)
|
|
{
|
|
Node->NodePosX -= Extents.X;
|
|
}
|
|
else
|
|
{
|
|
Node->NodePosX += Extents.X;
|
|
}
|
|
|
|
if (Node->NodePosY < FuncNodePos.Y)
|
|
{
|
|
Node->NodePosY -= Extents.Y;
|
|
}
|
|
else
|
|
{
|
|
Node->NodePosY += Extents.Y;
|
|
}
|
|
}
|
|
|
|
//Finally, do all the reconnection.
|
|
auto MakeConnection = [&](FReconnectionInfo& Info)
|
|
{
|
|
for (UEdGraphPin* LinkTo : Info.To)
|
|
{
|
|
if (Info.From)
|
|
{
|
|
Info.From->MakeLinkTo(LinkTo);
|
|
}
|
|
else
|
|
{
|
|
LinkTo->DefaultValue = Info.FallbackDefault;
|
|
}
|
|
}
|
|
};
|
|
for (TPair<FName, FReconnectionInfo>& ReconnectInfo : InputConnections){ MakeConnection(ReconnectInfo.Value); }
|
|
for (TPair<FName, FReconnectionInfo>& ReconnectInfo : OutputConnections){ MakeConnection(ReconnectInfo.Value); }
|
|
}
|
|
else
|
|
{
|
|
Error(LOCTEXT("MergeNullFunction", "Function call node must reference a valid script."), FunctionNode, NULL);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE |