@geastack/native-webgl-angle 0.1.12 → 0.1.13

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.
@@ -22,4 +22,25 @@ template <typename... T> inline void gea_three_webgl_read_pixels_native(double x
22
22
  double format, double type, const std::variant<T...>& destination, double offset) {
23
23
  std::visit([&](const auto& view) { gea_three_webgl_read_pixels_native(x,y,width,height,format,type,view,offset); }, destination);
24
24
  }`
25
+ ], [
26
+ // getBufferSubData writes a pack buffer's bytes into the caller's view, in place.
27
+ 'threeWebGLGetBufferSubData', 'gea_three_webgl_get_buffer_sub_data_native', 'void', `
28
+ #include <variant>
29
+ extern "C" void gea_three_webgl_get_buffer_sub_data_bytes(double target, double srcOffset, void* bytes, double byteLength);
30
+ template <typename T> inline void gea_three_webgl_get_buffer_sub_data_native(double target, double srcOffset,
31
+ const gea::Ref<gea::TypedArray<T>>& destination, double dstOffset, double length) {
32
+ if (!destination || !std::isfinite(dstOffset) || dstOffset < 0 || std::floor(dstOffset) != dstOffset || dstOffset > destination->size() ||
33
+ !std::isfinite(length) || length < 0 || std::floor(length) != length) {
34
+ gea_three_webgl_get_buffer_sub_data_bytes(target, srcOffset, nullptr, -1); return;
35
+ }
36
+ const auto start = static_cast<std::size_t>(dstOffset);
37
+ const auto count = length == 0 ? destination->size() - start : static_cast<std::size_t>(length);
38
+ if (count > destination->size() - start) { gea_three_webgl_get_buffer_sub_data_bytes(target, srcOffset, nullptr, -1); return; }
39
+ auto* data = destination->data();
40
+ gea_three_webgl_get_buffer_sub_data_bytes(target, srcOffset, data ? data + start : nullptr, static_cast<double>(count * sizeof(T)));
41
+ }
42
+ template <typename... T> inline void gea_three_webgl_get_buffer_sub_data_native(double target, double srcOffset,
43
+ const std::variant<T...>& destination, double dstOffset, double length) {
44
+ std::visit([&](const auto& view) { gea_three_webgl_get_buffer_sub_data_native(target, srcOffset, view, dstOffset, length); }, destination);
45
+ }`
25
46
  ]];
@@ -654,11 +654,15 @@ function ${name}( gl, v, textures ) {
654
654
 
655
655
  \tif ( v instanceof ${ctorName} ) {
656
656
 
657
- \t\tif ( ${fields.map((field, index) => `cache[ ${index} ] !== v.${field}`).join(' || ')} ) {
657
+ \t\t// One narrowing and one read per component: each \`v.x\` re-narrowed the union value.
658
+ \t\tconst vector = v;
659
+ ${fields.map((field) => `\t\tconst ${field} = vector.${field};`).join('\n')}
658
660
 
659
- \t\t\tgl.${glScalar}( this.addr, ${fields.map((field) => `v.${field}`).join(', ')} );
661
+ \t\tif ( ${fields.map((field, index) => `cache[ ${index} ] !== ${field}`).join(' || ')} ) {
660
662
 
661
- ${fields.map((field, index) => `\t\t\tcache[ ${index} ] = v.${field};`).join('\n')}
663
+ \t\t\tgl.${glScalar}( this.addr, ${fields.join(', ')} );
664
+
665
+ ${fields.map((field, index) => `\t\t\tcache[ ${index} ] = ${field};`).join('\n')}
662
666
 
663
667
  \t\t}
664
668
 
@@ -761,20 +765,34 @@ ${
761
765
  }
762
766
  }`
763
767
 
