@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/depth-stencil.js
CHANGED
|
@@ -1,277 +1,414 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
import { applyGLStates } from "./apply-states.js";
|
|
2
|
+
import { RS_CLEAR_A, RS_CLEAR_B, RS_CLEAR_G, RS_CLEAR_R, RS_COLOR_MASK, RS_CULL_ENABLED, RS_CULL_FACE, RS_DEPTH_FUNC, RS_DEPTH_MASK, RS_DEPTH_TEST, RS_DESIRED, RS_STENCIL_FUNC_FUNC, RS_STENCIL_FUNC_MASK, RS_STENCIL_FUNC_REF, RS_STENCIL_MASK, RS_STENCIL_OP_FAIL, RS_STENCIL_OP_ZFAIL, RS_STENCIL_OP_ZPASS, RS_STENCIL_TEST, } from "./state.js";
|
|
3
|
+
// ── Clear bits (used by `clearEngine`).
|
|
4
|
+
/** GL clear bits. */
|
|
5
|
+
const COLOR_BUFFER_BIT = 0x4000;
|
|
6
|
+
const DEPTH_BUFFER_BIT = 0x0100;
|
|
7
|
+
const STENCIL_BUFFER_BIT = 0x0400;
|
|
8
|
+
// ── Test-enable enums for the per-category reconcilers below.
|
|
9
|
+
/** GL `gl.DEPTH_TEST`. */
|
|
10
|
+
const DEPTH_TEST = 0x0b71;
|
|
11
|
+
/** GL `gl.CULL_FACE`. */
|
|
12
|
+
const CULL_FACE = 0x0b44;
|
|
13
|
+
/** GL `gl.STENCIL_TEST`. */
|
|
14
|
+
const STENCIL_TEST = 0x0b90;
|
|
15
|
+
// ── Framebuffer / renderbuffer enums (used only by generateRenderTargetStencil).
|
|
16
|
+
// Module-local consts mirror render-target.ts's constant style. Because the
|
|
17
|
+
// render-target core no longer references the stencil/packed enums, they live
|
|
18
|
+
// here and tree-shake away for consumers that never opt into a stencil buffer.
|
|
19
|
+
/** GL `gl.FRAMEBUFFER`. */
|
|
20
|
+
const FRAMEBUFFER = 0x8d40;
|
|
21
|
+
/** GL `gl.RENDERBUFFER`. */
|
|
22
|
+
const RENDERBUFFER = 0x8d41;
|
|
23
|
+
/** GL `gl.DEPTH24_STENCIL8` — packed depth+stencil sized format. */
|
|
24
|
+
const DEPTH24_STENCIL8 = 0x88f0;
|
|
25
|
+
/** GL `gl.STENCIL_INDEX8` — stencil-only sized format. */
|
|
26
|
+
const STENCIL_INDEX8 = 0x8d48;
|
|
27
|
+
/** GL `gl.DEPTH_STENCIL_ATTACHMENT`. */
|
|
28
|
+
const DEPTH_STENCIL_ATTACHMENT = 0x821a;
|
|
29
|
+
/** GL `gl.STENCIL_ATTACHMENT`. */
|
|
30
|
+
const STENCIL_ATTACHMENT = 0x8d20;
|
|
31
|
+
/** GL `gl.DEPTH_ATTACHMENT` — where the render-target core attaches its depth-only
|
|
32
|
+
* renderbuffer (re-established when rolling back a failed stencil attach). */
|
|
33
|
+
const DEPTH_ATTACHMENT = 0x8d00;
|
|
34
|
+
/** GL `gl.FRAMEBUFFER_COMPLETE`. */
|
|
35
|
+
const FRAMEBUFFER_COMPLETE = 0x8cd5;
|
|
36
|
+
/**
|
|
37
|
+
* Buffer depth-buffer state (test enable, write mask, comparison function) into
|
|
38
|
+
* the DESIRED state — the lite-gl equivalent of mutating Babylon's
|
|
39
|
+
* `engine.depthCullingState.{depthTest,depthMask,depthFunc}`. Flushed to GL by
|
|
40
|
+
* `applyGLStates` before the next draw / clear; omitted fields are untouched.
|
|
41
|
+
*
|
|
42
|
+
* @param engine - The engine.
|
|
43
|
+
* @param state - The depth fields to change. Omitted fields are untouched.
|
|
44
|
+
*/
|
|
45
|
+
export function setDepthState(engine, state) {
|
|
46
|
+
if (engine._isLost || engine._disposed) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const s = engine._state;
|
|
50
|
+
if (state.test !== undefined) {
|
|
51
|
+
s.rs[RS_DEPTH_TEST + RS_DESIRED] = state.test ? 1 : 0;
|
|
52
|
+
}
|
|
53
|
+
if (state.write !== undefined) {
|
|
54
|
+
s.rs[RS_DEPTH_MASK + RS_DESIRED] = state.write ? 1 : 0;
|
|
55
|
+
}
|
|
56
|
+
if (state.func !== undefined) {
|
|
57
|
+
s.rs[RS_DEPTH_FUNC + RS_DESIRED] = state.func;
|
|
58
|
+
}
|
|
59
|
+
s._flushDepthCull = flushDepthCull;
|
|
60
|
+
s.statesDirty = true;
|
|
32
61
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Enable/disable face culling and (optionally) set the cull face — the lite-gl
|
|
64
|
+
* equivalent of `engine.depthCullingState.cull` + `cullFace`.
|
|
65
|
+
*
|
|
66
|
+
* @param engine - The engine.
|
|
67
|
+
* @param enabled - Enable (`true`) or disable (`false`) `gl.CULL_FACE`.
|
|
68
|
+
* @param face - Optional cull face (`gl.BACK` / `gl.FRONT` / `gl.FRONT_AND_BACK`).
|
|
69
|
+
*/
|
|
70
|
+
export function setCullState(engine, enabled, face) {
|
|
71
|
+
if (engine._isLost || engine._disposed) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const s = engine._state;
|
|
75
|
+
s.rs[RS_CULL_ENABLED + RS_DESIRED] = enabled ? 1 : 0;
|
|
76
|
+
if (face !== undefined) {
|
|
77
|
+
s.rs[RS_CULL_FACE + RS_DESIRED] = face;
|
|
78
|
+
}
|
|
79
|
+
s._flushDepthCull = flushDepthCull;
|
|
80
|
+
s.statesDirty = true;
|
|
44
81
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Buffer stencil state (test enable, write mask, comparison func triple, op
|
|
84
|
+
* triple) into the DESIRED state — the lite-gl equivalent of mutating Babylon's
|
|
85
|
+
* `engine.stencilState.*`. Flushed by `applyGLStates` before the next draw /
|
|
86
|
+
* clear; omitted fields are untouched (merge-from-desired).
|
|
87
|
+
*
|
|
88
|
+
* @param engine - The engine.
|
|
89
|
+
* @param state - The stencil fields to change. Omitted fields are untouched.
|
|
90
|
+
*/
|
|
91
|
+
export function setStencilState(engine, state) {
|
|
92
|
+
if (engine._isLost || engine._disposed) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const s = engine._state;
|
|
96
|
+
if (state.test !== undefined) {
|
|
97
|
+
s.rs[RS_STENCIL_TEST + RS_DESIRED] = state.test ? 1 : 0;
|
|
98
|
+
}
|
|
99
|
+
if (state.mask !== undefined) {
|
|
100
|
+
s.rs[RS_STENCIL_MASK + RS_DESIRED] = state.mask;
|
|
101
|
+
}
|
|
102
|
+
if (state.func !== undefined) {
|
|
103
|
+
s.rs[RS_STENCIL_FUNC_FUNC + RS_DESIRED] = state.func;
|
|
104
|
+
}
|
|
105
|
+
if (state.ref !== undefined) {
|
|
106
|
+
s.rs[RS_STENCIL_FUNC_REF + RS_DESIRED] = state.ref;
|
|
107
|
+
}
|
|
108
|
+
if (state.funcMask !== undefined) {
|
|
109
|
+
s.rs[RS_STENCIL_FUNC_MASK + RS_DESIRED] = state.funcMask;
|
|
110
|
+
}
|
|
111
|
+
if (state.opFail !== undefined) {
|
|
112
|
+
s.rs[RS_STENCIL_OP_FAIL + RS_DESIRED] = state.opFail;
|
|
113
|
+
}
|
|
114
|
+
if (state.opZFail !== undefined) {
|
|
115
|
+
s.rs[RS_STENCIL_OP_ZFAIL + RS_DESIRED] = state.opZFail;
|
|
116
|
+
}
|
|
117
|
+
if (state.opZPass !== undefined) {
|
|
118
|
+
s.rs[RS_STENCIL_OP_ZPASS + RS_DESIRED] = state.opZPass;
|
|
119
|
+
}
|
|
120
|
+
s._flushStencil = flushStencil;
|
|
121
|
+
s.statesDirty = true;
|
|
76
122
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Buffer the color write mask into the DESIRED state — the lite-gl equivalent of
|
|
125
|
+
* Babylon's `setColorWrite` (which passes the same flag to all four channels).
|
|
126
|
+
* Flushed to GL (`gl.colorMask`) by `applyGLStates` before the next draw /
|
|
127
|
+
* clear.
|
|
128
|
+
*
|
|
129
|
+
* @param engine - The engine.
|
|
130
|
+
* @param r - Write red.
|
|
131
|
+
* @param g - Write green.
|
|
132
|
+
* @param b - Write blue.
|
|
133
|
+
* @param a - Write alpha.
|
|
134
|
+
*/
|
|
135
|
+
export function setColorMask(engine, r, g, b, a) {
|
|
136
|
+
if (engine._isLost || engine._disposed) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const packed = (r ? 8 : 0) | (g ? 4 : 0) | (b ? 2 : 0) | (a ? 1 : 0);
|
|
140
|
+
const s = engine._state;
|
|
141
|
+
s.rs[RS_COLOR_MASK + RS_DESIRED] = packed;
|
|
142
|
+
s._flushColorMask = flushColorMask;
|
|
143
|
+
s.statesDirty = true;
|
|
86
144
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Clear the currently-bound framebuffer's color / depth / stencil buffers — the
|
|
147
|
+
* lite-gl equivalent of Babylon's `clear(color, backBuffer, depth, stencil)`.
|
|
148
|
+
* Depth/stencil clears respect the current write masks (set them first via
|
|
149
|
+
* {@link setDepthState} / {@link setStencilState}). No-op when nothing is
|
|
150
|
+
* requested or the context is lost/disposed.
|
|
151
|
+
*
|
|
152
|
+
* @param engine - The engine.
|
|
153
|
+
* @param options - Which buffers to clear (and the color value).
|
|
154
|
+
*/
|
|
155
|
+
export function clearEngine(engine, options) {
|
|
156
|
+
if (engine._isLost || engine._disposed) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const gl = engine.gl;
|
|
160
|
+
let mask = 0;
|
|
161
|
+
if (options.color !== undefined) {
|
|
162
|
+
const c = options.color;
|
|
163
|
+
const a = c.a ?? 1;
|
|
164
|
+
const rs = engine._state.rs;
|
|
165
|
+
// Cached: gl.clearColor is per-context state GL retains, so only re-issue
|
|
166
|
+
// it when the requested color actually changes (Babylon re-sets it every
|
|
167
|
+
// clear; this elides the redundant JS↔native call for constant backgrounds).
|
|
168
|
+
if (rs[RS_CLEAR_R] !== c.r || rs[RS_CLEAR_G] !== c.g || rs[RS_CLEAR_B] !== c.b || rs[RS_CLEAR_A] !== a) {
|
|
169
|
+
gl.clearColor(c.r, c.g, c.b, a);
|
|
170
|
+
rs[RS_CLEAR_R] = c.r;
|
|
171
|
+
rs[RS_CLEAR_G] = c.g;
|
|
172
|
+
rs[RS_CLEAR_B] = c.b;
|
|
173
|
+
rs[RS_CLEAR_A] = a;
|
|
174
|
+
}
|
|
175
|
+
mask |= COLOR_BUFFER_BIT;
|
|
176
|
+
}
|
|
177
|
+
if (options.depth === true) {
|
|
178
|
+
mask |= DEPTH_BUFFER_BIT;
|
|
179
|
+
}
|
|
180
|
+
if (options.stencil === true) {
|
|
181
|
+
mask |= STENCIL_BUFFER_BIT;
|
|
182
|
+
}
|
|
183
|
+
if (mask !== 0) {
|
|
184
|
+
// Babylon parity: a clear respects the current depth/stencil/color write
|
|
185
|
+
// masks, so flush any deferred state before clearing.
|
|
186
|
+
applyGLStates(engine);
|
|
187
|
+
gl.clear(mask);
|
|
188
|
+
}
|
|
116
189
|
}
|
|
190
|
+
/* ─────────────────── deferred render-state reconcilers ──────────────────────
|
|
191
|
+
* The per-category half of `applyGLStates`. Each setter above installs the
|
|
192
|
+
* matching reconciler onto its `_state._flush*` slot; `applyGLStates`
|
|
193
|
+
* (apply-states.ts) dispatches ONLY through those slots. Co-locating them with
|
|
194
|
+
* their setters makes each one reachable solely when its setter is in the bundle,
|
|
195
|
+
* so a scene that never touches depth/cull, stencil, or color-mask tree-shakes
|
|
196
|
+
* the corresponding reconciler — and its GL code — away entirely. Each reconciles
|
|
197
|
+
* its DESIRED (`rs[RS_X + RS_DESIRED]`) slots against the ACTUAL twins (`rs[RS_X]`)
|
|
198
|
+
* and issues only the `gl.*` calls that changed, in the same order and with the
|
|
199
|
+
* same elision rules as the former monolithic flush. */
|
|
200
|
+
/** Reconcile depth + cull (Babylon's `_depthCullingState.apply`). @internal */
|
|
117
201
|
function flushDepthCull(engine) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
rs[RS_DEPTH_MASK]
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
rs[RS_DEPTH_FUNC]
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
rs[RS_CULL_ENABLED]
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
rs[RS_CULL_FACE
|
|
151
|
-
|
|
152
|
-
|
|
202
|
+
const gl = engine.gl;
|
|
203
|
+
const rs = engine._state.rs;
|
|
204
|
+
const dTest = rs[RS_DEPTH_TEST + RS_DESIRED];
|
|
205
|
+
if (dTest !== rs[RS_DEPTH_TEST]) {
|
|
206
|
+
rs[RS_DEPTH_TEST] = dTest;
|
|
207
|
+
if (dTest === 1) {
|
|
208
|
+
gl.enable(DEPTH_TEST);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
gl.disable(DEPTH_TEST);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const dMask = rs[RS_DEPTH_MASK + RS_DESIRED];
|
|
215
|
+
if (dMask !== rs[RS_DEPTH_MASK]) {
|
|
216
|
+
rs[RS_DEPTH_MASK] = dMask;
|
|
217
|
+
gl.depthMask(dMask === 1);
|
|
218
|
+
}
|
|
219
|
+
const dFunc = rs[RS_DEPTH_FUNC + RS_DESIRED];
|
|
220
|
+
if (dFunc !== rs[RS_DEPTH_FUNC]) {
|
|
221
|
+
rs[RS_DEPTH_FUNC] = dFunc;
|
|
222
|
+
gl.depthFunc(dFunc);
|
|
223
|
+
}
|
|
224
|
+
const dCull = rs[RS_CULL_ENABLED + RS_DESIRED];
|
|
225
|
+
if (dCull !== rs[RS_CULL_ENABLED]) {
|
|
226
|
+
rs[RS_CULL_ENABLED] = dCull;
|
|
227
|
+
if (dCull === 1) {
|
|
228
|
+
gl.enable(CULL_FACE);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
gl.disable(CULL_FACE);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const dCullFace = rs[RS_CULL_FACE + RS_DESIRED];
|
|
235
|
+
if (dCullFace !== rs[RS_CULL_FACE]) {
|
|
236
|
+
rs[RS_CULL_FACE] = dCullFace;
|
|
237
|
+
gl.cullFace(dCullFace);
|
|
238
|
+
}
|
|
153
239
|
}
|
|
240
|
+
/** Reconcile the stencil test / mask / func-triple / op-triple (Babylon's
|
|
241
|
+
* `_stencilState.apply`); each triple is issued as a unit. @internal */
|
|
154
242
|
function flushStencil(engine) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
rs[RS_STENCIL_MASK]
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
rs[RS_STENCIL_FUNC_FUNC]
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
rs[RS_STENCIL_OP_FAIL]
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
243
|
+
const gl = engine.gl;
|
|
244
|
+
const rs = engine._state.rs;
|
|
245
|
+
const dTest = rs[RS_STENCIL_TEST + RS_DESIRED];
|
|
246
|
+
if (dTest !== rs[RS_STENCIL_TEST]) {
|
|
247
|
+
rs[RS_STENCIL_TEST] = dTest;
|
|
248
|
+
if (dTest === 1) {
|
|
249
|
+
gl.enable(STENCIL_TEST);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
gl.disable(STENCIL_TEST);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const dMask = rs[RS_STENCIL_MASK + RS_DESIRED];
|
|
256
|
+
if (dMask !== rs[RS_STENCIL_MASK]) {
|
|
257
|
+
rs[RS_STENCIL_MASK] = dMask;
|
|
258
|
+
gl.stencilMask(dMask);
|
|
259
|
+
}
|
|
260
|
+
const dFuncFunc = rs[RS_STENCIL_FUNC_FUNC + RS_DESIRED];
|
|
261
|
+
const dFuncRef = rs[RS_STENCIL_FUNC_REF + RS_DESIRED];
|
|
262
|
+
const dFuncMask = rs[RS_STENCIL_FUNC_MASK + RS_DESIRED];
|
|
263
|
+
if (dFuncFunc !== rs[RS_STENCIL_FUNC_FUNC] || dFuncRef !== rs[RS_STENCIL_FUNC_REF] || dFuncMask !== rs[RS_STENCIL_FUNC_MASK]) {
|
|
264
|
+
rs[RS_STENCIL_FUNC_FUNC] = dFuncFunc;
|
|
265
|
+
rs[RS_STENCIL_FUNC_REF] = dFuncRef;
|
|
266
|
+
rs[RS_STENCIL_FUNC_MASK] = dFuncMask;
|
|
267
|
+
gl.stencilFunc(dFuncFunc, dFuncRef, dFuncMask);
|
|
268
|
+
}
|
|
269
|
+
const dOpFail = rs[RS_STENCIL_OP_FAIL + RS_DESIRED];
|
|
270
|
+
const dOpZFail = rs[RS_STENCIL_OP_ZFAIL + RS_DESIRED];
|
|
271
|
+
const dOpZPass = rs[RS_STENCIL_OP_ZPASS + RS_DESIRED];
|
|
272
|
+
if (dOpFail !== rs[RS_STENCIL_OP_FAIL] || dOpZFail !== rs[RS_STENCIL_OP_ZFAIL] || dOpZPass !== rs[RS_STENCIL_OP_ZPASS]) {
|
|
273
|
+
rs[RS_STENCIL_OP_FAIL] = dOpFail;
|
|
274
|
+
rs[RS_STENCIL_OP_ZFAIL] = dOpZFail;
|
|
275
|
+
rs[RS_STENCIL_OP_ZPASS] = dOpZPass;
|
|
276
|
+
gl.stencilOp(dOpFail, dOpZFail, dOpZPass);
|
|
277
|
+
}
|
|
189
278
|
}
|
|
279
|
+
/** Reconcile the packed color-write mask (Babylon's `setColorWrite`). @internal */
|
|
190
280
|
function flushColorMask(engine) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
281
|
+
const rs = engine._state.rs;
|
|
282
|
+
const dColorMask = rs[RS_COLOR_MASK + RS_DESIRED];
|
|
283
|
+
if (dColorMask !== rs[RS_COLOR_MASK]) {
|
|
284
|
+
rs[RS_COLOR_MASK] = dColorMask;
|
|
285
|
+
engine.gl.colorMask((dColorMask & 8) !== 0, (dColorMask & 4) !== 0, (dColorMask & 2) !== 0, (dColorMask & 1) !== 0);
|
|
286
|
+
}
|
|
197
287
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
288
|
+
/**
|
|
289
|
+
* Opt-in: give a `/render-target` {@link GLRenderTarget} a stencil attachment,
|
|
290
|
+
* replacing the core's depth-only `DEPTH_COMPONENT16` renderbuffer with either a
|
|
291
|
+
* packed **`DEPTH24_STENCIL8`** buffer (default — depth *and* stencil) or a
|
|
292
|
+
* stencil-only **`STENCIL_INDEX8`** buffer.
|
|
293
|
+
*
|
|
294
|
+
* Stencil is intentionally NOT a {@link createRenderTarget} option: keeping this
|
|
295
|
+
* helper in the depth-stencil module means the stencil/packed renderbuffer
|
|
296
|
+
* code tree-shakes out of every bundle that only needs a color (and optional
|
|
297
|
+
* depth) target.
|
|
298
|
+
*
|
|
299
|
+
* The attachment is **restore-correct**: it is rebuilt automatically — at the new
|
|
300
|
+
* size on {@link resizeRenderTarget}, and into the fresh framebuffer after a
|
|
301
|
+
* `webglcontextrestored` event — so the stencil survives for the life of the
|
|
302
|
+
* target, and {@link disposeRenderTarget} releases it along with the target.
|
|
303
|
+
*
|
|
304
|
+
* No-op on a lost/disposed context or a disposed target.
|
|
305
|
+
*
|
|
306
|
+
* @param engine - The engine that owns `rt`.
|
|
307
|
+
* @param rt - The render target to attach the stencil buffer to.
|
|
308
|
+
* @param options - `depth` (default `true`): when `true` the attachment is a
|
|
309
|
+
* packed depth+stencil buffer (`DEPTH24_STENCIL8` on `DEPTH_STENCIL_ATTACHMENT`)
|
|
310
|
+
* — the common case, and the correct choice when the target was created with
|
|
311
|
+
* `generateDepthBuffer: true`. When `false` the attachment is stencil-only
|
|
312
|
+
* (`STENCIL_INDEX8` on `STENCIL_ATTACHMENT`).
|
|
313
|
+
* @throws If a renderbuffer handle could not be allocated or the framebuffer is
|
|
314
|
+
* incomplete after attaching.
|
|
315
|
+
*/
|
|
316
|
+
export function generateRenderTargetStencil(engine, rt, options) {
|
|
317
|
+
if (engine._isLost || engine._disposed || rt._disposed) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const packDepth = options?.depth ?? true;
|
|
321
|
+
const attachment = packDepth ? DEPTH_STENCIL_ATTACHMENT : STENCIL_ATTACHMENT;
|
|
322
|
+
const format = packDepth ? DEPTH24_STENCIL8 : STENCIL_INDEX8;
|
|
323
|
+
const build = (e) => {
|
|
324
|
+
const gl = e.gl;
|
|
325
|
+
// Capture the caller's draw target so this helper is STATE-NEUTRAL: it must
|
|
326
|
+
// not silently redirect subsequent draws to `rt` (during an internal
|
|
327
|
+
// rebuild `prevFb` is `rt._framebuffer`, which the core re-checks next).
|
|
328
|
+
const prevFb = e._state.boundFramebuffer;
|
|
329
|
+
const newRb = gl.createRenderbuffer();
|
|
330
|
+
if (newRb === null) {
|
|
331
|
+
throw new Error("lite-gl: gl.createRenderbuffer returned null (render target stencil)");
|
|
332
|
+
}
|
|
333
|
+
let committed = false;
|
|
334
|
+
try {
|
|
335
|
+
gl.bindFramebuffer(FRAMEBUFFER, rt._framebuffer);
|
|
336
|
+
e._state.boundFramebuffer = rt._framebuffer;
|
|
337
|
+
gl.bindRenderbuffer(RENDERBUFFER, newRb);
|
|
338
|
+
gl.renderbufferStorage(RENDERBUFFER, format, rt.width, rt.height);
|
|
339
|
+
gl.framebufferRenderbuffer(FRAMEBUFFER, attachment, RENDERBUFFER, newRb);
|
|
340
|
+
gl.bindRenderbuffer(RENDERBUFFER, null);
|
|
341
|
+
const status = gl.checkFramebufferStatus(FRAMEBUFFER);
|
|
342
|
+
if (status !== FRAMEBUFFER_COMPLETE) {
|
|
343
|
+
throw new Error(`lite-gl: render target framebuffer incomplete after stencil attach (status 0x${status.toString(16)})`);
|
|
344
|
+
}
|
|
345
|
+
// Commit only after a complete attachment: release the buffer we
|
|
346
|
+
// replaced (the core depth-only one, or our own from a prior rebuild).
|
|
347
|
+
if (rt._depthStencil !== null) {
|
|
348
|
+
gl.deleteRenderbuffer(rt._depthStencil);
|
|
349
|
+
}
|
|
350
|
+
rt._depthStencil = newRb;
|
|
351
|
+
committed = true;
|
|
352
|
+
}
|
|
353
|
+
finally {
|
|
354
|
+
if (!committed) {
|
|
355
|
+
// Any non-committed exit (incomplete framebuffer OR an unexpected
|
|
356
|
+
// GL throw): detach + delete the buffer we couldn't adopt so it
|
|
357
|
+
// never leaks, leaving the attachment point empty for the
|
|
358
|
+
// caller-level rollback to re-establish the prior buffer.
|
|
359
|
+
gl.framebufferRenderbuffer(FRAMEBUFFER, attachment, RENDERBUFFER, null);
|
|
360
|
+
gl.deleteRenderbuffer(newRb);
|
|
361
|
+
}
|
|
362
|
+
// Restore the caller's draw target + the bound-framebuffer cache.
|
|
363
|
+
if (e._state.boundFramebuffer !== prevFb) {
|
|
364
|
+
gl.bindFramebuffer(FRAMEBUFFER, prevFb);
|
|
365
|
+
e._state.boundFramebuffer = prevFb;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
// Build once now, but COMMIT the resize/restore hook only if it succeeds — a
|
|
370
|
+
// failed opt-in must leave the target exactly as it was. The packed attach
|
|
371
|
+
// above can clear the core `DEPTH_ATTACHMENT`, so on failure restore the prior
|
|
372
|
+
// hook AND re-establish the prior depth/stencil attachment (the prior hook's,
|
|
373
|
+
// or the core depth-only buffer).
|
|
374
|
+
const prevHook = rt._rebuildDepthStencil;
|
|
375
|
+
const prevDepthStencil = rt._depthStencil;
|
|
246
376
|
try {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
377
|
+
build(engine);
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
rt._rebuildDepthStencil = prevHook;
|
|
381
|
+
try {
|
|
382
|
+
if (prevHook !== undefined) {
|
|
383
|
+
prevHook(engine);
|
|
384
|
+
}
|
|
385
|
+
else if (prevDepthStencil !== null) {
|
|
386
|
+
reattachCoreDepthBuffer(engine, rt, prevDepthStencil);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
// Best-effort restore; surface the original failure below.
|
|
391
|
+
}
|
|
392
|
+
throw err;
|
|
393
|
+
}
|
|
394
|
+
rt._rebuildDepthStencil = build;
|
|
257
395
|
}
|
|
396
|
+
/**
|
|
397
|
+
* Re-attach a core depth-only renderbuffer at `DEPTH_ATTACHMENT` — used to roll a
|
|
398
|
+
* render target back when a packed {@link generateRenderTargetStencil} attach
|
|
399
|
+
* fails completeness (attaching at `DEPTH_STENCIL_ATTACHMENT` clears the core
|
|
400
|
+
* `DEPTH_ATTACHMENT`). State-neutral: restores the caller's bound framebuffer.
|
|
401
|
+
* @internal
|
|
402
|
+
*/
|
|
258
403
|
function reattachCoreDepthBuffer(engine, rt, depthBuffer) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
404
|
+
const gl = engine.gl;
|
|
405
|
+
const prevFb = engine._state.boundFramebuffer;
|
|
406
|
+
gl.bindFramebuffer(FRAMEBUFFER, rt._framebuffer);
|
|
407
|
+
engine._state.boundFramebuffer = rt._framebuffer;
|
|
408
|
+
gl.framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT, RENDERBUFFER, depthBuffer);
|
|
409
|
+
if (engine._state.boundFramebuffer !== prevFb) {
|
|
410
|
+
gl.bindFramebuffer(FRAMEBUFFER, prevFb);
|
|
411
|
+
engine._state.boundFramebuffer = prevFb;
|
|
412
|
+
}
|
|
268
413
|
}
|
|
269
|
-
|
|
270
|
-
clearEngine,
|
|
271
|
-
generateRenderTargetStencil,
|
|
272
|
-
setColorMask,
|
|
273
|
-
setCullState,
|
|
274
|
-
setDepthState,
|
|
275
|
-
setStencilState
|
|
276
|
-
};
|
|
277
|
-
//# sourceMappingURL=depth-stencil.js.map
|
|
414
|
+
//# sourceMappingURL=depth-stencil.js.map
|