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}."), }; }