void UNiagaraNodeWriteDataSet::Compile(class INiagaraCompiler* Compiler, TArray<FNiagaraNodeResult>& Outputs) { bool bError = false; if (DataSet.Type == ENiagaraDataSetType::Event) { //Compile the Emit pin. TNiagaraExprPtr EmitExpression = Compiler->CompilePin(Pins[0]); if (EmitExpression.IsValid()) { //Test the Valid pin result against 0. Maybe just require a direct connection of 0 or 0xFFFFFFFF? FNiagaraVariableInfo Zero(TEXT("0.0, 0.0, 0.0, 0.0"), ENiagaraDataType::Vector); TNiagaraExprPtr ZeroContantExpression = Compiler->GetInternalConstant(Zero, FVector4(0.0f, 0.0f, 0.0f, 0.0f)); TArray<TNiagaraExprPtr> ConditonInputs; ConditonInputs.Add(EmitExpression); ConditonInputs.Add(ZeroContantExpression); check(ZeroContantExpression.IsValid()); TArray<TNiagaraExprPtr> ConditionOpOutputs; INiagaraCompiler::GreaterThan(Compiler, ConditonInputs, ConditionOpOutputs); TNiagaraExprPtr ValidExpr = ConditionOpOutputs[0]; TArray<TNiagaraExprPtr> InputExpressions; for (int32 i = 0; i < Variables.Num(); ++i) { const FNiagaraVariableInfo& Var = Variables[i]; UEdGraphPin* Pin = Pins[i + 1];//Pin[0] is emit check(Pin->Direction == EGPD_Input); TNiagaraExprPtr Result = Compiler->CompilePin(Pin); if (!Result.IsValid()) { bError = true; Compiler->Error(FText::Format(LOCTEXT("DataSetWriteErrorFormat", "Error writing variable {0} to dataset {1}"), FText::FromName(DataSet.Name), Pin->PinFriendlyName), this, Pin); } InputExpressions.Add(Result); } //Gets the index to write to. TNiagaraExprPtr IndexExpression = Compiler->AcquireSharedDataIndex(DataSet, true, ValidExpr); if (!bError) { check(Variables.Num() == InputExpressions.Num()); for (int32 i = 0; i < Variables.Num(); ++i) { Outputs.Add(FNiagaraNodeResult(Compiler->SharedDataWrite(DataSet, Variables[i], IndexExpression, InputExpressions[i]), Pins[i + 1]));//Pin[0] is Emit } } } } else { check(false);//IMPLEMENT OTHER DATA SETS. } }
void UNiagaraNodeOutput::Compile(class INiagaraCompiler* Compiler, TArray<FNiagaraNodeResult>& OutputExpressions) { TArray<TNiagaraExprPtr> InputExpressions; for (int32 i = 0; i < Outputs.Num(); ++i) { const FNiagaraVariableInfo& Out = Outputs[i]; UEdGraphPin* Pin = Pins[i]; check(Pin->Direction == EGPD_Input); TNiagaraExprPtr Result = Compiler->CompilePin(Pin); if (!Result.IsValid()) { //The pin was not connected so pass through the initial value of the attribute. Result = Compiler->GetAttribute(Out); } InputExpressions.Add(Result); } check(Outputs.Num() == InputExpressions.Num()); for (int32 i = 0; i < Outputs.Num(); ++i) { OutputExpressions.Add(FNiagaraNodeResult(Compiler->Output(Outputs[i], InputExpressions[i]), Pins[i])); } }
void UNiagaraNodeOp::Compile(class INiagaraCompiler* Compiler, TArray<FNiagaraNodeResult>& Outputs) { const FNiagaraOpInfo* OpInfo = FNiagaraOpInfo::GetOpInfo(OpName); check(OpInfo); int32 NumInputs = OpInfo->Inputs.Num(); int32 NumOutputs = OpInfo->Outputs.Num(); TArray<TNiagaraExprPtr> Inputs; bool bError = false; for (int32 i = 0; i < NumInputs; ++i) { UEdGraphPin *Pin = Pins[i]; check(Pin->Direction == EGPD_Input); TNiagaraExprPtr InputExpr = Compiler->CompilePin(Pin); if (!InputExpr.IsValid()) { bError = true; FFormatNamedArguments Args; Args.Add(TEXT("OpName"), GetNodeTitle(ENodeTitleType::FullTitle)); FText Format = LOCTEXT("InputErrorFormat", "Error compiling input on {OpName} node."); Compiler->Error(FText::Format(Format, Args), this, Pin); } Inputs.Add(InputExpr); } TArray<TNiagaraExprPtr> OutputExpressions; if ( !bError && OpInfo->OpDelegate.Execute(Compiler, Inputs, OutputExpressions)) { check(OutputExpressions.Num() == OpInfo->Outputs.Num()); for (int32 i = 0; i < NumOutputs; ++i) { UEdGraphPin *Pin = Pins[NumInputs + i]; check(Pin->Direction == EGPD_Output); Outputs.Add(FNiagaraNodeResult(OutputExpressions[i], Pin)); } } else { FFormatNamedArguments Args; Args.Add(TEXT("OpName"), GetNodeTitle(ENodeTitleType::FullTitle)); FText Format = LOCTEXT("NodeErrorFormat", "Error compiling {OpName} node."); Compiler->Error(FText::Format(Format, Args), this, nullptr); } }
void FNiagaraCompiler_VectorVM::CompileScript(UNiagaraScript* InScript) { //TODO - Most of this function can be refactored up into FNiagaraCompiler once we know how the compute script and VM script will coexist in the UNiagaraScript. check(InScript); Script = InScript; Source = CastChecked<UNiagaraScriptSource>(InScript->Source); //Should we roll our own message/error log and put it in a window somewhere? MessageLog.SetSourceName(InScript->GetPathName()); // Clone the source graph so we can modify it as needed; merging in the child graphs SourceGraph = CastChecked<UNiagaraGraph>(FEdGraphUtilities::CloneGraph(Source->NodeGraph, NULL, &MessageLog)); FEdGraphUtilities::MergeChildrenGraphsIn(SourceGraph, SourceGraph, /*bRequireSchemaMatch=*/ true); if (!MergeInFunctionNodes()) { //TODO: Insert a good error reporting and compile failure system. InScript->Attributes.Empty(); InScript->ByteCode.Empty(); InScript->ConstantData.Empty(); return; } TempRegisters.AddZeroed(VectorVM::NumTempRegisters); // Find the output node. UNiagaraNodeOutput* OutputNode = SourceGraph->FindOutputNode(); TArray<FNiagaraNodeResult> OutputExpressions; OutputNode->Compile(this, OutputExpressions); //Todo - track usage of temp registers so we can allocate and free and reuse from a smaller set. int32 NextTempRegister = 0; Script->ByteCode.Empty(); //Now we have a set of expressions from which we can generate the bytecode. for (int32 i = 0; i < Expressions.Num() ; ++i) { TNiagaraExprPtr Expr = Expressions[i]; if (Expr.IsValid()) { Expr->Process(); Expr->PostProcess(); } else { check(0);//Replace with graceful bailout? } Expressions[i].Reset(); } PinToExpression.Empty();//TODO - Replace this with expression caching at a lower level. Will be more useful and nicer. // Terminate with the 'done' opcode. Script->ByteCode.Add((int8)VectorVM::EOp::done); Script->ConstantData = ConstantData; Script->Attributes = OutputNode->Outputs; }