// Copyright 2020 Phyronnaz #include "VoxelGenerators/VoxelGeneratorTools.h" #include "VoxelGenerators/VoxelGenerator.h" #include "VoxelGenerators/VoxelGeneratorInstance.h" #include "VoxelGenerators/VoxelGeneratorParameters.h" #include "VoxelGenerators/VoxelGeneratorInstanceWrapper.h" #include "VoxelTools/VoxelToolHelpers.h" #include "VoxelMessages.h" #include "VoxelUtilities/VoxelGeneratorUtilities.h" #include "UObject/PropertyPortFlags.h" UVoxelGeneratorInstanceWrapper* UVoxelGeneratorTools::MakeGeneratorInstance(FVoxelGeneratorPicker GeneratorPicker, FVoxelGeneratorInit GeneratorInit) { if (!GeneratorPicker.IsValid()) { FVoxelMessages::Error(FUNCTION_ERROR("Invalid generator")); return nullptr; } auto* Instance = NewObject(); Instance->Instance = GeneratorPicker.GetInstance(true); Instance->Instance->Init(GeneratorInit); return Instance; } UVoxelTransformableGeneratorInstanceWrapper* UVoxelGeneratorTools::MakeTransformableGeneratorInstance(FVoxelTransformableGeneratorPicker GeneratorPicker, FVoxelGeneratorInit GeneratorInit) { if (!GeneratorPicker.IsValid()) { FVoxelMessages::Error(FUNCTION_ERROR("Invalid generator")); return nullptr; } auto* Instance = NewObject(); Instance->Instance = GeneratorPicker.GetInstance(true); Instance->Instance->Init(GeneratorInit); return Instance; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// bool UVoxelGeneratorTools::SetGeneratorParameterImpl(TVoxelGeneratorPicker& Picker, FName Name, FProperty& Property, void* Data, const FString& FunctionName) { if (!CheckIsValidParameterName(Picker, Name, Property, FunctionName)) { return false; } FString Result; Property.ExportTextItem(Result, Data, nullptr, nullptr, PPF_None); Picker.Parameters.Add(Name, Result); return true; } bool UVoxelGeneratorTools::CheckIsValidParameterName( TVoxelGeneratorPicker GeneratorPicker, FName Name, FProperty& Property, const FString& FunctionName) { if (!GeneratorPicker.IsValid()) { FVoxelMessages::Error(FUNCTION_ERROR_IMPL(FunctionName, "Invalid generator")); return false; } TArray Parameters; GeneratorPicker.GetGenerator()->GetParameters(Parameters); const FVoxelGeneratorParameterType Type(Property); for (auto& It : Parameters) { if (It.Id == Name) { if (It.Type.CanBeAssignedFrom(Type)) { return true; } else { FVoxelMessages::Error(FUNCTION_ERROR_IMPL(FunctionName, FString::Printf( TEXT("Incompatible parameter type: cannot cast from %s to %s"), *Type.ToString(), *It.Type.ToString()))); return false; } } } FVoxelMessages::Error(FUNCTION_ERROR_IMPL(FunctionName, FString::Printf(TEXT( "Parameter name not found: %s. Make sure you use the parameter unique name and not its display name. " "You can find the unique name in the parameter tooltip in the Generator details."), *Name.ToString()))); return false; } bool UVoxelGeneratorTools::SetGeneratorParameter(const FVoxelGeneratorPicker& Picker, FName UniqueName, int32 Value) { checkf(false, TEXT("SetGeneratorParameter can only be called from blueprints")); return false; } bool UVoxelGeneratorTools::SetTransformableGeneratorParameter(const FVoxelTransformableGeneratorPicker& Picker, FName UniqueName, int32 Value) { checkf(false, TEXT("SetTransformableGeneratorParameter can only be called from blueprints")); return false; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// template TVoxelTexture UVoxelGeneratorTools::CreateTextureFromGeneratorImpl( const FVoxelGeneratorInstance& Generator, FName OutputName, const FIntPoint& Start, const FIntPoint& Size, float Scale) { VOXEL_TOOL_FUNCTION_COUNTER(Size.X * Size.Y); check(Size.X > 0 && Size.Y > 0); using TGeneratorType = typename TChooseClass::Value, v_flt, T>::Result; const auto FunctionPtr = Generator.GetOutputsPtrMap().FindRef(OutputName); if (!ensure(FunctionPtr)) return {}; const auto Texture = MakeVoxelShared::FTextureData>(); Texture->SetSize(Size.X, Size.Y); for (int32 X = 0; X < Size.X; X++) { for (int32 Y = 0; Y < Size.Y; Y++) { const auto Value = (Generator.*FunctionPtr)(Scale * (Start.X + X), Scale * (Start.Y + Y), 0, 0, FVoxelItemStack::Empty); Texture->SetValue(X, Y, T(Value)); } } return TVoxelTexture(Texture); } template VOXEL_API TVoxelTexture UVoxelGeneratorTools::CreateTextureFromGeneratorImpl( const FVoxelGeneratorInstance& Generator, FName OutputName, const FIntPoint& Start, const FIntPoint& Size, float Scale); template VOXEL_API TVoxelTexture UVoxelGeneratorTools::CreateTextureFromGeneratorImpl( const FVoxelGeneratorInstance& Generator, FName OutputName, const FIntPoint& Start, const FIntPoint& Size, float Scale); /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// template TVoxelSharedPtr SetupGenerator( const FString& FunctionName, UVoxelGeneratorInstanceWrapper* Generator, FName OutputName, int32 SizeX, int32 SizeY) { VOXEL_FUNCTION_COUNTER(); if (!Generator || !Generator->IsValid()) { FVoxelMessages::Error( FUNCTION_ERROR_IMPL(FunctionName, "Invalid Generator!")); return {}; } if (SizeX <= 0 || SizeY <= 0) { FVoxelMessages::Error( FUNCTION_ERROR_IMPL(FunctionName, "Invalid Size!")); return {}; } using TGeneratorType = typename TChooseClass::Value, v_flt, T>::Result; if (!Generator->Instance->GetOutputsPtrMap().Contains(OutputName)) { FVoxelMessages::Error(FUNCTION_ERROR_IMPL(FunctionName, FVoxelUtilities::GetMissingGeneratorOutputErrorString(OutputName, *Generator->Instance))); return {}; } return Generator->Instance; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void UVoxelGeneratorTools::CreateFloatTextureFromGenerator( FVoxelFloatTexture& OutTexture, UVoxelGeneratorInstanceWrapper* Generator, FName OutputName, int32 SizeX, int32 SizeY, float Scale, int32 StartX, int32 StartY) { VOXEL_FUNCTION_COUNTER(); const auto Instance = SetupGenerator(__FUNCTION__, Generator, OutputName, SizeX, SizeY); if (!Instance) return; OutTexture.Texture = CreateTextureFromGeneratorImpl(*Instance, OutputName, FIntPoint(StartX, StartY), FIntPoint(SizeX, SizeY), Scale); } void UVoxelGeneratorTools::CreateFloatTextureFromGeneratorAsync( UObject* WorldContextObject, FLatentActionInfo LatentInfo, FVoxelFloatTexture& OutTexture, UVoxelGeneratorInstanceWrapper* Generator, FName OutputName, int32 SizeX, int32 SizeY, float Scale, int32 StartX, int32 StartY, bool bHideLatentWarnings) { VOXEL_FUNCTION_COUNTER(); const auto Instance = SetupGenerator(__FUNCTION__, Generator, OutputName, SizeX, SizeY); if (!Instance) return; FVoxelToolHelpers::StartAsyncLatentAction_WithoutWorld_WithValue( WorldContextObject, LatentInfo, __FUNCTION__, bHideLatentWarnings, OutTexture, [=](FVoxelFloatTexture& Texture) { Texture.Texture = CreateTextureFromGeneratorImpl(*Instance, OutputName, FIntPoint(StartX, StartY), FIntPoint(SizeX, SizeY), Scale); }); } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void UVoxelGeneratorTools::CreateColorTextureFromGenerator( FVoxelColorTexture& OutTexture, UVoxelGeneratorInstanceWrapper* Generator, FName OutputName, int32 SizeX, int32 SizeY, float Scale, int32 StartX, int32 StartY) { VOXEL_FUNCTION_COUNTER(); const auto Instance = SetupGenerator(__FUNCTION__, Generator, OutputName, SizeX, SizeY); if (!Instance) return; OutTexture.Texture = CreateTextureFromGeneratorImpl(*Instance, OutputName, FIntPoint(StartX, StartY), FIntPoint(SizeX, SizeY), Scale); } void UVoxelGeneratorTools::CreateColorTextureFromGeneratorAsync( UObject* WorldContextObject, FLatentActionInfo LatentInfo, FVoxelColorTexture& OutTexture, UVoxelGeneratorInstanceWrapper* Generator, FName OutputName, int32 SizeX, int32 SizeY, float Scale, int32 StartX, int32 StartY, bool bHideLatentWarnings) { VOXEL_FUNCTION_COUNTER(); const auto Instance = SetupGenerator(__FUNCTION__, Generator, OutputName, SizeX, SizeY); if (!Instance) return; FVoxelToolHelpers::StartAsyncLatentAction_WithoutWorld_WithValue( WorldContextObject, LatentInfo, __FUNCTION__, bHideLatentWarnings, OutTexture, [=](FVoxelColorTexture& Texture) { Texture.Texture = CreateTextureFromGeneratorImpl(*Instance, OutputName, FIntPoint(StartX, StartY), FIntPoint(SizeX, SizeY), Scale); }); }