mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-04-19 05:48:07 -04:00
* SceneEditorSession: make game vs editor scenes more distinct, Scene is whichever is currently active * Route prefab update, model reload etc events to both scenes if needed * SceneTree update checking a bit cleaner * Bring back GameEditorSessions instead, so undo, selection etc can all be linked 1:1 with scenes again * tweak and tidy
218 lines
5.2 KiB
C#
218 lines
5.2 KiB
C#
using System.Text.Json.Serialization;
|
|
|
|
namespace Editor;
|
|
|
|
public partial class SceneViewportWidget
|
|
{
|
|
private class SceneCookie
|
|
{
|
|
public Vector3 CameraPosition { get; set; }
|
|
public Rotation CameraRotation { get; set; }
|
|
public float? CameraOrthoHeight { get; set; }
|
|
}
|
|
|
|
public enum ViewMode
|
|
{
|
|
[Title( "3D" ), Icon( "view_in_ar" )]
|
|
Perspective,
|
|
[Title( "Top 2D" ), Icon( "roofing" )]
|
|
Top2d,
|
|
[Title( "Front 2D" ), Icon( "cottage" )]
|
|
Front2d,
|
|
[Title( "Side 2D" ), Icon( "gite" )]
|
|
Side2d
|
|
}
|
|
|
|
public class ViewportState
|
|
{
|
|
public Vector3 CameraPosition { get; set; }
|
|
public Rotation CameraRotation { get; set; }
|
|
|
|
/// <summary>
|
|
/// View mode of this viewport
|
|
/// </summary>
|
|
public ViewMode View
|
|
{
|
|
get => _mode;
|
|
set => SetViewmode( value );
|
|
}
|
|
private ViewMode _mode;
|
|
|
|
[JsonIgnore] public bool Is2D => View != ViewMode.Perspective;
|
|
|
|
/// <summary>
|
|
/// Render mode to use for this viewport
|
|
/// </summary>
|
|
public SceneCameraDebugMode RenderMode { get; set; } = SceneCameraDebugMode.Normal;
|
|
|
|
/// <summary>
|
|
/// Should the scene render in wireframe mode
|
|
/// </summary>
|
|
public bool WireframeMode { get; set; } = false;
|
|
|
|
/// <summary>
|
|
/// Should we render post processing effects?
|
|
/// </summary>
|
|
public bool EnablePostProcessing { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Enable the default directional light when editing prefabs.
|
|
/// </summary>
|
|
public bool EnablePrefabLighting { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Should the skybox be visible in 2D mode
|
|
/// </summary>
|
|
public bool ShowSkyIn2D
|
|
{
|
|
get => !Is2D || _showSky;
|
|
set => _showSky = value;
|
|
}
|
|
private bool _showSky;
|
|
|
|
/// <summary>
|
|
/// Show the grid
|
|
/// </summary>
|
|
public bool ShowGrid { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Should we fade the grid
|
|
/// </summary>
|
|
[Range( 0.0f, 1.0f )]
|
|
public float GridOpacity { get; set; } = 0.2f;
|
|
|
|
/// <summary>
|
|
/// The plane the grid is shown on
|
|
/// </summary>
|
|
public Gizmo.GridAxis GridAxis { get; set; } = Gizmo.GridAxis.XY;
|
|
|
|
/// <summary>
|
|
/// The orthographic size for the camera
|
|
/// </summary>
|
|
[Title( "Orthographic Height" )]
|
|
public float CameraOrthoHeight { get; set; } = 1000.0f;
|
|
|
|
private void SetViewmode( ViewMode viewmode )
|
|
{
|
|
_mode = viewmode;
|
|
|
|
switch ( viewmode )
|
|
{
|
|
case ViewMode.Top2d:
|
|
CameraRotation = Rotation.LookAt( Vector3.Down, Vector3.Left );
|
|
GridAxis = Gizmo.GridAxis.XY;
|
|
break;
|
|
|
|
case ViewMode.Front2d:
|
|
CameraRotation = Rotation.LookAt( Vector3.Forward, Vector3.Up );
|
|
GridAxis = Gizmo.GridAxis.YZ;
|
|
break;
|
|
|
|
case ViewMode.Side2d:
|
|
CameraRotation = Rotation.LookAt( Vector3.Left, Vector3.Up );
|
|
GridAxis = Gizmo.GridAxis.ZX;
|
|
break;
|
|
|
|
default:
|
|
GridAxis = Gizmo.GridAxis.XY;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
public ViewportState State { get; init; }
|
|
|
|
private void InitializeCamera()
|
|
{
|
|
Session.MakeActive();
|
|
|
|
using var scope = SceneEditorSession.Scope();
|
|
|
|
Scene scene = Session.Scene;
|
|
if ( !scene.IsValid() )
|
|
return;
|
|
|
|
// 1. load last camera position from cookies if possible
|
|
if ( scene.Source is not null &&
|
|
ProjectCookie.Get<SceneCookie>( $"{scene.Source.ResourcePath}.Viewport{Id}", null ) is SceneCookie cookie )
|
|
{
|
|
State.CameraPosition = cookie.CameraPosition;
|
|
if ( cookie.CameraOrthoHeight.HasValue )
|
|
State.CameraOrthoHeight = cookie.CameraOrthoHeight.Value;
|
|
if ( !State.Is2D )
|
|
State.CameraRotation = cookie.CameraRotation;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// 2. Place camera where a Camera component is
|
|
//
|
|
var cc = scene.Camera;
|
|
if ( cc.IsValid() )
|
|
{
|
|
State.CameraPosition = cc.WorldPosition;
|
|
if ( !State.Is2D )
|
|
State.CameraRotation = cc.WorldRotation;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// 3. BBox frame the scene
|
|
//
|
|
if ( !State.Is2D )
|
|
State.CameraRotation = Rotation.From( 45, 45, 0 );
|
|
|
|
var fieldOfView = 80.0f;
|
|
var bounds = scene.GetBounds();
|
|
var distance = MathX.SphereCameraDistance( bounds.Size.Length * 0.5f, fieldOfView ) * 1.0f;
|
|
State.CameraPosition = bounds.Center + distance * State.CameraRotation.Backward;
|
|
}
|
|
|
|
[Event( "scene.session.save" )]
|
|
public void SaveState()
|
|
{
|
|
if ( ProjectCookie is null ) return;
|
|
|
|
Scene scene = Session.Scene;
|
|
if ( !scene.IsValid() )
|
|
return;
|
|
|
|
if ( scene.Source is not null )
|
|
{
|
|
// TODO: this should still store something for non-resource scenes?
|
|
ProjectCookie.Set( $"{scene.Source.ResourcePath}.Viewport{Id}", new SceneCookie()
|
|
{
|
|
CameraPosition = State.CameraPosition,
|
|
CameraRotation = State.CameraRotation,
|
|
CameraOrthoHeight = State.CameraOrthoHeight,
|
|
} );
|
|
}
|
|
|
|
ProjectCookie.Set( $"SceneView.Viewport{Id}.Settings", State );
|
|
}
|
|
|
|
[Shortcut( "scene.cycle-viewmode", "CTRL+SPACE" )]
|
|
public void CycleViewmode()
|
|
{
|
|
ViewMode newMode = (ViewMode)(((int)State.View + 1) % ((int)ViewMode.Side2d + 1));
|
|
State.View = newMode == ViewMode.Perspective ? ViewMode.Top2d : newMode; // skip 3d
|
|
|
|
Vector3 center = Vector3.Zero;
|
|
int count = 0;
|
|
|
|
// TODO: support other (mesh tool?) selections here
|
|
if ( SceneEditorSession.Active is not null )
|
|
{
|
|
foreach ( var selected in SceneEditorSession.Active.Selection.OfType<GameObject>() )
|
|
{
|
|
center += selected.WorldPosition;
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if ( count > 0 )
|
|
{
|
|
State.CameraPosition = (center / count) - State.CameraRotation.Forward * 400;
|
|
}
|
|
}
|
|
}
|