acdream/src/AcDream.App/Rendering/RenderFrameGlStateController.cs
Erik 28e1cf8029 refactor(render): extract world scene frame owner
Move fallback and PView world drawing, shared alpha, particles, visibility, selection, and diagnostics behind focused frame owners. Make exceptional frames failure-atomic by restoring the shared GL baseline and preserving primary alpha failures through cleanup.

Co-authored-by: Codex <codex@openai.com>
2026-07-22 07:22:09 +02:00

113 lines
3.5 KiB
C#

using Silk.NET.OpenGL;
namespace AcDream.App.Rendering;
internal interface IRenderFrameGlState
{
void RestoreFrameDefaults();
}
internal interface IRenderFrameGlStateApi
{
void SetCapability(EnableCap capability, bool enabled);
void ColorMask(bool red, bool green, bool blue, bool alpha);
void StencilMask(uint mask);
void DepthMask(bool enabled);
void DepthFunc(DepthFunction function);
void CullFace(TriangleFace face);
void FrontFace(FrontFaceDirection direction);
void UseProgram(uint program);
void BindVertexArray(uint vertexArray);
void BindBuffer(BufferTargetARB target, uint buffer);
}
internal sealed class SilkRenderFrameGlStateApi : IRenderFrameGlStateApi
{
private readonly GL _gl;
public SilkRenderFrameGlStateApi(GL gl)
{
_gl = gl ?? throw new ArgumentNullException(nameof(gl));
}
public void SetCapability(EnableCap capability, bool enabled)
{
if (enabled)
_gl.Enable(capability);
else
_gl.Disable(capability);
}
public void ColorMask(bool red, bool green, bool blue, bool alpha) =>
_gl.ColorMask(red, green, blue, alpha);
public void StencilMask(uint mask) => _gl.StencilMask(mask);
public void DepthMask(bool enabled) => _gl.DepthMask(enabled);
public void DepthFunc(DepthFunction function) => _gl.DepthFunc(function);
public void CullFace(TriangleFace face) => _gl.CullFace(face);
public void FrontFace(FrontFaceDirection direction) => _gl.FrontFace(direction);
public void UseProgram(uint program) => _gl.UseProgram(program);
public void BindVertexArray(uint vertexArray) => _gl.BindVertexArray(vertexArray);
public void BindBuffer(BufferTargetARB target, uint buffer) =>
_gl.BindBuffer(target, buffer);
}
/// <summary>
/// Restores the frame-global OpenGL convention shared by frame clear and
/// exceptional world-pass rollback. This prevents a failed doorway scissor or
/// portal depth mask from clipping/color-masking the next frame's clear.
/// </summary>
internal sealed class RenderFrameGlStateController : IRenderFrameGlState
{
private readonly IRenderFrameGlStateApi _gl;
public RenderFrameGlStateController(IRenderFrameGlStateApi gl)
{
_gl = gl ?? throw new ArgumentNullException(nameof(gl));
}
public void RestoreFrameDefaults()
{
_gl.SetCapability(EnableCap.ScissorTest, enabled: false);
_gl.SetCapability(EnableCap.StencilTest, enabled: false);
_gl.SetCapability(EnableCap.Blend, enabled: false);
_gl.SetCapability(EnableCap.SampleAlphaToCoverage, enabled: false);
for (int index = 0; index < ClipFrame.MaxPlanes; index++)
{
_gl.SetCapability(
EnableCap.ClipDistance0 + index,
enabled: false);
}
_gl.ColorMask(true, true, true, true);
_gl.StencilMask(0xFF);
_gl.DepthMask(true);
_gl.DepthFunc(DepthFunction.Less);
_gl.SetCapability(EnableCap.DepthTest, enabled: true);
// Renderers that need face culling establish it locally. The shared
// frame convention is culling off; SkyRenderer restores the state it
// observed, so enabling it here would leak culling into later passes.
_gl.SetCapability(EnableCap.CullFace, enabled: false);
_gl.CullFace(TriangleFace.Back);
_gl.FrontFace(FrontFaceDirection.CW);
_gl.UseProgram(0);
_gl.BindVertexArray(0);
_gl.BindBuffer(BufferTargetARB.ArrayBuffer, 0);
}
}