@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.
- package/LICENSE +202 -0
- package/README.md +184 -0
- package/geatsc-plugin-batched-probe.mjs +98 -0
- package/geatsc-plugin-instancing.mjs +160 -0
- package/geatsc-plugin-uniforms.mjs +1955 -0
- package/geatsc-plugin-uploads.mjs +29 -0
- package/geatsc-plugin.mjs +10275 -0
- package/native/angle_webgl_host.mm +2687 -0
- package/native/audio_host.mm +857 -0
- package/native/audio_uwp.h +116 -0
- package/package.json +70 -0
- package/src/gea-native-types.d.ts +4 -0
- package/src/nativeAudioHost.ts +296 -0
- package/src/nativeThreeUtils.ts +11 -0
- package/src/nativeWebGL.ts +1211 -0
- package/src/nativeWebGLAnimation.ts +13 -0
- package/src/nativeWebGLHost.ts +333 -0
- package/src/nativeWebXRManager.ts +48 -0
- package/src/text/atlas-sans.ts +195 -0
- package/src/text/atlas-serif-italic.ts +195 -0
- package/src/text/atlas-serif.ts +195 -0
- package/src/text/native-text-types.ts +17 -0
- package/src/text/native-text.ts +203 -0
- package/src/troika-three-text.ts +248 -0
- package/test/auto-instanced-render-scene.ts +66 -0
- package/test/batched-render-scene.ts +58 -0
|
@@ -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
|
+
}
|