CelticCraft/Plugins/VoxelFree/Source/VoxelGraph/Private/VoxelGraphGenerator.cpp

306 lines
No EOL
8.8 KiB
C++

// Copyright 2020 Phyronnaz
#include "VoxelGraphGenerator.h"
#include "IVoxelGraphEditor.h"
#include "VoxelGraphGlobals.h"
#include "VoxelGraphOutputs.h"
#include "VoxelGraphOutputsConfig.h"
#include "VoxelGraphConstants.h"
#include "VoxelGraphErrorReporter.h"
#include "VoxelNodes/VoxelExecNodes.h"
#include "VoxelNodes/VoxelSeedNodes.h"
#include "VoxelMessages.h"
#include "VoxelNode.h"
#include "VoxelGenerators/VoxelEmptyGenerator.h"
#include "VoxelGenerators/VoxelGeneratorParameters.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphSchema.h"
#include "Engine/Texture2D.h"
#include "Misc/ScopeExit.h"
#include "Misc/MessageDialog.h"
#define VOXEL_GRAPH_THUMBNAIL_RES 128
#if WITH_EDITOR
void IVoxelGraphEditor::SetVoxelGraphEditor(TSharedPtr<IVoxelGraphEditor> InVoxelGraphEditor)
{
ensure(!VoxelGraphEditor.IsValid());
VoxelGraphEditor = InVoxelGraphEditor;
}
TSharedPtr<IVoxelGraphEditor> IVoxelGraphEditor::VoxelGraphEditor = nullptr;
#endif
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
TMap<uint32, FVoxelGraphOutput> UVoxelGraphGenerator::GetOutputs() const
{
TMap<uint32, FVoxelGraphOutput> Result;
for (int32 Index = 0; Index < FVoxelGraphOutput::DefaultOutputs.Num(); Index++)
{
Result.Add(Index, FVoxelGraphOutput::DefaultOutputs[Index]);
}
if (Outputs)
{
const auto& AdditionalOutputs = Outputs->Outputs;
for (int32 Index = 0; Index < AdditionalOutputs.Num(); Index++)
{
Result.Add(FVoxelGraphOutputsIndices::DefaultOutputsMax + Index, AdditionalOutputs[Index]);
}
}
for (auto& It : Result)
{
It.Value.Index = It.Key;
}
return Result;
}
TArray<FVoxelGraphPermutationArray> UVoxelGraphGenerator::GetPermutations() const
{
TArray<FVoxelGraphPermutationArray> Result;
Result.Append(FVoxelGraphOutput::DefaultOutputsPermutations);
if (Outputs)
{
const auto& GraphOutputs = Outputs->Outputs;
for (int32 Index = 0; Index < GraphOutputs.Num(); Index++)
{
FVoxelGraphPermutationArray NewElement;
NewElement.Add(FVoxelGraphOutputsIndices::DefaultOutputsMax + Index);
Result.Add(NewElement);
if (GraphOutputs[Index].Category == EVoxelDataPinCategory::Float)
{
FVoxelGraphPermutationArray NewRangeElement;
NewRangeElement.Add(FVoxelGraphOutputsIndices::DefaultOutputsMax + Index);
NewRangeElement.Add(FVoxelGraphOutputsIndices::RangeAnalysisIndex);
Result.Add(NewRangeElement);
}
}
}
return Result;
}
/////////////////////////////////////////////////////////////////////////////////
#if WITH_EDITORONLY_DATA
UTexture2D* UVoxelGraphGenerator::GetPreviewTexture()
{
if (!PreviewTexture)
{
PreviewTexture = UTexture2D::CreateTransient(VOXEL_GRAPH_THUMBNAIL_RES, VOXEL_GRAPH_THUMBNAIL_RES);
PreviewTexture->CompressionSettings = TC_HDR;
PreviewTexture->SRGB = false;
PreviewTextureSave.SetNumZeroed(VOXEL_GRAPH_THUMBNAIL_RES * VOXEL_GRAPH_THUMBNAIL_RES);
FTexture2DMipMap& Mip = PreviewTexture->GetPlatformData()->Mips[0];
void* Data = Mip.BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(Data, PreviewTextureSave.GetData(), PreviewTextureSave.Num() * sizeof(FColor));
Mip.BulkData.Unlock();
PreviewTexture->UpdateResource();
}
return PreviewTexture;
}
void UVoxelGraphGenerator::SetPreviewTexture(const TArray<FColor>& Colors, int32 Size)
{
// Do not save thumbnails in the free version, as they can't be right since we can't run graphs
}
#endif
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
void UVoxelGraphGenerator::ApplyParameters(const TMap<FName, FString>& Parameters)
{
for (UVoxelNode* Node : AllNodes)
{
Node->ApplyParameters(Parameters);
}
}
void UVoxelGraphGenerator::GetParameters(TArray<FVoxelGeneratorParameter>& OutParameters) const
{
for (UVoxelNode* Node : AllNodes)
{
Node->GetParameters(OutParameters);
}
TMap<FName, FVoxelGeneratorParameter> NamesToParameters;
for (auto& Parameter : OutParameters)
{
auto* ExistingParameter = NamesToParameters.Find(Parameter.Id);
if (!ExistingParameter)
{
NamesToParameters.Add(Parameter.Id, Parameter);
continue;
}
if (ExistingParameter->Name != Parameter.Name)
{
FVoxelMessages::Error(FString::Printf(
TEXT("Parameters with same Unique Name but different Display Name: %s vs %s for %s"),
*Parameter.Name,
*ExistingParameter->Name,
*Parameter.Id.ToString()));
}
if (ExistingParameter->Type != Parameter.Type)
{
FVoxelMessages::Error(FString::Printf(
TEXT("Parameters with same Unique Name but different type: %s vs %s for %s"),
*Parameter.Type.ToString(),
*ExistingParameter->Type.ToString(),
*Parameter.Id.ToString()));
}
}
}
TVoxelSharedRef<FVoxelTransformableGeneratorInstance> UVoxelGraphGenerator::GetTransformableInstance()
{
return GetTransformableInstance({});
}
TVoxelSharedRef<FVoxelTransformableGeneratorInstance> UVoxelGraphGenerator::GetTransformableInstance(const TMap<FName, FString>& Parameters)
{
FVoxelMessages::Info("Running Voxel Graphs require Voxel Plugin Pro");
return MakeVoxelShared<FVoxelTransformableEmptyGeneratorInstance>();
}
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
#if WITH_EDITOR
void UVoxelGraphGenerator::PostInitProperties()
{
Super::PostInitProperties();
if (!HasAnyFlags(RF_ClassDefaultObject | RF_NeedLoad))
{
CreateGraphs();
}
}
void UVoxelGraphGenerator::PostLoad()
{
Super::PostLoad();
CreateGraphs();
BindUpdateSetterNodes();
}
void UVoxelGraphGenerator::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
if (PropertyChangedEvent.MemberProperty && PropertyChangedEvent.ChangeType != EPropertyChangeType::Interactive)
{
if (PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_STATIC(UVoxelGraphGenerator, SaveLocation))
{
if (!SaveLocation.FilePath.IsEmpty())
{
SaveLocation.FilePath = FPaths::ConvertRelativePathToFull(SaveLocation.FilePath);
FPaths::MakePathRelativeTo(SaveLocation.FilePath, *FPaths::ProjectDir());
}
}
if (PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_STATIC(UVoxelGraphGenerator, Outputs))
{
BindUpdateSetterNodes();
UpdateSetterNodes();
}
}
}
/////////////////////////////////////////////////////////////////////////////////
UVoxelNode* UVoxelGraphGenerator::ConstructNewNode(UClass* NewNodeClass, const FVector2D& Position, bool bSelectNewNode)
{
Modify();
VoxelGraph->Modify();
UVoxelNode* VoxelNode = NewObject<UVoxelNode>(this, NewNodeClass, NAME_None, RF_Transactional);
AllNodes.Add(VoxelNode); // To have valid list even without compiling
MarkPackageDirty();
#if WITH_EDITOR
VoxelNode->Graph = this;
// Create the graph node
check(!VoxelNode->GraphNode);
IVoxelGraphEditor::GetVoxelGraphEditor()->CreateVoxelGraphNode(VoxelGraph, VoxelNode, bSelectNewNode);
VoxelNode->GraphNode->NodePosX = Position.X;
VoxelNode->GraphNode->NodePosY = Position.Y;
#endif // WITH_EDITOR
return VoxelNode;
}
void UVoxelGraphGenerator::CreateGraphs()
{
if (auto* VoxelGraphEditor = IVoxelGraphEditor::GetVoxelGraphEditor())
{
if (!VoxelGraph)
{
VoxelGraph = VoxelGraphEditor->CreateNewVoxelGraph(this);
VoxelGraph->bAllowDeletion = false;
// Give the schema a chance to fill out any required nodes (like the results node)
const UEdGraphSchema* Schema = VoxelGraph->GetSchema();
Schema->CreateDefaultNodesForGraph(*VoxelGraph);
}
if (!VoxelDebugGraph)
{
VoxelDebugGraph = VoxelGraphEditor->CreateNewVoxelGraph(this);
VoxelDebugGraph->bAllowDeletion = false;
}
}
}
void UVoxelGraphGenerator::CompileVoxelNodesFromGraphNodes()
{
if (!ensure(this))
{
return;
}
if (auto* VoxelGraphEditor = IVoxelGraphEditor::GetVoxelGraphEditor())
{
VoxelGraphEditor->CompileVoxelNodesFromGraphNodes(this);
}
}
void UVoxelGraphGenerator::UpdateSetterNodes()
{
for (auto& Node : AllNodes)
{
if (IsValid(Node))
{
if (auto* SetNode = Cast<UVoxelNode_SetNode>(Node))
{
SetNode->UpdateSetterNode();
}
}
}
}
void UVoxelGraphGenerator::BindUpdateSetterNodes()
{
if (Outputs && !Outputs->OnPropertyChanged.IsBoundToObject(this))
{
Outputs->OnPropertyChanged.AddUObject(this, &UVoxelGraphGenerator::UpdateSetterNodes);
}
}
#endif