@geastack/native-webgl-angle 0.1.6

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.
@@ -0,0 +1,1955 @@
1
+ // The native model of three's shader uniforms.
2
+ //
3
+ // three types a uniform set as `Object`: `{ name: { value: anything } }`, filled
4
+ // by a generic `for`-`in` shape copy (`cloneUniforms`) and read back by name in
5
+ // a dozen renderer modules and by string id in `WebGLUniforms.upload`. Compiled
6
+ // as written, that is a dictionary of boxed values and every read of a uniform
7
+ // is an unbox -- the exact carrier this build refuses. Stated once here instead:
8
+ //
9
+ // - `NativeUniformValue` is one DISJOINT union of every value a uniform holds
10
+ // in three's own renderer: the math classes the setters test for
11
+ // (`v.x !== undefined` is a Vector, `v.r` a Color, `v.elements` a Matrix --
12
+ // they narrow with `instanceof` here), textures, the flat numeric arrays,
13
+ // and the light-uniform arrays. Each arm is a distinct native carrier, so a
14
+ // slot is one tagged union and every consumer narrows it natively.
15
+ // - `NativeUniformSlot` is `{ value, needsUpdate? }` and `NativeUniforms` the
16
+ // string-keyed table of slots -- one type for a ShaderLib template, a merged
17
+ // material set, a `ShaderMaterial`'s own custom uniforms and the property
18
+ // bag the renderer keeps per material, which is what lets `cloneUniforms`
19
+ // and `mergeUniforms` stay the generic `for`-`in` copies three wrote.
20
+ // - The light-uniform records `WebGLLights` caches are CLASSES, so an
21
+ // `instanceof` can tell them apart inside a union (a structural record
22
+ // cannot be told from another one with the same fields at runtime).
23
+ //
24
+ // The typedefs live in `UniformsLib.js`, the root of the chain; every other
25
+ // module aliases them through `import()` types.
26
+
27
+ const glContext = "import('@geastack/native-webgl-angle/nativeWebGL').NativeWebGL2RenderingContext"
28
+ const glHandle = "import('@geastack/native-webgl-angle/nativeWebGL').NativeHandle"
29
+
30
+ export const nativeLightUniformClassNames = [
31
+ 'NativeDirectionalLightUniform',
32
+ 'NativeSpotLightUniform',
33
+ 'NativePointLightUniform',
34
+ 'NativeHemisphereLightUniform',
35
+ 'NativeRectAreaLightUniform',
36
+ 'NativeShadowUniform',
37
+ 'NativePointShadowUniform',
38
+ ]
39
+
40
+ /**
41
+ * The JSDoc typedef block injected into `UniformsLib.js`, after the light
42
+ * uniform classes it names.
43
+ */
44
+ export const nativeUniformTypedefs = `/**
45
+ * Every value a shader uniform slot can hold, as ONE disjoint union: the math
46
+ * classes three's setters duck-type (\`v.x\`, \`v.r\`, \`v.elements\`), textures,
47
+ * the flat numeric arrays, and the light-uniform arrays \`WebGLLights\` builds.
48
+ * A slot is therefore one native tagged union, and every consumer narrows it
49
+ * with \`instanceof\`/\`typeof\`/\`Array.isArray\` instead of reading a box.
50
+ * @typedef {number|boolean|null|undefined
51
+ * |import('../../math/Color.js').Color
52
+ * |import('../../math/Vector2.js').Vector2
53
+ * |import('../../math/Vector3.js').Vector3
54
+ * |import('../../math/Vector4.js').Vector4
55
+ * |import('../../math/Matrix2.js').Matrix2
56
+ * |import('../../math/Matrix3.js').Matrix3
57
+ * |import('../../math/Matrix4.js').Matrix4
58
+ * |import('../../textures/Texture.js').Texture
59
+ * |number[]|Float32Array|Int32Array|Uint32Array
60
+ * |Array<import('../../math/Vector3.js').Vector3>
61
+ * |Array<import('../../math/Matrix4.js').Matrix4>
62
+ * |Array<import('../../textures/Texture.js').Texture|null>
63
+ ${nativeLightUniformClassNames.map((name) => ` * |${name}|${name}[]`).join('\n')}
64
+ * } NativeUniformValue
65
+ * @typedef {{ value: NativeUniformValue, needsUpdate?: boolean }} NativeUniformSlot
66
+ * @typedef {Record<string, NativeUniformSlot>} NativeUniforms
67
+ */`
68
+
69
+ /**
70
+ * The classes that replace `WebGLLights`' light-uniform literals. Field names,
71
+ * order and defaults are three's own (`UniformsCache`/`ShadowUniformsCache`).
72
+ * `NativePointShadowUniform` deliberately does NOT extend `NativeShadowUniform`:
73
+ * an inheritance edge would make the two array arms of `NativeUniformValue`
74
+ * subtype-related, and the union's arms must stay disjoint. They live in
75
+ * `UniformsLib.js`, the root of the import graph, so `WebGLLights` and
76
+ * `WebGLUniforms` both reach them without a cycle.
77
+ */
78
+ export const nativeLightUniformClasses = `export class NativeDirectionalLightUniform {
79
+
80
+ \tconstructor() {
81
+
82
+ \t\tthis.direction = new Vector3();
83
+ \t\tthis.color = new Color();
84
+
85
+ \t}
86
+
87
+ }
88
+
89
+ export class NativeSpotLightUniform {
90
+
91
+ \tconstructor() {
92
+
93
+ \t\tthis.position = new Vector3();
94
+ \t\tthis.direction = new Vector3();
95
+ \t\tthis.color = new Color();
96
+ \t\tthis.distance = 0;
97
+ \t\tthis.coneCos = 0;
98
+ \t\tthis.penumbraCos = 0;
99
+ \t\tthis.decay = 0;
100
+
101
+ \t}
102
+
103
+ }
104
+
105
+ export class NativePointLightUniform {
106
+
107
+ \tconstructor() {
108
+
109
+ \t\tthis.position = new Vector3();
110
+ \t\tthis.color = new Color();
111
+ \t\tthis.distance = 0;
112
+ \t\tthis.decay = 0;
113
+
114
+ \t}
115
+
116
+ }
117
+
118
+ export class NativeHemisphereLightUniform {
119
+
120
+ \tconstructor() {
121
+
122
+ \t\tthis.direction = new Vector3();
123
+ \t\tthis.skyColor = new Color();
124
+ \t\tthis.groundColor = new Color();
125
+
126
+ \t}
127
+
128
+ }
129
+
130
+ export class NativeRectAreaLightUniform {
131
+
132
+ \tconstructor() {
133
+
134
+ \t\tthis.color = new Color();
135
+ \t\tthis.position = new Vector3();
136
+ \t\tthis.halfWidth = new Vector3();
137
+ \t\tthis.halfHeight = new Vector3();
138
+
139
+ \t}
140
+
141
+ }
142
+
143
+ export class NativeShadowUniform {
144
+
145
+ \tconstructor() {
146
+
147
+ \t\tthis.shadowIntensity = 1;
148
+ \t\tthis.shadowBias = 0;
149
+ \t\tthis.shadowNormalBias = 0;
150
+ \t\tthis.shadowRadius = 1;
151
+ \t\tthis.shadowMapSize = new Vector2();
152
+
153
+ \t}
154
+
155
+ }
156
+
157
+ export class NativePointShadowUniform {
158
+
159
+ \tconstructor() {
160
+
161
+ \t\tthis.shadowIntensity = 1;
162
+ \t\tthis.shadowBias = 0;
163
+ \t\tthis.shadowNormalBias = 0;
164
+ \t\tthis.shadowRadius = 1;
165
+ \t\tthis.shadowMapSize = new Vector2();
166
+ \t\tthis.shadowCameraNear = 1;
167
+ \t\tthis.shadowCameraFar = 1000;
168
+
169
+ \t}
170
+
171
+ }
172
+
173
+ /** @typedef {NativeDirectionalLightUniform|NativeSpotLightUniform|NativePointLightUniform|NativeHemisphereLightUniform|NativeRectAreaLightUniform} NativeLightUniform */
174
+ /** @typedef {NativeShadowUniform|NativePointShadowUniform} NativeLightShadowUniform */
175
+ `
176
+
177
+ /**
178
+ * `WebGLLights`' two uniform caches over the classes, replacing three's
179
+ * literal-building `UniformsCache`/`ShadowUniformsCache`, plus the
180
+ * `instanceof` reads the light loops use where three trusted `light.type`.
181
+ * Plain functions, not `new`-called ones: three's return an object literal
182
+ * out of a `new` expression, which is a construct thunk for nothing.
183
+ */
184
+ export const nativeLightUniformCaches = `/** @typedef {import('../shaders/UniformsLib.js').NativeLightUniform} NativeLightUniform */
185
+ /** @typedef {import('../shaders/UniformsLib.js').NativeLightShadowUniform} NativeLightShadowUniform */
186
+
187
+ ${['NativeDirectionalLightUniform', 'NativeSpotLightUniform', 'NativePointLightUniform', 'NativeHemisphereLightUniform', 'NativeRectAreaLightUniform']
188
+ .map(
189
+ (name) => `/** @param {NativeLightUniform} uniforms @return {${name}} */
190
+ function require${name}( uniforms ) {
191
+
192
+ \tif ( uniforms instanceof ${name} ) return uniforms;
193
+
194
+ \tthrow new Error( 'THREE.WebGLLights: light uniforms are not a ${name}.' );
195
+
196
+ }`,
197
+ )
198
+ .join('\n\n')}
199
+
200
+ ${['NativeShadowUniform', 'NativePointShadowUniform']
201
+ .map(
202
+ (name) => `/** @param {NativeLightShadowUniform} uniforms @return {${name}} */
203
+ function require${name}( uniforms ) {
204
+
205
+ \tif ( uniforms instanceof ${name} ) return uniforms;
206
+
207
+ \tthrow new Error( 'THREE.WebGLLights: shadow uniforms are not a ${name}.' );
208
+
209
+ }`,
210
+ )
211
+ .join('\n\n')}
212
+
213
+ function UniformsCache() {
214
+
215
+ \t/** @type {Map<number, NativeLightUniform>} */
216
+ \tconst lights = new Map();
217
+
218
+ \treturn {
219
+
220
+ \t\t/** @param {import('../../lights/Light.js').Light} light @return {NativeLightUniform} */
221
+ \t\tget: function ( light ) {
222
+
223
+ \t\t\tconst cached = lights.get( light.id );
224
+
225
+ \t\t\tif ( cached !== undefined ) return cached;
226
+
227
+ \t\t\t/** @type {NativeLightUniform} */
228
+ \t\t\tlet uniforms;
229
+
230
+ \t\t\tswitch ( light.type ) {
231
+
232
+ \t\t\t\tcase 'DirectionalLight':
233
+ \t\t\t\t\tuniforms = new NativeDirectionalLightUniform();
234
+ \t\t\t\t\tbreak;
235
+
236
+ \t\t\t\tcase 'SpotLight':
237
+ \t\t\t\t\tuniforms = new NativeSpotLightUniform();
238
+ \t\t\t\t\tbreak;
239
+
240
+ \t\t\t\tcase 'PointLight':
241
+ \t\t\t\t\tuniforms = new NativePointLightUniform();
242
+ \t\t\t\t\tbreak;
243
+
244
+ \t\t\t\tcase 'HemisphereLight':
245
+ \t\t\t\t\tuniforms = new NativeHemisphereLightUniform();
246
+ \t\t\t\t\tbreak;
247
+
248
+ \t\t\t\tcase 'RectAreaLight':
249
+ \t\t\t\t\tuniforms = new NativeRectAreaLightUniform();
250
+ \t\t\t\t\tbreak;
251
+
252
+ \t\t\t\tdefault:
253
+ \t\t\t\t\tthrow new Error( 'THREE.WebGLLights: no uniforms for light type ' + light.type + '.' );
254
+
255
+ \t\t\t}
256
+
257
+ \t\t\tlights.set( light.id, uniforms );
258
+
259
+ \t\t\treturn uniforms;
260
+
261
+ \t\t}
262
+
263
+ \t};
264
+
265
+ }
266
+
267
+ function ShadowUniformsCache() {
268
+
269
+ \t/** @type {Map<number, NativeLightShadowUniform>} */
270
+ \tconst lights = new Map();
271
+
272
+ \treturn {
273
+
274
+ \t\t/** @param {import('../../lights/Light.js').Light} light @return {NativeLightShadowUniform} */
275
+ \t\tget: function ( light ) {
276
+
277
+ \t\t\tconst cached = lights.get( light.id );
278
+
279
+ \t\t\tif ( cached !== undefined ) return cached;
280
+
281
+ \t\t\t/** @type {NativeLightShadowUniform} */
282
+ \t\t\tlet uniforms;
283
+
284
+ \t\t\tswitch ( light.type ) {
285
+
286
+ \t\t\t\tcase 'DirectionalLight':
287
+ \t\t\t\t\tuniforms = new NativeShadowUniform();
288
+ \t\t\t\t\tbreak;
289
+
290
+ \t\t\t\tcase 'SpotLight':
291
+ \t\t\t\t\tuniforms = new NativeShadowUniform();
292
+ \t\t\t\t\tbreak;
293
+
294
+ \t\t\t\tcase 'PointLight':
295
+ \t\t\t\t\tuniforms = new NativePointShadowUniform();
296
+ \t\t\t\t\tbreak;
297
+
298
+ \t\t\t\tdefault:
299
+ \t\t\t\t\tthrow new Error( 'THREE.WebGLLights: no shadow uniforms for light type ' + light.type + '.' );
300
+
301
+ \t\t\t}
302
+
303
+ \t\t\tlights.set( light.id, uniforms );
304
+
305
+ \t\t\treturn uniforms;
306
+
307
+ \t\t}
308
+
309
+ \t};
310
+
311
+ }
312
+ `
313
+
314
+ /**
315
+ * `UniformsUtils.js`, typed: the same two `for`-`in` copies three wrote, over
316
+ * `NativeUniforms`, plus the per-arm clone and the narrowing accessors every
317
+ * consumer of a slot uses in place of `uniforms.x.value.method()`.
318
+ */
319
+ export const nativeUniformsUtilsSource = `import { ColorManagement } from '../../math/ColorManagement.js';
320
+ import { warn } from '../../utils.js';
321
+ import { Color } from '../../math/Color.js';
322
+ import { Matrix3 } from '../../math/Matrix3.js';
323
+ import { Matrix4 } from '../../math/Matrix4.js';
324
+ import { Vector2 } from '../../math/Vector2.js';
325
+ import { Vector3 } from '../../math/Vector3.js';
326
+ import { Vector4 } from '../../math/Vector4.js';
327
+ import { Texture } from '../../textures/Texture.js';
328
+
329
+ /** @typedef {import('./UniformsLib.js').NativeUniformValue} NativeUniformValue */
330
+ /** @typedef {import('./UniformsLib.js').NativeUniformSlot} NativeUniformSlot */
331
+ /** @typedef {import('./UniformsLib.js').NativeUniforms} NativeUniforms */
332
+
333
+ /**
334
+ * The array guards claim an arm only from a NON-EMPTY first element: an empty
335
+ * array of one arm is indistinguishable at runtime from an empty array of any
336
+ * other, and a guard that claimed \`number[]\` for an empty \`Vector3[]\` would
337
+ * make the compiler unwrap the wrong arm. Empty arrays therefore fall through
338
+ * every guard and are returned as they are.
339
+ */
340
+
341
+ /** @param {NativeUniformValue} value @return {value is number[]} */
342
+ export function isUniformNumberArray( value ) {
343
+
344
+ \treturn Array.isArray( value ) && value.length > 0 && typeof value[ 0 ] === 'number';
345
+
346
+ }
347
+
348
+ /** @param {NativeUniformValue} value @return {value is Vector3[]} */
349
+ function isVector3Array( value ) {
350
+
351
+ \treturn Array.isArray( value ) && value.length > 0 && value[ 0 ] instanceof Vector3;
352
+
353
+ }
354
+
355
+ /** @param {NativeUniformValue} value @return {value is Matrix4[]} */
356
+ function isMatrix4Array( value ) {
357
+
358
+ \treturn Array.isArray( value ) && value.length > 0 && value[ 0 ] instanceof Matrix4;
359
+
360
+ }
361
+
362
+ /** @param {NativeUniformValue} value @return {value is Array<Texture|null>} */
363
+ export function isUniformTextureArray( value ) {
364
+
365
+ \tif ( ! Array.isArray( value ) || value.length === 0 ) return false;
366
+
367
+ \tconst first = value[ 0 ];
368
+
369
+ \treturn first === null || first instanceof Texture;
370
+
371
+ }
372
+
373
+ /**
374
+ * One uniform value, deep-copied the way three's \`cloneUniforms\` copies it: a
375
+ * three object is \`clone()\`d (a render-target texture cannot be and becomes
376
+ * null, with three's own warning), an array of three objects clones each
377
+ * element, a numeric array is sliced, and anything else is shared. The light
378
+ * uniform arrays and typed arrays are shared too -- three shares a typed
379
+ * array as well, and the light arrays only ever exist empty in a template
380
+ * and are replaced wholesale by the renderer every frame, never appended to.
381
+ * @param {NativeUniformValue} value
382
+ * @return {NativeUniformValue}
383
+ */
384
+ export function cloneUniformValue( value ) {
385
+
386
+ \tif ( value instanceof Texture ) {
387
+
388
+ \t\tif ( value.isRenderTargetTexture ) {
389
+
390
+ \t\t\twarn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' );
391
+ \t\t\treturn null;
392
+
393
+ \t\t}
394
+
395
+ \t\treturn value.clone();
396
+
397
+ \t}
398
+
399
+ \tif ( value instanceof Color ) return value.clone();
400
+ \tif ( value instanceof Vector2 ) return value.clone();
401
+ \tif ( value instanceof Vector3 ) return value.clone();
402
+ \tif ( value instanceof Vector4 ) return value.clone();
403
+ \tif ( value instanceof Matrix3 ) return value.clone();
404
+ \tif ( value instanceof Matrix4 ) return value.clone();
405
+
406
+ \tif ( isUniformNumberArray( value ) ) return value.slice();
407
+
408
+ \tif ( isVector3Array( value ) ) {
409
+
410
+ \t\t/** @type {Vector3[]} */
411
+ \t\tconst cloned = [];
412
+
413
+ \t\tfor ( let i = 0, l = value.length; i < l; i ++ ) cloned.push( value[ i ].clone() );
414
+
415
+ \t\treturn cloned;
416
+
417
+ \t}
418
+
419
+ \tif ( isMatrix4Array( value ) ) {
420
+
421
+ \t\t/** @type {Matrix4[]} */
422
+ \t\tconst cloned = [];
423
+
424
+ \t\tfor ( let i = 0, l = value.length; i < l; i ++ ) cloned.push( value[ i ].clone() );
425
+
426
+ \t\treturn cloned;
427
+
428
+ \t}
429
+
430
+ \tif ( isUniformTextureArray( value ) ) {
431
+
432
+ \t\t/** @type {Array<Texture|null>} */
433
+ \t\tconst cloned = [];
434
+
435
+ \t\tfor ( let i = 0, l = value.length; i < l; i ++ ) {
436
+
437
+ \t\t\tconst texture = value[ i ];
438
+ \t\t\tcloned.push( texture === null ? null : texture.clone() );
439
+
440
+ \t\t}
441
+
442
+ \t\treturn cloned;
443
+
444
+ \t}
445
+
446
+ \treturn value;
447
+
448
+ }
449
+
450
+ /**
451
+ * Clones the given uniform definitions by performing a deep-copy. That means
452
+ * if the value of a uniform refers to an object like a Vector3 or Texture,
453
+ * the cloned uniform will refer to a new object reference.
454
+ *
455
+ * @param {NativeUniforms} src - An object representing uniform definitions.
456
+ * @return {NativeUniforms} The cloned uniforms.
457
+ */
458
+ export function cloneUniforms( src ) {
459
+
460
+ \t/** @type {NativeUniforms} */
461
+ \tconst dst = {};
462
+
463
+ \tfor ( const u in src ) {
464
+
465
+ \t\tconst uniform = src[ u ];
466
+
467
+ \t\t/** @type {NativeUniformSlot} */
468
+ \t\tconst cloned = { value: cloneUniformValue( uniform.value ) };
469
+
470
+ \t\tif ( uniform.needsUpdate !== undefined ) cloned.needsUpdate = uniform.needsUpdate;
471
+
472
+ \t\tdst[ u ] = cloned;
473
+
474
+ \t}
475
+
476
+ \treturn dst;
477
+
478
+ }
479
+
480
+ /**
481
+ * Merges the given uniform definitions into a single object. Since the
482
+ * method internally uses cloneUniforms(), it performs a deep-copy when
483
+ * producing the merged uniform definitions.
484
+ *
485
+ * @param {NativeUniforms[]} uniforms - An array of uniform definitions.
486
+ * @return {NativeUniforms} The merged uniforms.
487
+ */
488
+ export function mergeUniforms( uniforms ) {
489
+
490
+ \t/** @type {NativeUniforms} */
491
+ \tconst merged = {};
492
+
493
+ \tfor ( let u = 0; u < uniforms.length; u ++ ) {
494
+
495
+ \t\tconst tmp = cloneUniforms( uniforms[ u ] );
496
+
497
+ \t\tfor ( const p in tmp ) {
498
+
499
+ \t\t\tmerged[ p ] = tmp[ p ];
500
+
501
+ \t\t}
502
+
503
+ \t}
504
+
505
+ \treturn merged;
506
+
507
+ }
508
+
509
+ /**
510
+ * The narrowing reads. three writes \`uniforms.diffuse.value.copy( c )\`,
511
+ * trusting the shader template to have put a Color there; these say the same
512
+ * thing about the union and refuse loudly when the template did not.
513
+ */
514
+
515
+ /** @param {NativeUniformSlot} uniform @return {Color} */
516
+ export function uniformColor( uniform ) {
517
+
518
+ \tconst value = uniform.value;
519
+
520
+ \tif ( value instanceof Color ) return value;
521
+
522
+ \tthrow new Error( 'UniformsUtils: uniform does not hold a Color.' );
523
+
524
+ }
525
+
526
+ /** @param {NativeUniformSlot} uniform @return {Vector2} */
527
+ export function uniformVector2( uniform ) {
528
+
529
+ \tconst value = uniform.value;
530
+
531
+ \tif ( value instanceof Vector2 ) return value;
532
+
533
+ \tthrow new Error( 'UniformsUtils: uniform does not hold a Vector2.' );
534
+
535
+ }
536
+
537
+ /** @param {NativeUniformSlot} uniform @return {Vector3} */
538
+ export function uniformVector3( uniform ) {
539
+
540
+ \tconst value = uniform.value;
541
+
542
+ \tif ( value instanceof Vector3 ) return value;
543
+
544
+ \tthrow new Error( 'UniformsUtils: uniform does not hold a Vector3.' );
545
+
546
+ }
547
+
548
+ /** @param {NativeUniformSlot} uniform @return {Matrix3} */
549
+ export function uniformMatrix3( uniform ) {
550
+
551
+ \tconst value = uniform.value;
552
+
553
+ \tif ( value instanceof Matrix3 ) return value;
554
+
555
+ \tthrow new Error( 'UniformsUtils: uniform does not hold a Matrix3.' );
556
+
557
+ }
558
+
559
+ /** @param {NativeUniformSlot} uniform @return {Texture|null} */
560
+ export function uniformTexture( uniform ) {
561
+
562
+ \tconst value = uniform.value;
563
+
564
+ \tif ( value instanceof Texture ) return value;
565
+ \tif ( value === null || value === undefined ) return null;
566
+
567
+ \tthrow new Error( 'UniformsUtils: uniform does not hold a Texture.' );
568
+
569
+ }
570
+
571
+ /**
572
+ * Clones the given uniform groups by performing a deep-copy.
573
+ *
574
+ * @param {Array<import('../../core/UniformsGroup.js').UniformsGroup>} src - An array of uniform groups.
575
+ * @return {Array<import('../../core/UniformsGroup.js').UniformsGroup>} The cloned uniform groups.
576
+ */
577
+ export function cloneUniformsGroups( src ) {
578
+
579
+ \t/** @type {Array<import('../../core/UniformsGroup.js').UniformsGroup>} */
580
+ \tconst dst = [];
581
+
582
+ \tfor ( let u = 0; u < src.length; u ++ ) {
583
+
584
+ \t\tdst.push( src[ u ].clone() );
585
+
586
+ \t}
587
+
588
+ \treturn dst;
589
+
590
+ }
591
+
592
+ /**
593
+ * Returns a color space that is appropriate for the unlit uniform color.
594
+ *
595
+ * @param {InstanceType<typeof import('../WebGLRenderer.js').WebGLRenderer>} renderer - The renderer.
596
+ * @return {string} The color space.
597
+ */
598
+ export function getUnlitUniformColorSpace( renderer ) {
599
+
600
+ \tconst currentRenderTarget = renderer.getRenderTarget();
601
+
602
+ \tif ( currentRenderTarget === null ) {
603
+
604
+ \t\t// https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398
605
+ \t\treturn renderer.getOutputColorSpace();
606
+
607
+ \t}
608
+
609
+ \t// https://github.com/mrdoob/three.js/issues/27868
610
+ \tif ( currentRenderTarget.isXRRenderTarget === true ) {
611
+
612
+ \t\treturn currentRenderTarget.texture.colorSpace;
613
+
614
+ \t}
615
+
616
+ \treturn ColorManagement.workingColorSpace;
617
+
618
+ }
619
+
620
+ // Legacy
621
+
622
+ const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms };
623
+
624
+ export { UniformsUtils };
625
+ `
626
+
627
+ /**
628
+ * Rewrite every `<receiver>.uniforms.<name>.value.<method>(` into the narrowing
629
+ * accessor for that uniform's declared type. Fails on any `.value.` method
630
+ * call the map does not name, so a new site cannot silently stay a boxed read.
631
+ * @param {string} text
632
+ * @param {string} fileName
633
+ * @param {Record<string, string>} accessorByUniform
634
+ */
635
+ export const rewriteUniformValueMethods = (text, fileName, accessorByUniform) => {
636
+ const rewritten = text.replace(/([\w.]*uniforms)\.(\w+)\.value\./g, (match, receiver, name) => {
637
+ const accessor = accessorByUniform[name]
638
+ if (accessor === undefined) throw new Error(`Three uniform '${name}' at ${fileName} is read as a method receiver but has no native accessor`)
639
+ return `${accessor}( ${receiver}.${name} ).`
640
+ })
641
+ const left = /[\w.]*uniforms\.\w+\.value\./.exec(rewritten)
642
+ if (left !== null) throw new Error(`Three uniform value method call at ${fileName} was not rewritten: ${left[0]}`)
643
+ return rewritten
644
+ }
645
+
646
+ const setterHeader = (receiver) => `/** @this {${receiver}} @param {${glContext}} gl @param {NativeUniformValue} v @param {NativeTextures|undefined} textures @return {void} */`
647
+
648
+ const vectorSetter = (name, size, ctorName, glScalar, glArray, requireArray) => {
649
+ const fields = ['x', 'y', 'z', 'w'].slice(0, size)
650
+ return `${setterHeader('SingleUniform')}
651
+ function ${name}( gl, v, textures ) {
652
+
653
+ \tconst cache = this.cache;
654
+
655
+ \tif ( v instanceof ${ctorName} ) {
656
+
657
+ \t\tif ( ${fields.map((field, index) => `cache[ ${index} ] !== v.${field}`).join(' || ')} ) {
658
+
659
+ \t\t\tgl.${glScalar}( this.addr, ${fields.map((field) => `v.${field}`).join(', ')} );
660
+
661
+ ${fields.map((field, index) => `\t\t\tcache[ ${index} ] = v.${field};`).join('\n')}
662
+
663
+ \t\t}
664
+
665
+ \t} else {
666
+
667
+ \t\tconst flatValue = ${requireArray}( v );
668
+
669
+ \t\tif ( arraysEqual( cache, flatValue ) ) return;
670
+
671
+ \t\tgl.${glArray}( this.addr, flatValue );
672
+
673
+ \t\tcopyArray( cache, flatValue );
674
+
675
+ \t}
676
+
677
+ }`
678
+ }
679
+
680
+ const matrixSetter = (name, size, ctorName, glArray, scratch) => `${setterHeader('SingleUniform')}
681
+ function ${name}( gl, v, textures ) {
682
+
683
+ \tconst cache = this.cache;
684
+
685
+ \tif ( v instanceof ${ctorName} ) {
686
+
687
+ \t\tconst elements = v.elements;
688
+
689
+ \t\tif ( arraysEqual( cache, elements ) ) return;
690
+
691
+ \t\t${scratch}.set( elements );
692
+
693
+ \t\tgl.${glArray}( this.addr, false, ${scratch} );
694
+
695
+ \t\tcopyArray( cache, elements );
696
+
697
+ \t} else {
698
+
699
+ \t\tconst flatValue = requireFloatUniformArray( v );
700
+
701
+ \t\tif ( arraysEqual( cache, flatValue ) ) return;
702
+
703
+ \t\tgl.${glArray}( this.addr, false, flatValue );
704
+
705
+ \t\tcopyArray( cache, flatValue );
706
+
707
+ \t}
708
+
709
+ }`
710
+
711
+ const scalarSetter = (name, glScalar, booleans) => `${setterHeader('SingleUniform')}
712
+ function ${name}( gl, v, textures ) {
713
+
714
+ \tconst cache = this.cache;
715
+ \tconst value = ${booleans ? "typeof v === 'boolean' ? ( v ? 1 : 0 ) : requireUniformNumber( v )" : 'requireUniformNumber( v )'};
716
+
717
+ \tif ( cache[ 0 ] === value ) return;
718
+
719
+ \tgl.${glScalar}( this.addr, value );
720
+
721
+ \tcache[ 0 ] = value;
722
+
723
+ }`
724
+
725
+ const textureSetter = (name, setter, empty, shadowAware) => `${setterHeader('SingleUniform')}
726
+ function ${name}( gl, v, textures ) {
727
+
728
+ \tconst manager = requireTextures( textures );
729
+ \tconst cache = this.cache;
730
+
731
+ \tconst unit = manager.allocateTextureUnit();
732
+
733
+ \tif ( cache[ 0 ] !== unit ) {
734
+
735
+ \t\tgl.uniform1i( this.addr, unit );
736
+ \t\tcache[ 0 ] = unit;
737
+
738
+ \t}
739
+ ${
740
+ shadowAware
741
+ ? `
742
+ \t/** @type {Texture} */
743
+ \tlet emptyTexture2D;
744
+
745
+ \tif ( this.type === gl.SAMPLER_2D_SHADOW ) {
746
+
747
+ \t\temptyShadowTexture.compareFunction = manager.isReversedDepthBuffer() ? GreaterEqualCompare : LessEqualCompare;
748
+ \t\temptyTexture2D = emptyShadowTexture;
749
+
750
+ \t} else {
751
+
752
+ \t\temptyTexture2D = emptyTexture;
753
+
754
+ \t}
755
+
756
+ \tmanager.${setter}( uniformTextureOr( v, emptyTexture2D ), unit );
757
+ `
758
+ : `
759
+ \tmanager.${setter}( uniformTextureOr( v, ${empty} ), unit );
760
+ `
761
+ }
762
+ }`
763
+
764
+ const flatArraySetter = (name, glArray, requireArray) => `${setterHeader('PureArrayUniform')}
765
+ function ${name}( gl, v, textures ) {
766
+
767
+ \tgl.${glArray}( this.addr, ${requireArray}( v ) );
768
+
769
+ }`
770
+
771
+ const flattenedArraySetter = (name, blockSize, glArray, matrix) => `${setterHeader('PureArrayUniform')}
772
+ function ${name}( gl, v, textures ) {
773
+
774
+ \tconst data = flatten( v, this.size, ${blockSize} );
775
+
776
+ \tgl.${glArray}( this.addr, ${matrix ? 'false, ' : ''}data );
777
+
778
+ }`
779
+
780
+ const textureArraySetter = (name, setter, empty, shadowAware) => `${setterHeader('PureArrayUniform')}
781
+ function ${name}( gl, v, textures ) {
782
+
783
+ \tconst manager = requireTextures( textures );
784
+ \tconst cache = this.cache;
785
+
786
+ \tif ( Array.isArray( v ) && v.length === 0 ) {
787
+
788
+ \t\tconst units = allocTexUnits( manager, 0 );
789
+
790
+ \t\tif ( ! arraysEqual( cache, units ) ) {
791
+
792
+ \t\t\tgl.uniform1iv( this.addr, units );
793
+ \t\t\tcopyArray( cache, units );
794
+
795
+ \t\t}
796
+
797
+ \t\treturn;
798
+
799
+ \t}
800
+
801
+ \tconst list = requireTextureArray( v );
802
+ \tconst n = list.length;
803
+
804
+ \tconst units = allocTexUnits( manager, n );
805
+
806
+ \tif ( ! arraysEqual( cache, units ) ) {
807
+
808
+ \t\tgl.uniform1iv( this.addr, units );
809
+ \t\tcopyArray( cache, units );
810
+
811
+ \t}
812
+ ${
813
+ shadowAware
814
+ ? `
815
+ \t/** @type {Texture} */
816
+ \tlet emptyTexture2D;
817
+
818
+ \tif ( this.type === gl.SAMPLER_2D_SHADOW ) {
819
+
820
+ \t\temptyTexture2D = emptyShadowTexture;
821
+
822
+ \t} else {
823
+
824
+ \t\temptyTexture2D = emptyTexture;
825
+
826
+ \t}
827
+ `
828
+ : ''
829
+ }
830
+ \tfor ( let i = 0; i !== n; ++ i ) {
831
+
832
+ \t\tconst texture = list[ i ];
833
+ \t\tmanager.${setter}( texture === null ? ${shadowAware ? 'emptyTexture2D' : empty} : texture, units[ i ] );
834
+
835
+ \t}
836
+
837
+ }`
838
+
839
+ const singularSetterCases = `\t\tcase 0x1406: return setValueV1f; // FLOAT
840
+ \t\tcase 0x8b50: return setValueV2f; // _VEC2
841
+ \t\tcase 0x8b51: return setValueV3f; // _VEC3
842
+ \t\tcase 0x8b52: return setValueV4f; // _VEC4
843
+
844
+ \t\tcase 0x8b5a: return setValueM2; // _MAT2
845
+ \t\tcase 0x8b5b: return setValueM3; // _MAT3
846
+ \t\tcase 0x8b5c: return setValueM4; // _MAT4
847
+
848
+ \t\tcase 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL
849
+ \t\tcase 0x8b53: case 0x8b57: return setValueV2i; // _VEC2
850
+ \t\tcase 0x8b54: case 0x8b58: return setValueV3i; // _VEC3
851
+ \t\tcase 0x8b55: case 0x8b59: return setValueV4i; // _VEC4
852
+
853
+ \t\tcase 0x1405: return setValueV1ui; // UINT
854
+ \t\tcase 0x8dc6: return setValueV2ui; // _VEC2
855
+ \t\tcase 0x8dc7: return setValueV3ui; // _VEC3
856
+ \t\tcase 0x8dc8: return setValueV4ui; // _VEC4
857
+
858
+ \t\tcase 0x8b5e: // SAMPLER_2D
859
+ \t\tcase 0x8d66: // SAMPLER_EXTERNAL_OES
860
+ \t\tcase 0x8dca: // INT_SAMPLER_2D
861
+ \t\tcase 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
862
+ \t\tcase 0x8b62: // SAMPLER_2D_SHADOW
863
+ \t\t\treturn setValueT1;
864
+
865
+ \t\tcase 0x8b5f: // SAMPLER_3D
866
+ \t\tcase 0x8dcb: // INT_SAMPLER_3D
867
+ \t\tcase 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
868
+ \t\t\treturn setValueT3D1;
869
+
870
+ \t\tcase 0x8b60: // SAMPLER_CUBE
871
+ \t\tcase 0x8dcc: // INT_SAMPLER_CUBE
872
+ \t\tcase 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
873
+ \t\tcase 0x8dc5: // SAMPLER_CUBE_SHADOW
874
+ \t\t\treturn setValueT6;
875
+
876
+ \t\tcase 0x8dc1: // SAMPLER_2D_ARRAY
877
+ \t\tcase 0x8dcf: // INT_SAMPLER_2D_ARRAY
878
+ \t\tcase 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
879
+ \t\tcase 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
880
+ \t\t\treturn setValueT2DArray1;`
881
+
882
+ const arraySetterCases = singularSetterCases
883
+ .replace(/return setValue(V[1-4](?:f|i|ui)|M[2-4]);/g, 'return setValue$1Array;')
884
+ .replace('return setValueT1;', 'return setValueT1Array;')
885
+ .replace('return setValueT3D1;', 'return setValueT3DArray;')
886
+ .replace('return setValueT6;', 'return setValueT6Array;')
887
+ .replace('return setValueT2DArray1;', 'return setValueT2DArrayArray;')
888
+
889
+ /**
890
+ * `WebGLUniforms.js`, typed end to end. Same tree, same parser, same setter
891
+ * table and the same per-uniform caches three keeps; the only change is what
892
+ * each setter is handed -- a `NativeUniformValue` it narrows with `instanceof`
893
+ * where three duck-typed `v.x`/`v.r`/`v.elements` -- and how a structured
894
+ * uniform reaches its members, through the light classes instead of `value[ id ]`.
895
+ */
896
+ // Fixed renderer names need no owning string parameter. Read the map on every
897
+ // call so replacement/deletion retains the same behavior as setValue.
898
+ // Build-time comparison switch; emitted code has no runtime branch.
899
+ export const nativeUniformNamesEnabled = process.env.GEA_WEBGL_UNIFORM_NAMES !== 'baseline'
900
+ export const nativeUniformBindingsEnabled = process.env.GEA_WEBGL_UNIFORM_BINDINGS !== 'baseline'
901
+ export const nativeFixedUniforms = [
902
+ ['projectionMatrix', 'Matrix4'],
903
+ ['viewMatrix', 'Matrix4'],
904
+ ['modelViewMatrix', 'Matrix4'],
905
+ ['normalMatrix', 'Matrix3'],
906
+ ['modelMatrix', 'Matrix4'],
907
+ ['toneMappingExposure', 'number'],
908
+ ['cameraPosition', 'Vector3'],
909
+ ...(nativeUniformBindingsEnabled ? [
910
+ ['directionalShadowMap', 'Array<Texture|null>', true],
911
+ ['spotShadowMap', 'Array<Texture|null>', true],
912
+ ['pointShadowMap', 'Array<Texture|null>', true],
913
+ ] : []),
914
+ ]
915
+ const fixedUniformMethods = nativeFixedUniforms.map(([name, type, textures]) => {
916
+ const matrix = type === 'Matrix3' || type === 'Matrix4'
917
+ return `
918
+ /** @param {${glContext}} gl @param {${type}} value ${textures ? '@param {NativeTextures|undefined} textures' : ''} */
919
+ set_${name}( gl, value${textures ? ', textures' : ''} ) {
920
+ const uniform = this.map.${name};
921
+ if ( uniform === undefined ) return;
922
+ ${matrix ? `if ( ! ( uniform instanceof SingleUniform ) ) throw new Error( 'THREE.WebGLUniforms: ${type} fast path requires a single uniform.' );
923
+ setNative${type}UniformValue( uniform, gl, value );` : `setNativeUniformValue( uniform, gl, value, ${textures ? 'textures' : 'undefined'} );`}
924
+ }
925
+ `
926
+ }).join('\n')
927
+
928
+
929
+ // Uniform nodes belong to the linked program: id/type/location remain fixed
930
+ // until relinking constructs new nodes. Cache only the name classification,
931
+ // never the material's value cells (which remain replaceable on every upload).
932
+ export const nativeUniformBindingNames = [
933
+ 'alphaMapTransform', 'ambientLightColor', 'bumpMapTransform',
934
+ 'directionalLights', 'directionalLightShadows', 'directionalShadowMap', 'directionalShadowMatrix',
935
+ 'displacementMapTransform', 'displacementScale', 'displacementBias',
936
+ 'emissiveMapTransform', 'hemisphereLights', 'lightMapIntensity', 'lightMapTransform',
937
+ 'metalnessMapTransform', 'normalMapTransform', 'pointLightShadows', 'pointShadowMatrix',
938
+ 'probesResolution', 'roughnessMapTransform', 'specularMapTransform', 'spotLightShadows',
939
+ ];
940
+ export const nativeUniformBindingHelpers = `
941
+ /** @param {string} id @return {number} */
942
+ function nativeUniformBindingSlot( id ) {
943
+ switch ( id ) {
944
+ case 'clippingPlanes': return -1;
945
+ ${nativeUniformBindingNames.map((name, i) => ` case '${name}': return ${i + 1};`).join('\n')}
946
+ default: return 0;
947
+ }
948
+ }
949
+ /** @param {NativeUniforms} values @param {NativeUniform} uniform @return {import('../shaders/UniformsLib.js').NativeUniformSlot|undefined} */
950
+ function nativeUniformBindingValue( values, uniform ) {
951
+ switch ( uniform.nativeBindingSlot ) {
952
+ ${nativeUniformBindingNames.map((name, i) => ` case ${i + 1}: return values.${name};`).join('\n')}
953
+ default: return values[ uniform.id ];
954
+ }
955
+ }
956
+ `;
957
+
958
+ const optimizedNativeWebGLUniformsSource = `import { CubeTexture } from '../../textures/CubeTexture.js';
959
+ import { Texture } from '../../textures/Texture.js';
960
+ import { DataArrayTexture } from '../../textures/DataArrayTexture.js';
961
+ import { Data3DTexture } from '../../textures/Data3DTexture.js';
962
+ import { DepthTexture } from '../../textures/DepthTexture.js';
963
+ import { LessEqualCompare, GreaterEqualCompare } from '../../constants.js';
964
+ import { WebGLTextures } from './WebGLTextures.js';
965
+ import { Color } from '../../math/Color.js';
966
+ import { Matrix2 } from '../../math/Matrix2.js';
967
+ import { Matrix3 } from '../../math/Matrix3.js';
968
+ import { Matrix4 } from '../../math/Matrix4.js';
969
+ import { Vector2 } from '../../math/Vector2.js';
970
+ import { Vector3 } from '../../math/Vector3.js';
971
+ import { Vector4 } from '../../math/Vector4.js';
972
+ import { isUniformNumberArray, isUniformTextureArray } from '../shaders/UniformsUtils.js';
973
+ import {
974
+ ${nativeLightUniformClassNames.map((name) => `\t${name},`).join('\n')}
975
+ } from '../shaders/UniformsLib.js';
976
+
977
+ /** @typedef {import('../shaders/UniformsLib.js').NativeUniformValue} NativeUniformValue */
978
+ /** @typedef {import('../shaders/UniformsLib.js').NativeUniforms} NativeUniforms */
979
+ /** @typedef {InstanceType<typeof WebGLTextures>} NativeTextures */
980
+ /** @typedef {{ name: string, type: number, size: number }} NativeActiveUniformInfo */
981
+ /** @typedef {SingleUniform|PureArrayUniform|StructuredUniform} NativeUniform */
982
+ /** @typedef {{ value: Float32Array|null, needsUpdate: boolean }} NativeClippingUniform */
983
+ /** @typedef {number[]|Float32Array} NativeFloatUniformArray */
984
+ /** @typedef {number[]|Int32Array} NativeIntUniformArray */
985
+ /** @typedef {number[]|Uint32Array} NativeUintUniformArray */
986
+ /** @typedef {(this: SingleUniform, gl: ${glContext}, value: NativeUniformValue, textures: NativeTextures|undefined) => void} NativeSingularUniformSetter */
987
+ /** @typedef {(this: PureArrayUniform, gl: ${glContext}, value: NativeUniformValue, textures: NativeTextures|undefined) => void} NativeArrayUniformSetter */
988
+
989
+ const emptyTexture = /*@__PURE__*/ new Texture();
990
+ const emptyShadowTexture = /*@__PURE__*/ new DepthTexture( 1, 1 );
991
+ const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture();
992
+ const empty3dTexture = /*@__PURE__*/ new Data3DTexture();
993
+ const emptyCubeTexture = /*@__PURE__*/ new CubeTexture();
994
+
995
+ const emptyFloatArray = new Float32Array( 0 );
996
+ const emptyIntArray = new Int32Array( 0 );
997
+ const emptyUintArray = new Uint32Array( 0 );
998
+
999
+ // --- Utilities ---
1000
+
1001
+ // Array Caches (provide typed arrays for temporary by size)
1002
+
1003
+ /** @type {Array<Float32Array|undefined>} */
1004
+ const arrayCacheF32 = [];
1005
+ /** @type {Array<Int32Array|undefined>} */
1006
+ const arrayCacheI32 = [];
1007
+
1008
+ // Float32Array caches used for uploading Matrix uniforms
1009
+
1010
+ const mat4array = new Float32Array( 16 );
1011
+ const mat3array = new Float32Array( 9 );
1012
+ const mat2array = new Float32Array( 4 );
1013
+
1014
+ /**
1015
+ * The value narrowings. three's setters duck-type their argument (\`v.x\`,
1016
+ * \`v.elements\`, \`firstElem <= 0 || firstElem > 0\`); over the union each test
1017
+ * is an \`instanceof\`/\`typeof\`, and a value of the wrong arm is a loud error
1018
+ * rather than an upload of garbage.
1019
+ */
1020
+
1021
+ /** @param {NativeUniformValue} value @return {number} */
1022
+ function requireUniformNumber( value ) {
1023
+
1024
+ \tif ( typeof value === 'number' ) return value;
1025
+
1026
+ \tthrow new Error( 'THREE.WebGLUniforms: uniform value must be a number.' );
1027
+
1028
+ }
1029
+
1030
+ /** @param {NativeUniformValue} value @return {NativeFloatUniformArray} */
1031
+ function requireFloatUniformArray( value ) {
1032
+
1033
+ \tif ( value instanceof Float32Array ) return value;
1034
+ \tif ( isUniformNumberArray( value ) ) return value;
1035
+ \tif ( Array.isArray( value ) && value.length === 0 ) return emptyFloatArray;
1036
+
1037
+ \tthrow new Error( 'THREE.WebGLUniforms: Float uniform value must be a number array or Float32Array.' );
1038
+
1039
+ }
1040
+
1041
+ /** @param {NativeUniformValue} value @return {NativeIntUniformArray} */
1042
+ function requireIntUniformArray( value ) {
1043
+
1044
+ \tif ( value instanceof Int32Array ) return value;
1045
+ \tif ( isUniformNumberArray( value ) ) return value;
1046
+ \tif ( Array.isArray( value ) && value.length === 0 ) return emptyIntArray;
1047
+
1048
+ \tthrow new Error( 'THREE.WebGLUniforms: Integer uniform value must be a number array or Int32Array.' );
1049
+
1050
+ }
1051
+
1052
+ /** @param {NativeUniformValue} value @return {NativeUintUniformArray} */
1053
+ function requireUintUniformArray( value ) {
1054
+
1055
+ \tif ( value instanceof Uint32Array ) return value;
1056
+ \tif ( isUniformNumberArray( value ) ) return value;
1057
+ \tif ( Array.isArray( value ) && value.length === 0 ) return emptyUintArray;
1058
+
1059
+ \tthrow new Error( 'THREE.WebGLUniforms: Unsigned integer uniform value must be a number array or Uint32Array.' );
1060
+
1061
+ }
1062
+
1063
+ /** @param {NativeUniformValue} value @return {Array<Texture|null>} */
1064
+ function requireTextureArray( value ) {
1065
+
1066
+ \tif ( isUniformTextureArray( value ) ) return value;
1067
+
1068
+ \tthrow new Error( 'THREE.WebGLUniforms: sampler array uniform value must be an array of textures.' );
1069
+
1070
+ }
1071
+
1072
+ /** @param {NativeUniformValue} value @param {Texture} fallback @return {Texture} */
1073
+ function uniformTextureOr( value, fallback ) {
1074
+
1075
+ \tif ( value instanceof Texture ) return value;
1076
+ \tif ( value === null || value === undefined || value === false ) return fallback;
1077
+
1078
+ \tthrow new Error( 'THREE.WebGLUniforms: sampler uniform value must be a texture.' );
1079
+
1080
+ }
1081
+
1082
+ /** @param {NativeTextures|undefined} textures @return {NativeTextures} */
1083
+ function requireTextures( textures ) {
1084
+
1085
+ \tif ( textures === undefined ) throw new Error( 'THREE.WebGLUniforms: sampler uniforms need the texture manager.' );
1086
+
1087
+ \treturn textures;
1088
+
1089
+ }
1090
+
1091
+ /**
1092
+ * One element of an object array, written into the flat upload buffer. three
1093
+ * calls \`element.toArray( r, offset )\` on whatever the element is; over the
1094
+ * union the element is narrowed to the classes that have a fixed layout.
1095
+ * @param {NativeUniformValue} value @param {Float32Array} target @param {number} offset @param {number} blockSize
1096
+ */
1097
+ function copyUniformElement( value, target, offset, blockSize ) {
1098
+
1099
+ \tif ( value instanceof Matrix2 ) {
1100
+
1101
+ \t\tif ( blockSize !== 4 ) throw new Error( 'THREE.WebGLUniforms: Matrix2 block size mismatch.' );
1102
+ \t\tfor ( let i = 0; i < 4; i ++ ) target[ offset + i ] = value.elements[ i ];
1103
+ \t\treturn;
1104
+
1105
+ \t}
1106
+
1107
+ \tif ( value instanceof Matrix3 ) {
1108
+
1109
+ \t\tif ( blockSize !== 9 ) throw new Error( 'THREE.WebGLUniforms: Matrix3 block size mismatch.' );
1110
+ \t\tfor ( let i = 0; i < 9; i ++ ) target[ offset + i ] = value.elements[ i ];
1111
+ \t\treturn;
1112
+
1113
+ \t}
1114
+
1115
+ \tif ( value instanceof Matrix4 ) {
1116
+
1117
+ \t\tif ( blockSize !== 16 ) throw new Error( 'THREE.WebGLUniforms: Matrix4 block size mismatch.' );
1118
+ \t\tfor ( let i = 0; i < 16; i ++ ) target[ offset + i ] = value.elements[ i ];
1119
+ \t\treturn;
1120
+
1121
+ \t}
1122
+
1123
+ \tif ( value instanceof Color ) {
1124
+
1125
+ \t\tif ( blockSize !== 3 ) throw new Error( 'THREE.WebGLUniforms: Color block size mismatch.' );
1126
+ \t\ttarget[ offset ] = value.r;
1127
+ \t\ttarget[ offset + 1 ] = value.g;
1128
+ \t\ttarget[ offset + 2 ] = value.b;
1129
+ \t\treturn;
1130
+
1131
+ \t}
1132
+
1133
+ \tif ( value instanceof Vector2 ) {
1134
+
1135
+ \t\tif ( blockSize !== 2 ) throw new Error( 'THREE.WebGLUniforms: Vector2 block size mismatch.' );
1136
+ \t\ttarget[ offset ] = value.x;
1137
+ \t\ttarget[ offset + 1 ] = value.y;
1138
+ \t\treturn;
1139
+
1140
+ \t}
1141
+
1142
+ \tif ( value instanceof Vector3 ) {
1143
+
1144
+ \t\tif ( blockSize !== 3 ) throw new Error( 'THREE.WebGLUniforms: Vector3 block size mismatch.' );
1145
+ \t\ttarget[ offset ] = value.x;
1146
+ \t\ttarget[ offset + 1 ] = value.y;
1147
+ \t\ttarget[ offset + 2 ] = value.z;
1148
+ \t\treturn;
1149
+
1150
+ \t}
1151
+
1152
+ \tif ( value instanceof Vector4 ) {
1153
+
1154
+ \t\tif ( blockSize !== 4 ) throw new Error( 'THREE.WebGLUniforms: Vector4 block size mismatch.' );
1155
+ \t\ttarget[ offset ] = value.x;
1156
+ \t\ttarget[ offset + 1 ] = value.y;
1157
+ \t\ttarget[ offset + 2 ] = value.z;
1158
+ \t\ttarget[ offset + 3 ] = value.w;
1159
+ \t\treturn;
1160
+
1161
+ \t}
1162
+
1163
+ \tthrow new Error( 'THREE.WebGLUniforms: uniform array element has no flat layout.' );
1164
+
1165
+ }
1166
+
1167
+ // Flattening for arrays of vectors and matrices
1168
+
1169
+ /** @param {NativeUniformValue} array @param {number} nBlocks @param {number} blockSize @return {NativeFloatUniformArray} */
1170
+ function flatten( array, nBlocks, blockSize ) {
1171
+
1172
+ \tif ( array instanceof Float32Array ) return array;
1173
+ \tif ( isUniformNumberArray( array ) ) return array;
1174
+
1175
+ \tconst n = nBlocks * blockSize;
1176
+ \tlet r = arrayCacheF32[ n ];
1177
+
1178
+ \tif ( r === undefined ) {
1179
+
1180
+ \t\tr = new Float32Array( n );
1181
+ \t\tarrayCacheF32[ n ] = r;
1182
+
1183
+ \t}
1184
+
1185
+ \tif ( nBlocks !== 0 ) {
1186
+
1187
+ \t\tif ( ! Array.isArray( array ) ) throw new Error( 'THREE.WebGLUniforms: uniform array value must be an array.' );
1188
+
1189
+ \t\tlet offset = 0;
1190
+
1191
+ \t\tfor ( let i = 0; i !== nBlocks; ++ i ) {
1192
+
1193
+ \t\t\tcopyUniformElement( array[ i ], r, offset, blockSize );
1194
+ \t\t\toffset += blockSize;
1195
+
1196
+ \t\t}
1197
+
1198
+ \t}
1199
+
1200
+ \treturn r;
1201
+
1202
+ }
1203
+
1204
+ /** @param {number[]} a @param {number[]|Float32Array|Int32Array|Uint32Array} b */
1205
+ function arraysEqual( a, b ) {
1206
+
1207
+ \tif ( a.length !== b.length ) return false;
1208
+
1209
+ \tfor ( let i = 0, l = a.length; i < l; i ++ ) {
1210
+
1211
+ \t\tif ( a[ i ] !== b[ i ] ) return false;
1212
+
1213
+ \t}
1214
+
1215
+ \treturn true;
1216
+
1217
+ }
1218
+
1219
+ /** @param {number[]} a @param {number[]|Float32Array|Int32Array|Uint32Array} b */
1220
+ function copyArray( a, b ) {
1221
+
1222
+ \ta.length = b.length;
1223
+
1224
+ \tfor ( let i = 0, l = b.length; i < l; i ++ ) {
1225
+
1226
+ \t\ta[ i ] = b[ i ];
1227
+
1228
+ \t}
1229
+
1230
+ }
1231
+
1232
+ // Texture unit allocation
1233
+
1234
+ /** @param {NativeTextures} textures @param {number} n @return {Int32Array} */
1235
+ function allocTexUnits( textures, n ) {
1236
+
1237
+ \tlet r = arrayCacheI32[ n ];
1238
+
1239
+ \tif ( r === undefined ) {
1240
+
1241
+ \t\tr = new Int32Array( n );
1242
+ \t\tarrayCacheI32[ n ] = r;
1243
+
1244
+ \t}
1245
+
1246
+ \tfor ( let i = 0; i !== n; ++ i ) {
1247
+
1248
+ \t\tr[ i ] = textures.allocateTextureUnit();
1249
+
1250
+ \t}
1251
+
1252
+ \treturn r;
1253
+
1254
+ }
1255
+
1256
+ // --- Setters ---
1257
+
1258
+ // Note: Defining these methods externally, because they come in a bunch
1259
+ // and this way their names minify.
1260
+
1261
+ // Single scalar
1262
+
1263
+ ${scalarSetter('setValueV1f', 'uniform1f', false)}
1264
+
1265
+ // Single float vector (from flat array or THREE.VectorN)
1266
+
1267
+ ${vectorSetter('setValueV2f', 2, 'Vector2', 'uniform2f', 'uniform2fv', 'requireFloatUniformArray')}
1268
+
1269
+ ${setterHeader('SingleUniform')}
1270
+ function setValueV3f( gl, v, textures ) {
1271
+
1272
+ \tconst cache = this.cache;
1273
+
1274
+ \tif ( v instanceof Vector3 ) {
1275
+
1276
+ \t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
1277
+
1278
+ \t\t\tgl.uniform3f( this.addr, v.x, v.y, v.z );
1279
+
1280
+ \t\t\tcache[ 0 ] = v.x;
1281
+ \t\t\tcache[ 1 ] = v.y;
1282
+ \t\t\tcache[ 2 ] = v.z;
1283
+
1284
+ \t\t}
1285
+
1286
+ \t} else if ( v instanceof Color ) {
1287
+
1288
+ \t\tif ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
1289
+
1290
+ \t\t\tgl.uniform3f( this.addr, v.r, v.g, v.b );
1291
+
1292
+ \t\t\tcache[ 0 ] = v.r;
1293
+ \t\t\tcache[ 1 ] = v.g;
1294
+ \t\t\tcache[ 2 ] = v.b;
1295
+
1296
+ \t\t}
1297
+
1298
+ \t} else {
1299
+
1300
+ \t\tconst flatValue = requireFloatUniformArray( v );
1301
+
1302
+ \t\tif ( arraysEqual( cache, flatValue ) ) return;
1303
+
1304
+ \t\tgl.uniform3fv( this.addr, flatValue );
1305
+
1306
+ \t\tcopyArray( cache, flatValue );
1307
+
1308
+ \t}
1309
+
1310
+ }
1311
+
1312
+ ${vectorSetter('setValueV4f', 4, 'Vector4', 'uniform4f', 'uniform4fv', 'requireFloatUniformArray')}
1313
+
1314
+ // Single matrix (from flat array or THREE.MatrixN)
1315
+
1316
+ ${matrixSetter('setValueM2', 2, 'Matrix2', 'uniformMatrix2fv', 'mat2array')}
1317
+
1318
+ ${matrixSetter('setValueM3', 3, 'Matrix3', 'uniformMatrix3fv', 'mat3array')}
1319
+
1320
+ ${matrixSetter('setValueM4', 4, 'Matrix4', 'uniformMatrix4fv', 'mat4array')}
1321
+
1322
+ // Single integer / boolean
1323
+
1324
+ ${scalarSetter('setValueV1i', 'uniform1i', true)}
1325
+
1326
+ // Single integer / boolean vector (from flat array or THREE.VectorN)
1327
+
1328
+ ${vectorSetter('setValueV2i', 2, 'Vector2', 'uniform2i', 'uniform2iv', 'requireIntUniformArray')}
1329
+
1330
+ ${vectorSetter('setValueV3i', 3, 'Vector3', 'uniform3i', 'uniform3iv', 'requireIntUniformArray')}
1331
+
1332
+ ${vectorSetter('setValueV4i', 4, 'Vector4', 'uniform4i', 'uniform4iv', 'requireIntUniformArray')}
1333
+
1334
+ // Single unsigned integer
1335
+
1336
+ ${scalarSetter('setValueV1ui', 'uniform1ui', true)}
1337
+
1338
+ // Single unsigned integer vector (from flat array or THREE.VectorN)
1339
+
1340
+ ${vectorSetter('setValueV2ui', 2, 'Vector2', 'uniform2ui', 'uniform2uiv', 'requireUintUniformArray')}
1341
+
1342
+ ${vectorSetter('setValueV3ui', 3, 'Vector3', 'uniform3ui', 'uniform3uiv', 'requireUintUniformArray')}
1343
+
1344
+ ${vectorSetter('setValueV4ui', 4, 'Vector4', 'uniform4ui', 'uniform4uiv', 'requireUintUniformArray')}
1345
+
1346
+ // Single texture (2D / Cube)
1347
+
1348
+ ${textureSetter('setValueT1', 'setTexture2D', 'emptyTexture', true)}
1349
+
1350
+ ${textureSetter('setValueT3D1', 'setTexture3D', 'empty3dTexture', false)}
1351
+
1352
+ ${textureSetter('setValueT6', 'setTextureCube', 'emptyCubeTexture', false)}
1353
+
1354
+ ${textureSetter('setValueT2DArray1', 'setTexture2DArray', 'emptyArrayTexture', false)}
1355
+
1356
+ // Helper to pick the right setter for the singular case
1357
+
1358
+ /** @param {number} type @return {NativeSingularUniformSetter} */
1359
+ function getSingularSetter( type ) {
1360
+
1361
+ \tswitch ( type ) {
1362
+
1363
+ ${singularSetterCases}
1364
+
1365
+ \t}
1366
+
1367
+ \tthrow new Error( 'THREE.WebGLUniforms: Unsupported singular uniform type.' );
1368
+
1369
+ }
1370
+
1371
+ // Array of scalars
1372
+
1373
+ ${flatArraySetter('setValueV1fArray', 'uniform1fv', 'requireFloatUniformArray')}
1374
+
1375
+ // Array of vectors (from flat array or array of THREE.VectorN)
1376
+
1377
+ ${flattenedArraySetter('setValueV2fArray', 2, 'uniform2fv', false)}
1378
+
1379
+ ${flattenedArraySetter('setValueV3fArray', 3, 'uniform3fv', false)}
1380
+
1381
+ ${flattenedArraySetter('setValueV4fArray', 4, 'uniform4fv', false)}
1382
+
1383
+ // Array of matrices (from flat array or array of THREE.MatrixN)
1384
+
1385
+ ${flattenedArraySetter('setValueM2Array', 4, 'uniformMatrix2fv', true)}
1386
+
1387
+ ${flattenedArraySetter('setValueM3Array', 9, 'uniformMatrix3fv', true)}
1388
+
1389
+ ${flattenedArraySetter('setValueM4Array', 16, 'uniformMatrix4fv', true)}
1390
+
1391
+ // Array of integer / boolean
1392
+
1393
+ ${flatArraySetter('setValueV1iArray', 'uniform1iv', 'requireIntUniformArray')}
1394
+
1395
+ // Array of integer / boolean vectors (from flat array)
1396
+
1397
+ ${flatArraySetter('setValueV2iArray', 'uniform2iv', 'requireIntUniformArray')}
1398
+
1399
+ ${flatArraySetter('setValueV3iArray', 'uniform3iv', 'requireIntUniformArray')}
1400
+
1401
+ ${flatArraySetter('setValueV4iArray', 'uniform4iv', 'requireIntUniformArray')}
1402
+
1403
+ // Array of unsigned integer
1404
+
1405
+ ${flatArraySetter('setValueV1uiArray', 'uniform1uiv', 'requireUintUniformArray')}
1406
+
1407
+ // Array of unsigned integer vectors (from flat array)
1408
+
1409
+ ${flatArraySetter('setValueV2uiArray', 'uniform2uiv', 'requireUintUniformArray')}
1410
+
1411
+ ${flatArraySetter('setValueV3uiArray', 'uniform3uiv', 'requireUintUniformArray')}
1412
+
1413
+ ${flatArraySetter('setValueV4uiArray', 'uniform4uiv', 'requireUintUniformArray')}
1414
+
1415
+ // Array of textures (2D / 3D / Cube / 2DArray)
1416
+
1417
+ ${textureArraySetter('setValueT1Array', 'setTexture2D', 'emptyTexture', true)}
1418
+
1419
+ ${textureArraySetter('setValueT3DArray', 'setTexture3D', 'empty3dTexture', false)}
1420
+
1421
+ ${textureArraySetter('setValueT6Array', 'setTextureCube', 'emptyCubeTexture', false)}
1422
+
1423
+ ${textureArraySetter('setValueT2DArrayArray', 'setTexture2DArray', 'emptyArrayTexture', false)}
1424
+
1425
+ // Helper to pick the right setter for a pure (bottom-level) array
1426
+
1427
+ /** @param {number} type @return {NativeArrayUniformSetter} */
1428
+ function getPureArraySetter( type ) {
1429
+
1430
+ \tswitch ( type ) {
1431
+
1432
+ ${arraySetterCases}
1433
+
1434
+ \t}
1435
+
1436
+ \tthrow new Error( 'THREE.WebGLUniforms: Unsupported array uniform type.' );
1437
+
1438
+ }
1439
+
1440
+ ${nativeUniformBindingsEnabled ? nativeUniformBindingHelpers : ''}
1441
+
1442
+ // --- Uniform Classes ---
1443
+
1444
+ class SingleUniform {
1445
+
1446
+ \t/** @param {string} id @param {NativeActiveUniformInfo} activeInfo @param {${glHandle}} addr */
1447
+ \tconstructor( id, activeInfo, addr ) {
1448
+
1449
+ \t\tthis.id = id;
1450
+ ${nativeUniformBindingsEnabled ? '\t\tthis.nativeBindingSlot = nativeUniformBindingSlot( id );' : ''}
1451
+ \t\tthis.addr = addr;
1452
+ \t\t// A native number[] read past its length is not \`undefined\`, so the
1453
+ \t\t// cache starts with four slots no value compares equal to.
1454
+ \t\t/** @type {number[]} */
1455
+ \t\tthis.cache = [ NaN, NaN, NaN, NaN ];
1456
+ \t\tthis.type = activeInfo.type;
1457
+ \t\tthis.setValue = getSingularSetter( activeInfo.type );
1458
+
1459
+ \t\t// this.path = activeInfo.name; // DEBUG
1460
+
1461
+ \t}
1462
+
1463
+ }
1464
+
1465
+ class PureArrayUniform {
1466
+
1467
+ \t/** @param {string} id @param {NativeActiveUniformInfo} activeInfo @param {${glHandle}} addr */
1468
+ \tconstructor( id, activeInfo, addr ) {
1469
+
1470
+ \t\tthis.id = id;
1471
+ ${nativeUniformBindingsEnabled ? '\t\tthis.nativeBindingSlot = nativeUniformBindingSlot( id );' : ''}
1472
+ \t\tthis.addr = addr;
1473
+ \t\t// A native number[] read past its length is not \`undefined\`, so the
1474
+ \t\t// cache starts with four slots no value compares equal to.
1475
+ \t\t/** @type {number[]} */
1476
+ \t\tthis.cache = [ NaN, NaN, NaN, NaN ];
1477
+ \t\tthis.type = activeInfo.type;
1478
+ \t\tthis.size = activeInfo.size;
1479
+ \t\tthis.setValue = getPureArraySetter( activeInfo.type );
1480
+
1481
+ \t\t// this.path = activeInfo.name; // DEBUG
1482
+
1483
+ \t}
1484
+
1485
+ }
1486
+
1487
+ /**
1488
+ * The member a structured uniform's step reads: three writes \`value[ u.id ]\`,
1489
+ * where the value is an array (id is the index) or a light-uniform record
1490
+ * (id is the field name). The light records are classes, so the read is a
1491
+ * narrowed field read; an array indexes whichever arm it is.
1492
+ * @param {NativeUniformValue} value @param {string} id @return {NativeUniformValue}
1493
+ */
1494
+ function structuredUniformMember( value, id ) {
1495
+
1496
+ \tif ( Array.isArray( value ) ) return value[ Number( id ) ];
1497
+
1498
+ \tif ( value instanceof NativeDirectionalLightUniform ) {
1499
+
1500
+ \t\tif ( id === 'direction' ) return value.direction;
1501
+ \t\tif ( id === 'color' ) return value.color;
1502
+
1503
+ \t} else if ( value instanceof NativeSpotLightUniform ) {
1504
+
1505
+ \t\tif ( id === 'position' ) return value.position;
1506
+ \t\tif ( id === 'direction' ) return value.direction;
1507
+ \t\tif ( id === 'color' ) return value.color;
1508
+ \t\tif ( id === 'distance' ) return value.distance;
1509
+ \t\tif ( id === 'coneCos' ) return value.coneCos;
1510
+ \t\tif ( id === 'penumbraCos' ) return value.penumbraCos;
1511
+ \t\tif ( id === 'decay' ) return value.decay;
1512
+
1513
+ \t} else if ( value instanceof NativePointLightUniform ) {
1514
+
1515
+ \t\tif ( id === 'position' ) return value.position;
1516
+ \t\tif ( id === 'color' ) return value.color;
1517
+ \t\tif ( id === 'distance' ) return value.distance;
1518
+ \t\tif ( id === 'decay' ) return value.decay;
1519
+
1520
+ \t} else if ( value instanceof NativeHemisphereLightUniform ) {
1521
+
1522
+ \t\tif ( id === 'direction' ) return value.direction;
1523
+ \t\tif ( id === 'skyColor' ) return value.skyColor;
1524
+ \t\tif ( id === 'groundColor' ) return value.groundColor;
1525
+
1526
+ \t} else if ( value instanceof NativeRectAreaLightUniform ) {
1527
+
1528
+ \t\tif ( id === 'color' ) return value.color;
1529
+ \t\tif ( id === 'position' ) return value.position;
1530
+ \t\tif ( id === 'halfWidth' ) return value.halfWidth;
1531
+ \t\tif ( id === 'halfHeight' ) return value.halfHeight;
1532
+
1533
+ \t} else if ( value instanceof NativeShadowUniform ) {
1534
+
1535
+ \t\tif ( id === 'shadowIntensity' ) return value.shadowIntensity;
1536
+ \t\tif ( id === 'shadowBias' ) return value.shadowBias;
1537
+ \t\tif ( id === 'shadowNormalBias' ) return value.shadowNormalBias;
1538
+ \t\tif ( id === 'shadowRadius' ) return value.shadowRadius;
1539
+ \t\tif ( id === 'shadowMapSize' ) return value.shadowMapSize;
1540
+
1541
+ \t} else if ( value instanceof NativePointShadowUniform ) {
1542
+
1543
+ \t\tif ( id === 'shadowIntensity' ) return value.shadowIntensity;
1544
+ \t\tif ( id === 'shadowBias' ) return value.shadowBias;
1545
+ \t\tif ( id === 'shadowNormalBias' ) return value.shadowNormalBias;
1546
+ \t\tif ( id === 'shadowRadius' ) return value.shadowRadius;
1547
+ \t\tif ( id === 'shadowMapSize' ) return value.shadowMapSize;
1548
+ \t\tif ( id === 'shadowCameraNear' ) return value.shadowCameraNear;
1549
+ \t\tif ( id === 'shadowCameraFar' ) return value.shadowCameraFar;
1550
+
1551
+ \t}
1552
+
1553
+ \tthrow new Error( 'THREE.WebGLUniforms: structured uniform has no member ' + id + '.' );
1554
+
1555
+ }
1556
+
1557
+ class StructuredUniform {
1558
+
1559
+ \t/** @param {string} id */
1560
+ \tconstructor( id ) {
1561
+
1562
+ \t\tthis.id = id;
1563
+ ${nativeUniformBindingsEnabled ? '\t\tthis.nativeBindingSlot = nativeUniformBindingSlot( id );' : ''}
1564
+
1565
+ \t\t/** @type {NativeUniform[]} */
1566
+ \t\tthis.seq = [];
1567
+ \t\t/** @type {Record<string, NativeUniform>} */
1568
+ \t\tthis.map = {};
1569
+
1570
+ \t}
1571
+
1572
+ \t/** @param {${glContext}} gl @param {NativeUniformValue} value @param {NativeTextures|undefined} textures @return {void} */
1573
+ \tsetValue( gl, value, textures ) {
1574
+
1575
+ \t\tconst seq = this.seq;
1576
+
1577
+ \t\tfor ( let i = 0, n = seq.length; i !== n; ++ i ) {
1578
+
1579
+ \t\t\tconst u = seq[ i ];
1580
+ \t\t\tsetNativeUniformValue( u, gl, structuredUniformMember( value, u.id ), textures );
1581
+
1582
+ \t\t}
1583
+
1584
+ \t}
1585
+
1586
+ }
1587
+
1588
+ /**
1589
+ * Three kinds of uniform node, one dispatch: \`u.setValue\` is a field on the
1590
+ * two leaf classes and a method on the structured one, so the call is placed
1591
+ * behind an \`instanceof\` split rather than through the union.
1592
+ * @param {NativeUniform} uniform @param {${glContext}} gl @param {NativeUniformValue} value @param {NativeTextures|undefined} textures
1593
+ */
1594
+ function setNativeUniformValue( uniform, gl, value, textures ) {
1595
+
1596
+ \tif ( uniform instanceof SingleUniform ) uniform.setValue( gl, value, textures );
1597
+ \telse if ( uniform instanceof PureArrayUniform ) uniform.setValue( gl, value, textures );
1598
+ \telse uniform.setValue( gl, value, textures );
1599
+
1600
+ }
1601
+
1602
+ // --- Top-level ---
1603
+
1604
+ // Parser - builds up the property tree from the path strings
1605
+
1606
+ const RePathPart = /(\\w+)(\\])?(\\[|\\.)?/g;
1607
+
1608
+ // extracts
1609
+ // - the identifier (member name or array index)
1610
+ // - followed by an optional right bracket (found when array index)
1611
+ // - followed by an optional left bracket or dot (type of subscript)
1612
+ //
1613
+ // Note: These portions can be read in a non-overlapping fashion and
1614
+ // allow straightforward parsing of the hierarchy that WebGL encodes
1615
+ // in the uniform names.
1616
+
1617
+ /** @param {StructuredUniform|WebGLUniforms} container @param {NativeUniform} uniformObject */
1618
+ function addUniform( container, uniformObject ) {
1619
+
1620
+ \tcontainer.seq.push( uniformObject );
1621
+ \tcontainer.map[ uniformObject.id ] = uniformObject;
1622
+
1623
+ }
1624
+
1625
+ /** @param {NativeActiveUniformInfo} activeInfo @param {${glHandle}} addr @param {StructuredUniform|WebGLUniforms} container */
1626
+ function parseUniform( activeInfo, addr, container ) {
1627
+
1628
+ \tconst path = activeInfo.name,
1629
+ \t\tpathLength = path.length;
1630
+
1631
+ \t// reset RegExp object, because of the early exit of a previous run
1632
+ \tRePathPart.lastIndex = 0;
1633
+
1634
+ \twhile ( true ) {
1635
+
1636
+ \t\tconst match = RePathPart.exec( path ),
1637
+ \t\t\tmatchEnd = RePathPart.lastIndex;
1638
+
1639
+ \t\tconst id = match[ 1 ];
1640
+ \t\tconst subscript = match[ 3 ];
1641
+
1642
+ \t\t// Native uniform maps use string keys; an array index stays the string
1643
+ \t\t// it was parsed from and is converted where it indexes an array.
1644
+ \t\tif ( subscript === '' || subscript === '[' && matchEnd + 2 === pathLength ) {
1645
+
1646
+ \t\t\t// bare name or "pure" bottom-level array "[0]" suffix
1647
+
1648
+ \t\t\taddUniform( container, subscript === '' ?
1649
+ \t\t\t\tnew SingleUniform( id, activeInfo, addr ) :
1650
+ \t\t\t\tnew PureArrayUniform( id, activeInfo, addr ) );
1651
+
1652
+ \t\t\tbreak;
1653
+
1654
+ \t\t} else {
1655
+
1656
+ \t\t\t// step into inner node / create it in case it doesn't exist
1657
+
1658
+ \t\t\tconst map = container.map;
1659
+ \t\t\tlet next = map[ id ];
1660
+
1661
+ \t\t\tif ( next === undefined ) {
1662
+
1663
+ \t\t\t\tnext = new StructuredUniform( id );
1664
+ \t\t\t\taddUniform( container, next );
1665
+
1666
+ \t\t\t}
1667
+
1668
+ \t\t\tcontainer = next;
1669
+
1670
+ \t\t}
1671
+
1672
+ \t}
1673
+
1674
+ }
1675
+
1676
+ /** @param {SingleUniform} uniform @param {${glContext}} gl @param {Matrix3} value */
1677
+ function setNativeMatrix3UniformValue( uniform, gl, value ) {
1678
+
1679
+ \tconst cache = uniform.cache;
1680
+ \tconst elements = value.elements;
1681
+
1682
+ \tif ( arraysEqual( cache, elements ) ) return;
1683
+
1684
+ \tgl.uniformMatrix3fv( uniform.addr, false, elements );
1685
+ \tcopyArray( cache, elements );
1686
+
1687
+ }
1688
+
1689
+ /** @param {SingleUniform} uniform @param {${glContext}} gl @param {Matrix4} value */
1690
+ function setNativeMatrix4UniformValue( uniform, gl, value ) {
1691
+
1692
+ \tconst cache = uniform.cache;
1693
+ \tconst elements = value.elements;
1694
+
1695
+ \tif ( arraysEqual( cache, elements ) ) return;
1696
+
1697
+ \tgl.uniformMatrix4fv( uniform.addr, false, elements );
1698
+ \tcopyArray( cache, elements );
1699
+
1700
+ }
1701
+
1702
+ // Root Container
1703
+
1704
+ class WebGLUniforms {
1705
+
1706
+ \t/** @param {${glContext}} gl @param {${glHandle}} program */
1707
+ \tconstructor( gl, program ) {
1708
+
1709
+ \t\t/** @type {NativeUniform[]} */
1710
+ \t\tthis.seq = [];
1711
+ \t\t/** @type {Record<string, NativeUniform>} */
1712
+ \t\tthis.map = {};
1713
+
1714
+ \t\tconst n = /** @type {number} */ ( gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ) );
1715
+
1716
+ \t\tfor ( let i = 0; i < n; ++ i ) {
1717
+
1718
+ \t\t\tconst info = /** @type {NativeActiveUniformInfo|null} */ ( gl.getActiveUniform( program, i ) );
1719
+
1720
+ \t\t\tif ( info === null ) continue;
1721
+
1722
+ \t\t\tconst addr = gl.getUniformLocation( program, info.name );
1723
+
1724
+ \t\t\tparseUniform( info, addr, this );
1725
+
1726
+ \t\t}
1727
+
1728
+ \t\t// Sort uniforms to prioritize shadow samplers first (for optimal texture unit allocation)
1729
+
1730
+ \t\t/** @type {NativeUniform[]} */
1731
+ \t\tconst shadowSamplers = [];
1732
+ \t\t/** @type {NativeUniform[]} */
1733
+ \t\tconst otherUniforms = [];
1734
+
1735
+ \t\tfor ( const u of this.seq ) {
1736
+
1737
+ \t\t\tif ( u.type === gl.SAMPLER_2D_SHADOW || u.type === gl.SAMPLER_CUBE_SHADOW || u.type === gl.SAMPLER_2D_ARRAY_SHADOW ) {
1738
+
1739
+ \t\t\t\tshadowSamplers.push( u );
1740
+
1741
+ \t\t\t} else {
1742
+
1743
+ \t\t\t\totherUniforms.push( u );
1744
+
1745
+ \t\t\t}
1746
+
1747
+ \t\t}
1748
+
1749
+ \t\tif ( shadowSamplers.length > 0 ) {
1750
+
1751
+ \t\t\tfor ( const otherUniform of otherUniforms ) shadowSamplers.push( otherUniform );
1752
+
1753
+ \t\t\tthis.seq = shadowSamplers;
1754
+
1755
+ \t\t}
1756
+
1757
+ \t}
1758
+
1759
+ ${fixedUniformMethods}
1760
+ \t/** @param {${glContext}} gl @param {string} name @param {Matrix3} value */
1761
+ \tsetMatrix3Value( gl, name, value ) {
1762
+
1763
+ \t\tconst uniform = this.map[ name ];
1764
+
1765
+ \t\tif ( uniform === undefined ) return;
1766
+ \t\tif ( uniform instanceof SingleUniform ) {
1767
+
1768
+ \t\t\tsetNativeMatrix3UniformValue( uniform, gl, value );
1769
+ \t\t\treturn;
1770
+
1771
+ \t\t}
1772
+
1773
+ \t\tthrow new Error( 'THREE.WebGLUniforms: Matrix3 fast path requires a single uniform.' );
1774
+
1775
+ \t}
1776
+
1777
+ \t/** @param {${glContext}} gl @param {string} name @param {Matrix4} value */
1778
+ \tsetMatrix4Value( gl, name, value ) {
1779
+
1780
+ \t\tconst uniform = this.map[ name ];
1781
+
1782
+ \t\tif ( uniform === undefined ) return;
1783
+ \t\tif ( uniform instanceof SingleUniform ) {
1784
+
1785
+ \t\t\tsetNativeMatrix4UniformValue( uniform, gl, value );
1786
+ \t\t\treturn;
1787
+
1788
+ \t\t}
1789
+
1790
+ \t\tthrow new Error( 'THREE.WebGLUniforms: Matrix4 fast path requires a single uniform.' );
1791
+
1792
+ \t}
1793
+
1794
+ \t/** @param {${glContext}} gl @param {string} name @param {NativeUniformValue} value @param {NativeTextures|undefined} textures @return {void} */
1795
+ \tsetValue( gl, name, value, textures ) {
1796
+
1797
+ \t\tconst u = this.map[ name ];
1798
+
1799
+ \t\tif ( u !== undefined ) setNativeUniformValue( u, gl, value, textures );
1800
+
1801
+ \t}
1802
+
1803
+ \t// three's \`setOptional( gl, object, name )\` -- a dynamic \`object[ name ]\`
1804
+ \t// read -- has no caller in this build: the renderer's four uses are
1805
+ \t// direct, typed uploads (\`setMatrix4Value\` for the bind matrices; the
1806
+ \t// batching textures upload their own value on the line below each).
1807
+
1808
+ \t/** @param {${glContext}} gl @param {NativeUniform[]} seq @param {NativeUniforms} values @param {NativeTextures|undefined} textures @param {NativeClippingUniform|undefined} clippingPlanes */
1809
+ \tstatic upload( gl, seq, values, textures, clippingPlanes ) {
1810
+
1811
+ \t\tfor ( let i = 0, n = seq.length; i !== n; ++ i ) {
1812
+
1813
+ \t\t\tconst u = seq[ i ];
1814
+
1815
+ \t\t\tif ( ${nativeUniformBindingsEnabled ? 'u.nativeBindingSlot === -1' : "u.id === 'clippingPlanes'"} && clippingPlanes !== undefined ) {
1816
+
1817
+ \t\t\t\tif ( clippingPlanes.needsUpdate !== false ) setNativeUniformValue( u, gl, clippingPlanes.value, textures );
1818
+ \t\t\t\tcontinue;
1819
+
1820
+ \t\t\t}
1821
+
1822
+ \t\t\tconst v = ${nativeUniformBindingsEnabled ? 'nativeUniformBindingValue( values, u )' : 'values[ u.id ]'};
1823
+
1824
+ \t\t\tif ( v.needsUpdate !== false ) {
1825
+
1826
+ \t\t\t\t// note: always updating when .needsUpdate is undefined
1827
+ \t\t\t\tsetNativeUniformValue( u, gl, v.value, textures );
1828
+
1829
+ \t\t\t}
1830
+
1831
+ \t\t}
1832
+
1833
+ \t}
1834
+
1835
+ \t/** @param {NativeUniform[]} seq @param {NativeUniforms} values @param {NativeClippingUniform|undefined} clippingPlanes @return {NativeUniform[]} */
1836
+ \tstatic seqWithValue( seq, values, clippingPlanes ) {
1837
+
1838
+ \t\t/** @type {NativeUniform[]} */
1839
+ \t\tconst r = [];
1840
+
1841
+ \t\tfor ( let i = 0, n = seq.length; i !== n; ++ i ) {
1842
+
1843
+ \t\t\tconst u = seq[ i ];
1844
+
1845
+ \t\t\tif ( u.id === 'clippingPlanes' ) {
1846
+
1847
+ \t\t\t\tif ( clippingPlanes !== undefined ) r.push( u );
1848
+ \t\t\t\tcontinue;
1849
+
1850
+ \t\t\t}
1851
+
1852
+ \t\t\tif ( u.id in values ) r.push( u );
1853
+
1854
+ \t\t}
1855
+
1856
+ \t\treturn r;
1857
+
1858
+ \t}
1859
+
1860
+ }
1861
+
1862
+ export { WebGLUniforms };
1863
+ `
1864
+
1865
+
1866
+ export const nativeWebGLUniformsSource = nativeUniformNamesEnabled ? optimizedNativeWebGLUniformsSource
1867
+ : optimizedNativeWebGLUniformsSource.replace(fixedUniformMethods, '')
1868
+
1869
+ /**
1870
+ * `UniformsLib.js`: the light classes and the typedefs go in above the table,
1871
+ * the table is stated as sixteen `NativeUniforms` groups, and the empty light
1872
+ * arrays keep their arm casts (an empty `[]` has no arm of its own).
1873
+ * @param {string} transformed
1874
+ * @param {string} fileName
1875
+ * @param {(text: string, from: string, to: string, fileName: string, label: string) => string} replaceOne
1876
+ */
1877
+ export const transformUniformsLib = (transformed, fileName, replaceOne) => {
1878
+ // The light-uniform slots carry a `properties: { direction: {}, ... }`
1879
+ // member three's renderer never reads -- it documents the struct layout the
1880
+ // GLSL declares. A slot is `{ value, needsUpdate? }` and nothing else.
1881
+ const propertiesBlock = /,\s*properties: \{(?:[^{}]|\{[^{}]*\})*\}/g
1882
+ const propertiesBlocks = transformed.match(propertiesBlock)
1883
+ if (propertiesBlocks === null || propertiesBlocks.length !== 8) {
1884
+ const count = propertiesBlocks === null ? 0 : propertiesBlocks.length
1885
+ throw new Error(`Three UniformsLib source at ${fileName} has ${count} light-uniform properties blocks; expected 8`)
1886
+ }
1887
+ transformed = transformed.replace(propertiesBlock, '')
1888
+ const groups = [...transformed.matchAll(/^\t(\w+): \{$/gm)].map((match) => match[1])
1889
+ if (groups.length !== 16) throw new Error(`Three UniformsLib source at ${fileName} declares ${groups.length} uniform groups; expected 16`)
1890
+ const texture = "import('../../textures/Texture.js').Texture"
1891
+ transformed = replaceOne(
1892
+ transformed,
1893
+ 'const UniformsLib = {',
1894
+ `${nativeLightUniformClasses}
1895
+ ${nativeUniformTypedefs}
1896
+ /**
1897
+ * The LTC tables are attached by RectAreaLightUniformsLib, an addon this
1898
+ * build does not ship; WebGLLights still copies them into its state, whose
1899
+ * slots start as \`null\`, so the unattached table is spelled the same way --
1900
+ * a declared null slot, never an absent field, which would put an
1901
+ * \`undefined\` into a nullable carrier.
1902
+ * @typedef {{
1903
+ ${groups.map((group) => ` * ${group}: NativeUniforms,`).join('\n')}
1904
+ * LTC_FLOAT_1: ${texture}|null,
1905
+ * LTC_FLOAT_2: ${texture}|null,
1906
+ * LTC_HALF_1: ${texture}|null,
1907
+ * LTC_HALF_2: ${texture}|null
1908
+ * }} NativeUniformLibrary
1909
+ */
1910
+ /** @type {NativeUniformLibrary} */
1911
+ const UniformsLib = {
1912
+
1913
+ \tLTC_FLOAT_1: null,
1914
+ \tLTC_FLOAT_2: null,
1915
+ \tLTC_HALF_1: null,
1916
+ \tLTC_HALF_2: null,
1917
+ `,
1918
+ fileName,
1919
+ 'UniformsLib native uniform model',
1920
+ )
1921
+ for (const [field, type] of [
1922
+ ['ambientLightColor', 'number[]'],
1923
+ ['lightProbe', "Array<import('../../math/Vector3.js').Vector3>"],
1924
+ ['directionalLights', 'NativeDirectionalLightUniform[]'],
1925
+ ['directionalLightShadows', 'NativeShadowUniform[]'],
1926
+ ['directionalShadowMatrix', "Array<import('../../math/Matrix4.js').Matrix4>"],
1927
+ ['spotLights', 'NativeSpotLightUniform[]'],
1928
+ ['spotLightShadows', 'NativeShadowUniform[]'],
1929
+ ['spotLightMap', `Array<${texture}|null>`],
1930
+ ['spotLightMatrix', "Array<import('../../math/Matrix4.js').Matrix4>"],
1931
+ ['pointLights', 'NativePointLightUniform[]'],
1932
+ ['pointLightShadows', 'NativePointShadowUniform[]'],
1933
+ ['pointShadowMatrix', "Array<import('../../math/Matrix4.js').Matrix4>"],
1934
+ ['hemisphereLights', 'NativeHemisphereLightUniform[]'],
1935
+ ['rectAreaLights', 'NativeRectAreaLightUniform[]'],
1936
+ ]) {
1937
+ transformed = replaceOne(transformed, `${field}: { value: []`, `${field}: { value: /** @type {${type}} */ ( [] )`, fileName, `UniformsLib ${field} holder`)
1938
+ }
1939
+ return transformed
1940
+ }
1941
+
1942
+ const exportedNames = (source) => [...source.matchAll(/^export (?:function|const|class) (\w+)|^export \{ (\w+) \}/gm)].map((match) => match[1] ?? match[2])
1943
+
1944
+ /**
1945
+ * `UniformsUtils.js` is replaced whole. Its export surface must not shrink:
1946
+ * three's other modules import from it by name.
1947
+ * @param {string} transformed
1948
+ * @param {string} fileName
1949
+ */
1950
+ export const transformUniformsUtils = (transformed, fileName) => {
1951
+ const provided = exportedNames(nativeUniformsUtilsSource)
1952
+ const missing = exportedNames(transformed).filter((name) => !provided.includes(name))
1953
+ if (missing.length > 0) throw new Error(`Three UniformsUtils replacement at ${fileName} drops exports: ${missing.join(', ')}`)
1954
+ return nativeUniformsUtilsSource
1955
+ }