internalTexture.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. import { Observable } from "../../Misc/observable.js";
  2. import { TextureSampler } from "./textureSampler.js";
  3. /**
  4. * Defines the source of the internal texture
  5. */
  6. export var InternalTextureSource;
  7. (function (InternalTextureSource) {
  8. /**
  9. * The source of the texture data is unknown
  10. */
  11. InternalTextureSource[InternalTextureSource["Unknown"] = 0] = "Unknown";
  12. /**
  13. * Texture data comes from an URL
  14. */
  15. InternalTextureSource[InternalTextureSource["Url"] = 1] = "Url";
  16. /**
  17. * Texture data is only used for temporary storage
  18. */
  19. InternalTextureSource[InternalTextureSource["Temp"] = 2] = "Temp";
  20. /**
  21. * Texture data comes from raw data (ArrayBuffer)
  22. */
  23. InternalTextureSource[InternalTextureSource["Raw"] = 3] = "Raw";
  24. /**
  25. * Texture content is dynamic (video or dynamic texture)
  26. */
  27. InternalTextureSource[InternalTextureSource["Dynamic"] = 4] = "Dynamic";
  28. /**
  29. * Texture content is generated by rendering to it
  30. */
  31. InternalTextureSource[InternalTextureSource["RenderTarget"] = 5] = "RenderTarget";
  32. /**
  33. * Texture content is part of a multi render target process
  34. */
  35. InternalTextureSource[InternalTextureSource["MultiRenderTarget"] = 6] = "MultiRenderTarget";
  36. /**
  37. * Texture data comes from a cube data file
  38. */
  39. InternalTextureSource[InternalTextureSource["Cube"] = 7] = "Cube";
  40. /**
  41. * Texture data comes from a raw cube data
  42. */
  43. InternalTextureSource[InternalTextureSource["CubeRaw"] = 8] = "CubeRaw";
  44. /**
  45. * Texture data come from a prefiltered cube data file
  46. */
  47. InternalTextureSource[InternalTextureSource["CubePrefiltered"] = 9] = "CubePrefiltered";
  48. /**
  49. * Texture content is raw 3D data
  50. */
  51. InternalTextureSource[InternalTextureSource["Raw3D"] = 10] = "Raw3D";
  52. /**
  53. * Texture content is raw 2D array data
  54. */
  55. InternalTextureSource[InternalTextureSource["Raw2DArray"] = 11] = "Raw2DArray";
  56. /**
  57. * Texture content is a depth/stencil texture
  58. */
  59. InternalTextureSource[InternalTextureSource["DepthStencil"] = 12] = "DepthStencil";
  60. /**
  61. * Texture data comes from a raw cube data encoded with RGBD
  62. */
  63. InternalTextureSource[InternalTextureSource["CubeRawRGBD"] = 13] = "CubeRawRGBD";
  64. /**
  65. * Texture content is a depth texture
  66. */
  67. InternalTextureSource[InternalTextureSource["Depth"] = 14] = "Depth";
  68. })(InternalTextureSource || (InternalTextureSource = {}));
  69. /**
  70. * Class used to store data associated with WebGL texture data for the engine
  71. * This class should not be used directly
  72. */
  73. export class InternalTexture extends TextureSampler {
  74. /**
  75. * Gets a boolean indicating if the texture uses mipmaps
  76. * TODO implements useMipMaps as a separate setting from generateMipMaps
  77. */
  78. get useMipMaps() {
  79. return this.generateMipMaps;
  80. }
  81. set useMipMaps(value) {
  82. this.generateMipMaps = value;
  83. }
  84. /** Gets the unique id of the internal texture */
  85. get uniqueId() {
  86. return this._uniqueId;
  87. }
  88. /** @internal */
  89. _setUniqueId(id) {
  90. this._uniqueId = id;
  91. }
  92. /**
  93. * Gets the Engine the texture belongs to.
  94. * @returns The babylon engine
  95. */
  96. getEngine() {
  97. return this._engine;
  98. }
  99. /**
  100. * Gets the data source type of the texture
  101. */
  102. get source() {
  103. return this._source;
  104. }
  105. /**
  106. * Creates a new InternalTexture
  107. * @param engine defines the engine to use
  108. * @param source defines the type of data that will be used
  109. * @param delayAllocation if the texture allocation should be delayed (default: false)
  110. */
  111. constructor(engine, source, delayAllocation = false) {
  112. super();
  113. /**
  114. * Defines if the texture is ready
  115. */
  116. this.isReady = false;
  117. /**
  118. * Defines if the texture is a cube texture
  119. */
  120. this.isCube = false;
  121. /**
  122. * Defines if the texture contains 3D data
  123. */
  124. this.is3D = false;
  125. /**
  126. * Defines if the texture contains 2D array data
  127. */
  128. this.is2DArray = false;
  129. /**
  130. * Defines if the texture contains multiview data
  131. */
  132. this.isMultiview = false;
  133. /**
  134. * Gets the URL used to load this texture
  135. */
  136. this.url = "";
  137. /**
  138. * Gets a boolean indicating if the texture needs mipmaps generation
  139. */
  140. this.generateMipMaps = false;
  141. /**
  142. * Gets the number of samples used by the texture (WebGL2+ only)
  143. */
  144. this.samples = 0;
  145. /**
  146. * Gets the type of the texture (int, float...)
  147. */
  148. this.type = -1;
  149. /**
  150. * Gets the format of the texture (RGB, RGBA...)
  151. */
  152. this.format = -1;
  153. /**
  154. * Observable called when the texture is loaded
  155. */
  156. this.onLoadedObservable = new Observable();
  157. /**
  158. * Observable called when the texture load is raising an error
  159. */
  160. this.onErrorObservable = new Observable();
  161. /**
  162. * If this callback is defined it will be called instead of the default _rebuild function
  163. */
  164. this.onRebuildCallback = null;
  165. /**
  166. * Gets the width of the texture
  167. */
  168. this.width = 0;
  169. /**
  170. * Gets the height of the texture
  171. */
  172. this.height = 0;
  173. /**
  174. * Gets the depth of the texture
  175. */
  176. this.depth = 0;
  177. /**
  178. * Gets the initial width of the texture (It could be rescaled if the current system does not support non power of two textures)
  179. */
  180. this.baseWidth = 0;
  181. /**
  182. * Gets the initial height of the texture (It could be rescaled if the current system does not support non power of two textures)
  183. */
  184. this.baseHeight = 0;
  185. /**
  186. * Gets the initial depth of the texture (It could be rescaled if the current system does not support non power of two textures)
  187. */
  188. this.baseDepth = 0;
  189. /**
  190. * Gets a boolean indicating if the texture is inverted on Y axis
  191. */
  192. this.invertY = false;
  193. // Private
  194. /** @internal */
  195. this._invertVScale = false;
  196. /** @internal */
  197. this._associatedChannel = -1;
  198. /** @internal */
  199. this._source = InternalTextureSource.Unknown;
  200. /** @internal */
  201. this._buffer = null;
  202. /** @internal */
  203. this._bufferView = null;
  204. /** @internal */
  205. this._bufferViewArray = null;
  206. /** @internal */
  207. this._bufferViewArrayArray = null;
  208. /** @internal */
  209. this._size = 0;
  210. /** @internal */
  211. this._extension = "";
  212. /** @internal */
  213. this._files = null;
  214. /** @internal */
  215. this._workingCanvas = null;
  216. /** @internal */
  217. this._workingContext = null;
  218. /** @internal */
  219. this._cachedCoordinatesMode = null;
  220. /** @internal */
  221. this._isDisabled = false;
  222. /** @internal */
  223. this._compression = null;
  224. /** @internal */
  225. this._sphericalPolynomial = null;
  226. /** @internal */
  227. this._sphericalPolynomialPromise = null;
  228. /** @internal */
  229. this._sphericalPolynomialComputed = false;
  230. /** @internal */
  231. this._lodGenerationScale = 0;
  232. /** @internal */
  233. this._lodGenerationOffset = 0;
  234. /** @internal */
  235. this._useSRGBBuffer = false;
  236. /** @internal */
  237. this._creationFlags = 0;
  238. // The following three fields helps sharing generated fixed LODs for texture filtering
  239. // In environment not supporting the textureLOD extension like EDGE. They are for internal use only.
  240. // They are at the level of the gl texture to benefit from the cache.
  241. /** @internal */
  242. this._lodTextureHigh = null;
  243. /** @internal */
  244. this._lodTextureMid = null;
  245. /** @internal */
  246. this._lodTextureLow = null;
  247. /** @internal */
  248. this._isRGBD = false;
  249. /** @internal */
  250. this._linearSpecularLOD = false;
  251. /** @internal */
  252. this._irradianceTexture = null;
  253. /** @internal */
  254. this._hardwareTexture = null;
  255. /** @internal */
  256. this._maxLodLevel = null;
  257. /** @internal */
  258. this._references = 1;
  259. /** @internal */
  260. this._gammaSpace = null;
  261. /** @internal */
  262. this._premulAlpha = false;
  263. /** @internal */
  264. this._dynamicTextureSource = null;
  265. this._engine = engine;
  266. this._source = source;
  267. this._uniqueId = InternalTexture._Counter++;
  268. if (!delayAllocation) {
  269. this._hardwareTexture = engine._createHardwareTexture();
  270. }
  271. }
  272. /**
  273. * Increments the number of references (ie. the number of Texture that point to it)
  274. */
  275. incrementReferences() {
  276. this._references++;
  277. }
  278. /**
  279. * Change the size of the texture (not the size of the content)
  280. * @param width defines the new width
  281. * @param height defines the new height
  282. * @param depth defines the new depth (1 by default)
  283. */
  284. updateSize(width, height, depth = 1) {
  285. this._engine.updateTextureDimensions(this, width, height, depth);
  286. this.width = width;
  287. this.height = height;
  288. this.depth = depth;
  289. this.baseWidth = width;
  290. this.baseHeight = height;
  291. this.baseDepth = depth;
  292. this._size = width * height * depth;
  293. }
  294. /** @internal */
  295. _rebuild() {
  296. this.isReady = false;
  297. this._cachedCoordinatesMode = null;
  298. this._cachedWrapU = null;
  299. this._cachedWrapV = null;
  300. this._cachedWrapR = null;
  301. this._cachedAnisotropicFilteringLevel = null;
  302. if (this.onRebuildCallback) {
  303. const data = this.onRebuildCallback(this);
  304. const swapAndSetIsReady = (proxyInternalTexture) => {
  305. proxyInternalTexture._swapAndDie(this, false);
  306. this.isReady = data.isReady;
  307. };
  308. if (data.isAsync) {
  309. data.proxy.then(swapAndSetIsReady);
  310. }
  311. else {
  312. swapAndSetIsReady(data.proxy);
  313. }
  314. return;
  315. }
  316. let proxy;
  317. switch (this.source) {
  318. case InternalTextureSource.Temp:
  319. break;
  320. case InternalTextureSource.Url:
  321. proxy = this._engine.createTexture(this._originalUrl ?? this.url, !this.generateMipMaps, this.invertY, null, this.samplingMode,
  322. // Do not use Proxy here as it could be fully synchronous
  323. // and proxy would be undefined.
  324. (temp) => {
  325. temp._swapAndDie(this, false);
  326. this.isReady = true;
  327. }, null, this._buffer, undefined, this.format, this._extension, undefined, undefined, undefined, this._useSRGBBuffer);
  328. return;
  329. case InternalTextureSource.Raw:
  330. proxy = this._engine.createRawTexture(this._bufferView, this.baseWidth, this.baseHeight, this.format, this.generateMipMaps, this.invertY, this.samplingMode, this._compression, this.type, this._creationFlags, this._useSRGBBuffer);
  331. proxy._swapAndDie(this, false);
  332. this.isReady = true;
  333. break;
  334. case InternalTextureSource.Raw3D:
  335. proxy = this._engine.createRawTexture3D(this._bufferView, this.baseWidth, this.baseHeight, this.baseDepth, this.format, this.generateMipMaps, this.invertY, this.samplingMode, this._compression, this.type);
  336. proxy._swapAndDie(this, false);
  337. this.isReady = true;
  338. break;
  339. case InternalTextureSource.Raw2DArray:
  340. proxy = this._engine.createRawTexture2DArray(this._bufferView, this.baseWidth, this.baseHeight, this.baseDepth, this.format, this.generateMipMaps, this.invertY, this.samplingMode, this._compression, this.type);
  341. proxy._swapAndDie(this, false);
  342. this.isReady = true;
  343. break;
  344. case InternalTextureSource.Dynamic:
  345. proxy = this._engine.createDynamicTexture(this.baseWidth, this.baseHeight, this.generateMipMaps, this.samplingMode);
  346. proxy._swapAndDie(this, false);
  347. if (this._dynamicTextureSource) {
  348. this._engine.updateDynamicTexture(this, this._dynamicTextureSource, this.invertY, this._premulAlpha, this.format, true);
  349. }
  350. // The engine will make sure to update content so no need to flag it as isReady = true
  351. break;
  352. case InternalTextureSource.Cube:
  353. proxy = this._engine.createCubeTexture(this.url, null, this._files, !this.generateMipMaps, () => {
  354. proxy._swapAndDie(this, false);
  355. this.isReady = true;
  356. }, null, this.format, this._extension, false, 0, 0, null, undefined, this._useSRGBBuffer);
  357. return;
  358. case InternalTextureSource.CubeRaw:
  359. proxy = this._engine.createRawCubeTexture(this._bufferViewArray, this.width, this._originalFormat ?? this.format, this.type, this.generateMipMaps, this.invertY, this.samplingMode, this._compression);
  360. proxy._swapAndDie(this, false);
  361. this.isReady = true;
  362. break;
  363. case InternalTextureSource.CubeRawRGBD:
  364. // This case is being handeled by the environment texture tools and is not a part of the rebuild process.
  365. // To use CubeRawRGBD use updateRGBDAsync on the cube texture.
  366. return;
  367. case InternalTextureSource.CubePrefiltered:
  368. proxy = this._engine.createPrefilteredCubeTexture(this.url, null, this._lodGenerationScale, this._lodGenerationOffset, (proxy) => {
  369. if (proxy) {
  370. proxy._swapAndDie(this, false);
  371. }
  372. this.isReady = true;
  373. }, null, this.format, this._extension);
  374. proxy._sphericalPolynomial = this._sphericalPolynomial;
  375. return;
  376. case InternalTextureSource.DepthStencil:
  377. case InternalTextureSource.Depth: {
  378. // Will be handled at the RenderTargetWrapper level
  379. break;
  380. }
  381. }
  382. }
  383. /**
  384. * @internal
  385. */
  386. _swapAndDie(target, swapAll = true) {
  387. // TODO what about refcount on target?
  388. this._hardwareTexture?.setUsage(target._source, this.generateMipMaps, this.is2DArray, this.isCube, this.is3D, this.width, this.height, this.depth);
  389. target._hardwareTexture = this._hardwareTexture;
  390. if (swapAll) {
  391. target._isRGBD = this._isRGBD;
  392. }
  393. if (this._lodTextureHigh) {
  394. if (target._lodTextureHigh) {
  395. target._lodTextureHigh.dispose();
  396. }
  397. target._lodTextureHigh = this._lodTextureHigh;
  398. }
  399. if (this._lodTextureMid) {
  400. if (target._lodTextureMid) {
  401. target._lodTextureMid.dispose();
  402. }
  403. target._lodTextureMid = this._lodTextureMid;
  404. }
  405. if (this._lodTextureLow) {
  406. if (target._lodTextureLow) {
  407. target._lodTextureLow.dispose();
  408. }
  409. target._lodTextureLow = this._lodTextureLow;
  410. }
  411. if (this._irradianceTexture) {
  412. if (target._irradianceTexture) {
  413. target._irradianceTexture.dispose();
  414. }
  415. target._irradianceTexture = this._irradianceTexture;
  416. }
  417. const cache = this._engine.getLoadedTexturesCache();
  418. let index = cache.indexOf(this);
  419. if (index !== -1) {
  420. cache.splice(index, 1);
  421. }
  422. index = cache.indexOf(target);
  423. if (index === -1) {
  424. cache.push(target);
  425. }
  426. }
  427. /**
  428. * Dispose the current allocated resources
  429. */
  430. dispose() {
  431. this._references--;
  432. this.onLoadedObservable.clear();
  433. this.onErrorObservable.clear();
  434. if (this._references === 0) {
  435. this._engine._releaseTexture(this);
  436. this._hardwareTexture = null;
  437. this._dynamicTextureSource = null;
  438. }
  439. }
  440. }
  441. /** @internal */
  442. InternalTexture._Counter = 0;
  443. //# sourceMappingURL=internalTexture.js.map