Utils/MeshWriter.cs
using System.Runtime.InteropServices;

namespace HC3;

#nullable enable

public abstract class MeshWriter<T>
	where T : unmanaged
{
	private readonly List<T> _vertices = new();
	private readonly List<int> _indices = new();

	private BBox _bounds;

	protected List<T> Vertices => _vertices;
	protected List<int> Indices => _indices;

	public bool IsEmpty => _indices.Count == 0;

	public int VertexCount => _vertices.Count;

	public BBox Bounds
	{
		get => _bounds;
		protected set => _bounds = value;
	}

	public void Clear()
	{
		_vertices.Clear();
		_indices.Clear();

		_bounds = default;

		OnClear();
	}

	protected virtual void OnClear()
	{

	}

	public int AddVertex( T vertex )
	{
		var index = _vertices.Count;
		_vertices.Add( vertex );

		return index;
	}

	public void AddTriangle( int a, int b, int c )
	{
		_indices.Add( a );
		_indices.Add( b );
		_indices.Add( c );
	}

	public void AddIndices( IEnumerable<int> indices, int offset )
	{
		foreach ( var index in indices )
		{
			_indices.Add( index + offset );
		}
	}

	public BBox CopyTo( Mesh mesh )
	{
		if ( !mesh.HasVertexBuffer )
		{
			mesh.CreateVertexBuffer<T>( Vertices.Count, CollectionsMarshal.AsSpan( Vertices ) );
			mesh.CreateIndexBuffer( Indices.Count, Indices );
		}
		else
		{
			mesh.SetVertexBufferSize( Vertices.Count );
			mesh.SetIndexBufferSize( Indices.Count );

			mesh.SetVertexBufferData( Vertices );
			mesh.SetIndexBufferData( Indices );
		}

		mesh.SetIndexRange( 0, Indices.Count );
		mesh.Bounds = Bounds;

		return Bounds;
	}
}