Files
sbox-public/game/addons/tools/Code/Scene/ObjectTool/ScaleEditorTool.cs
wheatleymf 16f0e78ebb Resize gameobjects with gizmo tool proportionally (#5213)
Previous behaviour was causing disproportional resizing on gameobjects depending on their bounds, so most objects would look squashed where one of the axis would be larger/smaller than others. Now it should be all proportional with equal scale on all 3 axis
2026-07-09 13:58:39 +02:00

83 lines
2.4 KiB
C#

namespace Editor;
/// <summary>
/// Scale selected GameObjects.<br/> <br/>
/// <b>Ctrl</b> - toggle snap to grid<br/>
/// <b>Shift</b> - scale all 3 axis
/// </summary>
[Title( "Scale" )]
[Icon( "zoom_out_map" )]
[Alias( "tools.scale-tool" )]
[Group( "1" )]
[Order( 2 )]
public class ScaleEditorTool : EditorTool
{
readonly Dictionary<GameObject, (Vector3 StartScale, Vector3 StartSize)> startState = [];
Vector3 scaleDelta;
IDisposable undoScope;
public override void OnUpdate()
{
var nonSceneGos = Selection.OfType<GameObject>().Where( go => go.GetType() != typeof( Sandbox.Scene ) );
if ( !nonSceneGos.Any() ) return;
var handlePosition = nonSceneGos.First().WorldPosition;
var handleRotation = nonSceneGos.First().WorldRotation;
if ( !Gizmo.Pressed.Any && Gizmo.HasMouseFocus )
{
startState.Clear();
scaleDelta = default;
undoScope?.Dispose();
undoScope = null;
}
using ( Gizmo.Scope( "Tool", new Transform( handlePosition ) ) )
{
Gizmo.Hitbox.DepthBias = 0.01f;
if ( Gizmo.Control.Scale( "scale", Vector3.Zero, out var delta, handleRotation ) )
{
scaleDelta += delta / 0.01f;
if ( startState.Count == 0 )
{
undoScope ??= SceneEditorSession.Active.UndoScope( "Transform Object(s)" ).WithGameObjectChanges( nonSceneGos, GameObjectUndoFlags.All ).Push();
foreach ( var go in nonSceneGos )
{
go.DispatchPreEdited( nameof( GameObject.LocalScale ) );
go.BreakProceduralBone();
startState[go] = (go.WorldScale, go.GetBounds().Size);
}
}
foreach ( var (go, (startScale, startSize)) in startState )
{
if ( !go.IsValid() ) continue;
var newSize = MathF.Max( startSize.x, MathF.Max( startSize.y, startSize.z ) );
if ( newSize < 0.001f ) newSize = 1.0f;
var snap = Gizmo.Snap( scaleDelta, scaleDelta ) * 2.0f;
go.WorldScale = new Vector3(
startScale.x * (1.0f + snap.x / newSize),
startScale.y * (1.0f + snap.y / newSize),
startScale.z * (1.0f + snap.z / newSize)
);
go.DispatchEdited( nameof( GameObject.LocalScale ) );
}
}
}
}
[Shortcut( "tools.scale-tool", "r", typeof( SceneViewWidget ) )]
public static void ActivateSubTool()
{
if ( !(EditorToolManager.CurrentModeName == nameof( ObjectEditorTool ) || EditorToolManager.CurrentModeName == "object") ) return;
EditorToolManager.SetSubTool( nameof( ScaleEditorTool ) );
}
}