// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. #include "LandscapeEditorPrivatePCH.h" #include "ObjectTools.h" #include "LandscapeEdMode.h" #include "ScopedTransaction.h" #include "Landscape/LandscapeEdit.h" #include "Landscape/LandscapeRender.h" #include "Landscape/LandscapeDataAccess.h" #include "Landscape/LandscapeSplineProxies.h" #include "LandscapeEditorModule.h" #include "Editor/PropertyEditor/Public/PropertyEditorModule.h" #include "LandscapeEdModeTools.h" const int32 FNoiseParameter::Permutations[256] = { 151,160,137,91,90,15, 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 }; // // FLandscapeToolPaintBase // template class FLandscapeToolPaintBase : public FLandscapeToolBase { public: FLandscapeToolPaintBase(FEdModeLandscape* InEdMode) : FLandscapeToolBase(InEdMode) {} virtual bool IsValidForTarget(const FLandscapeToolTarget& Target) { return Target.TargetType == TToolTarget::TargetType; } }; template class FLandscapeToolStrokePaintBase { public: FLandscapeToolStrokePaintBase(FEdModeLandscape* InEdMode, const FLandscapeToolTarget& InTarget) : LandscapeInfo(InTarget.LandscapeInfo.Get()) , Cache(InTarget) { } virtual void Apply(FLevelEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray& MousePositions) = 0; protected: typename ToolTarget::CacheClass Cache; class ULandscapeInfo* LandscapeInfo; }; // // FLandscapeToolPaint // #define DATA_AT(Array, X, Y) ((Array)[(X-X1) + (Y-Y1)*(1+X2-X1)]) template class FLandscapeToolStrokePaint : public FLandscapeToolStrokePaintBase { TMap TotalInfluenceMap; // amount of time and weight the brush has spent on each vertex. public: FLandscapeToolStrokePaint(FEdModeLandscape* InEdMode, const FLandscapeToolTarget& InTarget) : FLandscapeToolStrokePaintBase(InEdMode, InTarget) {} virtual void Apply(FLevelEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray& MousePositions) OVERRIDE { // Get list of verts to update TMap BrushInfo; int32 X1, Y1, X2, Y2; if( !Brush->ApplyBrush(MousePositions, BrushInfo, X1, Y1, X2, Y2) || MousePositions.Num()==0 ) { return; } // Tablet pressure float Pressure = ViewportClient->Viewport->IsPenActive() ? ViewportClient->Viewport->GetTabletPressure() : 1.f; // expand the area by one vertex in each direction to ensure normals are calculated correctly X1 -= 1; Y1 -= 1; X2 += 1; Y2 += 1; this->Cache.CacheData(X1,Y1,X2,Y2); // Invert when holding Shift bool bInvert = MousePositions[MousePositions.Num()-1].bShiftDown; //UE_LOG(LogLandscape, Log, TEXT("bInvert = %d"), bInvert); bool bUseClayBrush = UISettings->bUseClayBrush && ToolTarget::TargetType == ELandscapeToolTargetType::Heightmap; bool bUseWeightTargetValue = UISettings->bUseWeightTargetValue && ToolTarget::TargetType == ELandscapeToolTargetType::Weightmap; // The data we'll be writing to TArray Data; this->Cache.GetCachedData(X1,Y1,X2,Y2,Data); // The source data we use for editing. // For heightmaps we use a cached snapshot, for weightmaps we use the live data. TArray* SourceDataArrayPtr = &Data; TArray OriginalData; if( ToolTarget::TargetType == ELandscapeToolTargetType::Heightmap ) { // Heightmaps use the original data rather than the data edited during the stroke. this->Cache.GetOriginalData(X1,Y1,X2,Y2,OriginalData); SourceDataArrayPtr = &OriginalData; } else if( !bUseWeightTargetValue ) { // When painting weights (and not using target value mode), we use a source value that tends more // to the current value as we paint over the same region multiple times. this->Cache.GetOriginalData(X1,Y1,X2,Y2,OriginalData); SourceDataArrayPtr = &OriginalData; for( int32 Y=Y1;Y( SourceValue, CurrentValue, FMath::Min(VertexInfluence * 0.05f, 1.f) ); } } } FMatrix ToWorld = ToolTarget::ToWorldMatrix(this->LandscapeInfo); FMatrix FromWorld = ToolTarget::FromWorldMatrix(this->LandscapeInfo); // Adjust strength based on brush size and drawscale, so strength 1 = one hemisphere float AdjustedStrength = ToolTarget::StrengthMultiplier(this->LandscapeInfo, UISettings->BrushRadius); typename ToolTarget::CacheClass::DataType DestValue = ToolTarget::CacheClass::ClampValue(255.f * UISettings->WeightTargetValue); FPlane BrushPlane; TArray Normals; if( bUseClayBrush ) { // Calculate normals for brush verts in data space Normals.Empty(OriginalData.Num()); Normals.AddZeroed(OriginalData.Num()); for( int32 Y=Y1;Y 0.f ) { AveragePoint /= TotalWeight; AverageNormal = AverageNormal.SafeNormal(); } // Convert to world space FVector AverageLocation = ToWorld.TransformPosition( AveragePoint ); FVector StrengthVector = ToWorld.TransformVector(FVector(0,0,UISettings->ToolStrength * Pressure * AdjustedStrength)); // Brush pushes out in the normal direction FVector OffsetVector = AverageNormal * StrengthVector.Z; if( bInvert ) { OffsetVector *= -1; } // World space brush plane BrushPlane = FPlane( AverageLocation + OffsetVector, AverageNormal ); } // Apply the brush for( auto It = BrushInfo.CreateIterator(); It; ++It ) { int32 X, Y; ALandscape::UnpackKey(It.Key(), X, Y); // Update influence map float VertexInfluence = TotalInfluenceMap.FindRef(It.Key()); TotalInfluenceMap.Add( It.Key(), VertexInfluence + It.Value() ); float PaintAmount = It.Value() * UISettings->ToolStrength * Pressure * AdjustedStrength; typename ToolTarget::CacheClass::DataType& CurrentValue = DATA_AT(Data,X,Y); const typename ToolTarget::CacheClass::DataType& SourceValue = DATA_AT(*SourceDataArrayPtr,X,Y); if( bUseWeightTargetValue ) { if( bInvert ) { CurrentValue = FMath::Lerp( CurrentValue, DestValue, PaintAmount / AdjustedStrength ); } else { CurrentValue = FMath::Lerp( CurrentValue, DestValue, PaintAmount / AdjustedStrength ); } } else if( bUseClayBrush ) { // Brush application starts from original world location at start of stroke FVector WorldLoc = ToWorld.TransformPosition(FVector(X,Y,SourceValue)); // Calculate new location on the brush plane WorldLoc.Z = (BrushPlane.W - BrushPlane.X*WorldLoc.X - BrushPlane.Y*WorldLoc.Y) / BrushPlane.Z; // Painted amount lerps based on brush falloff. float PaintValue = FMath::Lerp( (float)SourceValue, FromWorld.TransformPosition(WorldLoc).Z, It.Value() ); if( bInvert ) { CurrentValue = ToolTarget::CacheClass::ClampValue( FMath::Min(FMath::RoundToInt(PaintValue), CurrentValue) ); } else { CurrentValue = ToolTarget::CacheClass::ClampValue( FMath::Max(FMath::RoundToInt(PaintValue), CurrentValue) ); } } else { if( bInvert ) { CurrentValue = ToolTarget::CacheClass::ClampValue( FMath::Min(SourceValue - FMath::RoundToInt(PaintAmount), CurrentValue) ); } else { CurrentValue = ToolTarget::CacheClass::ClampValue( FMath::Max(SourceValue + FMath::RoundToInt(PaintAmount), CurrentValue) ); } } } this->Cache.SetCachedData(X1,Y1,X2,Y2,Data, UISettings->PaintingRestriction); this->Cache.Flush(); } #undef DATA_AT }; template class FLandscapeToolPaint : public FLandscapeToolPaintBase > { public: FLandscapeToolPaint(class FEdModeLandscape* InEdMode) : FLandscapeToolPaintBase >(InEdMode) {} virtual const TCHAR* GetToolName() OVERRIDE { return TEXT("Paint"); } virtual FText GetDisplayName() OVERRIDE { return NSLOCTEXT("UnrealEd", "LandscapeMode_Paint", "Paint"); }; }; // // FLandscapeToolSmooth // template class FLandscapeToolStrokeSmooth : public FLandscapeToolStrokePaintBase { public: FLandscapeToolStrokeSmooth(FEdModeLandscape* InEdMode, const FLandscapeToolTarget& InTarget) : FLandscapeToolStrokePaintBase(InEdMode, InTarget) {} virtual void Apply(FLevelEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray& MousePositions) OVERRIDE { if (!this->LandscapeInfo) return; // Get list of verts to update TMap BrushInfo; int32 X1, Y1, X2, Y2; if (!Brush->ApplyBrush(MousePositions, BrushInfo, X1, Y1, X2, Y2)) { return; } // Tablet pressure float Pressure = ViewportClient->Viewport->IsPenActive() ? ViewportClient->Viewport->GetTabletPressure() : 1.f; // expand the area by one vertex in each direction to ensure normals are calculated correctly X1 -= 1; Y1 -= 1; X2 += 1; Y2 += 1; this->Cache.CacheData(X1,Y1,X2,Y2); TArray Data; this->Cache.GetCachedData(X1,Y1,X2,Y2,Data); // Apply the brush if (UISettings->bDetailSmooth) { LowPassFilter(X1, Y1, X2, Y2, BrushInfo, Data, UISettings->DetailScale, UISettings->ToolStrength * Pressure); } else { // Filter size is SmoothFilterKernelScale * BrushSize, But avoids overflow value or under 1 int32 HalfFilterSize = FMath::Clamp(UISettings->SmoothFilterKernelScale * FMath::Max(Y2-Y1+1, X2-X1+1) * 0.25f, 1, 127); for( auto It = BrushInfo.CreateIterator(); It; ++It ) { int32 X, Y; ALandscape::UnpackKey(It.Key(), X, Y); if( It.Value() > 0.f ) { int32 FilterValue = 0; int32 FilterSamplingNumber = 0; for( int32 y = Y - HalfFilterSize; y <= Y + HalfFilterSize; y++ ) { int32 YY = FMath::Clamp(y, Y1, Y2); for( int32 x = X - HalfFilterSize; x <= X + HalfFilterSize; x++ ) { int32 XX = FMath::Clamp(x, X1, X2); if (BrushInfo.Find(FIntPoint(XX, YY))) { FilterValue += Data[(XX-X1) + (YY-Y1)*(1+X2-X1)]; FilterSamplingNumber++; } } } FilterValue /= FilterSamplingNumber; int32 HeightDataIndex = (X-X1) + (Y-Y1)*(1+X2-X1); Data[HeightDataIndex] = FMath::Lerp( Data[HeightDataIndex], (typename ToolTarget::CacheClass::DataType)FilterValue, It.Value() * UISettings->ToolStrength * Pressure ); } } } this->Cache.SetCachedData(X1,Y1,X2,Y2,Data, UISettings->PaintingRestriction); this->Cache.Flush(); } }; template class FLandscapeToolSmooth : public FLandscapeToolPaintBase > { public: FLandscapeToolSmooth(class FEdModeLandscape* InEdMode) : FLandscapeToolPaintBase >(InEdMode) {} virtual const TCHAR* GetToolName() OVERRIDE { return TEXT("Smooth"); } virtual FText GetDisplayName() OVERRIDE { return NSLOCTEXT("UnrealEd", "LandscapeMode_Smooth", "Smooth"); }; }; // // FLandscapeToolFlatten // template class FLandscapeToolStrokeFlatten : public FLandscapeToolStrokePaintBase { typename ToolTarget::CacheClass::DataType FlattenHeight; FVector FlattenNormal; float FlattenPlaneDist; bool bInitializedFlattenHeight; bool bTargetIsHeightmap; public: FLandscapeToolStrokeFlatten(FEdModeLandscape* InEdMode, const FLandscapeToolTarget& InTarget) : FLandscapeToolStrokePaintBase(InEdMode, InTarget) , bInitializedFlattenHeight(false) , bTargetIsHeightmap(InTarget.TargetType == ELandscapeToolTargetType::Heightmap) { if (InEdMode->UISettings->bUseFlattenTarget && bTargetIsHeightmap) { FTransform LocalToWorld = InTarget.LandscapeInfo->GetLandscapeProxy()->ActorToWorld(); float Height = (InEdMode->UISettings->FlattenTarget - LocalToWorld.GetTranslation().Z) / LocalToWorld.GetScale3D().Z; FlattenHeight = LandscapeDataAccess::GetTexHeight(Height); bInitializedFlattenHeight = true; } } virtual void Apply(FLevelEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray& MousePositions) OVERRIDE { if (!this->LandscapeInfo) return; if (!bInitializedFlattenHeight || (UISettings->bPickValuePerApply && bTargetIsHeightmap)) { bInitializedFlattenHeight = false; float FlattenX = MousePositions[0].PositionX; float FlattenY = MousePositions[0].PositionY; int32 FlattenHeightX = FMath::FloorToInt(FlattenX); int32 FlattenHeightY = FMath::FloorToInt(FlattenY); this->Cache.CacheData(FlattenHeightX,FlattenHeightY,FlattenHeightX+1,FlattenHeightY+1); float HeightValue = this->Cache.GetValue(FlattenX, FlattenY); FlattenHeight = HeightValue; if (UISettings->bUseSlopeFlatten && bTargetIsHeightmap) { FlattenNormal = this->Cache.GetNormal(FlattenHeightX, FlattenHeightY); FlattenPlaneDist = -(FlattenNormal | FVector(FlattenX, FlattenY, HeightValue) ); } bInitializedFlattenHeight = true; } // Get list of verts to update TMap BrushInfo; int32 X1, Y1, X2, Y2; if (!Brush->ApplyBrush(MousePositions, BrushInfo, X1, Y1, X2, Y2)) { return; } // Tablet pressure float Pressure = ViewportClient->Viewport->IsPenActive() ? ViewportClient->Viewport->GetTabletPressure() : 1.f; // expand the area by one vertex in each direction to ensure normals are calculated correctly X1 -= 1; Y1 -= 1; X2 += 1; Y2 += 1; this->Cache.CacheData(X1,Y1,X2,Y2); TArray HeightData; this->Cache.GetCachedData(X1,Y1,X2,Y2,HeightData); // Apply the brush for( auto It = BrushInfo.CreateIterator(); It; ++It ) { int32 X, Y; ALandscape::UnpackKey(It.Key(), X, Y); if( It.Value() > 0.f ) { int32 HeightDataIndex = (X-X1) + (Y-Y1)*(1+X2-X1); if (!(UISettings->bUseSlopeFlatten && bTargetIsHeightmap)) { int32 Delta = HeightData[HeightDataIndex] - FlattenHeight; switch(UISettings->FlattenMode) { case ELandscapeToolNoiseMode::Add: if (Delta < 0) { HeightData[HeightDataIndex] = FMath::Lerp(HeightData[HeightDataIndex], FlattenHeight, It.Value() * UISettings->ToolStrength * Pressure); } break; case ELandscapeToolNoiseMode::Sub: if (Delta > 0) { HeightData[HeightDataIndex] = FMath::Lerp(HeightData[HeightDataIndex], FlattenHeight, It.Value() * UISettings->ToolStrength * Pressure); } break; default: case ELandscapeToolNoiseMode::Both: HeightData[HeightDataIndex] = FMath::Lerp( HeightData[HeightDataIndex], FlattenHeight, It.Value() * UISettings->ToolStrength * Pressure ); break; } } else { typename ToolTarget::CacheClass::DataType DestValue = -( FlattenNormal.X * X + FlattenNormal.Y * Y + FlattenPlaneDist ) / FlattenNormal.Z; //float PlaneDist = FlattenNormal | FVector(X, Y, HeightData(HeightDataIndex)) + FlattenPlaneDist; float PlaneDist = HeightData[HeightDataIndex] - DestValue; DestValue = HeightData[HeightDataIndex] - PlaneDist * It.Value() * UISettings->ToolStrength * Pressure; switch(UISettings->FlattenMode) { case ELandscapeToolNoiseMode::Add: if (PlaneDist < 0) { HeightData[HeightDataIndex] = FMath::Lerp( HeightData[HeightDataIndex], DestValue, It.Value() * UISettings->ToolStrength * Pressure ); } break; case ELandscapeToolNoiseMode::Sub: if (PlaneDist > 0) { HeightData[HeightDataIndex] = FMath::Lerp( HeightData[HeightDataIndex], DestValue, It.Value() * UISettings->ToolStrength * Pressure ); } break; default: case ELandscapeToolNoiseMode::Both: HeightData[HeightDataIndex] = FMath::Lerp( HeightData[HeightDataIndex], DestValue, It.Value() * UISettings->ToolStrength * Pressure ); break; } } } } this->Cache.SetCachedData(X1,Y1,X2,Y2,HeightData, UISettings->PaintingRestriction); this->Cache.Flush(); } }; template class FLandscapeToolFlatten : public FLandscapeToolPaintBase> { protected: FVector LastMousePosition; UStaticMesh* PlaneMesh; UStaticMeshComponent* MeshComponent; public: FLandscapeToolFlatten(class FEdModeLandscape* InEdMode) : FLandscapeToolPaintBase >(InEdMode) , LastMousePosition(FVector::ZeroVector) , PlaneMesh(LoadObject(NULL, TEXT("/Engine/EditorLandscapeResources/FlattenPlaneMesh.FlattenPlaneMesh"))) , MeshComponent(NULL) { check(PlaneMesh); } virtual const TCHAR* GetToolName() OVERRIDE { return TEXT("Flatten"); } virtual FText GetDisplayName() OVERRIDE { return NSLOCTEXT("UnrealEd", "LandscapeMode_Flatten", "Flatten"); }; virtual void Tick(FLevelEditorViewportClient* ViewportClient,float DeltaTime) { bool bShowGrid = this->EdMode->UISettings->bUseFlattenTarget && this->EdMode->CurrentToolTarget.TargetType == ELandscapeToolTargetType::Heightmap && this->EdMode->UISettings->bShowFlattenTargetPreview; MeshComponent->SetVisibility(bShowGrid); } virtual bool MouseMove(FLevelEditorViewportClient* ViewportClient, FViewport* Viewport, int32 x, int32 y) OVERRIDE { bool bResult = FLandscapeToolPaintBase>::MouseMove(ViewportClient, Viewport, x, y); if (ViewportClient->IsLevelEditorClient() && MeshComponent != NULL) { this->EdMode->LandscapeMouseTrace((FLevelEditorViewportClient*)ViewportClient, x, y, LastMousePosition); const FTransform LocalToWorld = this->EdMode->CurrentToolTarget.LandscapeInfo->GetLandscapeProxy()->ActorToWorld(); FVector Origin; Origin.X = FMath::RoundToFloat(LastMousePosition.X); Origin.Y = FMath::RoundToFloat(LastMousePosition.Y); Origin.Z = (FMath::RoundToFloat((this->EdMode->UISettings->FlattenTarget - LocalToWorld.GetTranslation().Z) / LocalToWorld.GetScale3D().Z * LANDSCAPE_INV_ZSCALE) - 0.1f) * LANDSCAPE_ZSCALE; MeshComponent->SetRelativeLocation(Origin, false); } return bResult; } virtual void EnterTool() { FLandscapeToolPaintBase>::EnterTool(); ALandscapeProxy* LandscapeProxy = this->EdMode->CurrentToolTarget.LandscapeInfo->GetLandscapeProxy(); MeshComponent = ConstructObject(UStaticMeshComponent::StaticClass(), LandscapeProxy, NAME_None, RF_Transient); MeshComponent->StaticMesh = PlaneMesh; MeshComponent->AttachTo(LandscapeProxy->GetRootComponent()); MeshComponent->RegisterComponent(); bool bShowGrid = this->EdMode->UISettings->bUseFlattenTarget && this->EdMode->CurrentToolTarget.TargetType == ELandscapeToolTargetType::Heightmap && this->EdMode->UISettings->bShowFlattenTargetPreview; MeshComponent->SetVisibility(bShowGrid); // Try to set a sane initial location for the preview grid const FTransform LocalToWorld = this->EdMode->CurrentToolTarget.LandscapeInfo->GetLandscapeProxy()->GetRootComponent()->GetComponentToWorld(); FVector Origin = FVector::ZeroVector; Origin.Z = (FMath::RoundToFloat((this->EdMode->UISettings->FlattenTarget - LocalToWorld.GetTranslation().Z) / LocalToWorld.GetScale3D().Z * LANDSCAPE_INV_ZSCALE) - 0.1f) * LANDSCAPE_ZSCALE; MeshComponent->SetRelativeLocation(Origin, false); } virtual void ExitTool() { MeshComponent->DetachFromParent(); MeshComponent->DestroyComponent(); } }; // // FLandscapeToolNoise // template class FLandscapeToolStrokeNoise : public FLandscapeToolStrokePaintBase { public: FLandscapeToolStrokeNoise(FEdModeLandscape* InEdMode, const FLandscapeToolTarget& InTarget) : FLandscapeToolStrokePaintBase(InEdMode, InTarget) {} virtual void Apply(FLevelEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray& MousePositions) OVERRIDE { if (!this->LandscapeInfo) return; // Get list of verts to update TMap BrushInfo; int32 X1, Y1, X2, Y2; if (!Brush->ApplyBrush(MousePositions, BrushInfo, X1, Y1, X2, Y2)) { return; } // Tablet pressure float Pressure = ViewportClient->Viewport->IsPenActive() ? ViewportClient->Viewport->GetTabletPressure() : 1.f; // expand the area by one vertex in each direction to ensure normals are calculated correctly X1 -= 1; Y1 -= 1; X2 += 1; Y2 += 1; this->Cache.CacheData(X1,Y1,X2,Y2); TArray Data; this->Cache.GetCachedData(X1,Y1,X2,Y2,Data); float BrushSizeAdjust = 1.0f; if (ToolTarget::TargetType != ELandscapeToolTargetType::Weightmap && UISettings->BrushRadius < UISettings->MaximumValueRadius) { BrushSizeAdjust = UISettings->BrushRadius / UISettings->MaximumValueRadius; } bool bUseWeightTargetValue = UISettings->bUseWeightTargetValue && ToolTarget::TargetType == ELandscapeToolTargetType::Weightmap; // Apply the brush for( auto It = BrushInfo.CreateIterator(); It; ++It ) { int32 X, Y; ALandscape::UnpackKey(It.Key(), X, Y); if( It.Value() > 0.f ) { float OriginalValue = Data[(X-X1) + (Y-Y1)*(1+X2-X1)]; if (bUseWeightTargetValue) { FNoiseParameter NoiseParam(0, UISettings->NoiseScale, 255.f / 2.f); float DestValue = ELandscapeToolNoiseMode::Conversion(ELandscapeToolNoiseMode::Add, NoiseParam.NoiseAmount, NoiseParam.Sample(X, Y)) * UISettings->WeightTargetValue; switch (UISettings->NoiseMode) { case ELandscapeToolNoiseMode::Add: if (OriginalValue >= DestValue) { continue; } break; case ELandscapeToolNoiseMode::Sub: DestValue += (1.f - UISettings->WeightTargetValue) * NoiseParam.NoiseAmount; if (OriginalValue <= DestValue) { continue; } break; } Data[(X-X1) + (Y-Y1)*(1+X2-X1)] = ToolTarget::CacheClass::ClampValue( FMath::RoundToInt(FMath::Lerp( OriginalValue, DestValue, It.Value() * UISettings->ToolStrength * Pressure)) ); } else { float TotalStrength = It.Value() * UISettings->ToolStrength * Pressure * ToolTarget::StrengthMultiplier(this->LandscapeInfo, UISettings->BrushRadius); FNoiseParameter NoiseParam(0, UISettings->NoiseScale, TotalStrength * BrushSizeAdjust); float PaintAmount = ELandscapeToolNoiseMode::Conversion(UISettings->NoiseMode, NoiseParam.NoiseAmount, NoiseParam.Sample(X, Y)); Data[(X-X1) + (Y-Y1)*(1+X2-X1)] = ToolTarget::CacheClass::ClampValue(OriginalValue + PaintAmount); } } } this->Cache.SetCachedData(X1,Y1,X2,Y2,Data, UISettings->PaintingRestriction); this->Cache.Flush(); } }; template class FLandscapeToolNoise : public FLandscapeToolPaintBase > { public: FLandscapeToolNoise(class FEdModeLandscape* InEdMode) : FLandscapeToolPaintBase >(InEdMode) {} virtual const TCHAR* GetToolName() OVERRIDE { return TEXT("Noise"); } virtual FText GetDisplayName() OVERRIDE { return NSLOCTEXT("UnrealEd", "LandscapeMode_Noise", "Noise"); }; }; // // Toolset initialization // void FEdModeLandscape::IntializeToolSet_Paint() { FLandscapeToolSet* ToolSet_Sculpt = new(LandscapeToolSets) FLandscapeToolSet(TEXT("ToolSet_Sculpt")); ToolSet_Sculpt->AddTool(new FLandscapeToolPaint(this)); ToolSet_Sculpt->ValidBrushes.Add("BrushSet_Circle"); ToolSet_Sculpt->ValidBrushes.Add("BrushSet_Alpha"); ToolSet_Sculpt->ValidBrushes.Add("BrushSet_Pattern"); ToolSet_Sculpt->ValidBrushes.Add("BrushSet_Component"); FLandscapeToolSet* ToolSet_Paint = new(LandscapeToolSets) FLandscapeToolSet(TEXT("ToolSet_Paint")); ToolSet_Paint->AddTool(new FLandscapeToolPaint(this)); ToolSet_Paint->ValidBrushes.Add("BrushSet_Circle"); ToolSet_Paint->ValidBrushes.Add("BrushSet_Alpha"); ToolSet_Paint->ValidBrushes.Add("BrushSet_Pattern"); ToolSet_Paint->ValidBrushes.Add("BrushSet_Component"); } void FEdModeLandscape::IntializeToolSet_Smooth() { FLandscapeToolSet* ToolSet_Smooth = new(LandscapeToolSets) FLandscapeToolSet(TEXT("ToolSet_Smooth")); ToolSet_Smooth->AddTool(new FLandscapeToolSmooth(this)); ToolSet_Smooth->AddTool(new FLandscapeToolSmooth(this)); ToolSet_Smooth->ValidBrushes.Add("BrushSet_Circle"); ToolSet_Smooth->ValidBrushes.Add("BrushSet_Alpha"); ToolSet_Smooth->ValidBrushes.Add("BrushSet_Pattern"); } void FEdModeLandscape::IntializeToolSet_Flatten() { FLandscapeToolSet* ToolSet_Flatten = new(LandscapeToolSets) FLandscapeToolSet(TEXT("ToolSet_Flatten")); ToolSet_Flatten->AddTool(new FLandscapeToolFlatten(this)); ToolSet_Flatten->AddTool(new FLandscapeToolFlatten(this)); ToolSet_Flatten->ValidBrushes.Add("BrushSet_Circle"); ToolSet_Flatten->ValidBrushes.Add("BrushSet_Alpha"); ToolSet_Flatten->ValidBrushes.Add("BrushSet_Pattern"); } void FEdModeLandscape::IntializeToolSet_Noise() { FLandscapeToolSet* ToolSet_Noise = new(LandscapeToolSets) FLandscapeToolSet(TEXT("ToolSet_Noise")); ToolSet_Noise->AddTool(new FLandscapeToolNoise(this)); ToolSet_Noise->AddTool(new FLandscapeToolNoise(this)); ToolSet_Noise->ValidBrushes.Add("BrushSet_Circle"); ToolSet_Noise->ValidBrushes.Add("BrushSet_Alpha"); ToolSet_Noise->ValidBrushes.Add("BrushSet_Pattern"); }