FTransform FActorPositioning::GetCurrentViewportPlacementTransform(const AActor& Actor, bool bSnap)
{
	FVector Collision = Actor.GetPlacementExtent();
	const UActorFactory* Factory = GEditor->FindActorFactoryForActorClass(Actor.GetClass());

	// Get cursor origin and direction in world space.
	FViewportCursorLocation CursorLocation = GCurrentLevelEditingViewportClient->GetCursorWorldLocationFromMousePos();
	const auto CursorPos = CursorLocation.GetCursorPos();

	FTransform ActorTransform = FTransform::Identity;

	if (CursorLocation.GetViewportType() == LVT_Perspective && !GCurrentLevelEditingViewportClient->Viewport->GetHitProxy( CursorPos.X, CursorPos.Y ))
	{
		ActorTransform.SetTranslation(GetActorPositionInFrontOfCamera(Actor, CursorLocation.GetOrigin(), CursorLocation.GetDirection()));
	}
	else
	{
		const FSnappedPositioningData PositioningData = FSnappedPositioningData(GCurrentLevelEditingViewportClient, GEditor->ClickLocation, GEditor->ClickPlane)
			.DrawSnapHelpers(true)
			.UseFactory(Factory)
			.UsePlacementExtent(Actor.GetPlacementExtent());

		ActorTransform = bSnap ? GetSnappedSurfaceAlignedTransform(PositioningData) : GetSurfaceAlignedTransform(PositioningData);

		if (GetDefault<ULevelEditorViewportSettings>()->SnapToSurface.bEnabled)
		{
			// HACK: If we are aligning rotation to surfaces, we have to factor in the inverse of the actor transform so that the resulting transform after SpawnActor is correct.

			if (auto* RootComponent = Actor.GetRootComponent())
			{
				RootComponent->UpdateComponentToWorld();
			}
			ActorTransform = Actor.GetTransform().Inverse() * ActorTransform;
		}
	}

	return ActorTransform;
}
Exemplo n.º 2
0
/**
* Creates an actor using the specified factory.  
*
* Does nothing if ActorClass is NULL.
*/
static AActor* PrivateAddActor( UObject* Asset, UActorFactory* Factory, bool SelectActor = true, EObjectFlags ObjectFlags = RF_Transactional, const FName Name = NAME_None )
{
	if (!Factory)
	{
		return nullptr;
	}

	AActor* Actor = NULL;
	AActor* NewActorTemplate = Factory->GetDefaultActor( Asset );
	if ( !NewActorTemplate )
	{
		return nullptr;
	}

	// For Brushes/Volumes, use the default brush as the template rather than the factory default actor
	if (NewActorTemplate->IsA(ABrush::StaticClass()) && GWorld->GetDefaultBrush() != nullptr)
	{
		NewActorTemplate = GWorld->GetDefaultBrush();
	}

	const FSnappedPositioningData PositioningData = FSnappedPositioningData(GCurrentLevelEditingViewportClient, GEditor->ClickLocation, GEditor->ClickPlane)
		.UseFactory(Factory)
		.UseStartTransform(NewActorTemplate->GetTransform())
		.UsePlacementExtent(NewActorTemplate->GetPlacementExtent());

	const FTransform ActorTransform = FActorPositioning::GetSnappedSurfaceAlignedTransform(PositioningData);

	// Do not fade snapping indicators over time if the viewport is not realtime
	bool bClearImmediately = !GCurrentLevelEditingViewportClient || !GCurrentLevelEditingViewportClient->IsRealtime();
	FSnappingUtils::ClearSnappingHelpers( bClearImmediately );

	ULevel* DesiredLevel = GWorld->GetCurrentLevel();

	// Don't spawn the actor if the current level is locked.
	if ( FLevelUtils::IsLevelLocked(DesiredLevel) )
	{
		FNotificationInfo Info( NSLOCTEXT("UnrealEd", "Error_OperationDisallowedOnLockedLevel", "The requested operation could not be completed because the level is locked.") );
		Info.ExpireDuration = 3.0f;
		FSlateNotificationManager::Get().AddNotification(Info);
		return nullptr;
	}

	{
		FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "CreateActor", "Create Actor") );
		if ( !(ObjectFlags & RF_Transactional) )
		{
			Transaction.Cancel();
		}

		// Create the actor.
		Actor = Factory->CreateActor( Asset, DesiredLevel, ActorTransform, ObjectFlags, Name );
		if(Actor)
		{
			if ( SelectActor )
			{
				GEditor->SelectNone( false, true );
				GEditor->SelectActor( Actor, true, true );
			}

			Actor->InvalidateLightingCache();
			Actor->PostEditChange();
		}
	}

	GEditor->RedrawLevelEditingViewports();

	if ( Actor )
	{
		Actor->MarkPackageDirty();
		ULevel::LevelDirtiedEvent.Broadcast();
	}

	return Actor;
}
/**
* Creates an actor using the specified factory.  
*
* Does nothing if ActorClass is NULL.
*/
static AActor* PrivateAddActor( UObject* Asset, UActorFactory* Factory, bool SelectActor = true, EObjectFlags ObjectFlags = RF_Transactional, const FName Name = NAME_None )
{
	if (!Factory)
	{
		return nullptr;
	}

	AActor* Actor = NULL;
	AActor* NewActorTemplate = Factory->GetDefaultActor( Asset );
	if ( !NewActorTemplate )
	{
		return nullptr;
	}

	UWorld* OldWorld = nullptr;

	// The play world needs to be selected if it exists
	if (GIsEditor && GEditor->PlayWorld && !GIsPlayInEditorWorld)
	{
		OldWorld = SetPlayInEditorWorld(GEditor->PlayWorld);
	}

	// For Brushes/Volumes, use the default brush as the template rather than the factory default actor
	if (NewActorTemplate->IsA(ABrush::StaticClass()) && GWorld->GetDefaultBrush() != nullptr)
	{
		NewActorTemplate = GWorld->GetDefaultBrush();
	}

	const FSnappedPositioningData PositioningData = FSnappedPositioningData(GCurrentLevelEditingViewportClient, GEditor->ClickLocation, GEditor->ClickPlane)
		.UseFactory(Factory)
		.UsePlacementExtent(NewActorTemplate->GetPlacementExtent());

	FTransform ActorTransform = FActorPositioning::GetSnappedSurfaceAlignedTransform(PositioningData);

	if (GetDefault<ULevelEditorViewportSettings>()->SnapToSurface.bEnabled)
	{
		// HACK: If we are aligning rotation to surfaces, we have to factor in the inverse of the actor transform so that the resulting transform after SpawnActor is correct.

		if (auto* RootComponent = NewActorTemplate->GetRootComponent())
		{
			RootComponent->UpdateComponentToWorld();
		}
		ActorTransform = NewActorTemplate->GetTransform().Inverse() * ActorTransform;
	}

	// Do not fade snapping indicators over time if the viewport is not realtime
	bool bClearImmediately = !GCurrentLevelEditingViewportClient || !GCurrentLevelEditingViewportClient->IsRealtime();
	FSnappingUtils::ClearSnappingHelpers( bClearImmediately );

	ULevel* DesiredLevel = GWorld->GetCurrentLevel();

	// Don't spawn the actor if the current level is locked.
	if (FLevelUtils::IsLevelLocked(DesiredLevel))
	{
		FNotificationInfo Info(NSLOCTEXT("UnrealEd", "Error_OperationDisallowedOnLockedLevel", "The requested operation could not be completed because the level is locked."));
		Info.ExpireDuration = 3.0f;
		FSlateNotificationManager::Get().AddNotification(Info);
	}
	else
	{
		FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "CreateActor", "Create Actor"), (ObjectFlags & RF_Transactional) != 0 );

		// Create the actor.
		Actor = Factory->CreateActor( Asset, DesiredLevel, ActorTransform, ObjectFlags, Name );
		if(Actor)
		{
			if ( SelectActor )
			{
				GEditor->SelectNone( false, true );
				GEditor->SelectActor( Actor, true, true );
			}

			Actor->InvalidateLightingCache();
			Actor->PostEditChange();
		}

		GEditor->RedrawLevelEditingViewports();
	}

	if ( Actor )
	{
		Actor->MarkPackageDirty();
		ULevel::LevelDirtiedEvent.Broadcast();
	}

	// Restore the old world if there was one
	if (OldWorld)
	{
		RestoreEditorWorld(OldWorld);
	}

	return Actor;
}