I3DMLoaderBase.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // I3DM File Format
  2. // https://github.com/CesiumGS/3d-tiles/blob/master/specification/TileFormats/Instanced3DModel/README.md
  3. import { FeatureTable, BatchTable } from '../utilities/FeatureTable.js';
  4. import { arrayToString } from '../utilities/arrayToString.js';
  5. import { LoaderBase } from './LoaderBase.js';
  6. export class I3DMLoaderBase extends LoaderBase {
  7. parse( buffer ) {
  8. const dataView = new DataView( buffer );
  9. // 32-byte header
  10. // 4 bytes
  11. const magic =
  12. String.fromCharCode( dataView.getUint8( 0 ) ) +
  13. String.fromCharCode( dataView.getUint8( 1 ) ) +
  14. String.fromCharCode( dataView.getUint8( 2 ) ) +
  15. String.fromCharCode( dataView.getUint8( 3 ) );
  16. console.assert( magic === 'i3dm' );
  17. // 4 bytes
  18. const version = dataView.getUint32( 4, true );
  19. console.assert( version === 1 );
  20. // 4 bytes
  21. const byteLength = dataView.getUint32( 8, true );
  22. console.assert( byteLength === buffer.byteLength );
  23. // 4 bytes
  24. const featureTableJSONByteLength = dataView.getUint32( 12, true );
  25. // 4 bytes
  26. const featureTableBinaryByteLength = dataView.getUint32( 16, true );
  27. // 4 bytes
  28. const batchTableJSONByteLength = dataView.getUint32( 20, true );
  29. // 4 bytes
  30. const batchTableBinaryByteLength = dataView.getUint32( 24, true );
  31. // 4 bytes
  32. const gltfFormat = dataView.getUint32( 28, true );
  33. // Feature Table
  34. const featureTableStart = 32;
  35. const featureTableBuffer = buffer.slice(
  36. featureTableStart,
  37. featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength,
  38. );
  39. const featureTable = new FeatureTable(
  40. featureTableBuffer,
  41. 0,
  42. featureTableJSONByteLength,
  43. featureTableBinaryByteLength,
  44. );
  45. // Batch Table
  46. const batchTableStart = featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength;
  47. const batchTableBuffer = buffer.slice(
  48. batchTableStart,
  49. batchTableStart + batchTableJSONByteLength + batchTableBinaryByteLength,
  50. );
  51. const batchTable = new BatchTable(
  52. batchTableBuffer,
  53. featureTable.getData( 'INSTANCES_LENGTH' ),
  54. 0,
  55. batchTableJSONByteLength,
  56. batchTableBinaryByteLength,
  57. );
  58. const glbStart = batchTableStart + batchTableJSONByteLength + batchTableBinaryByteLength;
  59. const bodyBytes = new Uint8Array( buffer, glbStart, byteLength - glbStart );
  60. let glbBytes = null;
  61. let promise = null;
  62. if ( gltfFormat ) {
  63. glbBytes = bodyBytes;
  64. promise = Promise.resolve();
  65. } else {
  66. const externalUri = this.resolveExternalURL( arrayToString( bodyBytes ) );
  67. promise = fetch( externalUri, this.fetchOptions )
  68. .then( res => {
  69. if ( ! res.ok ) {
  70. throw new Error( `I3DMLoaderBase : Failed to load file "${ externalUri }" with status ${ res.status } : ${ res.statusText }` );
  71. }
  72. return res.arrayBuffer();
  73. } )
  74. .then( buffer => {
  75. glbBytes = new Uint8Array( buffer );
  76. } );
  77. }
  78. return promise.then( () => {
  79. return {
  80. version,
  81. featureTable,
  82. batchTable,
  83. glbBytes,
  84. };
  85. } );
  86. }
  87. }