Sfoglia il codice sorgente

Merge pull request #61 from NASA-AMMOS/other-file-loaders

Add loaders for other tiles formats
Garrett Johnson 5 anni fa
parent
commit
e8f8a1aeba

+ 1 - 1
example/bundle/customMaterial.dd39ecee.js

@@ -45180,7 +45180,7 @@ var parent = module.bundle.parent;
 if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') {
   var hostname = "" || location.hostname;
   var protocol = location.protocol === 'https:' ? 'wss' : 'ws';
-  var ws = new WebSocket(protocol + '://' + hostname + ':' + "62153" + '/');
+  var ws = new WebSocket(protocol + '://' + hostname + ':' + "63798" + '/');
 
   ws.onmessage = function (event) {
     checkedAssets = {};

File diff suppressed because it is too large
+ 1 - 1
example/bundle/customMaterial.dd39ecee.js.map


+ 1 - 1
example/bundle/customMaterial.js

@@ -212,7 +212,7 @@ var parent = module.bundle.parent;
 if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') {
   var hostname = "" || location.hostname;
   var protocol = location.protocol === 'https:' ? 'wss' : 'ws';
-  var ws = new WebSocket(protocol + '://' + hostname + ':' + "62153" + '/');
+  var ws = new WebSocket(protocol + '://' + hostname + ':' + "63798" + '/');
 
   ws.onmessage = function (event) {
     checkedAssets = {};

File diff suppressed because it is too large
+ 1 - 1
example/bundle/customMaterial.js.map


+ 1 - 1
example/bundle/example.e31bb0bc.js

@@ -45960,7 +45960,7 @@ var parent = module.bundle.parent;
 if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') {
   var hostname = "" || location.hostname;
   var protocol = location.protocol === 'https:' ? 'wss' : 'ws';
-  var ws = new WebSocket(protocol + '://' + hostname + ':' + "62153" + '/');
+  var ws = new WebSocket(protocol + '://' + hostname + ':' + "63798" + '/');
 
   ws.onmessage = function (event) {
     checkedAssets = {};

+ 4 - 2
src/base/B3DMLoaderBase.d.ts

@@ -1,8 +1,10 @@
+import { FeatureTable, BatchTable } from '../utilities/FeatureTable';
+
 export interface B3DMBaseResult {
 
 	version : String;
-	featureTable: Object;
-	batchTable : Object;
+	featureTable: FeatureTable;
+	batchTable : BatchTable;
 	glbBytes : Uint8Array;
 
 }

+ 5 - 121
src/base/B3DMLoaderBase.js

@@ -1,18 +1,7 @@
-// https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/specification/TileFormats/Batched3DModel/README.md
+// B3DM File Format
+// https://github.com/CesiumGS/3d-tiles/blob/master/specification/TileFormats/Batched3DModel/README.md
 
-// convert an array of numbers to a string
-function arrayToString( array ) {
-
-	let str = '';
-	for ( let i = 0, l = array.length; i < l; i ++ ) {
-
-		str += String.fromCharCode( array[ i ] );
-
-	}
-
-	return str;
-
-}
+import { FeatureTable, BatchTable } from '../utilities/FeatureTable.js';
 
 export class B3DMLoaderBase {
 
@@ -69,119 +58,14 @@ export class B3DMLoaderBase {
 
 		// Feature Table
 		const featureTableStart = 28;
-
-		const jsonFeatureTableData = new Uint8Array( buffer, featureTableStart, featureTableJSONByteLength );
-		const jsonFeatureTable = featureTableJSONByteLength === 0 ? {} : JSON.parse( arrayToString( jsonFeatureTableData ) );
-		const featureTable = { ...jsonFeatureTable };
-
-		// const binFeatureTableData = new Uint8Array( buffer, featureTableStart + featureTableJSONByteLength, featureTableBinaryByteLength );
-		// TODO: dereference the json feature table data in to the binary array.
-		// https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/specification/TileFormats/FeatureTable/README.md#json-header
-		// TODO: The feature table contains data with implicit stride and data types, which means we can't parse it into arrays
-		// unless they are specified ahead of time?s
+		const featureTable = new FeatureTable( buffer, featureTableStart, featureTableJSONByteLength, featureTableBinaryByteLength );
 
 		// Batch Table
 		const batchTableStart = featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength;
-
-		const jsonBatchTableData = new Uint8Array( buffer, batchTableStart, batchTableJSONByteLength );
-		const jsonBatchTable = batchTableJSONByteLength === 0 ? {} : JSON.parse( arrayToString( jsonBatchTableData ) );
-		const batchTable = { ...jsonBatchTable };
-
-		// dereference the json batch table data in to the binary array.
-		// https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/specification/TileFormats/FeatureTable/README.md#json-header
-		// const binBatchTableData = new Uint8Array( buffer, batchTableStart + batchTableJSONByteLength, batchTableBinaryByteLength );
-		const batchLength = jsonFeatureTable.BATCH_LENGTH;
-		for ( const key in jsonBatchTable ) {
-
-			const feature = jsonBatchTable[ key ];
-			if ( Array.isArray( feature ) ) {
-
-				batchTable[ key ] = {
-
-					type: 'SCALAR',
-					stride: 1,
-					data: feature,
-
-				};
-
-			} else {
-
-				let stride;
-				let data;
-				const arrayStart = batchTableStart + batchTableJSONByteLength;
-				const arrayLength = batchLength * stride + feature.byteOffset;
-				switch ( feature.type ) {
-
-					case 'SCALAR':
-						stride = 1;
-						break;
-
-					case 'VEC2':
-						stride = 2;
-						break;
-
-					case 'VEC3':
-						stride = 3;
-						break;
-
-					case 'VEC4':
-						stride = 4;
-						break;
-
-				}
-
-				switch ( feature.componentType ) {
-
-					case 'BYTE':
-						data = new Int8Array( buffer, arrayStart, arrayLength );
-						break;
-
-					case 'UNSIGNED_BYTE':
-						data = new Uint8Array( buffer, arrayStart, arrayLength );
-						break;
-
-					case 'SHORT':
-						data = new Int16Array( buffer, arrayStart, arrayLength );
-						break;
-
-					case 'UNSIGNED_SHORT':
-						data = new Uint16Array( buffer, arrayStart, arrayLength );
-						break;
-
-					case 'INT':
-						data = new Int32Array( buffer, arrayStart, arrayLength );
-						break;
-
-					case 'UNSIGNED_INT':
-						data = new Uint32Array( buffer, arrayStart, arrayLength );
-						break;
-
-					case 'FLOAT':
-						data = new Float32Array( buffer, arrayStart, arrayLength );
-						break;
-
-					case 'DOUBLE':
-						data = new Float64Array( buffer, arrayStart, arrayLength );
-						break;
-
-				}
-
-				batchTable[ key ] = {
-
-					type: feature.type,
-					stride,
-					data,
-
-				};
-
-			}
-
-		}
+		const batchTable = new BatchTable( buffer, featureTable.getData( 'BATCH_LENGTH' ), batchTableStart, batchTableJSONByteLength, batchTableBinaryByteLength );
 
 		const glbStart = batchTableStart + batchTableJSONByteLength + batchTableBinaryByteLength;
 		const glbBytes = new Uint8Array( buffer, glbStart, byteLength - glbStart );
-		// TODO: Understand how to apply the batchId semantics
-		// https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/specification/TileFormats/Batched3DModel/README.md#binary-gltf
 
 		return {
 			version,

+ 81 - 0
src/base/CMPTLoaderBase.js

@@ -0,0 +1,81 @@
+// CMPT File Format
+// https://github.com/CesiumGS/3d-tiles/blob/master/specification/TileFormats/Composite/README.md
+
+export class CMPTLoaderBase {
+
+	constructor() {
+
+		this.fetchOptions = {};
+
+	}
+
+	load( url ) {
+
+		return fetch( url, this.fetchOptions )
+			.then( res => res.arrayBuffer() )
+			.then( buffer => this.parse( buffer ) );
+
+	}
+
+	parse( buffer ) {
+
+		const dataView = new DataView( buffer );
+
+		// 16-byte header
+
+		// 4 bytes
+		const magic =
+			String.fromCharCode( dataView.getUint8( 0 ) ) +
+			String.fromCharCode( dataView.getUint8( 1 ) ) +
+			String.fromCharCode( dataView.getUint8( 2 ) ) +
+			String.fromCharCode( dataView.getUint8( 3 ) );
+
+		console.assert( magic === 'cmpt' );
+
+		// 4 bytes
+		const version = dataView.getUint32( 4, true );
+
+		console.assert( version === 1 );
+
+		// 4 bytes
+		const byteLength = dataView.getUint32( 8, true );
+
+		console.assert( byteLength === buffer.byteLength );
+
+		// 4 bytes
+		const tilesLength = dataView.getUint32( 12, true );
+
+		const tiles = [];
+		let offset = 16;
+		for ( let i = 0; i < tilesLength; i ++ ) {
+
+			const tileView = new DataView( buffer, offset, 12 );
+			const tileMagic =
+				String.fromCharCode( tileView.getUint8( 0 ) ) +
+				String.fromCharCode( tileView.getUint8( 1 ) ) +
+				String.fromCharCode( tileView.getUint8( 2 ) ) +
+				String.fromCharCode( tileView.getUint8( 3 ) );
+			const tileVersion = tileView.getUint32( 4, true );
+			const byteLength = tileView.getUint32( 8, true );
+
+			const tileBuffer = new Uint8Array( buffer, offset, byteLength );
+			tiles.push( {
+
+				type: tileMagic,
+				buffer: tileBuffer,
+				version: tileVersion,
+
+			} );
+			offset += byteLength;
+
+		}
+
+		return {
+			version,
+			tiles,
+		};
+
+	}
+
+}
+

+ 106 - 0
src/base/I3DMLoaderBase.js

@@ -0,0 +1,106 @@
+// I3DM File Format
+// https://github.com/CesiumGS/3d-tiles/blob/master/specification/TileFormats/Instanced3DModel/README.md
+
+import { arrayToString } from '../utilities/arrayToString.js';
+
+export class I3DMLoaderBase {
+
+	constructor() {
+
+		this.fetchOptions = {};
+
+	}
+
+	load( url ) {
+
+		return fetch( url, this.fetchOptions )
+			.then( res => res.arrayBuffer() )
+			.then( buffer => this.parse( buffer ) );
+
+	}
+
+	parse( buffer ) {
+
+		const dataView = new DataView( buffer );
+
+		// 32-byte header
+
+		// 4 bytes
+		const magic =
+			String.fromCharCode( dataView.getUint8( 0 ) ) +
+			String.fromCharCode( dataView.getUint8( 1 ) ) +
+			String.fromCharCode( dataView.getUint8( 2 ) ) +
+			String.fromCharCode( dataView.getUint8( 3 ) );
+
+		console.assert( magic === 'i3dm' );
+
+		// 4 bytes
+		const version = dataView.getUint32( 4, true );
+
+		console.assert( version === 1 );
+
+		// 4 bytes
+		const byteLength = dataView.getUint32( 8, true );
+
+		console.assert( byteLength === buffer.byteLength );
+
+		// 4 bytes
+		const featureTableJSONByteLength = dataView.getUint32( 12, true );
+
+		// 4 bytes
+		const featureTableBinaryByteLength = dataView.getUint32( 16, true );
+
+		// 4 bytes
+		const batchTableJSONByteLength = dataView.getUint32( 20, true );
+
+		// 4 bytes
+		const batchTableBinaryByteLength = dataView.getUint32( 24, true );
+
+		// 4 bytes
+		const gltfFormat = dataView.getUint32( 28, true )
+
+		// Feature Table
+		const featureTableStart = 32;
+		const featureTable = new FeatureTable( buffer, featureTableStart, featureTableJSONByteLength, featureTableBinaryByteLength );
+
+		// Batch Table
+		const BATCH_ID = featureTable.getData( 'BATCH_ID', 'UNSIGNED_SHORT' );
+		let maxBatchId = - 1;
+		for ( let i = 0, l = BATCH_ID.length; i < l; i ++ ) {
+
+			maxBatchId = Math.max( BATCH_ID[ i ], maxBatchId );
+
+		}
+
+		const batchLength = maxBatchId === - 1 ? 0 : maxBatchId + 1;
+		const batchTableStart = featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength;
+		const batchTable = new BatchTable( buffer, batchLength, batchTableStart, batchTableJSONByteLength, batchTableBinaryByteLength );
+
+		const glbStart = batchTableStart + batchTableJSONByteLength + batchTableBinaryByteLength;
+		const bodyBytes = new Uint8Array( buffer, glbStart, byteLength - glbStart );
+
+		// TODO: Consider just loading the data here rather than making the follow on function load it.
+		let glbBytes = null;
+		let externalUri = null;
+		if ( gltfFormat ) {
+
+			glbBytes = bodyBytes;
+
+		} else {
+
+			externalUri = arrayToString( bodyBytes );
+
+		}
+
+		return {
+			version,
+			featureTable,
+			batchTable,
+			glbBytes,
+			externalUri,
+		};
+
+	}
+
+}
+

+ 77 - 0
src/base/PNTSLoaderBase.js

@@ -0,0 +1,77 @@
+// PNTS File Format
+// https://github.com/CesiumGS/3d-tiles/blob/master/specification/TileFormats/PointCloud/README.md
+
+import { BatchTable } from "../utilities/FeatureTable";
+
+export class I3DMLoaderBase {
+
+	constructor() {
+
+		this.fetchOptions = {};
+
+	}
+
+	load( url ) {
+
+		return fetch( url, this.fetchOptions )
+			.then( res => res.arrayBuffer() )
+			.then( buffer => this.parse( buffer ) );
+
+	}
+
+	parse( buffer ) {
+
+		const dataView = new DataView( buffer );
+
+		// 28-byte header
+
+		// 4 bytes
+		const magic =
+			String.fromCharCode( dataView.getUint8( 0 ) ) +
+			String.fromCharCode( dataView.getUint8( 1 ) ) +
+			String.fromCharCode( dataView.getUint8( 2 ) ) +
+			String.fromCharCode( dataView.getUint8( 3 ) );
+
+		console.assert( magic === 'pnts' );
+
+		// 4 bytes
+		const version = dataView.getUint32( 4, true );
+
+		console.assert( version === 1 );
+
+		// 4 bytes
+		const byteLength = dataView.getUint32( 8, true );
+
+		console.assert( byteLength === buffer.byteLength );
+
+		// 4 bytes
+		const featureTableJSONByteLength = dataView.getUint32( 12, true );
+
+		// 4 bytes
+		const featureTableBinaryByteLength = dataView.getUint32( 16, true );
+
+		// 4 bytes
+		const batchTableJSONByteLength = dataView.getUint32( 20, true );
+
+		// 4 bytes
+		const batchTableBinaryByteLength = dataView.getUint32( 24, true );
+
+		// Feature Table
+		const featureTableStart = 28;
+		const featureTable = new FeatureTable( buffer, featureTableStart, featureTableJSONByteLength, featureTableBinaryByteLength );
+
+		// Batch Table
+		const batchLength = featureTable.getData( 'BATCH_LENGTH' ) || 0;
+		const batchTableStart = featureTableStart + featureTableJSONByteLength + featureTableBinaryByteLength;
+		const batchTable = new BatchTable( buffer, batchLength, batchTableStart, batchTableJSONByteLength, batchTableBinaryByteLength );
+
+		return {
+			version,
+			featureTable,
+			batchTable,
+		};
+
+	}
+
+}
+

+ 155 - 0
src/utilities/FeatureTable.js

@@ -0,0 +1,155 @@
+import { arrayToString } from './arrayToString.js';
+
+export class FeatureTable {
+
+	constructor( buffer, start, headerLength, binLength ) {
+
+		this.buffer = buffer;
+		this.binOffset = start + headerLength;
+		this.binLength = binLength;
+
+		let header = null;
+		if ( headerLength !== 0 ) {
+
+			const headerData = new Uint8Array( buffer, start, headerLength );
+			header = JSON.parse( arrayToString( headerData ) );
+
+		} else {
+
+			header = {};
+
+		}
+		this.header = header;
+
+	}
+
+	getKeys() {
+
+		return Object.keys( this.header );
+
+	}
+
+	getData( key, count, defaultComponentType = null, defaultType = null ) {
+
+		const header = this.header;
+
+		if ( ! ( key in header ) ) {
+
+			return null;
+
+		}
+
+		const feature = header[ key ];
+		if ( ! ( feature instanceof Object ) ) {
+
+			return feature;
+
+		} else if ( Array.isArray( feature ) ) {
+
+			return feature;
+
+		} else {
+
+			const { buffer, binOffset, binLength } = this;
+			const byteOffset = feature.byteOffset || 0;
+			const featureType = feature.type || defaultType;
+			const featureComponentType = feature.componentType || defaultComponentType;
+
+			if ( 'type' in feature && defaultType && feature.type !== defaultType) {
+
+				throw new Error( 'FeatureTable: Specified type does not match expected type.' );
+
+			}
+
+			let stride;
+			switch ( featureType ) {
+
+				case 'SCALAR':
+					stride = 1;
+					break;
+
+				case 'VEC2':
+					stride = 2;
+					break;
+
+				case 'VEC3':
+					stride = 3;
+					break;
+
+				case 'VEC4':
+					stride = 4;
+					break;
+
+			}
+
+			let data;
+			const arrayStart = binOffset + byteOffset;
+			const arrayLength = count * stride;
+
+			switch ( featureComponentType ) {
+
+				case 'BYTE':
+					data = new Int8Array( buffer, arrayStart, arrayLength );
+					break;
+
+				case 'UNSIGNED_BYTE':
+					data = new Uint8Array( buffer, arrayStart, arrayLength );
+					break;
+
+				case 'SHORT':
+					data = new Int16Array( buffer, arrayStart, arrayLength );
+					break;
+
+				case 'UNSIGNED_SHORT':
+					data = new Uint16Array( buffer, arrayStart, arrayLength );
+					break;
+
+				case 'INT':
+					data = new Int32Array( buffer, arrayStart, arrayLength );
+					break;
+
+				case 'UNSIGNED_INT':
+					data = new Uint32Array( buffer, arrayStart, arrayLength );
+					break;
+
+				case 'FLOAT':
+					data = new Float32Array( buffer, arrayStart, arrayLength );
+					break;
+
+				case 'DOUBLE':
+					data = new Float64Array( buffer, arrayStart, arrayLength );
+					break;
+
+			}
+
+			const dataEnd = arrayStart + arrayLength * data.BYTES_PER_ELEMENT;
+			if ( dataEnd > binOffset + binLength ) {
+
+				throw new Error( 'FeatureTable: Feature data read outside binary body length.' );
+
+			}
+
+			return data;
+
+		}
+
+	}
+
+}
+
+export class BatchTable extends FeatureTable {
+
+	constructor( buffer, batchSize, start, headerLength, binLength ) {
+
+		super( buffer, start, headerLength, binLength );
+		this.batchSize = batchSize;
+
+	}
+
+	getData( key, componentType = null, type = null ) {
+
+		return this.getData( key, this.batchSize, type, componentType );
+
+	}
+
+}

+ 12 - 0
src/utilities/arrayToString.js

@@ -0,0 +1,12 @@
+export function arrayToString( array ) {
+
+	let str = '';
+	for ( let i = 0, l = array.length; i < l; i ++ ) {
+
+		str += String.fromCharCode( array[ i ] );
+
+	}
+
+	return str;
+
+}