Core/RuinMeshFactory.cs
using System;
using System.Collections.Generic;

namespace Prototype;

/// <summary>Runtime-authored low-poly meshes. These are real triangle meshes, not scaled dev boxes.</summary>
public static class RuinMeshFactory
{
	private static readonly Dictionary<string, Model> Models = new();
	private static readonly Material Stone = Material.Load( "materials/dev/primary_white.vmat" );

	public static GameObject Lathe( string name, Vector3 position, float bottomRadius, float topRadius, float height, Color color, GameObject parent = null, int sides = 12 )
	{
		var key = $"lathe:{bottomRadius:0.0}:{topRadius:0.0}:{height:0.0}:{sides}";
		if ( !Models.TryGetValue( key, out var model ) )
		{
			var buffer = new VertexBuffer();
			buffer.Init( false );
			for ( var i = 0; i < sides; i++ )
			{
				var a0 = i * MathF.PI * 2f / sides;
				var a1 = (i + 1) * MathF.PI * 2f / sides;
				var n0 = new Vector3( MathF.Cos(a0), MathF.Sin(a0), 0f ).Normal;
				var n1 = new Vector3( MathF.Cos(a1), MathF.Sin(a1), 0f ).Normal;
				var b0 = new Vector3( n0.x * bottomRadius, n0.y * bottomRadius, -height * .5f );
				var b1 = new Vector3( n1.x * bottomRadius, n1.y * bottomRadius, -height * .5f );
				var t0 = new Vector3( n0.x * topRadius, n0.y * topRadius, height * .5f );
				var t1 = new Vector3( n1.x * topRadius, n1.y * topRadius, height * .5f );
				AddTriangle( buffer, b0, t0, t1, n0, n0, n1 );
				AddTriangle( buffer, b0, t1, b1, n0, n1, n1 );
				AddTriangle( buffer, Vector3.Down * height * .5f, b1, b0, Vector3.Down, Vector3.Down, Vector3.Down );
				AddTriangle( buffer, Vector3.Up * height * .5f, t0, t1, Vector3.Up, Vector3.Up, Vector3.Up );
			}
			var mesh = new Mesh( Stone ); mesh.CreateBuffers( buffer );
			model = new ModelBuilder().AddMesh( mesh ).Create();
			Models[key] = model;
		}
		var go = new GameObject( true, name ); go.WorldPosition = position;
		if ( parent is not null ) go.SetParent( parent, true );
		var renderer = go.Components.Create<ModelRenderer>(); renderer.Model = model; renderer.Tint = color;
		return go;
	}

	private static void AddTriangle( VertexBuffer buffer, Vector3 a, Vector3 b, Vector3 c, Vector3 na, Vector3 nb, Vector3 nc )
	{
		buffer.Add( new Vertex( a, na, Vector3.Zero, Vector4.Zero ) );
		buffer.Add( new Vertex( b, nb, Vector3.Zero, Vector4.Zero ) );
		buffer.Add( new Vertex( c, nc, Vector3.Zero, Vector4.Zero ) );
	}
}