From 0500646f082260a0438b0175e79c98073aac6384 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 14 Jun 2026 18:49:52 +0200 Subject: [PATCH] fix(D.2b): draw UI chrome behind content (TextRenderer Flush layer order) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TextRenderer.Flush batched by primitive type and flushed rects -> text -> sprites LAST, so the 8-piece chrome (incl. the center fill) painted OVER the vital bars + numbers ("the window is drawn in front of the bars"). Reorder to sprites -> rects -> text so chrome composites behind widget fills + text. Correct while bars are solid rects; when bars become gradient SPRITES this must move to true submission/painter order (sprite-on-sprite z) — noted inline as the D.2b follow-up. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/AcDream.App/Rendering/TextRenderer.cs | 46 +++++++++++++---------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/AcDream.App/Rendering/TextRenderer.cs b/src/AcDream.App/Rendering/TextRenderer.cs index b07a9d40..a0252518 100644 --- a/src/AcDream.App/Rendering/TextRenderer.cs +++ b/src/AcDream.App/Rendering/TextRenderer.cs @@ -197,26 +197,15 @@ public sealed unsafe class TextRenderer : IDisposable _gl.Enable(EnableCap.Blend); _gl.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); - // Untextured rects first — they form panel backgrounds. - if (_rectVerts > 0) - { - _shader.SetInt("uUseTexture", 0); - UploadBuffer(_rectBuf); - _gl.DrawArrays(PrimitiveType.Triangles, 0, (uint)_rectVerts); - } + // LAYERED compositing for the UI (background → fill → text): + // 1. RGBA dat sprites — window chrome / panel backgrounds (behind) + // 2. Untextured rects — widget fills (e.g. vital bars) on the chrome + // 3. Text glyphs — on top + // NOTE: this type-bucketed order is correct while bars are solid rects. + // When bars become gradient SPRITES, this must move to true submission + // (painter) order so sprite-on-sprite z is preserved (D.2b follow-up). - // Textured text glyphs. - if (_textVerts > 0 && font is not null) - { - _shader.SetInt("uUseTexture", 1); - _gl.ActiveTexture(TextureUnit.Texture0); - _gl.BindTexture(TextureTarget.Texture2D, font.TextureId); - _shader.SetInt("uTex", 0); - UploadBuffer(_textBuf); - _gl.DrawArrays(PrimitiveType.Triangles, 0, (uint)_textVerts); - } - - // RGBA dat sprites — one draw call per distinct GL texture. + // 1. RGBA dat sprites first — one draw call per distinct GL texture. if (hasSprites) { _shader.SetInt("uUseTexture", 2); @@ -231,6 +220,25 @@ public sealed unsafe class TextRenderer : IDisposable } } + // 2. Untextured rects — widget fills on top of the chrome. + if (_rectVerts > 0) + { + _shader.SetInt("uUseTexture", 0); + UploadBuffer(_rectBuf); + _gl.DrawArrays(PrimitiveType.Triangles, 0, (uint)_rectVerts); + } + + // 3. Textured text glyphs on top. + if (_textVerts > 0 && font is not null) + { + _shader.SetInt("uUseTexture", 1); + _gl.ActiveTexture(TextureUnit.Texture0); + _gl.BindTexture(TextureTarget.Texture2D, font.TextureId); + _shader.SetInt("uTex", 0); + UploadBuffer(_textBuf); + _gl.DrawArrays(PrimitiveType.Triangles, 0, (uint)_textVerts); + } + // Restore GL state. _gl.DepthMask(true); if (!wasBlend) _gl.Disable(EnableCap.Blend);