mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-15 01:39:39 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
219 lines
6.3 KiB
C#
219 lines
6.3 KiB
C#
using Sandbox.Internal;
|
|
using System;
|
|
using System.Collections.Immutable;
|
|
|
|
namespace Sandbox;
|
|
|
|
public static partial class SandboxToolExtensions
|
|
{
|
|
/// <summary>
|
|
/// Render this camera to the target widget. Once you do this the target widget becomes "externally painted", so you
|
|
/// won't be able to paint on it anymore with Qt's Paint stuff.
|
|
/// </summary>
|
|
public static bool RenderToPixmap( this SceneCamera camera, Pixmap targetPixmap, bool async = false )
|
|
{
|
|
if ( camera.World == null )
|
|
return false;
|
|
|
|
if ( targetPixmap == null || targetPixmap.Width <= 1 || targetPixmap.Height <= 1 )
|
|
return false;
|
|
|
|
camera.OnPreRender( targetPixmap.Size );
|
|
|
|
using Bitmap bitmap = new Bitmap( targetPixmap.Width, targetPixmap.Height );
|
|
camera.RenderToBitmap( bitmap );
|
|
targetPixmap.UpdateFromPixels( bitmap );
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Render this camera to the target widget. Once you do this the target widget becomes "externally painted", so you
|
|
/// won't be able to paint on it anymore with Qt's Paint stuff.
|
|
/// </summary>
|
|
public static bool RenderToPixmap( this CameraComponent camera, Pixmap targetPixmap, bool async = false )
|
|
{
|
|
if ( targetPixmap == null || targetPixmap.Width <= 1 || targetPixmap.Height <= 1 )
|
|
return false;
|
|
|
|
if ( !camera.IsValid() )
|
|
return false;
|
|
|
|
using ( camera.Scene.Push() )
|
|
{
|
|
camera.Scene.PreCameraRender();
|
|
camera.InitializeRendering();
|
|
camera.SceneCamera.OnPreRender( targetPixmap.Size );
|
|
|
|
using Bitmap bitmap = new Bitmap( targetPixmap.Width, targetPixmap.Height );
|
|
camera.RenderToBitmap( bitmap );
|
|
targetPixmap.UpdateFromPixels( bitmap );
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Render this camera to the target widget. Once you do this the target widget becomes "externally painted", so you
|
|
/// won't be able to paint on it anymore with Qt's Paint stuff.
|
|
/// </summary>
|
|
public static bool RenderToPixmap( this Scene scene, Pixmap targetPixmap, bool async = false )
|
|
{
|
|
return RenderToPixmap( scene.Camera, targetPixmap, async );
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Render this camera to the target widget. Once you do this the target widget becomes "externally painted", so you
|
|
/// won't be able to paint on it anymore with Qt's Paint stuff.
|
|
/// </summary>
|
|
public static unsafe bool RenderToVideo( this SceneCamera camera, VideoWriter videoWriter, TimeSpan? time = default )
|
|
{
|
|
if ( camera.World == null )
|
|
return false;
|
|
|
|
if ( videoWriter == null || videoWriter.Width <= 1 || videoWriter.Height <= 1 )
|
|
return false;
|
|
|
|
camera.OnPreRender( new Vector2( videoWriter.Width, videoWriter.Height ) );
|
|
|
|
using Bitmap bitmap = new Bitmap( videoWriter.Width, videoWriter.Height );
|
|
camera.RenderToBitmap( bitmap );
|
|
|
|
videoWriter.AddFrame( bitmap, time );
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Render this camera to the target widget. Once you do this the target widget becomes "externally painted", so you
|
|
/// won't be able to paint on it anymore with Qt's Paint stuff.
|
|
/// </summary>
|
|
public static async Task<bool> RenderToVideoAsync( this SceneCamera camera, VideoWriter videoWriter, TimeSpan? time = default )
|
|
{
|
|
if ( camera.World == null )
|
|
return false;
|
|
|
|
if ( videoWriter == null || videoWriter.Width <= 1 || videoWriter.Height <= 1 )
|
|
return false;
|
|
|
|
camera.OnPreRender( new Vector2( videoWriter.Width, videoWriter.Height ) );
|
|
|
|
using Bitmap bitmap = new Bitmap( videoWriter.Width, videoWriter.Height );
|
|
camera.RenderToBitmap( bitmap );
|
|
|
|
return await Task.Run( () => videoWriter.AddFrame( bitmap, time ) );
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Shortcut for EditorTypeLibrary.GetSerializedObject( x )
|
|
/// </summary>
|
|
public static SerializedObject GetSerialized( this object self )
|
|
{
|
|
try
|
|
{
|
|
return EditorTypeLibrary.GetSerializedObject( self );
|
|
}
|
|
catch
|
|
{
|
|
return new ReflectionSerializedObject( self );
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Describes the path to a <see cref="SerializedProperty"/> from either a <see cref="GameObject"/>
|
|
/// or <see cref="Component"/>.
|
|
/// </summary>
|
|
public sealed class PropertyPath
|
|
{
|
|
private string _fullName;
|
|
|
|
/// <summary>
|
|
/// Full path to reach the original property, starting from a property on a <see cref="GameObject"/> or
|
|
/// <see cref="Component"/>.
|
|
/// </summary>
|
|
public IReadOnlyList<SerializedProperty> Properties { get; }
|
|
|
|
/// <summary>
|
|
/// Names of each property in <see cref="Properties"/>, separated by <c>'.'</c>s.
|
|
/// </summary>
|
|
public string FullName => _fullName ??= string.Join( ".", Properties.Select( x => x.Name ) );
|
|
|
|
/// <summary>
|
|
/// <see cref="GameObject"/>(s) or <see cref="Component"/>(s) that contain the original property.
|
|
/// </summary>
|
|
public IEnumerable<object> Targets => Properties[0].Parent.Targets;
|
|
|
|
internal PropertyPath( IEnumerable<SerializedProperty> properties )
|
|
{
|
|
Properties = properties.ToImmutableList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns <see cref="FullName"/>.
|
|
/// </summary>
|
|
public override string ToString() => FullName;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tries to find the path from a <see cref="GameObject"/> or <see cref="Component"/> to this property.
|
|
/// Returns <see langword="null"/> if not found.
|
|
/// </summary>
|
|
public static PropertyPath FindPathInScene( this SerializedProperty prop )
|
|
{
|
|
var path = new List<SerializedProperty>();
|
|
|
|
while ( prop?.Parent is not null )
|
|
{
|
|
path.Add( prop );
|
|
|
|
if ( prop.Parent.Targets.Any( x => x is Component or GameObject ) )
|
|
{
|
|
path.Reverse();
|
|
return new PropertyPath( path );
|
|
}
|
|
|
|
prop = prop.Parent?.ParentProperty;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tries to find the <see cref="GameObject"/> that contains the given property.
|
|
/// Returns <see langword="null"/> if not found.
|
|
/// </summary>
|
|
public static GameObject GetContainingGameObject( this SerializedProperty prop )
|
|
{
|
|
if ( prop.FindPathInScene() is not { } path )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if ( path.Targets.OfType<GameObject>().FirstOrDefault() is { } go )
|
|
{
|
|
return go;
|
|
}
|
|
|
|
if ( path.Targets.OfType<Component>().FirstOrDefault() is { } component )
|
|
{
|
|
return component.GameObject;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a feasible title from the current selection
|
|
/// </summary>
|
|
public static string ConstructTitle( this SelectionSystem sys )
|
|
{
|
|
if ( sys.Count == 0 ) return "Nothing";
|
|
if ( sys.Count > 1 ) return $"{sys.Count} Objects";
|
|
|
|
if ( sys.First() is GameObject go )
|
|
return go.Name;
|
|
|
|
return sys.First().ToString();
|
|
}
|
|
}
|