768
+ // Arrays compare against the program's cached copy like single values do: uniform state is
769
+ // per program, and an unchanged write still dirtied the program's whole uniform block.
764
770
  const flatArraySetter = (name, glArray, requireArray) => `${setterHeader('PureArrayUniform')}
765
771
  function ${name}( gl, v, textures ) {
766
772
 
767
- \tgl.${glArray}( this.addr, ${requireArray}( v ) );
773
+ \tconst cache = this.cache;
774
+ \tconst data = ${requireArray}( v );
775
+
776
+ \tif ( arraysEqual( cache, data ) ) return;
777
+
778
+ \tgl.${glArray}( this.addr, data );
779
+
780
+ \tcopyArray( cache, data );
768
781
 
769
782
  }`
770
783
 
771
784
  const flattenedArraySetter = (name, blockSize, glArray, matrix) => `${setterHeader('PureArrayUniform')}
772
785
  function ${name}( gl, v, textures ) {
773
786
 
787
+ \tconst cache = this.cache;
774
788
  \tconst data = flatten( v, this.size, ${blockSize} );
775
789
 
790
+ \tif ( arraysEqual( cache, data ) ) return;
791
+
776
792
  \tgl.${glArray}( this.addr, ${matrix ? 'false, ' : ''}data );
777
793
 
794
+ \tcopyArray( cache, data );
795
+
778
796
  }`
779
797
 
780
798
  const textureArraySetter = (name, setter, empty, shadowAware) => `${setterHeader('PureArrayUniform')}
@@ -906,6 +924,8 @@ export const nativeFixedUniforms = [
906
924
  ['modelMatrix', 'Matrix4'],
907
925
  ['toneMappingExposure', 'number'],
908
926
  ['cameraPosition', 'Vector3'],
927
+ ['receiveShadow', 'boolean'],
928
+ ['isOrthographic', 'boolean'],
909
929
  ...(nativeUniformBindingsEnabled ? [
910
930
  ['directionalShadowMap', 'Array<Texture|null>', true],
911
931
  ['spotShadowMap', 'Array<Texture|null>', true],
@@ -917,13 +937,17 @@ const fixedUniformMethods = nativeFixedUniforms.map(([name, type, textures]) =>
917
937
  return `
918
938
  /** @param {${glContext}} gl @param {${type}} value ${textures ? '@param {NativeTextures|undefined} textures' : ''} */
919
939
  set_${name}( gl, value${textures ? ', textures' : ''} ) {
920
- const uniform = this.map.${name};
940
+ const uniform = this.fixed_${name};
921
941
  if ( uniform === undefined ) return;
922
942
  ${matrix ? `if ( ! ( uniform instanceof SingleUniform ) ) throw new Error( 'THREE.WebGLUniforms: ${type} fast path requires a single uniform.' );
923
943
  setNative${type}UniformValue( uniform, gl, value );` : `setNativeUniformValue( uniform, gl, value, ${textures ? 'textures' : 'undefined'} );`}
924
944
  }
