createUniformArray.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. import Cartesian2 from "../Core/Cartesian2.js";
  2. import Cartesian3 from "../Core/Cartesian3.js";
  3. import Cartesian4 from "../Core/Cartesian4.js";
  4. import Color from "../Core/Color.js";
  5. import defined from "../Core/defined.js";
  6. import DeveloperError from "../Core/DeveloperError.js";
  7. import Matrix2 from "../Core/Matrix2.js";
  8. import Matrix3 from "../Core/Matrix3.js";
  9. import Matrix4 from "../Core/Matrix4.js";
  10. import RuntimeError from "../Core/RuntimeError.js";
  11. /**
  12. * @private
  13. * @constructor
  14. */
  15. function createUniformArray(gl, activeUniform, uniformName, locations) {
  16. switch (activeUniform.type) {
  17. case gl.FLOAT:
  18. return new UniformArrayFloat(gl, activeUniform, uniformName, locations);
  19. case gl.FLOAT_VEC2:
  20. return new UniformArrayFloatVec2(
  21. gl,
  22. activeUniform,
  23. uniformName,
  24. locations
  25. );
  26. case gl.FLOAT_VEC3:
  27. return new UniformArrayFloatVec3(
  28. gl,
  29. activeUniform,
  30. uniformName,
  31. locations
  32. );
  33. case gl.FLOAT_VEC4:
  34. return new UniformArrayFloatVec4(
  35. gl,
  36. activeUniform,
  37. uniformName,
  38. locations
  39. );
  40. case gl.SAMPLER_2D:
  41. case gl.SAMPLER_CUBE:
  42. return new UniformArraySampler(gl, activeUniform, uniformName, locations);
  43. case gl.INT:
  44. case gl.BOOL:
  45. return new UniformArrayInt(gl, activeUniform, uniformName, locations);
  46. case gl.INT_VEC2:
  47. case gl.BOOL_VEC2:
  48. return new UniformArrayIntVec2(gl, activeUniform, uniformName, locations);
  49. case gl.INT_VEC3:
  50. case gl.BOOL_VEC3:
  51. return new UniformArrayIntVec3(gl, activeUniform, uniformName, locations);
  52. case gl.INT_VEC4:
  53. case gl.BOOL_VEC4:
  54. return new UniformArrayIntVec4(gl, activeUniform, uniformName, locations);
  55. case gl.FLOAT_MAT2:
  56. return new UniformArrayMat2(gl, activeUniform, uniformName, locations);
  57. case gl.FLOAT_MAT3:
  58. return new UniformArrayMat3(gl, activeUniform, uniformName, locations);
  59. case gl.FLOAT_MAT4:
  60. return new UniformArrayMat4(gl, activeUniform, uniformName, locations);
  61. default:
  62. throw new RuntimeError(
  63. `Unrecognized uniform type: ${activeUniform.type} for uniform "${uniformName}".`
  64. );
  65. }
  66. }
  67. /**
  68. * @private
  69. * @constructor
  70. */
  71. function UniformArrayFloat(gl, activeUniform, uniformName, locations) {
  72. const length = locations.length;
  73. /**
  74. * @type {String}
  75. * @readonly
  76. */
  77. this.name = uniformName;
  78. this.value = new Array(length);
  79. this._value = new Float32Array(length);
  80. this._gl = gl;
  81. this._location = locations[0];
  82. }
  83. UniformArrayFloat.prototype.set = function () {
  84. const value = this.value;
  85. const length = value.length;
  86. const arraybuffer = this._value;
  87. let changed = false;
  88. for (let i = 0; i < length; ++i) {
  89. const v = value[i];
  90. if (v !== arraybuffer[i]) {
  91. arraybuffer[i] = v;
  92. changed = true;
  93. }
  94. }
  95. if (changed) {
  96. this._gl.uniform1fv(this._location, arraybuffer);
  97. }
  98. };
  99. ///////////////////////////////////////////////////////////////////////////
  100. /**
  101. * @private
  102. * @constructor
  103. */
  104. function UniformArrayFloatVec2(gl, activeUniform, uniformName, locations) {
  105. const length = locations.length;
  106. /**
  107. * @type {String}
  108. * @readonly
  109. */
  110. this.name = uniformName;
  111. this.value = new Array(length);
  112. this._value = new Float32Array(length * 2);
  113. this._gl = gl;
  114. this._location = locations[0];
  115. }
  116. UniformArrayFloatVec2.prototype.set = function () {
  117. const value = this.value;
  118. const length = value.length;
  119. const arraybuffer = this._value;
  120. let changed = false;
  121. let j = 0;
  122. for (let i = 0; i < length; ++i) {
  123. const v = value[i];
  124. if (!Cartesian2.equalsArray(v, arraybuffer, j)) {
  125. Cartesian2.pack(v, arraybuffer, j);
  126. changed = true;
  127. }
  128. j += 2;
  129. }
  130. if (changed) {
  131. this._gl.uniform2fv(this._location, arraybuffer);
  132. }
  133. };
  134. ///////////////////////////////////////////////////////////////////////////
  135. /**
  136. * @private
  137. * @constructor
  138. */
  139. function UniformArrayFloatVec3(gl, activeUniform, uniformName, locations) {
  140. const length = locations.length;
  141. /**
  142. * @type {String}
  143. * @readonly
  144. */
  145. this.name = uniformName;
  146. this.value = new Array(length);
  147. this._value = new Float32Array(length * 3);
  148. this._gl = gl;
  149. this._location = locations[0];
  150. }
  151. UniformArrayFloatVec3.prototype.set = function () {
  152. const value = this.value;
  153. const length = value.length;
  154. const arraybuffer = this._value;
  155. let changed = false;
  156. let j = 0;
  157. for (let i = 0; i < length; ++i) {
  158. const v = value[i];
  159. if (defined(v.red)) {
  160. if (
  161. v.red !== arraybuffer[j] ||
  162. v.green !== arraybuffer[j + 1] ||
  163. v.blue !== arraybuffer[j + 2]
  164. ) {
  165. arraybuffer[j] = v.red;
  166. arraybuffer[j + 1] = v.green;
  167. arraybuffer[j + 2] = v.blue;
  168. changed = true;
  169. }
  170. } else if (defined(v.x)) {
  171. if (!Cartesian3.equalsArray(v, arraybuffer, j)) {
  172. Cartesian3.pack(v, arraybuffer, j);
  173. changed = true;
  174. }
  175. } else {
  176. //>>includeStart('debug', pragmas.debug);
  177. throw new DeveloperError("Invalid vec3 value.");
  178. //>>includeEnd('debug');
  179. }
  180. j += 3;
  181. }
  182. if (changed) {
  183. this._gl.uniform3fv(this._location, arraybuffer);
  184. }
  185. };
  186. ///////////////////////////////////////////////////////////////////////////
  187. /**
  188. * @private
  189. * @constructor
  190. */
  191. function UniformArrayFloatVec4(gl, activeUniform, uniformName, locations) {
  192. const length = locations.length;
  193. /**
  194. * @type {String}
  195. * @readonly
  196. */
  197. this.name = uniformName;
  198. this.value = new Array(length);
  199. this._value = new Float32Array(length * 4);
  200. this._gl = gl;
  201. this._location = locations[0];
  202. }
  203. UniformArrayFloatVec4.prototype.set = function () {
  204. // PERFORMANCE_IDEA: if it is a common case that only a few elements
  205. // in a uniform array change, we could use heuristics to determine
  206. // when it is better to call uniform4f for each element that changed
  207. // vs. call uniform4fv once to set the entire array. This applies
  208. // to all uniform array types, not just vec4. We might not care
  209. // once we have uniform buffers since that will be the fast path.
  210. // PERFORMANCE_IDEA: Micro-optimization (I bet it works though):
  211. // As soon as changed is true, break into a separate loop that
  212. // does the copy without the equals check.
  213. const value = this.value;
  214. const length = value.length;
  215. const arraybuffer = this._value;
  216. let changed = false;
  217. let j = 0;
  218. for (let i = 0; i < length; ++i) {
  219. const v = value[i];
  220. if (defined(v.red)) {
  221. if (!Color.equalsArray(v, arraybuffer, j)) {
  222. Color.pack(v, arraybuffer, j);
  223. changed = true;
  224. }
  225. } else if (defined(v.x)) {
  226. if (!Cartesian4.equalsArray(v, arraybuffer, j)) {
  227. Cartesian4.pack(v, arraybuffer, j);
  228. changed = true;
  229. }
  230. } else {
  231. //>>includeStart('debug', pragmas.debug);
  232. throw new DeveloperError("Invalid vec4 value.");
  233. //>>includeEnd('debug');
  234. }
  235. j += 4;
  236. }
  237. if (changed) {
  238. this._gl.uniform4fv(this._location, arraybuffer);
  239. }
  240. };
  241. ///////////////////////////////////////////////////////////////////////////
  242. /**
  243. * @private
  244. * @constructor
  245. */
  246. function UniformArraySampler(gl, activeUniform, uniformName, locations) {
  247. const length = locations.length;
  248. /**
  249. * @type {String}
  250. * @readonly
  251. */
  252. this.name = uniformName;
  253. this.value = new Array(length);
  254. this._value = new Float32Array(length);
  255. this._gl = gl;
  256. this._locations = locations;
  257. this.textureUnitIndex = undefined;
  258. }
  259. UniformArraySampler.prototype.set = function () {
  260. const gl = this._gl;
  261. const textureUnitIndex = gl.TEXTURE0 + this.textureUnitIndex;
  262. const value = this.value;
  263. const length = value.length;
  264. for (let i = 0; i < length; ++i) {
  265. const v = value[i];
  266. gl.activeTexture(textureUnitIndex + i);
  267. gl.bindTexture(v._target, v._texture);
  268. }
  269. };
  270. UniformArraySampler.prototype._setSampler = function (textureUnitIndex) {
  271. this.textureUnitIndex = textureUnitIndex;
  272. const locations = this._locations;
  273. const length = locations.length;
  274. for (let i = 0; i < length; ++i) {
  275. const index = textureUnitIndex + i;
  276. this._gl.uniform1i(locations[i], index);
  277. }
  278. return textureUnitIndex + length;
  279. };
  280. ///////////////////////////////////////////////////////////////////////////
  281. /**
  282. * @private
  283. * @constructor
  284. */
  285. function UniformArrayInt(gl, activeUniform, uniformName, locations) {
  286. const length = locations.length;
  287. /**
  288. * @type {String}
  289. * @readonly
  290. */
  291. this.name = uniformName;
  292. this.value = new Array(length);
  293. this._value = new Int32Array(length);
  294. this._gl = gl;
  295. this._location = locations[0];
  296. }
  297. UniformArrayInt.prototype.set = function () {
  298. const value = this.value;
  299. const length = value.length;
  300. const arraybuffer = this._value;
  301. let changed = false;
  302. for (let i = 0; i < length; ++i) {
  303. const v = value[i];
  304. if (v !== arraybuffer[i]) {
  305. arraybuffer[i] = v;
  306. changed = true;
  307. }
  308. }
  309. if (changed) {
  310. this._gl.uniform1iv(this._location, arraybuffer);
  311. }
  312. };
  313. ///////////////////////////////////////////////////////////////////////////
  314. /**
  315. * @private
  316. * @constructor
  317. */
  318. function UniformArrayIntVec2(gl, activeUniform, uniformName, locations) {
  319. const length = locations.length;
  320. /**
  321. * @type {String}
  322. * @readonly
  323. */
  324. this.name = uniformName;
  325. this.value = new Array(length);
  326. this._value = new Int32Array(length * 2);
  327. this._gl = gl;
  328. this._location = locations[0];
  329. }
  330. UniformArrayIntVec2.prototype.set = function () {
  331. const value = this.value;
  332. const length = value.length;
  333. const arraybuffer = this._value;
  334. let changed = false;
  335. let j = 0;
  336. for (let i = 0; i < length; ++i) {
  337. const v = value[i];
  338. if (!Cartesian2.equalsArray(v, arraybuffer, j)) {
  339. Cartesian2.pack(v, arraybuffer, j);
  340. changed = true;
  341. }
  342. j += 2;
  343. }
  344. if (changed) {
  345. this._gl.uniform2iv(this._location, arraybuffer);
  346. }
  347. };
  348. ///////////////////////////////////////////////////////////////////////////
  349. /**
  350. * @private
  351. * @constructor
  352. */
  353. function UniformArrayIntVec3(gl, activeUniform, uniformName, locations) {
  354. const length = locations.length;
  355. /**
  356. * @type {String}
  357. * @readonly
  358. */
  359. this.name = uniformName;
  360. this.value = new Array(length);
  361. this._value = new Int32Array(length * 3);
  362. this._gl = gl;
  363. this._location = locations[0];
  364. }
  365. UniformArrayIntVec3.prototype.set = function () {
  366. const value = this.value;
  367. const length = value.length;
  368. const arraybuffer = this._value;
  369. let changed = false;
  370. let j = 0;
  371. for (let i = 0; i < length; ++i) {
  372. const v = value[i];
  373. if (!Cartesian3.equalsArray(v, arraybuffer, j)) {
  374. Cartesian3.pack(v, arraybuffer, j);
  375. changed = true;
  376. }
  377. j += 3;
  378. }
  379. if (changed) {
  380. this._gl.uniform3iv(this._location, arraybuffer);
  381. }
  382. };
  383. ///////////////////////////////////////////////////////////////////////////
  384. /**
  385. * @private
  386. * @constructor
  387. */
  388. function UniformArrayIntVec4(gl, activeUniform, uniformName, locations) {
  389. const length = locations.length;
  390. /**
  391. * @type {String}
  392. * @readonly
  393. */
  394. this.name = uniformName;
  395. this.value = new Array(length);
  396. this._value = new Int32Array(length * 4);
  397. this._gl = gl;
  398. this._location = locations[0];
  399. }
  400. UniformArrayIntVec4.prototype.set = function () {
  401. const value = this.value;
  402. const length = value.length;
  403. const arraybuffer = this._value;
  404. let changed = false;
  405. let j = 0;
  406. for (let i = 0; i < length; ++i) {
  407. const v = value[i];
  408. if (!Cartesian4.equalsArray(v, arraybuffer, j)) {
  409. Cartesian4.pack(v, arraybuffer, j);
  410. changed = true;
  411. }
  412. j += 4;
  413. }
  414. if (changed) {
  415. this._gl.uniform4iv(this._location, arraybuffer);
  416. }
  417. };
  418. ///////////////////////////////////////////////////////////////////////////
  419. /**
  420. * @private
  421. * @constructor
  422. */
  423. function UniformArrayMat2(gl, activeUniform, uniformName, locations) {
  424. const length = locations.length;
  425. /**
  426. * @type {String}
  427. * @readonly
  428. */
  429. this.name = uniformName;
  430. this.value = new Array(length);
  431. this._value = new Float32Array(length * 4);
  432. this._gl = gl;
  433. this._location = locations[0];
  434. }
  435. UniformArrayMat2.prototype.set = function () {
  436. const value = this.value;
  437. const length = value.length;
  438. const arraybuffer = this._value;
  439. let changed = false;
  440. let j = 0;
  441. for (let i = 0; i < length; ++i) {
  442. const v = value[i];
  443. if (!Matrix2.equalsArray(v, arraybuffer, j)) {
  444. Matrix2.pack(v, arraybuffer, j);
  445. changed = true;
  446. }
  447. j += 4;
  448. }
  449. if (changed) {
  450. this._gl.uniformMatrix2fv(this._location, false, arraybuffer);
  451. }
  452. };
  453. ///////////////////////////////////////////////////////////////////////////
  454. /**
  455. * @private
  456. * @constructor
  457. */
  458. function UniformArrayMat3(gl, activeUniform, uniformName, locations) {
  459. const length = locations.length;
  460. /**
  461. * @type {String}
  462. * @readonly
  463. */
  464. this.name = uniformName;
  465. this.value = new Array(length);
  466. this._value = new Float32Array(length * 9);
  467. this._gl = gl;
  468. this._location = locations[0];
  469. }
  470. UniformArrayMat3.prototype.set = function () {
  471. const value = this.value;
  472. const length = value.length;
  473. const arraybuffer = this._value;
  474. let changed = false;
  475. let j = 0;
  476. for (let i = 0; i < length; ++i) {
  477. const v = value[i];
  478. if (!Matrix3.equalsArray(v, arraybuffer, j)) {
  479. Matrix3.pack(v, arraybuffer, j);
  480. changed = true;
  481. }
  482. j += 9;
  483. }
  484. if (changed) {
  485. this._gl.uniformMatrix3fv(this._location, false, arraybuffer);
  486. }
  487. };
  488. ///////////////////////////////////////////////////////////////////////////
  489. /**
  490. * @private
  491. * @constructor
  492. */
  493. function UniformArrayMat4(gl, activeUniform, uniformName, locations) {
  494. const length = locations.length;
  495. /**
  496. * @type {String}
  497. * @readonly
  498. */
  499. this.name = uniformName;
  500. this.value = new Array(length);
  501. this._value = new Float32Array(length * 16);
  502. this._gl = gl;
  503. this._location = locations[0];
  504. }
  505. UniformArrayMat4.prototype.set = function () {
  506. const value = this.value;
  507. const length = value.length;
  508. const arraybuffer = this._value;
  509. let changed = false;
  510. let j = 0;
  511. for (let i = 0; i < length; ++i) {
  512. const v = value[i];
  513. if (!Matrix4.equalsArray(v, arraybuffer, j)) {
  514. Matrix4.pack(v, arraybuffer, j);
  515. changed = true;
  516. }
  517. j += 16;
  518. }
  519. if (changed) {
  520. this._gl.uniformMatrix4fv(this._location, false, arraybuffer);
  521. }
  522. };
  523. export default createUniformArray;