internalTexture.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. import { Observable } from "../../Misc/observable";
  2. import { Nullable, int } from "../../types";
  3. import { SphericalPolynomial } from "../../Maths/sphericalPolynomial";
  4. import { RenderTargetCreationOptions } from "../../Materials/Textures/renderTargetCreationOptions";
  5. import { IInternalTextureTracker } from "../../Materials/Textures/internalTextureTracker";
  6. import { _TimeToken } from "../../Instrumentation/timeToken";
  7. import { _DepthCullingState, _StencilState, _AlphaState } from "../../States/index";
  8. import { Constants } from "../../Engines/constants";
  9. import { _DevTools } from '../../Misc/devTools';
  10. declare type Engine = import("../../Engines/engine").Engine;
  11. declare type BaseTexture = import("../../Materials/Textures/baseTexture").BaseTexture;
  12. /**
  13. * Class used to store data associated with WebGL texture data for the engine
  14. * This class should not be used directly
  15. */
  16. export class InternalTexture implements IInternalTextureTracker {
  17. /** hidden */
  18. public static _UpdateRGBDAsync = (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: Nullable<SphericalPolynomial>, lodScale: number, lodOffset: number): Promise<void> => {
  19. throw _DevTools.WarnImport("environmentTextureTools");
  20. }
  21. /**
  22. * The source of the texture data is unknown
  23. */
  24. public static DATASOURCE_UNKNOWN = 0;
  25. /**
  26. * Texture data comes from an URL
  27. */
  28. public static DATASOURCE_URL = 1;
  29. /**
  30. * Texture data is only used for temporary storage
  31. */
  32. public static DATASOURCE_TEMP = 2;
  33. /**
  34. * Texture data comes from raw data (ArrayBuffer)
  35. */
  36. public static DATASOURCE_RAW = 3;
  37. /**
  38. * Texture content is dynamic (video or dynamic texture)
  39. */
  40. public static DATASOURCE_DYNAMIC = 4;
  41. /**
  42. * Texture content is generated by rendering to it
  43. */
  44. public static DATASOURCE_RENDERTARGET = 5;
  45. /**
  46. * Texture content is part of a multi render target process
  47. */
  48. public static DATASOURCE_MULTIRENDERTARGET = 6;
  49. /**
  50. * Texture data comes from a cube data file
  51. */
  52. public static DATASOURCE_CUBE = 7;
  53. /**
  54. * Texture data comes from a raw cube data
  55. */
  56. public static DATASOURCE_CUBERAW = 8;
  57. /**
  58. * Texture data come from a prefiltered cube data file
  59. */
  60. public static DATASOURCE_CUBEPREFILTERED = 9;
  61. /**
  62. * Texture content is raw 3D data
  63. */
  64. public static DATASOURCE_RAW3D = 10;
  65. /**
  66. * Texture content is a depth texture
  67. */
  68. public static DATASOURCE_DEPTHTEXTURE = 11;
  69. /**
  70. * Texture data comes from a raw cube data encoded with RGBD
  71. */
  72. public static DATASOURCE_CUBERAW_RGBD = 12;
  73. /**
  74. * Defines if the texture is ready
  75. */
  76. public isReady: boolean;
  77. /**
  78. * Defines if the texture is a cube texture
  79. */
  80. public isCube: boolean;
  81. /**
  82. * Defines if the texture contains 3D data
  83. */
  84. public is3D: boolean;
  85. /**
  86. * Defines if the texture contains multiview data
  87. */
  88. public isMultiview: boolean;
  89. /**
  90. * Gets the URL used to load this texture
  91. */
  92. public url: string;
  93. /**
  94. * Gets the sampling mode of the texture
  95. */
  96. public samplingMode: number;
  97. /**
  98. * Gets a boolean indicating if the texture needs mipmaps generation
  99. */
  100. public generateMipMaps: boolean;
  101. /**
  102. * Gets the number of samples used by the texture (WebGL2+ only)
  103. */
  104. public samples: number;
  105. /**
  106. * Gets the type of the texture (int, float...)
  107. */
  108. public type: number;
  109. /**
  110. * Gets the format of the texture (RGB, RGBA...)
  111. */
  112. public format: number;
  113. /**
  114. * Observable called when the texture is loaded
  115. */
  116. public onLoadedObservable = new Observable<InternalTexture>();
  117. /**
  118. * Gets the width of the texture
  119. */
  120. public width: number;
  121. /**
  122. * Gets the height of the texture
  123. */
  124. public height: number;
  125. /**
  126. * Gets the depth of the texture
  127. */
  128. public depth: number;
  129. /**
  130. * Gets the initial width of the texture (It could be rescaled if the current system does not support non power of two textures)
  131. */
  132. public baseWidth: number;
  133. /**
  134. * Gets the initial height of the texture (It could be rescaled if the current system does not support non power of two textures)
  135. */
  136. public baseHeight: number;
  137. /**
  138. * Gets the initial depth of the texture (It could be rescaled if the current system does not support non power of two textures)
  139. */
  140. public baseDepth: number;
  141. /**
  142. * Gets a boolean indicating if the texture is inverted on Y axis
  143. */
  144. public invertY: boolean;
  145. /**
  146. * Gets or set the previous tracker in the list
  147. */
  148. public previous: Nullable<IInternalTextureTracker> = null;
  149. /**
  150. * Gets or set the next tracker in the list
  151. */
  152. public next: Nullable<IInternalTextureTracker> = null;
  153. // Private
  154. /** @hidden */
  155. public _invertVScale = false;
  156. /** @hidden */
  157. public _initialSlot = -1;
  158. /** @hidden */
  159. public _designatedSlot = -1;
  160. /** @hidden */
  161. public _dataSource = InternalTexture.DATASOURCE_UNKNOWN;
  162. /** @hidden */
  163. public _buffer: Nullable<string | ArrayBuffer | HTMLImageElement | Blob>;
  164. /** @hidden */
  165. public _bufferView: Nullable<ArrayBufferView>;
  166. /** @hidden */
  167. public _bufferViewArray: Nullable<ArrayBufferView[]>;
  168. /** @hidden */
  169. public _bufferViewArrayArray: Nullable<ArrayBufferView[][]>;
  170. /** @hidden */
  171. public _size: number;
  172. /** @hidden */
  173. public _extension: string;
  174. /** @hidden */
  175. public _files: Nullable<string[]>;
  176. /** @hidden */
  177. public _workingCanvas: HTMLCanvasElement;
  178. /** @hidden */
  179. public _workingContext: CanvasRenderingContext2D;
  180. /** @hidden */
  181. public _framebuffer: Nullable<WebGLFramebuffer>;
  182. /** @hidden */
  183. public _depthStencilBuffer: Nullable<WebGLRenderbuffer>;
  184. /** @hidden */
  185. public _MSAAFramebuffer: Nullable<WebGLFramebuffer>;
  186. /** @hidden */
  187. public _MSAARenderBuffer: Nullable<WebGLRenderbuffer>;
  188. /** @hidden */
  189. public _attachments: Nullable<number[]>;
  190. /** @hidden */
  191. public _cachedCoordinatesMode: Nullable<number>;
  192. /** @hidden */
  193. public _cachedWrapU: Nullable<number>;
  194. /** @hidden */
  195. public _cachedWrapV: Nullable<number>;
  196. /** @hidden */
  197. public _cachedWrapR: Nullable<number>;
  198. /** @hidden */
  199. public _cachedAnisotropicFilteringLevel: Nullable<number>;
  200. /** @hidden */
  201. public _isDisabled: boolean;
  202. /** @hidden */
  203. public _compression: Nullable<string>;
  204. /** @hidden */
  205. public _generateStencilBuffer: boolean;
  206. /** @hidden */
  207. public _generateDepthBuffer: boolean;
  208. /** @hidden */
  209. public _comparisonFunction: number = 0;
  210. /** @hidden */
  211. public _sphericalPolynomial: Nullable<SphericalPolynomial> = null;
  212. /** @hidden */
  213. public _lodGenerationScale: number = 0;
  214. /** @hidden */
  215. public _lodGenerationOffset: number = 0;
  216. // Multiview
  217. /** @hidden */
  218. public _colorTextureArray: Nullable<WebGLTexture>;
  219. /** @hidden */
  220. public _depthStencilTextureArray: Nullable<WebGLTexture>;
  221. // The following three fields helps sharing generated fixed LODs for texture filtering
  222. // In environment not supporting the textureLOD extension like EDGE. They are for internal use only.
  223. // They are at the level of the gl texture to benefit from the cache.
  224. /** @hidden */
  225. public _lodTextureHigh: BaseTexture;
  226. /** @hidden */
  227. public _lodTextureMid: BaseTexture;
  228. /** @hidden */
  229. public _lodTextureLow: BaseTexture;
  230. /** @hidden */
  231. public _isRGBD: boolean = false;
  232. /** @hidden */
  233. public _webGLTexture: Nullable<WebGLTexture>;
  234. /** @hidden */
  235. public _references: number = 1;
  236. private _engine: Engine;
  237. /**
  238. * Gets the Engine the texture belongs to.
  239. * @returns The babylon engine
  240. */
  241. public getEngine(): Engine {
  242. return this._engine;
  243. }
  244. /**
  245. * Gets the data source type of the texture (can be one of the InternalTexture.DATASOURCE_XXXX)
  246. */
  247. public get dataSource(): number {
  248. return this._dataSource;
  249. }
  250. /**
  251. * Creates a new InternalTexture
  252. * @param engine defines the engine to use
  253. * @param dataSource defines the type of data that will be used
  254. * @param delayAllocation if the texture allocation should be delayed (default: false)
  255. */
  256. constructor(engine: Engine, dataSource: number, delayAllocation = false) {
  257. this._engine = engine;
  258. this._dataSource = dataSource;
  259. if (!delayAllocation) {
  260. this._webGLTexture = engine._createTexture();
  261. }
  262. }
  263. /**
  264. * Increments the number of references (ie. the number of Texture that point to it)
  265. */
  266. public incrementReferences(): void {
  267. this._references++;
  268. }
  269. /**
  270. * Change the size of the texture (not the size of the content)
  271. * @param width defines the new width
  272. * @param height defines the new height
  273. * @param depth defines the new depth (1 by default)
  274. */
  275. public updateSize(width: int, height: int, depth: int = 1): void {
  276. this.width = width;
  277. this.height = height;
  278. this.depth = depth;
  279. this.baseWidth = width;
  280. this.baseHeight = height;
  281. this.baseDepth = depth;
  282. this._size = width * height * depth;
  283. }
  284. /** @hidden */
  285. public _rebuild(): void {
  286. var proxy: InternalTexture;
  287. this.isReady = false;
  288. this._cachedCoordinatesMode = null;
  289. this._cachedWrapU = null;
  290. this._cachedWrapV = null;
  291. this._cachedAnisotropicFilteringLevel = null;
  292. switch (this._dataSource) {
  293. case InternalTexture.DATASOURCE_TEMP:
  294. return;
  295. case InternalTexture.DATASOURCE_URL:
  296. proxy = this._engine.createTexture(this.url, !this.generateMipMaps, this.invertY, null, this.samplingMode, () => {
  297. proxy._swapAndDie(this);
  298. this.isReady = true;
  299. }, null, this._buffer, undefined, this.format);
  300. return;
  301. case InternalTexture.DATASOURCE_RAW:
  302. proxy = this._engine.createRawTexture(this._bufferView, this.baseWidth, this.baseHeight, this.format, this.generateMipMaps,
  303. this.invertY, this.samplingMode, this._compression);
  304. proxy._swapAndDie(this);
  305. this.isReady = true;
  306. return;
  307. case InternalTexture.DATASOURCE_RAW3D:
  308. proxy = this._engine.createRawTexture3D(this._bufferView, this.baseWidth, this.baseHeight, this.baseDepth, this.format, this.generateMipMaps,
  309. this.invertY, this.samplingMode, this._compression);
  310. proxy._swapAndDie(this);
  311. this.isReady = true;
  312. return;
  313. case InternalTexture.DATASOURCE_DYNAMIC:
  314. proxy = this._engine.createDynamicTexture(this.baseWidth, this.baseHeight, this.generateMipMaps, this.samplingMode);
  315. proxy._swapAndDie(this);
  316. this._engine.updateDynamicTexture(this, this._engine.getRenderingCanvas()!, this.invertY, undefined, undefined, true);
  317. // The engine will make sure to update content so no need to flag it as isReady = true
  318. return;
  319. case InternalTexture.DATASOURCE_RENDERTARGET:
  320. let options = new RenderTargetCreationOptions();
  321. options.generateDepthBuffer = this._generateDepthBuffer;
  322. options.generateMipMaps = this.generateMipMaps;
  323. options.generateStencilBuffer = this._generateStencilBuffer;
  324. options.samplingMode = this.samplingMode;
  325. options.type = this.type;
  326. if (this.isCube) {
  327. proxy = this._engine.createRenderTargetCubeTexture(this.width, options);
  328. } else {
  329. let size = {
  330. width: this.width,
  331. height: this.height
  332. };
  333. proxy = this._engine.createRenderTargetTexture(size, options);
  334. }
  335. proxy._swapAndDie(this);
  336. this.isReady = true;
  337. return;
  338. case InternalTexture.DATASOURCE_DEPTHTEXTURE:
  339. let depthTextureOptions = {
  340. bilinearFiltering: this.samplingMode !== Constants.TEXTURE_BILINEAR_SAMPLINGMODE,
  341. comparisonFunction: this._comparisonFunction,
  342. generateStencil: this._generateStencilBuffer,
  343. isCube: this.isCube
  344. };
  345. proxy = this._engine.createDepthStencilTexture({ width: this.width, height: this.height }, depthTextureOptions);
  346. proxy._swapAndDie(this);
  347. this.isReady = true;
  348. return;
  349. case InternalTexture.DATASOURCE_CUBE:
  350. proxy = this._engine.createCubeTexture(this.url, null, this._files, !this.generateMipMaps, () => {
  351. proxy._swapAndDie(this);
  352. this.isReady = true;
  353. }, null, this.format, this._extension);
  354. return;
  355. case InternalTexture.DATASOURCE_CUBERAW:
  356. proxy = this._engine.createRawCubeTexture(this._bufferViewArray!, this.width, this.format, this.type, this.generateMipMaps, this.invertY, this.samplingMode, this._compression);
  357. proxy._swapAndDie(this);
  358. this.isReady = true;
  359. return;
  360. case InternalTexture.DATASOURCE_CUBERAW_RGBD:
  361. proxy = this._engine.createRawCubeTexture(null, this.width, this.format, this.type, this.generateMipMaps, this.invertY, this.samplingMode, this._compression);
  362. InternalTexture._UpdateRGBDAsync(proxy, this._bufferViewArrayArray!, this._sphericalPolynomial, this._lodGenerationScale, this._lodGenerationOffset).then(() => {
  363. proxy._swapAndDie(this);
  364. this.isReady = true;
  365. });
  366. return;
  367. case InternalTexture.DATASOURCE_CUBEPREFILTERED:
  368. proxy = this._engine.createPrefilteredCubeTexture(this.url, null, this._lodGenerationScale, this._lodGenerationOffset, (proxy) => {
  369. if (proxy) {
  370. proxy._swapAndDie(this);
  371. }
  372. this.isReady = true;
  373. }, null, this.format, this._extension);
  374. proxy._sphericalPolynomial = this._sphericalPolynomial;
  375. return;
  376. }
  377. }
  378. /** @hidden */
  379. public _swapAndDie(target: InternalTexture): void {
  380. target._webGLTexture = this._webGLTexture;
  381. if (this._framebuffer) {
  382. target._framebuffer = this._framebuffer;
  383. }
  384. if (this._depthStencilBuffer) {
  385. target._depthStencilBuffer = this._depthStencilBuffer;
  386. }
  387. if (this._lodTextureHigh) {
  388. if (target._lodTextureHigh) {
  389. target._lodTextureHigh.dispose();
  390. }
  391. target._lodTextureHigh = this._lodTextureHigh;
  392. }
  393. if (this._lodTextureMid) {
  394. if (target._lodTextureMid) {
  395. target._lodTextureMid.dispose();
  396. }
  397. target._lodTextureMid = this._lodTextureMid;
  398. }
  399. if (this._lodTextureLow) {
  400. if (target._lodTextureLow) {
  401. target._lodTextureLow.dispose();
  402. }
  403. target._lodTextureLow = this._lodTextureLow;
  404. }
  405. let cache = this._engine.getLoadedTexturesCache();
  406. var index = cache.indexOf(this);
  407. if (index !== -1) {
  408. cache.splice(index, 1);
  409. }
  410. }
  411. /**
  412. * Dispose the current allocated resources
  413. */
  414. public dispose(): void {
  415. if (!this._webGLTexture) {
  416. return;
  417. }
  418. this._references--;
  419. if (this._references === 0) {
  420. this._engine._releaseTexture(this);
  421. this._webGLTexture = null;
  422. this.previous = null;
  423. this.next = null;
  424. }
  425. }
  426. }