Files
FLESH/Source/FLESHEditor/Private/FLESHViewportClient.cpp
2025-04-23 01:18:06 +08:00

389 lines
12 KiB
C++

#include "FLESHViewportClient.h"
#include "FLESHEditor.h"
#include "CanvasItem.h"
#include "CanvasTypes.h"
#include "Engine/SkeletalMesh.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/DirectionalLightComponent.h"
#include "Components/SkyLightComponent.h"
#include "Slate/SceneViewport.h"
#include "PreviewScene.h"
#include "EditorViewportClient.h"
#include "EngineGlobals.h"
#include "Engine/Engine.h"
#include "Engine.h"
#include "CanvasTypes.h"
#include "SceneView.h"
#include "InputCoreTypes.h"
#include "Components/SplineComponent.h"
#include "EditorModeManager.h"
#include "UnrealWidget.h"
FFLESHViewportClient::FFLESHViewportClient(FFLESHEditor* InEditor)
: FEditorViewportClient(nullptr)
, Viewport(nullptr)
, Editor(InEditor)
, bShowWireframe(false)
, bShowBones(false)
{
// Create a valid preview scene
PreviewScene = MakeShareable(new FPreviewScene(FPreviewScene::ConstructionValues()));
// Set the scene for FEditorViewportClient - use constructor instead of SetPreviewScene
FEditorViewportClient::PreviewScene = PreviewScene.Get();
// Set viewport type
SetViewportType(LVT_Perspective);
// Enable real-time rendering
SetRealtime(true);
// Set initial view position and rotation
SetInitialViewTransform(
LVT_Perspective,
FVector(0.0f, 100.0f, 0.0f), // Camera position
FRotator(0.0f, -90.0f, 0.0f), // Camera rotation
200.0f // Camera distance
);
// Enable camera controls
EngineShowFlags.SetPostProcessing(true);
EngineShowFlags.SetLighting(true);
EngineShowFlags.SetIndirectLightingCache(true);
EngineShowFlags.SetTemporalAA(true);
// Set default render mode
SetViewMode(VMI_Lit);
// Set camera control options similar to asset editor
SetRealtime(true);
bSetListenerPosition = false;
// Enable standard editor camera controls
if (Widget)
{
Widget->SetSnapEnabled(true);
}
// Load and display objects from NodeTree
LoadNodesFromNodeTree();
}
FFLESHViewportClient::~FFLESHViewportClient()
{
// Clean up resources
}
void FFLESHViewportClient::Draw(const FSceneView* View, FPrimitiveDrawInterface* PDI)
{
FEditorViewportClient::Draw(View, PDI);
// Draw navigation widget (coordinate axes)
if (PDI)
{
// Draw coordinate system axes
const float AxisLength = 50.0f;
const float AxisThickness = 1.0f;
// Draw X axis (red)
PDI->DrawLine(FVector::ZeroVector, FVector(AxisLength, 0.0f, 0.0f), FLinearColor::Red, SDPG_Foreground, AxisThickness);
// Draw Y axis (green)
PDI->DrawLine(FVector::ZeroVector, FVector(0.0f, AxisLength, 0.0f), FLinearColor::Green, SDPG_Foreground, AxisThickness);
// Draw Z axis (blue)
PDI->DrawLine(FVector::ZeroVector, FVector(0.0f, 0.0f, AxisLength), FLinearColor::Blue, SDPG_Foreground, AxisThickness);
}
// Draw custom UI elements
if (Viewport)
{
FCanvas* Canvas = Viewport->GetDebugCanvas();
if (Canvas)
{
// Draw mode information
FString ModeText;
if (bShowWireframe)
{
ModeText += TEXT("Wireframe Mode | ");
}
if (bShowBones)
{
ModeText += TEXT("Show Bones | ");
}
if (!ModeText.IsEmpty())
{
// Remove last separator
ModeText.RemoveAt(ModeText.Len() - 3, 3);
// Draw text
FCanvasTextItem TextItem(FVector2D(10, 10), FText::FromString(ModeText), GEngine->GetSmallFont(), FLinearColor::White);
Canvas->DrawItem(TextItem);
}
}
}
}
bool FFLESHViewportClient::InputKey(const FInputKeyEventArgs& EventArgs)
{
// Handle keyboard and mouse input
bool bHandled = false;
// Add custom shortcuts
if (EventArgs.Event == IE_Pressed)
{
if (EventArgs.Key == EKeys::W)
{
// W key toggles wireframe mode
ToggleWireframe();
bHandled = true;
}
else if (EventArgs.Key == EKeys::B)
{
// B key toggles bone display
ToggleBones();
bHandled = true;
}
else if (EventArgs.Key == EKeys::R)
{
// R key resets camera
ResetCamera();
bHandled = true;
}
else if (EventArgs.Key == EKeys::F)
{
// F key focuses on selected object
FocusOnSelectedNode();
bHandled = true;
}
}
// If not handled, pass to base class
if (!bHandled)
{
bHandled = FEditorViewportClient::InputKey(EventArgs);
}
return bHandled;
}
bool FFLESHViewportClient::InputKey(FViewport* InViewport, int32 ControllerId, FKey Key, EInputEvent Event, float AmountDepressed, bool bGamepad)
{
// Create new parameter structure and call the new version of InputKey
FInputKeyEventArgs Args(InViewport, ControllerId, Key, Event, AmountDepressed, false);
// Forward to the new API version
return InputKey(Args);
}
// This version of InputAxis is deprecated, but kept for compatibility
bool FFLESHViewportClient::InputAxis(FViewport* InViewport, int32 ControllerId, FKey Key, float Delta, float DeltaTime, int32 NumSamples, bool bGamepad)
{
// Create InputKeyEventArgs for the new API
FInputKeyEventArgs Args(InViewport, ControllerId, Key, IE_Axis);
Args.AmountDepressed = Delta;
return InputKey(Args);
}
void FFLESHViewportClient::ResetCamera()
{
// Reset camera position and rotation
SetViewLocation(FVector(0.0f, 100.0f, 0.0f));
SetViewRotation(FRotator(0.0f, -90.0f, 0.0f));
// Invalidate view
Invalidate();
}
void FFLESHViewportClient::ToggleWireframe()
{
// Toggle wireframe mode
bShowWireframe = !bShowWireframe;
if (bShowWireframe)
{
SetViewMode(VMI_Wireframe);
}
else
{
SetViewMode(VMI_Lit);
}
// Invalidate view
Invalidate();
}
void FFLESHViewportClient::ToggleBones()
{
// Toggle bone display
bShowBones = !bShowBones;
// Update engine flags
EngineShowFlags.SetBones(bShowBones);
// Invalidate view
Invalidate();
}
void FFLESHViewportClient::LoadNodesFromNodeTree()
{
if (!PreviewScene.IsValid() || !Editor)
{
return;
}
// Clear current preview scene components by creating a new one
PreviewScene = MakeShareable(new FPreviewScene(FPreviewScene::ConstructionValues()));
FEditorViewportClient::PreviewScene = PreviewScene.Get();
// Add a default light
UDirectionalLightComponent* DirectionalLight = NewObject<UDirectionalLightComponent>();
DirectionalLight->SetMobility(EComponentMobility::Movable);
DirectionalLight->SetIntensity(1.0f);
PreviewScene->AddComponent(DirectionalLight, FTransform(FRotator(-45.0f, 45.0f, 0.0f)));
// Add a skylight for ambient lighting
USkyLightComponent* SkyLight = NewObject<USkyLightComponent>();
SkyLight->SetMobility(EComponentMobility::Movable);
SkyLight->SourceType = ESkyLightSourceType::SLS_CapturedScene;
PreviewScene->AddComponent(SkyLight, FTransform::Identity);
// Add a second directional light from another angle
UDirectionalLightComponent* BackLight = NewObject<UDirectionalLightComponent>();
BackLight->SetMobility(EComponentMobility::Movable);
BackLight->SetIntensity(0.6f);
BackLight->SetLightColor(FLinearColor(0.8f, 0.8f, 1.0f)); // Slightly blue backlight
PreviewScene->AddComponent(BackLight, FTransform(FRotator(45.0f, -135.0f, 0.0f)));
// Get all nodes from NodeTree
const TArray<TSharedPtr<FVisceraNodeItem>>& NodeRoots = Editor->GetNodeTreeRoots();
// Recursively load all nodes
for (const TSharedPtr<FVisceraNodeItem>& RootNode : NodeRoots)
{
if (RootNode.IsValid())
{
LoadNodeRecursive(RootNode, nullptr);
}
}
// Update viewport
Invalidate();
}
void FFLESHViewportClient::LoadNodeRecursive(TSharedPtr<FVisceraNodeItem> Node, USceneComponent* ParentComponent)
{
if (!Node.IsValid() || !PreviewScene.IsValid())
{
return;
}
USceneComponent* NodeComponent = nullptr;
// Simplified node loading logic, use static mesh for all node types
UStaticMeshComponent* MeshComponent = NewObject<UStaticMeshComponent>();
// Choose different mesh and color based on node type
FString MeshPath;
FLinearColor Color;
if (Node->NodeType.Equals(TEXT("SoftBody")))
{
MeshPath = TEXT("/Engine/BasicShapes/Sphere.Sphere");
Color = FLinearColor(1.0f, 0.5f, 0.5f, 0.7f); // Translucent red
}
else if (Node->NodeType.Equals(TEXT("LineChain")))
{
MeshPath = TEXT("/Engine/BasicShapes/Cylinder.Cylinder");
Color = FLinearColor(0.5f, 0.5f, 1.0f, 0.7f); // Translucent blue
}
else if (Node->NodeType.Equals(TEXT("Plane")))
{
MeshPath = TEXT("/Engine/BasicShapes/Plane.Plane");
Color = FLinearColor(0.5f, 0.5f, 1.0f, 0.5f); // Translucent blue
}
else if (Node->NodeType.Equals(TEXT("Matrix")))
{
MeshPath = TEXT("/Engine/BasicShapes/Cube.Cube");
Color = FLinearColor(0.5f, 1.0f, 0.5f, 0.7f); // Translucent green
MeshComponent->SetWorldScale3D(FVector(0.25f, 0.25f, 0.25f)); // Scale down cube
}
else // Default to sphere
{
MeshPath = TEXT("/Engine/BasicShapes/Sphere.Sphere");
Color = FLinearColor(1.0f, 1.0f, 1.0f, 0.7f); // Translucent white
}
// Load static mesh
UStaticMesh* StaticMesh = LoadObject<UStaticMesh>(nullptr, *MeshPath);
if (StaticMesh)
{
MeshComponent->SetStaticMesh(StaticMesh);
// Set translucent material
UMaterial* Material = LoadObject<UMaterial>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial.BasicShapeMaterial"));
if (Material)
{
UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(Material, MeshComponent);
if (DynamicMaterial)
{
DynamicMaterial->SetVectorParameterValue(TEXT("Color"), Color);
MeshComponent->SetMaterial(0, DynamicMaterial);
}
}
}
// Add to preview scene
PreviewScene->AddComponent(MeshComponent, FTransform::Identity);
NodeComponent = MeshComponent;
// If parent component exists, set parent-child relationship
if (NodeComponent && ParentComponent)
{
NodeComponent->AttachToComponent(ParentComponent, FAttachmentTransformRules::KeepRelativeTransform);
}
// Recursively load child nodes
for (const TSharedPtr<FVisceraNodeItem>& ChildNode : Node->Children)
{
if (ChildNode.IsValid() && NodeComponent)
{
LoadNodeRecursive(ChildNode, NodeComponent);
}
}
}
void FFLESHViewportClient::UpdateVisibleNodes()
{
// Reload all nodes
LoadNodesFromNodeTree();
}
void FFLESHViewportClient::FocusOnSelectedNode()
{
if (!Editor)
{
return;
}
// Get currently selected node
TSharedPtr<FVisceraNodeItem> SelectedNode = Editor->GetSelectedNodeItem();
if (!SelectedNode.IsValid())
{
return;
}
// Position camera at the selected node's location
// Note: Here we use a default position since we don't have actual position information for the node
// In a real implementation, we should find the component for this node and get its position
FVector FocusLocation = FVector::ZeroVector;
// Set camera position and rotation
SetViewLocation(FocusLocation + FVector(0.0f, 100.0f, 0.0f));
SetViewRotation(FRotator(0.0f, -90.0f, 0.0f));
// Update view
Invalidate();
}