From bb4928c72f455710c186d7f5b5273e7861d1083c Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Sun, 14 Aug 2022 20:34:54 +0200 Subject: [PATCH] Improvements to tile-loading and other fixes --- src/MapViewer.js | 6 +++++- src/controls/ControlsManager.js | 5 ++++- src/map/LowresTileLoader.js | 17 ++++++++++++----- src/map/Map.js | 8 +++++--- src/map/Tile.js | 2 +- src/map/TileLoader.js | 20 +++++++++++++------- src/map/TileManager.js | 12 +++++++++--- src/map/lowres/LowresFragmentShader.js | 2 +- 8 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/MapViewer.js b/src/MapViewer.js index 7776d49..5ad4287 100644 --- a/src/MapViewer.js +++ b/src/MapViewer.js @@ -369,7 +369,11 @@ export class MapViewer { updateLoadedMapArea = () => { if (!this.map) return; - this.map.loadMapArea(this.data.loadedCenter.x, this.data.loadedCenter.y, this.data.loadedHiresViewDistance, this.data.loadedLowresViewDistance); + if (this.controlsManager.distance < 1000) { + this.map.loadMapArea(this.data.loadedCenter.x, this.data.loadedCenter.y, this.data.loadedHiresViewDistance, this.data.loadedLowresViewDistance); + } else { + this.map.loadMapArea(this.data.loadedCenter.x, this.data.loadedCenter.y, 0, this.data.loadedLowresViewDistance); + } } clearTileCache(newTileCacheHash) { diff --git a/src/controls/ControlsManager.js b/src/controls/ControlsManager.js index b608aae..138c250 100644 --- a/src/controls/ControlsManager.js +++ b/src/controls/ControlsManager.js @@ -58,6 +58,7 @@ export class ControlsManager { this.lastTilt = this.tilt; this.lastMapUpdatePosition = this.position.clone(); + this.lastMapUpdateDistance = this.distance; this.averageDeltaTime = 16; @@ -156,9 +157,11 @@ export class ControlsManager { if ( Math.abs(this.lastMapUpdatePosition.x - this.position.x) >= triggerDistance || - Math.abs(this.lastMapUpdatePosition.z - this.position.z) >= triggerDistance + Math.abs(this.lastMapUpdatePosition.z - this.position.z) >= triggerDistance || + (this.distance < 1000 && this.lastMapUpdateDistance > 1000) ) { this.lastMapUpdatePosition = this.position.clone(); + this.lastMapUpdateDistance = this.distance; this.mapViewer.loadMapArea(this.position.x, this.position.z); } } diff --git a/src/map/LowresTileLoader.js b/src/map/LowresTileLoader.js index 20b4398..c14d261 100644 --- a/src/map/LowresTileLoader.js +++ b/src/map/LowresTileLoader.js @@ -38,13 +38,13 @@ import { export class LowresTileLoader { - constructor(tilePath, tileSettings, lod, vertexShader, fragmentShader, uniforms, tileCacheHash = 0, layer = 0) { + constructor(tilePath, tileSettings, lod, vertexShader, fragmentShader, uniforms, loadBlocker = () => Promise.resolve(), tileCacheHash = 0) { Object.defineProperty( this, 'isLowresTileLoader', { value: true } ); this.tilePath = tilePath; this.tileSettings = tileSettings; this.lod = lod; - this.layer = layer; + this.loadBlocker = loadBlocker; this.tileCacheHash = tileCacheHash; this.vertexShader = vertexShader; @@ -62,12 +62,13 @@ export class LowresTileLoader { this.geometry.translate(tileSettings.tileSize.x / 2 + 1, 0, tileSettings.tileSize.x / 2 + 1); } - load = (tileX, tileZ) => { + load = (tileX, tileZ, cancelCheck = () => false) => { let tileUrl = this.tilePath + this.lod + "/" + pathFromCoords(tileX, tileZ) + '.png'; + //await this.loadBlocker(); return new Promise((resolve, reject) => { this.textureLoader.load(tileUrl + '?' + this.tileCacheHash, - texture => { + async texture => { texture.anisotropy = 1; texture.generateMipmaps = false; texture.magFilter = NearestFilter; @@ -77,6 +78,13 @@ export class LowresTileLoader { texture.flipY = false; texture.flatShading = true; + await this.loadBlocker(); + if (cancelCheck()){ + texture.dispose(); + reject({status: "cancelled"}); + return; + } + let material = new ShaderMaterial({ uniforms: { ...this.uniforms, @@ -102,7 +110,6 @@ export class LowresTileLoader { }); let object = new Mesh(this.geometry, material); - if (this.layer) object.layers.set(this.layer); const scale = Math.pow(this.tileSettings.lodFactor, this.lod - 1); object.position.set(tileX * this.tileSettings.tileSize.x * scale, 0, tileZ * this.tileSettings.tileSize.z * scale); diff --git a/src/map/Map.js b/src/map/Map.js index c51c75b..43f4372 100644 --- a/src/map/Map.js +++ b/src/map/Map.js @@ -46,11 +46,13 @@ export class Map { /** * @param id {string} * @param dataUrl {string} + * @param loadBlocker {function: Promise} * @param events {EventTarget} */ - constructor(id, dataUrl, events = null) { + constructor(id, dataUrl, loadBlocker, events = null) { Object.defineProperty( this, 'isMap', { value: true } ); + this.loadBlocker = loadBlocker; this.events = events; this.data = { @@ -115,12 +117,12 @@ export class Map { this.hiresMaterial = this.createHiresMaterial(hiresVertexShader, hiresFragmentShader, uniforms, textures); - this.hiresTileManager = new TileManager(new Scene(), new TileLoader(`${this.data.dataUrl}tiles/0/`, this.hiresMaterial, this.data.hires, tileCacheHash), this.onTileLoad("hires"), this.onTileUnload("hires"), this.events); + this.hiresTileManager = new TileManager(new Scene(), new TileLoader(`${this.data.dataUrl}tiles/0/`, this.hiresMaterial, this.data.hires, this.loadBlocker, tileCacheHash), this.onTileLoad("hires"), this.onTileUnload("hires"), this.events); this.hiresTileManager.scene.autoUpdate = false; this.lowresTileManager = []; for (let i = 0; i < this.data.lowres.lodCount; i++) { - this.lowresTileManager[i] = new TileManager(new Scene(), new LowresTileLoader(`${this.data.dataUrl}tiles/`, this.data.lowres, i + 1, lowresVertexShader, lowresFragmentShader, uniforms, tileCacheHash), this.onTileLoad("lowres"), this.onTileUnload("lowres"), this.events); + this.lowresTileManager[i] = new TileManager(new Scene(), new LowresTileLoader(`${this.data.dataUrl}tiles/`, this.data.lowres, i + 1, lowresVertexShader, lowresFragmentShader, uniforms, async () => {}, tileCacheHash), this.onTileLoad("lowres"), this.onTileUnload("lowres"), this.events); this.lowresTileManager[i].scene.autoUpdate = false; } diff --git a/src/map/Tile.js b/src/map/Tile.js index 239c46b..a771431 100644 --- a/src/map/Tile.js +++ b/src/map/Tile.js @@ -57,7 +57,7 @@ export class Tile { this.unload(); this.unloaded = false; - return tileLoader.load(this.x, this.z) + return tileLoader.load(this.x, this.z, () => this.unloaded) .then(model => { if (this.unloaded){ Tile.disposeModel(model); diff --git a/src/map/TileLoader.js b/src/map/TileLoader.js index a2f961f..8d2b756 100644 --- a/src/map/TileLoader.js +++ b/src/map/TileLoader.js @@ -35,42 +35,48 @@ export class TileLoader { * scale: {x: number, z: number}, * translate: {x: number, z: number} * }} + * @param loadBlocker {function: Promise} * @param tileCacheHash {number} - * @param layer {number} */ - constructor(tilePath, material, tileSettings, tileCacheHash = 0, layer = 0) { + constructor(tilePath, material, tileSettings, loadBlocker = () => Promise.resolve(), tileCacheHash = 0) { Object.defineProperty( this, 'isTileLoader', { value: true } ); this.tilePath = tilePath; this.material = material; this.tileSettings = tileSettings; - this.layer = layer; - this.tileCacheHash = tileCacheHash; + this.loadBlocker = loadBlocker; + this.fileLoader = new FileLoader(); this.fileLoader.setResponseType('json'); this.bufferGeometryLoader = new BufferGeometryLoader(); } - load = (tileX, tileZ) => { + load = (tileX, tileZ, cancelCheck = () => false) => { let tileUrl = this.tilePath + pathFromCoords(tileX, tileZ) + '.json'; + //await this.loadBlocker(); return new Promise((resolve, reject) => { this.fileLoader.load(tileUrl + '?' + this.tileCacheHash, - json => { + async json => { let geometryJson = json.tileGeometry || {}; if (!geometryJson.type || geometryJson.type !== 'BufferGeometry'){ reject({status: "empty"}); return; } + await this.loadBlocker(); + if (cancelCheck()){ + reject({status: "cancelled"}); + return; + } + let geometry = this.bufferGeometryLoader.parse(geometryJson); let object = new Mesh(geometry, this.material); - if (this.layer) object.layers.set(this.layer); let tileSize = this.tileSettings.tileSize; let translate = this.tileSettings.translate; diff --git a/src/map/TileManager.js b/src/map/TileManager.js index 3f6d76a..d9c7fe3 100644 --- a/src/map/TileManager.js +++ b/src/map/TileManager.js @@ -82,13 +82,18 @@ export class TileManager { this.viewDistanceX = viewDistanceX; this.viewDistanceZ = viewDistanceZ; + if (viewDistanceX <= 0 || viewDistanceZ <= 0) { + this.removeAllTiles(); + return; + } + if (unloadTiles || this.centerTile.x !== x || this.centerTile.y !== z) { this.centerTile.set(x, z); this.removeFarTiles(); this.tileMap.setAll(TileMap.EMPTY); this.tiles.forEach(tile => { - if (!tile.loading) { + if (!tile.loading && !tile.unloaded) { this.tileMap.setTile(tile.x - this.centerTile.x + TileManager.tileMapHalfSize, tile.z - this.centerTile.y + TileManager.tileMapHalfSize, TileMap.LOADED); } }); @@ -187,7 +192,8 @@ export class TileManager { this.tiles.set(tileHash, tile); tile.load(this.tileLoader) .then(() => { - this.tileMap.setTile(tile.x - this.centerTile.x + TileManager.tileMapHalfSize, tile.z - this.centerTile.y + TileManager.tileMapHalfSize, TileMap.LOADED); + if (!tile.unloaded) + this.tileMap.setTile(tile.x - this.centerTile.x + TileManager.tileMapHalfSize, tile.z - this.centerTile.y + TileManager.tileMapHalfSize, TileMap.LOADED); if (this.loadTimeout) clearTimeout(this.loadTimeout); this.loadTimeout = setTimeout(this.loadCloseTiles, 0); @@ -200,7 +206,7 @@ export class TileManager { //alert(this.events, "Failed to load tile: " + error.type, "warning"); }) .finally(() => { - this.tileMap.setTile(tile.x - this.centerTile.x + TileManager.tileMapHalfSize, tile.z - this.centerTile.y + TileManager.tileMapHalfSize, TileMap.LOADED); + //this.tileMap.setTile(tile.x - this.centerTile.x + TileManager.tileMapHalfSize, tile.z - this.centerTile.y + TileManager.tileMapHalfSize, TileMap.LOADED); this.currentlyLoading--; }); diff --git a/src/map/lowres/LowresFragmentShader.js b/src/map/lowres/LowresFragmentShader.js index 76c4c57..af31043 100644 --- a/src/map/lowres/LowresFragmentShader.js +++ b/src/map/lowres/LowresFragmentShader.js @@ -73,7 +73,7 @@ vec2 posToMetaUV(vec2 pos) { void main() { //discard if hires tile is loaded at that position - //if (vDistance < 900.0 && texture(hiresTileMap.map, ((vWorldPosition.xz - hiresTileMap.translate) / hiresTileMap.scale - hiresTileMap.pos) / hiresTileMap.size + 0.5).r > 0.75) discard; + if (vDistance < 900.0 && texture(hiresTileMap.map, ((vWorldPosition.xz - hiresTileMap.translate) / hiresTileMap.scale - hiresTileMap.pos) / hiresTileMap.size + 0.5).r > 0.75) discard; vec4 color = texture(textureImage, posToColorUV(vPosition.xz)); vec4 meta = texture(textureImage, posToMetaUV(vPosition.xz));