Files
UnrealEngineUWP/Engine/Source/Editor/PhAT/Private/PhATPreviewViewportClient.cpp

1010 lines
33 KiB
C++
Raw Normal View History

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "PhATModule.h"
#include "PhATEdSkeletalMeshComponent.h"
#include "PhAT.h"
#include "MouseDeltaTracker.h"
#include "ScopedTransaction.h"
#include "PhATHitProxies.h"
#include "PhATActions.h"
#include "PhATSharedData.h"
#include "PhATPreviewViewportClient.h"
#include "SPhATPreviewViewport.h"
#include "GameFramework/WorldSettings.h"
#include "CanvasTypes.h"
#include "PhysicsEngine/BodySetup.h"
#include "Engine/Font.h"
#include "PhysicsEngine/PhysicsConstraintTemplate.h"
#include "PhysicsEngine/PhysicsSettings.h"
#include "PhysicsEngine/PhysicsHandleComponent.h"
#include "DrawDebugHelpers.h"
FPhATEdPreviewViewportClient::FPhATEdPreviewViewportClient(TWeakPtr<FPhAT> InPhAT, TSharedPtr<FPhATSharedData> Data, const TSharedRef<SPhATPreviewViewport>& InPhATPreviewViewport)
: FEditorViewportClient(nullptr, &Data->PreviewScene, StaticCastSharedRef<SEditorViewport>(InPhATPreviewViewport))
, PhATPtr(InPhAT)
, SharedData(Data)
, MinPrimSize(0.5f)
, PhAT_TranslateSpeed(0.25f)
, PhAT_RotateSpeed(1.0 * (PI / 180.0))
, PhAT_LightRotSpeed(0.22f)
, SimGrabCheckDistance(5000.0f)
, SimHoldDistanceChangeDelta(20.0f)
, SimMinHoldDistance(10.0f)
, SimGrabMoveSpeed(1.0f)
{
check(PhATPtr.IsValid());
ModeTools->SetWidgetMode(FWidget::EWidgetMode::WM_Translate);
ModeTools->SetCoordSystem(COORD_Local);
bAllowedToMoveCamera = true;
// Setup defaults for the common draw helper.
DrawHelper.bDrawPivot = false;
DrawHelper.bDrawWorldBox = false;
DrawHelper.bDrawKillZ = false;
DrawHelper.GridColorAxis = FColor(80,80,80);
DrawHelper.GridColorMajor = FColor(72,72,72);
DrawHelper.GridColorMinor = FColor(64,64,64);
DrawHelper.PerspectiveGridSize = 32767;
PhATFont = GEngine->GetSmallFont();
check(PhATFont);
EngineShowFlags.DisableAdvancedFeatures();
EngineShowFlags.CompositeEditorPrimitives = true;
// Get actors asset collision bounding box, and move actor so its not intersection the floor plane at Z = 0.
FBox CollBox = SharedData->PhysicsAsset->CalcAABB(SharedData->EditorSkelComp, SharedData->EditorSkelComp->ComponentToWorld);
FVector SkelCompLocation = FVector(0, 0, -CollBox.Min.Z + SharedData->EditorSimOptions->FloorGap);
SharedData->EditorSkelComp->SetAbsolute(true, true, true);
SharedData->EditorSkelComp->SetRelativeLocation(SkelCompLocation);
SharedData->ResetTM = SharedData->EditorSkelComp->GetComponentToWorld();
// Get new bounding box and set view based on that.
CollBox = SharedData->PhysicsAsset->CalcAABB(SharedData->EditorSkelComp, SharedData->EditorSkelComp->ComponentToWorld);
FVector CollBoxExtent = CollBox.GetExtent();
// Take into account internal mesh translation/rotation/scaling etc.
FTransform LocalToWorld = SharedData->EditorSkelComp->ComponentToWorld;
FSphere WorldSphere = SharedData->EditorSkelMesh->Bounds.GetSphere().TransformBy(LocalToWorld);
CollBoxExtent = CollBox.GetExtent();
if (CollBoxExtent.X > CollBoxExtent.Y)
{
SetViewLocation( FVector(WorldSphere.Center.X, WorldSphere.Center.Y - 1.5*WorldSphere.W, WorldSphere.Center.Z) );
SetViewRotation( EditorViewportDefs::DefaultPerspectiveViewRotation );
}
else
{
SetViewLocation( FVector(WorldSphere.Center.X - 1.5*WorldSphere.W, WorldSphere.Center.Y, WorldSphere.Center.Z) );
SetViewRotation( FRotator::ZeroRotator );
}
SetViewLocationForOrbiting(FVector::ZeroVector);
SetViewModes(VMI_Lit, VMI_Lit);
bUsingOrbitCamera = true;
if (!FPhAT::IsPIERunning())
{
SetRealtime(true);
}
}
FPhATEdPreviewViewportClient::~FPhATEdPreviewViewportClient()
{
}
void FPhATEdPreviewViewportClient::DrawCanvas( FViewport& InViewport, FSceneView& View, FCanvas& Canvas )
{
if (!PhATPtr.IsValid())
{
return;
}
// Turn on/off the ground box
SharedData->EditorFloorComp->SetVisibility(SharedData->bDrawGround);
float W, H;
PhATFont->GetCharSize(TEXT('L'), W, H);
const float XOffset = 200.0f;
FCanvasTextItem TextItem( FVector2D::ZeroVector, FText::GetEmpty(), PhATFont, FLinearColor::White );
// Write body/constraint count at top.
FString StatusString = FText::Format(
NSLOCTEXT("UnrealEd", "BodiesConstraints_F", "{0} BODIES {1} CONSIDERED_FOR_BOUNDS {2} Ratio {3} CONSTRAINTS"),
FText::AsNumber(SharedData->PhysicsAsset->BodySetup.Num()),
FText::AsNumber(SharedData->PhysicsAsset->BoundsBodies.Num()),
FText::AsNumber(static_cast<float>(SharedData->PhysicsAsset->BoundsBodies.Num())/static_cast<float>(SharedData->PhysicsAsset->BodySetup.Num())),
FText::AsNumber(SharedData->PhysicsAsset->ConstraintSetup.Num()) ).ToString();
TextItem.Text = FText::FromString( StatusString );
Canvas.DrawItem( TextItem, XOffset, 3 );
TextItem.Text = FText::GetEmpty();
if (SharedData->bRunningSimulation)
{
#if PLATFORM_MAC
TextItem.Text = NSLOCTEXT("UnrealEd", "Sim_Mac", "SIM: Command+RightMouse to interact with bodies");
#else
TextItem.Text = NSLOCTEXT("UnrealEd", "Sim", "SIM: Ctrl+RightMouse to interact with bodies");
#endif
}
else if (SharedData->bSelectionLock)
{
TextItem.Text = NSLOCTEXT("UnrealEd", "Lock", "LOCK");
}else if(SharedData->EditingMode == FPhATSharedData::PEM_ConstraintEdit)
{
if(GetWidgetMode() == FWidget::WM_Translate)
{
TextItem.Text = NSLOCTEXT("UnrealEd", "SingleMove", "hold ALT to move a single reference frame");
}else if(GetWidgetMode() == FWidget::WM_Rotate)
{
TextItem.Text = NSLOCTEXT("UnrealEd", "DoubleRotate", "hold ALT to rotate both reference frames");
}
}
Canvas.DrawItem( TextItem, XOffset, Viewport->GetSizeXY().Y - (3 + H) );
// Draw current physics weight
if (SharedData->bRunningSimulation)
{
FString PhysWeightString = FString::Printf(TEXT("Phys Blend: %3.0f pct"), SharedData->EditorSimOptions->PhysicsBlend * 100.f);
int32 PWLW, PWLH;
StringSize(PhATFont, PWLW, PWLH, *PhysWeightString);
TextItem.Text = FText::FromString(PhysWeightString);
Canvas.DrawItem( TextItem, Viewport->GetSizeXY().X - (3 + PWLW + 2*W), Viewport->GetSizeXY().Y - (3 + H) );
}
int32 HalfX = (Viewport->GetSizeXY().X-XOffset)/2;
int32 HalfY = Viewport->GetSizeXY().Y/2;
if ((SharedData->bShowHierarchy && SharedData->EditorSimOptions->bShowNamesInHierarchy))
{
// Iterate over each graphics bone.
for(int32 i = 0; i <SharedData->EditorSkelComp->GetNumSpaceBases(); ++i)
{
FVector BonePos = SharedData->EditorSkelComp->ComponentToWorld.TransformPosition(SharedData->EditorSkelComp->GetSpaceBases()[i].GetLocation());
FPlane proj = View.Project(BonePos);
if (proj.W > 0.f) // This avoids drawing bone names that are behind us.
{
int32 XPos = HalfX + (HalfX * proj.X);
int32 YPos = HalfY + (HalfY * (proj.Y * -1));
FName BoneName = SharedData->EditorSkelMesh->RefSkeleton.GetBoneName(i);
FColor BoneNameColor = FColor::White;
//iterate through selected bones and see if any match
for(int32 j=0; j< SharedData->SelectedBodies.Num(); ++j)
{
int32 SelectedBodyIndex = SharedData->SelectedBodies[j].Index;
FName SelectedBoneName = SharedData->PhysicsAsset->BodySetup[SelectedBodyIndex]->BoneName;
if(SelectedBoneName == BoneName)
{
BoneNameColor = FColor::Green;
break;
}
}
if (Canvas.IsHitTesting())
{
Canvas.SetHitProxy(new HPhATEdBoneNameProxy(i));
}
TextItem.Text = FText::FromString(BoneName.ToString());
TextItem.SetColor(BoneNameColor);
Canvas.DrawItem( TextItem, XPos, YPos );
if (Canvas.IsHitTesting())
{
Canvas.SetHitProxy(NULL);
}
}
}
}
// If showing center-of-mass, and physics is started up..
if (SharedData->bShowCOM)
{
// iterate over each bone
for (int32 i = 0; i <SharedData->EditorSkelComp->Bodies.Num(); ++i)
{
FBodyInstance* BodyInst = SharedData->EditorSkelComp->Bodies[i];
check(BodyInst);
FVector BodyCOMPos = BodyInst->GetCOMPosition();
float BodyMass = BodyInst->GetBodyMass();
FPlane Projection = View.Project(BodyCOMPos);
if (Projection.W > 0.f) // This avoids drawing bone names that are behind us.
{
int32 XPos = HalfX + (HalfX * Projection.X);
int32 YPos = HalfY + (HalfY * (Projection.Y * -1));
FString COMString = FString::Printf(TEXT("%3.3f"), BodyMass);
TextItem.Text = FText::FromString(COMString);
TextItem.SetColor(SharedData->COMRenderColor);
Canvas.DrawItem( TextItem, XPos, YPos );
}
}
}
}
void FPhATEdPreviewViewportClient::Draw(const FSceneView* View, FPrimitiveDrawInterface* PDI)
{
FEditorViewportClient::Draw(View,PDI);
FPhATSharedData::EPhATRenderMode MeshViewMode = SharedData->GetCurrentMeshViewMode();
if (MeshViewMode != FPhATSharedData::PRM_None)
{
SharedData->EditorSkelComp->SetVisibility(true);
if (MeshViewMode == FPhATSharedData::PRM_Wireframe)
{
SharedData->EditorSkelComp->SetForceWireframe(true);
}
else
{
SharedData->EditorSkelComp->SetForceWireframe(false);
}
}
else
{
SharedData->EditorSkelComp->SetVisibility(false);
}
// Draw phat skeletal component.
if (PDI->IsHitTesting())
{
SharedData->EditorSkelComp->RenderHitTest(View, PDI);
}
else
{
SharedData->EditorSkelComp->Render(View, PDI);
}
}
bool FPhATEdPreviewViewportClient::InputKey(FViewport* Viewport, int32 ControllerId, FKey Key, EInputEvent Event, float AmountDepressed, bool Gamepad)
{
int32 HitX = Viewport->GetMouseX();
int32 HitY = Viewport->GetMouseY();
bool bCtrlDown = Viewport->KeyState(EKeys::LeftControl) || Viewport->KeyState(EKeys::RightControl);
bool bShiftDown = Viewport->KeyState(EKeys::LeftShift) || Viewport->KeyState(EKeys::RightShift);
bool bHandled = false;
if (SharedData->bRunningSimulation)
{
if (Key == EKeys::RightMouseButton || Key == EKeys::LeftMouseButton)
{
if (Event == IE_Pressed)
{
if (bShiftDown)
{
bHandled = true;
SimMousePress(Viewport, false, Key);
bAllowedToMoveCamera = false;
}
else if (bCtrlDown)
{
bHandled = true;
SimMousePress(Viewport, true, Key);
bAllowedToMoveCamera = false;
}
}
else if (Event == IE_Released)
{
bHandled = true;
SimMouseRelease();
bAllowedToMoveCamera = true;
}
UpdateAndApplyCursorVisibility();
}
else if (Key == EKeys::MouseScrollUp)
{
bHandled = true;
SimMouseWheelUp();
}
else if (Key == EKeys::MouseScrollDown)
{
bHandled = true;
SimMouseWheelDown();
}
else if(IsFlightCameraActive())
{
// If the flight camera is active (user is looking or moving around the scene)
// consume the event so hotkeys don't fire.
bHandled = true;
}
}
if( !bHandled )
{
bHandled = FEditorViewportClient::InputKey( Viewport, ControllerId, Key, Event, AmountDepressed, Gamepad );
}
if( bHandled )
{
Invalidate();
}
return bHandled;
}
bool FPhATEdPreviewViewportClient::InputAxis(FViewport* Viewport, int32 ControllerId, FKey Key, float Delta, float DeltaTime, int32 NumSamples, bool bGamepad)
{
bool bHandled = false;
// If we are 'manipulating' don't move the camera but do something else with mouse input.
if (SharedData->bManipulating)
{
bool bCtrlDown = Viewport->KeyState(EKeys::LeftControl) || Viewport->KeyState(EKeys::RightControl);
if (SharedData->bRunningSimulation)
{
if (Key == EKeys::MouseX)
{
SimMouseMove(Delta, 0.0f);
}
else if (Key == EKeys::MouseY)
{
SimMouseMove(0.0f, Delta);
}
bHandled = true;
}
}
if( !bHandled )
{
bHandled = FEditorViewportClient::InputAxis(Viewport,ControllerId,Key,Delta,DeltaTime,NumSamples,bGamepad);
}
Viewport->Invalidate();
return bHandled;
}
void FPhATEdPreviewViewportClient::ProcessClick(class FSceneView& View, class HHitProxy* HitProxy, FKey Key, EInputEvent Event, uint32 HitX, uint32 HitY)
{
if( Key == EKeys::LeftMouseButton )
{
if (HitProxy && HitProxy->IsA(HPhATEdBoneProxy::StaticGetType()))
{
HPhATEdBoneProxy* BoneProxy = (HPhATEdBoneProxy*)HitProxy;
SharedData->HitBone(BoneProxy->BodyIndex, BoneProxy->PrimType, BoneProxy->PrimIndex, IsCtrlPressed() || IsShiftPressed());
}
else if (HitProxy && HitProxy->IsA(HPhATEdConstraintProxy::StaticGetType()))
{
HPhATEdConstraintProxy* ConstraintProxy = (HPhATEdConstraintProxy*)HitProxy;
SharedData->HitConstraint(ConstraintProxy->ConstraintIndex, IsCtrlPressed() || IsShiftPressed());
}
else
{
HitNothing();
}
}
else if( Key == EKeys::RightMouseButton )
{
if (HitProxy)
{
if (HitProxy->IsA(HPhATEdBoneProxy::StaticGetType()) && SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit)
{
HPhATEdBoneProxy* BoneProxy = (HPhATEdBoneProxy*)HitProxy;
bool bAlreadySelected = false;
//find out if body is already selected
for(int32 i=0; i<SharedData->SelectedBodies.Num(); ++i)
{
if(SharedData->SelectedBodies[i].Index == BoneProxy->BodyIndex && SharedData->SelectedBodies[i].PrimitiveType == BoneProxy->PrimType && SharedData->SelectedBodies[i].PrimitiveIndex == BoneProxy->PrimIndex)
{
bAlreadySelected = true;
break;
}
}
// Select body under cursor if not already selected (if ctrl is held down we only add, not remove)
if (!bAlreadySelected)
{
FPhATSharedData::FSelection Selection(BoneProxy->BodyIndex, BoneProxy->PrimType, BoneProxy->PrimIndex);
SharedData->SetSelectedBody(&Selection, IsCtrlPressed());
}
// Pop up menu, if we have a body selected.
if (SharedData->GetSelectedBody())
{
OpenBodyMenu();
}
}
else if (HitProxy->IsA(HPhATEdConstraintProxy::StaticGetType()) && SharedData->EditingMode == FPhATSharedData::PEM_ConstraintEdit)
{
HPhATEdConstraintProxy* ConstraintProxy = (HPhATEdConstraintProxy*)HitProxy;
bool bAlreadySelected = false;
//find out if constraint is already selected
for(int32 i=0; i<SharedData->SelectedConstraints.Num(); ++i)
{
if(SharedData->SelectedConstraints[i].Index == ConstraintProxy->ConstraintIndex)
{
bAlreadySelected = true;
break;
}
}
// Select constraint under cursor if not already selected (if ctrl is held down we only add, not remove)
if (!bAlreadySelected)
{
SharedData->SetSelectedConstraint(ConstraintProxy->ConstraintIndex, IsCtrlPressed());
}
// Pop up menu, if we have a constraint selected.
if (SharedData->GetSelectedConstraint())
{
OpenConstraintMenu();
}
}
}
}
}
bool FPhATEdPreviewViewportClient::InputWidgetDelta( FViewport* Viewport, EAxisList::Type CurrentAxis, FVector& Drag, FRotator& Rot, FVector& Scale )
{
bool bHandled = false;
TArray<FPhATSharedData::FSelection> & SelectedObjects = SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit ? SharedData->SelectedBodies : SharedData->SelectedConstraints;
for(int32 i=0; i<SelectedObjects.Num(); ++i)
{
FPhATSharedData::FSelection & SelectedObject = SelectedObjects[i];
if( SharedData->bManipulating )
{
float BoneScale = 1.f;
if (SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit) /// BODY EDITING ///
{
int32 BoneIndex = SharedData->EditorSkelComp->GetBoneIndex(SharedData->PhysicsAsset->BodySetup[SelectedObject.Index]->BoneName);
FTransform BoneTM = SharedData->EditorSkelComp->GetBoneTransform(BoneIndex);
BoneScale = BoneTM.GetScale3D().GetAbsMax();
BoneTM.RemoveScaling();
SelectedObject.WidgetTM = SharedData->EditorSkelComp->GetPrimitiveTransform(BoneTM, SelectedObject.Index, SelectedObject.PrimitiveType, SelectedObject.PrimitiveIndex, BoneScale);
}
else /// CONSTRAINT EDITING ///
{
SelectedObject.WidgetTM = SharedData->GetConstraintMatrix(SelectedObject.Index, EConstraintFrame::Frame2, 1.f);
}
if ( GetWidgetMode() == FWidget::WM_Translate )
{
FVector Dir = SelectedObject.WidgetTM.InverseTransformVector( Drag.GetSafeNormal() );
FVector DragVec = Dir * Drag.Size() / BoneScale;
SelectedObject.ManipulateTM.AddToTranslation( DragVec );
}
else if ( GetWidgetMode() == FWidget::WM_Rotate )
{
FVector Axis;
float Angle;
Rot.Quaternion().ToAxisAndAngle(Axis, Angle);
Axis = SelectedObject.WidgetTM.InverseTransformVectorNoScale( Axis );
const FQuat Start = SelectedObject.ManipulateTM.GetRotation();
const FQuat Delta = FQuat( Axis, Angle );
const FQuat Result = Delta * Start;
SelectedObject.ManipulateTM = FTransform( Result );
}
else if ( GetWidgetMode() == FWidget::WM_Scale && SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit) // Scaling only valid for bodies.
{
ModifyPrimitiveSize(SelectedObject.Index, SelectedObject.PrimitiveType, SelectedObject.PrimitiveIndex, Scale );
}
if (SharedData->EditingMode == FPhATSharedData::PEM_ConstraintEdit)
{
UPhysicsConstraintTemplate* ConstraintSetup = SharedData->PhysicsAsset->ConstraintSetup[SelectedObject.Index];
ConstraintSetup->DefaultInstance.SetRefFrame(EConstraintFrame::Frame2, SelectedObject.ManipulateTM * StartManParentConTM);
//Rotation by default only rotates one frame, but translation by default moves both
bool bMultiFrame = (IsAltPressed() && GetWidgetMode() == FWidget::WM_Rotate) || (!IsAltPressed() && GetWidgetMode() == FWidget::WM_Translate);
if (bMultiFrame)
{
SharedData->SetSelectedConstraintRelTM(StartManRelConTM);
}
else
{
ConstraintSetup->DefaultInstance.SetRefFrame(EConstraintFrame::Frame1, FTransform(StartManChildConTM));
}
}
bHandled = true;
}
}
return bHandled;
}
void FPhATEdPreviewViewportClient::TrackingStarted( const struct FInputEventState& InInputState, bool bIsDraggingWidget, bool bNudge )
{
// If releasing the mouse button, check we are done manipulating
if ( bIsDraggingWidget )
{
FSceneViewFamilyContext ViewFamily( FSceneViewFamily::ConstructionValues( Viewport, GetScene(), EngineShowFlags ));
FSceneView* View = CalcSceneView(&ViewFamily);
const int32 HitX = InInputState.GetViewport()->GetMouseX();
const int32 HitY = InInputState.GetViewport()->GetMouseY();
StartManipulating(Widget->GetCurrentAxis(), FViewportClick(View, this, InInputState.GetKey(), InInputState.GetInputEvent(), HitX, HitY), View->ViewMatrices.ViewMatrix);
// If we are manipulating, don't move the camera as we drag now.
if (SharedData->bManipulating)
{
bAllowedToMoveCamera = false;
}
}
}
void FPhATEdPreviewViewportClient::TrackingStopped()
{
if (SharedData->bManipulating)
{
EndManipulating();
bAllowedToMoveCamera = true;
}
}
FWidget::EWidgetMode FPhATEdPreviewViewportClient::GetWidgetMode() const
{
FWidget::EWidgetMode ReturnWidgetMode = FWidget::WM_None;
FWidget::EWidgetMode WidgetMode = FEditorViewportClient::GetWidgetMode();
if( SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit && SharedData->GetSelectedBody())
{
ReturnWidgetMode = WidgetMode;
}
else if(
SharedData->EditingMode == FPhATSharedData::PEM_ConstraintEdit
&& SharedData->GetSelectedConstraint()
&& WidgetMode != FWidget::WM_Scale )
{
ReturnWidgetMode = WidgetMode;
}
return ReturnWidgetMode;
}
FVector FPhATEdPreviewViewportClient::GetWidgetLocation() const
{
if (SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit) /// BODY EDITING ///
{
// Don't draw widget if nothing selected.
if (!SharedData->GetSelectedBody())
{
return FVector::ZeroVector;
}
int32 BoneIndex = SharedData->EditorSkelComp->GetBoneIndex(SharedData->PhysicsAsset->BodySetup[SharedData->GetSelectedBody()->Index]->BoneName);
FTransform BoneTM = SharedData->EditorSkelComp->GetBoneTransform(BoneIndex);
const float Scale = BoneTM.GetScale3D().GetAbsMax();
BoneTM.RemoveScaling();
return SharedData->EditorSkelComp->GetPrimitiveTransform(BoneTM, SharedData->GetSelectedBody()->Index, SharedData->GetSelectedBody()->PrimitiveType, SharedData->GetSelectedBody()->PrimitiveIndex, Scale).GetTranslation();
}
else /// CONSTRAINT EDITING ///
{
if (!SharedData->GetSelectedConstraint())
{
return FVector::ZeroVector;
}
return SharedData->GetConstraintMatrix(SharedData->GetSelectedConstraint()->Index, EConstraintFrame::Frame2, 1.f).GetTranslation();
}
}
FMatrix FPhATEdPreviewViewportClient::GetWidgetCoordSystem() const
{
if( GetWidgetCoordSystemSpace() == COORD_Local )
{
if (SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit) /// BODY EDITING ///
{
// Don't draw widget if nothing selected.
if (!SharedData->GetSelectedBody())
{
return FMatrix::Identity;
}
int32 BoneIndex = SharedData->EditorSkelComp->GetBoneIndex(SharedData->PhysicsAsset->BodySetup[SharedData->GetSelectedBody()->Index]->BoneName);
FTransform BoneTM = SharedData->EditorSkelComp->GetBoneTransform(BoneIndex);
BoneTM.RemoveScaling();
return SharedData->EditorSkelComp->GetPrimitiveTransform(BoneTM, SharedData->GetSelectedBody()->Index, SharedData->GetSelectedBody()->PrimitiveType, SharedData->GetSelectedBody()->PrimitiveIndex, 1.f).ToMatrixNoScale().RemoveTranslation();
}
else /// CONSTRAINT EDITING ///
{
if (!SharedData->GetSelectedConstraint())
{
return FMatrix::Identity;
}
return SharedData->GetConstraintMatrix(SharedData->GetSelectedConstraint()->Index, EConstraintFrame::Frame2, 1.f).ToMatrixNoScale().RemoveTranslation();
}
}
else
{
return FMatrix::Identity;
}
}
ECoordSystem FPhATEdPreviewViewportClient::GetWidgetCoordSystemSpace() const
{
return GetWidgetMode() == FWidget::WM_Scale ? COORD_Local : ModeTools->GetCoordSystem();;
}
void FPhATEdPreviewViewportClient::Tick(float DeltaSeconds)
{
FEditorViewportClient::Tick(DeltaSeconds);
---- Merging with SlateDev branch ---- Introduces the concept of "Active Ticking" to allow Slate to go to sleep when there is no need to update the UI. While asleep, Slate will skip the Tick & Paint pass for that frame entirely. - There are TWO ways to "wake" Slate and cause a Tick/Paint pass: 1. Provide some sort of input (mouse movement, clicks, and key presses). Slate will always tick when the user is active. - Therefore, if the logic in a given widget's Tick is only relevant in response to user action, there is no need to register an active tick. 2. Register an Active Tick. Currently this is an all-or-nothing situation, so if a single active tick needs to execute, all of Slate will be ticked. - The purpose of an Active Tick is to allow a widget to "drive" Slate and guarantee a Tick/Paint pass in the absence of any user action. - Examples include animation, async operations that update periodically, progress updates, loading bars, etc. - An empty active tick is registered for viewports when they are real-time, so game project widgets are unaffected by this change and should continue to work as before. - An Active Tick is registered by creating an FWidgetActiveTickDelegate and passing it to SWidget::RegisterActiveTick() - There are THREE ways to unregister an active tick: 1. Return EActiveTickReturnType::StopTicking from the active tick function 2. Pass the FActiveTickHandle returned by RegisterActiveTick() to SWidget::UnregisterActiveTick() 3. Destroy the widget responsible for the active tick - Sleeping is currently disabled, can be enabled with Slate.AllowSlateToSleep cvar - There is currently a little buffer time during which Slate continues to tick following any input. Long-term, this is planned to be removed. - The duration of the buffer can be adjusted using Slate.SleepBufferPostInput cvar (defaults to 1.0f) - The FCurveSequence API has been updated to work with the active tick system - Playing a curve sequence now requires that you pass the widget being animated by the sequence - The active tick will automatically be registered on behalf of the widget and unregister when the sequence is complete - GetLerpLooping() has been removed. Instead, pass true as the second param to Play() to indicate that the animation will loop. This causes the active tick to be registered indefinitely until paused or jumped to the start/end. [CL 2391669 by Dan Hertzka in Main branch]
2014-12-17 16:07:57 -05:00
UWorld* World = SharedData->PreviewScene.GetWorld();
if (SharedData->bRunningSimulation)
{
// check if PIE disabled the realtime viewport and quit sim if so
if (!bIsRealtime)
{
SharedData->ToggleSimulation();
Invalidate();
}
AWorldSettings* Setting = World->GetWorldSettings();
Setting->WorldGravityZ = SharedData->bNoGravitySimulation ? 0.0f : UPhysicsSettings::Get()->DefaultGravityZ*SharedData->EditorSimOptions->GravScale;
Setting->bWorldGravitySet = true;
// We back up the transforms array now
SharedData->EditorSkelComp->AnimationSpaceBases = SharedData->EditorSkelComp->GetSpaceBases();
SharedData->EditorSkelComp->SetPhysicsBlendWeight(SharedData->EditorSimOptions->PhysicsBlend);
}
World->Tick(LEVELTICK_All, DeltaSeconds);
if(SharedData->Recorder.InRecording())
{
// make sure you don't allow switch SharedData->EditorSkelComp
SharedData->Recorder.UpdateRecord(SharedData->EditorSkelComp, DeltaSeconds);
}
}
FSceneInterface* FPhATEdPreviewViewportClient::GetScene() const
{
return SharedData->PreviewScene.GetScene();
}
FLinearColor FPhATEdPreviewViewportClient::GetBackgroundColor() const
{
return FColor(64,64,64);
}
void FPhATEdPreviewViewportClient::OpenBodyMenu()
{
TSharedPtr<SWidget> MenuWidget = PhATPtr.Pin()->BuildMenuWidgetBody();
TSharedPtr< SPhATPreviewViewport > ParentWidget = PhATPtr.Pin()->GetPreviewViewportWidget();
if ( MenuWidget.IsValid() && ParentWidget.IsValid() )
{
const FVector2D MouseCursorLocation = FSlateApplication::Get().GetCursorPos();
FSlateApplication::Get().PushMenu(
ParentWidget.ToSharedRef(),
MenuWidget.ToSharedRef(),
MouseCursorLocation,
FPopupTransitionEffect(FPopupTransitionEffect::ContextMenu)
);
}
}
void FPhATEdPreviewViewportClient::OpenConstraintMenu()
{
TSharedPtr<SWidget> MenuWidget = PhATPtr.Pin()->BuildMenuWidgetConstraint();
TSharedPtr< SPhATPreviewViewport > ParentWidget = PhATPtr.Pin()->GetPreviewViewportWidget();
if ( MenuWidget.IsValid() && ParentWidget.IsValid() )
{
const FVector2D MouseCursorLocation = FSlateApplication::Get().GetCursorPos();
FSlateApplication::Get().PushMenu(
ParentWidget.ToSharedRef(),
MenuWidget.ToSharedRef(),
MouseCursorLocation,
FPopupTransitionEffect(FPopupTransitionEffect::ContextMenu)
);
}
}
void FPhATEdPreviewViewportClient::StartManipulating(EAxisList::Type Axis, const FViewportClick& Click, const FMatrix& WorldToCamera)
{
check(!SharedData->bManipulating);
if (SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit && SharedData->SelectedBodies.Num())
{
GEditor->BeginTransaction( NSLOCTEXT("UnrealEd", "MoveElement", "Move Element") );
for(int32 i=0; i<SharedData->SelectedBodies.Num(); ++i)
{
SharedData->PhysicsAsset->BodySetup[SharedData->SelectedBodies[i].Index]->Modify();
SharedData->SelectedBodies[i].ManipulateTM = FTransform::Identity;
}
SharedData->bManipulating = true;
}
else if( SharedData->GetSelectedConstraint())
{
GEditor->BeginTransaction( NSLOCTEXT("UnrealEd", "MoveConstraint", "Move Constraint") );
for(int32 i=0; i<SharedData->SelectedConstraints.Num(); ++i)
{
SharedData->PhysicsAsset->ConstraintSetup[SharedData->SelectedConstraints[i].Index]->Modify();
SharedData->SelectedConstraints[i].ManipulateTM = FTransform::Identity;
}
const FTransform WParentFrame = SharedData->GetConstraintWorldTM(SharedData->GetSelectedConstraint(), EConstraintFrame::Frame2);
const FTransform WChildFrame = SharedData->GetConstraintWorldTM(SharedData->GetSelectedConstraint(), EConstraintFrame::Frame1);
StartManRelConTM = WChildFrame * WParentFrame.Inverse();
UPhysicsConstraintTemplate* Setup = SharedData->PhysicsAsset->ConstraintSetup[SharedData->GetSelectedConstraint()->Index];
StartManParentConTM = Setup->DefaultInstance.GetRefFrame(EConstraintFrame::Frame2);
StartManChildConTM = Setup->DefaultInstance.GetRefFrame(EConstraintFrame::Frame1);
SharedData->bManipulating = true;
}
}
void FPhATEdPreviewViewportClient::EndManipulating()
{
if (SharedData->bManipulating)
{
SharedData->bManipulating = false;
if (SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit)
{
for(int32 i=0; i<SharedData->SelectedBodies.Num(); ++i)
{
FPhATSharedData::FSelection & SelectedObject = SharedData->SelectedBodies[i];
UBodySetup* BodySetup = SharedData->PhysicsAsset->BodySetup[SelectedObject.Index];
FKAggregateGeom* AggGeom = &BodySetup->AggGeom;
if (SelectedObject.PrimitiveType == KPT_Sphere)
{
AggGeom->SphereElems[SelectedObject.PrimitiveIndex].Center = (SelectedObject.ManipulateTM * AggGeom->SphereElems[SelectedObject.PrimitiveIndex].GetTransform() ).GetLocation();
}
else if (SelectedObject.PrimitiveType == KPT_Box)
{
AggGeom->BoxElems[SelectedObject.PrimitiveIndex].SetTransform(SelectedObject.ManipulateTM * AggGeom->BoxElems[SelectedObject.PrimitiveIndex].GetTransform() );
}
else if (SelectedObject.PrimitiveType == KPT_Sphyl)
{
AggGeom->SphylElems[SelectedObject.PrimitiveIndex].SetTransform(SelectedObject.ManipulateTM * AggGeom->SphylElems[SelectedObject.PrimitiveIndex].GetTransform() );
}
else if (SelectedObject.PrimitiveType == KPT_Convex)
{
FKConvexElem& Convex = AggGeom->ConvexElems[SelectedObject.PrimitiveIndex];
Convex.SetTransform(SelectedObject.ManipulateTM * Convex.GetTransform() );
}
}
}
GEditor->EndTransaction();
Viewport->Invalidate();
}
}
void FPhATEdPreviewViewportClient::SimMousePress(FViewport* Viewport, bool bConstrainRotation, FKey Key)
{
bool bCtrlDown = Viewport->KeyState(EKeys::LeftControl) || Viewport->KeyState(EKeys::RightControl);
bool bShiftDown = Viewport->KeyState(EKeys::LeftShift) || Viewport->KeyState(EKeys::RightShift);
FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues( Viewport, GetScene(), EngineShowFlags ));
FSceneView* View = CalcSceneView(&ViewFamily);
const FViewportClick Click(View, this, EKeys::Invalid, IE_Released, Viewport->GetMouseX(), Viewport->GetMouseY());
#if DEBUG_CLICK_VIEWPORT
SharedData->LastClickOrigin = Click.GetOrigin();
SharedData->LastClickDirection = Click.GetDirection();
#endif
SharedData->LastClickPos = Click.GetClickPos();
FHitResult Result(1.f);
bool bHit = SharedData->EditorSkelComp->LineTraceComponent(Result, Click.GetOrigin() - Click.GetDirection() * SimGrabCheckDistance, Click.GetOrigin() + Click.GetDirection() * SimGrabCheckDistance, FCollisionQueryParams(true));
if (bHit)
{
check(Result.Item != INDEX_NONE);
FName BoneName = SharedData->PhysicsAsset->BodySetup[Result.Item]->BoneName;
//UE_LOG(LogPhysics, Warning, TEXT("Hit Bone Name (%s)"), *BoneName.ToString());
// Right mouse is for dragging things around
if (Key == EKeys::RightMouseButton)
{
SharedData->bManipulating = true;
DragX = 0.0f;
DragY = 0.0f;
SimGrabPush = 0.0f;
// Update mouse force properties from sim options.
SharedData->MouseHandle->LinearDamping = SharedData->EditorSimOptions->HandleLinearDamping;
SharedData->MouseHandle->LinearStiffness = SharedData->EditorSimOptions->HandleLinearStiffness;
SharedData->MouseHandle->AngularDamping = SharedData->EditorSimOptions->HandleAngularDamping;
SharedData->MouseHandle->AngularStiffness = SharedData->EditorSimOptions->HandleAngularStiffness;
SharedData->MouseHandle->InterpolationSpeed = SharedData->EditorSimOptions->InterpolationSpeed;
// Create handle to object.
SharedData->MouseHandle->GrabComponent(SharedData->EditorSkelComp, BoneName, Result.Location, bConstrainRotation);
FMatrix InvViewMatrix = View->ViewMatrices.ViewMatrix.InverseFast();
SimGrabMinPush = SimMinHoldDistance - (Result.Time * SimGrabCheckDistance);
SimGrabLocation = Result.Location;
SimGrabX = InvViewMatrix.GetUnitAxis( EAxis::X );
SimGrabY = InvViewMatrix.GetUnitAxis( EAxis::Y );
SimGrabZ = InvViewMatrix.GetUnitAxis( EAxis::Z );
}
// Left mouse is for poking things
else if (Key == EKeys::LeftMouseButton)
{
SharedData->EditorSkelComp->AddImpulseAtLocation(Click.GetDirection() * SharedData->EditorSimOptions->PokeStrength, Result.Location, BoneName);
}
}
}
void FPhATEdPreviewViewportClient::SimMouseMove(float DeltaX, float DeltaY)
{
DragX = Viewport->GetMouseX() - SharedData->LastClickPos.X;
DragY = Viewport->GetMouseY() - SharedData->LastClickPos.Y;
if (!SharedData->MouseHandle->GrabbedComponent)
{
return;
}
//We need to convert Pixel Delta into Screen position (deal with different viewport sizes)
FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues( Viewport, GetScene(), EngineShowFlags ));
FSceneView* View = CalcSceneView(&ViewFamily);
FVector4 ScreenOldPos = View->PixelToScreen(SharedData->LastClickPos.X, SharedData->LastClickPos.Y, 1.f);
FVector4 ScreenNewPos = View->PixelToScreen(DragX + SharedData->LastClickPos.X, DragY + SharedData->LastClickPos.Y, 1.f);
FVector4 ScreenDelta = ScreenNewPos - ScreenOldPos;
FVector4 ProjectedDelta = View->ScreenToWorld(ScreenDelta);
FVector4 WorldDelta;
//Now we project new ScreenPos to xy-plane of SimGrabLocation
FVector LocalOffset = View->ViewMatrices.ViewMatrix.TransformPosition(SimGrabLocation + SimGrabZ * SimGrabPush);
float ZDistance = GetViewportType() == ELevelViewportType::LVT_Perspective ? fabs(LocalOffset.Z) : 1.f; //in the ortho case we don't need to do any fixup because there is no perspective
WorldDelta = ProjectedDelta * ZDistance;
//Now we convert back into WorldPos
FVector WorldPos = SimGrabLocation + WorldDelta + SimGrabZ * SimGrabPush;
FVector NewLocation = WorldPos;
float QuickRadius = 5 - SimGrabPush / SimHoldDistanceChangeDelta;
QuickRadius = QuickRadius < 2 ? 2 : QuickRadius;
DrawDebugPoint(GetWorld(), NewLocation, QuickRadius, FColorList::Red, false, 0.3);
SharedData->MouseHandle->SetTargetLocation(NewLocation);
SharedData->MouseHandle->GrabbedComponent->WakeRigidBody(SharedData->MouseHandle->GrabbedBoneName);
}
void FPhATEdPreviewViewportClient::SimMouseRelease()
{
SharedData->bManipulating = false;
if (!SharedData->MouseHandle->GrabbedComponent)
{
return;
}
SharedData->MouseHandle->GrabbedComponent->WakeRigidBody(SharedData->MouseHandle->GrabbedBoneName);
SharedData->MouseHandle->ReleaseComponent();
}
void FPhATEdPreviewViewportClient::SimMouseWheelUp()
{
if (!SharedData->MouseHandle->GrabbedComponent)
{
return;
}
SimGrabPush += SimHoldDistanceChangeDelta;
SimMouseMove(0.0f, 0.0f);
}
void FPhATEdPreviewViewportClient::SimMouseWheelDown()
{
if (!SharedData->MouseHandle->GrabbedComponent)
{
return;
}
SimGrabPush -= SimHoldDistanceChangeDelta;
SimGrabPush = FMath::Max(SimGrabMinPush, SimGrabPush);
SimMouseMove(0.0f, 0.0f);
}
void FPhATEdPreviewViewportClient::ModifyPrimitiveSize(int32 BodyIndex, EKCollisionPrimitiveType PrimType, int32 PrimIndex, FVector DeltaSize)
{
check(SharedData->GetSelectedBody());
FKAggregateGeom* AggGeom = &SharedData->PhysicsAsset->BodySetup[BodyIndex]->AggGeom;
if (PrimType == KPT_Sphere)
{
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
check(AggGeom->SphereElems.IsValidIndex(PrimIndex));
AggGeom->SphereElems[PrimIndex].ScaleElem(DeltaSize, MinPrimSize);
}
else if (PrimType == KPT_Box)
{
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
check(AggGeom->BoxElems.IsValidIndex(PrimIndex));
AggGeom->BoxElems[PrimIndex].ScaleElem(DeltaSize, MinPrimSize);
}
else if (PrimType == KPT_Sphyl)
{
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
check(AggGeom->SphylElems.IsValidIndex(PrimIndex));
AggGeom->SphylElems[PrimIndex].ScaleElem(DeltaSize, MinPrimSize);
}
else if (PrimType == KPT_Convex)
{
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
check(AggGeom->ConvexElems.IsValidIndex(PrimIndex));
FVector ModifiedSize = DeltaSize;
if (GEditor->UsePercentageBasedScaling())
{
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
ModifiedSize = DeltaSize * ((GEditor->GetScaleGridSize() / 100.0f) / GEditor->GetGridSize());
}
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
AggGeom->ConvexElems[PrimIndex].ScaleElem(ModifiedSize, MinPrimSize);
}
}
void FPhATEdPreviewViewportClient::HitNothing()
{
if (!SharedData->bSelectionLock)
{
if (SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit)
{
if(IsCtrlPressed() == false) //we only want to deselect if Ctrl is not used
{
SharedData->SetSelectedBody(0);
}
}
else
{
if(IsCtrlPressed() == false) //we only want to deselect if Ctrl is not used
{
SharedData->SetSelectedConstraint(INDEX_NONE);
}
}
}
if (!SharedData->bSelectionLock)
{
Viewport->Invalidate();
PhATPtr.Pin()->RefreshHierachyTree();
}
}