engine.rawTexture.ts 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. import { Nullable } from "../../types";
  2. import { InternalTexture, InternalTextureSource } from '../../Materials/Textures/internalTexture';
  3. import { Logger } from '../../Misc/logger';
  4. import { Tools } from '../../Misc/tools';
  5. import { Scene } from '../../scene';
  6. import { Constants } from '../constants';
  7. import { ThinEngine } from '../thinEngine';
  8. import { IWebRequest } from '../../Misc/interfaces/iWebRequest';
  9. declare module "../../Engines/thinEngine" {
  10. export interface ThinEngine {
  11. /**
  12. * Creates a raw texture
  13. * @param data defines the data to store in the texture
  14. * @param width defines the width of the texture
  15. * @param height defines the height of the texture
  16. * @param format defines the format of the data
  17. * @param generateMipMaps defines if the engine should generate the mip levels
  18. * @param invertY defines if data must be stored with Y axis inverted
  19. * @param samplingMode defines the required sampling mode (Texture.NEAREST_SAMPLINGMODE by default)
  20. * @param compression defines the compression used (null by default)
  21. * @param type defines the type fo the data (Engine.TEXTURETYPE_UNSIGNED_INT by default)
  22. * @returns the raw texture inside an InternalTexture
  23. */
  24. createRawTexture(data: Nullable<ArrayBufferView>, width: number, height: number, format: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: Nullable<string>, type: number): InternalTexture;
  25. /**
  26. * Update a raw texture
  27. * @param texture defines the texture to update
  28. * @param data defines the data to store in the texture
  29. * @param format defines the format of the data
  30. * @param invertY defines if data must be stored with Y axis inverted
  31. */
  32. updateRawTexture(texture: Nullable<InternalTexture>, data: Nullable<ArrayBufferView>, format: number, invertY: boolean): void;
  33. /**
  34. * Update a raw texture
  35. * @param texture defines the texture to update
  36. * @param data defines the data to store in the texture
  37. * @param format defines the format of the data
  38. * @param invertY defines if data must be stored with Y axis inverted
  39. * @param compression defines the compression used (null by default)
  40. * @param type defines the type fo the data (Engine.TEXTURETYPE_UNSIGNED_INT by default)
  41. */
  42. updateRawTexture(texture: Nullable<InternalTexture>, data: Nullable<ArrayBufferView>, format: number, invertY: boolean, compression: Nullable<string>, type: number): void;
  43. /**
  44. * Creates a new raw cube texture
  45. * @param data defines the array of data to use to create each face
  46. * @param size defines the size of the textures
  47. * @param format defines the format of the data
  48. * @param type defines the type of the data (like Engine.TEXTURETYPE_UNSIGNED_INT)
  49. * @param generateMipMaps defines if the engine should generate the mip levels
  50. * @param invertY defines if data must be stored with Y axis inverted
  51. * @param samplingMode defines the required sampling mode (like Texture.NEAREST_SAMPLINGMODE)
  52. * @param compression defines the compression used (null by default)
  53. * @returns the cube texture as an InternalTexture
  54. */
  55. createRawCubeTexture(data: Nullable<ArrayBufferView[]>, size: number, format: number, type: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: Nullable<string>): InternalTexture;
  56. /**
  57. * Update a raw cube texture
  58. * @param texture defines the texture to update
  59. * @param data defines the data to store
  60. * @param format defines the data format
  61. * @param type defines the type fo the data (Engine.TEXTURETYPE_UNSIGNED_INT by default)
  62. * @param invertY defines if data must be stored with Y axis inverted
  63. */
  64. updateRawCubeTexture(texture: InternalTexture, data: ArrayBufferView[], format: number, type: number, invertY: boolean): void;
  65. /**
  66. * Update a raw cube texture
  67. * @param texture defines the texture to update
  68. * @param data defines the data to store
  69. * @param format defines the data format
  70. * @param type defines the type fo the data (Engine.TEXTURETYPE_UNSIGNED_INT by default)
  71. * @param invertY defines if data must be stored with Y axis inverted
  72. * @param compression defines the compression used (null by default)
  73. */
  74. updateRawCubeTexture(texture: InternalTexture, data: ArrayBufferView[], format: number, type: number, invertY: boolean, compression: Nullable<string>): void;
  75. /**
  76. * Update a raw cube texture
  77. * @param texture defines the texture to update
  78. * @param data defines the data to store
  79. * @param format defines the data format
  80. * @param type defines the type fo the data (Engine.TEXTURETYPE_UNSIGNED_INT by default)
  81. * @param invertY defines if data must be stored with Y axis inverted
  82. * @param compression defines the compression used (null by default)
  83. * @param level defines which level of the texture to update
  84. */
  85. updateRawCubeTexture(texture: InternalTexture, data: ArrayBufferView[], format: number, type: number, invertY: boolean, compression: Nullable<string>, level: number): void;
  86. /**
  87. * Creates a new raw cube texture from a specified url
  88. * @param url defines the url where the data is located
  89. * @param scene defines the current scene
  90. * @param size defines the size of the textures
  91. * @param format defines the format of the data
  92. * @param type defines the type fo the data (like Engine.TEXTURETYPE_UNSIGNED_INT)
  93. * @param noMipmap defines if the engine should avoid generating the mip levels
  94. * @param callback defines a callback used to extract texture data from loaded data
  95. * @param mipmapGenerator defines to provide an optional tool to generate mip levels
  96. * @param onLoad defines a callback called when texture is loaded
  97. * @param onError defines a callback called if there is an error
  98. * @returns the cube texture as an InternalTexture
  99. */
  100. createRawCubeTextureFromUrl(url: string, scene: Nullable<Scene>, size: number, format: number, type: number, noMipmap: boolean,
  101. callback: (ArrayBuffer: ArrayBuffer) => Nullable<ArrayBufferView[]>,
  102. mipmapGenerator: Nullable<((faces: ArrayBufferView[]) => ArrayBufferView[][])>,
  103. onLoad: Nullable<() => void>,
  104. onError: Nullable<(message?: string, exception?: any) => void>): InternalTexture;
  105. /**
  106. * Creates a new raw cube texture from a specified url
  107. * @param url defines the url where the data is located
  108. * @param scene defines the current scene
  109. * @param size defines the size of the textures
  110. * @param format defines the format of the data
  111. * @param type defines the type fo the data (like Engine.TEXTURETYPE_UNSIGNED_INT)
  112. * @param noMipmap defines if the engine should avoid generating the mip levels
  113. * @param callback defines a callback used to extract texture data from loaded data
  114. * @param mipmapGenerator defines to provide an optional tool to generate mip levels
  115. * @param onLoad defines a callback called when texture is loaded
  116. * @param onError defines a callback called if there is an error
  117. * @param samplingMode defines the required sampling mode (like Texture.NEAREST_SAMPLINGMODE)
  118. * @param invertY defines if data must be stored with Y axis inverted
  119. * @returns the cube texture as an InternalTexture
  120. */
  121. createRawCubeTextureFromUrl(url: string, scene: Nullable<Scene>, size: number, format: number, type: number, noMipmap: boolean,
  122. callback: (ArrayBuffer: ArrayBuffer) => Nullable<ArrayBufferView[]>,
  123. mipmapGenerator: Nullable<((faces: ArrayBufferView[]) => ArrayBufferView[][])>,
  124. onLoad: Nullable<() => void>,
  125. onError: Nullable<(message?: string, exception?: any) => void>,
  126. samplingMode: number,
  127. invertY: boolean): InternalTexture;
  128. /**
  129. * Creates a new raw 3D texture
  130. * @param data defines the data used to create the texture
  131. * @param width defines the width of the texture
  132. * @param height defines the height of the texture
  133. * @param depth defines the depth of the texture
  134. * @param format defines the format of the texture
  135. * @param generateMipMaps defines if the engine must generate mip levels
  136. * @param invertY defines if data must be stored with Y axis inverted
  137. * @param samplingMode defines the required sampling mode (like Texture.NEAREST_SAMPLINGMODE)
  138. * @param compression defines the compressed used (can be null)
  139. * @param textureType defines the compressed used (can be null)
  140. * @returns a new raw 3D texture (stored in an InternalTexture)
  141. */
  142. createRawTexture3D(data: Nullable<ArrayBufferView>, width: number, height: number, depth: number, format: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: Nullable<string>, textureType: number): InternalTexture;
  143. /**
  144. * Update a raw 3D texture
  145. * @param texture defines the texture to update
  146. * @param data defines the data to store
  147. * @param format defines the data format
  148. * @param invertY defines if data must be stored with Y axis inverted
  149. */
  150. updateRawTexture3D(texture: InternalTexture, data: Nullable<ArrayBufferView>, format: number, invertY: boolean): void;
  151. /**
  152. * Update a raw 3D texture
  153. * @param texture defines the texture to update
  154. * @param data defines the data to store
  155. * @param format defines the data format
  156. * @param invertY defines if data must be stored with Y axis inverted
  157. * @param compression defines the used compression (can be null)
  158. * @param textureType defines the texture Type (Engine.TEXTURETYPE_UNSIGNED_INT, Engine.TEXTURETYPE_FLOAT...)
  159. */
  160. updateRawTexture3D(texture: InternalTexture, data: Nullable<ArrayBufferView>, format: number, invertY: boolean, compression: Nullable<string>, textureType: number): void;
  161. /**
  162. * Creates a new raw 2D array texture
  163. * @param data defines the data used to create the texture
  164. * @param width defines the width of the texture
  165. * @param height defines the height of the texture
  166. * @param depth defines the number of layers of the texture
  167. * @param format defines the format of the texture
  168. * @param generateMipMaps defines if the engine must generate mip levels
  169. * @param invertY defines if data must be stored with Y axis inverted
  170. * @param samplingMode defines the required sampling mode (like Texture.NEAREST_SAMPLINGMODE)
  171. * @param compression defines the compressed used (can be null)
  172. * @param textureType defines the compressed used (can be null)
  173. * @returns a new raw 2D array texture (stored in an InternalTexture)
  174. */
  175. createRawTexture2DArray(data: Nullable<ArrayBufferView>, width: number, height: number, depth: number, format: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: Nullable<string>, textureType: number): InternalTexture;
  176. /**
  177. * Update a raw 2D array texture
  178. * @param texture defines the texture to update
  179. * @param data defines the data to store
  180. * @param format defines the data format
  181. * @param invertY defines if data must be stored with Y axis inverted
  182. */
  183. updateRawTexture2DArray(texture: InternalTexture, data: Nullable<ArrayBufferView>, format: number, invertY: boolean): void;
  184. /**
  185. * Update a raw 2D array texture
  186. * @param texture defines the texture to update
  187. * @param data defines the data to store
  188. * @param format defines the data format
  189. * @param invertY defines if data must be stored with Y axis inverted
  190. * @param compression defines the used compression (can be null)
  191. * @param textureType defines the texture Type (Engine.TEXTURETYPE_UNSIGNED_INT, Engine.TEXTURETYPE_FLOAT...)
  192. */
  193. updateRawTexture2DArray(texture: InternalTexture, data: Nullable<ArrayBufferView>, format: number, invertY: boolean, compression: Nullable<string>, textureType: number): void;
  194. }
  195. }
  196. ThinEngine.prototype.updateRawTexture = function(texture: Nullable<InternalTexture>, data: Nullable<ArrayBufferView>, format: number, invertY: boolean, compression: Nullable<string> = null, type: number = Constants.TEXTURETYPE_UNSIGNED_INT): void {
  197. if (!texture) {
  198. return;
  199. }
  200. // Babylon's internalSizedFomat but gl's texImage2D internalFormat
  201. var internalSizedFomat = this._getRGBABufferInternalSizedFormat(type, format);
  202. // Babylon's internalFormat but gl's texImage2D format
  203. var internalFormat = this._getInternalFormat(format);
  204. var textureType = this._getWebGLTextureType(type);
  205. this._bindTextureDirectly(this._gl.TEXTURE_2D, texture, true);
  206. this._unpackFlipY(invertY === undefined ? true : (invertY ? true : false));
  207. if (!this._doNotHandleContextLost) {
  208. texture._bufferView = data;
  209. texture.format = format;
  210. texture.type = type;
  211. texture.invertY = invertY;
  212. texture._compression = compression;
  213. }
  214. if (texture.width % 4 !== 0) {
  215. this._gl.pixelStorei(this._gl.UNPACK_ALIGNMENT, 1);
  216. }
  217. if (compression && data) {
  218. this._gl.compressedTexImage2D(this._gl.TEXTURE_2D, 0, (<any>this.getCaps().s3tc)[compression], texture.width, texture.height, 0, <DataView>data);
  219. } else {
  220. this._gl.texImage2D(this._gl.TEXTURE_2D, 0, internalSizedFomat, texture.width, texture.height, 0, internalFormat, textureType, data);
  221. }
  222. if (texture.generateMipMaps) {
  223. this._gl.generateMipmap(this._gl.TEXTURE_2D);
  224. }
  225. this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
  226. // this.resetTextureCache();
  227. texture.isReady = true;
  228. };
  229. ThinEngine.prototype.createRawTexture = function(data: Nullable<ArrayBufferView>, width: number, height: number, format: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: Nullable<string> = null, type: number = Constants.TEXTURETYPE_UNSIGNED_INT): InternalTexture {
  230. var texture = new InternalTexture(this, InternalTextureSource.Raw);
  231. texture.baseWidth = width;
  232. texture.baseHeight = height;
  233. texture.width = width;
  234. texture.height = height;
  235. texture.format = format;
  236. texture.generateMipMaps = generateMipMaps;
  237. texture.samplingMode = samplingMode;
  238. texture.invertY = invertY;
  239. texture._compression = compression;
  240. texture.type = type;
  241. if (!this._doNotHandleContextLost) {
  242. texture._bufferView = data;
  243. }
  244. this.updateRawTexture(texture, data, format, invertY, compression, type);
  245. this._bindTextureDirectly(this._gl.TEXTURE_2D, texture, true);
  246. // Filters
  247. var filters = this._getSamplingParameters(samplingMode, generateMipMaps);
  248. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, filters.mag);
  249. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, filters.min);
  250. if (generateMipMaps) {
  251. this._gl.generateMipmap(this._gl.TEXTURE_2D);
  252. }
  253. this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
  254. this._internalTexturesCache.push(texture);
  255. return texture;
  256. };
  257. ThinEngine.prototype.createRawCubeTexture = function(data: Nullable<ArrayBufferView[]>, size: number, format: number, type: number,
  258. generateMipMaps: boolean, invertY: boolean, samplingMode: number,
  259. compression: Nullable<string> = null): InternalTexture {
  260. var gl = this._gl;
  261. var texture = new InternalTexture(this, InternalTextureSource.CubeRaw);
  262. texture.isCube = true;
  263. texture.format = format;
  264. texture.type = type;
  265. if (!this._doNotHandleContextLost) {
  266. texture._bufferViewArray = data;
  267. }
  268. var textureType = this._getWebGLTextureType(type);
  269. var internalFormat = this._getInternalFormat(format);
  270. if (internalFormat === gl.RGB) {
  271. internalFormat = gl.RGBA;
  272. }
  273. // Mipmap generation needs a sized internal format that is both color-renderable and texture-filterable
  274. if (textureType === gl.FLOAT && !this._caps.textureFloatLinearFiltering) {
  275. generateMipMaps = false;
  276. samplingMode = Constants.TEXTURE_NEAREST_SAMPLINGMODE;
  277. Logger.Warn("Float texture filtering is not supported. Mipmap generation and sampling mode are forced to false and TEXTURE_NEAREST_SAMPLINGMODE, respectively.");
  278. }
  279. else if (textureType === this._gl.HALF_FLOAT_OES && !this._caps.textureHalfFloatLinearFiltering) {
  280. generateMipMaps = false;
  281. samplingMode = Constants.TEXTURE_NEAREST_SAMPLINGMODE;
  282. Logger.Warn("Half float texture filtering is not supported. Mipmap generation and sampling mode are forced to false and TEXTURE_NEAREST_SAMPLINGMODE, respectively.");
  283. }
  284. else if (textureType === gl.FLOAT && !this._caps.textureFloatRender) {
  285. generateMipMaps = false;
  286. Logger.Warn("Render to float textures is not supported. Mipmap generation forced to false.");
  287. }
  288. else if (textureType === gl.HALF_FLOAT && !this._caps.colorBufferFloat) {
  289. generateMipMaps = false;
  290. Logger.Warn("Render to half float textures is not supported. Mipmap generation forced to false.");
  291. }
  292. var width = size;
  293. var height = width;
  294. texture.width = width;
  295. texture.height = height;
  296. // Double check on POT to generate Mips.
  297. var isPot = !this.needPOTTextures || (Tools.IsExponentOfTwo(texture.width) && Tools.IsExponentOfTwo(texture.height));
  298. if (!isPot) {
  299. generateMipMaps = false;
  300. }
  301. // Upload data if needed. The texture won't be ready until then.
  302. if (data) {
  303. this.updateRawCubeTexture(texture, data, format, type, invertY, compression);
  304. }
  305. this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, texture, true);
  306. // Filters
  307. if (data && generateMipMaps) {
  308. this._gl.generateMipmap(this._gl.TEXTURE_CUBE_MAP);
  309. }
  310. var filters = this._getSamplingParameters(samplingMode, generateMipMaps);
  311. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, filters.mag);
  312. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, filters.min);
  313. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  314. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  315. this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
  316. texture.generateMipMaps = generateMipMaps;
  317. texture.samplingMode = samplingMode;
  318. return texture;
  319. };
  320. ThinEngine.prototype.updateRawCubeTexture = function(texture: InternalTexture, data: ArrayBufferView[], format: number, type: number, invertY: boolean, compression: Nullable<string> = null, level: number = 0): void {
  321. texture._bufferViewArray = data;
  322. texture.format = format;
  323. texture.type = type;
  324. texture.invertY = invertY;
  325. texture._compression = compression;
  326. var gl = this._gl;
  327. var textureType = this._getWebGLTextureType(type);
  328. var internalFormat = this._getInternalFormat(format);
  329. var internalSizedFomat = this._getRGBABufferInternalSizedFormat(type);
  330. var needConversion = false;
  331. if (internalFormat === gl.RGB) {
  332. internalFormat = gl.RGBA;
  333. needConversion = true;
  334. }
  335. this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
  336. this._unpackFlipY(invertY === undefined ? true : (invertY ? true : false));
  337. if (texture.width % 4 !== 0) {
  338. gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
  339. }
  340. // Data are known to be in +X +Y +Z -X -Y -Z
  341. for (let faceIndex = 0; faceIndex < 6; faceIndex++) {
  342. let faceData = data[faceIndex];
  343. if (compression) {
  344. gl.compressedTexImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, (<any>(this.getCaps().s3tc))[compression], texture.width, texture.height, 0, <DataView>faceData);
  345. } else {
  346. if (needConversion) {
  347. faceData = _convertRGBtoRGBATextureData(faceData, texture.width, texture.height, type);
  348. }
  349. gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, internalSizedFomat, texture.width, texture.height, 0, internalFormat, textureType, faceData);
  350. }
  351. }
  352. var isPot = !this.needPOTTextures || (Tools.IsExponentOfTwo(texture.width) && Tools.IsExponentOfTwo(texture.height));
  353. if (isPot && texture.generateMipMaps && level === 0) {
  354. this._gl.generateMipmap(this._gl.TEXTURE_CUBE_MAP);
  355. }
  356. this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
  357. // this.resetTextureCache();
  358. texture.isReady = true;
  359. };
  360. ThinEngine.prototype.createRawCubeTextureFromUrl = function(url: string, scene: Nullable<Scene>, size: number, format: number, type: number, noMipmap: boolean,
  361. callback: (ArrayBuffer: ArrayBuffer) => Nullable<ArrayBufferView[]>,
  362. mipmapGenerator: Nullable<((faces: ArrayBufferView[]) => ArrayBufferView[][])>,
  363. onLoad: Nullable<() => void> = null,
  364. onError: Nullable<(message?: string, exception?: any) => void> = null,
  365. samplingMode: number = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE,
  366. invertY: boolean = false): InternalTexture {
  367. var gl = this._gl;
  368. var texture = this.createRawCubeTexture(null, size, format, type, !noMipmap, invertY, samplingMode, null);
  369. scene?._addPendingData(texture);
  370. texture.url = url;
  371. this._internalTexturesCache.push(texture);
  372. var onerror = (request?: IWebRequest, exception?: any) => {
  373. scene?._removePendingData(texture);
  374. if (onError && request) {
  375. onError(request.status + " " + request.statusText, exception);
  376. }
  377. };
  378. var internalCallback = (data: any) => {
  379. var width = texture.width;
  380. var faceDataArrays = callback(data);
  381. if (!faceDataArrays) {
  382. return;
  383. }
  384. if (mipmapGenerator) {
  385. var textureType = this._getWebGLTextureType(type);
  386. var internalFormat = this._getInternalFormat(format);
  387. var internalSizedFomat = this._getRGBABufferInternalSizedFormat(type);
  388. var needConversion = false;
  389. if (internalFormat === gl.RGB) {
  390. internalFormat = gl.RGBA;
  391. needConversion = true;
  392. }
  393. this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
  394. this._unpackFlipY(false);
  395. var mipData = mipmapGenerator(faceDataArrays);
  396. for (var level = 0; level < mipData.length; level++) {
  397. var mipSize = width >> level;
  398. for (var faceIndex = 0; faceIndex < 6; faceIndex++) {
  399. let mipFaceData = mipData[level][faceIndex];
  400. if (needConversion) {
  401. mipFaceData = _convertRGBtoRGBATextureData(mipFaceData, mipSize, mipSize, type);
  402. }
  403. gl.texImage2D(faceIndex, level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipFaceData);
  404. }
  405. }
  406. this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
  407. }
  408. else {
  409. this.updateRawCubeTexture(texture, faceDataArrays, format, type, invertY);
  410. }
  411. texture.isReady = true;
  412. // this.resetTextureCache();
  413. scene?._removePendingData(texture);
  414. if (onLoad) {
  415. onLoad();
  416. }
  417. };
  418. this._loadFile(url, (data) => {
  419. internalCallback(data);
  420. }, undefined, scene?.offlineProvider, true, onerror);
  421. return texture;
  422. };
  423. /** @hidden */
  424. function _convertRGBtoRGBATextureData(rgbData: any, width: number, height: number, textureType: number): ArrayBufferView {
  425. // Create new RGBA data container.
  426. var rgbaData: any;
  427. if (textureType === Constants.TEXTURETYPE_FLOAT) {
  428. rgbaData = new Float32Array(width * height * 4);
  429. }
  430. else {
  431. rgbaData = new Uint32Array(width * height * 4);
  432. }
  433. // Convert each pixel.
  434. for (let x = 0; x < width; x++) {
  435. for (let y = 0; y < height; y++) {
  436. let index = (y * width + x) * 3;
  437. let newIndex = (y * width + x) * 4;
  438. // Map Old Value to new value.
  439. rgbaData[newIndex + 0] = rgbData[index + 0];
  440. rgbaData[newIndex + 1] = rgbData[index + 1];
  441. rgbaData[newIndex + 2] = rgbData[index + 2];
  442. // Add fully opaque alpha channel.
  443. rgbaData[newIndex + 3] = 1;
  444. }
  445. }
  446. return rgbaData;
  447. }
  448. /**
  449. * Create a function for createRawTexture3D/createRawTexture2DArray
  450. * @param is3D true for TEXTURE_3D and false for TEXTURE_2D_ARRAY
  451. * @hidden
  452. */
  453. function _makeCreateRawTextureFunction(is3D: boolean) {
  454. return function(this: ThinEngine, data: Nullable<ArrayBufferView>, width: number, height: number, depth: number, format: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: Nullable<string> = null, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT): InternalTexture {
  455. var target = is3D ? this._gl.TEXTURE_3D : this._gl.TEXTURE_2D_ARRAY;
  456. var source = is3D ? InternalTextureSource.Raw3D : InternalTextureSource.Raw2DArray;
  457. var texture = new InternalTexture(this, source);
  458. texture.baseWidth = width;
  459. texture.baseHeight = height;
  460. texture.baseDepth = depth;
  461. texture.width = width;
  462. texture.height = height;
  463. texture.depth = depth;
  464. texture.format = format;
  465. texture.type = textureType;
  466. texture.generateMipMaps = generateMipMaps;
  467. texture.samplingMode = samplingMode;
  468. if (is3D) {
  469. texture.is3D = true;
  470. } else {
  471. texture.is2DArray = true;
  472. }
  473. if (!this._doNotHandleContextLost) {
  474. texture._bufferView = data;
  475. }
  476. if (is3D) {
  477. this.updateRawTexture3D(texture, data, format, invertY, compression, textureType);
  478. } else {
  479. this.updateRawTexture2DArray(texture, data, format, invertY, compression, textureType);
  480. }
  481. this._bindTextureDirectly(target, texture, true);
  482. // Filters
  483. var filters = this._getSamplingParameters(samplingMode, generateMipMaps);
  484. this._gl.texParameteri(target, this._gl.TEXTURE_MAG_FILTER, filters.mag);
  485. this._gl.texParameteri(target, this._gl.TEXTURE_MIN_FILTER, filters.min);
  486. if (generateMipMaps) {
  487. this._gl.generateMipmap(target);
  488. }
  489. this._bindTextureDirectly(target, null);
  490. this._internalTexturesCache.push(texture);
  491. return texture;
  492. };
  493. }
  494. ThinEngine.prototype.createRawTexture2DArray = _makeCreateRawTextureFunction(false);
  495. ThinEngine.prototype.createRawTexture3D = _makeCreateRawTextureFunction(true);
  496. /**
  497. * Create a function for updateRawTexture3D/updateRawTexture2DArray
  498. * @param is3D true for TEXTURE_3D and false for TEXTURE_2D_ARRAY
  499. * @hidden
  500. */
  501. function _makeUpdateRawTextureFunction(is3D: boolean) {
  502. return function(this: ThinEngine, texture: InternalTexture, data: Nullable<ArrayBufferView>, format: number, invertY: boolean, compression: Nullable<string> = null, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT): void {
  503. var target = is3D ? this._gl.TEXTURE_3D : this._gl.TEXTURE_2D_ARRAY;
  504. var internalType = this._getWebGLTextureType(textureType);
  505. var internalFormat = this._getInternalFormat(format);
  506. var internalSizedFomat = this._getRGBABufferInternalSizedFormat(textureType, format);
  507. this._bindTextureDirectly(target, texture, true);
  508. this._unpackFlipY(invertY === undefined ? true : (invertY ? true : false));
  509. if (!this._doNotHandleContextLost) {
  510. texture._bufferView = data;
  511. texture.format = format;
  512. texture.invertY = invertY;
  513. texture._compression = compression;
  514. }
  515. if (texture.width % 4 !== 0) {
  516. this._gl.pixelStorei(this._gl.UNPACK_ALIGNMENT, 1);
  517. }
  518. if (compression && data) {
  519. this._gl.compressedTexImage3D(target, 0, (<any>this.getCaps().s3tc)[compression], texture.width, texture.height, texture.depth, 0, data);
  520. } else {
  521. this._gl.texImage3D(target, 0, internalSizedFomat, texture.width, texture.height, texture.depth, 0, internalFormat, internalType, data);
  522. }
  523. if (texture.generateMipMaps) {
  524. this._gl.generateMipmap(target);
  525. }
  526. this._bindTextureDirectly(target, null);
  527. // this.resetTextureCache();
  528. texture.isReady = true;
  529. };
  530. }
  531. ThinEngine.prototype.updateRawTexture2DArray = _makeUpdateRawTextureFunction(false);
  532. ThinEngine.prototype.updateRawTexture3D = _makeUpdateRawTextureFunction(true);