2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
/*=============================================================================
LandscapeSpline . cpp
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2014-10-16 05:16:44 -04:00
# include "Landscape.h"
2014-08-04 10:14:05 -04:00
# include "Components/SplineMeshComponent.h"
2014-06-05 16:38:54 -04:00
# include "ShaderParameterUtils.h"
Remove more headers from Engine.h (StaticMeshResources.h, AnimTree.h, SkeletalMeshTypes.h, SkeletalMeshActor.h, LightingBuildOptions.h, PixelFormat.h, WorldComposition.h, VisualLog.h, StaticLighting.h, Lightmap.h, ShadowMap.h, Model.h)
[CL 2086772 by James Golding in Main branch]
2014-05-29 17:21:47 -04:00
# include "StaticMeshResources.h"
2014-10-16 05:16:44 -04:00
# include "LandscapeSplineProxies.h"
# include "LandscapeSplinesComponent.h"
# include "LandscapeSplineControlPoint.h"
# include "LandscapeSplineSegment.h"
# include "ControlPointMeshComponent.h"
2014-10-23 11:49:04 -04:00
# include "Engine/CollisionProfile.h"
2014-10-24 10:40:35 -04:00
# include "Engine/Engine.h"
2014-10-23 11:49:04 -04:00
# include "EngineGlobals.h"
2014-10-16 05:16:44 -04:00
# include "Engine/StaticMesh.h"
# include "Engine/StaticMeshSocket.h"
2015-02-02 07:50:07 -05:00
# if WITH_EDITOR
# include "LandscapeSplineRaster.h"
2015-03-24 13:53:46 -04:00
# include "MessageLog.h"
# include "UObjectToken.h"
2015-02-02 07:50:07 -05:00
# endif
2014-03-14 14:13:41 -04:00
IMPLEMENT_HIT_PROXY ( HLandscapeSplineProxy , HHitProxy ) ;
IMPLEMENT_HIT_PROXY ( HLandscapeSplineProxy_Segment , HLandscapeSplineProxy ) ;
IMPLEMENT_HIT_PROXY ( HLandscapeSplineProxy_ControlPoint , HLandscapeSplineProxy ) ;
IMPLEMENT_HIT_PROXY ( HLandscapeSplineProxy_Tangent , HLandscapeSplineProxy ) ;
2015-03-24 13:53:46 -04:00
# define LOCTEXT_NAMESPACE "Landscape.Splines"
2014-03-14 14:13:41 -04:00
//////////////////////////////////////////////////////////////////////////
// LANDSCAPE SPLINES SCENE PROXY
/** Represents a ULandscapeSplinesComponent to the scene manager. */
# if WITH_EDITOR
class FLandscapeSplinesSceneProxy : public FPrimitiveSceneProxy
{
private :
const FLinearColor SplineColor ;
const UTexture2D * ControlPointSprite ;
2015-01-08 06:56:57 -05:00
const bool bDrawControlPointSprite ;
2014-03-14 14:13:41 -04:00
const bool bDrawFalloff ;
struct FSegmentProxy
{
ULandscapeSplineSegment * Owner ;
TRefCountPtr < HHitProxy > HitProxy ;
TArray < FLandscapeSplineInterpPoint > Points ;
uint32 bSelected : 1 ;
} ;
TArray < FSegmentProxy > Segments ;
struct FControlPointProxy
{
ULandscapeSplineControlPoint * Owner ;
TRefCountPtr < HHitProxy > HitProxy ;
FVector Location ;
TArray < FLandscapeSplineInterpPoint > Points ;
2014-04-02 18:09:23 -04:00
float SpriteScale ;
2014-03-14 14:13:41 -04:00
uint32 bSelected : 1 ;
} ;
TArray < FControlPointProxy > ControlPoints ;
public :
~ FLandscapeSplinesSceneProxy ( )
{
}
FLandscapeSplinesSceneProxy ( ULandscapeSplinesComponent * Component ) :
FPrimitiveSceneProxy ( Component ) ,
SplineColor ( Component - > SplineColor ) ,
ControlPointSprite ( Component - > ControlPointSprite ) ,
2015-01-08 06:56:57 -05:00
bDrawControlPointSprite ( Component - > bShowSplineEditorMesh ) ,
2014-03-14 14:13:41 -04:00
bDrawFalloff ( Component - > bShowSplineEditorMesh )
{
Segments . Reserve ( Component - > Segments . Num ( ) ) ;
2014-05-12 08:40:42 -04:00
for ( ULandscapeSplineSegment * Segment : Component - > Segments )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
FSegmentProxy SegmentProxy ;
SegmentProxy . Owner = Segment ;
2015-03-24 13:53:46 -04:00
SegmentProxy . HitProxy = nullptr ;
2014-05-12 08:40:42 -04:00
SegmentProxy . Points = Segment - > GetPoints ( ) ;
SegmentProxy . bSelected = Segment - > IsSplineSelected ( ) ;
Segments . Add ( SegmentProxy ) ;
2014-03-14 14:13:41 -04:00
}
ControlPoints . Reserve ( Component - > ControlPoints . Num ( ) ) ;
2014-05-12 08:40:42 -04:00
for ( ULandscapeSplineControlPoint * ControlPoint : Component - > ControlPoints )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
FControlPointProxy ControlPointProxy ;
ControlPointProxy . Owner = ControlPoint ;
2015-03-24 13:53:46 -04:00
ControlPointProxy . HitProxy = nullptr ;
2014-05-12 08:40:42 -04:00
ControlPointProxy . Location = ControlPoint - > Location ;
ControlPointProxy . Points = ControlPoint - > GetPoints ( ) ;
ControlPointProxy . SpriteScale = FMath : : Clamp < float > ( ControlPoint - > Width ! = 0 ? ControlPoint - > Width / 2 : ControlPoint - > SideFalloff / 4 , 10 , 1000 ) ;
ControlPointProxy . bSelected = ControlPoint - > IsSplineSelected ( ) ;
ControlPoints . Add ( ControlPointProxy ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-04-01 07:20:55 -04:00
virtual HHitProxy * CreateHitProxies ( UPrimitiveComponent * Component , TArray < TRefCountPtr < HHitProxy > > & OutHitProxies ) override
2014-03-14 14:13:41 -04:00
{
OutHitProxies . Reserve ( OutHitProxies . Num ( ) + Segments . Num ( ) + ControlPoints . Num ( ) ) ;
2014-05-12 08:40:42 -04:00
for ( FSegmentProxy & Segment : Segments )
2014-03-14 14:13:41 -04:00
{
Segment . HitProxy = new HLandscapeSplineProxy_Segment ( Segment . Owner ) ;
OutHitProxies . Add ( Segment . HitProxy ) ;
}
2014-05-12 08:40:42 -04:00
for ( FControlPointProxy & ControlPoint : ControlPoints )
2014-03-14 14:13:41 -04:00
{
ControlPoint . HitProxy = new HLandscapeSplineProxy_ControlPoint ( ControlPoint . Owner ) ;
OutHitProxies . Add ( ControlPoint . HitProxy ) ;
}
2015-03-24 13:53:46 -04:00
return nullptr ;
2014-03-14 14:13:41 -04:00
}
2014-08-12 18:24:52 -04:00
virtual void GetDynamicMeshElements ( const TArray < const FSceneView * > & Views , const FSceneViewFamily & ViewFamily , uint32 VisibilityMap , FMeshElementCollector & Collector ) const override
{
// Slight Depth Bias so that the splines show up when they exactly match the target surface
// e.g. someone playing with splines on a newly-created perfectly-flat landscape
static const float DepthBias = - 0.0001 ;
const FMatrix & LocalToWorld = GetLocalToWorld ( ) ;
const FLinearColor SelectedSplineColor = GEngine - > GetSelectedMaterialColor ( ) ;
2014-11-25 17:56:43 -05:00
const FLinearColor SelectedControlPointSpriteColor = FLinearColor : : White + ( GEngine - > GetSelectedMaterialColor ( ) * GEngine - > SelectionHighlightIntensityBillboards * 10 ) ;
2014-08-12 18:24:52 -04:00
for ( int32 ViewIndex = 0 ; ViewIndex < Views . Num ( ) ; ViewIndex + + )
{
if ( VisibilityMap & ( 1 < < ViewIndex ) )
{
const FSceneView * View = Views [ ViewIndex ] ;
FPrimitiveDrawInterface * PDI = Collector . GetPDI ( ViewIndex ) ;
for ( const FSegmentProxy & Segment : Segments )
{
const FLinearColor SegmentColor = Segment . bSelected ? SelectedSplineColor : SplineColor ;
FLandscapeSplineInterpPoint OldPoint = Segment . Points [ 0 ] ;
OldPoint . Center = LocalToWorld . TransformPosition ( OldPoint . Center ) ;
OldPoint . Left = LocalToWorld . TransformPosition ( OldPoint . Left ) ;
OldPoint . Right = LocalToWorld . TransformPosition ( OldPoint . Right ) ;
OldPoint . FalloffLeft = LocalToWorld . TransformPosition ( OldPoint . FalloffLeft ) ;
OldPoint . FalloffRight = LocalToWorld . TransformPosition ( OldPoint . FalloffRight ) ;
for ( int32 i = 1 ; i < Segment . Points . Num ( ) ; i + + )
{
FLandscapeSplineInterpPoint NewPoint = Segment . Points [ i ] ;
NewPoint . Center = LocalToWorld . TransformPosition ( NewPoint . Center ) ;
NewPoint . Left = LocalToWorld . TransformPosition ( NewPoint . Left ) ;
NewPoint . Right = LocalToWorld . TransformPosition ( NewPoint . Right ) ;
NewPoint . FalloffLeft = LocalToWorld . TransformPosition ( NewPoint . FalloffLeft ) ;
NewPoint . FalloffRight = LocalToWorld . TransformPosition ( NewPoint . FalloffRight ) ;
// Draw lines from the last keypoint.
PDI - > SetHitProxy ( Segment . HitProxy ) ;
// center line
PDI - > DrawLine ( OldPoint . Center , NewPoint . Center , SegmentColor , GetDepthPriorityGroup ( View ) , 0.0f , DepthBias ) ;
// draw sides
PDI - > DrawLine ( OldPoint . Left , NewPoint . Left , SegmentColor , GetDepthPriorityGroup ( View ) , 0.0f , DepthBias ) ;
PDI - > DrawLine ( OldPoint . Right , NewPoint . Right , SegmentColor , GetDepthPriorityGroup ( View ) , 0.0f , DepthBias ) ;
2015-03-24 13:53:46 -04:00
PDI - > SetHitProxy ( nullptr ) ;
2014-08-12 18:24:52 -04:00
// draw falloff sides
if ( bDrawFalloff )
{
DrawDashedLine ( PDI , OldPoint . FalloffLeft , NewPoint . FalloffLeft , SegmentColor , 100 , GetDepthPriorityGroup ( View ) , DepthBias ) ;
DrawDashedLine ( PDI , OldPoint . FalloffRight , NewPoint . FalloffRight , SegmentColor , 100 , GetDepthPriorityGroup ( View ) , DepthBias ) ;
}
OldPoint = NewPoint ;
}
}
for ( const FControlPointProxy & ControlPoint : ControlPoints )
{
2015-01-08 06:56:57 -05:00
const FVector ControlPointLocation = LocalToWorld . TransformPosition ( ControlPoint . Location ) ;
2014-08-12 18:24:52 -04:00
// Draw Sprite
2015-01-08 06:56:57 -05:00
if ( bDrawControlPointSprite )
{
const float ControlPointSpriteScale = LocalToWorld . GetScaleVector ( ) . X * ControlPoint . SpriteScale ;
const FVector ControlPointSpriteLocation = ControlPointLocation + FVector ( 0 , 0 , ControlPointSpriteScale * 0.75f ) ;
const FLinearColor ControlPointSpriteColor = ControlPoint . bSelected ? SelectedControlPointSpriteColor : FLinearColor : : White ;
2014-08-12 18:24:52 -04:00
2015-01-08 06:56:57 -05:00
PDI - > SetHitProxy ( ControlPoint . HitProxy ) ;
2014-08-12 18:24:52 -04:00
2015-01-08 06:56:57 -05:00
PDI - > DrawSprite (
ControlPointSpriteLocation ,
ControlPointSpriteScale ,
ControlPointSpriteScale ,
ControlPointSprite - > Resource ,
ControlPointSpriteColor ,
GetDepthPriorityGroup ( View ) ,
0 , ControlPointSprite - > Resource - > GetSizeX ( ) ,
0 , ControlPointSprite - > Resource - > GetSizeY ( ) ,
SE_BLEND_Masked ) ;
}
2014-08-12 18:24:52 -04:00
// Draw Lines
const FLinearColor ControlPointColor = ControlPoint . bSelected ? SelectedSplineColor : SplineColor ;
if ( ControlPoint . Points . Num ( ) = = 1 )
{
FLandscapeSplineInterpPoint NewPoint = ControlPoint . Points [ 0 ] ;
NewPoint . Center = LocalToWorld . TransformPosition ( NewPoint . Center ) ;
NewPoint . Left = LocalToWorld . TransformPosition ( NewPoint . Left ) ;
NewPoint . Right = LocalToWorld . TransformPosition ( NewPoint . Right ) ;
NewPoint . FalloffLeft = LocalToWorld . TransformPosition ( NewPoint . FalloffLeft ) ;
NewPoint . FalloffRight = LocalToWorld . TransformPosition ( NewPoint . FalloffRight ) ;
// draw end for spline connection
PDI - > DrawPoint ( NewPoint . Center , ControlPointColor , 6.0f , GetDepthPriorityGroup ( View ) ) ;
PDI - > DrawLine ( NewPoint . Left , NewPoint . Center , ControlPointColor , GetDepthPriorityGroup ( View ) , 0.0f , DepthBias ) ;
PDI - > DrawLine ( NewPoint . Right , NewPoint . Center , ControlPointColor , GetDepthPriorityGroup ( View ) , 0.0f , DepthBias ) ;
if ( bDrawFalloff )
{
DrawDashedLine ( PDI , NewPoint . FalloffLeft , NewPoint . Left , ControlPointColor , 100 , GetDepthPriorityGroup ( View ) , DepthBias ) ;
DrawDashedLine ( PDI , NewPoint . FalloffRight , NewPoint . Right , ControlPointColor , 100 , GetDepthPriorityGroup ( View ) , DepthBias ) ;
}
}
else if ( ControlPoint . Points . Num ( ) > = 2 )
{
FLandscapeSplineInterpPoint OldPoint = ControlPoint . Points . Last ( ) ;
//OldPoint.Left = LocalToWorld.TransformPosition(OldPoint.Left);
OldPoint . Right = LocalToWorld . TransformPosition ( OldPoint . Right ) ;
//OldPoint.FalloffLeft = LocalToWorld.TransformPosition(OldPoint.FalloffLeft);
OldPoint . FalloffRight = LocalToWorld . TransformPosition ( OldPoint . FalloffRight ) ;
for ( const FLandscapeSplineInterpPoint & Point : ControlPoint . Points )
{
FLandscapeSplineInterpPoint NewPoint = Point ;
NewPoint . Center = LocalToWorld . TransformPosition ( NewPoint . Center ) ;
NewPoint . Left = LocalToWorld . TransformPosition ( NewPoint . Left ) ;
NewPoint . Right = LocalToWorld . TransformPosition ( NewPoint . Right ) ;
NewPoint . FalloffLeft = LocalToWorld . TransformPosition ( NewPoint . FalloffLeft ) ;
NewPoint . FalloffRight = LocalToWorld . TransformPosition ( NewPoint . FalloffRight ) ;
PDI - > SetHitProxy ( ControlPoint . HitProxy ) ;
// center line
PDI - > DrawLine ( ControlPointLocation , NewPoint . Center , ControlPointColor , GetDepthPriorityGroup ( View ) , 0.0f , DepthBias ) ;
// draw sides
PDI - > DrawLine ( OldPoint . Right , NewPoint . Left , ControlPointColor , GetDepthPriorityGroup ( View ) , 0.0f , DepthBias ) ;
2015-03-24 13:53:46 -04:00
PDI - > SetHitProxy ( nullptr ) ;
2014-08-12 18:24:52 -04:00
// draw falloff sides
if ( bDrawFalloff )
{
DrawDashedLine ( PDI , OldPoint . FalloffRight , NewPoint . FalloffLeft , ControlPointColor , 100 , GetDepthPriorityGroup ( View ) , DepthBias ) ;
}
// draw end for spline connection
PDI - > DrawPoint ( NewPoint . Center , ControlPointColor , 6.0f , GetDepthPriorityGroup ( View ) ) ;
PDI - > DrawLine ( NewPoint . Left , NewPoint . Center , ControlPointColor , GetDepthPriorityGroup ( View ) , 0.0f , DepthBias ) ;
PDI - > DrawLine ( NewPoint . Right , NewPoint . Center , ControlPointColor , GetDepthPriorityGroup ( View ) , 0.0f , DepthBias ) ;
if ( bDrawFalloff )
{
DrawDashedLine ( PDI , NewPoint . FalloffLeft , NewPoint . Left , ControlPointColor , 100 , GetDepthPriorityGroup ( View ) , DepthBias ) ;
DrawDashedLine ( PDI , NewPoint . FalloffRight , NewPoint . Right , ControlPointColor , 100 , GetDepthPriorityGroup ( View ) , DepthBias ) ;
}
//OldPoint = NewPoint;
OldPoint . Right = NewPoint . Right ;
OldPoint . FalloffRight = NewPoint . FalloffRight ;
}
}
}
2015-03-24 13:53:46 -04:00
PDI - > SetHitProxy ( nullptr ) ;
2014-08-12 18:24:52 -04:00
}
}
}
2015-04-01 07:20:55 -04:00
virtual FPrimitiveViewRelevance GetViewRelevance ( const FSceneView * View ) override
2014-03-14 14:13:41 -04:00
{
FPrimitiveViewRelevance Result ;
Result . bDrawRelevance = IsShown ( View ) & & View - > Family - > EngineShowFlags . Splines ;
Result . bDynamicRelevance = true ;
return Result ;
}
2015-04-01 07:20:55 -04:00
virtual uint32 GetMemoryFootprint ( ) const override
2014-03-14 14:13:41 -04:00
{
2014-06-11 06:27:25 -04:00
return sizeof ( * this ) + GetAllocatedSize ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-06-11 06:27:25 -04:00
uint32 GetAllocatedSize ( ) const
2014-03-14 14:13:41 -04:00
{
2014-06-11 06:27:25 -04:00
uint32 AllocatedSize = FPrimitiveSceneProxy : : GetAllocatedSize ( ) + Segments . GetAllocatedSize ( ) + ControlPoints . GetAllocatedSize ( ) ;
2014-05-12 08:40:42 -04:00
for ( const FSegmentProxy & Segment : Segments )
2014-03-14 14:13:41 -04:00
{
AllocatedSize + = Segment . Points . GetAllocatedSize ( ) ;
}
2014-06-11 06:27:25 -04:00
for ( const FControlPointProxy & ControlPoint : ControlPoints )
{
AllocatedSize + = ControlPoint . Points . GetAllocatedSize ( ) ;
}
2014-03-14 14:13:41 -04:00
return AllocatedSize ;
}
} ;
# endif
//////////////////////////////////////////////////////////////////////////
// SPLINE COMPONENT
2014-10-14 10:29:11 -04:00
ULandscapeSplinesComponent : : ULandscapeSplinesComponent ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-03-14 14:13:41 -04:00
{
Mobility = EComponentMobility : : Static ;
# if WITH_EDITORONLY_DATA
SplineResolution = 512 ;
SplineColor = FColor ( 0 , 192 , 48 ) ;
if ( ! IsRunningCommandlet ( ) )
{
// Structure to hold one-time initialization
struct FConstructorStatics
{
ConstructorHelpers : : FObjectFinder < UTexture2D > SpriteTexture ;
ConstructorHelpers : : FObjectFinder < UStaticMesh > SplineEditorMesh ;
FConstructorStatics ( )
: SpriteTexture ( TEXT ( " /Engine/EditorResources/S_Terrain.S_Terrain " ) )
, SplineEditorMesh ( TEXT ( " /Engine/EditorLandscapeResources/SplineEditorMesh " ) )
{
}
} ;
static FConstructorStatics ConstructorStatics ;
ControlPointSprite = ConstructorStatics . SpriteTexture . Object ;
SplineEditorMesh = ConstructorStatics . SplineEditorMesh . Object ;
}
# endif
//RelativeScale3D = FVector(1/100.0f, 1/100.0f, 1/100.0f); // cancel out landscape scale. The scale is set up when component is created, but for a default landscape it's this
}
2014-05-12 08:40:42 -04:00
void ULandscapeSplinesComponent : : CheckSplinesValid ( )
{
# if DO_CHECK
// This shouldn't happen, but it has somehow (TTP #334549) so we have to fix it
ensure ( ! ControlPoints . Contains ( nullptr ) ) ;
ensure ( ! Segments . Contains ( nullptr ) ) ;
// Remove all null control points/segments
ControlPoints . Remove ( nullptr ) ;
Segments . Remove ( nullptr ) ;
// Check for cross-spline connections, as this is a potential source of nulls
2015-03-24 13:53:46 -04:00
// this may be allowed in future, but is not currently
2014-05-12 08:40:42 -04:00
for ( ULandscapeSplineControlPoint * ControlPoint : ControlPoints )
{
ensure ( ControlPoint - > GetOuterULandscapeSplinesComponent ( ) = = this ) ;
for ( const FLandscapeSplineConnection & Connection : ControlPoint - > ConnectedSegments )
{
ensure ( Connection . Segment - > GetOuterULandscapeSplinesComponent ( ) = = this ) ;
}
}
for ( ULandscapeSplineSegment * Segment : Segments )
{
ensure ( Segment - > GetOuterULandscapeSplinesComponent ( ) = = this ) ;
for ( const FLandscapeSplineSegmentConnection & Connection : Segment - > Connections )
{
ensure ( Connection . ControlPoint - > GetOuterULandscapeSplinesComponent ( ) = = this ) ;
}
}
# endif
}
2014-03-14 14:13:41 -04:00
void ULandscapeSplinesComponent : : OnRegister ( )
{
2014-05-12 08:40:42 -04:00
CheckSplinesValid ( ) ;
2014-03-14 14:13:41 -04:00
2014-05-12 08:40:42 -04:00
Super : : OnRegister ( ) ;
2014-03-14 14:13:41 -04:00
}
# if WITH_EDITOR
FPrimitiveSceneProxy * ULandscapeSplinesComponent : : CreateSceneProxy ( )
{
2014-05-12 08:40:42 -04:00
CheckSplinesValid ( ) ;
2014-03-14 14:13:41 -04:00
return new FLandscapeSplinesSceneProxy ( this ) ;
}
# endif
2014-10-01 14:45:04 -04:00
FBoxSphereBounds ULandscapeSplinesComponent : : CalcBounds ( const FTransform & LocalToWorld ) const
2014-03-14 14:13:41 -04:00
{
FBox NewBoundsCalc ( 0 ) ;
2014-05-12 08:40:42 -04:00
for ( ULandscapeSplineControlPoint * ControlPoint : ControlPoints )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
// TTP #334549: Somehow we're getting nulls in the ControlPoints array
if ( ControlPoint )
2014-05-06 11:17:57 -04:00
{
NewBoundsCalc + = ControlPoint - > GetBounds ( ) ;
}
2014-03-14 14:13:41 -04:00
}
2014-05-12 08:40:42 -04:00
for ( ULandscapeSplineSegment * Segment : Segments )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
if ( Segment )
2014-05-06 11:17:57 -04:00
{
NewBoundsCalc + = Segment - > GetBounds ( ) ;
}
2014-03-14 14:13:41 -04:00
}
2014-10-27 07:55:56 -04:00
FBoxSphereBounds NewBounds ;
if ( NewBoundsCalc . IsValid )
{
NewBoundsCalc = NewBoundsCalc . TransformBy ( LocalToWorld ) ;
NewBounds = FBoxSphereBounds ( NewBoundsCalc ) ;
}
else
{
// There's no such thing as an "invalid" FBoxSphereBounds (unlike FBox)
// try to return something that won't modify the parent bounds
if ( AttachParent )
{
NewBounds = FBoxSphereBounds ( AttachParent - > Bounds . Origin , FVector : : ZeroVector , 0.0f ) ;
}
else
{
NewBounds = FBoxSphereBounds ( LocalToWorld . GetTranslation ( ) , FVector : : ZeroVector , 0.0f ) ;
}
}
return NewBounds ;
2014-03-14 14:13:41 -04:00
}
bool ULandscapeSplinesComponent : : ModifySplines ( bool bAlwaysMarkDirty /*= true*/ )
{
bool bSavedToTransactionBuffer = Modify ( bAlwaysMarkDirty ) ;
2014-05-12 08:40:42 -04:00
for ( ULandscapeSplineControlPoint * ControlPoint : ControlPoints )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
bSavedToTransactionBuffer = ControlPoint - > Modify ( bAlwaysMarkDirty ) | | bSavedToTransactionBuffer ;
2014-03-14 14:13:41 -04:00
}
2014-05-12 08:40:42 -04:00
for ( ULandscapeSplineSegment * Segment : Segments )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
bSavedToTransactionBuffer = Segment - > Modify ( bAlwaysMarkDirty ) | | bSavedToTransactionBuffer ;
2014-03-14 14:13:41 -04:00
}
return bSavedToTransactionBuffer ;
}
2015-03-24 13:53:46 -04:00
FArchive & operator < < ( FArchive & Ar , FForeignControlPointData & Value )
{
# if WITH_EDITORONLY_DATA
if ( ! Ar . IsFilterEditorOnly ( ) )
{
Ar < < Value . ModificationKey < < Value . MeshComponent ;
}
# endif
return Ar ;
}
FArchive & operator < < ( FArchive & Ar , FForeignSplineSegmentData & Value )
{
# if WITH_EDITORONLY_DATA
if ( ! Ar . IsFilterEditorOnly ( ) )
{
Ar < < Value . ModificationKey < < Value . MeshComponents ;
}
# endif
return Ar ;
}
FArchive & operator < < ( FArchive & Ar , FForeignWorldSplineData & Value )
{
# if WITH_EDITORONLY_DATA
if ( ! Ar . IsFilterEditorOnly ( ) )
{
Ar < < Value . ForeignSplineSegmentDataMap ;
}
# endif
return Ar ;
}
void ULandscapeSplinesComponent : : Serialize ( FArchive & Ar )
{
Super : : Serialize ( Ar ) ;
# if WITH_EDITORONLY_DATA
if ( Ar . UE4Ver ( ) > = VER_UE4_LANDSCAPE_SPLINE_CROSS_LEVEL_MESHES & &
! Ar . IsFilterEditorOnly ( ) )
{
Ar < < ForeignWorldSplineDataMap ;
}
if ( ! Ar . IsPersistent ( ) )
{
Ar < < MeshComponentLocalOwnersMap ;
Ar < < MeshComponentForeignOwnersMap ;
}
# endif
}
# if WITH_EDITOR
void ULandscapeSplinesComponent : : AutoFixMeshComponentErrors ( UWorld * OtherWorld )
{
UWorld * ThisOuterWorld = GetTypedOuter < UWorld > ( ) ;
TAssetPtr < UWorld > OtherWorldAssetPtr = OtherWorld ;
ULandscapeSplinesComponent * StreamingSplinesComponent = GetStreamingSplinesComponentForLevel ( OtherWorld - > PersistentLevel ) ;
auto * ForeignWorldSplineData = StreamingSplinesComponent ? StreamingSplinesComponent - > ForeignWorldSplineDataMap . Find ( ThisOuterWorld ) : nullptr ;
// Fix control point meshes
for ( ULandscapeSplineControlPoint * ControlPoint : ControlPoints )
{
if ( ControlPoint - > GetForeignWorld ( ) = = OtherWorld )
{
auto * ForeignControlPointData = ForeignWorldSplineData ? ForeignWorldSplineData - > ForeignControlPointDataMap . Find ( ControlPoint ) : nullptr ;
if ( ! ForeignControlPointData | | ForeignControlPointData - > ModificationKey ! = ControlPoint - > GetModificationKey ( ) )
{
// We don't pass true for update segments to avoid them being updated multiple times
ControlPoint - > UpdateSplinePoints ( true , false ) ;
}
}
}
// Fix spline segment meshes
for ( ULandscapeSplineSegment * Segment : Segments )
{
if ( Segment - > GetForeignWorlds ( ) . Contains ( OtherWorld ) )
{
auto * ForeignSplineSegmentData = ForeignWorldSplineData ? ForeignWorldSplineData - > ForeignSplineSegmentDataMap . Find ( Segment ) : nullptr ;
if ( ! ForeignSplineSegmentData | | ForeignSplineSegmentData - > ModificationKey ! = Segment - > GetModificationKey ( ) )
{
Segment - > UpdateSplinePoints ( true ) ;
}
}
}
if ( StreamingSplinesComponent )
{
StreamingSplinesComponent - > DestroyOrphanedForeignMeshComponents ( ThisOuterWorld ) ;
}
}
void ULandscapeSplinesComponent : : CheckForErrors ( )
{
Super : : CheckForErrors ( ) ;
UWorld * ThisOuterWorld = GetTypedOuter < UWorld > ( ) ;
TSet < UWorld * > OutdatedWorlds ;
TMap < UWorld * , FForeignWorldSplineData * > ForeignWorldSplineDataMapCache ;
// Check control point meshes
for ( ULandscapeSplineControlPoint * ControlPoint : ControlPoints )
{
UWorld * ForeignWorld = ControlPoint - > GetForeignWorld ( ) . Get ( ) ;
if ( ForeignWorld & & ! OutdatedWorlds . Contains ( ForeignWorld ) )
{
auto * * ForeignWorldSplineDataCachedPtr = ForeignWorldSplineDataMapCache . Find ( ForeignWorld ) ;
auto * ForeignWorldSplineData = ForeignWorldSplineDataCachedPtr ? * ForeignWorldSplineDataCachedPtr : nullptr ;
if ( ! ForeignWorldSplineDataCachedPtr )
{
ULandscapeSplinesComponent * StreamingSplinesComponent = GetStreamingSplinesComponentForLevel ( ForeignWorld - > PersistentLevel ) ;
ForeignWorldSplineData = StreamingSplinesComponent ? StreamingSplinesComponent - > ForeignWorldSplineDataMap . Find ( ThisOuterWorld ) : nullptr ;
ForeignWorldSplineDataMapCache . Add ( ForeignWorld , ForeignWorldSplineData ) ;
}
auto * ForeignControlPointData = ForeignWorldSplineData ? ForeignWorldSplineData - > ForeignControlPointDataMap . Find ( ControlPoint ) : nullptr ;
if ( ! ForeignControlPointData | | ForeignControlPointData - > ModificationKey ! = ControlPoint - > GetModificationKey ( ) )
{
OutdatedWorlds . Add ( ForeignWorld ) ;
}
}
}
// Check spline segment meshes
for ( ULandscapeSplineSegment * Segment : Segments )
{
for ( auto & ForeignWorldAssetPtr : Segment - > GetForeignWorlds ( ) )
{
UWorld * ForeignWorld = ForeignWorldAssetPtr . Get ( ) ;
if ( ForeignWorld & & ! OutdatedWorlds . Contains ( ForeignWorld ) )
{
auto * * ForeignWorldSplineDataCachedPtr = ForeignWorldSplineDataMapCache . Find ( ForeignWorld ) ;
auto * ForeignWorldSplineData = ForeignWorldSplineDataCachedPtr ? * ForeignWorldSplineDataCachedPtr : nullptr ;
if ( ! ForeignWorldSplineDataCachedPtr )
{
ULandscapeSplinesComponent * StreamingSplinesComponent = GetStreamingSplinesComponentForLevel ( ForeignWorld - > PersistentLevel ) ;
ForeignWorldSplineData = StreamingSplinesComponent ? StreamingSplinesComponent - > ForeignWorldSplineDataMap . Find ( ThisOuterWorld ) : nullptr ;
ForeignWorldSplineDataMapCache . Add ( ForeignWorld , ForeignWorldSplineData ) ;
}
auto * ForeignSplineSegmentData = ForeignWorldSplineData ? ForeignWorldSplineData - > ForeignSplineSegmentDataMap . Find ( Segment ) : nullptr ;
if ( ! ForeignSplineSegmentData | | ForeignSplineSegmentData - > ModificationKey ! = Segment - > GetModificationKey ( ) )
{
OutdatedWorlds . Add ( ForeignWorld ) ;
}
}
}
}
ForeignWorldSplineDataMapCache . Empty ( ) ;
for ( UWorld * OutdatedWorld : OutdatedWorlds )
{
FFormatNamedArguments Arguments ;
Arguments . Add ( TEXT ( " MeshMap " ) , FText : : FromName ( OutdatedWorld - > GetFName ( ) ) ) ;
Arguments . Add ( TEXT ( " SplineMap " ) , FText : : FromName ( ThisOuterWorld - > GetFName ( ) ) ) ;
FMessageLog ( " MapCheck " ) . Error ( )
- > AddToken ( FUObjectToken : : Create ( GetOwner ( ) ) )
- > AddToken ( FTextToken : : Create ( FText : : Format ( LOCTEXT ( " MapCheck_Message_MeshesOutDated " , " Meshes in {MeshMap} out of date compared to landscape spline in {SplineMap} " ) , Arguments ) ) )
- > AddToken ( FActionToken : : Create ( LOCTEXT ( " MapCheck_ActionName_MeshesOutDated " , " Rebuild landscape splines " ) , FText ( ) ,
FOnActionTokenExecuted : : CreateUObject ( this , & ULandscapeSplinesComponent : : AutoFixMeshComponentErrors , OutdatedWorld ) , true ) ) ;
}
// check for orphaned components
for ( auto & ForeignWorldSplineDataPair : ForeignWorldSplineDataMap )
{
auto & ForeignWorldAssetPtr = ForeignWorldSplineDataPair . Key ;
auto & ForeignWorldSplineData = ForeignWorldSplineDataPair . Value ;
// World is not loaded
if ( ForeignWorldAssetPtr . IsPending ( ) )
{
continue ;
}
UWorld * ForeignWorld = ForeignWorldAssetPtr . Get ( ) ;
for ( auto & ForeignSplineSegmentDataPair : ForeignWorldSplineData . ForeignSplineSegmentDataMap )
{
const ULandscapeSplineSegment * ForeignSplineSegment = ForeignSplineSegmentDataPair . Key . Get ( ) ;
auto & ForeignSplineSegmentData = ForeignSplineSegmentDataPair . Value ;
// No such segment or segment doesn't match our meshes
if ( ! ForeignSplineSegment )
{
FFormatNamedArguments Arguments ;
Arguments . Add ( TEXT ( " MeshMap " ) , FText : : FromName ( ThisOuterWorld - > GetFName ( ) ) ) ;
Arguments . Add ( TEXT ( " SplineMap " ) , FText : : FromName ( ForeignWorld - > GetFName ( ) ) ) ;
FMessageLog ( " MapCheck " ) . Error ( )
- > AddToken ( FUObjectToken : : Create ( GetOwner ( ) ) )
- > AddToken ( FTextToken : : Create ( FText : : Format ( LOCTEXT ( " MapCheck_Message_OrphanedMeshes " , " {MeshMap} contains orphaned meshes due to mismatch with landscape splines in {SplineMap} " ) , Arguments ) ) )
- > AddToken ( FActionToken : : Create ( LOCTEXT ( " MapCheck_ActionName_OrphanedMeshes " , " Clean up orphaned meshes " ) , FText ( ) ,
FOnActionTokenExecuted : : CreateUObject ( this , & ULandscapeSplinesComponent : : DestroyOrphanedForeignMeshComponents , ForeignWorld ) , true ) ) ;
break ;
}
}
}
}
# endif
2014-05-08 06:20:08 -04:00
void ULandscapeSplinesComponent : : PostLoad ( )
{
Super : : PostLoad ( ) ;
2015-03-24 13:53:46 -04:00
# if WITH_EDITOR
if ( GIsEditor )
{
// Build MeshComponentForeignOwnersMap (Component->Spline) from ForeignWorldSplineDataMap (World->Spline->Component)
for ( auto & ForeignWorldSplineDataPair : ForeignWorldSplineDataMap )
{
auto & ForeignWorld = ForeignWorldSplineDataPair . Key ;
auto & ForeignWorldSplineData = ForeignWorldSplineDataPair . Value ;
for ( auto & ForeignControlPointDataPair : ForeignWorldSplineData . ForeignControlPointDataMap )
{
TLazyObjectPtr < ULandscapeSplineControlPoint > ForeignControlPoint = ForeignControlPointDataPair . Key ;
auto & ForeignControlPointData = ForeignControlPointDataPair . Value ;
MeshComponentForeignOwnersMap . Add ( ForeignControlPointData . MeshComponent , ForeignControlPoint ) ;
}
for ( auto & ForeignSplineSegmentDataPair : ForeignWorldSplineData . ForeignSplineSegmentDataMap )
{
TLazyObjectPtr < ULandscapeSplineSegment > ForeignSplineSegment = ForeignSplineSegmentDataPair . Key ;
auto & ForeignSplineSegmentData = ForeignSplineSegmentDataPair . Value ;
for ( auto * MeshComponent : ForeignSplineSegmentData . MeshComponents )
{
MeshComponentForeignOwnersMap . Add ( MeshComponent , ForeignSplineSegment ) ;
}
}
}
}
# endif
2014-05-12 08:40:42 -04:00
CheckSplinesValid ( ) ;
2015-03-24 13:53:46 -04:00
# if WITH_EDITOR
if ( GIsEditor )
{
CheckForErrors ( ) ;
}
# endif
2014-05-08 06:20:08 -04:00
}
2014-03-14 14:13:41 -04:00
# if WITH_EDITOR
2014-07-22 07:34:30 -04:00
static bool bHackIsUndoingSplines = false ;
2014-03-14 14:13:41 -04:00
void ULandscapeSplinesComponent : : PostEditChangeProperty ( FPropertyChangedEvent & PropertyChangedEvent )
{
Super : : PostEditChangeProperty ( PropertyChangedEvent ) ;
2014-07-22 07:34:30 -04:00
// Don't update splines when undoing, not only is it unnecessary and expensive,
// it also causes failed asserts in debug builds when trying to register components
// (because the actor hasn't reset its OwnedComponents array yet)
if ( ! bHackIsUndoingSplines )
{
const bool bUpdateCollision = PropertyChangedEvent . ChangeType ! = EPropertyChangeType : : Interactive ;
2015-03-24 13:53:46 -04:00
RebuildAllSplines ( bUpdateCollision ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-07-22 07:34:30 -04:00
void ULandscapeSplinesComponent : : PostEditUndo ( )
{
bHackIsUndoingSplines = true ;
Super : : PostEditUndo ( ) ;
bHackIsUndoingSplines = false ;
MarkRenderStateDirty ( ) ;
}
2014-03-14 14:13:41 -04:00
2015-03-24 13:53:46 -04:00
void ULandscapeSplinesComponent : : RebuildAllSplines ( bool bUpdateCollision )
{
for ( ULandscapeSplineControlPoint * ControlPoint : ControlPoints )
{
ControlPoint - > UpdateSplinePoints ( true , false ) ;
}
for ( ULandscapeSplineSegment * Segment : Segments )
{
Segment - > UpdateSplinePoints ( true ) ;
}
}
2014-03-14 14:13:41 -04:00
void ULandscapeSplinesComponent : : ShowSplineEditorMesh ( bool bShow )
{
bShowSplineEditorMesh = bShow ;
2014-05-12 08:40:42 -04:00
for ( ULandscapeSplineSegment * Segment : Segments )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
Segment - > UpdateSplineEditorMesh ( ) ;
2014-03-14 14:13:41 -04:00
}
MarkRenderStateDirty ( ) ;
}
2015-03-24 13:53:46 -04:00
bool FForeignWorldSplineData : : IsEmpty ( )
{
return ForeignControlPointDataMap . Num ( ) = = 0 & & ForeignSplineSegmentDataMap . Num ( ) = = 0 ;
}
ULandscapeSplinesComponent * ULandscapeSplinesComponent : : GetStreamingSplinesComponentByLocation ( const FVector & LocalLocation , bool bCreate /* = true*/ )
{
ALandscapeProxy * OuterLandscape = Cast < ALandscapeProxy > ( GetOwner ( ) ) ;
if ( OuterLandscape )
{
FVector LandscapeLocalLocation = ComponentToWorld . GetRelativeTransform ( OuterLandscape - > LandscapeActorToWorld ( ) ) . TransformPosition ( LocalLocation ) ;
const int32 ComponentIndexX = ( LandscapeLocalLocation . X > = 0.0f ) ? FMath : : FloorToInt ( LandscapeLocalLocation . X / OuterLandscape - > ComponentSizeQuads ) : FMath : : CeilToInt ( LandscapeLocalLocation . X / OuterLandscape - > ComponentSizeQuads ) ;
const int32 ComponentIndexY = ( LandscapeLocalLocation . Y > = 0.0f ) ? FMath : : FloorToInt ( LandscapeLocalLocation . Y / OuterLandscape - > ComponentSizeQuads ) : FMath : : CeilToInt ( LandscapeLocalLocation . Y / OuterLandscape - > ComponentSizeQuads ) ;
ULandscapeComponent * LandscapeComponent = OuterLandscape - > GetLandscapeInfo ( ) - > XYtoComponentMap . FindRef ( FIntPoint ( ComponentIndexX , ComponentIndexY ) ) ;
if ( LandscapeComponent )
{
ALandscapeProxy * ComponentLandscapeProxy = LandscapeComponent - > GetLandscapeProxy ( ) ;
if ( ! ComponentLandscapeProxy - > SplineComponent & & bCreate )
{
ComponentLandscapeProxy - > Modify ( ) ;
ComponentLandscapeProxy - > SplineComponent = NewObject < ULandscapeSplinesComponent > ( ComponentLandscapeProxy , NAME_None , RF_Transactional ) ;
ComponentLandscapeProxy - > SplineComponent - > RelativeScale3D = RelativeScale3D ;
ComponentLandscapeProxy - > SplineComponent - > AttachTo ( ComponentLandscapeProxy - > GetRootComponent ( ) ) ;
}
if ( ComponentLandscapeProxy - > SplineComponent )
{
return ComponentLandscapeProxy - > SplineComponent ;
}
}
}
return this ;
}
ULandscapeSplinesComponent * ULandscapeSplinesComponent : : GetStreamingSplinesComponentForLevel ( ULevel * Level , bool bCreate /* = true*/ )
{
ALandscapeProxy * OuterLandscape = Cast < ALandscapeProxy > ( GetOwner ( ) ) ;
if ( OuterLandscape )
{
ULandscapeInfo * LandscapeInfo = OuterLandscape - > GetLandscapeInfo ( ) ;
check ( LandscapeInfo ) ;
ALandscapeProxy * Proxy = LandscapeInfo - > GetLandscapeProxyForLevel ( Level ) ;
if ( Proxy )
{
if ( ! Proxy - > SplineComponent & & bCreate )
{
Proxy - > Modify ( ) ;
Proxy - > SplineComponent = NewObject < ULandscapeSplinesComponent > ( Proxy , NAME_None , RF_Transactional ) ;
Proxy - > SplineComponent - > RelativeScale3D = RelativeScale3D ;
Proxy - > SplineComponent - > AttachTo ( Proxy - > GetRootComponent ( ) ) ;
}
return Proxy - > SplineComponent ;
}
}
return nullptr ;
}
TArray < ULandscapeSplinesComponent * > ULandscapeSplinesComponent : : GetAllStreamingSplinesComponents ( )
{
ALandscapeProxy * OuterLandscape = Cast < ALandscapeProxy > ( GetOwner ( ) ) ;
if ( OuterLandscape )
{
ULandscapeInfo * LandscapeInfo = OuterLandscape - > GetLandscapeInfo ( ) ;
check ( LandscapeInfo ) ;
TArray < ULandscapeSplinesComponent * > SplinesComponents ;
SplinesComponents . Reserve ( LandscapeInfo - > Proxies . Num ( ) + 1 ) ;
ALandscape * RootLandscape = LandscapeInfo - > LandscapeActor . Get ( ) ;
if ( RootLandscape & & RootLandscape - > SplineComponent )
{
SplinesComponents . Add ( RootLandscape - > SplineComponent ) ;
}
for ( ALandscapeProxy * LandscapeProxy : LandscapeInfo - > Proxies )
{
if ( LandscapeProxy & & LandscapeProxy - > SplineComponent )
{
SplinesComponents . Add ( LandscapeProxy - > SplineComponent ) ;
}
}
return SplinesComponents ;
}
return { } ;
}
void ULandscapeSplinesComponent : : UpdateModificationKey ( ULandscapeSplineSegment * Owner )
{
UWorld * OwnerWorld = Owner - > GetTypedOuter < UWorld > ( ) ;
checkSlow ( OwnerWorld ! = GetTypedOuter < UWorld > ( ) ) ;
auto * ForeignWorldSplineData = ForeignWorldSplineDataMap . Find ( OwnerWorld ) ;
checkSlow ( ForeignWorldSplineData ) ;
if ( ForeignWorldSplineData )
{
auto * ForeignSplineSegmentData = ForeignWorldSplineData - > ForeignSplineSegmentDataMap . Find ( Owner ) ;
ForeignSplineSegmentData - > ModificationKey = Owner - > GetModificationKey ( ) ;
}
}
void ULandscapeSplinesComponent : : UpdateModificationKey ( ULandscapeSplineControlPoint * Owner )
{
UWorld * OwnerWorld = Owner - > GetTypedOuter < UWorld > ( ) ;
checkSlow ( OwnerWorld ! = GetTypedOuter < UWorld > ( ) ) ;
auto * ForeignWorldSplineData = ForeignWorldSplineDataMap . Find ( OwnerWorld ) ;
checkSlow ( ForeignWorldSplineData ) ;
if ( ForeignWorldSplineData )
{
auto * ForeignControlPointData = ForeignWorldSplineData - > ForeignControlPointDataMap . Find ( Owner ) ;
ForeignControlPointData - > ModificationKey = Owner - > GetModificationKey ( ) ;
}
}
void ULandscapeSplinesComponent : : AddForeignMeshComponent ( ULandscapeSplineSegment * Owner , USplineMeshComponent * Component )
{
# if DO_GUARD_SLOW
UWorld * ThisOuterWorld = GetTypedOuter < UWorld > ( ) ;
UWorld * ComponentOuterWorld = Component - > GetTypedOuter < UWorld > ( ) ;
checkSlow ( ComponentOuterWorld = = ThisOuterWorld ) ;
# endif
UWorld * OwnerWorld = Owner - > GetTypedOuter < UWorld > ( ) ;
checkSlow ( OwnerWorld ! = ThisOuterWorld ) ;
auto & ForeignWorldSplineData = ForeignWorldSplineDataMap . FindOrAdd ( OwnerWorld ) ;
auto & ForeignSplineSegmentData = ForeignWorldSplineData . ForeignSplineSegmentDataMap . FindOrAdd ( Owner ) ;
ForeignSplineSegmentData . MeshComponents . Add ( Component ) ;
ForeignSplineSegmentData . ModificationKey = Owner - > GetModificationKey ( ) ;
MeshComponentForeignOwnersMap . Add ( Component , Owner ) ;
}
void ULandscapeSplinesComponent : : RemoveForeignMeshComponent ( ULandscapeSplineSegment * Owner , USplineMeshComponent * Component )
{
# if DO_GUARD_SLOW
UWorld * ThisOuterWorld = GetTypedOuter < UWorld > ( ) ;
UWorld * ComponentOuterWorld = Component - > GetTypedOuter < UWorld > ( ) ;
checkSlow ( ComponentOuterWorld = = ThisOuterWorld ) ;
# endif
UWorld * OwnerWorld = Owner - > GetTypedOuter < UWorld > ( ) ;
checkSlow ( OwnerWorld ! = ThisOuterWorld ) ;
auto * ForeignWorldSplineData = ForeignWorldSplineDataMap . Find ( OwnerWorld ) ;
checkSlow ( ForeignWorldSplineData ) ;
checkSlow ( MeshComponentForeignOwnersMap . FindRef ( Component ) = = Owner ) ;
verifySlow ( MeshComponentForeignOwnersMap . Remove ( Component ) = = 1 ) ;
if ( ForeignWorldSplineData )
{
auto * ForeignSplineSegmentData = ForeignWorldSplineData - > ForeignSplineSegmentDataMap . Find ( Owner ) ;
verifySlow ( ForeignSplineSegmentData - > MeshComponents . RemoveSingle ( Component ) = = 1 ) ;
if ( ForeignSplineSegmentData - > MeshComponents . Num ( ) = = 0 )
{
verifySlow ( ForeignWorldSplineData - > ForeignSplineSegmentDataMap . Remove ( Owner ) = = 1 ) ;
if ( ForeignWorldSplineData - > IsEmpty ( ) )
{
verifySlow ( ForeignWorldSplineDataMap . Remove ( OwnerWorld ) = = 1 ) ;
}
}
else
{
ForeignSplineSegmentData - > ModificationKey = Owner - > GetModificationKey ( ) ;
}
}
}
void ULandscapeSplinesComponent : : RemoveAllForeignMeshComponents ( ULandscapeSplineSegment * Owner )
{
UWorld * OwnerWorld = Owner - > GetTypedOuter < UWorld > ( ) ;
checkSlow ( OwnerWorld ! = GetTypedOuter < UWorld > ( ) ) ;
auto * ForeignWorldSplineData = ForeignWorldSplineDataMap . Find ( OwnerWorld ) ;
checkSlow ( ForeignWorldSplineData ) ;
if ( ForeignWorldSplineData )
{
auto * ForeignSplineSegmentData = ForeignWorldSplineData - > ForeignSplineSegmentDataMap . Find ( Owner ) ;
for ( auto * MeshComponent : ForeignSplineSegmentData - > MeshComponents )
{
checkSlow ( MeshComponentForeignOwnersMap . FindRef ( MeshComponent ) = = Owner ) ;
verifySlow ( MeshComponentForeignOwnersMap . Remove ( MeshComponent ) = = 1 ) ;
}
ForeignSplineSegmentData - > MeshComponents . Empty ( ) ;
verifySlow ( ForeignWorldSplineData - > ForeignSplineSegmentDataMap . Remove ( Owner ) = = 1 ) ;
if ( ForeignWorldSplineData - > IsEmpty ( ) )
{
verifySlow ( ForeignWorldSplineDataMap . Remove ( OwnerWorld ) = = 1 ) ;
}
}
}
void ULandscapeSplinesComponent : : AddForeignMeshComponent ( ULandscapeSplineControlPoint * Owner , UControlPointMeshComponent * Component )
{
# if DO_GUARD_SLOW
UWorld * ThisOuterWorld = GetTypedOuter < UWorld > ( ) ;
UWorld * ComponentOuterWorld = Component - > GetTypedOuter < UWorld > ( ) ;
checkSlow ( ComponentOuterWorld = = ThisOuterWorld ) ;
# endif
UWorld * OwnerWorld = Owner - > GetTypedOuter < UWorld > ( ) ;
checkSlow ( OwnerWorld ! = ThisOuterWorld ) ;
auto & ForeignWorldSplineData = ForeignWorldSplineDataMap . FindOrAdd ( OwnerWorld ) ;
checkSlow ( ! ForeignWorldSplineData . ForeignControlPointDataMap . Find ( Owner ) ) ;
auto & ForeignControlPointData = ForeignWorldSplineData . ForeignControlPointDataMap . Add ( Owner ) ;
ForeignControlPointData . MeshComponent = Component ;
ForeignControlPointData . ModificationKey = Owner - > GetModificationKey ( ) ;
MeshComponentForeignOwnersMap . Add ( Component , Owner ) ;
}
void ULandscapeSplinesComponent : : RemoveForeignMeshComponent ( ULandscapeSplineControlPoint * Owner , UControlPointMeshComponent * Component )
{
# if DO_GUARD_SLOW
UWorld * ThisOuterWorld = GetTypedOuter < UWorld > ( ) ;
UWorld * ComponentOuterWorld = Component - > GetTypedOuter < UWorld > ( ) ;
checkSlow ( ComponentOuterWorld = = ThisOuterWorld ) ;
# endif
UWorld * OwnerWorld = Owner - > GetTypedOuter < UWorld > ( ) ;
checkSlow ( OwnerWorld ! = ThisOuterWorld ) ;
auto * ForeignWorldSplineData = ForeignWorldSplineDataMap . Find ( OwnerWorld ) ;
checkSlow ( ForeignWorldSplineData ) ;
checkSlow ( MeshComponentForeignOwnersMap . FindRef ( Component ) = = Owner ) ;
verifySlow ( MeshComponentForeignOwnersMap . Remove ( Component ) = = 1 ) ;
if ( ForeignWorldSplineData )
{
auto * ForeignControlPointData = ForeignWorldSplineData - > ForeignControlPointDataMap . Find ( Owner ) ;
checkSlow ( ForeignControlPointData ) ;
checkSlow ( ForeignControlPointData - > MeshComponent = = Component ) ;
verifySlow ( ForeignWorldSplineData - > ForeignControlPointDataMap . Remove ( Owner ) = = 1 ) ;
if ( ForeignWorldSplineData - > IsEmpty ( ) )
{
verifySlow ( ForeignWorldSplineDataMap . Remove ( OwnerWorld ) = = 1 ) ;
}
}
}
void ULandscapeSplinesComponent : : DestroyOrphanedForeignMeshComponents ( UWorld * OwnerWorld )
{
auto * ForeignWorldSplineData = ForeignWorldSplineDataMap . Find ( OwnerWorld ) ;
if ( ForeignWorldSplineData )
{
for ( auto ForeignSplineSegmentDataIt = ForeignWorldSplineData - > ForeignSplineSegmentDataMap . CreateIterator ( ) ; ForeignSplineSegmentDataIt ; + + ForeignSplineSegmentDataIt )
{
const auto & ForeignSplineSegment = ForeignSplineSegmentDataIt - > Key ;
auto & ForeignSplineSegmentData = ForeignSplineSegmentDataIt - > Value ;
if ( ! ForeignSplineSegment )
{
for ( auto * MeshComponent : ForeignSplineSegmentData . MeshComponents )
{
checkSlow ( ! MeshComponentForeignOwnersMap . FindRef ( MeshComponent ) . IsValid ( ) ) ;
verifySlow ( MeshComponentForeignOwnersMap . Remove ( MeshComponent ) = = 1 ) ;
MeshComponent - > DestroyComponent ( ) ;
}
ForeignSplineSegmentData . MeshComponents . Empty ( ) ;
ForeignSplineSegmentDataIt . RemoveCurrent ( ) ;
}
}
if ( ForeignWorldSplineData - > IsEmpty ( ) )
{
verifySlow ( ForeignWorldSplineDataMap . Remove ( OwnerWorld ) = = 1 ) ;
}
}
}
UControlPointMeshComponent * ULandscapeSplinesComponent : : GetForeignMeshComponent ( ULandscapeSplineControlPoint * Owner )
{
UWorld * OwnerWorld = Owner - > GetTypedOuter < UWorld > ( ) ;
checkSlow ( OwnerWorld ! = GetTypedOuter < UWorld > ( ) ) ;
auto * ForeignWorldSplineData = ForeignWorldSplineDataMap . Find ( OwnerWorld ) ;
if ( ForeignWorldSplineData )
{
auto * ForeignControlPointData = ForeignWorldSplineData - > ForeignControlPointDataMap . Find ( Owner ) ;
if ( ForeignControlPointData )
{
return ForeignControlPointData - > MeshComponent ;
}
}
return nullptr ;
}
TArray < USplineMeshComponent * > ULandscapeSplinesComponent : : GetForeignMeshComponents ( ULandscapeSplineSegment * Owner )
{
UWorld * OwnerWorld = Owner - > GetTypedOuter < UWorld > ( ) ;
checkSlow ( OwnerWorld ! = GetTypedOuter < UWorld > ( ) ) ;
auto * ForeignWorldSplineData = ForeignWorldSplineDataMap . Find ( OwnerWorld ) ;
if ( ForeignWorldSplineData )
{
auto * ForeignSplineSegmentData = ForeignWorldSplineData - > ForeignSplineSegmentDataMap . Find ( Owner ) ;
if ( ForeignSplineSegmentData )
{
return ForeignSplineSegmentData - > MeshComponents ;
}
}
return { } ;
}
UObject * ULandscapeSplinesComponent : : GetOwnerForMeshComponent ( const UMeshComponent * SplineMeshComponent )
{
UObject * LocalOwner = MeshComponentLocalOwnersMap . FindRef ( SplineMeshComponent ) ;
if ( LocalOwner )
{
return LocalOwner ;
}
TLazyObjectPtr < UObject > * ForeignOwner = MeshComponentForeignOwnersMap . Find ( SplineMeshComponent ) ;
if ( ForeignOwner )
{
// this will be null if ForeignOwner isn't currently loaded
return ForeignOwner - > Get ( ) ;
}
return nullptr ;
}
2014-03-14 14:13:41 -04:00
# endif // WITH_EDITOR
//////////////////////////////////////////////////////////////////////////
// CONTROL POINT MESH COMPONENT
2014-10-14 10:29:11 -04:00
UControlPointMeshComponent : : UControlPointMeshComponent ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-03-14 14:13:41 -04:00
{
2014-07-22 05:44:07 -04:00
SetCollisionProfileName ( UCollisionProfile : : BlockAll_ProfileName ) ;
2014-07-22 06:19:14 -04:00
Mobility = EComponentMobility : : Static ;
2014-07-22 05:44:07 -04:00
2014-03-14 14:13:41 -04:00
# if WITH_EDITORONLY_DATA
bSelected = false ;
# endif
}
//////////////////////////////////////////////////////////////////////////
// SPLINE CONTROL POINT
2014-10-14 10:29:11 -04:00
ULandscapeSplineControlPoint : : ULandscapeSplineControlPoint ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-03-14 14:13:41 -04:00
{
Width = 1000 ;
SideFalloff = 1000 ;
EndFalloff = 2000 ;
# if WITH_EDITORONLY_DATA
2015-03-24 13:53:46 -04:00
Mesh = nullptr ;
2014-03-14 14:13:41 -04:00
MeshScale = FVector ( 1 ) ;
LDMaxDrawDistance = 0 ;
2015-03-18 10:30:26 -04:00
TranslucencySortPriority = 0 ;
2014-03-14 14:13:41 -04:00
LayerName = NAME_None ;
bRaiseTerrain = true ;
bLowerTerrain = true ;
2015-03-24 13:53:46 -04:00
LocalMeshComponent = nullptr ;
bPlaceSplineMeshesInStreamingLevels = true ;
2014-03-14 14:13:41 -04:00
bEnableCollision = true ;
bCastShadow = true ;
// transients
bSelected = false ;
# endif
}
2015-03-24 13:53:46 -04:00
void ULandscapeSplineControlPoint : : Serialize ( FArchive & Ar )
{
Super : : Serialize ( Ar ) ;
# if WITH_EDITOR
if ( Ar . UE4Ver ( ) < VER_UE4_LANDSCAPE_SPLINE_CROSS_LEVEL_MESHES )
{
bPlaceSplineMeshesInStreamingLevels = false ;
}
# endif
}
2014-03-14 14:13:41 -04:00
void ULandscapeSplineControlPoint : : PostLoad ( )
{
Super : : PostLoad ( ) ;
# if WITH_EDITOR
2015-03-24 13:53:46 -04:00
if ( GIsEditor )
{
if ( LocalMeshComponent ! = nullptr )
{
ULandscapeSplinesComponent * OuterSplines = GetOuterULandscapeSplinesComponent ( ) ;
OuterSplines - > MeshComponentLocalOwnersMap . Add ( LocalMeshComponent , this ) ;
}
}
if ( GetLinkerUE4Version ( ) < VER_UE4_LANDSCAPE_SPLINE_CROSS_LEVEL_MESHES )
2014-03-14 14:13:41 -04:00
{
2014-05-16 11:12:41 -04:00
// Fix collision profile
2015-03-24 13:53:46 -04:00
if ( LocalMeshComponent ! = nullptr ) // ForeignMeshComponents didn't exist yet
2014-05-16 11:12:41 -04:00
{
2015-03-24 13:53:46 -04:00
const FName CollisionProfile = bEnableCollision ? UCollisionProfile : : BlockAll_ProfileName : UCollisionProfile : : NoCollision_ProfileName ;
if ( LocalMeshComponent - > GetCollisionProfileName ( ) ! = CollisionProfile )
{
LocalMeshComponent - > SetCollisionProfileName ( CollisionProfile ) ;
}
2014-05-16 11:12:41 -04:00
2015-03-24 13:53:46 -04:00
LocalMeshComponent - > SetFlags ( RF_TextExportTransient ) ;
}
2014-03-14 14:13:41 -04:00
}
# endif
}
FLandscapeSplineSegmentConnection & FLandscapeSplineConnection : : GetNearConnection ( ) const
{
return Segment - > Connections [ End ] ;
}
FLandscapeSplineSegmentConnection & FLandscapeSplineConnection : : GetFarConnection ( ) const
{
return Segment - > Connections [ 1 - End ] ;
}
2015-03-24 13:53:46 -04:00
# if WITH_EDITOR
2014-03-14 14:13:41 -04:00
FName ULandscapeSplineControlPoint : : GetBestConnectionTo ( FVector Destination ) const
{
FName BestSocket = NAME_None ;
float BestScore = - FLT_MAX ;
2015-03-24 13:53:46 -04:00
if ( Mesh ! = nullptr )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
for ( const UStaticMeshSocket * Socket : Mesh - > Sockets )
2014-03-14 14:13:41 -04:00
{
FTransform SocketTransform = FTransform ( Socket - > RelativeRotation , Socket - > RelativeLocation ) * FTransform ( Rotation , Location , MeshScale ) ;
FVector SocketLocation = SocketTransform . GetTranslation ( ) ;
FRotator SocketRotation = SocketTransform . GetRotation ( ) . Rotator ( ) ;
float Score = ( Destination - Location ) . Size ( ) - ( Destination - SocketLocation ) . Size ( ) ; // Score closer sockets higher
Score * = FMath : : Abs ( FVector : : DotProduct ( ( Destination - SocketLocation ) , SocketRotation . Vector ( ) ) ) ; // score closer rotation higher
if ( Score > BestScore )
{
BestSocket = Socket - > SocketName ;
BestScore = Score ;
}
}
}
return BestSocket ;
}
void ULandscapeSplineControlPoint : : GetConnectionLocalLocationAndRotation ( FName SocketName , OUT FVector & OutLocation , OUT FRotator & OutRotation ) const
{
OutLocation = FVector : : ZeroVector ;
OutRotation = FRotator : : ZeroRotator ;
2015-03-24 13:53:46 -04:00
if ( Mesh ! = nullptr )
2014-03-14 14:13:41 -04:00
{
const UStaticMeshSocket * Socket = Mesh - > FindSocket ( SocketName ) ;
2015-03-24 13:53:46 -04:00
if ( Socket ! = nullptr )
2014-03-14 14:13:41 -04:00
{
OutLocation = Socket - > RelativeLocation ;
OutRotation = Socket - > RelativeRotation ;
}
}
}
void ULandscapeSplineControlPoint : : GetConnectionLocationAndRotation ( FName SocketName , OUT FVector & OutLocation , OUT FRotator & OutRotation ) const
{
OutLocation = Location ;
OutRotation = Rotation ;
2015-03-24 13:53:46 -04:00
if ( Mesh ! = nullptr )
2014-03-14 14:13:41 -04:00
{
const UStaticMeshSocket * Socket = Mesh - > FindSocket ( SocketName ) ;
2015-03-24 13:53:46 -04:00
if ( Socket ! = nullptr )
2014-03-14 14:13:41 -04:00
{
FTransform SocketTransform = FTransform ( Socket - > RelativeRotation , Socket - > RelativeLocation ) * FTransform ( Rotation , Location , MeshScale ) ;
OutLocation = SocketTransform . GetTranslation ( ) ;
OutRotation = SocketTransform . GetRotation ( ) . Rotator ( ) . GetNormalized ( ) ;
}
}
}
void ULandscapeSplineControlPoint : : SetSplineSelected ( bool bInSelected )
{
bSelected = bInSelected ;
GetOuterULandscapeSplinesComponent ( ) - > MarkRenderStateDirty ( ) ;
2015-03-24 13:53:46 -04:00
if ( LocalMeshComponent ! = nullptr )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
LocalMeshComponent - > bSelected = bInSelected ;
LocalMeshComponent - > PushSelectionToProxy ( ) ;
}
auto ForeignMeshComponentsMap = GetForeignMeshComponents ( ) ;
for ( auto & ForeignMeshComponentsPair : ForeignMeshComponentsMap )
{
ULandscapeSplinesComponent * MeshComponentOuterSplines = ForeignMeshComponentsPair . Key ;
auto * MeshComponent = ForeignMeshComponentsPair . Value ;
2014-03-14 14:13:41 -04:00
MeshComponent - > bSelected = bInSelected ;
MeshComponent - > PushSelectionToProxy ( ) ;
}
}
void ULandscapeSplineControlPoint : : AutoCalcRotation ( )
{
Modify ( ) ;
FRotator Delta = FRotator : : ZeroRotator ;
2014-05-12 08:40:42 -04:00
for ( const FLandscapeSplineConnection & Connection : ConnectedSegments )
2014-03-14 14:13:41 -04:00
{
// Get the start and end location/rotation of this connection
FVector StartLocation ; FRotator StartRotation ;
2014-05-12 08:40:42 -04:00
this - > GetConnectionLocationAndRotation ( Connection . GetNearConnection ( ) . SocketName , StartLocation , StartRotation ) ;
2014-03-14 14:13:41 -04:00
FVector StartLocalLocation ; FRotator StartLocalRotation ;
2014-05-12 08:40:42 -04:00
this - > GetConnectionLocalLocationAndRotation ( Connection . GetNearConnection ( ) . SocketName , StartLocalLocation , StartLocalRotation ) ;
2014-03-14 14:13:41 -04:00
FVector EndLocation ; FRotator EndRotation ;
2014-05-12 08:40:42 -04:00
Connection . GetFarConnection ( ) . ControlPoint - > GetConnectionLocationAndRotation ( Connection . GetFarConnection ( ) . SocketName , EndLocation , EndRotation ) ;
2014-03-14 14:13:41 -04:00
// Find the delta between the direction of the tangent at the connection point and
// the direction to the other end's control point
FQuat SocketLocalRotation = StartLocalRotation . Quaternion ( ) ;
2014-05-12 08:40:42 -04:00
if ( FMath : : Sign ( Connection . GetNearConnection ( ) . TangentLen ) < 0 )
2014-03-14 14:13:41 -04:00
{
SocketLocalRotation = SocketLocalRotation * FRotator ( 0 , 180 , 0 ) . Quaternion ( ) ;
}
const FVector DesiredDirection = ( EndLocation - StartLocation ) ;
const FQuat DesiredSocketRotation = DesiredDirection . Rotation ( ) . Quaternion ( ) ;
const FRotator DesiredRotation = ( DesiredSocketRotation * SocketLocalRotation . Inverse ( ) ) . Rotator ( ) . GetNormalized ( ) ;
const FRotator DesiredRotationDelta = ( DesiredRotation - Rotation ) . GetNormalized ( ) ;
Delta + = DesiredRotationDelta ;
}
// Average delta of all connections
Delta * = 1.0f / ConnectedSegments . Num ( ) ;
// Apply Delta and normalize
Rotation = ( Rotation + Delta ) . GetNormalized ( ) ;
}
void ULandscapeSplineControlPoint : : AutoFlipTangents ( )
{
2014-05-12 08:40:42 -04:00
for ( const FLandscapeSplineConnection & Connection : ConnectedSegments )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
Connection . Segment - > AutoFlipTangents ( ) ;
2014-03-14 14:13:41 -04:00
}
}
void ULandscapeSplineControlPoint : : AutoSetConnections ( bool bIncludingValid )
{
2014-05-12 08:40:42 -04:00
for ( const FLandscapeSplineConnection & Connection : ConnectedSegments )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
FLandscapeSplineSegmentConnection & NearConnection = Connection . GetNearConnection ( ) ;
2014-03-14 14:13:41 -04:00
if ( bIncludingValid | |
2015-03-24 13:53:46 -04:00
( Mesh ! = nullptr & & Mesh - > FindSocket ( NearConnection . SocketName ) = = nullptr ) | |
( Mesh = = nullptr & & NearConnection . SocketName ! = NAME_None ) )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
FLandscapeSplineSegmentConnection & FarConnection = Connection . GetFarConnection ( ) ;
2014-03-14 14:13:41 -04:00
FVector EndLocation ; FRotator EndRotation ;
FarConnection . ControlPoint - > GetConnectionLocationAndRotation ( FarConnection . SocketName , EndLocation , EndRotation ) ;
NearConnection . SocketName = GetBestConnectionTo ( EndLocation ) ;
NearConnection . TangentLen = FMath : : Abs ( NearConnection . TangentLen ) ;
// Allow flipping tangent on the null connection
if ( NearConnection . SocketName = = NAME_None )
{
FVector StartLocation ; FRotator StartRotation ;
NearConnection . ControlPoint - > GetConnectionLocationAndRotation ( NearConnection . SocketName , StartLocation , StartRotation ) ;
2014-11-26 10:01:12 -05:00
if ( FVector : : DotProduct ( ( EndLocation - StartLocation ) . GetSafeNormal ( ) , StartRotation . Vector ( ) ) < 0 )
2014-03-14 14:13:41 -04:00
{
NearConnection . TangentLen = - NearConnection . TangentLen ;
}
}
}
}
}
# endif
# if WITH_EDITOR
2015-03-24 13:53:46 -04:00
TMap < ULandscapeSplinesComponent * , UControlPointMeshComponent * > ULandscapeSplineControlPoint : : GetForeignMeshComponents ( )
{
TMap < ULandscapeSplinesComponent * , UControlPointMeshComponent * > ForeignMeshComponentsMap ;
ULandscapeSplinesComponent * OuterSplines = GetOuterULandscapeSplinesComponent ( ) ;
TArray < ULandscapeSplinesComponent * > SplineComponents = OuterSplines - > GetAllStreamingSplinesComponents ( ) ;
for ( ULandscapeSplinesComponent * SplineComponent : SplineComponents )
{
if ( SplineComponent ! = OuterSplines )
{
auto * ForeignMeshComponent = SplineComponent - > GetForeignMeshComponent ( this ) ;
if ( ForeignMeshComponent )
{
ForeignMeshComponent - > Modify ( ) ;
ForeignMeshComponentsMap . Add ( SplineComponent , ForeignMeshComponent ) ;
}
}
}
return ForeignMeshComponentsMap ;
}
2014-05-29 16:46:26 -04:00
void ULandscapeSplineControlPoint : : UpdateSplinePoints ( bool bUpdateCollision , bool bUpdateAttachedSegments )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
Modify ( ) ;
2014-03-14 14:13:41 -04:00
ULandscapeSplinesComponent * OuterSplines = GetOuterULandscapeSplinesComponent ( ) ;
2015-03-24 13:53:46 -04:00
auto ForeignMeshComponentsMap = GetForeignMeshComponents ( ) ;
2014-03-14 14:13:41 -04:00
2015-03-24 13:53:46 -04:00
ModificationKey = FGuid : : NewGuid ( ) ;
UControlPointMeshComponent * MeshComponent = LocalMeshComponent ;
ULandscapeSplinesComponent * MeshComponentOuterSplines = OuterSplines ;
if ( Mesh ! = nullptr )
{
// Attempt to place mesh components into the appropriate landscape streaming levels based on the components under the spline
if ( bPlaceSplineMeshesInStreamingLevels )
{
MeshComponentOuterSplines = OuterSplines - > GetStreamingSplinesComponentByLocation ( Location ) ;
if ( MeshComponentOuterSplines ! = OuterSplines )
{
MeshComponent = MeshComponentOuterSplines - > GetForeignMeshComponent ( this ) ;
MeshComponentOuterSplines - > Modify ( ) ;
MeshComponentOuterSplines - > UpdateModificationKey ( this ) ;
}
}
// Create mesh component if needed
if ( MeshComponent = = nullptr )
{
AActor * MeshComponentOuterActor = MeshComponentOuterSplines - > GetOwner ( ) ;
MeshComponentOuterSplines - > Modify ( ) ;
MeshComponentOuterActor - > Modify ( ) ;
MeshComponent = NewObject < UControlPointMeshComponent > ( MeshComponentOuterActor , NAME_None , RF_Transactional | RF_TextExportTransient ) ;
MeshComponent - > bSelected = bSelected ;
MeshComponent - > AttachTo ( MeshComponentOuterSplines ) ;
if ( MeshComponentOuterSplines = = OuterSplines )
{
MeshComponentOuterSplines - > MeshComponentLocalOwnersMap . Add ( MeshComponent , this ) ;
}
else
{
MeshComponentOuterSplines - > AddForeignMeshComponent ( this , MeshComponent ) ;
ForeignWorld = MeshComponentOuterSplines - > GetTypedOuter < UWorld > ( ) ;
}
}
if ( MeshComponent - > RelativeLocation ! = Location | |
MeshComponent - > RelativeRotation ! = Rotation | |
MeshComponent - > RelativeScale3D ! = MeshScale )
2014-03-14 14:13:41 -04:00
{
MeshComponent - > Modify ( ) ;
2015-03-24 13:53:46 -04:00
MeshComponent - > SetRelativeTransform ( FTransform ( Rotation , Location , MeshScale ) ) ;
2014-03-14 14:13:41 -04:00
MeshComponent - > InvalidateLightingCache ( ) ;
}
2015-03-24 13:53:46 -04:00
if ( MeshComponent - > StaticMesh ! = Mesh )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
MeshComponent - > Modify ( ) ;
MeshComponent - > SetStaticMesh ( Mesh ) ;
2014-03-14 14:13:41 -04:00
AutoSetConnections ( false ) ;
}
2014-11-26 15:31:30 -05:00
if ( MeshComponent - > OverrideMaterials ! = MaterialOverrides )
2014-03-14 14:13:41 -04:00
{
MeshComponent - > Modify ( ) ;
2014-11-26 15:31:30 -05:00
MeshComponent - > OverrideMaterials = MaterialOverrides ;
2014-03-14 14:13:41 -04:00
MeshComponent - > MarkRenderStateDirty ( ) ;
if ( MeshComponent - > BodyInstance . IsValidBodyInstance ( ) )
{
MeshComponent - > BodyInstance . UpdatePhysicalMaterials ( ) ;
}
}
2015-03-18 10:30:26 -04:00
if ( MeshComponent - > TranslucencySortPriority ! = TranslucencySortPriority )
{
MeshComponent - > Modify ( ) ;
MeshComponent - > TranslucencySortPriority = TranslucencySortPriority ;
MeshComponent - > MarkRenderStateDirty ( ) ;
}
2014-03-14 14:13:41 -04:00
if ( MeshComponent - > LDMaxDrawDistance ! = LDMaxDrawDistance )
{
MeshComponent - > Modify ( ) ;
MeshComponent - > LDMaxDrawDistance = LDMaxDrawDistance ;
MeshComponent - > CachedMaxDrawDistance = 0 ;
MeshComponent - > MarkRenderStateDirty ( ) ;
}
if ( MeshComponent - > CastShadow ! = bCastShadow )
{
MeshComponent - > Modify ( ) ;
MeshComponent - > SetCastShadow ( bCastShadow ) ;
}
2014-05-16 11:12:41 -04:00
const FName CollisionProfile = bEnableCollision ? UCollisionProfile : : BlockAll_ProfileName : UCollisionProfile : : NoCollision_ProfileName ;
if ( MeshComponent - > BodyInstance . GetCollisionProfileName ( ) ! = CollisionProfile )
2014-03-14 14:13:41 -04:00
{
MeshComponent - > Modify ( ) ;
2014-05-16 11:12:41 -04:00
MeshComponent - > BodyInstance . SetCollisionProfileName ( CollisionProfile ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-03-24 13:53:46 -04:00
else
{
MeshComponent = nullptr ;
ForeignWorld = NULL ;
}
2014-03-14 14:13:41 -04:00
2015-03-24 13:53:46 -04:00
// Destroy any unused components
bool bDestroyedAnyComponents = false ;
if ( LocalMeshComponent & & LocalMeshComponent ! = MeshComponent )
{
OuterSplines - > Modify ( ) ;
LocalMeshComponent - > Modify ( ) ;
checkSlow ( OuterSplines - > MeshComponentLocalOwnersMap . FindRef ( LocalMeshComponent ) = = this ) ;
verifySlow ( OuterSplines - > MeshComponentLocalOwnersMap . Remove ( LocalMeshComponent ) = = 1 ) ;
LocalMeshComponent - > DestroyComponent ( ) ;
LocalMeshComponent = nullptr ;
}
for ( auto & ForeignMeshComponentsPair : ForeignMeshComponentsMap )
{
2015-04-09 15:23:52 -04:00
ULandscapeSplinesComponent * ForeignMeshComponentOuterSplines = ForeignMeshComponentsPair . Key ;
2015-03-24 13:53:46 -04:00
auto * ForeignMeshComponent = ForeignMeshComponentsPair . Value ;
if ( ForeignMeshComponent ! = MeshComponent )
{
2015-04-09 15:23:52 -04:00
ForeignMeshComponentOuterSplines - > Modify ( ) ;
2015-03-24 13:53:46 -04:00
ForeignMeshComponent - > Modify ( ) ;
2015-04-09 15:23:52 -04:00
ForeignMeshComponentOuterSplines - > RemoveForeignMeshComponent ( this , ForeignMeshComponent ) ;
2015-03-24 13:53:46 -04:00
ForeignMeshComponent - > DestroyComponent ( ) ;
}
}
ForeignMeshComponentsMap . Empty ( ) ;
if ( bDestroyedAnyComponents )
{
AutoSetConnections ( false ) ;
}
// Update "Points" array
if ( Mesh ! = nullptr )
2014-03-14 14:13:41 -04:00
{
Points . Reset ( ConnectedSegments . Num ( ) ) ;
2014-05-12 08:40:42 -04:00
for ( const FLandscapeSplineConnection & Connection : ConnectedSegments )
2014-03-14 14:13:41 -04:00
{
FVector StartLocation ; FRotator StartRotation ;
GetConnectionLocationAndRotation ( Connection . GetNearConnection ( ) . SocketName , StartLocation , StartRotation ) ;
const float Roll = FMath : : DegreesToRadians ( StartRotation . Roll ) ;
const FVector Tangent = StartRotation . Vector ( ) ;
2014-11-26 10:01:12 -05:00
const FVector BiNormal = FQuat ( Tangent , - Roll ) . RotateVector ( ( Tangent ^ FVector ( 0 , 0 , - 1 ) ) . GetSafeNormal ( ) ) ;
2014-03-14 14:13:41 -04:00
const FVector LeftPos = StartLocation - BiNormal * Width ;
const FVector RightPos = StartLocation + BiNormal * Width ;
const FVector FalloffLeftPos = StartLocation - BiNormal * ( Width + SideFalloff ) ;
const FVector FalloffRightPos = StartLocation + BiNormal * ( Width + SideFalloff ) ;
2015-03-24 13:53:46 -04:00
Points . Emplace ( StartLocation , LeftPos , RightPos , FalloffLeftPos , FalloffRightPos , 1.0f ) ;
2014-03-14 14:13:41 -04:00
}
const FVector CPLocation = Location ;
Points . Sort ( [ & CPLocation ] ( const FLandscapeSplineInterpPoint & x , const FLandscapeSplineInterpPoint & y ) { return ( x . Center - CPLocation ) . Rotation ( ) . Yaw < ( y . Center - CPLocation ) . Rotation ( ) . Yaw ; } ) ;
}
else
{
Points . Reset ( 1 ) ;
FVector StartLocation ; FRotator StartRotation ;
GetConnectionLocationAndRotation ( NAME_None , StartLocation , StartRotation ) ;
const float Roll = FMath : : DegreesToRadians ( StartRotation . Roll ) ;
const FVector Tangent = StartRotation . Vector ( ) ;
2014-11-26 10:01:12 -05:00
const FVector BiNormal = FQuat ( Tangent , - Roll ) . RotateVector ( ( Tangent ^ FVector ( 0 , 0 , - 1 ) ) . GetSafeNormal ( ) ) ;
2014-03-14 14:13:41 -04:00
const FVector LeftPos = StartLocation - BiNormal * Width ;
const FVector RightPos = StartLocation + BiNormal * Width ;
const FVector FalloffLeftPos = StartLocation - BiNormal * ( Width + SideFalloff ) ;
const FVector FalloffRightPos = StartLocation + BiNormal * ( Width + SideFalloff ) ;
2015-03-24 13:53:46 -04:00
Points . Emplace ( StartLocation , LeftPos , RightPos , FalloffLeftPos , FalloffRightPos , 1.0f ) ;
2014-03-14 14:13:41 -04:00
}
// Update Bounds
Bounds = FBox ( 0 ) ;
2014-05-12 08:40:42 -04:00
for ( const FLandscapeSplineInterpPoint & Point : Points )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
Bounds + = Point . FalloffLeft ;
Bounds + = Point . FalloffRight ;
2014-03-14 14:13:41 -04:00
}
OuterSplines - > MarkRenderStateDirty ( ) ;
2014-05-29 16:46:26 -04:00
if ( bUpdateAttachedSegments )
2014-03-14 14:13:41 -04:00
{
2014-05-29 16:46:26 -04:00
for ( const FLandscapeSplineConnection & Connection : ConnectedSegments )
{
Connection . Segment - > UpdateSplinePoints ( bUpdateCollision ) ;
}
2014-03-14 14:13:41 -04:00
}
}
void ULandscapeSplineControlPoint : : DeleteSplinePoints ( )
{
Modify ( ) ;
ULandscapeSplinesComponent * OuterSplines = CastChecked < ULandscapeSplinesComponent > ( GetOuter ( ) ) ;
Points . Reset ( ) ;
Bounds = FBox ( 0 ) ;
OuterSplines - > MarkRenderStateDirty ( ) ;
2015-03-24 13:53:46 -04:00
if ( LocalMeshComponent ! = nullptr )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
OuterSplines - > Modify ( ) ;
checkSlow ( OuterSplines - > MeshComponentLocalOwnersMap . FindRef ( LocalMeshComponent ) = = this ) ;
verifySlow ( OuterSplines - > MeshComponentLocalOwnersMap . Remove ( LocalMeshComponent ) = = 1 ) ;
LocalMeshComponent - > DestroyComponent ( ) ;
LocalMeshComponent = nullptr ;
}
auto ForeignMeshComponentsMap = GetForeignMeshComponents ( ) ;
for ( auto & ForeignMeshComponentsPair : ForeignMeshComponentsMap )
{
ULandscapeSplinesComponent * MeshComponentOuterSplines = ForeignMeshComponentsPair . Key ;
MeshComponentOuterSplines - > Modify ( ) ;
auto * MeshComponent = ForeignMeshComponentsPair . Value ;
MeshComponent - > Modify ( ) ;
MeshComponentOuterSplines - > RemoveForeignMeshComponent ( this , MeshComponent ) ;
2014-03-14 14:13:41 -04:00
MeshComponent - > DestroyComponent ( ) ;
}
}
void ULandscapeSplineControlPoint : : PostEditUndo ( )
{
2014-07-22 07:34:30 -04:00
bHackIsUndoingSplines = true ;
Super : : PostEditUndo ( ) ;
bHackIsUndoingSplines = false ;
2014-03-14 14:13:41 -04:00
GetOuterULandscapeSplinesComponent ( ) - > MarkRenderStateDirty ( ) ;
}
void ULandscapeSplineControlPoint : : PostDuplicate ( bool bDuplicateForPIE )
{
if ( ! bDuplicateForPIE )
{
2015-03-24 13:53:46 -04:00
// if we get duplicated but our local mesh doesn't, then clear our reference to the mesh - it's not ours
if ( LocalMeshComponent ! = nullptr )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
ULandscapeSplinesComponent * OuterSplines = CastChecked < ULandscapeSplinesComponent > ( GetOuter ( ) ) ;
if ( LocalMeshComponent - > GetOuter ( ) ! = OuterSplines - > GetOwner ( ) )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
LocalMeshComponent = nullptr ;
2014-03-14 14:13:41 -04:00
}
}
2015-03-24 13:53:46 -04:00
UpdateSplinePoints ( ) ;
2014-03-14 14:13:41 -04:00
}
Super : : PostDuplicate ( bDuplicateForPIE ) ;
}
void ULandscapeSplineControlPoint : : PostEditImport ( )
{
Super : : PostEditImport ( ) ;
GetOuterULandscapeSplinesComponent ( ) - > ControlPoints . AddUnique ( this ) ;
}
void ULandscapeSplineControlPoint : : PostEditChangeProperty ( FPropertyChangedEvent & PropertyChangedEvent )
{
Super : : PostEditChangeProperty ( PropertyChangedEvent ) ;
Width = FMath : : Max ( Width , 0.001f ) ;
SideFalloff = FMath : : Max ( SideFalloff , 0.0f ) ;
EndFalloff = FMath : : Max ( EndFalloff , 0.0f ) ;
2014-07-22 07:34:30 -04:00
// Don't update splines when undoing, not only is it unnecessary and expensive,
// it also causes failed asserts in debug builds when trying to register components
// (because the actor hasn't reset its OwnedComponents array yet)
if ( ! bHackIsUndoingSplines )
{
const bool bUpdateCollision = PropertyChangedEvent . ChangeType ! = EPropertyChangeType : : Interactive ;
UpdateSplinePoints ( bUpdateCollision ) ;
}
2014-03-14 14:13:41 -04:00
}
# endif // WITH_EDITOR
//////////////////////////////////////////////////////////////////////////
// SPLINE SEGMENT
2014-10-14 10:29:11 -04:00
ULandscapeSplineSegment : : ULandscapeSplineSegment ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
Connections [ 0 ] . ControlPoint = nullptr ;
2014-03-14 14:13:41 -04:00
Connections [ 0 ] . TangentLen = 0 ;
2015-03-24 13:53:46 -04:00
Connections [ 1 ] . ControlPoint = nullptr ;
2014-03-14 14:13:41 -04:00
Connections [ 1 ] . TangentLen = 0 ;
# if WITH_EDITORONLY_DATA
LayerName = NAME_None ;
bRaiseTerrain = true ;
bLowerTerrain = true ;
// SplineMesh properties
SplineMeshes . Empty ( ) ;
LDMaxDrawDistance = 0 ;
2015-03-18 10:30:26 -04:00
TranslucencySortPriority = 0 ;
2015-03-24 13:53:46 -04:00
bPlaceSplineMeshesInStreamingLevels = true ;
2014-03-14 14:13:41 -04:00
bEnableCollision = true ;
bCastShadow = true ;
// transients
bSelected = false ;
# endif
}
void ULandscapeSplineSegment : : PostInitProperties ( )
{
Super : : PostInitProperties ( ) ;
# if WITH_EDITORONLY_DATA
if ( ! HasAnyFlags ( RF_ClassDefaultObject | RF_NeedLoad | RF_AsyncLoading ) )
{
// create a new random seed for all new objects
RandomSeed = FMath : : Rand ( ) ;
}
# endif
}
void ULandscapeSplineSegment : : Serialize ( FArchive & Ar )
{
Super : : Serialize ( Ar ) ;
# if WITH_EDITOR
if ( Ar . UE4Ver ( ) < VER_UE4_SPLINE_MESH_ORIENTATION )
{
2014-05-12 08:40:42 -04:00
for ( FLandscapeSplineMeshEntry & MeshEntry : SplineMeshes )
2014-03-14 14:13:41 -04:00
{
switch ( MeshEntry . Orientation_DEPRECATED )
{
case LSMO_XUp :
MeshEntry . ForwardAxis = ESplineMeshAxis : : Z ;
MeshEntry . UpAxis = ESplineMeshAxis : : X ;
break ;
case LSMO_YUp :
MeshEntry . ForwardAxis = ESplineMeshAxis : : Z ;
MeshEntry . UpAxis = ESplineMeshAxis : : Y ;
break ;
}
}
}
2015-03-24 13:53:46 -04:00
if ( Ar . UE4Ver ( ) < VER_UE4_LANDSCAPE_SPLINE_CROSS_LEVEL_MESHES )
{
bPlaceSplineMeshesInStreamingLevels = false ;
}
2014-03-14 14:13:41 -04:00
# endif
}
void ULandscapeSplineSegment : : PostLoad ( )
{
Super : : PostLoad ( ) ;
# if WITH_EDITOR
if ( GIsEditor )
{
2015-03-24 13:53:46 -04:00
if ( GetLinkerUE4Version ( ) < VER_UE4_ADDED_LANDSCAPE_SPLINE_EDITOR_MESH & &
LocalMeshComponents . Num ( ) = = 0 ) // ForeignMeshComponents didn't exist yet
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
UpdateSplinePoints ( ) ;
}
// Replace null meshes with the editor mesh
// Otherwise the spline will have no mesh and won't be easily selectable
ULandscapeSplinesComponent * OuterSplines = GetOuterULandscapeSplinesComponent ( ) ;
if ( OuterSplines - > SplineEditorMesh ! = nullptr )
{
for ( auto * MeshComponent : LocalMeshComponents )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
if ( MeshComponent - > StaticMesh = = nullptr )
{
MeshComponent - > ConditionalPostLoad ( ) ;
MeshComponent - > SetStaticMesh ( OuterSplines - > SplineEditorMesh ) ;
MeshComponent - > SetHiddenInGame ( true ) ;
MeshComponent - > SetVisibility ( OuterSplines - > bShowSplineEditorMesh ) ;
MeshComponent - > BodyInstance . SetCollisionProfileName ( UCollisionProfile : : NoCollision_ProfileName ) ;
}
2014-03-14 14:13:41 -04:00
}
}
2015-03-24 13:53:46 -04:00
for ( auto * MeshComponent : LocalMeshComponents )
{
OuterSplines - > MeshComponentLocalOwnersMap . Add ( MeshComponent , this ) ;
}
2014-03-14 14:13:41 -04:00
}
2015-03-24 13:53:46 -04:00
if ( GetLinkerUE4Version ( ) < VER_UE4_LANDSCAPE_SPLINE_CROSS_LEVEL_MESHES )
2014-03-14 14:13:41 -04:00
{
2014-05-16 11:12:41 -04:00
// Fix collision profile
2015-03-24 13:53:46 -04:00
for ( auto * MeshComponent : LocalMeshComponents ) // ForeignMeshComponents didn't exist yet
2014-05-16 11:12:41 -04:00
{
2015-03-24 13:53:46 -04:00
const bool bUsingEditorMesh = MeshComponent - > bHiddenInGame ;
const FName CollisionProfile = ( bEnableCollision & & ! bUsingEditorMesh ) ? UCollisionProfile : : BlockAll_ProfileName : UCollisionProfile : : NoCollision_ProfileName ;
if ( MeshComponent - > GetCollisionProfileName ( ) ! = CollisionProfile )
{
MeshComponent - > SetCollisionProfileName ( CollisionProfile ) ;
}
2014-05-16 11:12:41 -04:00
2015-03-24 13:53:46 -04:00
MeshComponent - > SetFlags ( RF_TextExportTransient ) ;
}
2014-03-14 14:13:41 -04:00
}
# endif
}
/** */
# if WITH_EDITOR
void ULandscapeSplineSegment : : SetSplineSelected ( bool bInSelected )
{
bSelected = bInSelected ;
GetOuterULandscapeSplinesComponent ( ) - > MarkRenderStateDirty ( ) ;
2015-03-24 13:53:46 -04:00
for ( auto * MeshComponent : LocalMeshComponents )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
MeshComponent - > bSelected = bInSelected ;
MeshComponent - > PushSelectionToProxy ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-24 13:53:46 -04:00
auto ForeignMeshComponentsMap = GetForeignMeshComponents ( ) ;
for ( auto & ForeignMeshComponentsPair : ForeignMeshComponentsMap )
{
ULandscapeSplinesComponent * MeshComponentOuterSplines = ForeignMeshComponentsPair . Key ;
for ( auto * MeshComponent : ForeignMeshComponentsPair . Value )
{
MeshComponent - > bSelected = bInSelected ;
MeshComponent - > PushSelectionToProxy ( ) ;
}
}
2014-03-14 14:13:41 -04:00
}
void ULandscapeSplineSegment : : AutoFlipTangents ( )
{
FVector StartLocation ; FRotator StartRotation ;
Connections [ 0 ] . ControlPoint - > GetConnectionLocationAndRotation ( Connections [ 0 ] . SocketName , StartLocation , StartRotation ) ;
FVector EndLocation ; FRotator EndRotation ;
Connections [ 1 ] . ControlPoint - > GetConnectionLocationAndRotation ( Connections [ 1 ] . SocketName , EndLocation , EndRotation ) ;
// Flipping the tangent is only allowed if not using a socket
2014-11-26 10:01:12 -05:00
if ( Connections [ 0 ] . SocketName = = NAME_None & & FVector : : DotProduct ( ( EndLocation - StartLocation ) . GetSafeNormal ( ) * Connections [ 0 ] . TangentLen , StartRotation . Vector ( ) ) < 0 )
2014-03-14 14:13:41 -04:00
{
Connections [ 0 ] . TangentLen = - Connections [ 0 ] . TangentLen ;
}
2014-11-26 10:01:12 -05:00
if ( Connections [ 1 ] . SocketName = = NAME_None & & FVector : : DotProduct ( ( StartLocation - EndLocation ) . GetSafeNormal ( ) * Connections [ 1 ] . TangentLen , EndRotation . Vector ( ) ) < 0 )
2014-03-14 14:13:41 -04:00
{
Connections [ 1 ] . TangentLen = - Connections [ 1 ] . TangentLen ;
}
}
# endif
static float ApproxLength ( const FInterpCurveVector & SplineInfo , const float Start = 0.0f , const float End = 1.0f , const int32 ApproxSections = 4 )
{
float SplineLength = 0 ;
FVector OldPos = SplineInfo . Eval ( Start , FVector : : ZeroVector ) ;
for ( int32 i = 1 ; i < = ApproxSections ; i + + )
{
FVector NewPos = SplineInfo . Eval ( FMath : : Lerp ( Start , End , ( float ) i / ( float ) ApproxSections ) , FVector : : ZeroVector ) ;
SplineLength + = ( NewPos - OldPos ) . Size ( ) ;
OldPos = NewPos ;
}
return SplineLength ;
}
static ESplineMeshAxis : : Type CrossAxis ( ESplineMeshAxis : : Type InForwardAxis , ESplineMeshAxis : : Type InUpAxis )
{
check ( InForwardAxis ! = InUpAxis ) ;
return ( ESplineMeshAxis : : Type ) ( 3 ^ InForwardAxis ^ InUpAxis ) ;
}
bool FLandscapeSplineMeshEntry : : IsValid ( ) const
{
2015-03-24 13:53:46 -04:00
return Mesh ! = nullptr & & ForwardAxis ! = UpAxis & & Scale . GetAbsMin ( ) > KINDA_SMALL_NUMBER ;
2014-03-14 14:13:41 -04:00
}
# if WITH_EDITOR
2015-03-24 13:53:46 -04:00
TMap < ULandscapeSplinesComponent * , TArray < USplineMeshComponent * > > ULandscapeSplineSegment : : GetForeignMeshComponents ( )
{
TMap < ULandscapeSplinesComponent * , TArray < USplineMeshComponent * > > ForeignMeshComponentsMap ;
ULandscapeSplinesComponent * OuterSplines = GetOuterULandscapeSplinesComponent ( ) ;
TArray < ULandscapeSplinesComponent * > SplineComponents = OuterSplines - > GetAllStreamingSplinesComponents ( ) ;
for ( ULandscapeSplinesComponent * SplineComponent : SplineComponents )
{
if ( SplineComponent ! = OuterSplines )
{
auto ForeignMeshComponents = SplineComponent - > GetForeignMeshComponents ( this ) ;
if ( ForeignMeshComponents . Num ( ) > 0 )
{
for ( auto * ForeignMeshComponent : ForeignMeshComponents )
{
ForeignMeshComponent - > Modify ( ) ;
}
ForeignMeshComponentsMap . Add ( SplineComponent , MoveTemp ( ForeignMeshComponents ) ) ;
}
}
}
return ForeignMeshComponentsMap ;
}
2014-03-14 14:13:41 -04:00
void ULandscapeSplineSegment : : UpdateSplinePoints ( bool bUpdateCollision )
{
Modify ( ) ;
2015-03-24 13:53:46 -04:00
ULandscapeSplinesComponent * OuterSplines = GetOuterULandscapeSplinesComponent ( ) ;
2014-03-14 14:13:41 -04:00
SplineInfo . Points . Empty ( 2 ) ;
Points . Reset ( ) ;
2015-03-24 13:53:46 -04:00
if ( Connections [ 0 ] . ControlPoint = = nullptr
| | Connections [ 1 ] . ControlPoint = = nullptr )
2014-03-14 14:13:41 -04:00
{
return ;
}
// Set up BSpline
FVector StartLocation ; FRotator StartRotation ;
Connections [ 0 ] . ControlPoint - > GetConnectionLocationAndRotation ( Connections [ 0 ] . SocketName , StartLocation , StartRotation ) ;
2015-02-02 04:36:43 -05:00
SplineInfo . Points . Emplace ( 0.0f , StartLocation , StartRotation . Vector ( ) * Connections [ 0 ] . TangentLen , StartRotation . Vector ( ) * Connections [ 0 ] . TangentLen , CIM_CurveUser ) ;
2014-03-14 14:13:41 -04:00
FVector EndLocation ; FRotator EndRotation ;
Connections [ 1 ] . ControlPoint - > GetConnectionLocationAndRotation ( Connections [ 1 ] . SocketName , EndLocation , EndRotation ) ;
2015-02-02 04:36:43 -05:00
SplineInfo . Points . Emplace ( 1.0f , EndLocation , EndRotation . Vector ( ) * - Connections [ 1 ] . TangentLen , EndRotation . Vector ( ) * - Connections [ 1 ] . TangentLen , CIM_CurveUser ) ;
2014-03-14 14:13:41 -04:00
// Pointify
// Calculate spline length
const float SplineLength = ApproxLength ( SplineInfo , 0.0f , 1.0f , 4 ) ;
2015-02-02 04:36:43 -05:00
const float StartFalloffFraction = ( ( Connections [ 0 ] . ControlPoint - > ConnectedSegments . Num ( ) > 1 ) ? 0 : ( Connections [ 0 ] . ControlPoint - > EndFalloff / SplineLength ) ) ;
const float EndFalloffFraction = ( ( Connections [ 1 ] . ControlPoint - > ConnectedSegments . Num ( ) > 1 ) ? 0 : ( Connections [ 1 ] . ControlPoint - > EndFalloff / SplineLength ) ) ;
2014-03-14 14:13:41 -04:00
const float StartWidth = Connections [ 0 ] . ControlPoint - > Width ;
const float EndWidth = Connections [ 1 ] . ControlPoint - > Width ;
const float StartSideFalloff = Connections [ 0 ] . ControlPoint - > SideFalloff ;
const float EndSideFalloff = Connections [ 1 ] . ControlPoint - > SideFalloff ;
const float StartRollDegrees = StartRotation . Roll * ( Connections [ 0 ] . TangentLen > 0 ? 1 : - 1 ) ;
const float EndRollDegrees = EndRotation . Roll * ( Connections [ 1 ] . TangentLen > 0 ? - 1 : 1 ) ;
const float StartRoll = FMath : : DegreesToRadians ( StartRollDegrees ) ;
const float EndRoll = FMath : : DegreesToRadians ( EndRollDegrees ) ;
2014-05-06 06:26:25 -04:00
int32 NumPoints = FMath : : CeilToInt ( SplineLength / OuterSplines - > SplineResolution ) ;
2014-03-14 14:13:41 -04:00
NumPoints = FMath : : Clamp ( NumPoints , 1 , 1000 ) ;
2015-02-02 04:36:43 -05:00
LandscapeSplineRaster : : Pointify ( SplineInfo , Points , NumPoints , StartFalloffFraction , EndFalloffFraction , StartWidth , EndWidth , StartSideFalloff , EndSideFalloff , StartRollDegrees , EndRollDegrees ) ;
2014-03-14 14:13:41 -04:00
// Update Bounds
Bounds = FBox ( 0 ) ;
2014-05-12 08:40:42 -04:00
for ( const FLandscapeSplineInterpPoint & Point : Points )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
Bounds + = Point . FalloffLeft ;
Bounds + = Point . FalloffRight ;
2014-03-14 14:13:41 -04:00
}
OuterSplines - > MarkRenderStateDirty ( ) ;
// Spline mesh components
TArray < const FLandscapeSplineMeshEntry * > UsableMeshes ;
UsableMeshes . Reserve ( SplineMeshes . Num ( ) ) ;
2014-05-12 08:40:42 -04:00
for ( const FLandscapeSplineMeshEntry & MeshEntry : SplineMeshes )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
if ( MeshEntry . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
UsableMeshes . Add ( & MeshEntry ) ;
2014-03-14 14:13:41 -04:00
}
}
// Editor mesh
bool bUsingEditorMesh = false ;
2015-04-13 10:10:38 -04:00
FLandscapeSplineMeshEntry SplineEditorMeshEntry ;
2015-03-24 13:53:46 -04:00
if ( UsableMeshes . Num ( ) = = 0 & & OuterSplines - > SplineEditorMesh ! = nullptr )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
SplineEditorMeshEntry . Mesh = OuterSplines - > SplineEditorMesh ;
2015-04-13 10:10:38 -04:00
SplineEditorMeshEntry . MaterialOverrides = { } ;
SplineEditorMeshEntry . bCenterH = true ;
SplineEditorMeshEntry . Offset = { 0.0f , 0.5f } ;
SplineEditorMeshEntry . bScaleToWidth = true ;
SplineEditorMeshEntry . Scale = { 3 , 1 , 1 } ;
SplineEditorMeshEntry . ForwardAxis = ESplineMeshAxis : : X ;
SplineEditorMeshEntry . UpAxis = ESplineMeshAxis : : Z ;
2014-03-14 14:13:41 -04:00
UsableMeshes . Add ( & SplineEditorMeshEntry ) ;
2015-03-24 13:53:46 -04:00
bUsingEditorMesh = true ;
2014-03-14 14:13:41 -04:00
}
OuterSplines - > Modify ( ) ;
2015-03-24 13:53:46 -04:00
TArray < USplineMeshComponent * > MeshComponents ;
TArray < USplineMeshComponent * > OldLocalMeshComponents = MoveTemp ( LocalMeshComponents ) ;
LocalMeshComponents . Reserve ( 20 ) ;
auto ForeignMeshComponentsMap = GetForeignMeshComponents ( ) ;
// Unregister components
for ( auto * MeshComponent : OldLocalMeshComponents )
2014-03-14 14:13:41 -04:00
{
2014-05-12 08:40:42 -04:00
MeshComponent - > Modify ( ) ;
2015-03-24 13:53:46 -04:00
MeshComponent - > UnregisterComponent ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-24 13:53:46 -04:00
for ( auto & ForeignMeshComponentsPair : ForeignMeshComponentsMap )
{
ForeignMeshComponentsPair . Key - > Modify ( ) ;
ForeignMeshComponentsPair . Key - > GetOwner ( ) - > Modify ( ) ;
for ( auto * MeshComponent : ForeignMeshComponentsPair . Value )
{
MeshComponent - > Modify ( ) ;
MeshComponent - > UnregisterComponent ( ) ;
}
}
ModificationKey = FGuid : : NewGuid ( ) ;
ForeignWorlds . Reset ( ) ;
2014-03-14 14:13:41 -04:00
if ( SplineLength > 0 & & ( StartWidth > 0 | | EndWidth > 0 ) & & UsableMeshes . Num ( ) > 0 )
{
float T = 0 ;
int32 iMesh = 0 ;
struct FMeshSettings
{
const float T ;
2014-05-12 08:40:42 -04:00
const FLandscapeSplineMeshEntry * const MeshEntry ;
2014-03-14 14:13:41 -04:00
2014-05-12 08:40:42 -04:00
FMeshSettings ( float InT , const FLandscapeSplineMeshEntry * const InMeshEntry ) :
2014-03-14 14:13:41 -04:00
T ( InT ) , MeshEntry ( InMeshEntry ) { }
} ;
TArray < FMeshSettings > MeshSettings ;
MeshSettings . Reserve ( 21 ) ;
FRandomStream Random ( RandomSeed ) ;
// First pass:
// Choose meshes, create components, calculate lengths
while ( T < 1.0f & & iMesh < 20 ) // Max 20 meshes per spline segment
{
const float CosInterp = 0.5f - 0.5f * FMath : : Cos ( T * PI ) ;
const float Width = FMath : : Lerp ( StartWidth , EndWidth , CosInterp ) ;
const FLandscapeSplineMeshEntry * MeshEntry = UsableMeshes [ Random . RandHelper ( UsableMeshes . Num ( ) ) ] ;
UStaticMesh * Mesh = MeshEntry - > Mesh ;
const FBoxSphereBounds MeshBounds = Mesh - > GetBounds ( ) ;
FVector Scale = MeshEntry - > Scale ;
if ( MeshEntry - > bScaleToWidth )
{
2014-06-04 09:10:57 -04:00
Scale * = Width / USplineMeshComponent : : GetAxisValue ( MeshBounds . BoxExtent , CrossAxis ( MeshEntry - > ForwardAxis , MeshEntry - > UpAxis ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-06-04 09:10:57 -04:00
const float MeshLength = FMath : : Abs ( USplineMeshComponent : : GetAxisValue ( MeshBounds . BoxExtent , MeshEntry - > ForwardAxis ) * 2 * USplineMeshComponent : : GetAxisValue ( Scale , MeshEntry - > ForwardAxis ) ) ;
2014-03-14 14:13:41 -04:00
float MeshT = ( MeshLength / SplineLength ) ;
// Improve our approximation if we're not going off the end of the spline
if ( T + MeshT < = 1.0f )
{
MeshT * = ( MeshLength / ApproxLength ( SplineInfo , T , T + MeshT , 4 ) ) ;
MeshT * = ( MeshLength / ApproxLength ( SplineInfo , T , T + MeshT , 4 ) ) ;
}
// If it's smaller to round up than down, don't add another component
if ( iMesh ! = 0 & & ( 1.0f - T ) < ( T + MeshT - 1.0f ) )
{
break ;
}
2015-03-24 13:53:46 -04:00
ULandscapeSplinesComponent * MeshComponentOuterSplines = OuterSplines ;
// Attempt to place mesh components into the appropriate landscape streaming levels based on the components under the spline
if ( bPlaceSplineMeshesInStreamingLevels & & ! bUsingEditorMesh )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
// Only "approx" because we rescale T for the 2nd pass based on how well our chosen meshes fit, but it should be good enough
FVector ApproxMeshLocation = SplineInfo . Eval ( T + MeshT / 2 , FVector : : ZeroVector ) ;
MeshComponentOuterSplines = OuterSplines - > GetStreamingSplinesComponentByLocation ( ApproxMeshLocation ) ;
MeshComponentOuterSplines - > Modify ( ) ;
}
USplineMeshComponent * MeshComponent = nullptr ;
if ( MeshComponentOuterSplines = = OuterSplines )
{
if ( OldLocalMeshComponents . Num ( ) > 0 )
{
MeshComponent = OldLocalMeshComponents . Pop ( false ) ;
LocalMeshComponents . Add ( MeshComponent ) ;
}
2014-03-14 14:13:41 -04:00
}
else
{
2015-03-24 13:53:46 -04:00
TArray < USplineMeshComponent * > * ForeignMeshComponents = ForeignMeshComponentsMap . Find ( MeshComponentOuterSplines ) ;
if ( ForeignMeshComponents & & ForeignMeshComponents - > Num ( ) > 0 )
{
MeshComponentOuterSplines - > UpdateModificationKey ( this ) ;
MeshComponent = ForeignMeshComponents - > Pop ( false ) ;
ForeignWorlds . AddUnique ( MeshComponentOuterSplines - > GetTypedOuter < UWorld > ( ) ) ;
}
2014-03-14 14:13:41 -04:00
}
2015-03-24 13:53:46 -04:00
if ( ! MeshComponent )
{
AActor * MeshComponentOuterActor = MeshComponentOuterSplines - > GetOwner ( ) ;
MeshComponentOuterActor - > Modify ( ) ;
MeshComponent = NewObject < USplineMeshComponent > ( MeshComponentOuterActor , NAME_None , RF_Transactional | RF_TextExportTransient ) ;
MeshComponent - > bSelected = bSelected ;
MeshComponent - > AttachTo ( MeshComponentOuterSplines ) ;
if ( MeshComponentOuterSplines = = OuterSplines )
{
LocalMeshComponents . Add ( MeshComponent ) ;
MeshComponentOuterSplines - > MeshComponentLocalOwnersMap . Add ( MeshComponent , this ) ;
}
else
{
MeshComponentOuterSplines - > AddForeignMeshComponent ( this , MeshComponent ) ;
ForeignWorlds . AddUnique ( MeshComponentOuterSplines - > GetTypedOuter < UWorld > ( ) ) ;
}
}
MeshComponents . Add ( MeshComponent ) ;
2014-03-14 14:13:41 -04:00
MeshComponent - > SetStaticMesh ( Mesh ) ;
2014-11-26 15:31:30 -05:00
MeshComponent - > OverrideMaterials = MeshEntry - > MaterialOverrides ;
2014-03-14 14:13:41 -04:00
MeshComponent - > MarkRenderStateDirty ( ) ;
if ( MeshComponent - > BodyInstance . IsValidBodyInstance ( ) )
{
MeshComponent - > BodyInstance . UpdatePhysicalMaterials ( ) ;
}
MeshComponent - > SetHiddenInGame ( bUsingEditorMesh ) ;
MeshComponent - > SetVisibility ( ! bUsingEditorMesh | | OuterSplines - > bShowSplineEditorMesh ) ;
MeshSettings . Add ( FMeshSettings ( T , MeshEntry ) ) ;
iMesh + + ;
T + = MeshT ;
}
2015-03-24 13:53:46 -04:00
// Add terminating key
MeshSettings . Add ( FMeshSettings ( T , nullptr ) ) ;
2014-03-14 14:13:41 -04:00
2015-03-24 13:53:46 -04:00
// Destroy old unwanted components now
for ( UMeshComponent * MeshComponent : OldLocalMeshComponents )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
verifySlow ( OuterSplines - > MeshComponentLocalOwnersMap . Remove ( MeshComponent ) = = 1 ) ;
MeshComponent - > DestroyComponent ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-24 13:53:46 -04:00
OldLocalMeshComponents . Empty ( ) ;
for ( auto & ForeignMeshComponentsPair : ForeignMeshComponentsMap )
{
ULandscapeSplinesComponent * MeshComponentOuterSplines = ForeignMeshComponentsPair . Key ;
for ( auto * MeshComponent : ForeignMeshComponentsPair . Value )
{
MeshComponentOuterSplines - > RemoveForeignMeshComponent ( this , MeshComponent ) ;
MeshComponent - > DestroyComponent ( ) ;
}
}
ForeignMeshComponentsMap . Empty ( ) ;
2014-03-14 14:13:41 -04:00
// Second pass:
// Rescale components to fit a whole number to the spline, set up final parameters
const float Rescale = 1.0f / T ;
for ( int32 i = 0 ; i < MeshComponents . Num ( ) ; i + + )
{
USplineMeshComponent * const MeshComponent = MeshComponents [ i ] ;
const UStaticMesh * const Mesh = MeshComponent - > StaticMesh ;
const FBoxSphereBounds MeshBounds = Mesh - > GetBounds ( ) ;
2014-05-29 17:14:20 -04:00
const float RescaledT = MeshSettings [ i ] . T * Rescale ;
2014-03-14 14:13:41 -04:00
const FLandscapeSplineMeshEntry * MeshEntry = MeshSettings [ i ] . MeshEntry ;
const ESplineMeshAxis : : Type SideAxis = CrossAxis ( MeshEntry - > ForwardAxis , MeshEntry - > UpAxis ) ;
const float TEnd = MeshSettings [ i + 1 ] . T * Rescale ;
2014-05-29 17:14:20 -04:00
const float CosInterp = 0.5f - 0.5f * FMath : : Cos ( RescaledT * PI ) ;
2014-03-14 14:13:41 -04:00
const float Width = FMath : : Lerp ( StartWidth , EndWidth , CosInterp ) ;
const bool bDoOrientationRoll = ( MeshEntry - > ForwardAxis = = ESplineMeshAxis : : X & & MeshEntry - > UpAxis = = ESplineMeshAxis : : Y ) | |
( MeshEntry - > ForwardAxis = = ESplineMeshAxis : : Y & & MeshEntry - > UpAxis = = ESplineMeshAxis : : Z ) | |
( MeshEntry - > ForwardAxis = = ESplineMeshAxis : : Z & & MeshEntry - > UpAxis = = ESplineMeshAxis : : X ) ;
const float Roll = FMath : : Lerp ( StartRoll , EndRoll , CosInterp ) + ( bDoOrientationRoll ? - HALF_PI : 0 ) ;
FVector Scale = MeshEntry - > Scale ;
if ( MeshEntry - > bScaleToWidth )
{
2014-06-04 09:10:57 -04:00
Scale * = Width / USplineMeshComponent : : GetAxisValue ( MeshBounds . BoxExtent , SideAxis ) ;
2014-03-14 14:13:41 -04:00
}
FVector2D Offset = MeshEntry - > Offset ;
if ( MeshEntry - > bCenterH )
{
if ( bDoOrientationRoll )
{
2014-06-04 09:10:57 -04:00
Offset . Y - = USplineMeshComponent : : GetAxisValue ( MeshBounds . Origin , SideAxis ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-06-04 09:10:57 -04:00
Offset . X - = USplineMeshComponent : : GetAxisValue ( MeshBounds . Origin , SideAxis ) ;
2014-03-14 14:13:41 -04:00
}
}
FVector2D Scale2D ;
switch ( MeshEntry - > ForwardAxis )
{
case ESplineMeshAxis : : X :
Scale2D = FVector2D ( Scale . Y , Scale . Z ) ;
break ;
case ESplineMeshAxis : : Y :
Scale2D = FVector2D ( Scale . Z , Scale . X ) ;
break ;
case ESplineMeshAxis : : Z :
Scale2D = FVector2D ( Scale . X , Scale . Y ) ;
break ;
default :
check ( 0 ) ;
break ;
}
Offset * = Scale2D ;
2015-02-02 04:36:43 -05:00
Offset = Offset . GetRotated ( - Roll ) ;
2014-03-14 14:13:41 -04:00
2014-05-29 17:14:20 -04:00
MeshComponent - > SplineParams . StartPos = SplineInfo . Eval ( RescaledT , FVector : : ZeroVector ) ;
MeshComponent - > SplineParams . StartTangent = SplineInfo . EvalDerivative ( RescaledT , FVector : : ZeroVector ) * ( TEnd - RescaledT ) ;
2014-03-14 14:13:41 -04:00
MeshComponent - > SplineParams . StartScale = Scale2D ;
MeshComponent - > SplineParams . StartRoll = Roll ;
MeshComponent - > SplineParams . StartOffset = Offset ;
const float CosInterpEnd = 0.5f - 0.5f * FMath : : Cos ( TEnd * PI ) ;
const float WidthEnd = FMath : : Lerp ( StartWidth , EndWidth , CosInterpEnd ) ;
const float RollEnd = FMath : : Lerp ( StartRoll , EndRoll , CosInterpEnd ) + ( bDoOrientationRoll ? - HALF_PI : 0 ) ;
FVector ScaleEnd = MeshEntry - > Scale ;
if ( MeshEntry - > bScaleToWidth )
{
2014-06-04 09:10:57 -04:00
ScaleEnd * = WidthEnd / USplineMeshComponent : : GetAxisValue ( MeshBounds . BoxExtent , SideAxis ) ;
2014-03-14 14:13:41 -04:00
}
FVector2D OffsetEnd = MeshEntry - > Offset ;
if ( MeshEntry - > bCenterH )
{
if ( bDoOrientationRoll )
{
2014-06-04 09:10:57 -04:00
OffsetEnd . Y - = USplineMeshComponent : : GetAxisValue ( MeshBounds . Origin , SideAxis ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-06-04 09:10:57 -04:00
OffsetEnd . X - = USplineMeshComponent : : GetAxisValue ( MeshBounds . Origin , SideAxis ) ;
2014-03-14 14:13:41 -04:00
}
}
FVector2D Scale2DEnd ;
switch ( MeshEntry - > ForwardAxis )
{
case ESplineMeshAxis : : X :
Scale2DEnd = FVector2D ( ScaleEnd . Y , ScaleEnd . Z ) ;
break ;
case ESplineMeshAxis : : Y :
Scale2DEnd = FVector2D ( ScaleEnd . Z , ScaleEnd . X ) ;
break ;
case ESplineMeshAxis : : Z :
Scale2DEnd = FVector2D ( ScaleEnd . X , ScaleEnd . Y ) ;
break ;
default :
check ( 0 ) ;
break ;
}
OffsetEnd * = Scale2DEnd ;
2015-02-02 04:36:43 -05:00
OffsetEnd = OffsetEnd . GetRotated ( - RollEnd ) ;
2014-03-14 14:13:41 -04:00
MeshComponent - > SplineParams . EndPos = SplineInfo . Eval ( TEnd , FVector : : ZeroVector ) ;
2014-05-29 17:14:20 -04:00
MeshComponent - > SplineParams . EndTangent = SplineInfo . EvalDerivative ( TEnd , FVector : : ZeroVector ) * ( TEnd - RescaledT ) ;
2014-03-14 14:13:41 -04:00
MeshComponent - > SplineParams . EndScale = Scale2DEnd ;
MeshComponent - > SplineParams . EndRoll = RollEnd ;
MeshComponent - > SplineParams . EndOffset = OffsetEnd ;
2014-06-05 12:13:19 -04:00
MeshComponent - > SplineUpDir = FVector ( 0 , 0 , 1 ) ; // Up, to be consistent between joined meshes. We rotate it to horizontal using roll if using Z Forward X Up or X Forward Y Up
2014-03-14 14:13:41 -04:00
MeshComponent - > ForwardAxis = MeshEntry - > ForwardAxis ;
2015-03-24 13:53:46 -04:00
if ( MeshComponent - > AttachParent ! = OuterSplines )
{
FTransform RelativeTransform = OuterSplines - > ComponentToWorld . GetRelativeTransform ( MeshComponent - > AttachParent - > ComponentToWorld ) ;
MeshComponent - > SplineParams . StartPos = RelativeTransform . TransformPosition ( MeshComponent - > SplineParams . StartPos ) ;
MeshComponent - > SplineParams . EndPos = RelativeTransform . TransformPosition ( MeshComponent - > SplineParams . EndPos ) ;
}
2014-06-04 09:10:57 -04:00
if ( USplineMeshComponent : : GetAxisValue ( MeshEntry - > Scale , MeshEntry - > ForwardAxis ) < 0 )
2014-03-14 14:13:41 -04:00
{
Swap ( MeshComponent - > SplineParams . StartPos , MeshComponent - > SplineParams . EndPos ) ;
Swap ( MeshComponent - > SplineParams . StartTangent , MeshComponent - > SplineParams . EndTangent ) ;
Swap ( MeshComponent - > SplineParams . StartScale , MeshComponent - > SplineParams . EndScale ) ;
Swap ( MeshComponent - > SplineParams . StartRoll , MeshComponent - > SplineParams . EndRoll ) ;
Swap ( MeshComponent - > SplineParams . StartOffset , MeshComponent - > SplineParams . EndOffset ) ;
MeshComponent - > SplineParams . StartTangent = - MeshComponent - > SplineParams . StartTangent ;
MeshComponent - > SplineParams . EndTangent = - MeshComponent - > SplineParams . EndTangent ;
MeshComponent - > SplineParams . StartScale . X = - MeshComponent - > SplineParams . StartScale . X ;
MeshComponent - > SplineParams . EndScale . X = - MeshComponent - > SplineParams . EndScale . X ;
MeshComponent - > SplineParams . StartRoll = - MeshComponent - > SplineParams . StartRoll ;
MeshComponent - > SplineParams . EndRoll = - MeshComponent - > SplineParams . EndRoll ;
MeshComponent - > SplineParams . StartOffset . X = - MeshComponent - > SplineParams . StartOffset . X ;
MeshComponent - > SplineParams . EndOffset . X = - MeshComponent - > SplineParams . EndOffset . X ;
}
// Set Mesh component's location to half way between the start and end points. Improves the bounds and allows LDMaxDrawDistance to work
MeshComponent - > RelativeLocation = ( MeshComponent - > SplineParams . StartPos + MeshComponent - > SplineParams . EndPos ) / 2 ;
MeshComponent - > SplineParams . StartPos - = MeshComponent - > RelativeLocation ;
MeshComponent - > SplineParams . EndPos - = MeshComponent - > RelativeLocation ;
if ( MeshComponent - > LDMaxDrawDistance ! = LDMaxDrawDistance )
{
MeshComponent - > LDMaxDrawDistance = LDMaxDrawDistance ;
MeshComponent - > CachedMaxDrawDistance = 0 ;
}
2015-03-18 10:30:26 -04:00
MeshComponent - > TranslucencySortPriority = TranslucencySortPriority ;
2014-03-14 14:13:41 -04:00
MeshComponent - > SetCastShadow ( bCastShadow ) ;
MeshComponent - > InvalidateLightingCache ( ) ;
2014-05-16 11:12:41 -04:00
MeshComponent - > BodyInstance . SetCollisionProfileName ( ( bEnableCollision & & ! bUsingEditorMesh ) ? UCollisionProfile : : BlockAll_ProfileName : UCollisionProfile : : NoCollision_ProfileName ) ;
2014-03-14 14:13:41 -04:00
# if WITH_EDITOR
if ( bUpdateCollision )
{
MeshComponent - > RecreateCollision ( ) ;
}
else
{
if ( MeshComponent - > BodySetup )
{
MeshComponent - > BodySetup - > InvalidatePhysicsData ( ) ;
MeshComponent - > BodySetup - > AggGeom . EmptyElements ( ) ;
}
}
# endif
}
// Finally, register components
2015-03-24 13:53:46 -04:00
for ( auto * MeshComponent : MeshComponents )
{
MeshComponent - > RegisterComponent ( ) ;
}
2014-03-14 14:13:41 -04:00
}
else
{
2015-03-24 13:53:46 -04:00
// Spline needs no mesh components (0 length or no meshes to use) so destroy any we have
for ( auto * MeshComponent : OldLocalMeshComponents )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
verifySlow ( OuterSplines - > MeshComponentLocalOwnersMap . Remove ( MeshComponent ) = = 1 ) ;
MeshComponent - > DestroyComponent ( ) ;
}
OldLocalMeshComponents . Empty ( ) ;
for ( auto & ForeignMeshComponentsPair : ForeignMeshComponentsMap )
{
for ( USplineMeshComponent * MeshComponent : ForeignMeshComponentsPair . Value )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
ULandscapeSplinesComponent * MeshComponentOuterSplines = dynamic_cast < ULandscapeSplinesComponent * > ( MeshComponent - > GetAttachParent ( ) ) ;
if ( MeshComponentOuterSplines )
{
MeshComponentOuterSplines - > RemoveForeignMeshComponent ( this , MeshComponent ) ;
}
2014-05-12 08:40:42 -04:00
MeshComponent - > DestroyComponent ( ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-03-24 13:53:46 -04:00
ForeignMeshComponentsMap . Empty ( ) ;
2014-03-14 14:13:41 -04:00
}
}
void ULandscapeSplineSegment : : UpdateSplineEditorMesh ( )
{
ULandscapeSplinesComponent * OuterSplines = CastChecked < ULandscapeSplinesComponent > ( GetOuter ( ) ) ;
2015-03-24 13:53:46 -04:00
for ( auto * MeshComponent : LocalMeshComponents )
2014-03-14 14:13:41 -04:00
{
if ( MeshComponent - > bHiddenInGame )
{
MeshComponent - > SetVisibility ( OuterSplines - > bShowSplineEditorMesh ) ;
}
}
2015-03-24 13:53:46 -04:00
auto ForeignMeshComponentsMap = GetForeignMeshComponents ( ) ;
for ( auto & ForeignMeshComponentsPair : ForeignMeshComponentsMap )
{
for ( auto * MeshComponent : ForeignMeshComponentsPair . Value )
{
if ( MeshComponent - > bHiddenInGame )
{
MeshComponent - > SetVisibility ( OuterSplines - > bShowSplineEditorMesh ) ;
}
}
}
2014-03-14 14:13:41 -04:00
}
void ULandscapeSplineSegment : : DeleteSplinePoints ( )
{
Modify ( ) ;
2015-03-24 13:53:46 -04:00
ULandscapeSplinesComponent * OuterSplines = GetOuterULandscapeSplinesComponent ( ) ;
2014-03-14 14:13:41 -04:00
SplineInfo . Reset ( ) ;
Points . Reset ( ) ;
Bounds = FBox ( 0 ) ;
OuterSplines - > MarkRenderStateDirty ( ) ;
2015-03-24 13:53:46 -04:00
// Destroy mesh components
OuterSplines - > GetOwner ( ) - > Modify ( ) ;
for ( auto * MeshComponent : LocalMeshComponents )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
MeshComponent - > Modify ( ) ;
2014-03-14 14:13:41 -04:00
MeshComponent - > DestroyComponent ( ) ;
}
2015-03-24 13:53:46 -04:00
LocalMeshComponents . Empty ( ) ;
auto ForeignMeshComponentsMap = GetForeignMeshComponents ( ) ;
for ( auto & ForeignMeshComponentsPair : ForeignMeshComponentsMap )
{
ULandscapeSplinesComponent * MeshComponentOuterSplines = ForeignMeshComponentsPair . Key ;
MeshComponentOuterSplines - > Modify ( ) ;
MeshComponentOuterSplines - > GetOwner ( ) - > Modify ( ) ;
for ( auto * MeshComponent : ForeignMeshComponentsPair . Value )
{
MeshComponent - > Modify ( ) ;
MeshComponentOuterSplines - > RemoveForeignMeshComponent ( this , MeshComponent ) ;
MeshComponent - > DestroyComponent ( ) ;
}
}
ModificationKey . Invalidate ( ) ;
ForeignWorlds . Empty ( ) ;
2014-03-14 14:13:41 -04:00
}
# endif
void ULandscapeSplineSegment : : FindNearest ( const FVector & InLocation , float & t , FVector & OutLocation , FVector & OutTangent )
{
float TempOutDistanceSq ;
t = SplineInfo . InaccurateFindNearest ( InLocation , TempOutDistanceSq ) ;
OutLocation = SplineInfo . Eval ( t , FVector : : ZeroVector ) ;
OutTangent = SplineInfo . EvalDerivative ( t , FVector : : ZeroVector ) ;
}
bool ULandscapeSplineSegment : : Modify ( bool bAlwaysMarkDirty /*= true*/ )
{
bool bSavedToTransactionBuffer = Super : : Modify ( bAlwaysMarkDirty ) ;
2015-03-24 13:53:46 -04:00
//for (auto MeshComponent : MeshComponents)
//{
// if (MeshComponent)
// {
// bSavedToTransactionBuffer = MeshComponent->Modify(bAlwaysMarkDirty) || bSavedToTransactionBuffer;
// }
//}
2014-03-14 14:13:41 -04:00
return bSavedToTransactionBuffer ;
}
# if WITH_EDITOR
void ULandscapeSplineSegment : : PostEditUndo ( )
{
2014-07-22 07:34:30 -04:00
bHackIsUndoingSplines = true ;
Super : : PostEditUndo ( ) ;
bHackIsUndoingSplines = false ;
2014-03-14 14:13:41 -04:00
GetOuterULandscapeSplinesComponent ( ) - > MarkRenderStateDirty ( ) ;
}
void ULandscapeSplineSegment : : PostDuplicate ( bool bDuplicateForPIE )
{
if ( ! bDuplicateForPIE )
{
2015-03-24 13:53:46 -04:00
// if we get duplicated but our local meshes don't, then clear our reference to the meshes - they're not ours
if ( LocalMeshComponents . Num ( ) > 0 )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
ULandscapeSplinesComponent * OuterSplines = CastChecked < ULandscapeSplinesComponent > ( GetOuter ( ) ) ;
// we assume all meshes are duplicated or none are, to avoid testing every one
if ( LocalMeshComponents [ 0 ] - > GetOuter ( ) ! = OuterSplines - > GetOwner ( ) )
2014-03-14 14:13:41 -04:00
{
2015-03-24 13:53:46 -04:00
LocalMeshComponents . Empty ( ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-03-24 13:53:46 -04:00
UpdateSplinePoints ( ) ;
2014-03-14 14:13:41 -04:00
}
Super : : PostDuplicate ( bDuplicateForPIE ) ;
}
void ULandscapeSplineSegment : : PostEditImport ( )
{
Super : : PostEditImport ( ) ;
GetOuterULandscapeSplinesComponent ( ) - > Segments . AddUnique ( this ) ;
2015-03-24 13:53:46 -04:00
if ( Connections [ 0 ] . ControlPoint ! = nullptr )
2014-03-14 14:13:41 -04:00
{
Connections [ 0 ] . ControlPoint - > ConnectedSegments . AddUnique ( FLandscapeSplineConnection ( this , 0 ) ) ;
Connections [ 1 ] . ControlPoint - > ConnectedSegments . AddUnique ( FLandscapeSplineConnection ( this , 1 ) ) ;
}
}
void ULandscapeSplineSegment : : PostEditChangeProperty ( FPropertyChangedEvent & PropertyChangedEvent )
{
Super : : PostEditChangeProperty ( PropertyChangedEvent ) ;
// Flipping the tangent is only allowed if not using a socket
if ( Connections [ 0 ] . SocketName ! = NAME_None )
{
Connections [ 0 ] . TangentLen = FMath : : Abs ( Connections [ 0 ] . TangentLen ) ;
}
if ( Connections [ 1 ] . SocketName ! = NAME_None )
{
Connections [ 1 ] . TangentLen = FMath : : Abs ( Connections [ 1 ] . TangentLen ) ;
}
2014-07-22 07:34:30 -04:00
// Don't update splines when undoing, not only is it unnecessary and expensive,
// it also causes failed asserts in debug builds when trying to register components
// (because the actor hasn't reset its OwnedComponents array yet)
if ( ! bHackIsUndoingSplines )
{
const bool bUpdateCollision = PropertyChangedEvent . ChangeType ! = EPropertyChangeType : : Interactive ;
UpdateSplinePoints ( bUpdateCollision ) ;
}
2014-03-14 14:13:41 -04:00
}
# endif // WITH_EDITOR
2015-03-24 13:53:46 -04:00
# undef LOCTEXT_NAMESPACE