WebGLUniforms.js 18 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  1. /**
  2. * Uniforms of a program.
  3. * Those form a tree structure with a special top-level container for the root,
  4. * which you get by calling 'new WebGLUniforms( gl, program )'.
  5. *
  6. *
  7. * Properties of inner nodes including the top-level container:
  8. *
  9. * .seq - array of nested uniforms
  10. * .map - nested uniforms by name
  11. *
  12. *
  13. * Methods of all nodes except the top-level container:
  14. *
  15. * .setValue( gl, value, [textures] )
  16. *
  17. * uploads a uniform value(s)
  18. * the 'textures' parameter is needed for sampler uniforms
  19. *
  20. *
  21. * Static methods of the top-level container (textures factorizations):
  22. *
  23. * .upload( gl, seq, values, textures )
  24. *
  25. * sets uniforms in 'seq' to 'values[id].value'
  26. *
  27. * .seqWithValue( seq, values ) : filteredSeq
  28. *
  29. * filters 'seq' entries with corresponding entry in values
  30. *
  31. *
  32. * Methods of the top-level container (textures factorizations):
  33. *
  34. * .setValue( gl, name, value, textures )
  35. *
  36. * sets uniform with name 'name' to 'value'
  37. *
  38. * .setOptional( gl, obj, prop )
  39. *
  40. * like .set for an optional property of the object
  41. *
  42. */
  43. import { CubeTexture } from '../../textures/CubeTexture.js';
  44. import { Texture } from '../../textures/Texture.js';
  45. import { DataArrayTexture } from '../../textures/DataArrayTexture.js';
  46. import { Data3DTexture } from '../../textures/Data3DTexture.js';
  47. const emptyTexture = /*@__PURE__*/ new Texture();
  48. const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture();
  49. const empty3dTexture = /*@__PURE__*/ new Data3DTexture();
  50. const emptyCubeTexture = /*@__PURE__*/ new CubeTexture();
  51. // --- Utilities ---
  52. // Array Caches (provide typed arrays for temporary by size)
  53. const arrayCacheF32 = [];
  54. const arrayCacheI32 = [];
  55. // Float32Array caches used for uploading Matrix uniforms
  56. const mat4array = new Float32Array( 16 );
  57. const mat3array = new Float32Array( 9 );
  58. const mat2array = new Float32Array( 4 );
  59. // Flattening for arrays of vectors and matrices
  60. function flatten( array, nBlocks, blockSize ) {
  61. const firstElem = array[ 0 ];
  62. if ( firstElem <= 0 || firstElem > 0 ) return array;
  63. // unoptimized: ! isNaN( firstElem )
  64. // see http://jacksondunstan.com/articles/983
  65. const n = nBlocks * blockSize;
  66. let r = arrayCacheF32[ n ];
  67. if ( r === undefined ) {
  68. r = new Float32Array( n );
  69. arrayCacheF32[ n ] = r;
  70. }
  71. if ( nBlocks !== 0 ) {
  72. firstElem.toArray( r, 0 );
  73. for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) {
  74. offset += blockSize;
  75. array[ i ].toArray( r, offset );
  76. }
  77. }
  78. return r;
  79. }
  80. function arraysEqual( a, b ) {
  81. if ( a.length !== b.length ) return false;
  82. for ( let i = 0, l = a.length; i < l; i ++ ) {
  83. if ( a[ i ] !== b[ i ] ) return false;
  84. }
  85. return true;
  86. }
  87. function copyArray( a, b ) {
  88. for ( let i = 0, l = b.length; i < l; i ++ ) {
  89. a[ i ] = b[ i ];
  90. }
  91. }
  92. // Texture unit allocation
  93. function allocTexUnits( textures, n ) {
  94. let r = arrayCacheI32[ n ];
  95. if ( r === undefined ) {
  96. r = new Int32Array( n );
  97. arrayCacheI32[ n ] = r;
  98. }
  99. for ( let i = 0; i !== n; ++ i ) {
  100. r[ i ] = textures.allocateTextureUnit();
  101. }
  102. return r;
  103. }
  104. // --- Setters ---
  105. // Note: Defining these methods externally, because they come in a bunch
  106. // and this way their names minify.
  107. // Single scalar
  108. function setValueV1f( gl, v ) {
  109. const cache = this.cache;
  110. if ( cache[ 0 ] === v ) return;
  111. gl.uniform1f( this.addr, v );
  112. cache[ 0 ] = v;
  113. }
  114. // Single float vector (from flat array or THREE.VectorN)
  115. function setValueV2f( gl, v ) {
  116. const cache = this.cache;
  117. if ( v.x !== undefined ) {
  118. if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
  119. gl.uniform2f( this.addr, v.x, v.y );
  120. cache[ 0 ] = v.x;
  121. cache[ 1 ] = v.y;
  122. }
  123. } else {
  124. if ( arraysEqual( cache, v ) ) return;
  125. gl.uniform2fv( this.addr, v );
  126. copyArray( cache, v );
  127. }
  128. }
  129. function setValueV3f( gl, v ) {
  130. const cache = this.cache;
  131. if ( v.x !== undefined ) {
  132. if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
  133. gl.uniform3f( this.addr, v.x, v.y, v.z );
  134. cache[ 0 ] = v.x;
  135. cache[ 1 ] = v.y;
  136. cache[ 2 ] = v.z;
  137. }
  138. } else if ( v.r !== undefined ) {
  139. if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
  140. gl.uniform3f( this.addr, v.r, v.g, v.b );
  141. cache[ 0 ] = v.r;
  142. cache[ 1 ] = v.g;
  143. cache[ 2 ] = v.b;
  144. }
  145. } else {
  146. if ( arraysEqual( cache, v ) ) return;
  147. gl.uniform3fv( this.addr, v );
  148. copyArray( cache, v );
  149. }
  150. }
  151. function setValueV4f( gl, v ) {
  152. const cache = this.cache;
  153. if ( v.x !== undefined ) {
  154. if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
  155. gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
  156. cache[ 0 ] = v.x;
  157. cache[ 1 ] = v.y;
  158. cache[ 2 ] = v.z;
  159. cache[ 3 ] = v.w;
  160. }
  161. } else {
  162. if ( arraysEqual( cache, v ) ) return;
  163. gl.uniform4fv( this.addr, v );
  164. copyArray( cache, v );
  165. }
  166. }
  167. // Single matrix (from flat array or THREE.MatrixN)
  168. function setValueM2( gl, v ) {
  169. const cache = this.cache;
  170. const elements = v.elements;
  171. if ( elements === undefined ) {
  172. if ( arraysEqual( cache, v ) ) return;
  173. gl.uniformMatrix2fv( this.addr, false, v );
  174. copyArray( cache, v );
  175. } else {
  176. if ( arraysEqual( cache, elements ) ) return;
  177. mat2array.set( elements );
  178. gl.uniformMatrix2fv( this.addr, false, mat2array );
  179. copyArray( cache, elements );
  180. }
  181. }
  182. function setValueM3( gl, v ) {
  183. const cache = this.cache;
  184. const elements = v.elements;
  185. if ( elements === undefined ) {
  186. if ( arraysEqual( cache, v ) ) return;
  187. gl.uniformMatrix3fv( this.addr, false, v );
  188. copyArray( cache, v );
  189. } else {
  190. if ( arraysEqual( cache, elements ) ) return;
  191. mat3array.set( elements );
  192. gl.uniformMatrix3fv( this.addr, false, mat3array );
  193. copyArray( cache, elements );
  194. }
  195. }
  196. function setValueM4( gl, v ) {
  197. const cache = this.cache;
  198. const elements = v.elements;
  199. if ( elements === undefined ) {
  200. if ( arraysEqual( cache, v ) ) return;
  201. gl.uniformMatrix4fv( this.addr, false, v );
  202. copyArray( cache, v );
  203. } else {
  204. if ( arraysEqual( cache, elements ) ) return;
  205. mat4array.set( elements );
  206. gl.uniformMatrix4fv( this.addr, false, mat4array );
  207. copyArray( cache, elements );
  208. }
  209. }
  210. // Single integer / boolean
  211. function setValueV1i( gl, v ) {
  212. const cache = this.cache;
  213. if ( cache[ 0 ] === v ) return;
  214. gl.uniform1i( this.addr, v );
  215. cache[ 0 ] = v;
  216. }
  217. // Single integer / boolean vector (from flat array)
  218. function setValueV2i( gl, v ) {
  219. const cache = this.cache;
  220. if ( arraysEqual( cache, v ) ) return;
  221. gl.uniform2iv( this.addr, v );
  222. copyArray( cache, v );
  223. }
  224. function setValueV3i( gl, v ) {
  225. const cache = this.cache;
  226. if ( arraysEqual( cache, v ) ) return;
  227. gl.uniform3iv( this.addr, v );
  228. copyArray( cache, v );
  229. }
  230. function setValueV4i( gl, v ) {
  231. const cache = this.cache;
  232. if ( arraysEqual( cache, v ) ) return;
  233. gl.uniform4iv( this.addr, v );
  234. copyArray( cache, v );
  235. }
  236. // Single unsigned integer
  237. function setValueV1ui( gl, v ) {
  238. const cache = this.cache;
  239. if ( cache[ 0 ] === v ) return;
  240. gl.uniform1ui( this.addr, v );
  241. cache[ 0 ] = v;
  242. }
  243. // Single unsigned integer vector (from flat array)
  244. function setValueV2ui( gl, v ) {
  245. const cache = this.cache;
  246. if ( arraysEqual( cache, v ) ) return;
  247. gl.uniform2uiv( this.addr, v );
  248. copyArray( cache, v );
  249. }
  250. function setValueV3ui( gl, v ) {
  251. const cache = this.cache;
  252. if ( arraysEqual( cache, v ) ) return;
  253. gl.uniform3uiv( this.addr, v );
  254. copyArray( cache, v );
  255. }
  256. function setValueV4ui( gl, v ) {
  257. const cache = this.cache;
  258. if ( arraysEqual( cache, v ) ) return;
  259. gl.uniform4uiv( this.addr, v );
  260. copyArray( cache, v );
  261. }
  262. // Single texture (2D / Cube)
  263. function setValueT1( gl, v, textures ) {
  264. const cache = this.cache;
  265. const unit = textures.allocateTextureUnit();
  266. if ( cache[ 0 ] !== unit ) {
  267. gl.uniform1i( this.addr, unit );
  268. cache[ 0 ] = unit;
  269. }
  270. textures.setTexture2D( v || emptyTexture, unit );
  271. }
  272. function setValueT3D1( gl, v, textures ) {
  273. const cache = this.cache;
  274. const unit = textures.allocateTextureUnit();
  275. if ( cache[ 0 ] !== unit ) {
  276. gl.uniform1i( this.addr, unit );
  277. cache[ 0 ] = unit;
  278. }
  279. textures.setTexture3D( v || empty3dTexture, unit );
  280. }
  281. function setValueT6( gl, v, textures ) {
  282. const cache = this.cache;
  283. const unit = textures.allocateTextureUnit();
  284. if ( cache[ 0 ] !== unit ) {
  285. gl.uniform1i( this.addr, unit );
  286. cache[ 0 ] = unit;
  287. }
  288. textures.setTextureCube( v || emptyCubeTexture, unit );
  289. }
  290. function setValueT2DArray1( gl, v, textures ) {
  291. const cache = this.cache;
  292. const unit = textures.allocateTextureUnit();
  293. if ( cache[ 0 ] !== unit ) {
  294. gl.uniform1i( this.addr, unit );
  295. cache[ 0 ] = unit;
  296. }
  297. textures.setTexture2DArray( v || emptyArrayTexture, unit );
  298. }
  299. // Helper to pick the right setter for the singular case
  300. function getSingularSetter( type ) {
  301. switch ( type ) {
  302. case 0x1406: return setValueV1f; // FLOAT
  303. case 0x8b50: return setValueV2f; // _VEC2
  304. case 0x8b51: return setValueV3f; // _VEC3
  305. case 0x8b52: return setValueV4f; // _VEC4
  306. case 0x8b5a: return setValueM2; // _MAT2
  307. case 0x8b5b: return setValueM3; // _MAT3
  308. case 0x8b5c: return setValueM4; // _MAT4
  309. case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL
  310. case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2
  311. case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3
  312. case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4
  313. case 0x1405: return setValueV1ui; // UINT
  314. case 0x8dc6: return setValueV2ui; // _VEC2
  315. case 0x8dc7: return setValueV3ui; // _VEC3
  316. case 0x8dc8: return setValueV4ui; // _VEC4
  317. case 0x8b5e: // SAMPLER_2D
  318. case 0x8d66: // SAMPLER_EXTERNAL_OES
  319. case 0x8dca: // INT_SAMPLER_2D
  320. case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
  321. case 0x8b62: // SAMPLER_2D_SHADOW
  322. return setValueT1;
  323. case 0x8b5f: // SAMPLER_3D
  324. case 0x8dcb: // INT_SAMPLER_3D
  325. case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
  326. return setValueT3D1;
  327. case 0x8b60: // SAMPLER_CUBE
  328. case 0x8dcc: // INT_SAMPLER_CUBE
  329. case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
  330. case 0x8dc5: // SAMPLER_CUBE_SHADOW
  331. return setValueT6;
  332. case 0x8dc1: // SAMPLER_2D_ARRAY
  333. case 0x8dcf: // INT_SAMPLER_2D_ARRAY
  334. case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
  335. case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
  336. return setValueT2DArray1;
  337. }
  338. }
  339. // Array of scalars
  340. function setValueV1fArray( gl, v ) {
  341. gl.uniform1fv( this.addr, v );
  342. }
  343. // Array of vectors (from flat array or array of THREE.VectorN)
  344. function setValueV2fArray( gl, v ) {
  345. const data = flatten( v, this.size, 2 );
  346. gl.uniform2fv( this.addr, data );
  347. }
  348. function setValueV3fArray( gl, v ) {
  349. const data = flatten( v, this.size, 3 );
  350. gl.uniform3fv( this.addr, data );
  351. }
  352. function setValueV4fArray( gl, v ) {
  353. const data = flatten( v, this.size, 4 );
  354. gl.uniform4fv( this.addr, data );
  355. }
  356. // Array of matrices (from flat array or array of THREE.MatrixN)
  357. function setValueM2Array( gl, v ) {
  358. const data = flatten( v, this.size, 4 );
  359. gl.uniformMatrix2fv( this.addr, false, data );
  360. }
  361. function setValueM3Array( gl, v ) {
  362. const data = flatten( v, this.size, 9 );
  363. gl.uniformMatrix3fv( this.addr, false, data );
  364. }
  365. function setValueM4Array( gl, v ) {
  366. const data = flatten( v, this.size, 16 );
  367. gl.uniformMatrix4fv( this.addr, false, data );
  368. }
  369. // Array of integer / boolean
  370. function setValueV1iArray( gl, v ) {
  371. gl.uniform1iv( this.addr, v );
  372. }
  373. // Array of integer / boolean vectors (from flat array)
  374. function setValueV2iArray( gl, v ) {
  375. gl.uniform2iv( this.addr, v );
  376. }
  377. function setValueV3iArray( gl, v ) {
  378. gl.uniform3iv( this.addr, v );
  379. }
  380. function setValueV4iArray( gl, v ) {
  381. gl.uniform4iv( this.addr, v );
  382. }
  383. // Array of unsigned integer
  384. function setValueV1uiArray( gl, v ) {
  385. gl.uniform1uiv( this.addr, v );
  386. }
  387. // Array of unsigned integer vectors (from flat array)
  388. function setValueV2uiArray( gl, v ) {
  389. gl.uniform2uiv( this.addr, v );
  390. }
  391. function setValueV3uiArray( gl, v ) {
  392. gl.uniform3uiv( this.addr, v );
  393. }
  394. function setValueV4uiArray( gl, v ) {
  395. gl.uniform4uiv( this.addr, v );
  396. }
  397. // Array of textures (2D / 3D / Cube / 2DArray)
  398. function setValueT1Array( gl, v, textures ) {
  399. const n = v.length;
  400. const units = allocTexUnits( textures, n );
  401. gl.uniform1iv( this.addr, units );
  402. for ( let i = 0; i !== n; ++ i ) {
  403. textures.setTexture2D( v[ i ] || emptyTexture, units[ i ] );
  404. }
  405. }
  406. function setValueT3DArray( gl, v, textures ) {
  407. const n = v.length;
  408. const units = allocTexUnits( textures, n );
  409. gl.uniform1iv( this.addr, units );
  410. for ( let i = 0; i !== n; ++ i ) {
  411. textures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] );
  412. }
  413. }
  414. function setValueT6Array( gl, v, textures ) {
  415. const n = v.length;
  416. const units = allocTexUnits( textures, n );
  417. gl.uniform1iv( this.addr, units );
  418. for ( let i = 0; i !== n; ++ i ) {
  419. textures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
  420. }
  421. }
  422. function setValueT2DArrayArray( gl, v, textures ) {
  423. const n = v.length;
  424. const units = allocTexUnits( textures, n );
  425. gl.uniform1iv( this.addr, units );
  426. for ( let i = 0; i !== n; ++ i ) {
  427. textures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] );
  428. }
  429. }
  430. // Helper to pick the right setter for a pure (bottom-level) array
  431. function getPureArraySetter( type ) {
  432. switch ( type ) {
  433. case 0x1406: return setValueV1fArray; // FLOAT
  434. case 0x8b50: return setValueV2fArray; // _VEC2
  435. case 0x8b51: return setValueV3fArray; // _VEC3
  436. case 0x8b52: return setValueV4fArray; // _VEC4
  437. case 0x8b5a: return setValueM2Array; // _MAT2
  438. case 0x8b5b: return setValueM3Array; // _MAT3
  439. case 0x8b5c: return setValueM4Array; // _MAT4
  440. case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL
  441. case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2
  442. case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3
  443. case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4
  444. case 0x1405: return setValueV1uiArray; // UINT
  445. case 0x8dc6: return setValueV2uiArray; // _VEC2
  446. case 0x8dc7: return setValueV3uiArray; // _VEC3
  447. case 0x8dc8: return setValueV4uiArray; // _VEC4
  448. case 0x8b5e: // SAMPLER_2D
  449. case 0x8d66: // SAMPLER_EXTERNAL_OES
  450. case 0x8dca: // INT_SAMPLER_2D
  451. case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
  452. case 0x8b62: // SAMPLER_2D_SHADOW
  453. return setValueT1Array;
  454. case 0x8b5f: // SAMPLER_3D
  455. case 0x8dcb: // INT_SAMPLER_3D
  456. case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
  457. return setValueT3DArray;
  458. case 0x8b60: // SAMPLER_CUBE
  459. case 0x8dcc: // INT_SAMPLER_CUBE
  460. case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
  461. case 0x8dc5: // SAMPLER_CUBE_SHADOW
  462. return setValueT6Array;
  463. case 0x8dc1: // SAMPLER_2D_ARRAY
  464. case 0x8dcf: // INT_SAMPLER_2D_ARRAY
  465. case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
  466. case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
  467. return setValueT2DArrayArray;
  468. }
  469. }
  470. // --- Uniform Classes ---
  471. class SingleUniform {
  472. constructor( id, activeInfo, addr ) {
  473. this.id = id;
  474. this.addr = addr;
  475. this.cache = [];
  476. this.setValue = getSingularSetter( activeInfo.type );
  477. // this.path = activeInfo.name; // DEBUG
  478. }
  479. }
  480. class PureArrayUniform {
  481. constructor( id, activeInfo, addr ) {
  482. this.id = id;
  483. this.addr = addr;
  484. this.cache = [];
  485. this.size = activeInfo.size;
  486. this.setValue = getPureArraySetter( activeInfo.type );
  487. // this.path = activeInfo.name; // DEBUG
  488. }
  489. }
  490. class StructuredUniform {
  491. constructor( id ) {
  492. this.id = id;
  493. this.seq = [];
  494. this.map = {};
  495. }
  496. setValue( gl, value, textures ) {
  497. const seq = this.seq;
  498. for ( let i = 0, n = seq.length; i !== n; ++ i ) {
  499. const u = seq[ i ];
  500. u.setValue( gl, value[ u.id ], textures );
  501. }
  502. }
  503. }
  504. // --- Top-level ---
  505. // Parser - builds up the property tree from the path strings
  506. const RePathPart = /(\w+)(\])?(\[|\.)?/g;
  507. // extracts
  508. // - the identifier (member name or array index)
  509. // - followed by an optional right bracket (found when array index)
  510. // - followed by an optional left bracket or dot (type of subscript)
  511. //
  512. // Note: These portions can be read in a non-overlapping fashion and
  513. // allow straightforward parsing of the hierarchy that WebGL encodes
  514. // in the uniform names.
  515. function addUniform( container, uniformObject ) {
  516. container.seq.push( uniformObject );
  517. container.map[ uniformObject.id ] = uniformObject;
  518. }
  519. function parseUniform( activeInfo, addr, container ) {
  520. const path = activeInfo.name,
  521. pathLength = path.length;
  522. // reset RegExp object, because of the early exit of a previous run
  523. RePathPart.lastIndex = 0;
  524. while ( true ) {
  525. const match = RePathPart.exec( path ),
  526. matchEnd = RePathPart.lastIndex;
  527. let id = match[ 1 ];
  528. const idIsIndex = match[ 2 ] === ']',
  529. subscript = match[ 3 ];
  530. if ( idIsIndex ) id = id | 0; // convert to integer
  531. if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
  532. // bare name or "pure" bottom-level array "[0]" suffix
  533. addUniform( container, subscript === undefined ?
  534. new SingleUniform( id, activeInfo, addr ) :
  535. new PureArrayUniform( id, activeInfo, addr ) );
  536. break;
  537. } else {
  538. // step into inner node / create it in case it doesn't exist
  539. const map = container.map;
  540. let next = map[ id ];
  541. if ( next === undefined ) {
  542. next = new StructuredUniform( id );
  543. addUniform( container, next );
  544. }
  545. container = next;
  546. }
  547. }
  548. }
  549. // Root Container
  550. class WebGLUniforms {
  551. constructor( gl, program ) {
  552. this.seq = [];
  553. this.map = {};
  554. const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
  555. for ( let i = 0; i < n; ++ i ) {
  556. const info = gl.getActiveUniform( program, i ),
  557. addr = gl.getUniformLocation( program, info.name );
  558. parseUniform( info, addr, this );
  559. }
  560. }
  561. setValue( gl, name, value, textures ) {
  562. const u = this.map[ name ];
  563. if ( u !== undefined ) u.setValue( gl, value, textures );
  564. }
  565. setOptional( gl, object, name ) {
  566. const v = object[ name ];
  567. if ( v !== undefined ) this.setValue( gl, name, v );
  568. }
  569. static upload( gl, seq, values, textures ) {
  570. for ( let i = 0, n = seq.length; i !== n; ++ i ) {
  571. const u = seq[ i ],
  572. v = values[ u.id ];
  573. if ( v.needsUpdate !== false ) {
  574. // note: always updating when .needsUpdate is undefined
  575. u.setValue( gl, v.value, textures );
  576. }
  577. }
  578. }
  579. static seqWithValue( seq, values ) {
  580. const r = [];
  581. for ( let i = 0, n = seq.length; i !== n; ++ i ) {
  582. const u = seq[ i ];
  583. if ( u.id in values ) r.push( u );
  584. }
  585. return r;
  586. }
  587. }
  588. export { WebGLUniforms };