|
| 1 | +// Copyright soft-ue-expert. All Rights Reserved. |
| 2 | + |
| 3 | +#include "Tools/Write/SetViewportCameraTool.h" |
| 4 | +#include "SoftUEBridgeEditorModule.h" |
| 5 | +#include "Editor.h" |
| 6 | +#include "LevelEditorViewport.h" |
| 7 | +#include "SLevelViewport.h" |
| 8 | +#include "LevelEditor.h" |
| 9 | +#include "Modules/ModuleManager.h" |
| 10 | + |
| 11 | +FString USetViewportCameraTool::GetToolDescription() const |
| 12 | +{ |
| 13 | + return TEXT("Set the editor viewport camera position, rotation, and view mode. " |
| 14 | + "Supports perspective and orthographic views (Top, Front, Right, etc.). " |
| 15 | + "Use 'preset' for quick top-down/front/side views, or set location/rotation manually."); |
| 16 | +} |
| 17 | + |
| 18 | +TMap<FString, FBridgeSchemaProperty> USetViewportCameraTool::GetInputSchema() const |
| 19 | +{ |
| 20 | + TMap<FString, FBridgeSchemaProperty> Schema; |
| 21 | + |
| 22 | + FBridgeSchemaProperty Location; |
| 23 | + Location.Type = TEXT("array"); |
| 24 | + Location.Description = TEXT("Camera position [x, y, z]. Ignored for orthographic presets."); |
| 25 | + Location.bRequired = false; |
| 26 | + Schema.Add(TEXT("location"), Location); |
| 27 | + |
| 28 | + FBridgeSchemaProperty Rotation; |
| 29 | + Rotation.Type = TEXT("array"); |
| 30 | + Rotation.Description = TEXT("Camera rotation [pitch, yaw, roll] in degrees. Ignored for orthographic presets."); |
| 31 | + Rotation.bRequired = false; |
| 32 | + Schema.Add(TEXT("rotation"), Rotation); |
| 33 | + |
| 34 | + FBridgeSchemaProperty Preset; |
| 35 | + Preset.Type = TEXT("string"); |
| 36 | + Preset.Description = TEXT("Camera preset: 'top', 'bottom', 'front', 'back', 'left', 'right', or 'perspective'. " |
| 37 | + "Orthographic presets switch to ortho view. 'perspective' switches back."); |
| 38 | + Preset.bRequired = false; |
| 39 | + Schema.Add(TEXT("preset"), Preset); |
| 40 | + |
| 41 | + FBridgeSchemaProperty OrthoWidth; |
| 42 | + OrthoWidth.Type = TEXT("number"); |
| 43 | + OrthoWidth.Description = TEXT("Orthographic view width (zoom level). Larger = more zoomed out. Default: 5000."); |
| 44 | + OrthoWidth.bRequired = false; |
| 45 | + Schema.Add(TEXT("ortho_width"), OrthoWidth); |
| 46 | + |
| 47 | + return Schema; |
| 48 | +} |
| 49 | + |
| 50 | +TArray<FString> USetViewportCameraTool::GetRequiredParams() const |
| 51 | +{ |
| 52 | + return {}; |
| 53 | +} |
| 54 | + |
| 55 | +FBridgeToolResult USetViewportCameraTool::Execute( |
| 56 | + const TSharedPtr<FJsonObject>& Arguments, |
| 57 | + const FBridgeToolContext& Context) |
| 58 | +{ |
| 59 | + // Get the first level viewport |
| 60 | + FLevelEditorModule& LevelEditor = FModuleManager::GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor")); |
| 61 | + TSharedPtr<ILevelEditor> LevelEditorInstance = LevelEditor.GetFirstLevelEditor(); |
| 62 | + if (!LevelEditorInstance.IsValid()) |
| 63 | + { |
| 64 | + return FBridgeToolResult::Error(TEXT("No level editor found")); |
| 65 | + } |
| 66 | + |
| 67 | + TSharedPtr<SLevelViewport> ActiveViewport = LevelEditorInstance->GetActiveViewportInterface(); |
| 68 | + if (!ActiveViewport.IsValid()) |
| 69 | + { |
| 70 | + return FBridgeToolResult::Error(TEXT("No active viewport found")); |
| 71 | + } |
| 72 | + |
| 73 | + FLevelEditorViewportClient& ViewportClient = ActiveViewport->GetLevelViewportClient(); |
| 74 | + |
| 75 | + const FString Preset = GetStringArgOrDefault(Arguments, TEXT("preset")); |
| 76 | + const float OrthoWidth = GetFloatArgOrDefault(Arguments, TEXT("ortho_width"), 5000.0f); |
| 77 | + |
| 78 | + // Handle presets |
| 79 | + if (!Preset.IsEmpty()) |
| 80 | + { |
| 81 | + if (Preset.Equals(TEXT("top"), ESearchCase::IgnoreCase)) |
| 82 | + { |
| 83 | + ViewportClient.SetViewportType(LVT_OrthoXY); |
| 84 | + ViewportClient.SetOrthoZoom(OrthoWidth); |
| 85 | + ViewportClient.SetViewRotation(FRotator(-90, 0, 0)); |
| 86 | + } |
| 87 | + else if (Preset.Equals(TEXT("bottom"), ESearchCase::IgnoreCase)) |
| 88 | + { |
| 89 | + ViewportClient.SetViewportType(LVT_OrthoNegativeXY); |
| 90 | + ViewportClient.SetOrthoZoom(OrthoWidth); |
| 91 | + ViewportClient.SetViewRotation(FRotator(90, 0, 0)); |
| 92 | + } |
| 93 | + else if (Preset.Equals(TEXT("front"), ESearchCase::IgnoreCase)) |
| 94 | + { |
| 95 | + ViewportClient.SetViewportType(LVT_OrthoXZ); |
| 96 | + ViewportClient.SetOrthoZoom(OrthoWidth); |
| 97 | + ViewportClient.SetViewRotation(FRotator(0, -90, 0)); |
| 98 | + } |
| 99 | + else if (Preset.Equals(TEXT("back"), ESearchCase::IgnoreCase)) |
| 100 | + { |
| 101 | + ViewportClient.SetViewportType(LVT_OrthoNegativeXZ); |
| 102 | + ViewportClient.SetOrthoZoom(OrthoWidth); |
| 103 | + ViewportClient.SetViewRotation(FRotator(0, 90, 0)); |
| 104 | + } |
| 105 | + else if (Preset.Equals(TEXT("left"), ESearchCase::IgnoreCase)) |
| 106 | + { |
| 107 | + ViewportClient.SetViewportType(LVT_OrthoYZ); |
| 108 | + ViewportClient.SetOrthoZoom(OrthoWidth); |
| 109 | + ViewportClient.SetViewRotation(FRotator(0, 0, 0)); |
| 110 | + } |
| 111 | + else if (Preset.Equals(TEXT("right"), ESearchCase::IgnoreCase)) |
| 112 | + { |
| 113 | + ViewportClient.SetViewportType(LVT_OrthoNegativeYZ); |
| 114 | + ViewportClient.SetOrthoZoom(OrthoWidth); |
| 115 | + ViewportClient.SetViewRotation(FRotator(0, 180, 0)); |
| 116 | + } |
| 117 | + else if (Preset.Equals(TEXT("perspective"), ESearchCase::IgnoreCase)) |
| 118 | + { |
| 119 | + ViewportClient.SetViewportType(LVT_Perspective); |
| 120 | + } |
| 121 | + else |
| 122 | + { |
| 123 | + return FBridgeToolResult::Error(FString::Printf( |
| 124 | + TEXT("Unknown preset '%s'. Use: top, bottom, front, back, left, right, perspective"), *Preset)); |
| 125 | + } |
| 126 | + } |
| 127 | + |
| 128 | + // Apply custom location if provided |
| 129 | + const TArray<TSharedPtr<FJsonValue>>* LocArr; |
| 130 | + if (Arguments->TryGetArrayField(TEXT("location"), LocArr) && LocArr->Num() >= 3) |
| 131 | + { |
| 132 | + FVector Location; |
| 133 | + Location.X = (*LocArr)[0]->AsNumber(); |
| 134 | + Location.Y = (*LocArr)[1]->AsNumber(); |
| 135 | + Location.Z = (*LocArr)[2]->AsNumber(); |
| 136 | + ViewportClient.SetViewLocation(Location); |
| 137 | + } |
| 138 | + |
| 139 | + // Apply custom rotation if provided |
| 140 | + const TArray<TSharedPtr<FJsonValue>>* RotArr; |
| 141 | + if (Arguments->TryGetArrayField(TEXT("rotation"), RotArr) && RotArr->Num() >= 3) |
| 142 | + { |
| 143 | + FRotator Rotation; |
| 144 | + Rotation.Pitch = (*RotArr)[0]->AsNumber(); |
| 145 | + Rotation.Yaw = (*RotArr)[1]->AsNumber(); |
| 146 | + Rotation.Roll = (*RotArr)[2]->AsNumber(); |
| 147 | + ViewportClient.SetViewRotation(Rotation); |
| 148 | + } |
| 149 | + |
| 150 | + // Force viewport redraw |
| 151 | + ViewportClient.Invalidate(); |
| 152 | + |
| 153 | + // Build result |
| 154 | + FVector FinalLoc = ViewportClient.GetViewLocation(); |
| 155 | + FRotator FinalRot = ViewportClient.GetViewRotation(); |
| 156 | + |
| 157 | + TSharedPtr<FJsonObject> Result = MakeShareable(new FJsonObject); |
| 158 | + Result->SetBoolField(TEXT("success"), true); |
| 159 | + |
| 160 | + TArray<TSharedPtr<FJsonValue>> LocJson; |
| 161 | + LocJson.Add(MakeShared<FJsonValueNumber>(FinalLoc.X)); |
| 162 | + LocJson.Add(MakeShared<FJsonValueNumber>(FinalLoc.Y)); |
| 163 | + LocJson.Add(MakeShared<FJsonValueNumber>(FinalLoc.Z)); |
| 164 | + Result->SetArrayField(TEXT("location"), LocJson); |
| 165 | + |
| 166 | + TArray<TSharedPtr<FJsonValue>> RotJson; |
| 167 | + RotJson.Add(MakeShared<FJsonValueNumber>(FinalRot.Pitch)); |
| 168 | + RotJson.Add(MakeShared<FJsonValueNumber>(FinalRot.Yaw)); |
| 169 | + RotJson.Add(MakeShared<FJsonValueNumber>(FinalRot.Roll)); |
| 170 | + Result->SetArrayField(TEXT("rotation"), RotJson); |
| 171 | + |
| 172 | + const bool bOrtho = ViewportClient.IsOrtho(); |
| 173 | + Result->SetStringField(TEXT("view_type"), bOrtho ? TEXT("orthographic") : TEXT("perspective")); |
| 174 | + if (!Preset.IsEmpty()) |
| 175 | + { |
| 176 | + Result->SetStringField(TEXT("preset"), Preset); |
| 177 | + } |
| 178 | + |
| 179 | + UE_LOG(LogSoftUEBridgeEditor, Log, TEXT("set-viewport-camera: %s at [%.0f, %.0f, %.0f]"), |
| 180 | + bOrtho ? TEXT("ortho") : TEXT("perspective"), FinalLoc.X, FinalLoc.Y, FinalLoc.Z); |
| 181 | + return FBridgeToolResult::Json(Result); |
| 182 | +} |
0 commit comments