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>
113 lines
3.5 KiB
C#
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);
|
|
}
|
|
}
|