// Copyright IHY. #pragma once #include "CoreMinimal.h" #include "EditorSubsystem.h" #include "OptimizerTypes.h" #include "OptimizerSubsystem.generated.h" class UStaticMesh; class UStaticMeshComponent; /** * Editor subsystem driving the Mesh Optimizer pipeline. The Editor Utility Widget calls these: * 1. ScanLevel -> dry-run plan (sibling groups + per-placement corrected transforms) * 2. ApplyUnify -> reassign every sibling placement to its canonical mesh with the fixed transform * 3. BuildHISM -> collapse each group into one HierarchicalInstancedStaticMesh * Steps 2 and 3 each run inside a single undoable transaction. BuildHISM is independent of ApplyUnify * (it uses the canonical mesh + planned transforms directly). */ UCLASS() class OPTIMIZEREDITOR_API UOptimizerSubsystem : public UEditorSubsystem { GENERATED_BODY() public: /** Dry run: scan the level, group sibling meshes, plan corrected transforms. Mutates nothing. */ UFUNCTION(BlueprintCallable, Category = "Optimizer") FOptimizerScanResult ScanLevel(const FOptimizerScanSettings& Settings); /** Reassign all non-instanced sibling placements to their canonical mesh + corrected transform. Returns count changed. */ UFUNCTION(BlueprintCallable, Category = "Optimizer") int32 ApplyUnify(); /** Build one HISM actor per group from the planned transforms. Returns number of HISM actors created. */ UFUNCTION(BlueprintCallable, Category = "Optimizer") int32 BuildHISM(bool bDestroyOriginals = true); /** Discard the current plan. */ UFUNCTION(BlueprintCallable, Category = "Optimizer") void ClearPlan(); UFUNCTION(BlueprintCallable, Category = "Optimizer") bool HasPlan() const; private: /** One placement of a mesh in the level (a component, or one instance inside an ISM/HISM). */ struct FPlacement { TWeakObjectPtr Component; int32 InstanceIndex = INDEX_NONE; // >= 0 when this is an instance inside an ISM/HISM TWeakObjectPtr Mesh; FTransform World = FTransform::Identity; FTransform PlannedWorld = FTransform::Identity; bool bNeedsTransformFix = false; bool bShearRejected = false; bool bInstanced = false; // inside an ISM/HISM -> ApplyUnify can't swap it (HISM-only) }; /** A sibling group: distinct meshes that share geometry, collapsed onto one canonical. */ struct FGroup { TArray> Members; TWeakObjectPtr Canonical; TArray Placements; float MaxDeviation = 0.0f; bool bHasMirrored = false; bool bHasScaled = false; bool bMaterialMismatch = false; int32 ShearRejected = 0; }; TArray Groups; FOptimizerScanSettings LastSettings; FOptimizerScanResult BuildResultView() const; };