khronosTextureContainer2.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import { InternalTexture } from "../Materials/Textures/internalTexture";
  2. import { ThinEngine } from "../Engines/thinEngine";
  3. import { EngineCapabilities } from '../Engines/engineCapabilities';
  4. declare var LIBKTX: any;
  5. /**
  6. * Class for loading KTX2 files
  7. * !!! Experimental Extension Subject to Changes !!!
  8. * @hidden
  9. */
  10. export class KhronosTextureContainer2 {
  11. private static _ModulePromise: Promise<{ module: any }>;
  12. private static _TranscodeFormat: number;
  13. public constructor(engine: ThinEngine) {
  14. if (!KhronosTextureContainer2._ModulePromise) {
  15. KhronosTextureContainer2._ModulePromise = new Promise((resolve) => {
  16. LIBKTX().then((module: any) => {
  17. module.GL.makeContextCurrent(module.GL.registerContext(engine._gl, { majorVersion: engine._webGLVersion }));
  18. KhronosTextureContainer2._TranscodeFormat = this._determineTranscodeFormat(module.TranscodeTarget, engine.getCaps());
  19. resolve({ module: module });
  20. });
  21. });
  22. }
  23. }
  24. public uploadAsync(data: ArrayBufferView, internalTexture: InternalTexture): Promise<void> {
  25. return KhronosTextureContainer2._ModulePromise.then((moduleWrapper: any) => {
  26. const module = moduleWrapper.module;
  27. const ktxTexture = new module.ktxTexture(data);
  28. try {
  29. if (ktxTexture.isBasisSupercompressed) {
  30. ktxTexture.transcodeBasis(KhronosTextureContainer2._TranscodeFormat, 0);
  31. }
  32. internalTexture.width = internalTexture.baseWidth = ktxTexture.baseWidth;
  33. internalTexture.height = internalTexture.baseHeight = ktxTexture.baseHeight;
  34. internalTexture.generateMipMaps = false;
  35. const result = ktxTexture.glUpload();
  36. if (result.error === 0) {
  37. internalTexture._webGLTexture = result.texture;
  38. }
  39. else {
  40. throw new Error(`Failed to upload: ${result.error}`);
  41. }
  42. internalTexture.isReady = true;
  43. }
  44. finally {
  45. ktxTexture.delete();
  46. }
  47. });
  48. }
  49. private _determineTranscodeFormat(transcodeTarget: any, caps: EngineCapabilities): number {
  50. if (caps.s3tc) {
  51. return transcodeTarget.BC1_OR_3;
  52. }
  53. else if (caps.etc2) {
  54. return transcodeTarget.ETC;
  55. }
  56. throw new Error("No compatible format available");
  57. }
  58. /**
  59. * Checks if the given data starts with a KTX2 file identifier.
  60. * @param data the data to check
  61. * @returns true if the data is a KTX2 file or false otherwise
  62. */
  63. public static IsValid(data: ArrayBufferView): boolean {
  64. if (data.byteLength >= 12)
  65. {
  66. // '«', 'K', 'T', 'X', ' ', '2', '0', '»', '\r', '\n', '\x1A', '\n'
  67. const identifier = new Uint8Array(data.buffer, data.byteOffset, 12);
  68. if (identifier[0] === 0xAB && identifier[1] === 0x4B && identifier[2] === 0x54 && identifier[3] === 0x58 && identifier[4] === 0x20 && identifier[5] === 0x32 &&
  69. identifier[6] === 0x30 && identifier[7] === 0xBB && identifier[8] === 0x0D && identifier[9] === 0x0A && identifier[10] === 0x1A && identifier[11] === 0x0A) {
  70. return true;
  71. }
  72. }
  73. return false;
  74. }
  75. }