Six covers as one TRIANGLE_STRIP would be joined by triangles bridging each cover to the next. WebGL 2 always enables primitive restart with a fixed index: the largest value of the index type (65535 for Uint16Array) ends one strip and starts another, inside the same draw call. There is nothing to enable:
<canvas id="c" width="1240" height="200" style="width:620px;height:100px"></canvas>
<script src="webgl-helper.js"></script>
<script>
const gl = GLH.context('c'), wall = GLH.coverWall();
const { attributes, uniforms } = GLH.load(gl, `#version 300 es
in vec2 aPosition; in float aBook; uniform vec3 uColors[6]; flat out vec3 vColor;
void main() { vColor = uColors[int(aBook)]; gl_Position = vec4(aPosition, 0, 1); }`,
`#version 300 es
precision mediump float; flat in vec3 vColor; out vec4 c;
void main() { c = vec4(vColor, 1); }`);
uniforms.uColors(GLH.covers.flatMap(GLH.rgb));
[false, true].forEach((restart, pane) => { // corners in strip order: BL BR TL TR
const indices = new Uint16Array([0, 1, 2, 3, 4, 5].flatMap((i) =>
[i * 4, i * 4 + 1, i * 4 + 3, i * 4 + 2, ...(restart ? [65535] : [])]));
gl.bindVertexArray(GLH.vao(gl, attributes, wall.vertices,
[['aPosition', 2], ['aUV', 2], ['aBook', 1]], indices));
gl.viewport(pane * 620, 0, 620, 200);
gl.drawElements(gl.TRIANGLE_STRIP, indices.length, gl.UNSIGNED_SHORT, 0);
});
window.__done = true;
</script>
On the left, the strip bridges the gaps; on the right, 65535 cuts it. RASTERIZER_DISCARD stops primitives before rasterization, so only the vertex stage runs (Transform Feedback). It also discards clear(): with it enabled, a blue clear left a red canvas red.
<!doctype html>
<style>
body { margin: 0; font: 11px system-ui, sans-serif; background: #f7f4ee; color: #333; }
canvas { display: block; width: 100%; max-width: 600px; }
.names { display: flex; max-width: 600px; text-align: center; font-family: monospace; }
.names div { flex: 1; padding: 4px 2px; }
p { max-width: 600px; margin: 2px 0; font-family: monospace; }
</style>
<canvas id="c" width="1240" height="200"></canvas>
<div class="names"><div>one strip: covers bridged</div><div>..., 65535, ...: restarted per cover</div></div>
<p id="out"></p>
<script>
const gl = document.getElementById('c').getContext('webgl2');
gl.clearColor(0.93, 0.91, 0.87, 1); gl.clear(gl.COLOR_BUFFER_BIT);
const program = gl.createProgram();
for (const [type, src] of [[gl.VERTEX_SHADER, `#version 300 es
layout(location = 0) in vec2 aPosition; layout(location = 1) in float aBook; uniform vec3 uColors[6]; flat out vec3 vColor;
void main() { vColor = uColors[int(aBook)]; gl_Position = vec4(aPosition, 0, 1); }`], [gl.FRAGMENT_SHADER, `#version 300 es
precision mediump float; flat in vec3 vColor; out vec4 c; void main() { c = vec4(vColor, 1); }`]]) {
const s = gl.createShader(type); gl.shaderSource(s, src); gl.compileShader(s); gl.attachShader(program, s);
}
gl.linkProgram(program); gl.useProgram(program);
const covers = ['#1f5f8b', '#5b3f99', '#e09a10', '#3f7d3a', '#b5452f', '#2a9d8f'];
gl.uniform3fv(gl.getUniformLocation(program, 'uColors'), covers.flatMap((hex) => [1, 3, 5].map((k) => parseInt(hex.slice(k, k + 2), 16) / 255)));
const vertices = [];
covers.forEach((hex, i) => {
for (const [u, v] of [[0, 0], [1, 0], [1, 1], [0, 1]]) vertices.push(-0.94 + i * 0.32 + u * 0.26, -0.82 + v * 1.64, i);
});
[false, true].forEach((restart, pane) => { // corners in strip order: BL BR TL TR
const indices = new Uint16Array([0, 1, 2, 3, 4, 5].flatMap((i) => [i * 4, i * 4 + 1, i * 4 + 3, i * 4 + 2, ...(restart ? [65535] : [])]));
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 12, 0); gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(1, 1, gl.FLOAT, false, 12, 8); gl.enableVertexAttribArray(1);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
gl.viewport(pane * 620, 0, 620, 200);
gl.drawElements(gl.TRIANGLE_STRIP, indices.length, gl.UNSIGNED_SHORT, 0); // always on in WebGL 2: nothing to enable
});
// RASTERIZER_DISCARD stops primitives before rasterization, and clear() too.
const probe = new Uint8Array(4);
gl.enable(gl.RASTERIZER_DISCARD);
gl.clearColor(0, 0, 1, 1); gl.clear(gl.COLOR_BUFFER_BIT); // discarded: the canvas keeps its pixels
gl.disable(gl.RASTERIZER_DISCARD);
gl.readPixels(5, 5, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, probe);
document.getElementById('out').textContent = `blue clear() under RASTERIZER_DISCARD -> corner pixel still ${probe.slice(0, 3).join(', ')}`;
</script>