mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-15 17:59:22 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
217 lines
9.5 KiB
C#
217 lines
9.5 KiB
C#
using NativeEngine;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Sandbox;
|
|
|
|
partial class Graphics
|
|
{
|
|
private static void ValidateMaterial( Material material )
|
|
{
|
|
if ( material is null || material.native.IsNull )
|
|
throw new ArgumentException( $"{nameof( material )} is invalid.", nameof( material ) );
|
|
}
|
|
|
|
private static void ValidateVertexBuffer( GpuBuffer vertexBuffer )
|
|
{
|
|
if ( !vertexBuffer.IsValid() )
|
|
throw new ArgumentException( $"{nameof( vertexBuffer )} is invalid.", nameof( vertexBuffer ) );
|
|
|
|
if ( !vertexBuffer.Usage.Contains( GpuBuffer.UsageFlags.Vertex ) )
|
|
throw new ArgumentException( $"{nameof( vertexBuffer )} does not have the required usage flag '{GpuBuffer.UsageFlags.Vertex}'.", nameof( vertexBuffer ) );
|
|
}
|
|
|
|
private static void ValidateIndexBuffer( GpuBuffer indexBuffer )
|
|
{
|
|
if ( !indexBuffer.IsValid() )
|
|
throw new ArgumentException( $"{nameof( indexBuffer )} is invalid.", nameof( indexBuffer ) );
|
|
|
|
if ( !indexBuffer.Usage.Contains( GpuBuffer.UsageFlags.Index ) )
|
|
throw new ArgumentException( $"{nameof( indexBuffer )} does not have the required usage flag '{GpuBuffer.UsageFlags.Index}'.", nameof( indexBuffer ) );
|
|
|
|
if ( indexBuffer.ElementSize != sizeof( uint ) && indexBuffer.ElementSize != sizeof( ushort ) )
|
|
throw new ArgumentOutOfRangeException( nameof( indexBuffer ), $"{nameof( indexBuffer )} must be size of {sizeof( uint )} or {sizeof( ushort )}." );
|
|
}
|
|
|
|
private static void ValidateIndirectBuffer( GpuBuffer indirectBuffer )
|
|
{
|
|
if ( !indirectBuffer.IsValid() )
|
|
throw new ArgumentException( $"{nameof( indirectBuffer )} is invalid.", nameof( indirectBuffer ) );
|
|
|
|
if ( !indirectBuffer.Usage.Contains( GpuBuffer.UsageFlags.IndirectDrawArguments ) )
|
|
throw new ArgumentException( $"Buffer must have the required usage flag '{GpuBuffer.UsageFlags.IndirectDrawArguments}'", nameof( indirectBuffer ) );
|
|
}
|
|
|
|
private static NativeEngine.VertexLayout GetVertexLayout<T>() where T : unmanaged
|
|
{
|
|
var vertexType = VertexLayout.Get<T>();
|
|
if ( vertexType.IsNull )
|
|
throw new ArgumentException( $"{nameof( T )} vertex layout is invalid.", nameof( T ) );
|
|
|
|
return vertexType;
|
|
}
|
|
|
|
private static bool SetRenderState<T>( GpuBuffer<T> vertexBuffer, Material material, RenderAttributes attributes ) where T : unmanaged
|
|
{
|
|
ValidateVertexBuffer( vertexBuffer );
|
|
ValidateMaterial( material );
|
|
|
|
var layout = GetVertexLayout<T>();
|
|
|
|
attributes ??= Attributes;
|
|
return RenderTools.SetRenderState( Context, attributes.Get(), material.native.GetMode( SceneLayer ), layout, Stats );
|
|
}
|
|
|
|
private static bool SetRenderState( Material material, RenderAttributes attributes )
|
|
{
|
|
ValidateMaterial( material );
|
|
|
|
attributes ??= Attributes;
|
|
return RenderTools.SetRenderState( Context, attributes.Get(), material.native.GetMode( SceneLayer ), default, Stats );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draws geometry using a vertex buffer and material.
|
|
/// </summary>
|
|
/// <typeparam name="T">The vertex type used for vertex layout.</typeparam>
|
|
/// <param name="vertexBuffer">The GPU buffer containing vertex data.</param>
|
|
/// <param name="material">The material to use for rendering.</param>
|
|
/// <param name="startVertex">The starting vertex index for rendering.</param>
|
|
/// <param name="vertexCount">The number of vertices to render. If 0, uses all vertices in the buffer.</param>
|
|
/// <param name="attributes">Optional render attributes to apply only for this draw call.</param>
|
|
/// <param name="primitiveType">The type of primitives to render. Defaults to triangles.</param>
|
|
public static void Draw<T>( GpuBuffer<T> vertexBuffer, Material material, int startVertex = 0, int vertexCount = 0, RenderAttributes attributes = null, PrimitiveType primitiveType = PrimitiveType.Triangles ) where T : unmanaged
|
|
{
|
|
AssertRenderBlock();
|
|
|
|
if ( !SetRenderState( vertexBuffer, material, attributes ) )
|
|
return;
|
|
|
|
if ( vertexCount <= 0 )
|
|
vertexCount = vertexBuffer.ElementCount;
|
|
|
|
if ( vertexCount <= 0 )
|
|
return;
|
|
|
|
if ( startVertex < 0 || startVertex >= vertexBuffer.ElementCount )
|
|
throw new ArgumentOutOfRangeException( nameof( startVertex ), $"{nameof( startVertex )} is out of bounds of the vertex buffer." );
|
|
|
|
if ( startVertex + vertexCount > vertexBuffer.ElementCount )
|
|
throw new ArgumentOutOfRangeException( nameof( vertexCount ), $"{nameof( vertexCount )} exceeds the bounds of the vertex buffer." );
|
|
|
|
Context.BindVertexBuffer( 0, vertexBuffer.native, 0 );
|
|
Context.Draw( (RenderPrimitiveType)primitiveType, startVertex, vertexCount );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draws indexed geometry using vertex and index buffers.
|
|
/// </summary>
|
|
/// <typeparam name="T">The vertex type used for vertex layout.</typeparam>
|
|
/// <param name="vertexBuffer">The GPU buffer containing vertex data.</param>
|
|
/// <param name="indexBuffer">The GPU buffer containing index data.</param>
|
|
/// <param name="material">The material to use for rendering.</param>
|
|
/// <param name="startIndex">The starting index for rendering.</param>
|
|
/// <param name="indexCount">The number of indices to render. If 0, uses all indices in the buffer.</param>
|
|
/// <param name="attributes">Optional render attributes to apply only for this draw call.</param>
|
|
/// <param name="primitiveType">The type of primitives to render. Defaults to triangles.</param>
|
|
public static void Draw<T>( GpuBuffer<T> vertexBuffer, GpuBuffer indexBuffer, Material material, int startIndex = 0, int indexCount = 0, RenderAttributes attributes = null, PrimitiveType primitiveType = PrimitiveType.Triangles ) where T : unmanaged
|
|
{
|
|
AssertRenderBlock();
|
|
|
|
ValidateIndexBuffer( indexBuffer );
|
|
|
|
if ( !SetRenderState( vertexBuffer, material, attributes ) )
|
|
return;
|
|
|
|
if ( indexCount <= 0 )
|
|
indexCount = indexBuffer.ElementCount;
|
|
|
|
if ( indexCount <= 0 )
|
|
return;
|
|
|
|
if ( startIndex < 0 || startIndex >= indexBuffer.ElementCount )
|
|
throw new ArgumentOutOfRangeException( nameof( startIndex ), $"{nameof( startIndex )} is out of bounds of the index buffer." );
|
|
|
|
if ( startIndex + indexCount > indexBuffer.ElementCount )
|
|
throw new ArgumentOutOfRangeException( nameof( indexCount ), $"{nameof( indexCount )} exceeds the bounds of the index buffer." );
|
|
|
|
Context.BindVertexBuffer( 0, vertexBuffer.native, 0 );
|
|
Context.BindIndexBuffer( indexBuffer.native, indexBuffer.ElementSize, 0 );
|
|
Context.DrawIndexed( (RenderPrimitiveType)primitiveType, startIndex, indexCount, 0, 0 );
|
|
}
|
|
|
|
internal static void DrawInstancedIndirect<T>( GpuBuffer<T> vertexBuffer, Material material, GpuBuffer indirectBuffer, uint indirectElementOffset = 0, RenderAttributes attributes = null, PrimitiveType primitiveType = PrimitiveType.Triangles ) where T : unmanaged
|
|
{
|
|
AssertRenderBlock();
|
|
|
|
ValidateIndirectBuffer( indirectBuffer );
|
|
|
|
if ( !SetRenderState( vertexBuffer, material, attributes ) )
|
|
return;
|
|
|
|
var bufferOffset = indirectElementOffset * Marshal.SizeOf<GpuBuffer.IndirectDrawArguments>();
|
|
|
|
Context.BindVertexBuffer( 0, vertexBuffer.native, 0 );
|
|
Context.DrawInstancedIndirect( (RenderPrimitiveType)primitiveType, indirectBuffer.native, (uint)bufferOffset );
|
|
}
|
|
|
|
internal static void DrawInstancedIndirect( Material material, GpuBuffer indirectBuffer, uint indirectElementOffset = 0, RenderAttributes attributes = null, PrimitiveType primitiveType = PrimitiveType.Triangles )
|
|
{
|
|
AssertRenderBlock();
|
|
|
|
ValidateIndirectBuffer( indirectBuffer );
|
|
|
|
if ( !SetRenderState( material, attributes ) )
|
|
return;
|
|
|
|
var bufferOffset = indirectElementOffset * Marshal.SizeOf<GpuBuffer.IndirectDrawArguments>();
|
|
|
|
Context.DrawInstancedIndirect( (RenderPrimitiveType)primitiveType, indirectBuffer.native, (uint)bufferOffset );
|
|
}
|
|
|
|
internal static void DrawIndexedInstanced( GpuBuffer indexBuffer, Material material, int instanceCount, RenderAttributes attributes = null, PrimitiveType primitiveType = PrimitiveType.Triangles )
|
|
{
|
|
AssertRenderBlock();
|
|
|
|
ValidateIndexBuffer( indexBuffer );
|
|
|
|
if ( !SetRenderState( material, attributes ) )
|
|
return;
|
|
|
|
Context.BindIndexBuffer( indexBuffer.native, indexBuffer.ElementSize, 0 );
|
|
Context.DrawIndexedInstanced( (RenderPrimitiveType)primitiveType, 0, indexBuffer.ElementCount, instanceCount, 0, 0 );
|
|
}
|
|
|
|
internal static void DrawIndexedInstancedIndirect<T>( GpuBuffer<T> vertexBuffer, GpuBuffer indexBuffer, Material material, GpuBuffer indirectBuffer, uint indirectElementOffset = 0, RenderAttributes attributes = null, PrimitiveType primitiveType = PrimitiveType.Triangles ) where T : unmanaged
|
|
{
|
|
AssertRenderBlock();
|
|
|
|
ValidateIndirectBuffer( indirectBuffer );
|
|
ValidateIndexBuffer( indexBuffer );
|
|
|
|
if ( !SetRenderState( vertexBuffer, material, attributes ) )
|
|
return;
|
|
|
|
var bufferOffset = indirectElementOffset * Marshal.SizeOf<GpuBuffer.IndirectDrawIndexedArguments>();
|
|
|
|
Context.BindVertexBuffer( 0, vertexBuffer.native, 0 );
|
|
Context.BindIndexBuffer( indexBuffer.native, indexBuffer.ElementSize, 0 );
|
|
Context.DrawIndexedInstancedIndirect( (RenderPrimitiveType)primitiveType, indirectBuffer.native, (uint)bufferOffset );
|
|
}
|
|
|
|
internal static void DrawIndexedInstancedIndirect( GpuBuffer indexBuffer, Material material, GpuBuffer indirectBuffer, uint indirectElementOffset = 0, RenderAttributes attributes = null, PrimitiveType primitiveType = PrimitiveType.Triangles )
|
|
{
|
|
AssertRenderBlock();
|
|
|
|
ValidateIndirectBuffer( indirectBuffer );
|
|
ValidateIndexBuffer( indexBuffer );
|
|
|
|
if ( !SetRenderState( material, attributes ) )
|
|
return;
|
|
|
|
var bufferOffset = indirectElementOffset * Marshal.SizeOf<GpuBuffer.IndirectDrawIndexedArguments>();
|
|
|
|
Context.BindIndexBuffer( indexBuffer.native, indexBuffer.ElementSize, 0 );
|
|
Context.DrawIndexedInstancedIndirect( (RenderPrimitiveType)primitiveType, indirectBuffer.native, (uint)bufferOffset );
|
|
}
|
|
}
|