using Silk.NET.OpenGL;
namespace AcDream.App.Rendering.Gpu.Gl;
/// One vertex attribute's GL shape: component count, element type, and whether integer values normalize to [0,1]/[-1,1].
internal readonly record struct GlVertexAttributeShape(int ComponentCount, VertexAttribPointerType Type, bool Normalized);
///
/// Pure, GL-context-free mappings from the RHI's backend-neutral enums to
/// Silk.NET's OpenGL enum values. Kept as small switch expressions so each
/// mapping is independently unit-testable and — per the campaign spec's
/// "when in doubt, set the state" rule — every backend-neutral value has an
/// explicit case rather than a fallthrough default.
///
internal static class GlEnumMapping
{
public static GlVertexAttributeShape VertexShapeOf(GpuVertexFormat format) => format switch
{
GpuVertexFormat.Float1 => new GlVertexAttributeShape(1, VertexAttribPointerType.Float, false),
GpuVertexFormat.Float2 => new GlVertexAttributeShape(2, VertexAttribPointerType.Float, false),
GpuVertexFormat.Float3 => new GlVertexAttributeShape(3, VertexAttribPointerType.Float, false),
GpuVertexFormat.Float4 => new GlVertexAttributeShape(4, VertexAttribPointerType.Float, false),
GpuVertexFormat.UByte4Normalized => new GlVertexAttributeShape(4, VertexAttribPointerType.UnsignedByte, true),
_ => throw new NotSupportedException($"No GL vertex attribute shape for {format}."),
};
public static PrimitiveType PrimitiveTypeOf(GpuPrimitiveTopology topology) => topology switch
{
GpuPrimitiveTopology.TriangleList => PrimitiveType.Triangles,
GpuPrimitiveTopology.LineList => PrimitiveType.Lines,
_ => throw new NotSupportedException($"No GL primitive type for {topology}."),
};
public static DrawElementsType DrawElementsTypeOf(GpuIndexType indexType) => indexType switch
{
GpuIndexType.UInt16 => DrawElementsType.UnsignedShort,
GpuIndexType.UInt32 => DrawElementsType.UnsignedInt,
_ => throw new NotSupportedException($"No GL index type for {indexType}."),
};
public static int IndexSizeBytesOf(GpuIndexType indexType) => indexType switch
{
GpuIndexType.UInt16 => sizeof(ushort),
GpuIndexType.UInt32 => sizeof(uint),
_ => throw new NotSupportedException($"No index byte size for {indexType}."),
};
public static DepthFunction DepthFunctionOf(GpuCompareOp compareOp) => compareOp switch
{
GpuCompareOp.Never => DepthFunction.Never,
GpuCompareOp.Less => DepthFunction.Less,
GpuCompareOp.LessOrEqual => DepthFunction.Lequal,
GpuCompareOp.Equal => DepthFunction.Equal,
GpuCompareOp.Greater => DepthFunction.Greater,
GpuCompareOp.GreaterOrEqual => DepthFunction.Gequal,
GpuCompareOp.Always => DepthFunction.Always,
_ => throw new NotSupportedException($"No GL depth function for {compareOp}."),
};
public static TriangleFace CullFaceModeOf(GpuCullMode cullMode) => cullMode switch
{
GpuCullMode.Back => TriangleFace.Back,
GpuCullMode.Front => TriangleFace.Front,
// GpuCullMode.None never reaches glCullFace — culling is disabled instead.
_ => throw new NotSupportedException($"No GL cull face mode for {cullMode}."),
};
public static FrontFaceDirection FrontFaceDirectionOf(GpuFrontFace frontFace) => frontFace switch
{
GpuFrontFace.CounterClockwise => FrontFaceDirection.Ccw,
GpuFrontFace.Clockwise => FrontFaceDirection.CW,
_ => throw new NotSupportedException($"No GL front-face direction for {frontFace}."),
};
public static (BlendingFactor Source, BlendingFactor Destination) BlendFactorsOf(GpuBlendMode blend) => blend switch
{
GpuBlendMode.StraightAlpha => (BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha),
GpuBlendMode.Additive => (BlendingFactor.SrcAlpha, BlendingFactor.One),
// GpuBlendMode.None never reaches glBlendFunc — blending is disabled instead.
_ => throw new NotSupportedException($"No GL blend factors for {blend}."),
};
public static TextureMinFilter MinFilterOf(GpuFilter filter, GpuMipFilter mipFilter) => (filter, mipFilter) switch
{
(GpuFilter.Nearest, GpuMipFilter.None) => TextureMinFilter.Nearest,
(GpuFilter.Linear, GpuMipFilter.None) => TextureMinFilter.Linear,
(GpuFilter.Nearest, GpuMipFilter.Nearest) => TextureMinFilter.NearestMipmapNearest,
(GpuFilter.Linear, GpuMipFilter.Nearest) => TextureMinFilter.LinearMipmapNearest,
(GpuFilter.Nearest, GpuMipFilter.Linear) => TextureMinFilter.NearestMipmapLinear,
(GpuFilter.Linear, GpuMipFilter.Linear) => TextureMinFilter.LinearMipmapLinear,
_ => throw new NotSupportedException($"No GL min filter for {filter}/{mipFilter}."),
};
public static TextureMagFilter MagFilterOf(GpuFilter filter) => filter switch
{
GpuFilter.Nearest => TextureMagFilter.Nearest,
GpuFilter.Linear => TextureMagFilter.Linear,
_ => throw new NotSupportedException($"No GL mag filter for {filter}."),
};
public static TextureWrapMode WrapModeOf(GpuAddressMode addressMode) => addressMode switch
{
GpuAddressMode.Repeat => TextureWrapMode.Repeat,
GpuAddressMode.ClampToEdge => TextureWrapMode.ClampToEdge,
_ => throw new NotSupportedException($"No GL wrap mode for {addressMode}."),
};
}