ctm.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. /*
  2. Copyright (c) 2011 Juan Mellado
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. THE SOFTWARE.
  18. */
  19. /*
  20. References:
  21. - "OpenCTM: The Open Compressed Triangle Mesh file format" by Marcus Geelnard
  22. http://openctm.sourceforge.net/
  23. */
  24. var CTM = CTM || {};
  25. CTM.CompressionMethod = {
  26. RAW: 0x00574152,
  27. MG1: 0x0031474d,
  28. MG2: 0x0032474d
  29. };
  30. CTM.Flags = {
  31. NORMALS: 0x00000001
  32. };
  33. CTM.File = function(stream){
  34. this.load(stream);
  35. };
  36. CTM.File.prototype.load = function(stream){
  37. this.header = new CTM.FileHeader(stream);
  38. this.body = new CTM.FileBody(this.header);
  39. this.getReader().read(stream, this.body);
  40. };
  41. CTM.File.prototype.getReader = function(){
  42. var reader;
  43. switch(this.header.compressionMethod){
  44. case CTM.CompressionMethod.RAW:
  45. reader = new CTM.ReaderRAW();
  46. break;
  47. case CTM.CompressionMethod.MG1:
  48. reader = new CTM.ReaderMG1();
  49. break;
  50. case CTM.CompressionMethod.MG2:
  51. reader = new CTM.ReaderMG2();
  52. break;
  53. }
  54. return reader;
  55. };
  56. CTM.FileHeader = function(stream){
  57. stream.readInt32(); //magic "OCTM"
  58. this.fileFormat = stream.readInt32();
  59. this.compressionMethod = stream.readInt32();
  60. this.vertexCount = stream.readInt32();
  61. this.triangleCount = stream.readInt32();
  62. this.uvMapCount = stream.readInt32();
  63. this.attrMapCount = stream.readInt32();
  64. this.flags = stream.readInt32();
  65. this.comment = stream.readString();
  66. };
  67. CTM.FileHeader.prototype.hasNormals = function(){
  68. return this.flags & CTM.Flags.NORMALS;
  69. };
  70. CTM.FileBody = function(header){
  71. var i = header.triangleCount * 3,
  72. v = header.vertexCount * 3,
  73. n = header.hasNormals()? header.vertexCount * 3: 0,
  74. u = header.vertexCount * 2,
  75. a = header.vertexCount * 4,
  76. j = 0;
  77. var data = new ArrayBuffer(
  78. (i + v + n + (u * header.uvMapCount) + (a * header.attrMapCount) ) * 4);
  79. this.indices = new Uint32Array(data, 0, i);
  80. this.vertices = new Float32Array(data, i * 4, v);
  81. if ( header.hasNormals() ){
  82. this.normals = new Float32Array(data, (i + v) * 4, n);
  83. }
  84. if (header.uvMapCount){
  85. this.uvMaps = [];
  86. for (j = 0; j < header.uvMapCount; ++ j){
  87. this.uvMaps[j] = {uv: new Float32Array(data,
  88. (i + v + n + (j * u) ) * 4, u) };
  89. }
  90. }
  91. if (header.attrMapCount){
  92. this.attrMaps = [];
  93. for (j = 0; j < header.attrMapCount; ++ j){
  94. this.attrMaps[j] = {attr: new Float32Array(data,
  95. (i + v + n + (u * header.uvMapCount) + (j * a) ) * 4, a) };
  96. }
  97. }
  98. };
  99. CTM.FileMG2Header = function(stream){
  100. stream.readInt32(); //magic "MG2H"
  101. this.vertexPrecision = stream.readFloat32();
  102. this.normalPrecision = stream.readFloat32();
  103. this.lowerBoundx = stream.readFloat32();
  104. this.lowerBoundy = stream.readFloat32();
  105. this.lowerBoundz = stream.readFloat32();
  106. this.higherBoundx = stream.readFloat32();
  107. this.higherBoundy = stream.readFloat32();
  108. this.higherBoundz = stream.readFloat32();
  109. this.divx = stream.readInt32();
  110. this.divy = stream.readInt32();
  111. this.divz = stream.readInt32();
  112. this.sizex = (this.higherBoundx - this.lowerBoundx) / this.divx;
  113. this.sizey = (this.higherBoundy - this.lowerBoundy) / this.divy;
  114. this.sizez = (this.higherBoundz - this.lowerBoundz) / this.divz;
  115. };
  116. CTM.ReaderRAW = function(){
  117. };
  118. CTM.ReaderRAW.prototype.read = function(stream, body){
  119. this.readIndices(stream, body.indices);
  120. this.readVertices(stream, body.vertices);
  121. if (body.normals){
  122. this.readNormals(stream, body.normals);
  123. }
  124. if (body.uvMaps){
  125. this.readUVMaps(stream, body.uvMaps);
  126. }
  127. if (body.attrMaps){
  128. this.readAttrMaps(stream, body.attrMaps);
  129. }
  130. };
  131. CTM.ReaderRAW.prototype.readIndices = function(stream, indices){
  132. stream.readInt32(); //magic "INDX"
  133. stream.readArrayInt32(indices);
  134. };
  135. CTM.ReaderRAW.prototype.readVertices = function(stream, vertices){
  136. stream.readInt32(); //magic "VERT"
  137. stream.readArrayFloat32(vertices);
  138. };
  139. CTM.ReaderRAW.prototype.readNormals = function(stream, normals){
  140. stream.readInt32(); //magic "NORM"
  141. stream.readArrayFloat32(normals);
  142. };
  143. CTM.ReaderRAW.prototype.readUVMaps = function(stream, uvMaps){
  144. var i = 0;
  145. for (; i < uvMaps.length; ++ i){
  146. stream.readInt32(); //magic "TEXC"
  147. uvMaps[i].name = stream.readString();
  148. uvMaps[i].filename = stream.readString();
  149. stream.readArrayFloat32(uvMaps[i].uv);
  150. }
  151. };
  152. CTM.ReaderRAW.prototype.readAttrMaps = function(stream, attrMaps){
  153. var i = 0;
  154. for (; i < attrMaps.length; ++ i){
  155. stream.readInt32(); //magic "ATTR"
  156. attrMaps[i].name = stream.readString();
  157. stream.readArrayFloat32(attrMaps[i].attr);
  158. }
  159. };
  160. CTM.ReaderMG1 = function(){
  161. };
  162. CTM.ReaderMG1.prototype.read = function(stream, body){
  163. this.readIndices(stream, body.indices);
  164. this.readVertices(stream, body.vertices);
  165. if (body.normals){
  166. this.readNormals(stream, body.normals);
  167. }
  168. if (body.uvMaps){
  169. this.readUVMaps(stream, body.uvMaps);
  170. }
  171. if (body.attrMaps){
  172. this.readAttrMaps(stream, body.attrMaps);
  173. }
  174. };
  175. CTM.ReaderMG1.prototype.readIndices = function(stream, indices){
  176. stream.readInt32(); //magic "INDX"
  177. stream.readInt32(); //packed size
  178. var interleaved = new CTM.InterleavedStream(indices, 3);
  179. LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
  180. CTM.restoreIndices(indices, indices.length);
  181. };
  182. CTM.ReaderMG1.prototype.readVertices = function(stream, vertices){
  183. stream.readInt32(); //magic "VERT"
  184. stream.readInt32(); //packed size
  185. var interleaved = new CTM.InterleavedStream(vertices, 1);
  186. LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
  187. };
  188. CTM.ReaderMG1.prototype.readNormals = function(stream, normals){
  189. stream.readInt32(); //magic "NORM"
  190. stream.readInt32(); //packed size
  191. var interleaved = new CTM.InterleavedStream(normals, 3);
  192. LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
  193. };
  194. CTM.ReaderMG1.prototype.readUVMaps = function(stream, uvMaps){
  195. var i = 0;
  196. for (; i < uvMaps.length; ++ i){
  197. stream.readInt32(); //magic "TEXC"
  198. uvMaps[i].name = stream.readString();
  199. uvMaps[i].filename = stream.readString();
  200. stream.readInt32(); //packed size
  201. var interleaved = new CTM.InterleavedStream(uvMaps[i].uv, 2);
  202. LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
  203. }
  204. };
  205. CTM.ReaderMG1.prototype.readAttrMaps = function(stream, attrMaps){
  206. var i = 0;
  207. for (; i < attrMaps.length; ++ i){
  208. stream.readInt32(); //magic "ATTR"
  209. attrMaps[i].name = stream.readString();
  210. stream.readInt32(); //packed size
  211. var interleaved = new CTM.InterleavedStream(attrMaps[i].attr, 4);
  212. LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
  213. }
  214. };
  215. CTM.ReaderMG2 = function(){
  216. };
  217. CTM.ReaderMG2.prototype.read = function(stream, body){
  218. this.MG2Header = new CTM.FileMG2Header(stream);
  219. this.readVertices(stream, body.vertices);
  220. this.readIndices(stream, body.indices);
  221. if (body.normals){
  222. this.readNormals(stream, body);
  223. }
  224. if (body.uvMaps){
  225. this.readUVMaps(stream, body.uvMaps);
  226. }
  227. if (body.attrMaps){
  228. this.readAttrMaps(stream, body.attrMaps);
  229. }
  230. };
  231. CTM.ReaderMG2.prototype.readVertices = function(stream, vertices){
  232. stream.readInt32(); //magic "VERT"
  233. stream.readInt32(); //packed size
  234. var interleaved = new CTM.InterleavedStream(vertices, 3);
  235. LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
  236. var gridIndices = this.readGridIndices(stream, vertices);
  237. CTM.restoreVertices(vertices, this.MG2Header, gridIndices, this.MG2Header.vertexPrecision);
  238. };
  239. CTM.ReaderMG2.prototype.readGridIndices = function(stream, vertices){
  240. stream.readInt32(); //magic "GIDX"
  241. stream.readInt32(); //packed size
  242. var gridIndices = new Uint32Array(vertices.length / 3);
  243. var interleaved = new CTM.InterleavedStream(gridIndices, 1);
  244. LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
  245. CTM.restoreGridIndices(gridIndices, gridIndices.length);
  246. return gridIndices;
  247. };
  248. CTM.ReaderMG2.prototype.readIndices = function(stream, indices){
  249. stream.readInt32(); //magic "INDX"
  250. stream.readInt32(); //packed size
  251. var interleaved = new CTM.InterleavedStream(indices, 3);
  252. LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
  253. CTM.restoreIndices(indices, indices.length);
  254. };
  255. CTM.ReaderMG2.prototype.readNormals = function(stream, body){
  256. stream.readInt32(); //magic "NORM"
  257. stream.readInt32(); //packed size
  258. var interleaved = new CTM.InterleavedStream(body.normals, 3);
  259. LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
  260. var smooth = CTM.calcSmoothNormals(body.indices, body.vertices);
  261. CTM.restoreNormals(body.normals, smooth, this.MG2Header.normalPrecision);
  262. };
  263. CTM.ReaderMG2.prototype.readUVMaps = function(stream, uvMaps){
  264. var i = 0;
  265. for (; i < uvMaps.length; ++ i){
  266. stream.readInt32(); //magic "TEXC"
  267. uvMaps[i].name = stream.readString();
  268. uvMaps[i].filename = stream.readString();
  269. var precision = stream.readFloat32();
  270. stream.readInt32(); //packed size
  271. var interleaved = new CTM.InterleavedStream(uvMaps[i].uv, 2);
  272. LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
  273. CTM.restoreMap(uvMaps[i].uv, 2, precision);
  274. }
  275. };
  276. CTM.ReaderMG2.prototype.readAttrMaps = function(stream, attrMaps){
  277. var i = 0;
  278. for (; i < attrMaps.length; ++ i){
  279. stream.readInt32(); //magic "ATTR"
  280. attrMaps[i].name = stream.readString();
  281. var precision = stream.readFloat32();
  282. stream.readInt32(); //packed size
  283. var interleaved = new CTM.InterleavedStream(attrMaps[i].attr, 4);
  284. LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
  285. CTM.restoreMap(attrMaps[i].attr, 4, precision);
  286. }
  287. };
  288. CTM.restoreIndices = function(indices, len){
  289. var i = 3;
  290. if (len > 0){
  291. indices[2] += indices[0];
  292. indices[1] += indices[0];
  293. }
  294. for (; i < len; i += 3){
  295. indices[i] += indices[i - 3];
  296. if (indices[i] === indices[i - 3]){
  297. indices[i + 1] += indices[i - 2];
  298. }else{
  299. indices[i + 1] += indices[i];
  300. }
  301. indices[i + 2] += indices[i];
  302. }
  303. };
  304. CTM.restoreGridIndices = function(gridIndices, len){
  305. var i = 1;
  306. for (; i < len; ++ i){
  307. gridIndices[i] += gridIndices[i - 1];
  308. }
  309. };
  310. CTM.restoreVertices = function(vertices, grid, gridIndices, precision){
  311. var gridIdx, delta, x, y, z,
  312. intVertices = new Uint32Array(vertices.buffer, vertices.byteOffset, vertices.length),
  313. ydiv = grid.divx, zdiv = ydiv * grid.divy,
  314. prevGridIdx = 0x7fffffff, prevDelta = 0,
  315. i = 0, j = 0, len = gridIndices.length;
  316. for (; i < len; j += 3){
  317. x = gridIdx = gridIndices[i ++];
  318. z = ~~(x / zdiv);
  319. x -= ~~(z * zdiv);
  320. y = ~~(x / ydiv);
  321. x -= ~~(y * ydiv);
  322. delta = intVertices[j];
  323. if (gridIdx === prevGridIdx){
  324. delta += prevDelta;
  325. }
  326. vertices[j] = grid.lowerBoundx +
  327. x * grid.sizex + precision * delta;
  328. vertices[j + 1] = grid.lowerBoundy +
  329. y * grid.sizey + precision * intVertices[j + 1];
  330. vertices[j + 2] = grid.lowerBoundz +
  331. z * grid.sizez + precision * intVertices[j + 2];
  332. prevGridIdx = gridIdx;
  333. prevDelta = delta;
  334. }
  335. };
  336. CTM.restoreNormals = function(normals, smooth, precision){
  337. var ro, phi, theta, sinPhi,
  338. nx, ny, nz, by, bz, len,
  339. intNormals = new Uint32Array(normals.buffer, normals.byteOffset, normals.length),
  340. i = 0, k = normals.length,
  341. PI_DIV_2 = 3.141592653589793238462643 * 0.5;
  342. for (; i < k; i += 3){
  343. ro = intNormals[i] * precision;
  344. phi = intNormals[i + 1];
  345. if (phi === 0){
  346. normals[i] = smooth[i] * ro;
  347. normals[i + 1] = smooth[i + 1] * ro;
  348. normals[i + 2] = smooth[i + 2] * ro;
  349. }else{
  350. if (phi <= 4){
  351. theta = (intNormals[i + 2] - 2) * PI_DIV_2;
  352. }else{
  353. theta = ( (intNormals[i + 2] * 4 / phi) - 2) * PI_DIV_2;
  354. }
  355. phi *= precision * PI_DIV_2;
  356. sinPhi = ro * Math.sin(phi);
  357. nx = sinPhi * Math.cos(theta);
  358. ny = sinPhi * Math.sin(theta);
  359. nz = ro * Math.cos(phi);
  360. bz = smooth[i + 1];
  361. by = smooth[i] - smooth[i + 2];
  362. len = Math.sqrt(2 * bz * bz + by * by);
  363. if (len > 1e-20){
  364. by /= len;
  365. bz /= len;
  366. }
  367. normals[i] = smooth[i] * nz +
  368. (smooth[i + 1] * bz - smooth[i + 2] * by) * ny - bz * nx;
  369. normals[i + 1] = smooth[i + 1] * nz -
  370. (smooth[i + 2] + smooth[i] ) * bz * ny + by * nx;
  371. normals[i + 2] = smooth[i + 2] * nz +
  372. (smooth[i] * by + smooth[i + 1] * bz) * ny + bz * nx;
  373. }
  374. }
  375. };
  376. CTM.restoreMap = function(map, count, precision){
  377. var delta, value,
  378. intMap = new Uint32Array(map.buffer, map.byteOffset, map.length),
  379. i = 0, j, len = map.length;
  380. for (; i < count; ++ i){
  381. delta = 0;
  382. for (j = i; j < len; j += count){
  383. value = intMap[j];
  384. delta += value & 1? -( (value + 1) >> 1): value >> 1;
  385. map[j] = delta * precision;
  386. }
  387. }
  388. };
  389. CTM.calcSmoothNormals = function(indices, vertices){
  390. var smooth = new Float32Array(vertices.length),
  391. indx, indy, indz, nx, ny, nz,
  392. v1x, v1y, v1z, v2x, v2y, v2z, len,
  393. i, k;
  394. for (i = 0, k = indices.length; i < k;){
  395. indx = indices[i ++] * 3;
  396. indy = indices[i ++] * 3;
  397. indz = indices[i ++] * 3;
  398. v1x = vertices[indy] - vertices[indx];
  399. v2x = vertices[indz] - vertices[indx];
  400. v1y = vertices[indy + 1] - vertices[indx + 1];
  401. v2y = vertices[indz + 1] - vertices[indx + 1];
  402. v1z = vertices[indy + 2] - vertices[indx + 2];
  403. v2z = vertices[indz + 2] - vertices[indx + 2];
  404. nx = v1y * v2z - v1z * v2y;
  405. ny = v1z * v2x - v1x * v2z;
  406. nz = v1x * v2y - v1y * v2x;
  407. len = Math.sqrt(nx * nx + ny * ny + nz * nz);
  408. if (len > 1e-10){
  409. nx /= len;
  410. ny /= len;
  411. nz /= len;
  412. }
  413. smooth[indx] += nx;
  414. smooth[indx + 1] += ny;
  415. smooth[indx + 2] += nz;
  416. smooth[indy] += nx;
  417. smooth[indy + 1] += ny;
  418. smooth[indy + 2] += nz;
  419. smooth[indz] += nx;
  420. smooth[indz + 1] += ny;
  421. smooth[indz + 2] += nz;
  422. }
  423. for (i = 0, k = smooth.length; i < k; i += 3){
  424. len = Math.sqrt(smooth[i] * smooth[i] +
  425. smooth[i + 1] * smooth[i + 1] +
  426. smooth[i + 2] * smooth[i + 2]);
  427. if(len > 1e-10){
  428. smooth[i] /= len;
  429. smooth[i + 1] /= len;
  430. smooth[i + 2] /= len;
  431. }
  432. }
  433. return smooth;
  434. };
  435. CTM.isLittleEndian = (function(){
  436. var buffer = new ArrayBuffer(2),
  437. bytes = new Uint8Array(buffer),
  438. ints = new Uint16Array(buffer);
  439. bytes[0] = 1;
  440. return ints[0] === 1;
  441. }());
  442. CTM.InterleavedStream = function(data, count){
  443. this.data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
  444. this.offset = CTM.isLittleEndian? 3: 0;
  445. this.count = count * 4;
  446. this.len = this.data.length;
  447. };
  448. CTM.InterleavedStream.prototype.writeByte = function(value){
  449. this.data[this.offset] = value;
  450. this.offset += this.count;
  451. if (this.offset >= this.len){
  452. this.offset -= this.len - 4;
  453. if (this.offset >= this.count){
  454. this.offset -= this.count + (CTM.isLittleEndian? 1: -1);
  455. }
  456. }
  457. };
  458. CTM.Stream = function(data){
  459. this.data = data;
  460. this.offset = 0;
  461. };
  462. CTM.Stream.prototype.TWO_POW_MINUS23 = Math.pow(2, -23);
  463. CTM.Stream.prototype.TWO_POW_MINUS126 = Math.pow(2, -126);
  464. CTM.Stream.prototype.readByte = function(){
  465. return this.data[this.offset ++] & 0xff;
  466. };
  467. CTM.Stream.prototype.readInt32 = function(){
  468. var i = this.readByte();
  469. i |= this.readByte() << 8;
  470. i |= this.readByte() << 16;
  471. return i | (this.readByte() << 24);
  472. };
  473. CTM.Stream.prototype.readFloat32 = function(){
  474. var m = this.readByte();
  475. m += this.readByte() << 8;
  476. var b1 = this.readByte();
  477. var b2 = this.readByte();
  478. m += (b1 & 0x7f) << 16;
  479. var e = ( (b2 & 0x7f) << 1) | ( (b1 & 0x80) >>> 7);
  480. var s = b2 & 0x80? -1: 1;
  481. if (e === 255){
  482. return m !== 0? NaN: s * Infinity;
  483. }
  484. if (e > 0){
  485. return s * (1 + (m * this.TWO_POW_MINUS23) ) * Math.pow(2, e - 127);
  486. }
  487. if (m !== 0){
  488. return s * m * this.TWO_POW_MINUS126;
  489. }
  490. return s * 0;
  491. };
  492. CTM.Stream.prototype.readString = function(){
  493. var len = this.readInt32();
  494. this.offset += len;
  495. return this.data.subarray(this.offset - len, len);
  496. };
  497. CTM.Stream.prototype.readArrayInt32 = function(array){
  498. var i = 0, len = array.length;
  499. while(i < len){
  500. array[i ++] = this.readInt32();
  501. }
  502. return array;
  503. };
  504. CTM.Stream.prototype.readArrayFloat32 = function(array){
  505. var i = 0, len = array.length;
  506. while(i < len){
  507. array[i ++] = this.readFloat32();
  508. }
  509. return array;
  510. };