@babylonjs/lite-gl 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -34
- package/apply-states.d.ts +1 -0
- package/apply-states.js +30 -0
- package/apply-states.js.map +1 -0
- package/blend.d.ts +123 -0
- package/blend.js +194 -0
- package/blend.js.map +1 -0
- package/context.d.ts +130 -0
- package/context.js +354 -0
- package/context.js.map +1 -0
- package/depth-stencil.d.ts +155 -231
- package/depth-stencil.js +399 -262
- package/depth-stencil.js.map +1 -1
- package/dynamic-texture.d.ts +59 -149
- package/dynamic-texture.js +123 -69
- package/dynamic-texture.js.map +1 -1
- package/effect-renderer.d.ts +65 -0
- package/effect-renderer.js +132 -0
- package/effect-renderer.js.map +1 -0
- package/effect.d.ts +142 -0
- package/effect.js +465 -0
- package/effect.js.map +1 -0
- package/html-texture.d.ts +44 -143
- package/html-texture.js +87 -81
- package/html-texture.js.map +1 -1
- package/index.d.ts +23 -1482
- package/index.js +42 -263
- package/index.js.map +1 -1
- package/mesh.d.ts +210 -307
- package/mesh.js +436 -311
- package/mesh.js.map +1 -1
- package/package.json +5 -29
- package/render-loop.d.ts +8 -0
- package/render-loop.js +62 -0
- package/render-loop.js.map +1 -0
- package/render-target.d.ts +233 -290
- package/render-target.js +534 -335
- package/render-target.js.map +1 -1
- package/scissor.d.ts +30 -72
- package/scissor.js +47 -33
- package/scissor.js.map +1 -1
- package/shader.d.ts +22 -0
- package/shader.js +65 -0
- package/shader.js.map +1 -0
- package/sprites.d.ts +182 -263
- package/sprites.js +426 -10
- package/sprites.js.map +1 -1
- package/state.d.ts +126 -0
- package/state.js +153 -0
- package/state.js.map +1 -0
- package/texture.d.ts +142 -0
- package/texture.js +433 -0
- package/texture.js.map +1 -0
- package/effect-BxxwfB_O.js +0 -737
- package/effect-BxxwfB_O.js.map +0 -1
- package/sprites--1oyVtJ3.js +0 -437
- package/sprites--1oyVtJ3.js.map +0 -1
- package/state--j_ncWIi.js +0 -155
- package/state--j_ncWIi.js.map +0 -1
- package/texture-DaMd1gGm.js +0 -329
- package/texture-DaMd1gGm.js.map +0 -1
package/sprites.js
CHANGED
|
@@ -1,10 +1,426 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Sprite / instanced-quad renderer.
|
|
3
|
+
*
|
|
4
|
+
* Part of the public API via the `@babylonjs/lite-gl` barrel. The package is
|
|
5
|
+
* `sideEffects: false`, so consumers that don't render sprites tree-shake it out.
|
|
6
|
+
*
|
|
7
|
+
* This is the lite-gl equivalent of Babylon's `SpriteRenderer` + `ThinSprite`
|
|
8
|
+
* (`Sprites/spriteRenderer.js`, `Sprites/thinSprite.js`). The vertex layout,
|
|
9
|
+
* per-cell UV math and corner/rotation transform are copied verbatim from the
|
|
10
|
+
* non-instanced path of Babylon's `SpriteRenderer` so a future NeonBrush port
|
|
11
|
+
* renders identically. The shaders are the GLSL ES 3.00 translation of
|
|
12
|
+
* Babylon's `Shaders/sprites.vertex.js` / `sprites.fragment.js`, with the
|
|
13
|
+
* fog / log-depth / pixel-perfect / alpha-test branches removed (lite-gl has
|
|
14
|
+
* no depth attachment by default — see notes on `disableDepthWrite` below).
|
|
15
|
+
*/
|
|
16
|
+
import { offContextRestored, onContextRestored } from "./context.js";
|
|
17
|
+
import { createEffect, disposeEffect, isEffectReady, setEffectTexture, useEffect } from "./effect.js";
|
|
18
|
+
import { GLBlendMode, setBlendMode } from "./blend.js";
|
|
19
|
+
import { applyGLStates } from "./apply-states.js";
|
|
20
|
+
/* ───────────────────────────── shaders (GLSL ES 3.00) ───────────────────── */
|
|
21
|
+
/** Vertex shader — GLSL ES 3.00 translation of Babylon's `spritesVertexShader`
|
|
22
|
+
* core path. Attribute locations 0..5 match `createSpriteRenderer`'s
|
|
23
|
+
* `attributeNames` order so the renderer's VAO feeds every program correctly. */
|
|
24
|
+
const SPRITE_VERTEX_SOURCE = `#version 300 es
|
|
25
|
+
precision highp float;
|
|
26
|
+
layout(location = 0) in vec4 position;
|
|
27
|
+
layout(location = 1) in vec2 options;
|
|
28
|
+
layout(location = 2) in vec2 offsets;
|
|
29
|
+
layout(location = 3) in vec2 inverts;
|
|
30
|
+
layout(location = 4) in vec4 cellInfo;
|
|
31
|
+
layout(location = 5) in vec4 color;
|
|
32
|
+
uniform mat4 view;
|
|
33
|
+
uniform mat4 projection;
|
|
34
|
+
out vec2 vUV;
|
|
35
|
+
out vec4 vColor;
|
|
36
|
+
void main(void) {
|
|
37
|
+
vec3 viewPos = (view * vec4(position.xyz, 1.0)).xyz;
|
|
38
|
+
float angle = position.w;
|
|
39
|
+
vec2 size = vec2(options.x, options.y);
|
|
40
|
+
vec2 offset = offsets.xy;
|
|
41
|
+
vec2 cornerPos = vec2(offset.x - 0.5, offset.y - 0.5) * size;
|
|
42
|
+
vec3 rotatedCorner;
|
|
43
|
+
rotatedCorner.x = cornerPos.x * cos(angle) - cornerPos.y * sin(angle);
|
|
44
|
+
rotatedCorner.y = cornerPos.x * sin(angle) + cornerPos.y * cos(angle);
|
|
45
|
+
rotatedCorner.z = 0.0;
|
|
46
|
+
viewPos += rotatedCorner;
|
|
47
|
+
gl_Position = projection * vec4(viewPos, 1.0);
|
|
48
|
+
vColor = color;
|
|
49
|
+
vec2 uvOffset = vec2(abs(offset.x - inverts.x), abs(1.0 - offset.y - inverts.y));
|
|
50
|
+
vec2 uvPlace = cellInfo.xy;
|
|
51
|
+
vec2 uvSize = cellInfo.zw;
|
|
52
|
+
vUV.x = uvPlace.x + uvSize.x * uvOffset.x;
|
|
53
|
+
vUV.y = uvPlace.y + uvSize.y * uvOffset.y;
|
|
54
|
+
}`;
|
|
55
|
+
/** Fragment shader — GLSL ES 3.00 translation of Babylon's `spritesPixelShader`
|
|
56
|
+
* color pass: `texture(diffuseSampler, vUV) * vColor`. The alpha-test/discard
|
|
57
|
+
* branch is dropped because lite-gl never runs the depth pre-pass. */
|
|
58
|
+
const SPRITE_FRAGMENT_SOURCE = `#version 300 es
|
|
59
|
+
precision highp float;
|
|
60
|
+
in vec2 vUV;
|
|
61
|
+
in vec4 vColor;
|
|
62
|
+
uniform sampler2D diffuseSampler;
|
|
63
|
+
out vec4 glFragColor;
|
|
64
|
+
void main(void) {
|
|
65
|
+
vec4 color = texture(diffuseSampler, vUV);
|
|
66
|
+
color *= vColor;
|
|
67
|
+
glFragColor = color;
|
|
68
|
+
}`;
|
|
69
|
+
/* ───────────────────────────── layout constants ─────────────────────────── */
|
|
70
|
+
/** Floats per vertex: position.xyz + angle (4), size (2), corner offset (2),
|
|
71
|
+
* inverts (2), cellInfo (4), color (4) = 18. Matches Babylon's non-instanced
|
|
72
|
+
* `_vertexBufferSize`. */
|
|
73
|
+
const FLOATS_PER_VERTEX = 18;
|
|
74
|
+
/** Four corner vertices per sprite quad (non-instanced, like Babylon). */
|
|
75
|
+
const VERTS_PER_SPRITE = 4;
|
|
76
|
+
/** Six indices per sprite (two triangles). */
|
|
77
|
+
const INDICES_PER_SPRITE = 6;
|
|
78
|
+
/** Bytes per float — `Float32Array.BYTES_PER_ELEMENT`. */
|
|
79
|
+
const BYTES_PER_FLOAT = 4;
|
|
80
|
+
/** Stride between consecutive vertices, in bytes. */
|
|
81
|
+
const VERTEX_STRIDE_BYTES = FLOATS_PER_VERTEX * BYTES_PER_FLOAT;
|
|
82
|
+
/** UV inset applied to each quad corner, matching Babylon's default
|
|
83
|
+
* `SpriteRenderer` epsilon (0.01) so cell sampling never bleeds neighbours. */
|
|
84
|
+
const SPRITE_EPSILON = 0.01;
|
|
85
|
+
/** Max sprites: 4 verts/sprite must keep every index within `Uint16` range
|
|
86
|
+
* (`capacity * 4 - 1 <= 65535`). */
|
|
87
|
+
const MAX_CAPACITY = 16384;
|
|
88
|
+
/** Per-corner U offset (pre-epsilon), one entry per quad vertex. Module-scoped
|
|
89
|
+
* literal — pure per bundler convention, allocated once (never per frame). */
|
|
90
|
+
const CORNER_OFFSET_X = [0, 1, 1, 0];
|
|
91
|
+
/** Per-corner V offset (pre-epsilon), one entry per quad vertex. */
|
|
92
|
+
const CORNER_OFFSET_Y = [0, 0, 1, 1];
|
|
93
|
+
/** Attribute names in location order — index `i` is bound to `location = i` by
|
|
94
|
+
* `createEffect`/`linkProgram`, matching the shader's `layout(location = i)`. */
|
|
95
|
+
const SPRITE_ATTRIBUTES = ["position", "options", "offsets", "inverts", "cellInfo", "color"];
|
|
96
|
+
/* ──────────────────────────────── public API ───────────────────────────── */
|
|
97
|
+
/**
|
|
98
|
+
* Create a sprite renderer with its own GPU buffers and compiled effect.
|
|
99
|
+
*
|
|
100
|
+
* Preallocates the CPU vertex scratch and the index buffer at `capacity`, so
|
|
101
|
+
* {@link renderSprites} performs no allocations. The sprite GPU buffers are
|
|
102
|
+
* rebuilt automatically on `webglcontextrestored` (the owned effect is rebuilt
|
|
103
|
+
* by the engine's context-restore protocol).
|
|
104
|
+
*
|
|
105
|
+
* @param engine - The engine to create GL resources on.
|
|
106
|
+
* @param options - See {@link GLSpriteRendererOptions}.
|
|
107
|
+
* @returns The new {@link GLSpriteRenderer}.
|
|
108
|
+
* @throws If `capacity` is not an integer in `[1, 16384]`, or if a provided
|
|
109
|
+
* `cellWidth`/`cellHeight` is not positive.
|
|
110
|
+
*/
|
|
111
|
+
export function createSpriteRenderer(engine, options) {
|
|
112
|
+
const capacity = options.capacity;
|
|
113
|
+
if (!Number.isInteger(capacity) || capacity < 1 || capacity > MAX_CAPACITY) {
|
|
114
|
+
throw new Error(`lite-gl: sprite renderer capacity must be an integer in [1, ${MAX_CAPACITY}], got ${capacity}`);
|
|
115
|
+
}
|
|
116
|
+
// cellWidth/cellHeight drive only the fixed-grid `cellIndex` path; manual-UV
|
|
117
|
+
// consumers (the lottie atlas) omit them. Default to 1; reject explicit ≤ 0.
|
|
118
|
+
const cellWidth = options.cellWidth ?? 1;
|
|
119
|
+
const cellHeight = options.cellHeight ?? 1;
|
|
120
|
+
if (!(cellWidth > 0) || !(cellHeight > 0)) {
|
|
121
|
+
throw new Error("lite-gl: sprite renderer cellWidth/cellHeight must be > 0");
|
|
122
|
+
}
|
|
123
|
+
const effect = createEffect(engine, {
|
|
124
|
+
name: "sprites",
|
|
125
|
+
vertexSource: SPRITE_VERTEX_SOURCE,
|
|
126
|
+
fragmentSource: SPRITE_FRAGMENT_SOURCE,
|
|
127
|
+
uniformNames: ["view", "projection"],
|
|
128
|
+
samplerNames: ["diffuseSampler"],
|
|
129
|
+
attributeNames: SPRITE_ATTRIBUTES,
|
|
130
|
+
});
|
|
131
|
+
// Build the static index buffer data once: [0,1,2, 0,2,3] per sprite.
|
|
132
|
+
const indices = new Uint16Array(capacity * INDICES_PER_SPRITE);
|
|
133
|
+
for (let i = 0; i < capacity; i++) {
|
|
134
|
+
const v = i * VERTS_PER_SPRITE;
|
|
135
|
+
const o = i * INDICES_PER_SPRITE;
|
|
136
|
+
indices[o] = v;
|
|
137
|
+
indices[o + 1] = v + 1;
|
|
138
|
+
indices[o + 2] = v + 2;
|
|
139
|
+
indices[o + 3] = v;
|
|
140
|
+
indices[o + 4] = v + 2;
|
|
141
|
+
indices[o + 5] = v + 3;
|
|
142
|
+
}
|
|
143
|
+
const renderer = {
|
|
144
|
+
texture: options.texture,
|
|
145
|
+
cellWidth,
|
|
146
|
+
cellHeight,
|
|
147
|
+
epsilon: options.epsilon ?? SPRITE_EPSILON,
|
|
148
|
+
blendMode: options.blendMode ?? GLBlendMode.ALPHA,
|
|
149
|
+
autoResetAlpha: options.autoResetAlpha ?? true,
|
|
150
|
+
disableDepthWrite: options.disableDepthWrite ?? false,
|
|
151
|
+
capacity,
|
|
152
|
+
_engine: engine,
|
|
153
|
+
_effect: effect,
|
|
154
|
+
_vao: null,
|
|
155
|
+
_vbo: null,
|
|
156
|
+
_ibo: null,
|
|
157
|
+
_vertexData: new Float32Array(capacity * VERTS_PER_SPRITE * FLOATS_PER_VERTEX),
|
|
158
|
+
_indices: indices,
|
|
159
|
+
_restore: () => { },
|
|
160
|
+
_disposed: false,
|
|
161
|
+
};
|
|
162
|
+
renderer._restore = () => {
|
|
163
|
+
buildSpriteBuffers(renderer);
|
|
164
|
+
};
|
|
165
|
+
onContextRestored(engine, renderer._restore);
|
|
166
|
+
buildSpriteBuffers(renderer);
|
|
167
|
+
return renderer;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Build the per-sprite vertex data and draw all visible sprites in one
|
|
171
|
+
* `drawElements` call. Performs no allocations — the vertex scratch is reused
|
|
172
|
+
* and uploaded with `bufferSubData`.
|
|
173
|
+
*
|
|
174
|
+
* No-op when the context is lost/disposed, the renderer is disposed, the
|
|
175
|
+
* texture is not ready, the effect is not ready, or there are no visible
|
|
176
|
+
* sprites. Sets the renderer's blend mode before drawing and resets to
|
|
177
|
+
* {@link GLBlendMode.DISABLE} afterwards (matching Babylon's
|
|
178
|
+
* `autoResetAlpha = true`), so a subsequent `drawEffect` is unaffected.
|
|
179
|
+
*
|
|
180
|
+
* @param renderer - The renderer to draw with.
|
|
181
|
+
* @param sprites - The sprites to draw (only `isVisible !== false` are drawn;
|
|
182
|
+
* excess beyond `capacity` is ignored, matching Babylon).
|
|
183
|
+
* @param deltaTime - Accepted for Babylon API parity; unused (lite-gl `GLSprite`
|
|
184
|
+
* holds no animation state, so `cellIndex` is consumer-driven).
|
|
185
|
+
* @param viewMatrix - Column-major 4x4 view matrix.
|
|
186
|
+
* @param projectionMatrix - Column-major 4x4 projection matrix.
|
|
187
|
+
*/
|
|
188
|
+
export function renderSprites(renderer, sprites, deltaTime, viewMatrix, projectionMatrix) {
|
|
189
|
+
const engine = renderer._engine;
|
|
190
|
+
if (engine._isLost || engine._disposed || renderer._disposed) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
// `deltaTime` is accepted for Babylon `SpriteRenderer.render` parity but
|
|
194
|
+
// unused: `GLSprite` carries no animation state, so `cellIndex` is driven
|
|
195
|
+
// entirely by the consumer. Referenced here to keep the parameter name in
|
|
196
|
+
// the public signature without tripping `noUnusedParameters`.
|
|
197
|
+
void deltaTime;
|
|
198
|
+
const tex = renderer.texture;
|
|
199
|
+
if (!tex.isReady || sprites.length === 0) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const effect = renderer._effect;
|
|
203
|
+
if (!isEffectReady(engine, effect)) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (renderer._vao === null || renderer._vbo === null) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
// ── Build vertex data (allocation-free) ──────────────────────────────────
|
|
210
|
+
const vd = renderer._vertexData;
|
|
211
|
+
const eps = renderer.epsilon;
|
|
212
|
+
const texW = tex.width;
|
|
213
|
+
const texH = tex.height;
|
|
214
|
+
const cellW = renderer.cellWidth;
|
|
215
|
+
const cellH = renderer.cellHeight;
|
|
216
|
+
const rowSize = texW / cellW; // cells per sheet row
|
|
217
|
+
const cellWidthN = cellW / texW;
|
|
218
|
+
const cellHeightN = cellH / texH;
|
|
219
|
+
const cap = renderer.capacity;
|
|
220
|
+
const count = sprites.length;
|
|
221
|
+
let visible = 0;
|
|
222
|
+
for (let i = 0; i < count && visible < cap; i++) {
|
|
223
|
+
const sprite = sprites[i];
|
|
224
|
+
if (sprite === undefined || sprite.isVisible === false) {
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
// UV rect — manual per-sprite rect (Babylon `ThinSprite._xOffset/_xSize`
|
|
228
|
+
// path, selected when `uSize` is set) or the fixed `cellIndex` grid.
|
|
229
|
+
// Both resolve to a normalized `(left, top, widthN, heightN)` rectangle,
|
|
230
|
+
// matching Babylon's `_appendSpriteVertex` vertex layout exactly.
|
|
231
|
+
let cellLeft;
|
|
232
|
+
let cellTop;
|
|
233
|
+
let cellWN;
|
|
234
|
+
let cellHN;
|
|
235
|
+
if (sprite.uSize !== undefined) {
|
|
236
|
+
cellLeft = sprite.uOffset ?? 0;
|
|
237
|
+
cellTop = sprite.vOffset ?? 0;
|
|
238
|
+
cellWN = sprite.uSize / texW;
|
|
239
|
+
cellHN = (sprite.vSize ?? 0) / texH;
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
const cellIndex = (sprite.cellIndex ?? 0) > 0 ? sprite.cellIndex : 0;
|
|
243
|
+
const row = (cellIndex / rowSize) >> 0;
|
|
244
|
+
cellLeft = ((cellIndex - row * rowSize) * cellW) / texW;
|
|
245
|
+
cellTop = (row * cellH) / texH;
|
|
246
|
+
cellWN = cellWidthN;
|
|
247
|
+
cellHN = cellHeightN;
|
|
248
|
+
}
|
|
249
|
+
const px = sprite.position.x;
|
|
250
|
+
const py = sprite.position.y;
|
|
251
|
+
const pz = sprite.position.z;
|
|
252
|
+
const angle = sprite.angle;
|
|
253
|
+
const w = sprite.width;
|
|
254
|
+
const h = sprite.height;
|
|
255
|
+
const invU = sprite.invertU === true ? 1 : 0;
|
|
256
|
+
const invV = sprite.invertV === true ? 1 : 0;
|
|
257
|
+
const color = sprite.color;
|
|
258
|
+
const cr = color !== undefined ? color.r : 1;
|
|
259
|
+
const cg = color !== undefined ? color.g : 1;
|
|
260
|
+
const cb = color !== undefined ? color.b : 1;
|
|
261
|
+
const ca = color !== undefined ? color.a : 1;
|
|
262
|
+
let off = visible * VERTS_PER_SPRITE * FLOATS_PER_VERTEX;
|
|
263
|
+
for (let c = 0; c < VERTS_PER_SPRITE; c++) {
|
|
264
|
+
const ox = CORNER_OFFSET_X[c] === 0 ? eps : 1 - eps;
|
|
265
|
+
const oy = CORNER_OFFSET_Y[c] === 0 ? eps : 1 - eps;
|
|
266
|
+
vd[off] = px;
|
|
267
|
+
vd[off + 1] = py;
|
|
268
|
+
vd[off + 2] = pz;
|
|
269
|
+
vd[off + 3] = angle;
|
|
270
|
+
vd[off + 4] = w;
|
|
271
|
+
vd[off + 5] = h;
|
|
272
|
+
vd[off + 6] = ox;
|
|
273
|
+
vd[off + 7] = oy;
|
|
274
|
+
vd[off + 8] = invU;
|
|
275
|
+
vd[off + 9] = invV;
|
|
276
|
+
vd[off + 10] = cellLeft;
|
|
277
|
+
vd[off + 11] = cellTop;
|
|
278
|
+
vd[off + 12] = cellWN;
|
|
279
|
+
vd[off + 13] = cellHN;
|
|
280
|
+
vd[off + 14] = cr;
|
|
281
|
+
vd[off + 15] = cg;
|
|
282
|
+
vd[off + 16] = cb;
|
|
283
|
+
vd[off + 17] = ca;
|
|
284
|
+
off += FLOATS_PER_VERTEX;
|
|
285
|
+
}
|
|
286
|
+
visible++;
|
|
287
|
+
}
|
|
288
|
+
if (visible === 0) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
// ── Upload + draw ────────────────────────────────────────────────────────
|
|
292
|
+
const gl = engine.gl;
|
|
293
|
+
const s = engine._state;
|
|
294
|
+
const vao = renderer._vao;
|
|
295
|
+
if (s.boundVao !== vao) {
|
|
296
|
+
gl.bindVertexArray(vao);
|
|
297
|
+
s.boundVao = vao;
|
|
298
|
+
// Binding the VAO restores its element-array binding (VAO state).
|
|
299
|
+
s.boundElementBuffer = renderer._ibo;
|
|
300
|
+
}
|
|
301
|
+
const vbo = renderer._vbo;
|
|
302
|
+
if (s.boundArrayBuffer !== vbo) {
|
|
303
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
304
|
+
s.boundArrayBuffer = vbo;
|
|
305
|
+
}
|
|
306
|
+
const floatCount = visible * VERTS_PER_SPRITE * FLOATS_PER_VERTEX;
|
|
307
|
+
gl.bufferSubData(gl.ARRAY_BUFFER, 0, vd, 0, floatCount);
|
|
308
|
+
useEffect(engine, effect);
|
|
309
|
+
const viewLoc = effect.uniformLocations["view"];
|
|
310
|
+
if (viewLoc !== null && viewLoc !== undefined) {
|
|
311
|
+
gl.uniformMatrix4fv(viewLoc, false, viewMatrix);
|
|
312
|
+
}
|
|
313
|
+
const projLoc = effect.uniformLocations["projection"];
|
|
314
|
+
if (projLoc !== null && projLoc !== undefined) {
|
|
315
|
+
gl.uniformMatrix4fv(projLoc, false, projectionMatrix);
|
|
316
|
+
}
|
|
317
|
+
setEffectTexture(engine, effect, "diffuseSampler", tex);
|
|
318
|
+
setBlendMode(engine, renderer.blendMode);
|
|
319
|
+
applyGLStates(engine);
|
|
320
|
+
gl.drawElements(gl.TRIANGLES, visible * INDICES_PER_SPRITE, gl.UNSIGNED_SHORT, 0);
|
|
321
|
+
// Auto-reset (Babylon `autoResetAlpha = true`): leave blend disabled so a
|
|
322
|
+
// subsequent fullscreen `drawEffect` renders with the same state as before.
|
|
323
|
+
// When `autoResetAlpha` is false (lottie), keep `renderer.blendMode` applied
|
|
324
|
+
// so a premultiplied-alpha mode persists across multiple atlas-page passes.
|
|
325
|
+
if (renderer.autoResetAlpha) {
|
|
326
|
+
setBlendMode(engine, GLBlendMode.DISABLE);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
/** Swap the sprite-sheet texture (≙ Babylon assigning `SpriteRenderer.texture`
|
|
330
|
+
* after an async load). The cell size is unchanged — adjust `cellWidth` /
|
|
331
|
+
* `cellHeight` on the renderer directly if the new sheet differs. No-op when
|
|
332
|
+
* the renderer is disposed. */
|
|
333
|
+
export function setSpriteRendererTexture(renderer, texture) {
|
|
334
|
+
if (renderer._disposed) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
renderer.texture = texture;
|
|
338
|
+
}
|
|
339
|
+
/** Release the renderer's VAO/VBO/IBO and the effect it owns, and unregister
|
|
340
|
+
* its context-restore handler. Idempotent. Does NOT dispose the texture — the
|
|
341
|
+
* consumer that supplied it owns its lifetime. */
|
|
342
|
+
export function disposeSpriteRenderer(renderer) {
|
|
343
|
+
if (renderer._disposed) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
renderer._disposed = true;
|
|
347
|
+
const engine = renderer._engine;
|
|
348
|
+
offContextRestored(engine, renderer._restore);
|
|
349
|
+
disposeEffect(engine, renderer._effect);
|
|
350
|
+
if (!engine._isLost && !engine._disposed) {
|
|
351
|
+
const gl = engine.gl;
|
|
352
|
+
const s = engine._state;
|
|
353
|
+
if (renderer._vao !== null) {
|
|
354
|
+
gl.deleteVertexArray(renderer._vao);
|
|
355
|
+
if (s.boundVao === renderer._vao) {
|
|
356
|
+
s.boundVao = null;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (renderer._vbo !== null) {
|
|
360
|
+
gl.deleteBuffer(renderer._vbo);
|
|
361
|
+
if (s.boundArrayBuffer === renderer._vbo) {
|
|
362
|
+
s.boundArrayBuffer = null;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (renderer._ibo !== null) {
|
|
366
|
+
gl.deleteBuffer(renderer._ibo);
|
|
367
|
+
if (s.boundElementBuffer === renderer._ibo) {
|
|
368
|
+
s.boundElementBuffer = null;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
renderer._vao = null;
|
|
373
|
+
renderer._vbo = null;
|
|
374
|
+
renderer._ibo = null;
|
|
375
|
+
}
|
|
376
|
+
/* ──────────────────────────── internal helpers ──────────────────────────── */
|
|
377
|
+
/** (Re)create the VAO + VBO + IBO and configure the six vertex attributes.
|
|
378
|
+
* Called from `createSpriteRenderer` and from the `webglcontextrestored`
|
|
379
|
+
* handler (the prior handles are dead per the WebGL spec — not deleted here).
|
|
380
|
+
* No-op when the context is lost/disposed. */
|
|
381
|
+
function buildSpriteBuffers(renderer) {
|
|
382
|
+
const engine = renderer._engine;
|
|
383
|
+
if (engine._isLost || engine._disposed) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const gl = engine.gl;
|
|
387
|
+
const s = engine._state;
|
|
388
|
+
const vao = gl.createVertexArray();
|
|
389
|
+
if (vao === null) {
|
|
390
|
+
throw new Error("lite-gl: gl.createVertexArray returned null (sprite VAO)");
|
|
391
|
+
}
|
|
392
|
+
renderer._vao = vao;
|
|
393
|
+
gl.bindVertexArray(vao);
|
|
394
|
+
s.boundVao = vao;
|
|
395
|
+
const vbo = gl.createBuffer();
|
|
396
|
+
if (vbo === null) {
|
|
397
|
+
throw new Error("lite-gl: gl.createBuffer returned null (sprite VBO)");
|
|
398
|
+
}
|
|
399
|
+
renderer._vbo = vbo;
|
|
400
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
401
|
+
s.boundArrayBuffer = vbo;
|
|
402
|
+
// Allocate the dynamic vertex storage at full capacity; filled per frame.
|
|
403
|
+
gl.bufferData(gl.ARRAY_BUFFER, renderer._vertexData.byteLength, gl.DYNAMIC_DRAW);
|
|
404
|
+
// Attribute pointers — locations match SPRITE_ATTRIBUTES / shader layout.
|
|
405
|
+
gl.enableVertexAttribArray(0);
|
|
406
|
+
gl.vertexAttribPointer(0, 4, gl.FLOAT, false, VERTEX_STRIDE_BYTES, 0);
|
|
407
|
+
gl.enableVertexAttribArray(1);
|
|
408
|
+
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, VERTEX_STRIDE_BYTES, 4 * BYTES_PER_FLOAT);
|
|
409
|
+
gl.enableVertexAttribArray(2);
|
|
410
|
+
gl.vertexAttribPointer(2, 2, gl.FLOAT, false, VERTEX_STRIDE_BYTES, 6 * BYTES_PER_FLOAT);
|
|
411
|
+
gl.enableVertexAttribArray(3);
|
|
412
|
+
gl.vertexAttribPointer(3, 2, gl.FLOAT, false, VERTEX_STRIDE_BYTES, 8 * BYTES_PER_FLOAT);
|
|
413
|
+
gl.enableVertexAttribArray(4);
|
|
414
|
+
gl.vertexAttribPointer(4, 4, gl.FLOAT, false, VERTEX_STRIDE_BYTES, 10 * BYTES_PER_FLOAT);
|
|
415
|
+
gl.enableVertexAttribArray(5);
|
|
416
|
+
gl.vertexAttribPointer(5, 4, gl.FLOAT, false, VERTEX_STRIDE_BYTES, 14 * BYTES_PER_FLOAT);
|
|
417
|
+
const ibo = gl.createBuffer();
|
|
418
|
+
if (ibo === null) {
|
|
419
|
+
throw new Error("lite-gl: gl.createBuffer returned null (sprite IBO)");
|
|
420
|
+
}
|
|
421
|
+
renderer._ibo = ibo;
|
|
422
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
423
|
+
s.boundElementBuffer = ibo;
|
|
424
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, renderer._indices, gl.STATIC_DRAW);
|
|
425
|
+
}
|
|
426
|
+
//# sourceMappingURL=sprites.js.map
|
package/sprites.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sprites.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
|
|
1
|
+
{"version":3,"file":"sprites.js","sourceRoot":"","sources":["../src/sprites.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Sprite / instanced-quad renderer.\n *\n * Part of the public API via the `@babylonjs/lite-gl` barrel. The package is\n * `sideEffects: false`, so consumers that don't render sprites tree-shake it out.\n *\n * This is the lite-gl equivalent of Babylon's `SpriteRenderer` + `ThinSprite`\n * (`Sprites/spriteRenderer.js`, `Sprites/thinSprite.js`). The vertex layout,\n * per-cell UV math and corner/rotation transform are copied verbatim from the\n * non-instanced path of Babylon's `SpriteRenderer` so a future NeonBrush port\n * renders identically. The shaders are the GLSL ES 3.00 translation of\n * Babylon's `Shaders/sprites.vertex.js` / `sprites.fragment.js`, with the\n * fog / log-depth / pixel-perfect / alpha-test branches removed (lite-gl has\n * no depth attachment by default — see notes on `disableDepthWrite` below).\n */\nimport { offContextRestored, onContextRestored, type GLEngineContext } from \"./context.js\";\nimport { createEffect, disposeEffect, type GLEffect, isEffectReady, setEffectTexture, useEffect } from \"./effect.js\";\nimport { GLBlendMode, setBlendMode } from \"./blend.js\";\nimport { applyGLStates } from \"./apply-states.js\";\nimport { type GLTexture } from \"./texture.js\";\n\n/* ───────────────────────────── shaders (GLSL ES 3.00) ───────────────────── */\n\n/** Vertex shader — GLSL ES 3.00 translation of Babylon's `spritesVertexShader`\n * core path. Attribute locations 0..5 match `createSpriteRenderer`'s\n * `attributeNames` order so the renderer's VAO feeds every program correctly. */\nconst SPRITE_VERTEX_SOURCE = `#version 300 es\nprecision highp float;\nlayout(location = 0) in vec4 position;\nlayout(location = 1) in vec2 options;\nlayout(location = 2) in vec2 offsets;\nlayout(location = 3) in vec2 inverts;\nlayout(location = 4) in vec4 cellInfo;\nlayout(location = 5) in vec4 color;\nuniform mat4 view;\nuniform mat4 projection;\nout vec2 vUV;\nout vec4 vColor;\nvoid main(void) {\n vec3 viewPos = (view * vec4(position.xyz, 1.0)).xyz;\n float angle = position.w;\n vec2 size = vec2(options.x, options.y);\n vec2 offset = offsets.xy;\n vec2 cornerPos = vec2(offset.x - 0.5, offset.y - 0.5) * size;\n vec3 rotatedCorner;\n rotatedCorner.x = cornerPos.x * cos(angle) - cornerPos.y * sin(angle);\n rotatedCorner.y = cornerPos.x * sin(angle) + cornerPos.y * cos(angle);\n rotatedCorner.z = 0.0;\n viewPos += rotatedCorner;\n gl_Position = projection * vec4(viewPos, 1.0);\n vColor = color;\n vec2 uvOffset = vec2(abs(offset.x - inverts.x), abs(1.0 - offset.y - inverts.y));\n vec2 uvPlace = cellInfo.xy;\n vec2 uvSize = cellInfo.zw;\n vUV.x = uvPlace.x + uvSize.x * uvOffset.x;\n vUV.y = uvPlace.y + uvSize.y * uvOffset.y;\n}`;\n\n/** Fragment shader — GLSL ES 3.00 translation of Babylon's `spritesPixelShader`\n * color pass: `texture(diffuseSampler, vUV) * vColor`. The alpha-test/discard\n * branch is dropped because lite-gl never runs the depth pre-pass. */\nconst SPRITE_FRAGMENT_SOURCE = `#version 300 es\nprecision highp float;\nin vec2 vUV;\nin vec4 vColor;\nuniform sampler2D diffuseSampler;\nout vec4 glFragColor;\nvoid main(void) {\n vec4 color = texture(diffuseSampler, vUV);\n color *= vColor;\n glFragColor = color;\n}`;\n\n/* ───────────────────────────── layout constants ─────────────────────────── */\n\n/** Floats per vertex: position.xyz + angle (4), size (2), corner offset (2),\n * inverts (2), cellInfo (4), color (4) = 18. Matches Babylon's non-instanced\n * `_vertexBufferSize`. */\nconst FLOATS_PER_VERTEX = 18;\n/** Four corner vertices per sprite quad (non-instanced, like Babylon). */\nconst VERTS_PER_SPRITE = 4;\n/** Six indices per sprite (two triangles). */\nconst INDICES_PER_SPRITE = 6;\n/** Bytes per float — `Float32Array.BYTES_PER_ELEMENT`. */\nconst BYTES_PER_FLOAT = 4;\n/** Stride between consecutive vertices, in bytes. */\nconst VERTEX_STRIDE_BYTES = FLOATS_PER_VERTEX * BYTES_PER_FLOAT;\n/** UV inset applied to each quad corner, matching Babylon's default\n * `SpriteRenderer` epsilon (0.01) so cell sampling never bleeds neighbours. */\nconst SPRITE_EPSILON = 0.01;\n/** Max sprites: 4 verts/sprite must keep every index within `Uint16` range\n * (`capacity * 4 - 1 <= 65535`). */\nconst MAX_CAPACITY = 16384;\n\n/** Per-corner U offset (pre-epsilon), one entry per quad vertex. Module-scoped\n * literal — pure per bundler convention, allocated once (never per frame). */\nconst CORNER_OFFSET_X = [0, 1, 1, 0];\n/** Per-corner V offset (pre-epsilon), one entry per quad vertex. */\nconst CORNER_OFFSET_Y = [0, 0, 1, 1];\n\n/** Attribute names in location order — index `i` is bound to `location = i` by\n * `createEffect`/`linkProgram`, matching the shader's `layout(location = i)`. */\nconst SPRITE_ATTRIBUTES = [\"position\", \"options\", \"offsets\", \"inverts\", \"cellInfo\", \"color\"] as const;\n\n/* ─────────────────────────────── public types ──────────────────────────── */\n\n/** An RGBA color with each channel in `[0, 1]`, used for per-sprite tint. */\nexport interface GLSpriteColor {\n /** Red, 0..1. */\n r: number;\n /** Green, 0..1. */\n g: number;\n /** Blue, 0..1. */\n b: number;\n /** Alpha, 0..1. */\n a: number;\n}\n\n/** A single sprite — a plain data object mirroring the fields of Babylon's\n * `ThinSprite` that the renderer reads. No animation state: `cellIndex` is set\n * directly by the consumer (lite-gl does not port `ThinSprite.playAnimation`). */\nexport interface GLSprite {\n /** World-space position of the sprite center. */\n position: { x: number; y: number; z: number };\n /** Width in world units. */\n width: number;\n /** Height in world units. */\n height: number;\n /** Rotation angle, in radians. */\n angle: number;\n /** Sprite-sheet cell index (0-based, row-major). Out-of-range / negative\n * values are clamped to 0, matching Babylon's `if (!cellIndex) = 0`. Ignored\n * when a manual UV rect (`uSize`) is set. Optional — defaults to `0`. */\n cellIndex?: number;\n /** Optional tint; defaults to opaque white `{ r: 1, g: 1, b: 1, a: 1 }`. */\n color?: GLSpriteColor;\n /** Flip the cell horizontally. Defaults to `false`. */\n invertU?: boolean;\n /** Flip the cell vertically. Defaults to `false`. */\n invertV?: boolean;\n /** Manual UV rect — normalized left (U) origin in `[0, 1]`, mirroring\n * Babylon's `ThinSprite._xOffset`. Set together with {@link GLSprite.uSize}\n * to address an arbitrary sub-rectangle of the sheet instead of the fixed\n * `cellIndex` grid (used by the lottie atlas, whose cells vary in size). */\n uOffset?: number;\n /** Manual UV rect — normalized top (V) origin in `[0, 1]` (≙ Babylon\n * `ThinSprite._yOffset`). See {@link GLSprite.uSize}. */\n vOffset?: number;\n /** Manual UV rect — cell width in **texels** (≙ Babylon `ThinSprite._xSize`;\n * divided by the texture width when building vertices). Presence of `uSize`\n * switches the sprite into manual-UV mode (the `cellIndex` grid is ignored).\n * `0` samples a single column — the \"solid color\" trick. */\n uSize?: number;\n /** Manual UV rect — cell height in **texels** (≙ Babylon `ThinSprite._ySize`).\n * See {@link GLSprite.uSize}. Defaults to `0` when `uSize` is set but `vSize`\n * is omitted. */\n vSize?: number;\n /** When `false`, the sprite is skipped. Defaults to `true`. */\n isVisible?: boolean;\n}\n\n/** Options for {@link createSpriteRenderer}. */\nexport interface GLSpriteRendererOptions {\n /** Maximum number of sprites drawable in one `renderSprites` call. Must be\n * an integer in `[1, 16384]` (the `Uint16` index-buffer limit). */\n capacity: number;\n /** Cell width in texels within the sprite sheet, for the fixed-grid\n * `cellIndex` path. Optional — defaults to `1`; irrelevant when every\n * sprite supplies a manual UV rect (`uSize`), as the lottie atlas does. */\n cellWidth?: number;\n /** Cell height in texels within the sprite sheet. Optional — defaults to\n * `1`. See {@link GLSpriteRendererOptions.cellWidth}. */\n cellHeight?: number;\n /** Per-corner UV/position inset applied to each quad vertex, in the `[0, 0.5)`\n * range — the `epsilon` constructor argument of Babylon's `SpriteRenderer`.\n * It both insets cell UV sampling (so a cell never bleeds its neighbours) and\n * shrinks the quad by `epsilon * size` per side. Defaults to `0.01` (Babylon's\n * `SpriteRenderer` default). Pass `0` to disable insetting — the lottie atlas\n * does this (it relies on edge-extruded cells + center sampling instead, so a\n * non-zero inset would shrink every sprite by ~`0.01·size` per edge). */\n epsilon?: number;\n /** The sprite-sheet texture. May be swapped later via\n * {@link setSpriteRendererTexture}. */\n texture: GLTexture;\n /** Blend mode for the draw. Defaults to {@link GLBlendMode.ALPHA} (2),\n * matching Babylon's `SpriteRenderer.blendMode` default. */\n blendMode?: GLBlendMode;\n /** When `true` (default), `renderSprites` resets the blend mode to\n * {@link GLBlendMode.DISABLE} after drawing — mirroring Babylon's\n * `SpriteRenderer.autoResetAlpha = true`. Set `false` to leave the\n * renderer's `blendMode` applied after the draw (the lottie player relies\n * on this so its premultiplied alpha mode persists across passes). */\n autoResetAlpha?: boolean;\n /** Accepted for Babylon API parity. lite-gl's default engine has no depth\n * attachment (`depth: false`), so there is no depth pre-pass and this flag\n * has no observable effect; it is stored verbatim for a future depth-aware\n * consumer. Defaults to `false`. */\n disableDepthWrite?: boolean;\n}\n\n/**\n * A sprite renderer owning its own VBO/IBO/VAO and `GLEffect`. Created by\n * {@link createSpriteRenderer}; drive it with {@link renderSprites} and release\n * it with {@link disposeSpriteRenderer}.\n */\nexport interface GLSpriteRenderer {\n /** The sprite-sheet texture sampled by the shader. Swap via\n * {@link setSpriteRendererTexture}. */\n texture: GLTexture;\n /** Cell width in texels (selects the sub-rectangle for `cellIndex`). */\n cellWidth: number;\n /** Cell height in texels. */\n cellHeight: number;\n /** Per-corner UV/position inset (Babylon `SpriteRenderer` `epsilon`). */\n epsilon: number;\n /** Active blend mode applied by `renderSprites` before drawing. */\n blendMode: GLBlendMode;\n /** When `true`, `renderSprites` resets blend to {@link GLBlendMode.DISABLE}\n * after drawing (Babylon `autoResetAlpha`). */\n autoResetAlpha: boolean;\n /** Babylon-parity flag (no effect without a depth attachment). */\n disableDepthWrite: boolean;\n /** Maximum sprites per draw, fixed at creation. */\n readonly capacity: number;\n /** @internal The engine the renderer was created for. */\n _engine: GLEngineContext;\n /** @internal The compiled sprite effect this renderer owns. */\n _effect: GLEffect;\n /** @internal Sprite VAO (attribute pointers + element binding). Null until\n * built and after disposal; rebuilt on `webglcontextrestored`. */\n _vao: WebGLVertexArrayObject | null;\n /** @internal Dynamic vertex buffer, sized for `capacity` at creation. */\n _vbo: WebGLBuffer | null;\n /** @internal Static index buffer (`capacity * 6` `Uint16` indices). */\n _ibo: WebGLBuffer | null;\n /** @internal Preallocated CPU-side vertex scratch — reused every frame\n * (`renderSprites` performs zero allocations). */\n _vertexData: Float32Array;\n /** @internal Preallocated index data, uploaded once. */\n _indices: Uint16Array;\n /** @internal Context-restored handler — rebuilds the GPU buffers. */\n _restore: () => void;\n /** @internal True once disposed; subsequent calls are no-ops. */\n _disposed: boolean;\n}\n\n/* ──────────────────────────────── public API ───────────────────────────── */\n\n/**\n * Create a sprite renderer with its own GPU buffers and compiled effect.\n *\n * Preallocates the CPU vertex scratch and the index buffer at `capacity`, so\n * {@link renderSprites} performs no allocations. The sprite GPU buffers are\n * rebuilt automatically on `webglcontextrestored` (the owned effect is rebuilt\n * by the engine's context-restore protocol).\n *\n * @param engine - The engine to create GL resources on.\n * @param options - See {@link GLSpriteRendererOptions}.\n * @returns The new {@link GLSpriteRenderer}.\n * @throws If `capacity` is not an integer in `[1, 16384]`, or if a provided\n * `cellWidth`/`cellHeight` is not positive.\n */\nexport function createSpriteRenderer(engine: GLEngineContext, options: GLSpriteRendererOptions): GLSpriteRenderer {\n const capacity = options.capacity;\n if (!Number.isInteger(capacity) || capacity < 1 || capacity > MAX_CAPACITY) {\n throw new Error(`lite-gl: sprite renderer capacity must be an integer in [1, ${MAX_CAPACITY}], got ${capacity}`);\n }\n // cellWidth/cellHeight drive only the fixed-grid `cellIndex` path; manual-UV\n // consumers (the lottie atlas) omit them. Default to 1; reject explicit ≤ 0.\n const cellWidth = options.cellWidth ?? 1;\n const cellHeight = options.cellHeight ?? 1;\n if (!(cellWidth > 0) || !(cellHeight > 0)) {\n throw new Error(\"lite-gl: sprite renderer cellWidth/cellHeight must be > 0\");\n }\n\n const effect = createEffect(engine, {\n name: \"sprites\",\n vertexSource: SPRITE_VERTEX_SOURCE,\n fragmentSource: SPRITE_FRAGMENT_SOURCE,\n uniformNames: [\"view\", \"projection\"],\n samplerNames: [\"diffuseSampler\"],\n attributeNames: SPRITE_ATTRIBUTES,\n });\n\n // Build the static index buffer data once: [0,1,2, 0,2,3] per sprite.\n const indices = new Uint16Array(capacity * INDICES_PER_SPRITE);\n for (let i = 0; i < capacity; i++) {\n const v = i * VERTS_PER_SPRITE;\n const o = i * INDICES_PER_SPRITE;\n indices[o] = v;\n indices[o + 1] = v + 1;\n indices[o + 2] = v + 2;\n indices[o + 3] = v;\n indices[o + 4] = v + 2;\n indices[o + 5] = v + 3;\n }\n\n const renderer: GLSpriteRenderer = {\n texture: options.texture,\n cellWidth,\n cellHeight,\n epsilon: options.epsilon ?? SPRITE_EPSILON,\n blendMode: options.blendMode ?? GLBlendMode.ALPHA,\n autoResetAlpha: options.autoResetAlpha ?? true,\n disableDepthWrite: options.disableDepthWrite ?? false,\n capacity,\n _engine: engine,\n _effect: effect,\n _vao: null,\n _vbo: null,\n _ibo: null,\n _vertexData: new Float32Array(capacity * VERTS_PER_SPRITE * FLOATS_PER_VERTEX),\n _indices: indices,\n _restore: () => {},\n _disposed: false,\n };\n\n renderer._restore = (): void => {\n buildSpriteBuffers(renderer);\n };\n onContextRestored(engine, renderer._restore);\n buildSpriteBuffers(renderer);\n return renderer;\n}\n\n/**\n * Build the per-sprite vertex data and draw all visible sprites in one\n * `drawElements` call. Performs no allocations — the vertex scratch is reused\n * and uploaded with `bufferSubData`.\n *\n * No-op when the context is lost/disposed, the renderer is disposed, the\n * texture is not ready, the effect is not ready, or there are no visible\n * sprites. Sets the renderer's blend mode before drawing and resets to\n * {@link GLBlendMode.DISABLE} afterwards (matching Babylon's\n * `autoResetAlpha = true`), so a subsequent `drawEffect` is unaffected.\n *\n * @param renderer - The renderer to draw with.\n * @param sprites - The sprites to draw (only `isVisible !== false` are drawn;\n * excess beyond `capacity` is ignored, matching Babylon).\n * @param deltaTime - Accepted for Babylon API parity; unused (lite-gl `GLSprite`\n * holds no animation state, so `cellIndex` is consumer-driven).\n * @param viewMatrix - Column-major 4x4 view matrix.\n * @param projectionMatrix - Column-major 4x4 projection matrix.\n */\nexport function renderSprites(\n renderer: GLSpriteRenderer,\n sprites: readonly GLSprite[],\n deltaTime: number,\n viewMatrix: Float32Array | number[],\n projectionMatrix: Float32Array | number[]\n): void {\n const engine = renderer._engine;\n if (engine._isLost || engine._disposed || renderer._disposed) {\n return;\n }\n // `deltaTime` is accepted for Babylon `SpriteRenderer.render` parity but\n // unused: `GLSprite` carries no animation state, so `cellIndex` is driven\n // entirely by the consumer. Referenced here to keep the parameter name in\n // the public signature without tripping `noUnusedParameters`.\n void deltaTime;\n const tex = renderer.texture;\n if (!tex.isReady || sprites.length === 0) {\n return;\n }\n const effect = renderer._effect;\n if (!isEffectReady(engine, effect)) {\n return;\n }\n if (renderer._vao === null || renderer._vbo === null) {\n return;\n }\n\n // ── Build vertex data (allocation-free) ──────────────────────────────────\n const vd = renderer._vertexData;\n const eps = renderer.epsilon;\n const texW = tex.width;\n const texH = tex.height;\n const cellW = renderer.cellWidth;\n const cellH = renderer.cellHeight;\n const rowSize = texW / cellW; // cells per sheet row\n const cellWidthN = cellW / texW;\n const cellHeightN = cellH / texH;\n const cap = renderer.capacity;\n const count = sprites.length;\n let visible = 0;\n for (let i = 0; i < count && visible < cap; i++) {\n const sprite = sprites[i];\n if (sprite === undefined || sprite.isVisible === false) {\n continue;\n }\n // UV rect — manual per-sprite rect (Babylon `ThinSprite._xOffset/_xSize`\n // path, selected when `uSize` is set) or the fixed `cellIndex` grid.\n // Both resolve to a normalized `(left, top, widthN, heightN)` rectangle,\n // matching Babylon's `_appendSpriteVertex` vertex layout exactly.\n let cellLeft: number;\n let cellTop: number;\n let cellWN: number;\n let cellHN: number;\n if (sprite.uSize !== undefined) {\n cellLeft = sprite.uOffset ?? 0;\n cellTop = sprite.vOffset ?? 0;\n cellWN = sprite.uSize / texW;\n cellHN = (sprite.vSize ?? 0) / texH;\n } else {\n const cellIndex = (sprite.cellIndex ?? 0) > 0 ? (sprite.cellIndex as number) : 0;\n const row = (cellIndex / rowSize) >> 0;\n cellLeft = ((cellIndex - row * rowSize) * cellW) / texW;\n cellTop = (row * cellH) / texH;\n cellWN = cellWidthN;\n cellHN = cellHeightN;\n }\n\n const px = sprite.position.x;\n const py = sprite.position.y;\n const pz = sprite.position.z;\n const angle = sprite.angle;\n const w = sprite.width;\n const h = sprite.height;\n const invU = sprite.invertU === true ? 1 : 0;\n const invV = sprite.invertV === true ? 1 : 0;\n const color = sprite.color;\n const cr = color !== undefined ? color.r : 1;\n const cg = color !== undefined ? color.g : 1;\n const cb = color !== undefined ? color.b : 1;\n const ca = color !== undefined ? color.a : 1;\n\n let off = visible * VERTS_PER_SPRITE * FLOATS_PER_VERTEX;\n for (let c = 0; c < VERTS_PER_SPRITE; c++) {\n const ox = CORNER_OFFSET_X[c] === 0 ? eps : 1 - eps;\n const oy = CORNER_OFFSET_Y[c] === 0 ? eps : 1 - eps;\n vd[off] = px;\n vd[off + 1] = py;\n vd[off + 2] = pz;\n vd[off + 3] = angle;\n vd[off + 4] = w;\n vd[off + 5] = h;\n vd[off + 6] = ox;\n vd[off + 7] = oy;\n vd[off + 8] = invU;\n vd[off + 9] = invV;\n vd[off + 10] = cellLeft;\n vd[off + 11] = cellTop;\n vd[off + 12] = cellWN;\n vd[off + 13] = cellHN;\n vd[off + 14] = cr;\n vd[off + 15] = cg;\n vd[off + 16] = cb;\n vd[off + 17] = ca;\n off += FLOATS_PER_VERTEX;\n }\n visible++;\n }\n if (visible === 0) {\n return;\n }\n\n // ── Upload + draw ────────────────────────────────────────────────────────\n const gl = engine.gl;\n const s = engine._state;\n const vao = renderer._vao;\n if (s.boundVao !== vao) {\n gl.bindVertexArray(vao);\n s.boundVao = vao;\n // Binding the VAO restores its element-array binding (VAO state).\n s.boundElementBuffer = renderer._ibo;\n }\n const vbo = renderer._vbo;\n if (s.boundArrayBuffer !== vbo) {\n gl.bindBuffer(gl.ARRAY_BUFFER, vbo);\n s.boundArrayBuffer = vbo;\n }\n const floatCount = visible * VERTS_PER_SPRITE * FLOATS_PER_VERTEX;\n gl.bufferSubData(gl.ARRAY_BUFFER, 0, vd, 0, floatCount);\n\n useEffect(engine, effect);\n const viewLoc = effect.uniformLocations[\"view\"];\n if (viewLoc !== null && viewLoc !== undefined) {\n gl.uniformMatrix4fv(viewLoc, false, viewMatrix);\n }\n const projLoc = effect.uniformLocations[\"projection\"];\n if (projLoc !== null && projLoc !== undefined) {\n gl.uniformMatrix4fv(projLoc, false, projectionMatrix);\n }\n setEffectTexture(engine, effect, \"diffuseSampler\", tex);\n\n setBlendMode(engine, renderer.blendMode);\n applyGLStates(engine);\n gl.drawElements(gl.TRIANGLES, visible * INDICES_PER_SPRITE, gl.UNSIGNED_SHORT, 0);\n // Auto-reset (Babylon `autoResetAlpha = true`): leave blend disabled so a\n // subsequent fullscreen `drawEffect` renders with the same state as before.\n // When `autoResetAlpha` is false (lottie), keep `renderer.blendMode` applied\n // so a premultiplied-alpha mode persists across multiple atlas-page passes.\n if (renderer.autoResetAlpha) {\n setBlendMode(engine, GLBlendMode.DISABLE);\n }\n}\n\n/** Swap the sprite-sheet texture (≙ Babylon assigning `SpriteRenderer.texture`\n * after an async load). The cell size is unchanged — adjust `cellWidth` /\n * `cellHeight` on the renderer directly if the new sheet differs. No-op when\n * the renderer is disposed. */\nexport function setSpriteRendererTexture(renderer: GLSpriteRenderer, texture: GLTexture): void {\n if (renderer._disposed) {\n return;\n }\n renderer.texture = texture;\n}\n\n/** Release the renderer's VAO/VBO/IBO and the effect it owns, and unregister\n * its context-restore handler. Idempotent. Does NOT dispose the texture — the\n * consumer that supplied it owns its lifetime. */\nexport function disposeSpriteRenderer(renderer: GLSpriteRenderer): void {\n if (renderer._disposed) {\n return;\n }\n renderer._disposed = true;\n const engine = renderer._engine;\n offContextRestored(engine, renderer._restore);\n disposeEffect(engine, renderer._effect);\n if (!engine._isLost && !engine._disposed) {\n const gl = engine.gl;\n const s = engine._state;\n if (renderer._vao !== null) {\n gl.deleteVertexArray(renderer._vao);\n if (s.boundVao === renderer._vao) {\n s.boundVao = null;\n }\n }\n if (renderer._vbo !== null) {\n gl.deleteBuffer(renderer._vbo);\n if (s.boundArrayBuffer === renderer._vbo) {\n s.boundArrayBuffer = null;\n }\n }\n if (renderer._ibo !== null) {\n gl.deleteBuffer(renderer._ibo);\n if (s.boundElementBuffer === renderer._ibo) {\n s.boundElementBuffer = null;\n }\n }\n }\n renderer._vao = null;\n renderer._vbo = null;\n renderer._ibo = null;\n}\n\n/* ──────────────────────────── internal helpers ──────────────────────────── */\n\n/** (Re)create the VAO + VBO + IBO and configure the six vertex attributes.\n * Called from `createSpriteRenderer` and from the `webglcontextrestored`\n * handler (the prior handles are dead per the WebGL spec — not deleted here).\n * No-op when the context is lost/disposed. */\nfunction buildSpriteBuffers(renderer: GLSpriteRenderer): void {\n const engine = renderer._engine;\n if (engine._isLost || engine._disposed) {\n return;\n }\n const gl = engine.gl;\n const s = engine._state;\n\n const vao = gl.createVertexArray();\n if (vao === null) {\n throw new Error(\"lite-gl: gl.createVertexArray returned null (sprite VAO)\");\n }\n renderer._vao = vao;\n gl.bindVertexArray(vao);\n s.boundVao = vao;\n\n const vbo = gl.createBuffer();\n if (vbo === null) {\n throw new Error(\"lite-gl: gl.createBuffer returned null (sprite VBO)\");\n }\n renderer._vbo = vbo;\n gl.bindBuffer(gl.ARRAY_BUFFER, vbo);\n s.boundArrayBuffer = vbo;\n // Allocate the dynamic vertex storage at full capacity; filled per frame.\n gl.bufferData(gl.ARRAY_BUFFER, renderer._vertexData.byteLength, gl.DYNAMIC_DRAW);\n\n // Attribute pointers — locations match SPRITE_ATTRIBUTES / shader layout.\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 4, gl.FLOAT, false, VERTEX_STRIDE_BYTES, 0);\n gl.enableVertexAttribArray(1);\n gl.vertexAttribPointer(1, 2, gl.FLOAT, false, VERTEX_STRIDE_BYTES, 4 * BYTES_PER_FLOAT);\n gl.enableVertexAttribArray(2);\n gl.vertexAttribPointer(2, 2, gl.FLOAT, false, VERTEX_STRIDE_BYTES, 6 * BYTES_PER_FLOAT);\n gl.enableVertexAttribArray(3);\n gl.vertexAttribPointer(3, 2, gl.FLOAT, false, VERTEX_STRIDE_BYTES, 8 * BYTES_PER_FLOAT);\n gl.enableVertexAttribArray(4);\n gl.vertexAttribPointer(4, 4, gl.FLOAT, false, VERTEX_STRIDE_BYTES, 10 * BYTES_PER_FLOAT);\n gl.enableVertexAttribArray(5);\n gl.vertexAttribPointer(5, 4, gl.FLOAT, false, VERTEX_STRIDE_BYTES, 14 * BYTES_PER_FLOAT);\n\n const ibo = gl.createBuffer();\n if (ibo === null) {\n throw new Error(\"lite-gl: gl.createBuffer returned null (sprite IBO)\");\n }\n renderer._ibo = ibo;\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);\n s.boundElementBuffer = ibo;\n gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, renderer._indices, gl.STATIC_DRAW);\n}\n"]}
|
package/state.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GL-state cache type. Owned by `GLEngineContext._state`.
|
|
3
|
+
*
|
|
4
|
+
* Two flavours of cached state coexist here:
|
|
5
|
+
*
|
|
6
|
+
* - **Eager bindings** (program / buffers / textures / VAO / framebuffer /
|
|
7
|
+
* viewport / scissor / unpack). Each binding setter issues its `gl.*` call
|
|
8
|
+
* immediately and updates the matching field in lock-step, eliding the call
|
|
9
|
+
* when the cache already matches.
|
|
10
|
+
* - **Deferred render-state** (blend / depth / cull / stencil / color-mask),
|
|
11
|
+
* stored in the {@link GLState.rs} index-array. These follow Babylon's
|
|
12
|
+
* `applyStates()` model: each setter records only the DESIRED slot
|
|
13
|
+
* (`rs[RS_X + RS_DESIRED]`) and sets `statesDirty`; the real `gl.*` calls are
|
|
14
|
+
* flushed by {@link applyGLStates} (apply-states.ts) immediately before each
|
|
15
|
+
* draw / clear, reconciling DESIRED → ACTUAL and writing the actual slots
|
|
16
|
+
* (`rs[RS_X]`) in lock-step. Both halves keep their `-1`/`0` unset sentinels.
|
|
17
|
+
*
|
|
18
|
+
* See `00-lite-gl.md` §4 for the full table of cached operations and the
|
|
19
|
+
* deferred-state flush sites.
|
|
20
|
+
*
|
|
21
|
+
* INVARIANTS:
|
|
22
|
+
* - The cache is the source of truth. If consumers poke `engine.gl.*` directly
|
|
23
|
+
* they will silently corrupt this state.
|
|
24
|
+
* - On `webglcontextlost` the whole `rs` array (both the actual and desired
|
|
25
|
+
* halves) is reset to its initial sentinels (handles are dead anyway;
|
|
26
|
+
* subsequent setters bail out on `engine._isLost`, and a post-restore setter
|
|
27
|
+
* re-marks `statesDirty`).
|
|
28
|
+
*/
|
|
29
|
+
export interface GLState {
|
|
30
|
+
currentProgram: WebGLProgram | null;
|
|
31
|
+
activeTextureUnit: number;
|
|
32
|
+
/** Per-unit binding; length === caps.maxTextureUnits. */
|
|
33
|
+
boundTextures: (WebGLTexture | null)[];
|
|
34
|
+
boundArrayBuffer: WebGLBuffer | null;
|
|
35
|
+
boundElementBuffer: WebGLBuffer | null;
|
|
36
|
+
boundVao: WebGLVertexArrayObject | null;
|
|
37
|
+
viewportX: number;
|
|
38
|
+
viewportY: number;
|
|
39
|
+
viewportW: number;
|
|
40
|
+
viewportH: number;
|
|
41
|
+
/**
|
|
42
|
+
* Currently-bound draw framebuffer, or `null` for the default (canvas)
|
|
43
|
+
* framebuffer. Owned by the render-target module's `bindRenderTarget`
|
|
44
|
+
* (binding `null` returns to the canvas). Reset to `null` on context-lost.
|
|
45
|
+
*/
|
|
46
|
+
boundFramebuffer: WebGLFramebuffer | null;
|
|
47
|
+
/**
|
|
48
|
+
* Deferred render-state (blend / depth / cull / stencil / color-mask) packed
|
|
49
|
+
* into ONE flat `Float64Array(46)`. Slots `0..20` (indexed by the `RS_*`
|
|
50
|
+
* consts) are the ACTUAL applied GL state — what {@link applyGLStates} last
|
|
51
|
+
* wrote to the context; slots `21..41` (`rs[RS_X + RS_DESIRED]`) are the
|
|
52
|
+
* DESIRED twin the setters record. The setters write ONLY the desired half
|
|
53
|
+
* (never `gl.*`, never the actual half) and raise `statesDirty`;
|
|
54
|
+
* `applyGLStates` reconciles each desired → its actual twin right before a
|
|
55
|
+
* draw / clear, issuing only the GL calls that changed and updating the
|
|
56
|
+
* actual half in lock-step. Both preset and arbitrary blend paths feed the
|
|
57
|
+
* same desired slots, so they can never desync.
|
|
58
|
+
*
|
|
59
|
+
* Sentinels (identical for both halves): `-1` for the tri-state enables
|
|
60
|
+
* (`RS_BLEND_ENABLED` / `RS_DEPTH_TEST` / `RS_DEPTH_MASK` / `RS_CULL_ENABLED`
|
|
61
|
+
* / `RS_STENCIL_TEST`) and the mask caches (`RS_STENCIL_MASK` /
|
|
62
|
+
* `RS_COLOR_MASK`); `0` for every func / equation / op / ref slot (no GL enum
|
|
63
|
+
* is `0`). An unset desired equals its unset actual and is never flushed; the
|
|
64
|
+
* `-1` blend/test sentinels guarantee the first applied state is never elided.
|
|
65
|
+
* The blend func/equation slots are only trusted while `RS_BLEND_ENABLED` is
|
|
66
|
+
* `1` — the disabled→enabled transition re-issues both (matching Babylon's
|
|
67
|
+
* `AlphaState`, which does not track them while blending is off).
|
|
68
|
+
*
|
|
69
|
+
* Float64 (not Int32): `RS_STENCIL_MASK` / `RS_STENCIL_FUNC_MASK` can be
|
|
70
|
+
* `0xFFFFFFFF`, which Int32 stores as `-1` — colliding with the `-1` unset
|
|
71
|
+
* sentinel. Reset on context-lost. */
|
|
72
|
+
rs: Float64Array;
|
|
73
|
+
/** `true` when at least one deferred-state setter ran since the last
|
|
74
|
+
* {@link applyGLStates}. Gates the flush so an unchanged frame issues no
|
|
75
|
+
* reconciliation work. */
|
|
76
|
+
statesDirty: boolean;
|
|
77
|
+
/** Scissor-test enable tri-state (`-1` unset, `0` off, `1` on). */
|
|
78
|
+
scissorEnabled: number;
|
|
79
|
+
scissorX: number;
|
|
80
|
+
scissorY: number;
|
|
81
|
+
scissorW: number;
|
|
82
|
+
scissorH: number;
|
|
83
|
+
/** Cached `gl.pixelStorei(UNPACK_ALIGNMENT)`, or `-1` when unset. */
|
|
84
|
+
unpackAlignment: number;
|
|
85
|
+
/** Cached `gl.pixelStorei(UNPACK_FLIP_Y_WEBGL)`, or `-1` when unset. */
|
|
86
|
+
unpackFlipY: number;
|
|
87
|
+
/** Cached `gl.pixelStorei(UNPACK_PREMULTIPLY_ALPHA_WEBGL)`, or `-1` unset. */
|
|
88
|
+
unpackPremultiplyAlpha: number;
|
|
89
|
+
/**
|
|
90
|
+
* Per-location vertex-attribute enable flags for the DEFAULT (null) VAO —
|
|
91
|
+
* the mesh / instancing path (mirrors Babylon's `_vertexAttribArraysEnabled`).
|
|
92
|
+
* Index is the attribute location. lite-gl's quad / sprite paths use their
|
|
93
|
+
* own VAOs and do not touch this. Cleared on context-lost.
|
|
94
|
+
*/
|
|
95
|
+
enabledAttribs: boolean[];
|
|
96
|
+
/**
|
|
97
|
+
* Attribute locations currently configured with a non-default vertex divisor
|
|
98
|
+
* (instanced attributes), mirroring Babylon's `_currentInstanceLocations`.
|
|
99
|
+
* `unbindInstanceAttributes` resets each back to divisor 0 and clears this.
|
|
100
|
+
*/
|
|
101
|
+
instanceLocations: number[];
|
|
102
|
+
/** Shared fullscreen quad — lazily created on first `applyEffectWrapper`. */
|
|
103
|
+
quadVbo: WebGLBuffer | null;
|
|
104
|
+
quadIbo: WebGLBuffer | null;
|
|
105
|
+
quadVao: WebGLVertexArrayObject | null;
|
|
106
|
+
}
|
|
107
|
+
/** Allocate a fresh, fully-null GLState sized for `maxTextureUnits`. */
|
|
108
|
+
export declare function createGLState(maxTextureUnits: number): GLState;
|
|
109
|
+
/** Reset only the cached "current GL state" — every binding (program / buffers /
|
|
110
|
+
* textures / VAO / framebuffer) and render-state (blend / depth / stencil /
|
|
111
|
+
* scissor / color-mask / viewport / unpack) field, including the whole `rs`
|
|
112
|
+
* deferred render-state array (BOTH the actual applied values and the DESIRED
|
|
113
|
+
* twins) plus `statesDirty` — to its unset sentinel, WITHOUT discarding owned
|
|
114
|
+
* GPU resources (the shared quad). After this, the next setter in each category
|
|
115
|
+
* is re-issued rather than elided.
|
|
116
|
+
*
|
|
117
|
+
* Used by `resetGLState` (context-lost) and by `wipeGLStateCache` (a host that
|
|
118
|
+
* shares the GL context calling in after mutating raw `gl.*` state). The shared
|
|
119
|
+
* quad's GL objects are still alive in the latter case, so they are preserved
|
|
120
|
+
* here to avoid leaking + needlessly rebuilding them every render scope. */
|
|
121
|
+
export declare function resetGLStateCache(state: GLState): void;
|
|
122
|
+
/** Zero the cache in-place. Used by the context-lost handler — GL handles are
|
|
123
|
+
* already dead per WebGL spec; we forget what we knew about them (including the
|
|
124
|
+
* shared quad, whose GL objects are gone and must be rebuilt) so the next
|
|
125
|
+
* bind/use after restore is NOT incorrectly elided. */
|
|
126
|
+
export declare function resetGLState(state: GLState): void;
|