babylon.glTFBinaryExtension.ts 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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 = GLTFUtils.CreateGlTFRuntime(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. }
  36. gltfRuntime.loadedBufferViews[BinaryExtensionBufferName] = binary.body;
  37. onSuccess(gltfRuntime);
  38. return true;
  39. }
  40. public loadBufferAsync(gltfRuntime: IGLTFRuntime, buffer: IGLTFBuffer, onSuccess: (data: ArrayBufferView) => void, onError: () => void): boolean {
  41. if (gltfRuntime.extensionsUsed.indexOf(this.name) == -1) {
  42. return false;
  43. }
  44. onSuccess(gltfRuntime.loadedBufferViews[BinaryExtensionBufferName]);
  45. return true;
  46. }
  47. public loadTextureAsync(gltfRuntime: IGLTFRuntime, texture: IGLTFTexture, onSuccess: (texture: Texture) => void, onError: () => void): boolean {
  48. var source: IGLTFImage = gltfRuntime.images[texture.source];
  49. if (!source.extensions || !(this.name in source.extensions)) {
  50. return false;
  51. }
  52. var sourceExt: IGLTFBinaryExtensionImage = source.extensions[this.name];
  53. var sampler: IGLTFSampler = gltfRuntime.samplers[texture.sampler];
  54. var createMipMaps =
  55. (sampler.minFilter === ETextureFilterType.NEAREST_MIPMAP_NEAREST) ||
  56. (sampler.minFilter === ETextureFilterType.NEAREST_MIPMAP_LINEAR) ||
  57. (sampler.minFilter === ETextureFilterType.LINEAR_MIPMAP_NEAREST) ||
  58. (sampler.minFilter === ETextureFilterType.LINEAR_MIPMAP_LINEAR);
  59. var samplingMode = Texture.BILINEAR_SAMPLINGMODE;
  60. var bufferView: IGLTFBufferView = gltfRuntime.bufferViews[sourceExt.bufferView];
  61. var imageBytes = GLTFUtils.GetBufferFromBufferView(gltfRuntime, bufferView, 0, bufferView.byteLength, EComponentType.UNSIGNED_BYTE);
  62. var blob = new Blob([imageBytes], { type: sourceExt.mimeType });
  63. var blobURL = URL.createObjectURL(blob);
  64. var revokeBlobURL = () => URL.revokeObjectURL(blobURL);
  65. var newTexture = new Texture(blobURL, gltfRuntime.scene, !createMipMaps, true, samplingMode, revokeBlobURL, revokeBlobURL);
  66. newTexture.wrapU = GLTFUtils.GetWrapMode(sampler.wrapS);
  67. newTexture.wrapV = GLTFUtils.GetWrapMode(sampler.wrapT);
  68. newTexture.name = name;
  69. texture.babylonTexture = newTexture;
  70. onSuccess(newTexture);
  71. return true;
  72. }
  73. public loadShaderStringAsync(gltfRuntime: IGLTFRuntime, shader: IGLTFShader, onSuccess: (shaderString: string) => void, onError: () => void): boolean {
  74. if (!shader.extensions || !(this.name in shader.extensions)) {
  75. return false;
  76. }
  77. var binaryExtensionShader: IGLTFBinaryExtensionShader = shader.extensions[this.name];
  78. var bufferView: IGLTFBufferView = gltfRuntime.bufferViews[binaryExtensionShader.bufferView];
  79. var shaderBytes = GLTFUtils.GetBufferFromBufferView(gltfRuntime, bufferView, 0, bufferView.byteLength, EComponentType.UNSIGNED_BYTE);
  80. var shaderString = GLTFUtils.DecodeBufferToText(shaderBytes);
  81. onSuccess(shaderString);
  82. return true;
  83. }
  84. // Parses a glTF binary array buffer into its content and body
  85. private _parseBinary(data: ArrayBuffer): IGLTFBinaryExtension {
  86. var binaryReader = new BinaryReader(data);
  87. var magic = GLTFUtils.DecodeBufferToText(binaryReader.getUint8Array(4));
  88. if (magic != "glTF") {
  89. Tools.Error("Unexpected magic: " + magic);
  90. return null;
  91. }
  92. var version = binaryReader.getUint32();
  93. if (version != 1) {
  94. Tools.Error("Unsupported version: " + version);
  95. return null;
  96. }
  97. var length = binaryReader.getUint32();
  98. if (length != data.byteLength) {
  99. Tools.Error("Length in header does not match actual data length: " + length + " != " + data.byteLength);
  100. return null;
  101. }
  102. var contentLength = binaryReader.getUint32();
  103. var contentFormat = <EContentFormat>binaryReader.getUint32();
  104. var content: Object;
  105. switch (contentFormat) {
  106. case EContentFormat.JSON:
  107. var jsonText = GLTFUtils.DecodeBufferToText(binaryReader.getUint8Array(contentLength));
  108. content = JSON.parse(jsonText);
  109. break;
  110. default:
  111. Tools.Error("Unexpected content format: " + contentFormat);
  112. return null;
  113. }
  114. var body = binaryReader.getUint8Array();
  115. return {
  116. content: content,
  117. body: body
  118. };
  119. };
  120. }
  121. class BinaryReader {
  122. private _arrayBuffer: ArrayBuffer;
  123. private _dataView: DataView;
  124. private _byteOffset: number;
  125. constructor(arrayBuffer: ArrayBuffer) {
  126. this._arrayBuffer = arrayBuffer;
  127. this._dataView = new DataView(arrayBuffer);
  128. this._byteOffset = 0;
  129. }
  130. public getUint32(): number {
  131. var value = this._dataView.getUint32(this._byteOffset, true);
  132. this._byteOffset += 4;
  133. return value;
  134. }
  135. public getUint8Array(length?: number): Uint8Array {
  136. if (!length) {
  137. length = this._arrayBuffer.byteLength - this._byteOffset;
  138. }
  139. var value = new Uint8Array(this._arrayBuffer, this._byteOffset, length);
  140. this._byteOffset += length;
  141. return value;
  142. }
  143. }
  144. GLTFFileLoader.RegisterExtension(new GLTFBinaryExtension());
  145. }