Phase O Task 3 — verbatim-copy GL infra from Chorizite.OpenGLSDLBackend
into src/AcDream.App/Rendering/Wb/ (namespace AcDream.App.Rendering.Wb).
18 files extracted (all namespace-changed; no algorithm changes):
OpenGLGraphicsDevice, ManagedGLTexture, ManagedGLTextureArray,
ManagedGLVertexBuffer, ManagedGLIndexBuffer, ManagedGLVertexArray,
ManagedGLFrameBuffer, ManagedGLUniformBuffer, GLSLShader, GLHelpers,
GLStateScope, GpuMemoryTracker, SceneData, DebugRenderSettings,
TextureParameters, TextureFormatExtensions, BufferUsageExtensions,
EmbeddedResourceReader.
3 internals promoted to public (O-D9):
EmbeddedResourceReader, TextureFormatExtensions, BufferUsageExtensions.
SixLabors.ImageSharp not reachable: TextureHelpers was placed in
AcDream.Core (no GL/ImageSharp dep); only the GL types went to App.
TextureHelpers.GetCompressedLayerSize added to AcDream.Core.Rendering.Wb
(was in Chorizite.OpenGLSDLBackend.Lib.TextureHelpers; uses
Chorizite.Core.Render.Enums.TextureFormat which Core gets transitively
via the still-present WB project refs).
T3/T4 boundary interims:
- WbMeshAdapter._graphicsDevice stays Chorizite.OpenGLSDLBackend.OpenGLGraphicsDevice
(T4 will swap it when ObjectMeshManager is extracted).
- OpenGLGraphicsDevice.ParticleBatcher deferred to null! (T4 extracts
ParticleBatcher alongside ObjectMeshManager; can't pass `this` of our
new type to the WB-original ctor before T4).
- ManagedGLTextureArray uses our TextureHelpers via explicit alias.
- IUniformBuffer is in Chorizite.Core.dll under Chorizite.OpenGLSDLBackend
namespace (unusual packaging); resolved via type alias.
- AcDream.App.csproj gets explicit Chorizite.Core 0.0.18 PackageReference
(IUniformBuffer + other Chorizite.Core types now used directly in App).
Build green. Test baseline 1147+8 maintained (1902 passing, 8 pre-existing
MotionInterpreterTests failures unrelated to T3).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
230 lines
11 KiB
C#
230 lines
11 KiB
C#
using Silk.NET.OpenGL;
|
|
using System;
|
|
|
|
namespace AcDream.App.Rendering.Wb {
|
|
/// <summary>
|
|
/// A RAII scope for saving and restoring OpenGL state.
|
|
/// </summary>
|
|
public unsafe struct GLStateScope : IDisposable {
|
|
private readonly GL _gl;
|
|
private fixed int _viewport[4];
|
|
private bool _scissorTest;
|
|
private fixed int _scissorBox[4];
|
|
private bool _depthTest;
|
|
private int _depthFunc;
|
|
private bool _depthMask;
|
|
private bool _cullFace;
|
|
private int _cullFaceMode;
|
|
private int _frontFace;
|
|
private bool _blend;
|
|
private int _blendSrc;
|
|
private int _blendDst;
|
|
private int _blendEquation;
|
|
|
|
// Extended state
|
|
private int _blendSrcAlpha;
|
|
private int _blendDstAlpha;
|
|
private int _blendEquationAlpha;
|
|
private fixed byte _colorMask[4];
|
|
private fixed float _clearColor[4];
|
|
private float _clearDepth;
|
|
private int _currentProgram;
|
|
private int _vertexArrayBinding;
|
|
private int _arrayBufferBinding;
|
|
private int _elementArrayBufferBinding;
|
|
private int _activeTexture;
|
|
private int _textureBinding2D;
|
|
private bool _stencilTest;
|
|
private int _stencilFunc;
|
|
private int _stencilRef;
|
|
private int _stencilValueMask;
|
|
private int _stencilFail;
|
|
private int _stencilPassDepthFail;
|
|
private int _stencilPassDepthPass;
|
|
private int _stencilWritemask;
|
|
private int _unpackAlignment;
|
|
private int _packAlignment;
|
|
|
|
private int _drawFramebufferBinding;
|
|
|
|
// Skia / Avalonia extra state protections
|
|
private fixed float _blendColor[4];
|
|
private int _polygonMode;
|
|
private bool _sampleAlphaToCoverage;
|
|
private bool _multisample;
|
|
private bool _primitiveRestart;
|
|
private int _readFramebufferBinding;
|
|
private int _uniformBufferBinding0;
|
|
private float _lineWidth;
|
|
private bool _programPointSize;
|
|
private int _samplerBinding0;
|
|
private int _samplerBinding1;
|
|
private int _samplerBinding2;
|
|
private int _unpackRowLength;
|
|
private int _unpackSkipRows;
|
|
private int _unpackSkipPixels;
|
|
private bool _sampleAlphaToOne;
|
|
|
|
private bool _isDisposed;
|
|
|
|
/// <summary>
|
|
/// Captures the current OpenGL state.
|
|
/// </summary>
|
|
/// <param name="gl"></param>
|
|
public GLStateScope(GL gl) {
|
|
_gl = gl;
|
|
_isDisposed = false;
|
|
|
|
fixed (int* v = _viewport) _gl.GetInteger(GetPName.Viewport, v);
|
|
_scissorTest = _gl.IsEnabled(EnableCap.ScissorTest);
|
|
fixed (int* s = _scissorBox) _gl.GetInteger(GetPName.ScissorBox, s);
|
|
|
|
_depthTest = _gl.IsEnabled(EnableCap.DepthTest);
|
|
_gl.GetInteger(GetPName.DepthFunc, out _depthFunc);
|
|
byte depthMask = 0;
|
|
_gl.GetBoolean((GetPName)GLEnum.DepthWritemask, (bool*)&depthMask);
|
|
_depthMask = depthMask != 0;
|
|
|
|
_cullFace = _gl.IsEnabled(EnableCap.CullFace);
|
|
_gl.GetInteger(GetPName.CullFaceMode, out _cullFaceMode);
|
|
_gl.GetInteger(GetPName.FrontFace, out _frontFace);
|
|
|
|
_blend = _gl.IsEnabled(EnableCap.Blend);
|
|
_gl.GetInteger(GetPName.BlendSrcRgb, out _blendSrc);
|
|
_gl.GetInteger(GetPName.BlendDstRgb, out _blendDst);
|
|
_gl.GetInteger(GetPName.BlendSrcAlpha, out _blendSrcAlpha);
|
|
_gl.GetInteger(GetPName.BlendDstAlpha, out _blendDstAlpha);
|
|
_gl.GetInteger(GetPName.BlendEquationRgb, out _blendEquation);
|
|
_gl.GetInteger(GetPName.BlendEquationAlpha, out _blendEquationAlpha);
|
|
|
|
fixed (byte* c = _colorMask) _gl.GetBoolean((GetPName)GLEnum.ColorWritemask, (bool*)c);
|
|
fixed (float* cc = _clearColor) _gl.GetFloat(GetPName.ColorClearValue, cc);
|
|
_gl.GetFloat(GetPName.DepthClearValue, out _clearDepth);
|
|
|
|
_gl.GetInteger(GetPName.CurrentProgram, out _currentProgram);
|
|
_gl.GetInteger(GetPName.VertexArrayBinding, out _vertexArrayBinding);
|
|
_gl.GetInteger(GetPName.ArrayBufferBinding, out _arrayBufferBinding);
|
|
_gl.GetInteger(GetPName.ElementArrayBufferBinding, out _elementArrayBufferBinding);
|
|
|
|
_gl.GetInteger(GetPName.ActiveTexture, out _activeTexture);
|
|
_gl.GetInteger(GetPName.TextureBinding2D, out _textureBinding2D);
|
|
|
|
_stencilTest = _gl.IsEnabled(EnableCap.StencilTest);
|
|
_gl.GetInteger(GetPName.StencilFunc, out _stencilFunc);
|
|
_gl.GetInteger(GetPName.StencilRef, out _stencilRef);
|
|
_gl.GetInteger(GetPName.StencilValueMask, out _stencilValueMask);
|
|
_gl.GetInteger(GetPName.StencilFail, out _stencilFail);
|
|
_gl.GetInteger(GetPName.StencilPassDepthFail, out _stencilPassDepthFail);
|
|
_gl.GetInteger(GetPName.StencilPassDepthPass, out _stencilPassDepthPass);
|
|
_gl.GetInteger(GetPName.StencilWritemask, out _stencilWritemask);
|
|
|
|
_gl.GetInteger(GetPName.UnpackAlignment, out _unpackAlignment);
|
|
_gl.GetInteger(GetPName.PackAlignment, out _packAlignment);
|
|
|
|
_gl.GetInteger(GetPName.DrawFramebufferBinding, out _drawFramebufferBinding);
|
|
|
|
fixed (float* bc = _blendColor) _gl.GetFloat(GetPName.BlendColor, bc);
|
|
_gl.GetInteger(GetPName.PolygonMode, out _polygonMode);
|
|
_sampleAlphaToCoverage = _gl.IsEnabled(EnableCap.SampleAlphaToCoverage);
|
|
_multisample = _gl.IsEnabled(EnableCap.Multisample);
|
|
_primitiveRestart = _gl.IsEnabled((EnableCap)GLEnum.PrimitiveRestart);
|
|
_gl.GetInteger(GetPName.ReadFramebufferBinding, out _readFramebufferBinding);
|
|
|
|
_gl.GetInteger(GetPName.UniformBufferBinding, out _uniformBufferBinding0);
|
|
|
|
_gl.GetFloat(GetPName.LineWidth, out _lineWidth);
|
|
_programPointSize = _gl.IsEnabled((EnableCap)GLEnum.ProgramPointSize);
|
|
|
|
_gl.ActiveTexture(TextureUnit.Texture0);
|
|
_gl.GetInteger((GetPName)GLEnum.SamplerBinding, out _samplerBinding0);
|
|
_gl.ActiveTexture(TextureUnit.Texture1);
|
|
_gl.GetInteger((GetPName)GLEnum.SamplerBinding, out _samplerBinding1);
|
|
_gl.ActiveTexture(TextureUnit.Texture2);
|
|
_gl.GetInteger((GetPName)GLEnum.SamplerBinding, out _samplerBinding2);
|
|
_gl.ActiveTexture((TextureUnit)_activeTexture);
|
|
|
|
_gl.GetInteger((GetPName)GLEnum.UnpackRowLength, out _unpackRowLength);
|
|
_gl.GetInteger((GetPName)GLEnum.UnpackSkipRows, out _unpackSkipRows);
|
|
_gl.GetInteger((GetPName)GLEnum.UnpackSkipPixels, out _unpackSkipPixels);
|
|
_sampleAlphaToOne = _gl.IsEnabled(EnableCap.SampleAlphaToOne);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restores only the scissor state from the scope.
|
|
/// </summary>
|
|
public void RestoreScissor() {
|
|
if (_scissorTest) _gl.Enable(EnableCap.ScissorTest);
|
|
else _gl.Disable(EnableCap.ScissorTest);
|
|
_gl.Scissor(_scissorBox[0], _scissorBox[1], (uint)_scissorBox[2], (uint)_scissorBox[3]);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restores the captured OpenGL state.
|
|
/// </summary>
|
|
public void Dispose() {
|
|
if (_isDisposed) return;
|
|
|
|
// Restoring state
|
|
if (_currentProgram != 0) _gl.UseProgram((uint)_currentProgram); else _gl.UseProgram(0);
|
|
|
|
_gl.BindVertexArray((uint)_vertexArrayBinding);
|
|
_gl.BindBuffer(BufferTargetARB.ArrayBuffer, (uint)_arrayBufferBinding);
|
|
_gl.BindBuffer(BufferTargetARB.ElementArrayBuffer, (uint)_elementArrayBufferBinding);
|
|
_gl.BindBuffer(GLEnum.UniformBuffer, (uint)_uniformBufferBinding0);
|
|
|
|
_gl.ActiveTexture((TextureUnit)_activeTexture);
|
|
_gl.BindTexture(TextureTarget.Texture2D, (uint)_textureBinding2D);
|
|
|
|
if (_stencilTest) _gl.Enable(EnableCap.StencilTest); else _gl.Disable(EnableCap.StencilTest);
|
|
_gl.StencilFunc((StencilFunction)_stencilFunc, _stencilRef, (uint)_stencilValueMask);
|
|
_gl.StencilOp((StencilOp)_stencilFail, (StencilOp)_stencilPassDepthFail, (StencilOp)_stencilPassDepthPass);
|
|
_gl.StencilMask((uint)_stencilWritemask);
|
|
|
|
_gl.PixelStore(PixelStoreParameter.UnpackAlignment, _unpackAlignment);
|
|
_gl.PixelStore(PixelStoreParameter.PackAlignment, _packAlignment);
|
|
_gl.PixelStore(PixelStoreParameter.UnpackRowLength, _unpackRowLength);
|
|
_gl.PixelStore(PixelStoreParameter.UnpackSkipRows, _unpackSkipRows);
|
|
_gl.PixelStore(PixelStoreParameter.UnpackSkipPixels, _unpackSkipPixels);
|
|
|
|
_gl.ClearColor(_clearColor[0], _clearColor[1], _clearColor[2], _clearColor[3]);
|
|
_gl.ClearDepth(_clearDepth);
|
|
|
|
_gl.Viewport(_viewport[0], _viewport[1], (uint)_viewport[2], (uint)_viewport[3]);
|
|
RestoreScissor();
|
|
|
|
if (_depthTest) _gl.Enable(EnableCap.DepthTest); else _gl.Disable(EnableCap.DepthTest);
|
|
_gl.DepthFunc((DepthFunction)_depthFunc);
|
|
_gl.DepthMask(_depthMask);
|
|
|
|
if (_cullFace) _gl.Enable(EnableCap.CullFace); else _gl.Disable(EnableCap.CullFace);
|
|
_gl.CullFace((TriangleFace)_cullFaceMode);
|
|
_gl.FrontFace((FrontFaceDirection)_frontFace);
|
|
|
|
if (_blend) _gl.Enable(EnableCap.Blend); else _gl.Disable(EnableCap.Blend);
|
|
_gl.BlendFuncSeparate((BlendingFactor)_blendSrc, (BlendingFactor)_blendDst, (BlendingFactor)_blendSrcAlpha, (BlendingFactor)_blendDstAlpha);
|
|
_gl.BlendEquationSeparate((BlendEquationModeEXT)_blendEquation, (BlendEquationModeEXT)_blendEquationAlpha);
|
|
_gl.BlendColor(_blendColor[0], _blendColor[1], _blendColor[2], _blendColor[3]);
|
|
|
|
_gl.ColorMask(_colorMask[0] != 0, _colorMask[1] != 0, _colorMask[2] != 0, _colorMask[3] != 0);
|
|
|
|
_gl.PolygonMode(GLEnum.FrontAndBack, (PolygonMode)_polygonMode);
|
|
|
|
if (_sampleAlphaToCoverage) _gl.Enable(EnableCap.SampleAlphaToCoverage); else _gl.Disable(EnableCap.SampleAlphaToCoverage);
|
|
if (_sampleAlphaToOne) _gl.Enable(EnableCap.SampleAlphaToOne); else _gl.Disable(EnableCap.SampleAlphaToOne);
|
|
if (_multisample) _gl.Enable(EnableCap.Multisample); else _gl.Disable(EnableCap.Multisample);
|
|
if (_primitiveRestart) _gl.Enable((EnableCap)GLEnum.PrimitiveRestart); else _gl.Disable((EnableCap)GLEnum.PrimitiveRestart);
|
|
if (_programPointSize) _gl.Enable((EnableCap)GLEnum.ProgramPointSize); else _gl.Disable((EnableCap)GLEnum.ProgramPointSize);
|
|
|
|
_gl.LineWidth(_lineWidth);
|
|
|
|
_gl.BindSampler(0, (uint)_samplerBinding0);
|
|
_gl.BindSampler(1, (uint)_samplerBinding1);
|
|
_gl.BindSampler(2, (uint)_samplerBinding2);
|
|
|
|
_gl.BindFramebuffer(FramebufferTarget.DrawFramebuffer, (uint)_drawFramebufferBinding);
|
|
_gl.BindFramebuffer(FramebufferTarget.ReadFramebuffer, (uint)_readFramebufferBinding);
|
|
|
|
_isDisposed = true;
|
|
}
|
|
}
|
|
}
|