|
@@ -93,7 +93,7 @@ export class TilesRendererBase {
|
|
|
const rootTileSet = tileSets[ this.rootURL ];
|
|
|
if ( ! ( this.rootURL in tileSets ) ) {
|
|
|
|
|
|
- this.loadTileSet( this.rootURL );
|
|
|
+ this.loadRootTileSet( this.rootURL );
|
|
|
return;
|
|
|
|
|
|
} else if ( ! rootTileSet || ! rootTileSet.root ) {
|
|
@@ -167,7 +167,21 @@ export class TilesRendererBase {
|
|
|
|
|
|
tile.parent = parentTile;
|
|
|
tile.children = tile.children || [];
|
|
|
- tile.__contentEmpty = ! tile.content || ! tile.content.uri;
|
|
|
+
|
|
|
+ const uri = tile.content && tile.content.uri;
|
|
|
+ if ( uri ) {
|
|
|
+
|
|
|
+ // "content" should only indicate loadable meshes, not external tile sets
|
|
|
+ const isExternalTileSet = /\.json$/i.test( tile.content.uri );
|
|
|
+ tile.__externalTileSet = isExternalTileSet;
|
|
|
+ tile.__contentEmpty = isExternalTileSet;
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ tile.__externalTileSet = false;
|
|
|
+ tile.__contentEmpty = true;
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
tile.__error = 0.0;
|
|
|
tile.__inFrustum = false;
|
|
@@ -225,41 +239,58 @@ export class TilesRendererBase {
|
|
|
}
|
|
|
|
|
|
// Private Functions
|
|
|
- loadTileSet( url ) {
|
|
|
+ fetchTileSet( url, fetchOptions, parent = null ) {
|
|
|
|
|
|
- const tileSets = this.tileSets;
|
|
|
- if ( ! ( url in tileSets ) ) {
|
|
|
+ return fetch( url, fetchOptions )
|
|
|
+ .then( res => {
|
|
|
+
|
|
|
+ if ( res.ok ) {
|
|
|
|
|
|
- const pr =
|
|
|
- fetch( url, this.fetchOptions )
|
|
|
- .then( res => {
|
|
|
+ return res.json();
|
|
|
|
|
|
- if ( res.ok ) {
|
|
|
+ } else {
|
|
|
|
|
|
- return res.json();
|
|
|
+ throw new Error( `TilesRenderer: Failed to load tileset "${ url }" with status ${ res.status } : ${ res.statusText }` );
|
|
|
|
|
|
- } else {
|
|
|
+ }
|
|
|
|
|
|
- throw new Error( `TilesRenderer: Failed to load tileset "${ url }" with status ${ res.status } : ${ res.statusText }` );
|
|
|
+ } )
|
|
|
+ .then( json => {
|
|
|
|
|
|
- }
|
|
|
+ const version = json.asset.version;
|
|
|
+ console.assert(
|
|
|
+ version === '1.0' || version === '0.0',
|
|
|
+ 'asset.version is expected to be a string of "1.0" or "0.0"'
|
|
|
+ );
|
|
|
|
|
|
- } )
|
|
|
- .then( json => {
|
|
|
+ const basePath = path.dirname( url );
|
|
|
|
|
|
- const version = json.asset.version;
|
|
|
- console.assert(
|
|
|
- version === '1.0' || version === '0.0',
|
|
|
- 'asset.version is expected to be a string of "1.0" or "0.0"'
|
|
|
- );
|
|
|
+ traverseSet(
|
|
|
+ json.root,
|
|
|
+ ( node, parent ) => this.preprocessNode( node, parent, basePath ),
|
|
|
+ null,
|
|
|
+ parent,
|
|
|
+ parent ? parent.__depth : 0,
|
|
|
+ );
|
|
|
|
|
|
- const basePath = path.dirname( url );
|
|
|
+ return json;
|
|
|
|
|
|
- traverseSet( json.root, ( node, parent ) => this.preprocessNode( node, parent, basePath ) );
|
|
|
+ } );
|
|
|
|
|
|
- tileSets[ url ] = json;
|
|
|
+ }
|
|
|
|
|
|
- } );
|
|
|
+ loadRootTileSet( url ) {
|
|
|
+
|
|
|
+ const tileSets = this.tileSets;
|
|
|
+ if ( ! ( url in tileSets ) ) {
|
|
|
+
|
|
|
+ const pr = this
|
|
|
+ .fetchTileSet( url, this.fetchOptions )
|
|
|
+ .then( json => {
|
|
|
+
|
|
|
+ tileSets[ url ] = json;
|
|
|
+
|
|
|
+ } );
|
|
|
|
|
|
pr.catch( err => {
|
|
|
|
|
@@ -298,6 +329,7 @@ export class TilesRendererBase {
|
|
|
const lruCache = this.lruCache;
|
|
|
const downloadQueue = this.downloadQueue;
|
|
|
const parseQueue = this.parseQueue;
|
|
|
+ const isExternalTileSet = tile.__externalTileSet;
|
|
|
lruCache.add( tile, t => {
|
|
|
|
|
|
// Stop the load if it's started
|
|
@@ -306,6 +338,10 @@ export class TilesRendererBase {
|
|
|
t.__loadAbort.abort();
|
|
|
t.__loadAbort = null;
|
|
|
|
|
|
+ } else if ( isExternalTileSet ) {
|
|
|
+
|
|
|
+ t.children.length = 0;
|
|
|
+
|
|
|
} else {
|
|
|
|
|
|
this.disposeTile( t );
|
|
@@ -323,7 +359,6 @@ export class TilesRendererBase {
|
|
|
|
|
|
}
|
|
|
|
|
|
- t.__buffer = null;
|
|
|
t.__loadingState = UNLOADED;
|
|
|
t.__loadIndex ++;
|
|
|
|
|
@@ -342,131 +377,168 @@ export class TilesRendererBase {
|
|
|
stats.downloading ++;
|
|
|
tile.__loadAbort = controller;
|
|
|
tile.__loadingState = LOADING;
|
|
|
- downloadQueue.add( tile, tile => {
|
|
|
|
|
|
+ const errorCallback = e => {
|
|
|
+
|
|
|
+ // if it has been unloaded then the tile has been disposed
|
|
|
if ( tile.__loadIndex !== loadIndex ) {
|
|
|
|
|
|
- return Promise.resolve();
|
|
|
+ return;
|
|
|
|
|
|
}
|
|
|
|
|
|
- return fetch( tile.content.uri, Object.assign( { signal }, this.fetchOptions ) );
|
|
|
+ if ( e.name !== 'AbortError' ) {
|
|
|
|
|
|
- } )
|
|
|
- .then( res => {
|
|
|
+ parseQueue.remove( tile );
|
|
|
+ downloadQueue.remove( tile );
|
|
|
|
|
|
- if ( tile.__loadIndex !== loadIndex ) {
|
|
|
+ if ( tile.__loadingState === PARSING ) {
|
|
|
+
|
|
|
+ stats.parsing --;
|
|
|
+
|
|
|
+ } else if ( tile.__loadingState === LOADING ) {
|
|
|
|
|
|
- return;
|
|
|
+ stats.downloading --;
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( res.ok ) {
|
|
|
+ stats.failed ++;
|
|
|
|
|
|
- return res.arrayBuffer();
|
|
|
+ console.error( 'TilesRenderer : Failed to load tile.' );
|
|
|
+ console.error( e );
|
|
|
+ tile.__loadingState = FAILED;
|
|
|
|
|
|
- } else {
|
|
|
+ } else {
|
|
|
|
|
|
- throw new Error( `Failed to load model with error code ${res.status}` );
|
|
|
+ lruCache.remove( tile );
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- } )
|
|
|
- .then( buffer => {
|
|
|
+ };
|
|
|
+
|
|
|
+ if ( isExternalTileSet ) {
|
|
|
+
|
|
|
+ downloadQueue.add( tile, tile => {
|
|
|
|
|
|
// if it has been unloaded then the tile has been disposed
|
|
|
if ( tile.__loadIndex !== loadIndex ) {
|
|
|
|
|
|
- return;
|
|
|
+ return Promise.resolve();
|
|
|
|
|
|
}
|
|
|
|
|
|
- stats.downloading --;
|
|
|
- stats.parsing ++;
|
|
|
- tile.__loadAbort = null;
|
|
|
- tile.__loadingState = PARSING;
|
|
|
- tile.__buffer = buffer;
|
|
|
+ return this.fetchTileSet( tile.content.uri, Object.assign( { signal }, this.fetchOptions ), tile );
|
|
|
|
|
|
- return parseQueue.add( tile, tile => {
|
|
|
+ } )
|
|
|
+ .then( json => {
|
|
|
|
|
|
// if it has been unloaded then the tile has been disposed
|
|
|
if ( tile.__loadIndex !== loadIndex ) {
|
|
|
|
|
|
- return Promise.resolve();
|
|
|
+ return;
|
|
|
|
|
|
}
|
|
|
|
|
|
- const uri = tile.content.uri;
|
|
|
- const extension = uri.split( /\./g ).pop();
|
|
|
- const buffer = tile.__buffer;
|
|
|
- tile.__buffer = null;
|
|
|
+ stats.downloading --;
|
|
|
+ tile.__loadAbort = null;
|
|
|
+ tile.__loadingState = LOADED;
|
|
|
|
|
|
- return this.parseTile( buffer, tile, extension );
|
|
|
+ tile.children.push( json.root );
|
|
|
|
|
|
- } );
|
|
|
+ } )
|
|
|
+ .catch( errorCallback );
|
|
|
|
|
|
- } )
|
|
|
- .then( () => {
|
|
|
+ } else {
|
|
|
+
|
|
|
+ downloadQueue.add( tile, tile => {
|
|
|
|
|
|
- // if it has been unloaded then the tile has been disposed
|
|
|
if ( tile.__loadIndex !== loadIndex ) {
|
|
|
|
|
|
- return;
|
|
|
+ return Promise.resolve();
|
|
|
|
|
|
}
|
|
|
|
|
|
- stats.parsing --;
|
|
|
- tile.__loadingState = LOADED;
|
|
|
- if ( tile.__wasSetVisible ) {
|
|
|
+ return fetch( tile.content.uri, Object.assign( { signal }, this.fetchOptions ) );
|
|
|
|
|
|
- this.setTileVisible( tile, true );
|
|
|
+ } )
|
|
|
+ .then( res => {
|
|
|
|
|
|
- }
|
|
|
+ if ( tile.__loadIndex !== loadIndex ) {
|
|
|
|
|
|
- if ( tile.__wasSetActive ) {
|
|
|
+ return;
|
|
|
|
|
|
- this.setTileActive( tile, true );
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ if ( res.ok ) {
|
|
|
|
|
|
- } )
|
|
|
- .catch( e => {
|
|
|
+ return res.arrayBuffer();
|
|
|
|
|
|
- // if it has been unloaded then the tile has been disposed
|
|
|
- if ( tile.__loadIndex !== loadIndex ) {
|
|
|
+ } else {
|
|
|
|
|
|
- return;
|
|
|
+ throw new Error( `Failed to load model with error code ${res.status}` );
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
+
|
|
|
+ } )
|
|
|
+ .then( buffer => {
|
|
|
+
|
|
|
+ // if it has been unloaded then the tile has been disposed
|
|
|
+ if ( tile.__loadIndex !== loadIndex ) {
|
|
|
|
|
|
- if ( e.name !== 'AbortError' ) {
|
|
|
+ return;
|
|
|
|
|
|
- parseQueue.remove( tile );
|
|
|
- downloadQueue.remove( tile );
|
|
|
+ }
|
|
|
+
|
|
|
+ stats.downloading --;
|
|
|
+ stats.parsing ++;
|
|
|
+ tile.__loadAbort = null;
|
|
|
+ tile.__loadingState = PARSING;
|
|
|
+
|
|
|
+ return parseQueue.add( tile, tile => {
|
|
|
|
|
|
- if ( tile.__loadingState === PARSING ) {
|
|
|
+ // if it has been unloaded then the tile has been disposed
|
|
|
+ if ( tile.__loadIndex !== loadIndex ) {
|
|
|
+
|
|
|
+ return Promise.resolve();
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
- stats.parsing --;
|
|
|
+ const uri = tile.content.uri;
|
|
|
+ const extension = uri.split( /\./g ).pop();
|
|
|
|
|
|
- } else if ( tile.__loadingState === LOADING ) {
|
|
|
+ return this.parseTile( buffer, tile, extension );
|
|
|
|
|
|
- stats.downloading --;
|
|
|
+ } );
|
|
|
+
|
|
|
+ } )
|
|
|
+ .then( () => {
|
|
|
+
|
|
|
+ // if it has been unloaded then the tile has been disposed
|
|
|
+ if ( tile.__loadIndex !== loadIndex ) {
|
|
|
+
|
|
|
+ return;
|
|
|
|
|
|
}
|
|
|
|
|
|
- stats.failed ++;
|
|
|
+ stats.parsing --;
|
|
|
+ tile.__loadingState = LOADED;
|
|
|
|
|
|
- console.error( 'TilesRenderer : Failed to load tile.' );
|
|
|
- console.error( e );
|
|
|
- tile.__loadingState = FAILED;
|
|
|
+ if ( tile.__wasSetVisible ) {
|
|
|
|
|
|
- } else {
|
|
|
+ this.setTileVisible( tile, true );
|
|
|
|
|
|
- lruCache.remove( tile );
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ if ( tile.__wasSetActive ) {
|
|
|
|
|
|
- } );
|
|
|
+ this.setTileActive( tile, true );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } )
|
|
|
+ .catch( errorCallback );
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|