babylon.glTFBinaryExtension.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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. private _binary: IGLTFBinaryExtension;
  21. public constructor() {
  22. super("KHR_binary_glTF");
  23. }
  24. public loadRuntimeAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: () => void): boolean {
  25. if (!(data instanceof ArrayBuffer)) {
  26. return false;
  27. }
  28. setTimeout(() => {
  29. this._binary = this._parseBinary(<ArrayBuffer>data);
  30. if (!this._binary) {
  31. onError();
  32. return true;
  33. }
  34. var gltfRuntime = GLTFFileLoaderBase.CreateRuntime(this._binary.content, scene, rootUrl);
  35. if (gltfRuntime.extensionsUsed.indexOf(this.name) === -1) {
  36. Tools.Warn("glTF binary file does not have " + this.name + " specified in extensionsUsed");
  37. gltfRuntime.extensionsUsed.push(this.name);
  38. }
  39. onSuccess(gltfRuntime);
  40. });
  41. return true;
  42. }
  43. public loadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void): boolean {
  44. if (gltfRuntime.extensionsUsed.indexOf(this.name) === -1) {
  45. return false;
  46. }
  47. if (id !== BinaryExtensionBufferName) {
  48. return false;
  49. }
  50. onSuccess(this._binary.body);
  51. return true;
  52. }
  53. public loadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void): boolean {
  54. var texture: IGLTFTexture = gltfRuntime.textures[id];
  55. var source: IGLTFImage = gltfRuntime.images[texture.source];
  56. if (!source.extensions || !(this.name in source.extensions)) {
  57. return false;
  58. }
  59. var sourceExt: IGLTFBinaryExtensionImage = source.extensions[this.name];
  60. var bufferView: IGLTFBufferView = gltfRuntime.bufferViews[sourceExt.bufferView];
  61. var buffer = GLTFUtils.GetBufferFromBufferView(gltfRuntime, bufferView, 0, bufferView.byteLength, EComponentType.UNSIGNED_BYTE);
  62. onSuccess(buffer);
  63. return true;
  64. }
  65. public loadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: () => void): boolean {
  66. var shader: IGLTFShader = gltfRuntime.shaders[id];
  67. if (!shader.extensions || !(this.name in shader.extensions)) {
  68. return false;
  69. }
  70. var binaryExtensionShader: IGLTFBinaryExtensionShader = shader.extensions[this.name];
  71. var bufferView: IGLTFBufferView = gltfRuntime.bufferViews[binaryExtensionShader.bufferView];
  72. var shaderBytes = GLTFUtils.GetBufferFromBufferView(gltfRuntime, bufferView, 0, bufferView.byteLength, EComponentType.UNSIGNED_BYTE);
  73. setTimeout(() => {
  74. var shaderString = GLTFUtils.DecodeBufferToText(shaderBytes);
  75. onSuccess(shaderString);
  76. });
  77. return true;
  78. }
  79. // Parses a glTF binary array buffer into its content and body
  80. private _parseBinary(data: ArrayBuffer): IGLTFBinaryExtension {
  81. var binaryReader = new BinaryReader(data);
  82. var magic = GLTFUtils.DecodeBufferToText(binaryReader.getUint8Array(4));
  83. if (magic != "glTF") {
  84. Tools.Error("Unexpected magic: " + magic);
  85. return null;
  86. }
  87. var version = binaryReader.getUint32();
  88. if (version != 1) {
  89. Tools.Error("Unsupported version: " + version);
  90. return null;
  91. }
  92. var length = binaryReader.getUint32();
  93. if (length != data.byteLength) {
  94. Tools.Error("Length in header does not match actual data length: " + length + " != " + data.byteLength);
  95. return null;
  96. }
  97. var contentLength = binaryReader.getUint32();
  98. var contentFormat = <EContentFormat>binaryReader.getUint32();
  99. var content: Object;
  100. switch (contentFormat) {
  101. case EContentFormat.JSON:
  102. var jsonText = GLTFUtils.DecodeBufferToText(binaryReader.getUint8Array(contentLength));
  103. content = JSON.parse(jsonText);
  104. break;
  105. default:
  106. Tools.Error("Unexpected content format: " + contentFormat);
  107. return null;
  108. }
  109. var body = binaryReader.getUint8Array();
  110. return {
  111. content: content,
  112. body: body
  113. };
  114. };
  115. }
  116. class BinaryReader {
  117. private _arrayBuffer: ArrayBuffer;
  118. private _dataView: DataView;
  119. private _byteOffset: number;
  120. constructor(arrayBuffer: ArrayBuffer) {
  121. this._arrayBuffer = arrayBuffer;
  122. this._dataView = new DataView(arrayBuffer);
  123. this._byteOffset = 0;
  124. }
  125. public getUint32(): number {
  126. var value = this._dataView.getUint32(this._byteOffset, true);
  127. this._byteOffset += 4;
  128. return value;
  129. }
  130. public getUint8Array(length?: number): Uint8Array {
  131. if (!length) {
  132. length = this._arrayBuffer.byteLength - this._byteOffset;
  133. }
  134. var value = new Uint8Array(this._arrayBuffer, this._byteOffset, length);
  135. this._byteOffset += length;
  136. return value;
  137. }
  138. }
  139. GLTFFileLoader.RegisterExtension(new GLTFBinaryExtension());
  140. }