You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Most code accessing brush/landscape data by calculating indexes (e.g. Data + (Y-Y1)*XSize + (X-X1)) replaced with scanline[X] style for speed LandscapeInfo->SelectedRegion is now only queried if it contains anything, to avoid hashing the key unneccessarily (the hash function was showing on profiles :( ) Smoothing tool's SmoothFilterKernel*Scale* replaced by the more intuitive Size Component brush fixed to be properly centered on the cursor at odd sizes and work correctly with the add component tool when cursor is over the landscape (but part of the brush is off the landscape) and size is >1 Copy tool fixed to copy the selected area and not a circle when using ctrl+c Also a few style cleanups. for (auto it = xyz.CreateIterator...) replaced with ranged for, enums replaced with enum classes, 0.f -> 0.0f, NULL->nullptr, etc. [CL 2392355 by Gareth Martin in Main branch]
523 lines
17 KiB
C++
523 lines
17 KiB
C++
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "LandscapeEditorPrivatePCH.h"
|
|
#include "ObjectTools.h"
|
|
#include "LandscapeEdMode.h"
|
|
#include "ScopedTransaction.h"
|
|
#include "LandscapeEdit.h"
|
|
#include "LandscapeRender.h"
|
|
#include "LandscapeDataAccess.h"
|
|
#include "LandscapeSplineProxies.h"
|
|
#include "LandscapeEditorModule.h"
|
|
#include "Editor/PropertyEditor/Public/PropertyEditorModule.h"
|
|
#include "LandscapeEdModeTools.h"
|
|
#include "Landscape.h"
|
|
#include "LandscapeLayerInfoObject.h"
|
|
|
|
//
|
|
// FLandscapeToolErosionBase
|
|
//
|
|
class FLandscapeToolStrokeErosionBase : public FLandscapeToolStrokeBase
|
|
{
|
|
public:
|
|
FLandscapeToolStrokeErosionBase(FEdModeLandscape* InEdMode, const FLandscapeToolTarget& InTarget)
|
|
: LandscapeInfo(InTarget.LandscapeInfo.Get())
|
|
, HeightCache(InTarget)
|
|
, WeightCache(InTarget)
|
|
, bWeightApplied(InTarget.TargetType != ELandscapeToolTargetType::Heightmap)
|
|
{
|
|
}
|
|
|
|
protected:
|
|
ULandscapeInfo* LandscapeInfo;
|
|
FLandscapeHeightCache HeightCache;
|
|
FLandscapeFullWeightCache WeightCache;
|
|
bool bWeightApplied;
|
|
};
|
|
|
|
template<class TStrokeClass>
|
|
class FLandscapeToolErosionBase : public FLandscapeToolBase<TStrokeClass>
|
|
{
|
|
public:
|
|
FLandscapeToolErosionBase(FEdModeLandscape* InEdMode)
|
|
: FLandscapeToolBase<TStrokeClass>(InEdMode)
|
|
{
|
|
}
|
|
|
|
virtual ELandscapeToolTargetTypeMask::Type GetSupportedTargetTypes() override
|
|
{
|
|
return ELandscapeToolTargetTypeMask::Heightmap;
|
|
}
|
|
};
|
|
|
|
//
|
|
// FLandscapeToolErosion
|
|
//
|
|
|
|
class FLandscapeToolStrokeErosion : public FLandscapeToolStrokeErosionBase
|
|
{
|
|
public:
|
|
FLandscapeToolStrokeErosion(FEdModeLandscape* InEdMode, const FLandscapeToolTarget& InTarget)
|
|
: FLandscapeToolStrokeErosionBase(InEdMode, InTarget)
|
|
{
|
|
}
|
|
|
|
void Apply(FEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray<FLandscapeToolMousePosition>& MousePositions)
|
|
{
|
|
if (!LandscapeInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Get list of verts to update
|
|
FLandscapeBrushData BrushInfo = Brush->ApplyBrush(MousePositions);
|
|
if (!BrushInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int32 X1, Y1, X2, Y2;
|
|
BrushInfo.GetInclusiveBounds(X1, Y1, X2, Y2);
|
|
|
|
// Tablet pressure
|
|
float Pressure = ViewportClient->Viewport->IsPenActive() ? ViewportClient->Viewport->GetTabletPressure() : 1.0f;
|
|
|
|
// expand the area by one vertex in each direction to ensure normals are calculated correctly
|
|
X1 -= 1;
|
|
Y1 -= 1;
|
|
X2 += 1;
|
|
Y2 += 1;
|
|
|
|
const int32 NeighborNum = 4;
|
|
const int32 Iteration = UISettings->ErodeIterationNum;
|
|
const int32 Thickness = UISettings->ErodeSurfaceThickness;
|
|
const int32 LayerNum = LandscapeInfo->Layers.Num();
|
|
|
|
HeightCache.CacheData(X1, Y1, X2, Y2);
|
|
TArray<uint16> HeightData;
|
|
HeightCache.GetCachedData(X1, Y1, X2, Y2, HeightData);
|
|
|
|
TArray<uint8> WeightDatas; // Weight*Layers...
|
|
WeightCache.CacheData(X1, Y1, X2, Y2);
|
|
WeightCache.GetCachedData(X1, Y1, X2, Y2, WeightDatas, LayerNum);
|
|
|
|
// Apply the brush
|
|
uint16 Thresh = UISettings->ErodeThresh;
|
|
int32 WeightMoveThresh = FMath::Min<int32>(FMath::Max<int32>(Thickness >> 2, Thresh), Thickness >> 1);
|
|
|
|
TArray<float> CenterWeights;
|
|
CenterWeights.Empty(LayerNum);
|
|
CenterWeights.AddUninitialized(LayerNum);
|
|
TArray<float> NeighborWeight;
|
|
NeighborWeight.Empty(NeighborNum*LayerNum);
|
|
NeighborWeight.AddUninitialized(NeighborNum*LayerNum);
|
|
|
|
bool bHasChanged = false;
|
|
for (int32 i = 0; i < Iteration; i++)
|
|
{
|
|
bHasChanged = false;
|
|
for (int32 Y = BrushInfo.GetBounds().Min.Y; Y < BrushInfo.GetBounds().Max.Y; Y++)
|
|
{
|
|
const float* BrushScanline = BrushInfo.GetDataPtr(FIntPoint(0, Y));
|
|
|
|
for (int32 X = BrushInfo.GetBounds().Min.X; X < BrushInfo.GetBounds().Max.X; X++)
|
|
{
|
|
const float BrushValue = BrushScanline[X];
|
|
|
|
if (BrushValue > 0.0f)
|
|
{
|
|
int32 Center = (X - X1) + (Y - Y1)*(1 + X2 - X1);
|
|
int32 Neighbor[NeighborNum] = {
|
|
(X - 1 - X1) + (Y - Y1)*(1 + X2 - X1), // -X
|
|
(X + 1 - X1) + (Y - Y1)*(1 + X2 - X1), // +X
|
|
(X - X1) + (Y - 1 - Y1)*(1 + X2 - X1), // -Y
|
|
(X - X1) + (Y + 1 - Y1)*(1 + X2 - X1) }; // +Y
|
|
uint32 SlopeTotal = 0;
|
|
uint16 SlopeMax = Thresh;
|
|
|
|
for (int32 Idx = 0; Idx < NeighborNum; Idx++)
|
|
{
|
|
if (HeightData[Center] > HeightData[Neighbor[Idx]])
|
|
{
|
|
uint16 Slope = HeightData[Center] - HeightData[Neighbor[Idx]];
|
|
if (Slope * BrushValue > Thresh)
|
|
{
|
|
SlopeTotal += Slope;
|
|
if (SlopeMax < Slope)
|
|
{
|
|
SlopeMax = Slope;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SlopeTotal > 0)
|
|
{
|
|
float Softness = 1.0f;
|
|
{
|
|
for (int32 Idx = 0; Idx < LayerNum; Idx++)
|
|
{
|
|
ULandscapeLayerInfoObject* LayerInfo = LandscapeInfo->Layers[Idx].LayerInfoObj;
|
|
if (LayerInfo)
|
|
{
|
|
uint8 Weight = WeightDatas[Center*LayerNum + Idx];
|
|
Softness -= (float)(Weight) / 255.0f * LayerInfo->Hardness;
|
|
}
|
|
}
|
|
}
|
|
if (Softness > 0.0f)
|
|
{
|
|
//Softness = FMath::Clamp<float>(Softness, 0.0f, 1.0f);
|
|
float TotalHeightDiff = 0;
|
|
int32 WeightTransfer = FMath::Min<int32>(WeightMoveThresh, SlopeMax - Thresh);
|
|
for (int32 Idx = 0; Idx < NeighborNum; Idx++)
|
|
{
|
|
float TotalWeight = 0.0f;
|
|
if (HeightData[Center] > HeightData[Neighbor[Idx]])
|
|
{
|
|
uint16 Slope = HeightData[Center] - HeightData[Neighbor[Idx]];
|
|
if (Slope > Thresh)
|
|
{
|
|
float WeightDiff = Softness * UISettings->ToolStrength * Pressure * ((float)Slope / SlopeTotal) * BrushValue;
|
|
//uint16 HeightDiff = (uint16)((SlopeMax - Thresh) * WeightDiff);
|
|
float HeightDiff = (SlopeMax - Thresh) * WeightDiff;
|
|
HeightData[Neighbor[Idx]] += HeightDiff;
|
|
TotalHeightDiff += HeightDiff;
|
|
|
|
if (bWeightApplied)
|
|
{
|
|
for (int32 LayerIdx = 0; LayerIdx < LayerNum; LayerIdx++)
|
|
{
|
|
float CenterWeight = (float)(WeightDatas[Center*LayerNum + LayerIdx]) / 255.0f;
|
|
float Weight = (float)(WeightDatas[Neighbor[Idx] * LayerNum + LayerIdx]) / 255.0f;
|
|
NeighborWeight[Idx*LayerNum + LayerIdx] = Weight*(float)Thickness + CenterWeight*WeightDiff*WeightTransfer; // transferred + original...
|
|
TotalWeight += NeighborWeight[Idx*LayerNum + LayerIdx];
|
|
}
|
|
// Need to normalize weight...
|
|
for (int32 LayerIdx = 0; LayerIdx < LayerNum; LayerIdx++)
|
|
{
|
|
WeightDatas[Neighbor[Idx] * LayerNum + LayerIdx] = (uint8)(255.0f * NeighborWeight[Idx*LayerNum + LayerIdx] / TotalWeight);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HeightData[Center] -= TotalHeightDiff;
|
|
|
|
if (bWeightApplied)
|
|
{
|
|
float TotalWeight = 0.0f;
|
|
float WeightDiff = Softness * UISettings->ToolStrength * Pressure * BrushValue;
|
|
|
|
for (int32 LayerIdx = 0; LayerIdx < LayerNum; LayerIdx++)
|
|
{
|
|
float Weight = (float)(WeightDatas[Center*LayerNum + LayerIdx]) / 255.0f;
|
|
CenterWeights[LayerIdx] = Weight*Thickness - Weight*WeightDiff*WeightTransfer;
|
|
TotalWeight += CenterWeights[LayerIdx];
|
|
}
|
|
// Need to normalize weight...
|
|
for (int32 LayerIdx = 0; LayerIdx < LayerNum; LayerIdx++)
|
|
{
|
|
WeightDatas[Center*LayerNum + LayerIdx] = (uint8)(255.0f * CenterWeights[LayerIdx] / TotalWeight);
|
|
}
|
|
}
|
|
|
|
bHasChanged = true;
|
|
} // if Softness > 0.0f
|
|
} // if SlopeTotal > 0
|
|
}
|
|
}
|
|
}
|
|
if (!bHasChanged)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
float BrushSizeAdjust = 1.0f;
|
|
if (UISettings->BrushRadius < UISettings->MaximumValueRadius)
|
|
{
|
|
BrushSizeAdjust = UISettings->BrushRadius / UISettings->MaximumValueRadius;
|
|
}
|
|
|
|
// Make some noise...
|
|
for (int32 Y = BrushInfo.GetBounds().Min.Y; Y < BrushInfo.GetBounds().Max.Y; Y++)
|
|
{
|
|
const float* BrushScanline = BrushInfo.GetDataPtr(FIntPoint(0, Y));
|
|
|
|
for (int32 X = BrushInfo.GetBounds().Min.X; X < BrushInfo.GetBounds().Max.X; X++)
|
|
{
|
|
const float BrushValue = BrushScanline[X];
|
|
|
|
if (BrushValue > 0.0f)
|
|
{
|
|
FNoiseParameter NoiseParam(0, UISettings->ErosionNoiseScale, BrushValue * Thresh * UISettings->ToolStrength * BrushSizeAdjust);
|
|
float PaintAmount = ELandscapeToolNoiseMode::Conversion((ELandscapeToolNoiseMode::Type)UISettings->ErosionNoiseMode.GetValue(), NoiseParam.NoiseAmount, NoiseParam.Sample(X, Y));
|
|
HeightData[(X - X1) + (Y - Y1)*(1 + X2 - X1)] = FLandscapeHeightCache::ClampValue(HeightData[(X - X1) + (Y - Y1)*(1 + X2 - X1)] + PaintAmount);
|
|
}
|
|
}
|
|
}
|
|
|
|
HeightCache.SetCachedData(X1, Y1, X2, Y2, HeightData);
|
|
HeightCache.Flush();
|
|
if (bWeightApplied)
|
|
{
|
|
WeightCache.SetCachedData(X1, Y1, X2, Y2, WeightDatas, LayerNum, ELandscapeLayerPaintingRestriction::None);
|
|
}
|
|
WeightCache.Flush();
|
|
}
|
|
};
|
|
|
|
class FLandscapeToolErosion : public FLandscapeToolErosionBase<FLandscapeToolStrokeErosion>
|
|
{
|
|
public:
|
|
FLandscapeToolErosion(FEdModeLandscape* InEdMode)
|
|
: FLandscapeToolErosionBase(InEdMode)
|
|
{
|
|
}
|
|
|
|
virtual const TCHAR* GetToolName() override { return TEXT("Erosion"); }
|
|
virtual FText GetDisplayName() override { return NSLOCTEXT("UnrealEd", "LandscapeMode_Erosion", "Erosion"); };
|
|
|
|
};
|
|
|
|
//
|
|
// FLandscapeToolHydraErosion
|
|
//
|
|
|
|
class FLandscapeToolStrokeHydraErosion : public FLandscapeToolStrokeErosionBase
|
|
{
|
|
public:
|
|
FLandscapeToolStrokeHydraErosion(FEdModeLandscape* InEdMode, const FLandscapeToolTarget& InTarget)
|
|
: FLandscapeToolStrokeErosionBase(InEdMode, InTarget)
|
|
{
|
|
}
|
|
|
|
void Apply(FEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray<FLandscapeToolMousePosition>& MousePositions)
|
|
{
|
|
if (!LandscapeInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Get list of verts to update
|
|
FLandscapeBrushData BrushInfo = Brush->ApplyBrush(MousePositions);
|
|
if (!BrushInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int32 X1, Y1, X2, Y2;
|
|
BrushInfo.GetInclusiveBounds(X1, Y1, X2, Y2);
|
|
|
|
// Tablet pressure
|
|
float Pressure = ViewportClient->Viewport->IsPenActive() ? ViewportClient->Viewport->GetTabletPressure() : 1.0f;
|
|
|
|
// expand the area by one vertex in each direction to ensure normals are calculated correctly
|
|
X1 -= 1;
|
|
Y1 -= 1;
|
|
X2 += 1;
|
|
Y2 += 1;
|
|
|
|
const int32 LayerNum = LandscapeInfo->Layers.Num();
|
|
|
|
const int32 Iteration = UISettings->HErodeIterationNum;
|
|
const uint16 RainAmount = UISettings->RainAmount;
|
|
const float DissolvingRatio = 0.07 * UISettings->ToolStrength * Pressure; //0.01;
|
|
const float EvaporateRatio = 0.5;
|
|
const float SedimentCapacity = 0.10 * UISettings->SedimentCapacity; //DissolvingRatio; //0.01;
|
|
|
|
HeightCache.CacheData(X1, Y1, X2, Y2);
|
|
TArray<uint16> HeightData;
|
|
HeightCache.GetCachedData(X1, Y1, X2, Y2, HeightData);
|
|
|
|
// Apply the brush
|
|
TArray<uint16> WaterData;
|
|
WaterData.Empty((1 + X2 - X1)*(1 + Y2 - Y1));
|
|
WaterData.AddZeroed((1 + X2 - X1)*(1 + Y2 - Y1));
|
|
TArray<uint16> SedimentData;
|
|
SedimentData.Empty((1 + X2 - X1)*(1 + Y2 - Y1));
|
|
SedimentData.AddZeroed((1 + X2 - X1)*(1 + Y2 - Y1));
|
|
|
|
// Only initial raining works better...
|
|
FNoiseParameter NoiseParam(0, UISettings->RainDistScale, RainAmount);
|
|
for (int32 Y = BrushInfo.GetBounds().Min.Y; Y < BrushInfo.GetBounds().Max.Y; Y++)
|
|
{
|
|
const float* BrushScanline = BrushInfo.GetDataPtr(FIntPoint(0, Y));
|
|
auto* WaterDataScanline = WaterData.GetData() + (Y - Y1) * (X2 - X1 + 1) + (0 - X1);
|
|
|
|
for (int32 X = BrushInfo.GetBounds().Min.X; X < BrushInfo.GetBounds().Max.X; X++)
|
|
{
|
|
const float BrushValue = BrushScanline[X];
|
|
|
|
if (BrushValue >= 1.0f)
|
|
{
|
|
float PaintAmount = ELandscapeToolNoiseMode::Conversion((ELandscapeToolNoiseMode::Type)UISettings->RainDistMode.GetValue(), NoiseParam.NoiseAmount, NoiseParam.Sample(X, Y));
|
|
if (PaintAmount > 0) // Raining only for positive region...
|
|
WaterDataScanline[X] += PaintAmount;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int32 i = 0; i < Iteration; i++)
|
|
{
|
|
bool bWaterExist = false;
|
|
for (int32 Y = BrushInfo.GetBounds().Min.Y; Y < BrushInfo.GetBounds().Max.Y; Y++)
|
|
{
|
|
const float* BrushScanline = BrushInfo.GetDataPtr(FIntPoint(0, Y));
|
|
|
|
for (int32 X = BrushInfo.GetBounds().Min.X; X < BrushInfo.GetBounds().Max.X; X++)
|
|
{
|
|
const float BrushValue = BrushScanline[X];
|
|
|
|
if (BrushValue > 0.0f)
|
|
{
|
|
int32 Center = (X - X1) + (Y - Y1)*(1 + X2 - X1);
|
|
|
|
const int32 NeighborNum = 8;
|
|
int32 Neighbor[NeighborNum] = {
|
|
(X - 1 - X1) + (Y - Y1)*(1 + X2 - X1), // -X
|
|
(X + 1 - X1) + (Y - Y1)*(1 + X2 - X1), // +X
|
|
(X - X1) + (Y - 1 - Y1)*(1 + X2 - X1), // -Y
|
|
(X - X1) + (Y + 1 - Y1)*(1 + X2 - X1), // +Y
|
|
(X - 1 - X1) + (Y - 1 - Y1)*(1 + X2 - X1), // -X -Y
|
|
(X + 1 - X1) + (Y + 1 - Y1)*(1 + X2 - X1), // +X +Y
|
|
(X + 1 - X1) + (Y - 1 - Y1)*(1 + X2 - X1), // +X -Y
|
|
(X - 1 - X1) + (Y + 1 - Y1)*(1 + X2 - X1) }; // -X +Y
|
|
|
|
// Dissolving...
|
|
float DissolvedAmount = DissolvingRatio * WaterData[Center] * BrushValue;
|
|
if (DissolvedAmount > 0 && HeightData[Center] >= DissolvedAmount)
|
|
{
|
|
HeightData[Center] -= DissolvedAmount;
|
|
SedimentData[Center] += DissolvedAmount;
|
|
}
|
|
|
|
uint32 TotalHeightDiff = 0;
|
|
uint32 TotalAltitudeDiff = 0;
|
|
uint32 AltitudeDiff[NeighborNum] = { 0 };
|
|
uint32 TotalWaterDiff = 0;
|
|
uint32 TotalSedimentDiff = 0;
|
|
|
|
uint32 Altitude = HeightData[Center] + WaterData[Center];
|
|
float AverageAltitude = 0;
|
|
uint32 LowerNeighbor = 0;
|
|
for (int32 Idx = 0; Idx < NeighborNum; Idx++)
|
|
{
|
|
uint32 NeighborAltitude = HeightData[Neighbor[Idx]] + WaterData[Neighbor[Idx]];
|
|
if (Altitude > NeighborAltitude)
|
|
{
|
|
AltitudeDiff[Idx] = Altitude - NeighborAltitude;
|
|
TotalAltitudeDiff += AltitudeDiff[Idx];
|
|
LowerNeighbor++;
|
|
AverageAltitude += NeighborAltitude;
|
|
if (HeightData[Center] > HeightData[Neighbor[Idx]])
|
|
{
|
|
TotalHeightDiff += HeightData[Center] - HeightData[Neighbor[Idx]];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AltitudeDiff[Idx] = 0;
|
|
}
|
|
}
|
|
|
|
// Water Transfer
|
|
if (LowerNeighbor > 0)
|
|
{
|
|
AverageAltitude /= (LowerNeighbor);
|
|
// This is not mathematically correct, but makes good result
|
|
if (TotalHeightDiff)
|
|
{
|
|
AverageAltitude *= (1.0f - 0.1 * UISettings->ToolStrength * Pressure);
|
|
//AverageAltitude -= 4000.0f * UISettings->ToolStrength;
|
|
}
|
|
|
|
uint32 WaterTransfer = FMath::Min<uint32>(WaterData[Center], Altitude - (uint32)AverageAltitude) * BrushValue;
|
|
|
|
for (int32 Idx = 0; Idx < NeighborNum; Idx++)
|
|
{
|
|
if (AltitudeDiff[Idx] > 0)
|
|
{
|
|
uint32 WaterDiff = (uint32)(WaterTransfer * (float)AltitudeDiff[Idx] / TotalAltitudeDiff);
|
|
WaterData[Neighbor[Idx]] += WaterDiff;
|
|
TotalWaterDiff += WaterDiff;
|
|
uint32 SedimentDiff = (uint32)(SedimentData[Center] * (float)WaterDiff / WaterData[Center]);
|
|
SedimentData[Neighbor[Idx]] += SedimentDiff;
|
|
TotalSedimentDiff += SedimentDiff;
|
|
}
|
|
}
|
|
|
|
WaterData[Center] -= TotalWaterDiff;
|
|
SedimentData[Center] -= TotalSedimentDiff;
|
|
}
|
|
|
|
// evaporation
|
|
if (WaterData[Center] > 0)
|
|
{
|
|
bWaterExist = true;
|
|
WaterData[Center] = (uint16)(WaterData[Center] * (1.0f - EvaporateRatio));
|
|
float SedimentCap = SedimentCapacity*WaterData[Center];
|
|
float SedimentDiff = SedimentData[Center] - SedimentCap;
|
|
if (SedimentDiff > 0)
|
|
{
|
|
SedimentData[Center] -= SedimentDiff;
|
|
HeightData[Center] = FMath::Clamp<uint16>(HeightData[Center] + SedimentDiff, 0, 65535);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bWaterExist)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (UISettings->bHErosionDetailSmooth)
|
|
{
|
|
//LowPassFilter<uint16>(X1, Y1, X2, Y2, BrushInfo, HeightData, UISettings->HErosionDetailScale, UISettings->ToolStrength * Pressure);
|
|
LowPassFilter<uint16>(X1, Y1, X2, Y2, BrushInfo, HeightData, UISettings->HErosionDetailScale, 1.0f);
|
|
}
|
|
|
|
HeightCache.SetCachedData(X1, Y1, X2, Y2, HeightData);
|
|
HeightCache.Flush();
|
|
}
|
|
};
|
|
|
|
class FLandscapeToolHydraErosion : public FLandscapeToolErosionBase<FLandscapeToolStrokeHydraErosion>
|
|
{
|
|
public:
|
|
FLandscapeToolHydraErosion(FEdModeLandscape* InEdMode)
|
|
: FLandscapeToolErosionBase(InEdMode)
|
|
{
|
|
}
|
|
|
|
virtual const TCHAR* GetToolName() override { return TEXT("HydraErosion"); } // formerly HydraulicErosion
|
|
virtual FText GetDisplayName() override { return NSLOCTEXT("UnrealEd", "LandscapeMode_HydraErosion", "Hydraulic Erosion"); };
|
|
|
|
};
|
|
|
|
//
|
|
// Toolset initialization
|
|
//
|
|
void FEdModeLandscape::InitializeTool_Erosion()
|
|
{
|
|
auto Tool_Erosion = MakeUnique<FLandscapeToolErosion>(this);
|
|
Tool_Erosion->ValidBrushes.Add("BrushSet_Circle");
|
|
Tool_Erosion->ValidBrushes.Add("BrushSet_Alpha");
|
|
Tool_Erosion->ValidBrushes.Add("BrushSet_Pattern");
|
|
LandscapeTools.Add(MoveTemp(Tool_Erosion));
|
|
}
|
|
|
|
void FEdModeLandscape::InitializeTool_HydraErosion()
|
|
{
|
|
auto Tool_HydraErosion = MakeUnique<FLandscapeToolHydraErosion>(this);
|
|
Tool_HydraErosion->ValidBrushes.Add("BrushSet_Circle");
|
|
Tool_HydraErosion->ValidBrushes.Add("BrushSet_Alpha");
|
|
Tool_HydraErosion->ValidBrushes.Add("BrushSet_Pattern");
|
|
LandscapeTools.Add(MoveTemp(Tool_HydraErosion));
|
|
}
|