1080 lines
45 KiB
C++
1080 lines
45 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "LandscapeEditorObject.h"
|
|
#include "LandscapeDataAccess.h"
|
|
#include "Engine/Texture2D.h"
|
|
#include "HAL/FileManager.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "UObject/ConstructorHelpers.h"
|
|
#include "LandscapeEditorModule.h"
|
|
#include "LandscapeEditorPrivate.h"
|
|
#include "LandscapeRender.h"
|
|
#include "LandscapeSettings.h"
|
|
#include "LandscapeImportHelper.h"
|
|
#include "LandscapeTiledImage.h"
|
|
#include "LandscapeMaterialInstanceConstant.h"
|
|
#include "LandscapeUtils.h"
|
|
#include "LandscapeEditorUtils.h"
|
|
#include "Misc/ConfigCacheIni.h"
|
|
#include "EngineUtils.h"
|
|
#include "RenderUtils.h"
|
|
#include "Misc/MessageDialog.h"
|
|
#include "AssetRegistry/AssetRegistryModule.h"
|
|
|
|
static TAutoConsoleVariable<bool> CVarLandscapeSimulateAlphaBrushTextureLoadFailure(
|
|
TEXT("landscape.SimulateAlphaBrushTextureLoadFailure"),
|
|
false,
|
|
TEXT("Debug utility to simulate a loading failure (e.g. invalid source data, which can happen in cooked editor or with a badly virtualized texture) when loading the alpha brush texture"));
|
|
|
|
const FVector ULandscapeEditorObject::NewLandscape_DefaultLocation = FVector(0, 0, 0);
|
|
const FRotator ULandscapeEditorObject::NewLandscape_DefaultRotation = FRotator::ZeroRotator;
|
|
const FVector ULandscapeEditorObject::NewLandscape_DefaultScale = FVector(100, 100, 100);
|
|
|
|
ULandscapeEditorObject::ULandscapeEditorObject(const FObjectInitializer& ObjectInitializer)
|
|
: Super(ObjectInitializer)
|
|
|
|
// Tool Settings:
|
|
, ToolStrength(0.3f)
|
|
, PaintToolStrength(0.3f)
|
|
, bUseWeightTargetValue(false)
|
|
, WeightTargetValue(1.0f)
|
|
, MaximumValueRadius(10000.0f)
|
|
, bCombinedLayersOperation(true)
|
|
|
|
, FlattenMode(ELandscapeToolFlattenMode::Both)
|
|
, bUseSlopeFlatten(false)
|
|
, bPickValuePerApply(false)
|
|
, bUseFlattenTarget(false)
|
|
, FlattenTarget(0)
|
|
, bShowFlattenTargetPreview(true)
|
|
|
|
, TerraceInterval(1.0f)
|
|
, TerraceSmooth(0.0001f)
|
|
|
|
, RampWidth(2000)
|
|
, RampSideFalloff(0.4f)
|
|
|
|
, SmoothFilterKernelSize(4)
|
|
, bDetailSmooth(false)
|
|
, DetailScale(0.3f)
|
|
|
|
, ErodeThresh(64)
|
|
, ErodeSurfaceThickness(256)
|
|
, ErodeIterationNum(28)
|
|
, ErosionNoiseMode(ELandscapeToolErosionMode::Lower)
|
|
, ErosionNoiseScale(60.0f)
|
|
, bErosionUseLayerHardness(false)
|
|
|
|
, RainAmount(128)
|
|
, SedimentCapacity(0.3f)
|
|
, HErodeIterationNum(75)
|
|
, RainDistMode(ELandscapeToolHydroErosionMode::Both)
|
|
, RainDistScale(60.0f)
|
|
, bHErosionDetailSmooth(true)
|
|
, HErosionDetailScale(0.01f)
|
|
|
|
, NoiseMode(ELandscapeToolNoiseMode::Both)
|
|
, NoiseScale(128.0f)
|
|
|
|
, bUseSelectedRegion(true)
|
|
, bUseNegativeMask(true)
|
|
|
|
, PasteMode(ELandscapeToolPasteMode::Both)
|
|
, bApplyToAllTargets(true)
|
|
, SnapMode(ELandscapeGizmoSnapType::None)
|
|
, bSmoothGizmoBrush(true)
|
|
|
|
, MirrorPoint(FVector::ZeroVector)
|
|
, MirrorOp(ELandscapeMirrorOperation::MinusXToPlusX)
|
|
|
|
, ResizeLandscape_QuadsPerSection(0)
|
|
, ResizeLandscape_SectionsPerComponent(0)
|
|
, ResizeLandscape_ComponentCount(0, 0)
|
|
, ResizeLandscape_ConvertMode(ELandscapeConvertMode::Expand)
|
|
|
|
, NewLandscape_Material(nullptr)
|
|
, NewLandscape_QuadsPerSection(63)
|
|
, NewLandscape_SectionsPerComponent(1)
|
|
, NewLandscape_ComponentCount(8, 8)
|
|
, NewLandscape_Location(NewLandscape_DefaultLocation)
|
|
, NewLandscape_Rotation(NewLandscape_DefaultRotation)
|
|
, NewLandscape_Scale(NewLandscape_DefaultScale)
|
|
, ImportLandscape_Width(0)
|
|
, ImportLandscape_Height(0)
|
|
, ImportLandscape_AlphamapType(ELandscapeImportAlphamapType::Additive)
|
|
|
|
// Brush Settings:
|
|
, BrushRadius(2048.0f)
|
|
, PaintBrushRadius(2048.0f)
|
|
, BrushFalloff(0.5f)
|
|
, PaintBrushFalloff(0.5f)
|
|
, bUseClayBrush(false)
|
|
, bApplyWithoutMovingSculpt(true)
|
|
, bApplyWithoutMovingPaint(false)
|
|
|
|
, AlphaBrushScale(0.5f)
|
|
, bAlphaBrushAutoRotate(true)
|
|
, AlphaBrushRotation(0.0f)
|
|
, AlphaBrushPanU(0.5f)
|
|
, AlphaBrushPanV(0.5f)
|
|
, bUseWorldSpacePatternBrush(false)
|
|
, WorldSpacePatternBrushSettings(FVector2D::ZeroVector, 0.0f, false, 3200)
|
|
, AlphaTexture(nullptr)
|
|
, AlphaTextureChannel(ELandscapeTextureColorChannel::Red)
|
|
, AlphaTextureSizeX(1)
|
|
, AlphaTextureSizeY(1)
|
|
|
|
, BrushComponentSize(1)
|
|
, TargetDisplayOrder(ELandscapeLayerDisplayMode::Default)
|
|
, ShowUnusedLayers(true)
|
|
{
|
|
// Structure to hold one-time initialization
|
|
struct FConstructorStatics
|
|
{
|
|
ConstructorHelpers::FObjectFinder<UTexture2D> AlphaTexture;
|
|
|
|
FConstructorStatics()
|
|
: AlphaTexture(TEXT("/Engine/EditorLandscapeResources/DefaultAlphaTexture"))
|
|
{
|
|
}
|
|
};
|
|
static FConstructorStatics ConstructorStatics;
|
|
|
|
SetAlphaTexture(ConstructorStatics.AlphaTexture.Object, AlphaTextureChannel);
|
|
}
|
|
|
|
void ULandscapeEditorObject::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
|
{
|
|
Super::PostEditChangeProperty(PropertyChangedEvent);
|
|
|
|
SetbUseSelectedRegion(bUseSelectedRegion);
|
|
SetbUseNegativeMask(bUseNegativeMask);
|
|
SetPasteMode(PasteMode);
|
|
SetGizmoSnapMode(SnapMode);
|
|
|
|
if (PropertyChangedEvent.MemberProperty == nullptr ||
|
|
PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ULandscapeEditorObject, AlphaTexture) ||
|
|
PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ULandscapeEditorObject, AlphaTextureChannel))
|
|
{
|
|
SetAlphaTexture(AlphaTexture, AlphaTextureChannel);
|
|
}
|
|
|
|
|
|
if (PropertyChangedEvent.MemberProperty == nullptr ||
|
|
PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ULandscapeEditorObject, NewLandscape_QuadsPerSection) ||
|
|
PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ULandscapeEditorObject, NewLandscape_SectionsPerComponent) ||
|
|
PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ULandscapeEditorObject, NewLandscape_ComponentCount))
|
|
{
|
|
// Only clamp the landscape size if we're not in World Partition
|
|
if (ParentMode && !ParentMode->IsGridBased())
|
|
{
|
|
NewLandscape_ClampSize();
|
|
}
|
|
}
|
|
|
|
if (PropertyChangedEvent.MemberProperty == nullptr ||
|
|
PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ULandscapeEditorObject, ResizeLandscape_QuadsPerSection) ||
|
|
PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ULandscapeEditorObject, ResizeLandscape_SectionsPerComponent) ||
|
|
PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ULandscapeEditorObject, ResizeLandscape_ConvertMode))
|
|
{
|
|
UpdateComponentCount();
|
|
}
|
|
|
|
if (PropertyChangedEvent.MemberProperty == nullptr ||
|
|
PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ULandscapeEditorObject, NewLandscape_Material) ||
|
|
PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ULandscapeEditorObject, ImportLandscape_HeightmapFilename) ||
|
|
PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ULandscapeEditorObject, ImportLandscape_Layers))
|
|
{
|
|
// In Import/Export tool we need to refresh from the existing material
|
|
const bool bRefreshFromTarget = ParentMode && ParentMode->CurrentTool && ParentMode->CurrentTool->GetToolName() == FName(TEXT("ImportExport"));
|
|
RefreshImportLayersList(bRefreshFromTarget);
|
|
}
|
|
|
|
if (PropertyChangedEvent.MemberProperty == nullptr ||
|
|
PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ULandscapeEditorObject, PaintingRestriction))
|
|
{
|
|
UpdateComponentLayerAllowList();
|
|
}
|
|
|
|
if (PropertyChangedEvent.MemberProperty == nullptr ||
|
|
PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ULandscapeEditorObject, TargetDisplayOrder))
|
|
{
|
|
UpdateTargetLayerDisplayOrder();
|
|
}
|
|
}
|
|
|
|
/** Load UI settings from ini file */
|
|
void ULandscapeEditorObject::Load()
|
|
{
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("ToolStrength"), ToolStrength, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("PaintToolStrength"), PaintToolStrength, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("WeightTargetValue"), WeightTargetValue, GEditorPerProjectIni);
|
|
bool InbUseWeightTargetValue = bUseWeightTargetValue;
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bUseWeightTargetValue"), InbUseWeightTargetValue, GEditorPerProjectIni);
|
|
bUseWeightTargetValue = InbUseWeightTargetValue;
|
|
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("BrushRadius"), BrushRadius, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("PaintBrushRadius"), PaintBrushRadius, GEditorPerProjectIni);
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("BrushComponentSize"), BrushComponentSize, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("BrushFalloff"), BrushFalloff, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("PaintBrushFalloff"), PaintBrushFalloff, GEditorPerProjectIni);
|
|
GConfig->GetString(TEXT("LandscapeEdit"), TEXT("TargetLayerAssetFilePath"), TargetLayerAssetFilePath.DirectoryPath.Path, GEditorPerProjectIni);
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bUseTargetLayerAssetFilePath"), TargetLayerAssetFilePath.bUseAssetDirectoryPath, GEditorPerProjectIni);
|
|
bool InbUseClayBrush = bUseClayBrush;
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bUseClayBrush"), InbUseClayBrush, GEditorPerProjectIni);
|
|
bUseClayBrush = InbUseClayBrush;
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("AlphaBrushScale"), AlphaBrushScale, GEditorPerProjectIni);
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("AlphaBrushAutoRotate"), bAlphaBrushAutoRotate, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("AlphaBrushRotation"), AlphaBrushRotation, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("AlphaBrushPanU"), AlphaBrushPanU, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("AlphaBrushPanV"), AlphaBrushPanV, GEditorPerProjectIni);
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bUseWorldSpacePatternBrush"), bUseWorldSpacePatternBrush, GEditorPerProjectIni);
|
|
GConfig->GetVector2D(TEXT("LandscapeEdit"), TEXT("WorldSpacePatternBrushSettings.Origin"), WorldSpacePatternBrushSettings.Origin, GEditorPerProjectIni);
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("WorldSpacePatternBrushSettings.bCenterTextureOnOrigin"), WorldSpacePatternBrushSettings.bCenterTextureOnOrigin, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("WorldSpacePatternBrushSettings.RepeatSize"), WorldSpacePatternBrushSettings.RepeatSize, GEditorPerProjectIni);
|
|
FString AlphaTextureName = (AlphaTexture != nullptr) ? AlphaTexture->GetPathName() : FString();
|
|
int32 InAlphaTextureChannel = static_cast<int32>(AlphaTextureChannel);
|
|
GConfig->GetString(TEXT("LandscapeEdit"), TEXT("AlphaTextureName"), AlphaTextureName, GEditorPerProjectIni);
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("AlphaTextureChannel"), InAlphaTextureChannel, GEditorPerProjectIni);
|
|
AlphaTextureChannel = (ELandscapeTextureColorChannel)InAlphaTextureChannel;
|
|
UTexture2D* LoadedTexture = LoadObject<UTexture2D>(nullptr, *AlphaTextureName, nullptr, LOAD_NoWarn);
|
|
if ((LoadedTexture == nullptr) && !AlphaTextureName.IsEmpty())
|
|
{
|
|
UE_LOG(LogLandscapeTools, Error, TEXT("Cannot load alpha texture (%s)"), *AlphaTextureName);
|
|
}
|
|
SetAlphaTexture(LoadedTexture, AlphaTextureChannel);
|
|
|
|
int32 InFlattenMode = (int32)ELandscapeToolFlattenMode::Both;
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("FlattenMode"), InFlattenMode, GEditorPerProjectIni);
|
|
FlattenMode = (ELandscapeToolFlattenMode)InFlattenMode;
|
|
|
|
bool InbUseSlopeFlatten = bUseSlopeFlatten;
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bUseSlopeFlatten"), InbUseSlopeFlatten, GEditorPerProjectIni);
|
|
bUseSlopeFlatten = InbUseSlopeFlatten;
|
|
|
|
bool InbPickValuePerApply = bPickValuePerApply;
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bPickValuePerApply"), InbPickValuePerApply, GEditorPerProjectIni);
|
|
bPickValuePerApply = InbPickValuePerApply;
|
|
|
|
bool InbUseFlattenTarget = bUseFlattenTarget;
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bUseFlattenTarget"), InbUseFlattenTarget, GEditorPerProjectIni);
|
|
bUseFlattenTarget = InbUseFlattenTarget;
|
|
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("FlattenTarget"), FlattenTarget, GEditorPerProjectIni);
|
|
|
|
bool InbShowFlattenTargetPreview = bShowFlattenTargetPreview;
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bShowFlattenTargetPreview"), InbShowFlattenTargetPreview, GEditorPerProjectIni);
|
|
bShowFlattenTargetPreview = InbShowFlattenTargetPreview;
|
|
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("TerraceSmooth"), TerraceSmooth, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("TerraceInterval"), TerraceInterval, GEditorPerProjectIni);
|
|
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("RampWidth"), RampWidth, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("RampSideFalloff"), RampSideFalloff, GEditorPerProjectIni);
|
|
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bCombinedLayersOperation"), bCombinedLayersOperation, GEditorPerProjectIni);
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bApplyWithoutMovingSculpt"), bApplyWithoutMovingSculpt, GEditorPerProjectIni);
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bApplyWithoutMovingPaint"), bApplyWithoutMovingPaint, GEditorPerProjectIni);
|
|
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("ErodeThresh"), ErodeThresh, GEditorPerProjectIni);
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("ErodeIterationNum"), ErodeIterationNum, GEditorPerProjectIni);
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("ErodeSurfaceThickness"), ErodeSurfaceThickness, GEditorPerProjectIni);
|
|
int32 InErosionNoiseMode = (int32)ErosionNoiseMode;
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("ErosionNoiseMode"), InErosionNoiseMode, GEditorPerProjectIni);
|
|
ErosionNoiseMode = (ELandscapeToolErosionMode)InErosionNoiseMode;
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("ErosionNoiseScale"), ErosionNoiseScale, GEditorPerProjectIni);
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bErosionUseLayerHardness"), bErosionUseLayerHardness, GEditorPerProjectIni);
|
|
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("RainAmount"), RainAmount, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("SedimentCapacity"), SedimentCapacity, GEditorPerProjectIni);
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("HErodeIterationNum"), HErodeIterationNum, GEditorPerProjectIni);
|
|
int32 InRainDistMode = (int32)RainDistMode;
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("RainDistNoiseMode"), InRainDistMode, GEditorPerProjectIni);
|
|
RainDistMode = (ELandscapeToolHydroErosionMode)InRainDistMode;
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("RainDistScale"), RainDistScale, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("HErosionDetailScale"), HErosionDetailScale, GEditorPerProjectIni);
|
|
bool InbHErosionDetailSmooth = bHErosionDetailSmooth;
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bHErosionDetailSmooth"), InbHErosionDetailSmooth, GEditorPerProjectIni);
|
|
bHErosionDetailSmooth = InbHErosionDetailSmooth;
|
|
|
|
int32 InNoiseMode = (int32)NoiseMode;
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("NoiseMode"), InNoiseMode, GEditorPerProjectIni);
|
|
NoiseMode = (ELandscapeToolNoiseMode)InNoiseMode;
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("NoiseScale"), NoiseScale, GEditorPerProjectIni);
|
|
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("SmoothFilterKernelSize"), SmoothFilterKernelSize, GEditorPerProjectIni);
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("DetailScale"), DetailScale, GEditorPerProjectIni);
|
|
bool InbDetailSmooth = bDetailSmooth;
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bDetailSmooth"), InbDetailSmooth, GEditorPerProjectIni);
|
|
bDetailSmooth = InbDetailSmooth;
|
|
|
|
GConfig->GetFloat(TEXT("LandscapeEdit"), TEXT("MaximumValueRadius"), MaximumValueRadius, GEditorPerProjectIni);
|
|
|
|
bool InbSmoothGizmoBrush = bSmoothGizmoBrush;
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bSmoothGizmoBrush"), InbSmoothGizmoBrush, GEditorPerProjectIni);
|
|
bSmoothGizmoBrush = InbSmoothGizmoBrush;
|
|
|
|
int32 InPasteMode = (int32)ELandscapeToolPasteMode::Both;
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("PasteMode"), InPasteMode, GEditorPerProjectIni);
|
|
//PasteMode = (ELandscapeToolPasteMode)InPasteMode;
|
|
SetPasteMode((ELandscapeToolPasteMode)InPasteMode);
|
|
|
|
int32 InMirrorOp = (int32)ELandscapeMirrorOperation::MinusXToPlusX;
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("MirrorOp"), InMirrorOp, GEditorPerProjectIni);
|
|
MirrorOp = (ELandscapeMirrorOperation)InMirrorOp;
|
|
|
|
int32 InConvertMode = (int32)ResizeLandscape_ConvertMode;
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("ConvertMode"), InConvertMode, GEditorPerProjectIni);
|
|
ResizeLandscape_ConvertMode = (ELandscapeConvertMode)InConvertMode;
|
|
|
|
// Region
|
|
//GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bUseSelectedRegion"), bUseSelectedRegion, GEditorPerProjectIni);
|
|
//GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bUseNegativeMask"), bUseNegativeMask, GEditorPerProjectIni);
|
|
bool InbApplyToAllTargets = bApplyToAllTargets;
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("bApplyToAllTargets"), InbApplyToAllTargets, GEditorPerProjectIni);
|
|
bApplyToAllTargets = InbApplyToAllTargets;
|
|
|
|
GConfig->GetBool(TEXT("LandscapeEdit"), TEXT("ShowUnusedLayers"), ShowUnusedLayers, GEditorPerProjectIni);
|
|
|
|
// Set EditRenderMode
|
|
SetbUseSelectedRegion(bUseSelectedRegion);
|
|
SetbUseNegativeMask(bUseNegativeMask);
|
|
|
|
// Gizmo History (not saved!)
|
|
GizmoHistories.Empty();
|
|
for (TActorIterator<ALandscapeGizmoActor> It(ParentMode->GetWorld()); It; ++It)
|
|
{
|
|
ALandscapeGizmoActor* Gizmo = *It;
|
|
if (!Gizmo->IsEditable())
|
|
{
|
|
new(GizmoHistories) FGizmoHistory(Gizmo);
|
|
}
|
|
}
|
|
|
|
FString NewLandscapeMaterialName;
|
|
|
|
// If NewLandscape_Material is not null, we will try to use it
|
|
if (!NewLandscape_Material.IsExplicitlyNull())
|
|
{
|
|
NewLandscapeMaterialName = NewLandscape_Material->GetPathName();
|
|
}
|
|
else
|
|
{
|
|
// If this project already has a saved NewLandscapeMaterialName, we use it
|
|
GConfig->GetString(TEXT("LandscapeEdit"), TEXT("NewLandscapeMaterialName"), NewLandscapeMaterialName, GEditorPerProjectIni);
|
|
|
|
if (NewLandscapeMaterialName.IsEmpty())
|
|
{
|
|
/* Project does not have a saved NewLandscapeMaterialNameand and NewLandscape_Material is not already assigned;
|
|
* we fallback to the DefaultLandscapeMaterial for the project, if set */
|
|
const ULandscapeSettings* Settings = GetDefault<ULandscapeSettings>();
|
|
TSoftObjectPtr<UMaterialInterface> DefaultMaterial = Settings->GetDefaultLandscapeMaterial();
|
|
|
|
if (!DefaultMaterial.IsNull())
|
|
{
|
|
NewLandscapeMaterialName = DefaultMaterial.ToString();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!NewLandscapeMaterialName.IsEmpty())
|
|
{
|
|
NewLandscape_Material = LoadObject<UMaterialInterface>(nullptr, *NewLandscapeMaterialName, nullptr, LOAD_NoWarn);
|
|
}
|
|
|
|
int32 AlphamapType = (uint8)ImportLandscape_AlphamapType;
|
|
GConfig->GetInt(TEXT("LandscapeEdit"), TEXT("ImportLandscape_AlphamapType"), AlphamapType, GEditorPerProjectIni);
|
|
ImportLandscape_AlphamapType = (ELandscapeImportAlphamapType)AlphamapType;
|
|
|
|
RefreshImportLayersList();
|
|
}
|
|
|
|
/** Save UI settings to ini file */
|
|
void ULandscapeEditorObject::Save()
|
|
{
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("ToolStrength"), ToolStrength, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("PaintToolStrength"), PaintToolStrength, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("WeightTargetValue"), WeightTargetValue, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bUseWeightTargetValue"), bUseWeightTargetValue, GEditorPerProjectIni);
|
|
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("BrushRadius"), BrushRadius, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("PaintBrushRadius"), PaintBrushRadius, GEditorPerProjectIni);
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("BrushComponentSize"), BrushComponentSize, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("BrushFalloff"), BrushFalloff, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("PaintBrushFalloff"), PaintBrushFalloff, GEditorPerProjectIni);
|
|
GConfig->SetString(TEXT("LandscapeEdit"), TEXT("TargetLayerAssetFilePath"), *TargetLayerAssetFilePath.DirectoryPath.Path, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bUseTargetLayerAssetFilePath"), TargetLayerAssetFilePath.bUseAssetDirectoryPath, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bUseClayBrush"), bUseClayBrush, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("AlphaBrushScale"), AlphaBrushScale, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("AlphaBrushAutoRotate"), bAlphaBrushAutoRotate, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("AlphaBrushRotation"), AlphaBrushRotation, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("AlphaBrushPanU"), AlphaBrushPanU, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("AlphaBrushPanV"), AlphaBrushPanV, GEditorPerProjectIni);
|
|
GConfig->SetVector2D(TEXT("LandscapeEdit"), TEXT("WorldSpacePatternBrushSettings.Origin"), WorldSpacePatternBrushSettings.Origin, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("WorldSpacePatternBrushSettings.bCenterTextureOnOrigin"), WorldSpacePatternBrushSettings.bCenterTextureOnOrigin, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("WorldSpacePatternBrushSettings.RepeatSize"), WorldSpacePatternBrushSettings.RepeatSize, GEditorPerProjectIni);
|
|
const FString AlphaTextureName = (AlphaTexture != nullptr) ? AlphaTexture->GetPathName() : FString();
|
|
GConfig->SetString(TEXT("LandscapeEdit"), TEXT("AlphaTextureName"), *AlphaTextureName, GEditorPerProjectIni);
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("AlphaTextureChannel"), (int32)AlphaTextureChannel, GEditorPerProjectIni);
|
|
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("FlattenMode"), (int32)FlattenMode, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bUseSlopeFlatten"), bUseSlopeFlatten, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bPickValuePerApply"), bPickValuePerApply, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bUseFlattenTarget"), bUseFlattenTarget, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("FlattenTarget"), FlattenTarget, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bShowFlattenTargetPreview"), bShowFlattenTargetPreview, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("TerraceSmooth"), TerraceSmooth, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("TerraceInterval"), TerraceInterval, GEditorPerProjectIni);
|
|
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("RampWidth"), RampWidth, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("RampSideFalloff"), RampSideFalloff, GEditorPerProjectIni);
|
|
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bCombinedLayersOperation"), bCombinedLayersOperation, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bApplyWithoutMovingSculpt"), bApplyWithoutMovingSculpt, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bApplyWithoutMovingPaint"), bApplyWithoutMovingPaint, GEditorPerProjectIni);
|
|
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("ErodeThresh"), ErodeThresh, GEditorPerProjectIni);
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("ErodeIterationNum"), ErodeIterationNum, GEditorPerProjectIni);
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("ErodeSurfaceThickness"), ErodeSurfaceThickness, GEditorPerProjectIni);
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("ErosionNoiseMode"), (int32)ErosionNoiseMode, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("ErosionNoiseScale"), ErosionNoiseScale, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bErosionUseLayerHardness"), bErosionUseLayerHardness, GEditorPerProjectIni);
|
|
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("RainAmount"), RainAmount, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("SedimentCapacity"), SedimentCapacity, GEditorPerProjectIni);
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("HErodeIterationNum"), ErodeIterationNum, GEditorPerProjectIni);
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("RainDistMode"), (int32)RainDistMode, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("RainDistScale"), RainDistScale, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("HErosionDetailScale"), HErosionDetailScale, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bHErosionDetailSmooth"), bHErosionDetailSmooth, GEditorPerProjectIni);
|
|
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("NoiseMode"), (int32)NoiseMode, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("NoiseScale"), NoiseScale, GEditorPerProjectIni);
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("SmoothFilterKernelSize"), SmoothFilterKernelSize, GEditorPerProjectIni);
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("DetailScale"), DetailScale, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bDetailSmooth"), bDetailSmooth, GEditorPerProjectIni);
|
|
|
|
GConfig->SetFloat(TEXT("LandscapeEdit"), TEXT("MaximumValueRadius"), MaximumValueRadius, GEditorPerProjectIni);
|
|
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bSmoothGizmoBrush"), bSmoothGizmoBrush, GEditorPerProjectIni);
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("PasteMode"), (int32)PasteMode, GEditorPerProjectIni);
|
|
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("MirrorOp"), (int32)MirrorOp, GEditorPerProjectIni);
|
|
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("ConvertMode"), (int32)ResizeLandscape_ConvertMode, GEditorPerProjectIni);
|
|
//GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bUseSelectedRegion"), bUseSelectedRegion, GEditorPerProjectIni);
|
|
//GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bUseNegativeMask"), bUseNegativeMask, GEditorPerProjectIni);
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("bApplyToAllTargets"), bApplyToAllTargets, GEditorPerProjectIni);
|
|
|
|
const FString NewLandscapeMaterialName = (NewLandscape_Material != nullptr) ? NewLandscape_Material->GetPathName() : FString();
|
|
GConfig->SetString(TEXT("LandscapeEdit"), TEXT("NewLandscapeMaterialName"), *NewLandscapeMaterialName, GEditorPerProjectIni);
|
|
|
|
GConfig->SetInt(TEXT("LandscapeEdit"), TEXT("ImportLandscape_AlphamapType"), (uint8)ImportLandscape_AlphamapType, GEditorPerProjectIni);
|
|
|
|
GConfig->SetBool(TEXT("LandscapeEdit"), TEXT("ShowUnusedLayers"), ShowUnusedLayers, GEditorPerProjectIni);
|
|
}
|
|
|
|
// Region
|
|
void ULandscapeEditorObject::SetbUseSelectedRegion(bool InbUseSelectedRegion)
|
|
{
|
|
bUseSelectedRegion = InbUseSelectedRegion;
|
|
if (bUseSelectedRegion)
|
|
{
|
|
GLandscapeEditRenderMode |= ELandscapeEditRenderMode::Mask;
|
|
}
|
|
else
|
|
{
|
|
GLandscapeEditRenderMode &= ~(ELandscapeEditRenderMode::Mask);
|
|
}
|
|
}
|
|
void ULandscapeEditorObject::SetbUseNegativeMask(bool InbUseNegativeMask)
|
|
{
|
|
bUseNegativeMask = InbUseNegativeMask;
|
|
if (bUseNegativeMask)
|
|
{
|
|
GLandscapeEditRenderMode |= ELandscapeEditRenderMode::InvertedMask;
|
|
}
|
|
else
|
|
{
|
|
GLandscapeEditRenderMode &= ~(ELandscapeEditRenderMode::InvertedMask);
|
|
}
|
|
}
|
|
|
|
void ULandscapeEditorObject::SetPasteMode(ELandscapeToolPasteMode InPasteMode)
|
|
{
|
|
PasteMode = InPasteMode;
|
|
}
|
|
|
|
void ULandscapeEditorObject::SetGizmoSnapMode(ELandscapeGizmoSnapType InSnapMode)
|
|
{
|
|
SnapMode = InSnapMode;
|
|
|
|
if (ParentMode->CurrentGizmoActor.IsValid())
|
|
{
|
|
ParentMode->CurrentGizmoActor->SnapType = SnapMode;
|
|
}
|
|
|
|
if (SnapMode != ELandscapeGizmoSnapType::None)
|
|
{
|
|
// Ignore gizmo updates if landscape info is invalid (Ex. landscape is deleted after using Copy Tool)
|
|
if (ParentMode->CurrentGizmoActor.IsValid() && ParentMode->CurrentGizmoActor->TargetLandscapeInfo)
|
|
{
|
|
const FVector WidgetLocation = ParentMode->CurrentGizmoActor->GetActorLocation();
|
|
const FRotator WidgetRotation = ParentMode->CurrentGizmoActor->GetActorRotation();
|
|
|
|
const FVector SnappedWidgetLocation = ParentMode->CurrentGizmoActor->SnapToLandscapeGrid(WidgetLocation);
|
|
const FRotator SnappedWidgetRotation = ParentMode->CurrentGizmoActor->SnapToLandscapeGrid(WidgetRotation);
|
|
|
|
ParentMode->CurrentGizmoActor->SetActorLocation(SnappedWidgetLocation, false);
|
|
ParentMode->CurrentGizmoActor->SetActorRotation(SnappedWidgetRotation);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ULandscapeEditorObject::LoadAlphaTextureSourceData(UTexture2D* InTexture, TArray<uint8>& OutSourceData, int32& OutSourceDataSizeX, int32& OutSourceDataSizeY, ELandscapeTextureColorChannel& InOutTextureChannel)
|
|
{
|
|
check(InTexture != nullptr);
|
|
|
|
if (InTexture && InTexture->Source.IsValid()
|
|
&& !CVarLandscapeSimulateAlphaBrushTextureLoadFailure.GetValueOnGameThread()) // For debug purposes, we can also simulate a loading failure for the alpha brush texture
|
|
{
|
|
FImage SourceImage;
|
|
if (InTexture->Source.GetMipImage(SourceImage, 0) && (SourceImage.Format != ERawImageFormat::Invalid))
|
|
{
|
|
OutSourceDataSizeX = SourceImage.SizeX;
|
|
OutSourceDataSizeY = SourceImage.SizeY;
|
|
const int32 NumPixels = OutSourceDataSizeX * OutSourceDataSizeY;
|
|
|
|
// Handle the case where we're being asked to sample from a channel that is non-existent in the source image :
|
|
EPixelFormat PixelFormat = InTexture->GetPixelFormat();
|
|
EPixelFormatChannelFlags ValidTextureChannels = GetPixelFormatValidChannels(PixelFormat);
|
|
if (((InOutTextureChannel == ELandscapeTextureColorChannel::Green && !EnumHasAnyFlags(ValidTextureChannels, EPixelFormatChannelFlags::G)))
|
|
|| ((InOutTextureChannel == ELandscapeTextureColorChannel::Blue && !EnumHasAnyFlags(ValidTextureChannels, EPixelFormatChannelFlags::B)))
|
|
|| ((InOutTextureChannel == ELandscapeTextureColorChannel::Alpha && !EnumHasAnyFlags(ValidTextureChannels, EPixelFormatChannelFlags::A))))
|
|
{
|
|
// Fallback to Red
|
|
InOutTextureChannel = ELandscapeTextureColorChannel::Red;
|
|
}
|
|
|
|
// Convert/expand the image to BGRA8 :
|
|
SourceImage.ChangeFormat(ERawImageFormat::BGRA8, EGammaSpace::Linear);
|
|
|
|
const int32 FinalDataSizeBytes = NumPixels;
|
|
check(SourceImage.RawData.Num() == FinalDataSizeBytes * 4);
|
|
OutSourceData.SetNum(FinalDataSizeBytes);
|
|
|
|
uint8* SrcPtr = SourceImage.RawData.GetData();
|
|
// Properly offset the source data as we're reading a single channel from a BGRA8 source :
|
|
switch (InOutTextureChannel)
|
|
{
|
|
case ELandscapeTextureColorChannel::Blue:
|
|
SrcPtr += 0;
|
|
break;
|
|
case ELandscapeTextureColorChannel::Green:
|
|
SrcPtr += 1;
|
|
break;
|
|
case ELandscapeTextureColorChannel::Red:
|
|
SrcPtr += 2;
|
|
break;
|
|
case ELandscapeTextureColorChannel::Alpha:
|
|
SrcPtr += 3;
|
|
break;
|
|
default:
|
|
check(false);
|
|
break;
|
|
}
|
|
|
|
for (int32 Index = 0; Index < NumPixels; Index++, SrcPtr += 4)
|
|
{
|
|
OutSourceData[Index] = *SrcPtr;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void ULandscapeEditorObject::SetAlphaTexture(UTexture2D* InTexture, ELandscapeTextureColorChannel InTextureChannel)
|
|
{
|
|
AlphaTexture = nullptr;
|
|
AlphaTextureChannel = InTextureChannel;
|
|
AlphaTextureSizeX = 0;
|
|
AlphaTextureSizeY = 0;
|
|
|
|
UTexture2D* DefaultAlphaTexture = GetClass()->GetDefaultObject<ULandscapeEditorObject>()->AlphaTexture;
|
|
// Try to read the texture data from the specified texture if any :
|
|
if (InTexture != nullptr)
|
|
{
|
|
if (LoadAlphaTextureSourceData(InTexture, AlphaTextureData, AlphaTextureSizeX, AlphaTextureSizeY, AlphaTextureChannel))
|
|
{
|
|
AlphaTexture = InTexture;
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogLandscapeTools, Error, TEXT("Invalid source data detected for texture (%s), the default AlphaTexture (%s) will be used."), *InTexture->GetPathName(), DefaultAlphaTexture ? *DefaultAlphaTexture->GetPathName() : TEXT("None"));
|
|
}
|
|
}
|
|
|
|
if (AlphaTexture == nullptr)
|
|
{
|
|
if (DefaultAlphaTexture == nullptr)
|
|
{
|
|
UE_LOG(LogLandscapeTools, Error, TEXT("No default AlphaTexture specified : the alpha brush won't work as expected."));
|
|
}
|
|
else if (LoadAlphaTextureSourceData(DefaultAlphaTexture, AlphaTextureData, AlphaTextureSizeX, AlphaTextureSizeY, AlphaTextureChannel))
|
|
{
|
|
AlphaTexture = DefaultAlphaTexture;
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogLandscapeTools, Error, TEXT("Invalid source data detected for default AlphaTexture (%s)"), *DefaultAlphaTexture->GetPathName());
|
|
}
|
|
}
|
|
|
|
// If the AlphaTexture was successfully loaded, all read data should be valid :
|
|
check ((AlphaTexture == nullptr) || HasValidAlphaTextureData());
|
|
}
|
|
|
|
bool ULandscapeEditorObject::HasValidAlphaTextureData() const
|
|
{
|
|
return ((AlphaTextureSizeX > 0) && (AlphaTextureSizeY > 0) && !AlphaTextureData.IsEmpty());
|
|
}
|
|
|
|
void ULandscapeEditorObject::ChooseBestComponentSizeForImport()
|
|
{
|
|
FLandscapeImportHelper::ChooseBestComponentSizeForImport(ImportLandscape_Width, ImportLandscape_Height, NewLandscape_QuadsPerSection, NewLandscape_SectionsPerComponent, NewLandscape_ComponentCount);
|
|
}
|
|
|
|
bool ULandscapeEditorObject::UseSingleFileImport() const
|
|
{
|
|
if (ParentMode)
|
|
{
|
|
return ParentMode->UseSingleFileImport();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ULandscapeEditorObject::RefreshImports()
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(ULandscapeEditorObject::RefreshImports);
|
|
|
|
ClearImportLandscapeData();
|
|
HeightmapImportDescriptorIndex = 0;
|
|
HeightmapImportDescriptor.Reset();
|
|
ImportLandscape_Width = 0;
|
|
ImportLandscape_Height = 0;
|
|
|
|
ImportLandscape_HeightmapImportResult = ELandscapeImportResult::Success;
|
|
ImportLandscape_HeightmapErrorMessage = FText();
|
|
|
|
if (!ImportLandscape_HeightmapFilename.IsEmpty())
|
|
{
|
|
FLandscapeTiledImage TiledImage;
|
|
|
|
FLandscapeFileInfo FileInfo = TiledImage.Load<uint16>(*ImportLandscape_HeightmapFilename);
|
|
|
|
if (FileInfo.PossibleResolutions.Num() > 0)
|
|
{
|
|
ImportLandscape_Width = TiledImage.GetResolution().X;
|
|
ImportLandscape_Height = TiledImage.GetResolution().Y;
|
|
}
|
|
|
|
if ( FileInfo.ResultCode != ELandscapeImportResult::Error)
|
|
{
|
|
ChooseBestComponentSizeForImport();
|
|
ImportLandscapeData();
|
|
}
|
|
|
|
ImportLandscape_HeightmapImportResult = FileInfo.ResultCode;
|
|
ImportLandscape_HeightmapErrorMessage = FileInfo.ErrorMessage;
|
|
}
|
|
|
|
RefreshLayerImports();
|
|
}
|
|
|
|
void ULandscapeEditorObject::RefreshLayerImports()
|
|
{
|
|
// Make sure to reset import width and height if we don't have a Heightmap to import
|
|
if (ImportLandscape_HeightmapFilename.IsEmpty())
|
|
{
|
|
HeightmapImportDescriptorIndex = 0;
|
|
ImportLandscape_Width = 0;
|
|
ImportLandscape_Height = 0;
|
|
}
|
|
|
|
for (FLandscapeImportLayer& UIImportLayer : ImportLandscape_Layers)
|
|
{
|
|
RefreshLayerImport(UIImportLayer);
|
|
}
|
|
}
|
|
|
|
void ULandscapeEditorObject::RefreshLayerImport(FLandscapeImportLayer& ImportLayer)
|
|
{
|
|
ImportLayer.ErrorMessage = FText();
|
|
ImportLayer.ImportResult = ELandscapeImportResult::Success;
|
|
|
|
if (ImportLayer.LayerName == ALandscapeProxy::VisibilityLayer->LayerName)
|
|
{
|
|
ImportLayer.LayerInfo = ALandscapeProxy::VisibilityLayer;
|
|
}
|
|
|
|
if (!ImportLayer.SourceFilePath.IsEmpty())
|
|
{
|
|
if (!ImportLayer.LayerInfo)
|
|
{
|
|
ImportLayer.ImportResult = ELandscapeImportResult::Error;
|
|
ImportLayer.ErrorMessage = NSLOCTEXT("LandscapeEditor.NewLandscape", "Import_LayerInfoNotSet", "Can't import a layer file without a layer info");
|
|
}
|
|
else
|
|
{
|
|
FLandscapeTiledImage TiledImage;
|
|
FLandscapeFileInfo FileInfo = TiledImage.Load<uint8>(*ImportLayer.SourceFilePath);
|
|
ImportLayer.ImportResult = FileInfo.ResultCode;
|
|
ImportLayer.ErrorMessage = FileInfo.ErrorMessage;
|
|
if (FileInfo.ResultCode == ELandscapeImportResult::Success)
|
|
{
|
|
if (FileInfo.PossibleResolutions[0] != FLandscapeFileResolution(ImportLandscape_Width, ImportLandscape_Height) && bHeightmapSelected)
|
|
{
|
|
ImportLayer.ImportResult = ELandscapeImportResult::Error;
|
|
ImportLayer.ErrorMessage = NSLOCTEXT("LandscapeEditor.ImportLandscape", "Import_WeightHeightResolutionMismatch", "Weightmap import resolution isn't same as Heightmap resolution.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ULandscapeEditorObject::OnChangeImportLandscapeResolution(int32 DescriptorIndex)
|
|
{
|
|
check(DescriptorIndex >= 0 && DescriptorIndex < HeightmapImportDescriptor.ImportResolutions.Num());
|
|
HeightmapImportDescriptorIndex = DescriptorIndex;
|
|
ImportLandscape_Width = HeightmapImportDescriptor.ImportResolutions[HeightmapImportDescriptorIndex].Width;
|
|
ImportLandscape_Height = HeightmapImportDescriptor.ImportResolutions[HeightmapImportDescriptorIndex].Height;
|
|
ClearImportLandscapeData();
|
|
ImportLandscapeData();
|
|
ChooseBestComponentSizeForImport();
|
|
}
|
|
|
|
void ULandscapeEditorObject::ImportLandscapeData()
|
|
{
|
|
FLandscapeTiledImage TiledImage;
|
|
FLandscapeFileInfo FileInfo = TiledImage.Load<uint16>(*ImportLandscape_HeightmapFilename);
|
|
|
|
if (FileInfo.ResultCode == ELandscapeImportResult::Error)
|
|
{
|
|
ImportLandscape_Data.Empty();
|
|
}
|
|
|
|
TiledImage.Read(ImportLandscape_Data, bFlipYAxis);
|
|
}
|
|
|
|
ELandscapeImportResult ULandscapeEditorObject::CreateImportLayersInfo(TArray<FLandscapeImportLayerInfo>& OutImportLayerInfos)
|
|
{
|
|
const uint32 ImportSizeX = ImportLandscape_Width;
|
|
const uint32 ImportSizeY = ImportLandscape_Height;
|
|
|
|
if (ImportLandscape_HeightmapImportResult == ELandscapeImportResult::Error)
|
|
{
|
|
// Cancel import
|
|
return ELandscapeImportResult::Error;
|
|
}
|
|
|
|
OutImportLayerInfos.Reserve(NewLandscape_Layers.Num());
|
|
|
|
// Fill in LayerInfos array and allocate data
|
|
for (FLandscapeImportLayer& UIImportLayer : NewLandscape_Layers)
|
|
{
|
|
OutImportLayerInfos.Add((const FLandscapeImportLayer&)UIImportLayer); //slicing is fine here
|
|
FLandscapeImportLayerInfo& ImportLayer = OutImportLayerInfos.Last();
|
|
|
|
if (ImportLayer.LayerInfo != nullptr && !ImportLayer.SourceFilePath.IsEmpty())
|
|
{
|
|
FLandscapeTiledImage LayerImage;
|
|
FLandscapeFileInfo LayerFileInfo = LayerImage.Load<uint8>(*ImportLayer.SourceFilePath);
|
|
|
|
UIImportLayer.ImportResult = LayerFileInfo.ResultCode;
|
|
|
|
if (UIImportLayer.ImportResult == ELandscapeImportResult::Error)
|
|
{
|
|
FMessageDialog::Open(EAppMsgType::Ok, UIImportLayer.ErrorMessage);
|
|
return ELandscapeImportResult::Error;
|
|
}
|
|
|
|
LayerImage.Read(ImportLayer.LayerData);
|
|
}
|
|
}
|
|
|
|
return ELandscapeImportResult::Success;
|
|
}
|
|
|
|
ELandscapeImportResult ULandscapeEditorObject::CreateNewLayersInfo(TArray<FLandscapeImportLayerInfo>& OutNewLayerInfos)
|
|
{
|
|
const int32 QuadsPerComponent = NewLandscape_SectionsPerComponent * NewLandscape_QuadsPerSection;
|
|
const int32 SizeX = NewLandscape_ComponentCount.X * QuadsPerComponent + 1;
|
|
const int32 SizeY = NewLandscape_ComponentCount.Y * QuadsPerComponent + 1;
|
|
|
|
OutNewLayerInfos.Reset(NewLandscape_Layers.Num());
|
|
|
|
// Fill in LayerInfos array and allocate data
|
|
for (const FLandscapeImportLayer& UIImportLayer : NewLandscape_Layers)
|
|
{
|
|
FLandscapeImportLayerInfo ImportLayer = FLandscapeImportLayerInfo(UIImportLayer.LayerName);
|
|
ImportLayer.LayerInfo = UIImportLayer.LayerInfo;
|
|
ImportLayer.SourceFilePath = "";
|
|
ImportLayer.LayerData = TArray<uint8>();
|
|
OutNewLayerInfos.Add(MoveTemp(ImportLayer));
|
|
}
|
|
|
|
// Fill the first weight-blended layer to 100%
|
|
if (FLandscapeImportLayerInfo* FirstBlendedLayer = OutNewLayerInfos.FindByPredicate([](const FLandscapeImportLayerInfo& ImportLayer) { return ImportLayer.LayerInfo && !ImportLayer.LayerInfo->bNoWeightBlend; }))
|
|
{
|
|
const int32 DataSize = SizeX * SizeY;
|
|
FirstBlendedLayer->LayerData.AddUninitialized(DataSize);
|
|
|
|
uint8* ByteData = FirstBlendedLayer->LayerData.GetData();
|
|
FMemory::Memset(ByteData, 255, DataSize);
|
|
}
|
|
|
|
return ELandscapeImportResult::Success;
|
|
}
|
|
|
|
void ULandscapeEditorObject::InitializeDefaultHeightData(TArray<uint16>& OutData)
|
|
{
|
|
const int32 QuadsPerComponent = NewLandscape_SectionsPerComponent * NewLandscape_QuadsPerSection;
|
|
const int32 SizeX = NewLandscape_ComponentCount.X * QuadsPerComponent + 1;
|
|
const int32 SizeY = NewLandscape_ComponentCount.Y * QuadsPerComponent + 1;
|
|
const int32 TotalSize = SizeX * SizeY;
|
|
// Initialize heightmap data
|
|
OutData.Reset();
|
|
OutData.AddUninitialized(TotalSize);
|
|
|
|
TArray<uint16> StrideData;
|
|
StrideData.AddUninitialized(SizeX);
|
|
// Initialize blank heightmap data
|
|
for (int32 X = 0; X < SizeX; ++X)
|
|
{
|
|
StrideData[X] = static_cast<uint16>(LandscapeDataAccess::MidValue);
|
|
}
|
|
for (int32 Y = 0; Y < SizeY; ++Y)
|
|
{
|
|
FMemory::Memcpy(&OutData[Y * SizeX], StrideData.GetData(), sizeof(uint16) * SizeX);
|
|
}
|
|
}
|
|
|
|
void ULandscapeEditorObject::ExpandImportData(TArray<uint16>& OutHeightData, TArray<FLandscapeImportLayerInfo>& OutImportLayerInfos)
|
|
{
|
|
const TArray<uint16>& ImportData = GetImportLandscapeData();
|
|
if (ImportData.Num())
|
|
{
|
|
const int32 QuadsPerComponent = NewLandscape_SectionsPerComponent * NewLandscape_QuadsPerSection;
|
|
FLandscapeImportResolution RequiredResolution(NewLandscape_ComponentCount.X * QuadsPerComponent + 1, NewLandscape_ComponentCount.Y * QuadsPerComponent + 1);
|
|
FLandscapeImportResolution ImportResolution(ImportLandscape_Width, ImportLandscape_Height);
|
|
|
|
FLandscapeImportHelper::TransformHeightmapImportData(ImportData, OutHeightData, ImportResolution, RequiredResolution, ELandscapeImportTransformType::ExpandCentered);
|
|
|
|
for (int32 LayerIdx = 0; LayerIdx < OutImportLayerInfos.Num(); ++LayerIdx)
|
|
{
|
|
TArray<uint8>& OutImportLayerData = OutImportLayerInfos[LayerIdx].LayerData;
|
|
TArray<uint8> OutLayerData;
|
|
if (OutImportLayerData.Num())
|
|
{
|
|
FLandscapeImportHelper::TransformWeightmapImportData(OutImportLayerData, OutLayerData, ImportResolution, RequiredResolution, ELandscapeImportTransformType::ExpandCentered);
|
|
OutImportLayerData = MoveTemp(OutLayerData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ULandscapeEditorObject::RefreshImportLayersList(bool bRefreshFromTarget, bool bRegenerateThumbnails)
|
|
{
|
|
TArray<FName> LayerNames;
|
|
TArray<ULandscapeLayerInfoObject*> LayerInfoObjs;
|
|
UMaterialInterface* Material = nullptr;
|
|
if (bRefreshFromTarget)
|
|
{
|
|
LayerNames.Reset(ImportLandscape_Layers.Num());
|
|
LayerInfoObjs.Reset(ImportLandscape_Layers.Num());
|
|
Material = ParentMode->GetTargetLandscapeMaterial();
|
|
for (const TSharedRef<FLandscapeTargetListInfo>& TargetListInfo : ParentMode->GetTargetList())
|
|
{
|
|
if ((TargetListInfo->TargetType != ELandscapeToolTargetType::Weightmap) && (TargetListInfo->TargetType != ELandscapeToolTargetType::Visibility))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
LayerNames.Add(TargetListInfo->LayerName);
|
|
LayerInfoObjs.Add(TargetListInfo->LayerInfoObj.Get());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Material = NewLandscape_Material.Get();
|
|
LayerNames = ALandscapeProxy::GetLayersFromMaterial(Material);
|
|
}
|
|
|
|
TArray<FLandscapeImportLayer>& LandscapeLayers = bRefreshFromTarget ? ImportLandscape_Layers : NewLandscape_Layers;
|
|
const TArray<FLandscapeImportLayer> OldLayersList = MoveTemp(LandscapeLayers);
|
|
LandscapeLayers.Reset(LayerNames.Num());
|
|
|
|
// Don't recreate the render state of everything, only update the materials context
|
|
FMaterialUpdateContext MaterialUpdateContext(FMaterialUpdateContext::EOptions::Default & ~FMaterialUpdateContext::EOptions::RecreateRenderStates);
|
|
for (int32 i = 0; i < LayerNames.Num(); i++)
|
|
{
|
|
const FName& LayerName = LayerNames[i];
|
|
|
|
if (!LayerName.IsNone())
|
|
{
|
|
bool bFound = false;
|
|
FLandscapeImportLayer NewImportLayer;
|
|
NewImportLayer.ImportResult = ELandscapeImportResult::Success;
|
|
NewImportLayer.ErrorMessage = FText();
|
|
|
|
for (int32 j = 0; j < OldLayersList.Num(); j++)
|
|
{
|
|
if (OldLayersList[j].LayerName == LayerName)
|
|
{
|
|
NewImportLayer = OldLayersList[j];
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bFound && !bRegenerateThumbnails)
|
|
{
|
|
if ((NewImportLayer.ThumbnailMIC != nullptr) && (NewImportLayer.ThumbnailMIC->Parent != Material))
|
|
{
|
|
NewImportLayer.ThumbnailMIC->SetParentEditorOnly(Material);
|
|
MaterialUpdateContext.AddMaterialInterface(NewImportLayer.ThumbnailMIC);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NewImportLayer.LayerName = LayerName;
|
|
NewImportLayer.ThumbnailMIC = UE::Landscape::CreateLandscapeLayerThumbnailMIC(MaterialUpdateContext, Material, LayerName);
|
|
}
|
|
|
|
if (bRefreshFromTarget)
|
|
{
|
|
NewImportLayer.LayerInfo = LayerInfoObjs[i];
|
|
}
|
|
|
|
RefreshLayerImport(NewImportLayer);
|
|
|
|
LandscapeLayers.Add(MoveTemp(NewImportLayer));
|
|
}
|
|
}
|
|
}
|
|
|
|
void ULandscapeEditorObject::AutoFillTargetLayers(const FString& DefaultTargetLayerAssetPath, const bool bCreateAssetForEmptyLayers)
|
|
{
|
|
for (FLandscapeImportLayer& NewLayer : NewLandscape_Layers)
|
|
{
|
|
if (const FAssetData* AssetData = LandscapeEditorUtils::FindLandscapeTargetLayerInfoAsset(NewLayer.LayerName, DefaultTargetLayerAssetPath))
|
|
{
|
|
NewLayer.LayerInfo = CastChecked<ULandscapeLayerInfoObject>(AssetData->GetAsset());
|
|
}
|
|
else if (bCreateAssetForEmptyLayers)
|
|
{
|
|
// Creates a new layer info object, using the default if available, or a new empty one
|
|
ULandscapeLayerInfoObject* LayerInfo = UE::Landscape::CreateTargetLayerInfo(NewLayer.LayerName, DefaultTargetLayerAssetPath);
|
|
LayerInfo->bNoWeightBlend = true;
|
|
|
|
NewLayer.LayerInfo = LayerInfo;
|
|
|
|
// Show in the content browser
|
|
TArray<UObject*> Objects;
|
|
Objects.Add(LayerInfo);
|
|
GEditor->SyncBrowserToObjects(Objects);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ULandscapeEditorObject::UpdateComponentLayerAllowList()
|
|
{
|
|
if (ParentMode->CurrentToolTarget.LandscapeInfo.IsValid())
|
|
{
|
|
ParentMode->CurrentToolTarget.LandscapeInfo->UpdateComponentLayerAllowList();
|
|
}
|
|
}
|
|
|
|
void ULandscapeEditorObject::UpdateTargetLayerDisplayOrder()
|
|
{
|
|
if (ParentMode != nullptr)
|
|
{
|
|
ParentMode->UpdateTargetLayerDisplayOrder(TargetDisplayOrder);
|
|
}
|
|
}
|
|
|
|
float ULandscapeEditorObject::GetCurrentToolStrength() const
|
|
{
|
|
if (IsWeightmapTarget())
|
|
{
|
|
return PaintToolStrength;
|
|
}
|
|
return ToolStrength;
|
|
}
|
|
|
|
void ULandscapeEditorObject::SetCurrentToolStrength(float NewToolStrength)
|
|
{
|
|
if (IsWeightmapTarget())
|
|
{
|
|
PaintToolStrength = NewToolStrength;
|
|
}
|
|
else
|
|
{
|
|
ToolStrength = NewToolStrength;
|
|
}
|
|
}
|
|
|
|
float ULandscapeEditorObject::GetCurrentToolBrushRadius() const
|
|
{
|
|
if (IsWeightmapTarget())
|
|
{
|
|
return PaintBrushRadius;
|
|
}
|
|
return BrushRadius;
|
|
|
|
|
|
}
|
|
|
|
void ULandscapeEditorObject::SetCurrentToolBrushRadius(float NewBrushStrength)
|
|
{
|
|
if (IsWeightmapTarget())
|
|
{
|
|
PaintBrushRadius = NewBrushStrength;
|
|
}
|
|
else
|
|
{
|
|
BrushRadius = NewBrushStrength;
|
|
}
|
|
}
|
|
|
|
float ULandscapeEditorObject::GetCurrentToolBrushFalloff() const
|
|
{
|
|
if (IsWeightmapTarget())
|
|
{
|
|
return PaintBrushFalloff;
|
|
|
|
}
|
|
return BrushFalloff;
|
|
|
|
}
|
|
|
|
void ULandscapeEditorObject::SetCurrentToolBrushFalloff(float NewBrushFalloff)
|
|
{
|
|
if (IsWeightmapTarget())
|
|
{
|
|
PaintBrushFalloff = NewBrushFalloff;
|
|
}
|
|
else
|
|
{
|
|
BrushFalloff = NewBrushFalloff;
|
|
}
|
|
}
|
|
|
|
float ULandscapeEditorObject::GetFlattenTarget(bool bInReturnPreviewValueIfActive) const
|
|
{
|
|
return (bFlattenEyeDropperModeActivated && bInReturnPreviewValueIfActive) ? FlattenEyeDropperModeDesiredTarget : FlattenTarget;
|
|
} |