Skip to content

Commit 652256b

Browse files
committed
atlas: pixelStorei(UNPACK_FLIP_Y_WEBGL) before texImage2D — the missing line
Diffed our minified bundle against memepool's working one and read both shaders end-to-end. The math, the slot encoding, the vertex layout, the texture parameters, the network path — all identical. The one substantive difference: memepool calls pixelStorei(UNPACK_FLIP_Y_WEBGL, true) before each canvas-to-texture upload. We didn't. Without that flag, canvas pixel (x, 0) [the top row, where we drew the image] lands at texture UV y=0 [the bottom of the texture]. The shader's `spriteY = atlasSize - spriteY - pxSize` flip then samples the bottom half of the texture — which is empty — and texture2D returns transparent. The composite line `base.rgb = tex.rgb * tex.a + vColor.rgb * (1 - tex.a)` collapses to vColor with tex.a=0, so every textured square rendered as flat colour, indistinguishable from "no image loaded". Verified end-to-end via playwright + WebGL FBO readback: the canvas had the image bytes, the GPU texture had them at the same coords, but the shader's flipped UV was sampling the empty bottom half. With UNPACK_FLIP_Y_WEBGL=true, the upload pre-flips so the shader's flip lands on the right region. Toggling the flag back to false right after the upload to avoid leaking the state to anything else in the page that might do its own texImage2D.
1 parent 0c6c322 commit 652256b

1 file changed

Lines changed: 8 additions & 0 deletions

File tree

frontend/src/app/components/block-overview-graph/_ordpool/ordpool-inscription-atlas.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,15 @@ export class OrdpoolInscriptionAtlas {
175175
this.gl.activeTexture(this.gl.TEXTURE0 + unit);
176176
this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);
177177
if (this.dirtyTexture) {
178+
// HACK -- Ordpool: flip-Y on upload so canvas(x, 0) [top row] lands at
179+
// texture UV y=1 [top]. The shader's `spriteY = atlasSize - spriteY -
180+
// pxSize` flip then reads the slot region correctly. Without this, every
181+
// atlas-sample falls into the empty bottom half of the texture and the
182+
// composite produces vColor (flat colored square). Memepool sets the
183+
// same flag.
184+
this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, true);
178185
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, this.canvas);
186+
this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, false);
179187
this.dirtyTexture = false;
180188
}
181189
}

0 commit comments

Comments
 (0)