925
945
  `
926
946
  }).join('\n')
947
+ // The fixed uniforms are resolved once when the program's uniforms are parsed; each
948
+ // per-draw setter then reads a field instead of hashing its name into `map` twice.
949
+ const fixedUniformFields = nativeFixedUniforms.map(([name]) =>
950
+ `\t\t/** @type {NativeUniform|undefined} */\n\t\tthis.fixed_${name} = this.map.${name};\n`).join('')
927
951
 
928
952
 
929
953
  // Uniform nodes belong to the linked program: id/type/location remain fixed
@@ -1273,25 +1297,31 @@ function setValueV3f( gl, v, textures ) {
1273
1297
 
1274
1298
  \tif ( v instanceof Vector3 ) {
1275
1299
 
1276
- \t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
1300
+ \t\tconst vector = v;
1301
+ \t\tconst x = vector.x, y = vector.y, z = vector.z;
1302
+
1303
+ \t\tif ( cache[ 0 ] !== x || cache[ 1 ] !== y || cache[ 2 ] !== z ) {
1277
1304
 
1278
- \t\t\tgl.uniform3f( this.addr, v.x, v.y, v.z );
1305
+ \t\t\tgl.uniform3f( this.addr, x, y, z );
1279
1306
 
1280
- \t\t\tcache[ 0 ] = v.x;
1281
- \t\t\tcache[ 1 ] = v.y;
1282
- \t\t\tcache[ 2 ] = v.z;
1307
+ \t\t\tcache[ 0 ] = x;
1308
+ \t\t\tcache[ 1 ] = y;
1309
+ \t\t\tcache[ 2 ] = z;
1283
1310
 
1284
1311
  \t\t}
1285
1312
 
1286
1313
  \t} else if ( v instanceof Color ) {
1287
1314
 
1288
- \t\tif ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
1315
+ \t\tconst color = v;
1316
+ \t\tconst r = color.r, g = color.g, b = color.b;
1289
1317
 
1290
- \t\t\tgl.uniform3f( this.addr, v.r, v.g, v.b );
1318
+ \t\tif ( cache[ 0 ] !== r || cache[ 1 ] !== g || cache[ 2 ] !== b ) {
1291
1319
 
1292
- \t\t\tcache[ 0 ] = v.r;
1293
- \t\t\tcache[ 1 ] = v.g;
1294
- \t\t\tcache[ 2 ] = v.b;
1320
+ \t\t\tgl.uniform3f( this.addr, r, g, b );
1321
+
1322
+ \t\t\tcache[ 0 ] = r;
1323
+ \t\t\tcache[ 1 ] = g;
1324
+ \t\t\tcache[ 2 ] = b;
1295
1325
 
1296
1326
  \t\t}
1297
1327
 
@@ -1484,69 +1514,115 @@ ${nativeUniformBindingsEnabled ? '\t\tthis.nativeBindingSlot = nativeUniformBind
1484
1514
 
1485
1515
  }
1486
1516
 
1517
+ /**
1518
+ * Member codes for a structured uniform's steps, resolved once when the program's
1519
+ * uniforms are parsed: an array step's code is its index; a light-record field's
1520
+ * code is a negative constant, so the per-draw read switches on a number instead
1521
+ * of comparing field names and parsing index strings.
1522
+ * @param {string} id @return {number}
1523
+ */
1524
+ function structuredUniformMemberCode( id ) {
1525
+
1526
+ \tif ( id === 'direction' ) return -1;
1527
+ \tif ( id === 'color' ) return -2;
1528
+ \tif ( id === 'position' ) return -3;
1529
+ \tif ( id === 'distance' ) return -4;
1530
+ \tif ( id === 'coneCos' ) return -5;
1531
+ \tif ( id === 'penumbraCos' ) return -6;
1532
+ \tif ( id === 'decay' ) return -7;
1533
+ \tif ( id === 'skyColor' ) return -8;
1534
+ \tif ( id === 'groundColor' ) return -9;
1535
+ \tif ( id === 'halfWidth' ) return -10;
1536
+ \tif ( id === 'halfHeight' ) return -11;
1537
+ \tif ( id === 'shadowIntensity' ) return -12;
1538
+ \tif ( id === 'shadowBias' ) return -13;
1539
+ \tif ( id === 'shadowNormalBias' ) return -14;
1540
+ \tif ( id === 'shadowRadius' ) return -15;
1541
+ \tif ( id === 'shadowMapSize' ) return -16;
1542
+ \tif ( id === 'shadowCameraNear' ) return -17;
1543
+ \tif ( id === 'shadowCameraFar' ) return -18;
1544
+ \tconst index = Number( id );
1545
+ \treturn Number.isInteger( index ) && index >= 0 ? index : - 1000;
1546
+
1547
+ }
1548
+
1487
1549
  /**
1488
1550
  * 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
1551
+ * where the value is an array (member is the index) or a light-uniform record
1552
+ * (member is the field's code). The light records are classes, so the read is a
1491
1553
  * narrowed field read; an array indexes whichever arm it is.
1492
- * @param {NativeUniformValue} value @param {string} id @return {NativeUniformValue}
1554
+ * @param {NativeUniformValue} value @param {number} member @param {string} id @return {NativeUniformValue}
1493
1555
  */
1494
- function structuredUniformMember( value, id ) {
1556
+ function structuredUniformMember( value, member, id ) {
1495
1557
 
1496
- \tif ( Array.isArray( value ) ) return value[ Number( id ) ];
1558
+ \tif ( Array.isArray( value ) ) return value[ member ];
1497
1559
 
1498
1560
  \tif ( value instanceof NativeDirectionalLightUniform ) {
1499
1561
 
1500
- \t\tif ( id === 'direction' ) return value.direction;
1501
- \t\tif ( id === 'color' ) return value.color;
1562
+ \t\tswitch ( member ) {
1563
+ \t\t\tcase -1: return value.direction;
1564
+ \t\t\tcase -2: return value.color;
1565
+ \t\t}
1502
1566
 
1503
1567
  \t} else if ( value instanceof NativeSpotLightUniform ) {
1504
1568
 
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;
1569
+ \t\tswitch ( member ) {
1570
+ \t\t\tcase -3: return value.position;
1571
+ \t\t\tcase -1: return value.direction;
1572
+ \t\t\tcase -2: return value.color;
1573
+ \t\t\tcase -4: return value.distance;
1574
+ \t\t\tcase -5: return value.coneCos;
1575
+ \t\t\tcase -6: return value.penumbraCos;
1576
+ \t\t\tcase -7: return value.decay;
1577
+ \t\t}
1512
1578
 
1513
1579
  \t} else if ( value instanceof NativePointLightUniform ) {
1514
1580
 
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;
1581
+ \t\tswitch ( member ) {
1582
+ \t\t\tcase -3: return value.position;
1583
+ \t\t\tcase -2: return value.color;
1584
+ \t\t\tcase -4: return value.distance;
1585
+ \t\t\tcase -7: return value.decay;
1586
+ \t\t}
1519
1587
 
1520
1588
  \t} else if ( value instanceof NativeHemisphereLightUniform ) {
1521
1589
 
1522
- \t\tif ( id === 'direction' ) return value.direction;
1523
- \t\tif ( id === 'skyColor' ) return value.skyColor;
1524
- \t\tif ( id === 'groundColor' ) return value.groundColor;
1590
+ \t\tswitch ( member ) {
1591
+ \t\t\tcase -1: return value.direction;
1592
+ \t\t\tcase -8: return value.skyColor;
1593
+ \t\t\tcase -9: return value.groundColor;
1594
+ \t\t}
1525
1595
 
1526
1596
  \t} else if ( value instanceof NativeRectAreaLightUniform ) {
1527
1597
 
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;
1598
+ \t\tswitch ( member ) {
1599
+ \t\t\tcase -2: return value.color;
1600
+ \t\t\tcase -3: return value.position;
1601
+ \t\t\tcase -10: return value.halfWidth;
1602
+ \t\t\tcase -11: return value.halfHeight;
1603
+ \t\t}
1532
1604
 
1533
1605
  \t} else if ( value instanceof NativeShadowUniform ) {
1534
1606
 
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;
1607
+ \t\tswitch ( member ) {
1608
+ \t\t\tcase -12: return value.shadowIntensity;
1609
+ \t\t\tcase -13: return value.shadowBias;
1610
+ \t\t\tcase -14: return value.shadowNormalBias;
1611
+ \t\t\tcase -15: return value.shadowRadius;
1612
+ \t\t\tcase -16: return value.shadowMapSize;
1613
+ \t\t}
1540
1614
 
1541
1615
  \t} else if ( value instanceof NativePointShadowUniform ) {
1542
1616
 
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;
1617
+ \t\tswitch ( member ) {
1618
+ \t\t\tcase -12: return value.shadowIntensity;
1619
+ \t\t\tcase -13: return value.shadowBias;
1620
+ \t\t\tcase -14: return value.shadowNormalBias;
1621
+ \t\t\tcase -15: return value.shadowRadius;
1622
+ \t\t\tcase -16: return value.shadowMapSize;
1623
+ \t\t\tcase -17: return value.shadowCameraNear;
1624
+ \t\t\tcase -18: return value.shadowCameraFar;
1625
+ \t\t}
1550
1626
 
1551
1627
  \t}
1552
1628
 
@@ -1566,18 +1642,20 @@ ${nativeUniformBindingsEnabled ? '\t\tthis.nativeBindingSlot = nativeUniformBind
1566
1642
  \t\tthis.seq = [];
1567
1643
  \t\t/** @type {Record<string, NativeUniform>} */
1568
1644
  \t\tthis.map = {};
1645
+ \t\t/** @type {number[]} member code of each seq entry */
1646
+ \t\tthis.members = [];
1569
1647
 
1570
1648
  \t}
1571
1649
 
1572
1650
  \t/** @param {${glContext}} gl @param {NativeUniformValue} value @param {NativeTextures|undefined} textures @return {void} */
1573
1651
  \tsetValue( gl, value, textures ) {
1574
1652
 
1575
- \t\tconst seq = this.seq;
1653
+ \t\tconst seq = this.seq, members = this.members;
1576
1654
 
1577
1655
  \t\tfor ( let i = 0, n = seq.length; i !== n; ++ i ) {
1578
1656
 
1579
1657
  \t\t\tconst u = seq[ i ];
1580
- \t\t\tsetNativeUniformValue( u, gl, structuredUniformMember( value, u.id ), textures );
1658
+ \t\t\tsetNativeUniformValue( u, gl, structuredUniformMember( value, members[ i ], u.id ), textures );
1581
1659
 
1582
1660
  \t\t}
1583
1661
 
@@ -1619,6 +1697,7 @@ function addUniform( container, uniformObject ) {
1619
1697
 
1620
1698
  \tcontainer.seq.push( uniformObject );
1621
1699
  \tcontainer.map[ uniformObject.id ] = uniformObject;
1700
+ \tif ( container instanceof StructuredUniform ) container.members.push( structuredUniformMemberCode( uniformObject.id ) );
1622
1701
 
1623
1702
  }
1624
1703
 
@@ -1754,6 +1833,7 @@ class WebGLUniforms {
1754
1833
 
1755
1834
  \t\t}
1756
1835
 
1836
+ ${fixedUniformFields}
1757
1837
  \t}
1758
1838
 
1759
1839
  ${fixedUniformMethods}
@@ -1805,8 +1885,8 @@ ${fixedUniformMethods}
1805
1885
  \t// direct, typed uploads (\`setMatrix4Value\` for the bind matrices; the
1806
1886
  \t// batching textures upload their own value on the line below each).
1807
1887
 
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 ) {
1888
+ \t/** @param {${glContext}} gl @param {NativeUniform[]} seq @param {NativeUniforms} values @param {NativeTextures|undefined} textures @param {NativeClippingUniform|undefined} clippingPlanes @param {Array<import('../shaders/UniformsLib.js').NativeUniformSlot|undefined>|undefined} [slots] */
1889
+ \tstatic upload( gl, seq, values, textures, clippingPlanes, slots ) {
1810
1890
 
1811
1891
  \t\tfor ( let i = 0, n = seq.length; i !== n; ++ i ) {
1812
1892
 
@@ -1819,7 +1899,9 @@ ${fixedUniformMethods}
1819
1899
 
1820
1900
  \t\t\t}
1821
1901
 
1822
- \t\t\tconst v = ${nativeUniformBindingsEnabled ? 'nativeUniformBindingValue( values, u )' : 'values[ u.id ]'};
1902
+ \t\t\t// The cell resolved with this list (see slotsOf), else a lookup by name.
1903
+ \t\t\tconst cached = slots !== undefined && i < slots.length ? slots[ i ] : undefined;
1904
+ \t\t\tconst v = cached !== undefined ? cached : ${nativeUniformBindingsEnabled ? 'nativeUniformBindingValue( values, u )' : 'values[ u.id ]'};
1823
1905
 
1824
1906
  \t\t\tif ( v.needsUpdate !== false ) {
1825
1907
 
@@ -1832,6 +1914,23 @@ ${fixedUniformMethods}
1832
1914
 
1833
1915
  \t}
1834
1916
 
1917
+ \t/** @param {NativeUniform[]} seq @param {NativeUniforms} values @return {Array<import('../shaders/UniformsLib.js').NativeUniformSlot|undefined>} */
1918
+ \tstatic slotsOf( seq, values ) {
1919
+
1920
+ \t\t/** @type {Array<import('../shaders/UniformsLib.js').NativeUniformSlot|undefined>} */
1921
+ \t\tconst r = [];
1922
+
1923
+ \t\tfor ( let i = 0, n = seq.length; i !== n; ++ i ) {
1924
+
1925
+ \t\t\tconst u = seq[ i ];
1926
+ \t\t\tr.push( ${nativeUniformBindingsEnabled ? 'u.nativeBindingSlot === -1 ? undefined : nativeUniformBindingValue( values, u )' : "u.id === 'clippingPlanes' ? undefined : values[ u.id ]"} );
1927
+
1928
+ \t\t}
1929
+
1930
+ \t\treturn r;
1931
+
1932
+ \t}
1933
+
1835
1934
  \t/** @param {NativeUniform[]} seq @param {NativeUniforms} values @param {NativeClippingUniform|undefined} clippingPlanes @return {NativeUniform[]} */
1836
1935
  \tstatic seqWithValue( seq, values, clippingPlanes ) {
1837
1936
 
@@ -1863,8 +1962,64 @@ export { WebGLUniforms };
1863
1962
  `
