Comment/doc truth pass: purge painter-era and double-buffer-era staleness
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 20 Sep 2026 02:13:15 +0000 (05:13 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 20 Sep 2026 02:13:15 +0000 (05:13 +0300)
Code comments/javadoc now match the z-buffer, triple-buffered reality:
- RenderAggregator class javadoc (was painter's algorithm), ctor slot docs
- ViewPanel frameContexts/frameParity comments (was double-buffer/parity)
- RenderingContext depth comment (dropped dead -Daukio.zbuffer knob and
  'Null in classic painter mode' — depth is always allocated)
- TexturedTriangle/ShapeCollection/package-info: slot ranges 0..2,
  javadoc links retargeted off deleted painter span writers
- AGENTS.org: removed dead BSP-painter and Agentic-development doc links,
  added Depth buffer doc, LightmappedCompositeShape + TriangleMeshBlock
  to the class catalog, render-pipeline overview now describes the
  radix-sort + two-pass z-buffer flow
- TODO.org: dropped completed 'Add 3D mouse support' (SpaceMouse exists)

No behavior change.

AGENTS.org
TODO.org
src/main/java/eu/svjatoslav/aukio/e3d/gui/RenderingContext.java
src/main/java/eu/svjatoslav/aukio/e3d/gui/ViewPanel.java
src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/RenderAggregator.java
src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/ShapeCollection.java
src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/package-info.java
src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/shapes/AbstractCoordinateShape.java
src/main/java/eu/svjatoslav/aukio/e3d/renderer/raster/shapes/basic/texturedpolygon/TexturedTriangle.java

index 2dc0fb8..f383da2 100644 (file)
@@ -314,6 +314,8 @@ scene.addShape(clickableCube);
 | Class                    | File                               | Purpose               | Key Methods                                                                                     |
 |--------------------------+------------------------------------+-----------------------+-------------------------------------------------------------------------------------------------|
 | ~AbstractCompositeShape~ | ~base/AbstractCompositeShape.java~ | Group shapes, CSG ops | ~.addShape()~, ~.subtract()~, ~.union()~, ~.intersect()~, ~.setShadingEnabled()~, ~.setColor()~ |
+| ~LightmappedCompositeShape~ | ~composite/LightmappedCompositeShape.java~ | Composite that fan-triangulates and optionally carries GI lightmaps | ~.setLightmappingEnabled(true)~ |
+| ~TriangleMeshBlock~ | ~basic/texturedpolygon/TriangleMeshBlock.java~ | SoA fast path for large textured triangle meshes (flat double[] arrays, one tight transform loop) | build from mesh data |
 
 ** Text (~shapes/composite/textcanvas/~)
 
@@ -402,9 +404,10 @@ AbstractShape (base)
 
 #+begin_example
 ViewPanel.renderFrame()
-  1. ShapeCollection.transformShapes() — apply camera transform
-  2. ShapeCollection.sortShapes() — sort by Z (back-to-front)
-  3. ShapeCollection.paintShapes() — painter's algorithm
+  1. ShapeCollection.transformShapes() — apply camera transform, cull, queue
+  2. ShapeCollection.sortShapes() — radix sort by Z (back-to-front)
+  3. ShapeCollection.paintShapes() — tiled parallel paint, two-pass z-buffer
+     (opaque front-to-back with depth writes, then alpha back-to-front)
   4. BufferStrategy.show() — page flip to display
 #+end_example
 
@@ -566,9 +569,8 @@ rebuild the exact demo scene headlessly.
 | ~Documentation/Near plane clip/index.org~              | Near-plane polygon clipping (straddling geometry)                   |
 | ~Documentation/Global illumination/index.org~          | Progressive GI: lightmaps, bounces, convergence                     |
 | ~Documentation/Perspective correct textures/index.org~ | Texture mapping math                                                |
-| ~Documentation/Agentic development/index.org~          | Stub: headless-toolkit docs moved to ~Documentation/index.org~ :: Agentic development |
 | ~Documentation/Stereoscopic rendering/index.org~       | Side-by-side stereo: two passes, per-eye viewports, IPD             |
-| ~Documentation/BSP-tree painter's algorithm/index.org~ | BSP compile + rank traversal fixing average-Z sort                  |
+| ~Documentation/Depth buffer/index.org~                 | Two-pass z-buffer, zw, depth margin, Hi-Z pyramid, determinism      |
 | ~Documentation/SDF textures/index.org~                 | SDF text: glyph fields, coverage window, TextCanvas                 |
 
 Regenerate all HTML: ~Documentation/export-docs.sh~ (add ~--check~ for rendered
index 33129ba..1e51ee8 100644 (file)
--- a/TODO.org
+++ b/TODO.org
@@ -1,8 +1,3 @@
-* Add 3D mouse support
-:PROPERTIES:
-:CUSTOM_ID: add-3d-mouse-support
-:END:
-
 * Demos
 :PROPERTIES:
 :CUSTOM_ID: demos
index 22b90c2..627bc81 100644 (file)
@@ -416,12 +416,12 @@ public class RenderingContext {
         final DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
         pixels = dbi.getData();
 
-        // Z-buffer mode (-Daukio.zbuffer=true): one w-depth (biased 1/z)
-        // value per pixel, cleared per tile in the paint workers. Depth
-        // turns the queue order into a performance heuristic only;
-        // correctness comes from the per-pixel test. (The queue itself
-        // stays painter back-to-front — Z descending, see
-        // RenderAggregator.) Null in classic painter mode.
+        // Z-buffer: one w-depth (biased 1/z) value per pixel, cleared per
+        // tile in the paint workers. Depth turns the queue order into a
+        // performance heuristic only; correctness comes from the per-pixel
+        // test. (The queue itself stays painter back-to-front — Z
+        // descending, see RenderAggregator.) Always allocated: the
+        // z-buffer path is the only renderer.
         depth = new float[width * height];
 
         graphics = (Graphics2D) bufferedImage.getGraphics();
index 1b87b20..96bd4bf 100755 (executable)
@@ -155,14 +155,15 @@ public class ViewPanel extends Canvas {
     private RenderingContext renderingContext = null;
 
     /**
-     * Double-buffered frame contexts, indexed by frame parity. While frame N
-     * is still being painted from one buffer, frame N+1 already transforms
-     * into the other, so paint threads never idle waiting for the transform
-     * phase and transform threads never wait for the last tile.
+     * Triple-buffered frame contexts, indexed by pass counter modulo 3.
+     * While frame N is still being painted from one buffer, frame N+1
+     * already transforms into another, so paint threads never idle waiting
+     * for the transform phase and transform threads never wait for the
+     * last tile.
      */
     private final RenderingContext[] frameContexts = new RenderingContext[3];
 
-    /** Parity (0/1) of the frame currently being prepared. */
+    /** Slot index (0..2) of the frame context currently being prepared. */
     private int frameParity = 0;
 
     /**
index bb28b67..ad82495 100644 (file)
@@ -19,9 +19,13 @@ import java.util.concurrent.Future;
 /**
  * Collects transformed shapes during a render frame and paints them in depth-sorted order.
  *
- * <p>The {@code RenderAggregator} implements the painter's algorithm: shapes are sorted
- * from back to front (highest Z-depth first) and then painted sequentially. This ensures
- * that closer shapes correctly occlude those behind them.</p>
+ * <p>Shapes are sorted from back to front (highest Z-depth first). Under the
+ * (unconditional) z-buffer, occlusion correctness comes from the per-pixel
+ * depth test; the queue order is a performance and coherence heuristic:
+ * pass 1 paints opaque shapes front-to-back (queue reversed) so the depth
+ * test rejects hidden fragments before the texture fetch, pass 2 paints
+ * alpha shapes back-to-front without depth writes so translucent overlap
+ * stays painter-coherent.</p>
  *
  * <p>When two shapes have the same Z-depth, their unique {@link AbstractCoordinateShape#shapeId}
  * is used as a tiebreaker to guarantee deterministic rendering order.</p>
@@ -44,10 +48,10 @@ public class RenderAggregator {
     /**
      * Creates an aggregator bound to a projection buffer slot. Sorting and
      * tile binning read the shapes' screen state for this slot, so the
-     * double-buffered pipeline can fill one slot's aggregator while the
-     * other slot's aggregator is still being painted.
+     * triple-buffered pipeline can fill one slot's aggregator while the
+     * other slots' aggregators are still being painted.
      *
-     * @param slot the buffer slot (0 or 1) this aggregator serves
+     * @param slot the buffer slot (0..2) this aggregator serves
      */
     public RenderAggregator(final int slot) {
         this.slot = slot;
@@ -839,7 +843,7 @@ public class RenderAggregator {
 
     /**
      * Comparator that sorts shapes by Z-depth in descending order (farthest first)
-     * for the painter's algorithm. Uses shape ID as a tiebreaker.
+     * for the render queue. Uses shape ID as a tiebreaker.
      */
     static class ShapesZIndexComparator implements Comparator<AbstractCoordinateShape>, Serializable {
 
index bf99292..5856d6b 100755 (executable)
@@ -425,7 +425,7 @@ public class ShapeCollection {
     /**
      * Sorts the given buffer slot's queued shapes by Z-depth.
      *
-     * @param slot buffer slot to sort (0 or 1)
+     * @param slot buffer slot to sort (0..2)
      */
     public void sortShapes(final int slot) {
         aggregators[slot].sort();
@@ -464,9 +464,9 @@ public class ShapeCollection {
     /**
      * Slot-selecting variant of
      * {@link #binShapesForTiles(int, int, int, int, int, ExecutorService)}
-     * for the double-buffered pipeline.
+     * for the triple-buffered pipeline.
      *
-     * @param slot     buffer slot whose queue gets binned (0 or 1)
+     * @param slot     buffer slot whose queue gets binned (0..2)
      * @param tilesX   tile columns across the viewport
      * @param tilesY   tile rows down the viewport
      * @param originX  X origin of the tiled viewport (eye offset in stereo)
index a7e5fee..0d6a073 100755 (executable)
@@ -7,7 +7,7 @@
  *   <li><b>Wireframe rendering</b> - lines and wireframe shapes</li>
  *   <li><b>Solid polygon rendering</b> - filled polygons with flat shading</li>
  *   <li><b>Textured polygon rendering</b> - polygons with texture mapping and mipmap support</li>
- *   <li><b>Depth sorting</b> - back-to-front painter's algorithm using Z-index ordering</li>
+ *   <li><b>Depth sorting</b> - back-to-front Z-index ordering feeding the two-pass z-buffer paint</li>
  * </ul>
  *
  * <p>Key classes in this package:</p>
index 70e466b..94fafb0 100644 (file)
@@ -77,7 +77,7 @@ public abstract class AbstractCoordinateShape extends AbstractShape {
     /**
      * Average Z-depth of this shape in screen space after transformation,
      * per buffer slot. Used by the {@link RenderAggregator} to sort shapes
-     * back-to-front for correct painter's algorithm rendering.
+     * back-to-front (the queue order the two-pass z-buffer paint consumes).
      * Access via {@link #getZ(RenderingContext)} / {@link #getZ(int)}.
      */
     private double onScreenZ0;
index fb57245..7d46c34 100644 (file)
@@ -211,14 +211,14 @@ public class TexturedTriangle extends AbstractCoordinateShape {
     }
 
     /**
-     * Z-buffer variant of {@link #drawHorizontalLinePerspective}: the
-     * biased 1/z endpoint values ride the interpolators' zw channel, and
-     * every pixel is depth-tested BEFORE the texture fetch — rejected
-     * pixels cost one float compare instead of a texel read. Opaque
-     * texels (alpha 255) write depth; blended texels write color only,
-     * so translucency never occludes. Requires
-     * {@code renderBuffer.depth != null} and {@code setPointsZW} called
-     * on both interpolators.
+     * Z-buffer span writer: the biased 1/z endpoint values ride the
+     * interpolators' zw channel, and every pixel is depth-tested BEFORE
+     * the texture fetch — rejected pixels cost one float compare instead
+     * of a texel read. Opaque texels (alpha 255) write depth; blended
+     * texels write color only, so translucency never occludes.
+     * {@code renderBuffer.depth} is always allocated (the z-buffer path
+     * is the only renderer); requires {@code setPointsZW} called on both
+     * interpolators.
      */
     private void drawHorizontalLinePerspectiveZ(
             final PerspectiveBorderInterpolator line1,
@@ -315,10 +315,10 @@ public class TexturedTriangle extends AbstractCoordinateShape {
         // Alpha pass (depthPass 2): depth-test but never depth-write,
         // so cutout foliage cannot occlude later fragments
         final boolean writeDepth = renderBuffer.depthPass != 2;
-        // see drawHorizontalLine: null texture (unit tests) = clamp
+        // null texture (unit tests) = clamp
         final boolean wrap = texture != null && texture.wrap;
 
-        // Same adaptive-subdivision ladder as the painter variant
+        // Adaptive-subdivision perspective ladder (Quake-style stepping)
         final double ue1 = su1 / sw1;
         final double ue2 = su2 / sw2;
         final double ve1 = sv1 / sw1;
@@ -1087,7 +1087,7 @@ public class TexturedTriangle extends AbstractCoordinateShape {
 
     /**
      * SDF scanline with Quake-style subdivided perspective correction —
-     * same stepping structure as {@link #drawHorizontalLinePerspective},
+     * same stepping structure as {@link #drawHorizontalLinePerspectiveZ},
      * with the coverage fetch replaced by the distance-field evaluation.
      */
     private void drawHorizontalLinePerspectiveSdf(
@@ -1305,9 +1305,9 @@ public class TexturedTriangle extends AbstractCoordinateShape {
     }
 
     /**
-     * Z-buffer variant of {@link #drawHorizontalLine}: per-pixel depth
-     * test (biased 1/z, linear along the span) BEFORE the texture fetch.
-     * Opaque texels write depth; blended texels write color only.
+     * Z-buffer span writer: per-pixel depth test (biased 1/z, linear
+     * along the span) BEFORE the texture fetch. Opaque texels write
+     * depth; blended texels write color only.
      */
     private void drawHorizontalLineZ(final PolygonBorderInterpolator line1,
                                      final PolygonBorderInterpolator line2,