示例#1
0
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 FNiagaraCompiler_VectorVM::TransformVector_Internal(TArray<TNiagaraExprPtr>& InputExpressions, TArray<TNiagaraExprPtr>& OutputExpressions)
{
	TNiagaraExprPtr MatrixExpr = InputExpressions[0];
	check(MatrixExpr->SourceExpressions.Num() == 4);
	TNiagaraExprPtr Row0 = MatrixExpr->GetSourceExpression(0);
	TNiagaraExprPtr Row1 = MatrixExpr->GetSourceExpression(1);
	TNiagaraExprPtr Row2 = MatrixExpr->GetSourceExpression(2);
	TNiagaraExprPtr Row3 = MatrixExpr->GetSourceExpression(3);

	TNiagaraExprPtr VectorExpr = InputExpressions[1];

	TArray<TNiagaraExprPtr> Temp;
	Temp.Add(Expression_VMNative(VectorVM::EOp::splatx, VectorExpr));
	Temp.Add(Expression_VMNative(VectorVM::EOp::splaty, VectorExpr));
	Temp.Add(Expression_VMNative(VectorVM::EOp::splatz, VectorExpr));
	Temp.Add(Expression_VMNative(VectorVM::EOp::splatw, VectorExpr));

	Temp[0] = Expression_VMNative(VectorVM::EOp::mul, MatrixExpr->GetSourceExpression(0), Temp[0]);
	Temp[1] = Expression_VMNative(VectorVM::EOp::mul, MatrixExpr->GetSourceExpression(1), Temp[1]);
	Temp[2] = Expression_VMNative(VectorVM::EOp::mul, MatrixExpr->GetSourceExpression(2), Temp[2]);
	Temp[3] = Expression_VMNative(VectorVM::EOp::mul, MatrixExpr->GetSourceExpression(3), Temp[3]);

	Temp[0] = Expression_VMNative(VectorVM::EOp::add, Temp[0], Temp[1]);
	Temp[1] = Expression_VMNative(VectorVM::EOp::add, Temp[2], Temp[3]);
	OutputExpressions.Add(Expression_VMNative(VectorVM::EOp::add, Temp[0], Temp[1]));
}
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::Transpose_Internal(TArray<TNiagaraExprPtr>& InputExpressions, TArray<TNiagaraExprPtr>& OutputExpressions)
{
	TNiagaraExprPtr MatrixExpr = InputExpressions[0];
	check(MatrixExpr->SourceExpressions.Num() == 4);
	TNiagaraExprPtr Row0 = MatrixExpr->GetSourceExpression(0);
	TNiagaraExprPtr Row1 = MatrixExpr->GetSourceExpression(1);
	TNiagaraExprPtr Row2 = MatrixExpr->GetSourceExpression(2);
	TNiagaraExprPtr Row3 = MatrixExpr->GetSourceExpression(3);

	//TODO: can probably make this faster if I provide direct shuffle ops in the VM rather than using the flexible, catch-all op compose.
	//Maybe don't want to make that externally usable though? Maybe for power users...
	TArray<TNiagaraExprPtr> Columns;
	Columns.Add(Expression_VMNative(VectorVM::EOp::composex, Row0, Row1, Row2, Row3));
	Columns.Add(Expression_VMNative(VectorVM::EOp::composey, Row0, Row1, Row2, Row3));
	Columns.Add(Expression_VMNative(VectorVM::EOp::composez, Row0, Row1, Row2, Row3));
	Columns.Add(Expression_VMNative(VectorVM::EOp::composew, Row0, Row1, Row2, Row3));

	Matrix_Internal(Columns, OutputExpressions);
}
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 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;
}