1864
1963
 
1865
1964
 
1866
- export const nativeWebGLUniformsSource = nativeUniformNamesEnabled ? optimizedNativeWebGLUniformsSource
1867
- : optimizedNativeWebGLUniformsSource.replace(fixedUniformMethods, '')
1965
+
1966
+ /**
1967
+ * Setters as direct calls. three stores each uniform's setter in a \`setValue\`
1968
+ * field; natively that is a callable-object call, which takes the large
1969
+ * \`NativeUniformValue\` union by value -- a copy and its reference counting on
1970
+ * every uniform of every draw. Here each setter takes its uniform as the first
1971
+ * parameter, and \`setNativeUniformValue\` switches on the uniform's GL type to
1972
+ * call it directly, so the value is passed by reference. Same setters, same
1973
+ * caches, same GL calls.
1974
+ * @param {string} source @return {string}
1975
+ */
1976
+ function directUniformSetters( source ) {
1977
+
1978
+ let out = source.replace(
1979
+ /\/\*\* @this \{(SingleUniform|PureArrayUniform)\} (@param [^\n]*?)\*\/\nfunction (setValue\w+)\( gl, v, textures \) \{\n([\s\S]*?)\n\}\n/g,
1980
+ (_match, receiver, params, name, body) =>
1981
+ '/** @param {' + receiver + '} uniform ' + params + '*/\nfunction ' + name + '( uniform, gl, v, textures ) {\n' +
1982
+ body.replace(/\bthis\b/g, 'uniform') + '\n}\n',
1983
+ );
1984
+ if ( /@this \{(SingleUniform|PureArrayUniform)\}/.test( out ) ) throw new Error( 'directUniformSetters: a setter kept @this' );
1985
+
1986
+ const dispatch = ( selector, receiver, name ) => {
1987
+ const start = out.indexOf( 'function ' + selector + '( type ) {' );
1988
+ const end = out.indexOf( '\n}\n', start );
1989
+ if ( start < 0 || end < 0 ) throw new Error( 'directUniformSetters: ' + selector + ' not found' );
1990
+ const body = out.slice( start, end );
1991
+ const cases = body.slice( body.indexOf( 'switch ( type ) {' ) + 'switch ( type ) {'.length, body.lastIndexOf( '}' ) );
1992
+ if ( ! /return setValue\w+;/.test( cases ) ) throw new Error( 'directUniformSetters: no cases in ' + selector );
1993
+ const direct = '/** @param {' + receiver + '} uniform @param {' + 'GL' + '} gl @param {NativeUniformValue} v @param {NativeTextures|undefined} textures @return {void} */\n' +
1994
+ 'function ' + name + '( uniform, gl, v, textures ) {\n\n\tswitch ( uniform.type ) {\n' +
1995
+ cases.replace( /return (setValue\w+);/g, '$1( uniform, gl, v, textures ); return;' ) +
1996
+ '\n\t}\n\n\tthrow new Error( \'THREE.WebGLUniforms: Unsupported uniform type.\' );\n\n}\n';
1997
+ // The selector now only validates the type at program link.
1998
+ const validating = body.replace( /return setValue\w+;/g, 'return true;' );
1999
+ out = out.slice( 0, start ) + validating + out.slice( end ) ;
2000
+ return direct;
2001
+ };
2002
+ const glType = out.match( /@param \{([^}]+)\} gl @param \{NativeUniformValue\} v/ );
2003
+ if ( ! glType ) throw new Error( 'directUniformSetters: gl type not found' );
2004
+ const singular = dispatch( 'getSingularSetter', 'SingleUniform', 'callSingularSetter' ).replace( '{GL}', '{' + glType[ 1 ] + '}' );
2005
+ const array = dispatch( 'getPureArraySetter', 'PureArrayUniform', 'callPureArraySetter' ).replace( '{GL}', '{' + glType[ 1 ] + '}' );
2006
+ const replaceOnce = ( from, to ) => {
2007
+ if ( out.split( from ).length !== 2 ) throw new Error( 'directUniformSetters: expected one ' + from );
2008
+ out = out.replace( from, to );
2009
+ };
2010
+ replaceOnce( '/** @param {number} type @return {NativeSingularUniformSetter} */', '/** @param {number} type @return {boolean} */' );
2011
+ replaceOnce( '/** @param {number} type @return {NativeArrayUniformSetter} */', '/** @param {number} type @return {boolean} */' );
2012
+ replaceOnce( '\t\tthis.setValue = getSingularSetter( activeInfo.type );', '\t\tgetSingularSetter( activeInfo.type );' );
2013
+ replaceOnce( '\t\tthis.setValue = getPureArraySetter( activeInfo.type );', '\t\tgetPureArraySetter( activeInfo.type );' );
2014
+ replaceOnce( '\tif ( uniform instanceof SingleUniform ) uniform.setValue( gl, value, textures );\n\telse if ( uniform instanceof PureArrayUniform ) uniform.setValue( gl, value, textures );',
2015
+ '\tif ( uniform instanceof SingleUniform ) callSingularSetter( uniform, gl, value, textures );\n\telse if ( uniform instanceof PureArrayUniform ) callPureArraySetter( uniform, gl, value, textures );' );
2016
+ replaceOnce( '// --- Uniform Classes ---', singular + '\n' + array + '\n// --- Uniform Classes ---' );
2017
+ return out;
2018
+
2019
+ }
2020
+
2021
+ export const nativeWebGLUniformsSource = directUniformSetters( nativeUniformNamesEnabled ? optimizedNativeWebGLUniformsSource
2022
+ : optimizedNativeWebGLUniformsSource.replace(fixedUniformMethods, '') )
1868
2023
 
