docs: private void drawTriangle(ShaderBuffer out1, float x1, float y1, float z1, float w1,
                                ShaderBuffer out2, float x2, float y2, float z2, float w2,
                                ShaderBuffer out3, float x3, float y3, float z3, float w3,
                                ShaderImplementation fragmentShader, ShaderBuffer fragmentIn, ShaderBuffer fragmentOut) {
          // (28).(4) (in bits) fixed-point coordinates
          final int fy1 = Math.round(y1 * 16);
          final int fy2 = Math.round(y2 * 16);
          final int fy3 = Math.round(y3 * 16);
          final int fx1 = Math.round(x1 * 16);
          final int fx2 = Math.round(x2 * 16);
          final int fx3 = Math.round(x3 * 16);
          // Deltas
          final int dx12 = fx1 - fx2;
          final int dx23 = fx2 - fx3;
          final int dx31 = fx3 - fx1;
          final int dy12 = fy1 - fy2;
          final int dy23 = fy2 - fy3;
          final int dy31 = fy3 - fy1;
          // Fixed-point deltas
          final int fdx12 = dx12 << 4;
          final int fdx23 = dx23 << 4;
          final int fdx31 = dx31 << 4;
          final int fdy12 = dy12 << 4;
          final int fdy23 = dy23 << 4;
          final int fdy31 = dy31 << 4;
          // Block size, standard 8x8 (must be power of two), here 2^3
          final int block = 1 << 3;
          // Bounding rectangle, start in the corner of the 8x8 block
          final int minX = Math.min(fx1, Math.min(fx2, fx3)) + 0xf >> 4 & ~(block - 1);
          final int maxX = Math.max(fx1, Math.max(fx2, fx3)) + 0xf >> 4;
          final int minY = Math.min(fy1, Math.min(fy2, fy3)) + 0xf >> 4 & ~(block - 1);
          final int maxY = Math.max(fy1, Math.max(fy2, fy3)) + 0xf >> 4;
          // Determinant of deltas to compute the normalized barycentric coordinates for interpolation
          final float det = dx23 * dy12 - dy23 * dx12;
          // Barycentric coordinates
          int c1 = dy12 * fx1 - dx12 * fy1;
          int c2 = dy23 * fx2 - dx23 * fy2;
          int c3 = dy31 * fx3 - dx31 * fy3;
          // Correct for fill convention
          if (dy12 < 0 || dy12 == 0 && dx12 > 0) {
              c1++;
          }
          if (dy23 < 0 || dy23 == 0 && dx23 > 0) {
              c2++;
          }
          if (dy31 < 0 || dy31 == 0 && dx31 > 0) {
              c3++;
          }
          // Loop through blocks
          for (int by = minY; by < maxY; by += block) {
              for (int bx = minX; bx < maxX; bx += block) {
                  // Corners of block
                  final int bx0 = bx << 4;
                  final int bx1 = bx + block - 1 << 4;
                  final int by0 = by << 4;
                  final int by1 = by + block - 1 << 4;
                  // Evaluate half-space functions
                  final boolean a00 = c1 + dx12 * by0 - dy12 * bx0 <= 0;
                  final boolean a10 = c1 + dx12 * by0 - dy12 * bx1 <= 0;
                  final boolean a01 = c1 + dx12 * by1 - dy12 * bx0 <= 0;
                  final boolean a11 = c1 + dx12 * by1 - dy12 * bx1 <= 0;
                  final boolean b00 = c2 + dx23 * by0 - dy23 * bx0 <= 0;
                  final boolean b10 = c2 + dx23 * by0 - dy23 * bx1 <= 0;
                  final boolean b01 = c2 + dx23 * by1 - dy23 * bx0 <= 0;
                  final boolean b11 = c2 + dx23 * by1 - dy23 * bx1 <= 0;
                  final boolean c00 = c3 + dx31 * by0 - dy31 * bx0 <= 0;
                  final boolean c10 = c3 + dx31 * by0 - dy31 * bx1 <= 0;
                  final boolean c01 = c3 + dx31 * by1 - dy31 * bx0 <= 0;
                  final boolean c11 = c3 + dx31 * by1 - dy31 * bx1 <= 0;
                  // Skip the block when outside an edge
                  if (a00 && a10 && a01 && a11 || b00 && b10 && b01 && b11 || c00 && c10 && c01 && c11) {
                      continue;
                  }
                  // Compute the barycentric coordinates
                  int cy1 = c1 + dx12 * by0 - dy12 * bx0;
                  int cy2 = c2 + dx23 * by0 - dy23 * bx0;
                  int cy3 = c3 + dx31 * by0 - dy31 * bx0;
                  // Iterate the block
                  for (int y = by; y < by + block; y++) {
                      int cx1 = cy1;
                      int cx2 = cy2;
                      int cx3 = cy3;
                      for (int x = bx; x < bx + block; x++) {
                          // Only draw pixels inside the triangle
                          if (cx1 > 0 && cx2 > 0 && cx3 > 0) {
                              // Compute the normalized barycentric coordinates
                              final float t = cx1 / det;
                              final float r = cx2 / det;
                              final float s = 1 - t - r;
                              // Lerp the rest of the data using the barycentric coordinates
                              final float z = SoftwareUtil.baryLerp(z1, z2, z3, r, s, t);
                              final float w = SoftwareUtil.baryLerp(w1, w2, w3, r, s, t);
                              fragmentIn.clear();
                              fragmentIn.writeRaw(Float.floatToIntBits(x));
                              fragmentIn.writeRaw(Float.floatToIntBits(y));
                              fragmentIn.writeRaw(Float.floatToIntBits(z));
                              fragmentIn.writeRaw(Float.floatToIntBits(w));
                              out1.position(4);
                              out2.position(4);
                              out3.position(4);
                              SoftwareUtil.baryLerp(out1, out2, out3, r, s, t, 1, fragmentIn);
                              fragmentIn.flip();
                              // Shade and write the fragment
                              writeFragment(fragmentShader, fragmentIn, fragmentOut, x, y, z);
                          }
                          cx1 -= fdy12;
                          cx2 -= fdy23;
                          cx3 -= fdy31;
                      }
                      cy1 += fdx12;
                      cy2 += fdx23;
                      cy3 += fdx31;
                  }
              }
          }
      }