babylon.glTFBinaryExtension.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. module BABYLON {
  2. const BinaryExtensionBufferName = "binary_glTF";
  3. enum EContentFormat {
  4. JSON = 0
  5. };
  6. interface IGLTFBinaryExtension {
  7. content: Object;
  8. body: Uint8Array;
  9. };
  10. interface IGLTFBinaryExtensionShader {
  11. bufferView: string;
  12. };
  13. interface IGLTFBinaryExtensionImage {
  14. bufferView: string;
  15. mimeType: string;
  16. height: number;
  17. width: number;
  18. };
  19. export class GLTFBinaryExtension extends GLTFFileLoaderExtension {
  20. public constructor() {
  21. super("KHR_binary_glTF");
  22. }
  23. public loadRuntimeAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: () => void): boolean {
  24. if (!(data instanceof ArrayBuffer)) {
  25. return false;
  26. }
  27. var binary: IGLTFBinaryExtension = this._parseBinary(<ArrayBuffer>data);
  28. if (!binary) {
  29. onError();
  30. return true;
  31. }
  32. var gltfRuntime = GLTFFileLoaderBase.createRuntime(binary.content, scene, rootUrl);
  33. if (gltfRuntime.extensionsUsed.indexOf(this.name) === -1) {
  34. Tools.Warn("glTF binary file does not have " + this.name + " specified in extensionsUsed");
  35. gltfRuntime.extensionsUsed.push(this.name);
  36. }
  37. gltfRuntime.loadedBufferViews[BinaryExtensionBufferName] = binary.body;
  38. onSuccess(gltfRuntime);
  39. return true;
  40. }
  41. public loadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (bufferView: ArrayBufferView) => void, onError: () => void): boolean {
  42. if (gltfRuntime.extensionsUsed.indexOf(this.name) === -1) {
  43. return false;
  44. }
  45. if (id !== BinaryExtensionBufferName) {
  46. return false;
  47. }
  48. onSuccess(gltfRuntime.loadedBufferViews[BinaryExtensionBufferName]);
  49. return true;
  50. }
  51. public loadTextureAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (texture: Texture) => void, onError: () => void): boolean {
  52. var texture: IGLTFTexture = gltfRuntime.textures[id];
  53. var source: IGLTFImage = gltfRuntime.images[texture.source];
  54. if (!source.extensions || !(this.name in source.extensions)) {
  55. return false;
  56. }
  57. var sourceExt: IGLTFBinaryExtensionImage = source.extensions[this.name];
  58. var sampler: IGLTFSampler = gltfRuntime.samplers[texture.sampler];
  59. var createMipMaps =
  60. (sampler.minFilter === ETextureFilterType.NEAREST_MIPMAP_NEAREST) ||
  61. (sampler.minFilter === ETextureFilterType.NEAREST_MIPMAP_LINEAR) ||
  62. (sampler.minFilter === ETextureFilterType.LINEAR_MIPMAP_NEAREST) ||
  63. (sampler.minFilter === ETextureFilterType.LINEAR_MIPMAP_LINEAR);
  64. var samplingMode = Texture.BILINEAR_SAMPLINGMODE;
  65. var bufferView: IGLTFBufferView = gltfRuntime.bufferViews[sourceExt.bufferView];
  66. var imageBytes = GLTFUtils.GetBufferFromBufferView(gltfRuntime, bufferView, 0, bufferView.byteLength, EComponentType.UNSIGNED_BYTE);
  67. var blob = new Blob([imageBytes], { type: sourceExt.mimeType });
  68. var blobURL = URL.createObjectURL(blob);
  69. var revokeBlobURL = () => URL.revokeObjectURL(blobURL);
  70. var newTexture = new Texture(blobURL, gltfRuntime.scene, !createMipMaps, true, samplingMode, revokeBlobURL, revokeBlobURL);
  71. newTexture.wrapU = GLTFUtils.GetWrapMode(sampler.wrapS);
  72. newTexture.wrapV = GLTFUtils.GetWrapMode(sampler.wrapT);
  73. newTexture.name = name;
  74. texture.babylonTexture = newTexture;
  75. onSuccess(newTexture);
  76. return true;
  77. }
  78. public loadShaderDataAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderData: string) => void, onError: () => void): boolean {
  79. var shader: IGLTFShader = gltfRuntime.shaders[id];
  80. if (!shader.extensions || !(this.name in shader.extensions)) {
  81. return false;
  82. }
  83. var binaryExtensionShader: IGLTFBinaryExtensionShader = shader.extensions[this.name];
  84. var bufferView: IGLTFBufferView = gltfRuntime.bufferViews[binaryExtensionShader.bufferView];
  85. var shaderBytes = GLTFUtils.GetBufferFromBufferView(gltfRuntime, bufferView, 0, bufferView.byteLength, EComponentType.UNSIGNED_BYTE);
  86. var shaderData = GLTFUtils.DecodeBufferToText(shaderBytes);
  87. onSuccess(shaderData);
  88. return true;
  89. }
  90. // Parses a glTF binary array buffer into its content and body
  91. private _parseBinary(data: ArrayBuffer): IGLTFBinaryExtension {
  92. var binaryReader = new BinaryReader(data);
  93. var magic = GLTFUtils.DecodeBufferToText(binaryReader.getUint8Array(4));
  94. if (magic != "glTF") {
  95. Tools.Error("Unexpected magic: " + magic);
  96. return null;
  97. }
  98. var version = binaryReader.getUint32();
  99. if (version != 1) {
  100. Tools.Error("Unsupported version: " + version);
  101. return null;
  102. }
  103. var length = binaryReader.getUint32();
  104. if (length != data.byteLength) {
  105. Tools.Error("Length in header does not match actual data length: " + length + " != " + data.byteLength);
  106. return null;
  107. }
  108. var contentLength = binaryReader.getUint32();
  109. var contentFormat = <EContentFormat>binaryReader.getUint32();
  110. var content: Object;
  111. switch (contentFormat) {
  112. case EContentFormat.JSON:
  113. var jsonText = GLTFUtils.DecodeBufferToText(binaryReader.getUint8Array(contentLength));
  114. content = JSON.parse(jsonText);
  115. break;
  116. default:
  117. Tools.Error("Unexpected content format: " + contentFormat);
  118. return null;
  119. }
  120. var body = binaryReader.getUint8Array();
  121. return {
  122. content: content,
  123. body: body
  124. };
  125. };
  126. }
  127. class BinaryReader {
  128. private _arrayBuffer: ArrayBuffer;
  129. private _dataView: DataView;
  130. private _byteOffset: number;
  131. constructor(arrayBuffer: ArrayBuffer) {
  132. this._arrayBuffer = arrayBuffer;
  133. this._dataView = new DataView(arrayBuffer);
  134. this._byteOffset = 0;
  135. }
  136. public getUint32(): number {
  137. var value = this._dataView.getUint32(this._byteOffset, true);
  138. this._byteOffset += 4;
  139. return value;
  140. }
  141. public getUint8Array(length?: number): Uint8Array {
  142. if (!length) {
  143. length = this._arrayBuffer.byteLength - this._byteOffset;
  144. }
  145. var value = new Uint8Array(this._arrayBuffer, this._byteOffset, length);
  146. this._byteOffset += length;
  147. return value;
  148. }
  149. }
  150. GLTFFileLoader.RegisterExtension(new GLTFBinaryExtension());
  151. }