1869
2024
  /**
1870
2025
  * `UniformsLib.js`: the light classes and the typedefs go in above the table,
@@ -1,11 +1,16 @@
1
1
  // The host owns the physical upload format. The compiler only preserves the
2
2
  // native carriers at these explicitly registered synchronous boundaries.
3
+ // Element type of the client pixels, by GL type: half floats travel as their
4
+ // 16-bit patterns, never widened to float32.
5
+ const pixelKind = '(type == 0x1403 || type == 0x140B || type == 0x8D61 ? 2 : type == 0x1405 ? 3 : type == 0x1401 ? 4 : type == 0x1400 ? 5 : type == 0x1402 ? 6 : type == 0x1404 ? 7 : 1)';
3
6
  export const nativeUploadFunctions = [
4
7
  ['threeWebGLBufferData', 'gea_three_webgl_buffer_data_native', ['target', 'usage', 'typeCode'], 'gea_three_webgl_buffer_data_bytes', ['target', 'usage'], 'typeCode'],
5
8
  ['threeWebGLBufferSubData', 'gea_three_webgl_buffer_sub_data_native', ['target', 'offset', 'typeCode'], 'gea_three_webgl_buffer_sub_data_bytes', ['target', 'offset'], 'typeCode'],
6
9
  ['threeWebGLBufferSubDataRange', 'gea_three_webgl_buffer_sub_data_range_native', ['target', 'offset', 'typeCode'], 'gea_three_webgl_buffer_sub_data_bytes', ['target', 'offset'], 'typeCode', true],
7
- ['threeWebGLTexImage2D', 'gea_three_webgl_tex_image_2d_native', ['target', 'level', 'internalFormat', 'width', 'height', 'format', 'type'], 'gea_three_webgl_tex_image_2d_bytes', ['target', 'level', 'internalFormat', 'width', 'height', 'format', 'type'], '(type == 0x1403 ? 2 : type == 0x1405 ? 3 : type == 0x1401 ? 4 : 1)'],
8
- ['threeWebGLTexSubImage2D', 'gea_three_webgl_tex_sub_image_2d_native', ['target', 'level', 'xoffset', 'yoffset', 'width', 'height', 'format', 'type'], 'gea_three_webgl_tex_sub_image_2d_bytes', ['target', 'level', 'xoffset', 'yoffset', 'width', 'height', 'format', 'type'], '(type == 0x1403 ? 2 : type == 0x1405 ? 3 : type == 0x1401 ? 4 : 1)'],
10
+ ['threeWebGLTexImage2D', 'gea_three_webgl_tex_image_2d_native', ['target', 'level', 'internalFormat', 'width', 'height', 'format', 'type'], 'gea_three_webgl_tex_image_2d_bytes', ['target', 'level', 'internalFormat', 'width', 'height', 'format', 'type'], pixelKind],
11
+ ['threeWebGLTexImage3D', 'gea_three_webgl_tex_image_3d_native', ['target', 'level', 'internalFormat', 'width', 'height', 'depth', 'format', 'type'], 'gea_three_webgl_tex_image_3d_bytes', ['target', 'level', 'internalFormat', 'width', 'height', 'depth', 'format', 'type'], pixelKind],
12
+ ['threeWebGLTexSubImage3D', 'gea_three_webgl_tex_sub_image_3d_native', ['target', 'level', 'xoffset', 'yoffset', 'zoffset', 'width', 'height', 'depth', 'format', 'type'], 'gea_three_webgl_tex_sub_image_3d_bytes', ['target', 'level', 'xoffset', 'yoffset', 'zoffset', 'width', 'height', 'depth', 'format', 'type'], pixelKind],
13
+ ['threeWebGLTexSubImage2D', 'gea_three_webgl_tex_sub_image_2d_native', ['target', 'level', 'xoffset', 'yoffset', 'width', 'height', 'format', 'type'], 'gea_three_webgl_tex_sub_image_2d_bytes', ['target', 'level', 'xoffset', 'yoffset', 'width', 'height', 'format', 'type'], pixelKind],
9
14
  ].map(([name, binding, parameters, raw, rawParameters, kind, range]) => {
10
15
  const declaration = `extern "C" void ${raw}(${rawParameters.map(p => `double ${p}`).join(', ')}, const void* bytes, double byteLength);
11
16
  template <typename Source> inline void ${binding}(${parameters.map(p => `double ${p}`).join(', ')}, const Source& values${range ? ', double sourceOffset, double length' : ''}) {