diff --git a/packages/Main/src/Core/Scheduler/Scheduler.js b/packages/Main/src/Core/Scheduler/Scheduler.js index 60d24c8603..0154025972 100644 --- a/packages/Main/src/Core/Scheduler/Scheduler.js +++ b/packages/Main/src/Core/Scheduler/Scheduler.js @@ -80,19 +80,25 @@ function _instanciateQueue() { execute(cmd, provider) { this.counters.pending--; this.counters.executing++; - return provider.executeCommand(cmd).then((result) => { - this.counters.executing--; - cmd.resolve(result); - // only count successul commands - this.counters.executed++; - }, (err) => { - this.counters.executing--; - cmd.reject(err); - this.counters.failed++; - if (__DEBUG__ && this.counters.failed < 3) { - console.error(err); - } - }); + return provider.executeCommand(cmd) + .then((result) => { + this.counters.executing--; + cmd.resolve(result); + // only count successul commands + this.counters.executed++; + }) + .catch((err) => { + this.counters.executing--; + cmd.reject(err); + this.counters.failed++; + if (__DEBUG__ && this.counters.failed < 3) { + if (err instanceof AggregateError) { + console.error(err, ...err.errors); + } else { + console.error(err); + } + } + }); }, }; } diff --git a/packages/Main/src/Layer/Layer.js b/packages/Main/src/Layer/Layer.js index 0db8446bba..08a0313d75 100644 --- a/packages/Main/src/Layer/Layer.js +++ b/packages/Main/src/Layer/Layer.js @@ -258,8 +258,9 @@ class Layer extends THREE.EventDispatcher { let data = this.cache.get(key); if (!data) { data = this.source.loadData(from, this) - .then(feat => this.convert(feat, to), (err) => { - throw err; + .then(feat => this.convert(feat, to)) + .catch((err) => { + this.source.handlingError(err); }); this.cache.set(key, data); } diff --git a/packages/Main/src/Parser/VectorTileParser.js b/packages/Main/src/Parser/VectorTileParser.js index 3b7c921ec3..1a26db31ab 100644 --- a/packages/Main/src/Parser/VectorTileParser.js +++ b/packages/Main/src/Parser/VectorTileParser.js @@ -140,23 +140,36 @@ function readPBF(file, options) { collection.position.set(vFeature0.extent * x + center, vFeature0.extent * y + center, 0).multiply(collection.scale); collection.updateMatrixWorld(); + let styleLayers = options.in.layers; + if (!styleLayers) { + styleLayers = {}; + vtLayerNames.forEach((vtLayerName, i) => { + styleLayers[vtLayerName] = [{ + id: vtLayerName, + order: i, + filterExpression: { filter: () => true }, + }]; + }); + } + vtLayerNames.forEach((vtLayerName) => { - if (!options.in.layers[vtLayerName]) { return Promise.resolve(collection); } + if (!styleLayers[vtLayerName]) { return; } const vectorTileLayer = vectorTile.layers[vtLayerName]; for (let i = vectorTileLayer.length - 1; i >= 0; i--) { const vtFeature = vectorTileLayer.feature(i); vtFeature.tileNumbers = { x, y: options.extent.row, z }; + // Find layers where this vtFeature is used - const layers = options.in.layers[vtLayerName] + const layers = styleLayers[vtLayerName] .filter(l => l.filterExpression.filter({ zoom: z }, vtFeature)); for (const layer of layers) { const feature = collection.requestFeatureById(layer.id, vtFeature.type - 1); feature.id = layer.id; feature.order = layer.order; - feature.style = options.in.styles[feature.id]; + feature.style = options.in.styles?.[feature.id]; vtFeatureToFeatureGeometry(vtFeature, feature); } diff --git a/packages/Main/src/Process/LayeredMaterialNodeProcessing.js b/packages/Main/src/Process/LayeredMaterialNodeProcessing.js index 0b8a87c76f..a7684c8a43 100644 --- a/packages/Main/src/Process/LayeredMaterialNodeProcessing.js +++ b/packages/Main/src/Process/LayeredMaterialNodeProcessing.js @@ -144,20 +144,24 @@ export function updateLayeredMaterialNodeImagery(context, layer, node, parent) { node.layerUpdateState[layer.id].newTry(); const command = buildCommand(context.view, layer, extentsSource, extentsDestination, node); - return context.scheduler.execute(command).then( - (results) => { - // Does nothing if the layer has been removed while command was being or waiting to be executed - if (!node.layerUpdateState[layer.id]) { - return; - } - const textures = results.map((texture, index) => (texture != null ? texture : - { isTexture: false, extent: extentsDestination[index] })); - // TODO: Handle error : result is undefined in provider. throw error - const pitchs = computePitchs(textures, extentsDestination); - nodeLayer.setTextures(textures, pitchs); - node.layerUpdateState[layer.id].success(); - }, - err => handlingError(err, node, layer, targetLevel, context.view)); + return context.scheduler.execute(command) + .then( + (results) => { + // Does nothing if the layer has been removed while command was being or waiting to be executed + if (!node.layerUpdateState[layer.id]) { + return; + } + const textures = results.map((texture, index) => (texture != null ? texture : + { isTexture: false, extent: extentsDestination[index] })); + + // TODO: Handle error : result is undefined in provider. throw error + const pitchs = computePitchs(textures, extentsDestination); + nodeLayer.setTextures(textures, pitchs); + node.layerUpdateState[layer.id].success(); + }) + .catch((err) => { + handlingError(err, node, layer, targetLevel, context.view); + }); } export function updateLayeredMaterialNodeElevation(context, layer, node, parent) { diff --git a/packages/Main/src/Provider/DataSourceProvider.js b/packages/Main/src/Provider/DataSourceProvider.js index 3f5a734cfb..399c8e6666 100644 --- a/packages/Main/src/Provider/DataSourceProvider.js +++ b/packages/Main/src/Provider/DataSourceProvider.js @@ -13,7 +13,9 @@ export default { const anyFulfilledPromise = results.find(promise => promise.status === 'fulfilled'); if (!anyFulfilledPromise) { // All promises failed -> reject - return Promise.reject(new Error('Failed to load any data')); + + const err = new AggregateError(results.map(r => r.reason), 'Failed to load any data'); + return Promise.reject(err); } return results.map(prom => (prom.value ? prom.value : null)); }); diff --git a/packages/Main/src/Provider/Fetcher.js b/packages/Main/src/Provider/Fetcher.js index d07c8ff2c9..7fb98120f4 100644 --- a/packages/Main/src/Provider/Fetcher.js +++ b/packages/Main/src/Provider/Fetcher.js @@ -8,7 +8,8 @@ const textureLoader = new TextureLoader(); function checkResponse(response) { if (!response.ok) { - const error = new Error(`Error loading ${response.url}: status ${response.status}`); + const error = new Error(response.url, { cause: `status ${response.status}` }); + error.name = 'FetchError'; error.response = response; throw error; } diff --git a/packages/Main/src/Renderer/LayeredMaterial.ts b/packages/Main/src/Renderer/LayeredMaterial.ts index 90118412b9..58cc3938ef 100644 --- a/packages/Main/src/Renderer/LayeredMaterial.ts +++ b/packages/Main/src/Renderer/LayeredMaterial.ts @@ -108,6 +108,7 @@ function updateLayersUniformsForType( let count = 0; let width = 0; let height = 0; + let setSize = false; // Determine total count of textures and dimensions // (assuming all textures are same size) @@ -125,7 +126,7 @@ function updateLayersUniformsForType( ++i, ++count ) { const texture = tile.textures[i]; - if (!texture) { continue; } + if (!texture.isTexture) { continue; } textureSetId += `${texture.id}.`; uOffsetScales[count] = tile.offsetScales[i]; @@ -135,14 +136,13 @@ function updateLayersUniformsForType( if (!img || img.width <= 0 || img.height <= 0) { console.error('Texture image not loaded or has zero dimensions'); uTextureCount.value = 0; - return; - } else if (count == 0) { + } else if (setSize === false) { width = img.width; height = img.height; + setSize = true; } else if (width !== img.width || height !== img.height) { console.error('Texture dimensions mismatch'); uTextureCount.value = 0; - return; } } } diff --git a/packages/Main/src/Renderer/WebGLComposer.ts b/packages/Main/src/Renderer/WebGLComposer.ts index e4275901f6..62f5de1381 100644 --- a/packages/Main/src/Renderer/WebGLComposer.ts +++ b/packages/Main/src/Renderer/WebGLComposer.ts @@ -76,6 +76,9 @@ export function makeDataArrayRenderTarget( // loop through each tile and its textures // to render them into DataArrayTexture layers let currentLayerIndex = 0; + + let setTexture = false; + for (const tile of tiles) { for ( let i = 0; @@ -83,13 +86,13 @@ export function makeDataArrayRenderTarget( ++i, ++currentLayerIndex ) { const texture = tile.textures[i]; - if (!texture) { continue; } + if (!texture.isTexture) { continue; } // Set the current source 2D texture on the quad's material (material as THREE.ShaderMaterial).uniforms.sourceTexture.value = texture; - if (!currentLayerIndex) { - // Set parameters from the first found texture + if (!setTexture) { + // Set parameters from the first valid texture arrayTexture.magFilter = texture.magFilter; arrayTexture.minFilter = texture.minFilter; arrayTexture.wrapS = texture.wrapS; @@ -99,6 +102,7 @@ export function makeDataArrayRenderTarget( arrayTexture.internalFormat = texture.internalFormat; arrayTexture.anisotropy = texture.anisotropy; arrayTexture.premultiplyAlpha = texture.premultiplyAlpha; + setTexture = true; } // render this source texture into the current layer diff --git a/packages/Main/src/Source/Source.js b/packages/Main/src/Source/Source.js index 3a156c3193..06ccc62298 100644 --- a/packages/Main/src/Source/Source.js +++ b/packages/Main/src/Source/Source.js @@ -118,6 +118,7 @@ class Source { } handlingError(err) { + if (Error.isError(err)) { throw err; } throw new Error(err); } diff --git a/packages/Main/test/unit/layeredmaterial.js b/packages/Main/test/unit/layeredmaterial.js index 06e54f6f20..16a1e7ef02 100644 --- a/packages/Main/test/unit/layeredmaterial.js +++ b/packages/Main/test/unit/layeredmaterial.js @@ -70,12 +70,12 @@ describe('material state vs layer state', function () { layer.visible = false; node.material.layersNeedUpdate = true; - node.onBeforeRender(); + node.onBeforeRender(renderer); assert.equal(material.uniforms.colorLayers.value[0].id, undefined); layer.visible = true; node.material.layersNeedUpdate = true; - node.onBeforeRender(); + node.onBeforeRender(renderer); assert.equal(material.uniforms.colorLayers.value[0].id, layer.id); assert.equal(material.uniforms.colorLayers.value[0].opacity, layer.opacity); });