From eda14d3c3232d3bbf78e16b6a351ccdb4205c1d5 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Thu, 25 Feb 2021 22:53:42 +0100 Subject: [PATCH] Move lots of data to deticated data fields and more tweaks The data fields now contain and syncronize all the data that might be important for libraries like VueJS. They can safely be made reactive without fear to make the whole ThreeJS object-stack reactive (which would blow up the ram usage and destroy performance) --- package-lock.json | 3 +- public/index.html | 6 +- src/MapViewer.js | 138 +++++++++++++++++--------- src/controls/ControlsManager.js | 118 +++++++++++++++++++--- src/controls/map/MapHeightControls.js | 10 +- src/map/Map.js | 117 +++++++++++----------- src/markers/ExtrudeMarker.js | 2 +- src/markers/HtmlMarker.js | 4 +- src/markers/LineMarker.js | 2 +- src/markers/Marker.js | 14 ++- src/markers/MarkerFileManager.js | 2 +- src/markers/MarkerManager.js | 12 +-- src/markers/MarkerSet.js | 49 +++++++-- src/markers/ObjectMarker.js | 16 +-- src/markers/PlayerMarker.js | 4 +- src/markers/PoiMarker.js | 15 ++- src/markers/ShapeMarker.js | 2 +- src/skybox/SkyFragmentShader.js | 4 +- src/skybox/SkyboxScene.js | 66 +----------- src/util/CombinedCamera.js | 65 +++++++++++- 20 files changed, 414 insertions(+), 235 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0760d72..12956a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,8 @@ { "name": "bluemap", - "requires": true, + "version": "0.1.0", "lockfileVersion": 1, + "requires": true, "dependencies": { "@babel/code-frame": { "version": "7.10.4", diff --git a/public/index.html b/public/index.html index 518913f..aa441c2 100644 --- a/public/index.html +++ b/public/index.html @@ -68,16 +68,16 @@ loadMaps("data/", bluemap.events).then(loadedMaps => { maps = loadedMaps; - markerManager = new BlueMap.MarkerFileManager(bluemap.markerScene, "data/markers.json", maps[0].id, bluemap.events); + markerManager = new BlueMap.MarkerFileManager(bluemap.markers, "data/markers.json", maps[0].data.id, bluemap.events); markerManager.update(); markerManager.setAutoUpdateInterval(1000 * 10); - playerManager = new BlueMap.PlayerMarkerManager(bluemap.markerScene, "live/players", "", bluemap.events); + playerManager = new BlueMap.PlayerMarkerManager(bluemap.markers, "live/players", "", bluemap.events); playerManager.update(); playerManager.setAutoUpdateInterval(1000); bluemap.switchMap(maps[0]).then(() => { - playerManager.worldId = maps[0].world; + playerManager.worldId = maps[0].data.world; }); }); diff --git a/src/MapViewer.js b/src/MapViewer.js index ec403c7..f69cecd 100644 --- a/src/MapViewer.js +++ b/src/MapViewer.js @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -import {PerspectiveCamera, Raycaster, Scene, Vector2, WebGLRenderer} from "three"; +import {Color, PerspectiveCamera, Raycaster, Scene, Vector2, Vector3, WebGLRenderer} from "three"; import {Map} from "./map/Map"; import {SkyboxScene} from "./skybox/SkyboxScene"; import {ControlsManager} from "./controls/ControlsManager"; @@ -35,6 +35,7 @@ import {LOWRES_VERTEX_SHADER} from "./map/lowres/LowresVertexShader"; import {LOWRES_FRAGMENT_SHADER} from "./map/lowres/LowresFragmentShader"; import {CombinedCamera} from "./util/CombinedCamera"; import {CSS2DRenderer} from "./util/CSS2DRenderer"; +import {MarkerSet} from "./markers/MarkerSet"; export class MapViewer { @@ -48,29 +49,33 @@ export class MapViewer { this.rootElement = element; this.events = events; + this.data = { + map: null, + camera: null, + controlsManager: null, + uniforms: { + sunlightStrength: { value: 1 }, + ambientLight: { value: 0 }, + skyColor: { value: new Color(0.5, 0.5, 1) }, + hiresTileMap: { + value: { + map: null, + size: TileManager.tileMapSize, + scale: new Vector2(1, 1), + translate: new Vector2(), + pos: new Vector2(), + } + } + }, + superSampling: 1, + loadedCenter: new Vector2(0, 0), + loadedHiresViewDistance: 200, + loadedLowresViewDistance: 2000, + } + this.stats = new Stats(); this.stats.hide(); - this.superSamplingValue = 1; - this.loadedCenter = new Vector2(0, 0); - this.loadedHiresViewDistance = 200; - this.loadedLowresViewDistance = 2000; - - // uniforms - this.uniforms = { - sunlightStrength: { value: 1 }, - ambientLight: { value: 0 }, - hiresTileMap: { - value: { - map: null, - size: TileManager.tileMapSize, - scale: new Vector2(1, 1), - translate: new Vector2(), - pos: new Vector2(), - } - } - }; - // renderer this.renderer = new WebGLRenderer({ antialias: true, @@ -79,12 +84,12 @@ export class MapViewer { logarithmicDepthBuffer: true, }); this.renderer.autoClear = false; - this.renderer.uniforms = this.uniforms; + this.renderer.uniforms = this.data.uniforms; // CSS2D renderer this.css2dRenderer = new CSS2DRenderer(); - this.skyboxScene = new SkyboxScene(); + this.skyboxScene = new SkyboxScene(this.data.uniforms); this.camera = new CombinedCamera(75, 1, 0.1, 10000, 0); this.skyboxCamera = new PerspectiveCamera(75, 1, 0.1, 10000); @@ -98,7 +103,7 @@ export class MapViewer { /** @type {Map} */ this.map = null; - this.markerScene = new Scene(); + this.markers = new MarkerSet("bm-root"); this.lastFrame = 0; @@ -142,7 +147,7 @@ export class MapViewer { */ handleContainerResize = () => { this.renderer.setSize(this.rootElement.clientWidth, this.rootElement.clientHeight); - this.renderer.setPixelRatio(window.devicePixelRatio * this.superSamplingValue); + this.renderer.setPixelRatio(window.devicePixelRatio * this.superSampling); this.css2dRenderer.setSize(this.rootElement.clientWidth, this.rootElement.clientHeight); @@ -170,7 +175,7 @@ export class MapViewer { this.raycaster.setFromCamera(normalizedScreenPos, this.camera); // check Object3D interactions - let intersects = this.raycaster.intersectObjects([this.map.hiresTileManager.scene, this.map.lowresTileManager.scene, this.markerScene], true); + let intersects = this.raycaster.intersectObjects([this.map.hiresTileManager.scene, this.map.lowresTileManager.scene, this.markers], true); let covered = false; for (let i = 0; i < intersects.length; i++) { if (intersects[i].object){ @@ -252,7 +257,7 @@ export class MapViewer { if (this.map && this.map.isLoaded) { //update uniforms - this.uniforms.hiresTileMap.value.pos.copy(this.map.hiresTileManager.centerTile); + this.data.uniforms.hiresTileMap.value.pos.copy(this.map.hiresTileManager.centerTile); this.renderer.render(this.map.lowresTileManager.scene, this.camera); this.renderer.clearDepth(); @@ -263,8 +268,8 @@ export class MapViewer { } // render markers - this.renderer.render(this.markerScene, this.camera); - this.css2dRenderer.render(this.markerScene, this.camera); + this.renderer.render(this.markers, this.camera); + this.css2dRenderer.render(this.markers, this.camera); } /** @@ -278,15 +283,13 @@ export class MapViewer { this.map = map; if (this.map && this.map.isMap) { - return map.load(HIRES_VERTEX_SHADER, HIRES_FRAGMENT_SHADER, LOWRES_VERTEX_SHADER, LOWRES_FRAGMENT_SHADER, this.uniforms) + return map.load(HIRES_VERTEX_SHADER, HIRES_FRAGMENT_SHADER, LOWRES_VERTEX_SHADER, LOWRES_FRAGMENT_SHADER, this.data.uniforms) .then(() => { - this.skyboxScene.ambientLight = map.ambientLight; - this.skyboxScene.skyColor = map.skyColor; - - this.uniforms.ambientLight.value = map.ambientLight; - this.uniforms.hiresTileMap.value.map = map.hiresTileManager.tileMap.texture; - this.uniforms.hiresTileMap.value.scale.set(map.hires.tileSize.x, map.hires.tileSize.z); - this.uniforms.hiresTileMap.value.translate.set(map.hires.translate.x, map.hires.translate.z); + this.data.uniforms.skyColor.value = map.data.skyColor; + this.data.uniforms.ambientLight.value = map.data.ambientLight; + this.data.uniforms.hiresTileMap.value.map = map.hiresTileManager.tileMap.texture; + this.data.uniforms.hiresTileMap.value.scale.set(map.data.hires.tileSize.x, map.data.hires.tileSize.z); + this.data.uniforms.hiresTileMap.value.translate.set(map.data.hires.translate.x, map.data.hires.translate.z); setTimeout(this.updateLoadedMapArea); @@ -306,13 +309,13 @@ export class MapViewer { * Loads the given area on the map (and unloads everything outside that area) * @param centerX {number} * @param centerZ {number} - * @param hiresViewDistance {number} - * @param lowresViewDistance {number} + * @param hiresViewDistance {number?} + * @param lowresViewDistance {number?} */ loadMapArea(centerX, centerZ, hiresViewDistance = -1, lowresViewDistance = -1) { - this.loadedCenter.set(centerX, centerZ); - if (hiresViewDistance >= 0) this.loadedHiresViewDistance = hiresViewDistance; - if (lowresViewDistance >= 0) this.loadedLowresViewDistance = lowresViewDistance; + this.data.loadedCenter.set(centerX, centerZ); + if (hiresViewDistance >= 0) this.data.loadedHiresViewDistance = hiresViewDistance; + if (lowresViewDistance >= 0) this.data.loadedLowresViewDistance = lowresViewDistance; this.updateLoadedMapArea(); } @@ -322,22 +325,67 @@ export class MapViewer { */ updateLoadedMapArea = () => { if (!this.map) return; - this.map.loadMapArea(this.loadedCenter.x, this.loadedCenter.y, this.loadedHiresViewDistance, this.loadedLowresViewDistance); + this.map.loadMapArea(this.data.loadedCenter.x, this.data.loadedCenter.y, this.data.loadedHiresViewDistance, this.data.loadedLowresViewDistance); } /** * @returns {number} */ get superSampling() { - return this.superSamplingValue; + return this.data.superSampling; } /** * @param value {number} */ set superSampling(value) { - this.superSamplingValue = value; + this.data.superSampling = value; this.handleContainerResize(); } + /** + * @returns {CombinedCamera} + */ + get camera() { + return this._camera; + } + + /** + * @param value {CombinedCamera} + */ + set camera(value) { + this._camera = value; + this.data.camera = value.data; + } + + /** + * @returns {ControlsManager} + */ + get controlsManager() { + return this._controlsManager; + } + + /** + * @param value {ControlsManager} + */ + set controlsManager(value) { + this._controlsManager = value; + this.data.controlsManager = value.data; + } + + /** + * @returns {Map} + */ + get map() { + return this._map; + } + + /** + * @param value {Map} + */ + set map(value) { + this._map = value; + if (value) this.data.map = value.data; + } + } diff --git a/src/controls/ControlsManager.js b/src/controls/ControlsManager.js index d2be6e2..71869fd 100644 --- a/src/controls/ControlsManager.js +++ b/src/controls/ControlsManager.js @@ -36,14 +36,20 @@ export class ControlsManager { constructor(mapViewer, camera) { Object.defineProperty( this, 'isControlsManager', { value: true } ); + this.data = { + mapViewer: null, + camera: null, + controls: null, + position: new Vector3(0, 0, 0), + rotation: 0, + angle: 0, + tilt: 0, + }; + this.mapViewer = mapViewer; this.camera = camera; - this.position = new Vector3(0, 0, 0); - this.rotation = 0; - this.angle = 0; - this.tilt = 0; - + /** @type {Vector3} */ this.lastPosition = this.position.clone(); this.lastRotation = this.rotation; this.lastAngle = this.angle; @@ -164,22 +170,22 @@ export class ControlsManager { isValueChanged() { return !( - this.position.equals(this.lastPosition) && - this.rotation === this.lastRotation && - this.angle === this.lastAngle && + this.data.position.equals(this.lastPosition) && + this.data.rotation === this.lastRotation && + this.data.angle === this.lastAngle && this.distance === this.lastDistance && this.ortho === this.lastOrtho && - this.tilt === this.lastTilt + this.data.tilt === this.lastTilt ); } resetValueChanged() { - this.lastPosition.copy(this.position); - this.lastRotation = this.rotation; - this.lastAngle = this.angle; + this.lastPosition.copy(this.data.position); + this.lastRotation = this.data.rotation; + this.lastAngle = this.data.angle; this.lastDistance = this.distance; this.lastOrtho = this.ortho; - this.lastTilt = this.tilt; + this.lastTilt = this.data.tilt; } /** @@ -218,6 +224,7 @@ export class ControlsManager { this._controls.stop(); this._controls = controls; + if (controls) this.data.controls = controls.data || null if (this._controls && this._controls.start) this._controls.start(this); @@ -230,4 +237,89 @@ export class ControlsManager { return this._controls; } + /** + * @returns {MapViewer} + */ + get mapViewer() { + return this._mapViewer; + } + + /** + * @param value {MapViewer} + */ + set mapViewer(value) { + this._mapViewer = value; + this.data.mapViewer = value.data; + } + + /** + * @returns {CombinedCamera} + */ + get camera() { + return this._camera; + } + + /** + * @param value {CombinedCamera} + */ + set camera(value) { + this._camera = value; + this.data.camera = value.data; + } + + /** + * @returns {Vector3} + */ + get position() { + return this.data.position; + } + + /** + * @param value {Vector3} + */ + set position(value) { + this.data.position = value; + } + + /** + * @returns {number} + */ + get rotation() { + return this.data.rotation; + } + + /** + * @param value {number} + */ + set rotation(value) { + this.data.rotation = value; + } + + /** + * @returns {number} + */ + get angle() { + return this.data.angle; + } + + /** + * @param value {number} + */ + set angle(value) { + this.data.angle = value; + } + + /** + * @returns {number} + */ + get tilt() { + return this.data.tilt; + } + + /** + * @param value {number} + */ + set tilt(value) { + this.data.tilt = value; + } } \ No newline at end of file diff --git a/src/controls/map/MapHeightControls.js b/src/controls/map/MapHeightControls.js index 956d80a..9a36a37 100644 --- a/src/controls/map/MapHeightControls.js +++ b/src/controls/map/MapHeightControls.js @@ -41,9 +41,6 @@ export class MapHeightControls { this.targetHeight = 0; this.cameraHeight = 0; - this.lastTarget = new Vector2(); - this.lastTargetTerrainHeight = 0; - this.minCameraHeight = 0; this.distanceTagretHeight = 0; } @@ -73,12 +70,7 @@ export class MapHeightControls { let targetSmoothing = this.targetHeightStiffness / (16.666 / delta); targetSmoothing = MathUtils.clamp(targetSmoothing, 0, 1); - let targetTerrainHeight = this.lastTargetTerrainHeight; - if (this.lastTarget.x !== this.manager.position.x || this.lastTarget.y !== this.manager.position.z){ - targetTerrainHeight = map.terrainHeightAt(this.manager.position.x, this.manager.position.z) || 0; - this.lastTargetTerrainHeight = targetTerrainHeight; - this.lastTarget.set(this.manager.position.x, this.manager.position.z); - } + let targetTerrainHeight = map.terrainHeightAt(this.manager.position.x, this.manager.position.z) + 3 || 0; let targetDelta = targetTerrainHeight - this.targetHeight; this.targetHeight += targetDelta * targetSmoothing; diff --git a/src/map/Map.js b/src/map/Map.js index 40805c2..c807afd 100644 --- a/src/map/Map.js +++ b/src/map/Map.js @@ -45,29 +45,28 @@ export class Map { constructor(id, dataUrl, settingsUrl, texturesUrl, events = null) { Object.defineProperty( this, 'isMap', { value: true } ); - this.id = id; this.events = events; - this.dataUrl = dataUrl; - this.settingsUrl = settingsUrl; - this.texturesUrl = texturesUrl; - - this.name = this.id; - this.world = "-"; - - this.startPos = {x: 0, z: 0}; - this.skyColor = new Color(); - this.ambientLight = 0; - - this.hires = { - tileSize: {x: 32, z: 32}, - scale: {x: 1, z: 1}, - translate: {x: 2, z: 2} - }; - this.lowres = { - tileSize: {x: 32, z: 32}, - scale: {x: 1, z: 1}, - translate: {x: 2, z: 2} + this.data = { + id: id, + dataUrl: dataUrl, + settingsUrl: settingsUrl, + texturesUrl: texturesUrl, + name: id, + world: "-", + startPos: {x: 0, z: 0}, + skyColor: new Color(), + ambientLight: 0, + hires: { + tileSize: {x: 32, z: 32}, + scale: {x: 1, z: 1}, + translate: {x: 2, z: 2} + }, + lowres: { + tileSize: {x: 32, z: 32}, + scale: {x: 1, z: 1}, + translate: {x: 2, z: 2} + } }; this.raycaster = new Raycaster(); @@ -104,29 +103,29 @@ export class Map { let settingsPromise = settingsFilePromise .then(worldSettings => { - this.name = worldSettings.name ? worldSettings.name : this.name; - this.world = worldSettings.world ? worldSettings.world : this.world; + this.data.name = worldSettings.name ? worldSettings.name : this.data.name; + this.data.world = worldSettings.world ? worldSettings.world : this.data.world; - this.startPos = {...this.startPos, ...worldSettings.startPos}; - this.skyColor.setRGB( - worldSettings.skyColor.r || this.skyColor.r, - worldSettings.skyColor.g || this.skyColor.g, - worldSettings.skyColor.b || this.skyColor.b, + this.data.startPos = {...this.data.startPos, ...worldSettings.startPos}; + this.data.skyColor.setRGB( + worldSettings.skyColor.r || this.data.skyColor.r, + worldSettings.skyColor.g || this.data.skyColor.g, + worldSettings.skyColor.b || this.data.skyColor.b, ); - this.ambientLight = worldSettings.ambientLight ? worldSettings.ambientLight : 0; + this.data.ambientLight = worldSettings.ambientLight ? worldSettings.ambientLight : this.data.ambientLight; if (worldSettings.hires === undefined) worldSettings.hires = {}; if (worldSettings.lowres === undefined) worldSettings.lowres = {}; - this.hires = { - tileSize: {...this.hires.tileSize, ...worldSettings.hires.tileSize}, - scale: {...this.hires.scale, ...worldSettings.hires.scale}, - translate: {...this.hires.translate, ...worldSettings.hires.translate} + this.data.hires = { + tileSize: {...this.data.hires.tileSize, ...worldSettings.hires.tileSize}, + scale: {...this.data.hires.scale, ...worldSettings.hires.scale}, + translate: {...this.data.hires.translate, ...worldSettings.hires.translate} }; - this.lowres = { - tileSize: {...this.lowres.tileSize, ...worldSettings.lowres.tileSize}, - scale: {...this.lowres.scale, ...worldSettings.lowres.scale}, - translate: {...this.lowres.translate, ...worldSettings.lowres.translate} + this.data.lowres = { + tileSize: {...this.data.lowres.tileSize, ...worldSettings.lowres.tileSize}, + scale: {...this.data.lowres.scale, ...worldSettings.lowres.scale}, + translate: {...this.data.lowres.translate, ...worldSettings.lowres.translate} }; }); @@ -137,13 +136,13 @@ export class Map { this.hiresMaterial = this.createHiresMaterial(hiresVertexShader, hiresFragmentShader, uniforms, textures); - this.hiresTileManager = new TileManager(new Scene(), new TileLoader(`${this.dataUrl}hires/`, this.hiresMaterial, this.hires), this.onTileLoad("hires"), this.onTileUnload("hires"), this.events); - this.lowresTileManager = new TileManager(new Scene(), new TileLoader(`${this.dataUrl}lowres/`, this.lowresMaterial, this.lowres), this.onTileLoad("lowres"), this.onTileUnload("lowres"), this.events); + this.hiresTileManager = new TileManager(new Scene(), new TileLoader(`${this.data.dataUrl}hires/`, this.hiresMaterial, this.data.hires), this.onTileLoad("hires"), this.onTileUnload("hires"), this.events); + this.lowresTileManager = new TileManager(new Scene(), new TileLoader(`${this.data.dataUrl}lowres/`, this.lowresMaterial, this.data.lowres), this.onTileLoad("lowres"), this.onTileUnload("lowres"), this.events); this.hiresTileManager.scene.autoUpdate = false; this.lowresTileManager.scene.autoUpdate = false; - alert(this.events, `Map '${this.id}' is loaded.`, "fine"); + alert(this.events, `Map '${this.data.id}' is loaded.`, "fine"); }); } @@ -170,15 +169,15 @@ export class Map { loadMapArea(x, z, hiresViewDistance, lowresViewDistance) { if (!this.isLoaded) return; - let hiresX = Math.floor((x - this.hires.translate.x) / this.hires.tileSize.x); - let hiresZ = Math.floor((z - this.hires.translate.z) / this.hires.tileSize.z); - let hiresViewX = Math.floor(hiresViewDistance / this.hires.tileSize.x); - let hiresViewZ = Math.floor(hiresViewDistance / this.hires.tileSize.z); + let hiresX = Math.floor((x - this.data.hires.translate.x) / this.data.hires.tileSize.x); + let hiresZ = Math.floor((z - this.data.hires.translate.z) / this.data.hires.tileSize.z); + let hiresViewX = Math.floor(hiresViewDistance / this.data.hires.tileSize.x); + let hiresViewZ = Math.floor(hiresViewDistance / this.data.hires.tileSize.z); - let lowresX = Math.floor((x - this.lowres.translate.x) / this.lowres.tileSize.x); - let lowresZ = Math.floor((z - this.lowres.translate.z) / this.lowres.tileSize.z); - let lowresViewX = Math.floor(lowresViewDistance / this.lowres.tileSize.x); - let lowresViewZ = Math.floor(lowresViewDistance / this.lowres.tileSize.z); + let lowresX = Math.floor((x - this.data.lowres.translate.x) / this.data.lowres.tileSize.x); + let lowresZ = Math.floor((z - this.data.lowres.translate.z) / this.data.lowres.tileSize.z); + let lowresViewX = Math.floor(lowresViewDistance / this.data.lowres.tileSize.x); + let lowresViewZ = Math.floor(lowresViewDistance / this.data.lowres.tileSize.z); this.hiresTileManager.loadAroundTile(hiresX, hiresZ, hiresViewX, hiresViewZ); this.lowresTileManager.loadAroundTile(lowresX, lowresZ, lowresViewX, lowresViewZ); @@ -190,20 +189,20 @@ export class Map { */ loadSettingsFile() { return new Promise((resolve, reject) => { - alert(this.events, `Loading settings for map '${this.id}'...`, "fine"); + alert(this.events, `Loading settings for map '${this.data.id}'...`, "fine"); let loader = new FileLoader(); loader.setResponseType("json"); - loader.load(this.settingsUrl, + loader.load(this.data.settingsUrl, settings => { - if (settings.maps && settings.maps[this.id]) { - resolve(settings.maps[this.id]); + if (settings.maps && settings.maps[this.data.id]) { + resolve(settings.maps[this.data.id]); } else { - reject(`the settings.json does not contain informations for map: ${this.id}`); + reject(`the settings.json does not contain informations for map: ${this.data.id}`); } }, () => {}, - () => reject(`Failed to load the settings.json for map: ${this.id}`) + () => reject(`Failed to load the settings.json for map: ${this.data.id}`) ) }); } @@ -214,14 +213,14 @@ export class Map { */ loadTexturesFile() { return new Promise((resolve, reject) => { - alert(this.events, `Loading textures for map '${this.id}'...`, "fine"); + alert(this.events, `Loading textures for map '${this.data.id}'...`, "fine"); let loader = new FileLoader(); loader.setResponseType("json"); - loader.load(this.texturesUrl, + loader.load(this.data.texturesUrl, resolve, () => {}, - () => reject(`Failed to load the textures.json for map: ${this.id}`) + () => reject(`Failed to load the textures.json for map: ${this.data.id}`) ) }); } @@ -343,10 +342,10 @@ export class Map { this.raycaster.far = 300; this.raycaster.layers.enableAll(); - let hiresTileHash = hashTile(Math.floor((x - this.hires.translate.x) / this.hires.tileSize.x), Math.floor((z - this.hires.translate.z) / this.hires.tileSize.z)); + let hiresTileHash = hashTile(Math.floor((x - this.data.hires.translate.x) / this.data.hires.tileSize.x), Math.floor((z - this.data.hires.translate.z) / this.data.hires.tileSize.z)); let tile = this.hiresTileManager.tiles.get(hiresTileHash); if (!tile || !tile.model) { - let lowresTileHash = hashTile(Math.floor((x - this.lowres.translate.x) / this.lowres.tileSize.x), Math.floor((z - this.lowres.translate.z) / this.lowres.tileSize.z)); + let lowresTileHash = hashTile(Math.floor((x - this.data.lowres.translate.x) / this.data.lowres.tileSize.x), Math.floor((z - this.data.lowres.translate.z) / this.data.lowres.tileSize.z)); tile = this.lowresTileManager.tiles.get(lowresTileHash); } diff --git a/src/markers/ExtrudeMarker.js b/src/markers/ExtrudeMarker.js index d12f1b3..3f81111 100644 --- a/src/markers/ExtrudeMarker.js +++ b/src/markers/ExtrudeMarker.js @@ -39,7 +39,7 @@ export class ExtrudeMarker extends ObjectMarker { constructor(markerId) { super(markerId); Object.defineProperty(this, 'isExtrudeMarker', {value: true}); - this.markerType = "extrude"; + this.data.type = "extrude"; let zero = new Vector2(); let shape = new Shape([zero, zero, zero]); diff --git a/src/markers/HtmlMarker.js b/src/markers/HtmlMarker.js index caccca7..ae347a5 100644 --- a/src/markers/HtmlMarker.js +++ b/src/markers/HtmlMarker.js @@ -34,9 +34,9 @@ export class HtmlMarker extends Marker { constructor(markerId) { super(markerId); Object.defineProperty(this, 'isHtmlMarker', {value: true}); - this.markerType = "html"; + this.data.type = "html"; - this.elementObject = new CSS2DObject(htmlToElement(`
`)); + this.elementObject = new CSS2DObject(htmlToElement(`
`)); this.elementObject.onBeforeRender = (renderer, scene, camera) => this.onBeforeRender(renderer, scene, camera); this.fadeDistanceMin = 0; diff --git a/src/markers/LineMarker.js b/src/markers/LineMarker.js index 7419c53..b111408 100644 --- a/src/markers/LineMarker.js +++ b/src/markers/LineMarker.js @@ -37,7 +37,7 @@ export class LineMarker extends ObjectMarker { constructor(markerId) { super(markerId); Object.defineProperty(this, 'isLineMarker', {value: true}); - this.markerType = "line"; + this.data.type = "line"; this.line = new LineMarkerLine([0, 0, 0]); diff --git a/src/markers/Marker.js b/src/markers/Marker.js index 4cedf7f..2524286 100644 --- a/src/markers/Marker.js +++ b/src/markers/Marker.js @@ -33,12 +33,20 @@ export class Marker extends Object3D { super(); Object.defineProperty(this, 'isMarker', {value: true}); - this.markerId = markerId; - this.markerType = "marker"; + this.data = { + id: markerId, + type: "marker", + position: this.position + }; + // redirect parent properties + Object.defineProperty(this, "position", { + get() { return this.data.position }, + set(value) { this.data.position = value } + }); } - dispose() {}; + dispose() {} /** * Updates this marker from the provided data object, usually parsed form json from a markers.json diff --git a/src/markers/MarkerFileManager.js b/src/markers/MarkerFileManager.js index 47c598d..52a6440 100644 --- a/src/markers/MarkerFileManager.js +++ b/src/markers/MarkerFileManager.js @@ -136,7 +136,7 @@ export class MarkerFileManager extends MarkerManager { let marker = this.markers.get(markerData.id); // create new if not existent of wrong type - if (!marker || marker.markerType !== markerData.type) { + if (!marker || marker.data.type !== markerData.type) { switch (markerData.type) { case "shape" : marker = new ShapeMarker(markerData.id); break; case "extrude" : marker = new ExtrudeMarker(markerData.id); break; diff --git a/src/markers/MarkerManager.js b/src/markers/MarkerManager.js index 3a05f61..634da54 100644 --- a/src/markers/MarkerManager.js +++ b/src/markers/MarkerManager.js @@ -95,7 +95,7 @@ export class MarkerManager { * Removes all markers managed by this marker-manager */ clear() { - this.markerSets.forEach(markerSet => this.removeMarkerSet(markerSet.markerSetId)); + this.markerSets.forEach(markerSet => this.removeMarkerSet(markerSet.data.id)); } /** @@ -104,10 +104,10 @@ export class MarkerManager { * @param markerSet {MarkerSet} */ addMarkerSet(markerSet) { - this.removeMarkerSet(markerSet.markerSetId); + this.removeMarkerSet(markerSet.data.id); - this.markerSets.set(markerSet.markerSetId, markerSet); - this.markerScene.add(markerSet) + this.markerSets.set(markerSet.data.id, markerSet); + this.markerScene.add(markerSet); } /** @@ -132,9 +132,9 @@ export class MarkerManager { * @param marker {Marker} */ addMarker(markerSet, marker) { - this.removeMarker(marker.markerId); + this.removeMarker(marker.data.id); - this.markers.set(marker.markerId, marker); + this.markers.set(marker.data.id, marker); markerSet.add(marker); } diff --git a/src/markers/MarkerSet.js b/src/markers/MarkerSet.js index 9d7d4a9..a73af37 100644 --- a/src/markers/MarkerSet.js +++ b/src/markers/MarkerSet.js @@ -22,22 +22,55 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -import {Object3D} from "three"; +import {Scene} from "three"; -export class MarkerSet extends Object3D { +export class MarkerSet extends Scene { /** - * @param markerSetId {string} + * @param id {string} */ - constructor(markerSetId) { + constructor(id) { super(); Object.defineProperty(this, 'isMarkerSet', {value: true}); - this.markerSetId = markerSetId; - this.label = markerSetId; + this.data = { + id: id, + label: id, + toggleable: true, + defaultHide: false, + markerSets: [], + markers: [], + }; + } - this.toggleable = true; - this.defaultHide = false; + add(...object) { + if (object.length === 1) { //super.add() will re-invoke this method for each array-entry if its more than one + let o = object[0]; + if (o.isMarkerSet) { + this.data.markerSets.push(o.data); + } + if (o.isMarker) { + this.data.markers.push(o.data); + } + } + + return super.add(...object); + } + + remove(...object) { + if (object.length === 1) { //super.remove() will re-invoke this method for each array-entry if its more than one + let o = object[0]; + if (o.isMarkerSet) { + let i = this.data.markerSets.indexOf(o.data); + if (i > -1) this.data.markerSets.splice(i, 1); + } + if (o.isMarker) { + let i = this.data.markers.indexOf(o.data); + if (i > -1) this.data.markers.splice(i, 1); + } + } + + return super.remove(...object); } dispose() { diff --git a/src/markers/ObjectMarker.js b/src/markers/ObjectMarker.js index e5d4e2a..2070507 100644 --- a/src/markers/ObjectMarker.js +++ b/src/markers/ObjectMarker.js @@ -35,11 +35,11 @@ export class ObjectMarker extends Marker { constructor(markerId) { super(markerId); Object.defineProperty(this, 'isObjectMarker', {value: true}); - this.markerType = "object"; + this.data.type = "object"; - this.label = null; - this.link = null; - this.newTab = true; + this.data.label = null; + this.data.link = null; + this.data.newTab = true; } onClick(event) { @@ -49,13 +49,17 @@ export class ObjectMarker extends Marker { pos.sub(this.position); } - if (this.label) { - let popup = new LabelPopup(this.label); + if (this.data.label) { + let popup = new LabelPopup(this.data.label); popup.position.copy(pos); this.add(popup); popup.open(); } + if (this.data.link){ + window.open(this.data.link, this.data.newTab ? '_blank' : '_self'); + } + return true; } diff --git a/src/markers/PlayerMarker.js b/src/markers/PlayerMarker.js index e7040ba..671f1aa 100644 --- a/src/markers/PlayerMarker.js +++ b/src/markers/PlayerMarker.js @@ -35,12 +35,12 @@ export class PlayerMarker extends Marker { constructor(markerId, playerUuid) { super(markerId); Object.defineProperty(this, 'isPlayerMarker', {value: true}); - this.markerType = "player"; + this.data.type = "player"; this.playerUuid = playerUuid; this.elementObject = new CSS2DObject(htmlToElement(` -
+
playerhead
diff --git a/src/markers/PoiMarker.js b/src/markers/PoiMarker.js index d8ce187..12cb79b 100644 --- a/src/markers/PoiMarker.js +++ b/src/markers/PoiMarker.js @@ -32,9 +32,9 @@ export class PoiMarker extends HtmlMarker { constructor(markerId) { super(markerId); Object.defineProperty(this, 'isPoiMarker', {value: true}); - this.markerType = "poi"; + this.data.type = "poi"; - this.html = `POI Icon (${this.markerId})
`; + this.html = `POI Icon (${this.data.id})
`; this.iconElement = this.element.getElementsByTagName("img").item(0); this.labelElement = this.element.getElementsByTagName("div").item(0); @@ -43,13 +43,13 @@ export class PoiMarker extends HtmlMarker { } onClick(event) { - if (this.hightlight) return; - this.hightlight = true; + if (this.highlight) return; + this.highlight = true; let eventHandler = evt => { if (evt.path.includes(this.element)) return; - this.hightlight = false; + this.highlight = false; window.removeEventListener("mousedown", eventHandler); window.removeEventListener("touchstart", eventHandler); @@ -67,7 +67,7 @@ export class PoiMarker extends HtmlMarker { return true; } - set hightlight(highlight) { + set highlight(highlight) { if (highlight) { this.element.classList.add("bm-marker-highlight"); } else { @@ -75,7 +75,7 @@ export class PoiMarker extends HtmlMarker { } } - get hightlight() { + get highlight() { return this.element.classList.contains("bm-marker-highlight"); } @@ -122,5 +122,4 @@ export class PoiMarker extends HtmlMarker { } - } \ No newline at end of file diff --git a/src/markers/ShapeMarker.js b/src/markers/ShapeMarker.js index 4f1eb00..f22ba28 100644 --- a/src/markers/ShapeMarker.js +++ b/src/markers/ShapeMarker.js @@ -39,7 +39,7 @@ export class ShapeMarker extends ObjectMarker { constructor(markerId) { super(markerId); Object.defineProperty(this, 'isShapeMarker', {value: true}); - this.markerType = "shape"; + this.data.type = "shape"; let zero = new Vector2(); let shape = new Shape([zero, zero, zero]); diff --git a/src/skybox/SkyFragmentShader.js b/src/skybox/SkyFragmentShader.js index 720c098..be59e76 100644 --- a/src/skybox/SkyFragmentShader.js +++ b/src/skybox/SkyFragmentShader.js @@ -23,7 +23,7 @@ * THE SOFTWARE. */ export const SKY_FRAGMENT_SHADER = ` -uniform float sunlight; +uniform float sunlightStrength; uniform float ambientLight; uniform vec3 skyColor; @@ -33,7 +33,7 @@ void main() { float horizonWidth = 0.005; float horizonHeight = 0.0; - vec4 color = vec4(skyColor * max(sunlight, ambientLight), 1.0); + vec4 color = vec4(skyColor * max(sunlightStrength, ambientLight), 1.0); float voidMultiplier = (clamp(vPosition.y - horizonHeight, -horizonWidth, horizonWidth) + horizonWidth) / (horizonWidth * 2.0); color.rgb *= voidMultiplier; diff --git a/src/skybox/SkyboxScene.js b/src/skybox/SkyboxScene.js index ef1f193..d8f6236 100644 --- a/src/skybox/SkyboxScene.js +++ b/src/skybox/SkyboxScene.js @@ -22,39 +22,23 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -import {BackSide, Color, Mesh, Scene, ShaderMaterial, SphereGeometry} from 'three'; +import {BackSide, Mesh, Scene, ShaderMaterial, SphereGeometry} from 'three'; import {SKY_FRAGMENT_SHADER} from './SkyFragmentShader'; import {SKY_VERTEX_SHADER} from './SkyVertexShader'; export class SkyboxScene extends Scene { - constructor() { + constructor(uniforms) { super(); this.autoUpdate = false; - Object.defineProperty( this, 'isSkyboxScene', { value: true } ); - - this.UNIFORM_sunlight = { - value: 1 - }; - - this.UNIFORM_skyColor = { - value: new Color(0.5, 0.5, 1) - }; - - this.UNIFORM_ambientLight = { - value: 0 - }; + Object.defineProperty(this, 'isSkyboxScene', {value: true}); let geometry = new SphereGeometry(1, 40, 5); let material = new ShaderMaterial({ - uniforms: { - sunlight: this.UNIFORM_sunlight, - skyColor: this.UNIFORM_skyColor, - ambientLight: this.UNIFORM_ambientLight, - }, + uniforms: uniforms, vertexShader: SKY_VERTEX_SHADER, fragmentShader: SKY_FRAGMENT_SHADER, side: BackSide @@ -64,46 +48,4 @@ export class SkyboxScene extends Scene { this.add(skybox); } - /** - * @returns {number} - */ - get sunlight() { - return this.UNIFORM_sunlight.value; - } - - /** - * @param strength {number} - */ - set sunlight(strength) { - this.UNIFORM_sunlight.value = strength; - } - - /** - * @returns {Color} - */ - get skyColor() { - return this.UNIFORM_skyColor.value; - } - - /** - * @param color {Color} - */ - set skyColor(color) { - this.UNIFORM_skyColor.value.set(color); - } - - /** - * @returns {number} - */ - get ambientLight() { - return this.UNIFORM_ambientLight.value; - } - - /** - * @param strength {number} - */ - set ambientLight(strength) { - this.UNIFORM_ambientLight.value = strength; - } - } \ No newline at end of file diff --git a/src/util/CombinedCamera.js b/src/util/CombinedCamera.js index 3b85e0a..fb4f81f 100644 --- a/src/util/CombinedCamera.js +++ b/src/util/CombinedCamera.js @@ -36,8 +36,39 @@ export class CombinedCamera extends PerspectiveCamera { constructor(fov, aspect, near, far, ortho) { super(fov, aspect, near, far); - this.ortho = ortho; - this.distance = 1; + this.data = { + fov: this.fov, + aspect: this.aspect, + near: this.near, + far: this.far, + zoom: this.zoom, + ortho: ortho, + distance: 1, + }; + + // redirect parent properties + Object.defineProperty(this, "fov", { + get() { return this.data.fov }, + set(value) { this.data.fov = value } + }); + Object.defineProperty(this, "aspect", { + get() { return this.data.aspect }, + set(value) { this.data.aspect = value } + }); + Object.defineProperty(this, "near", { + get() { return this.data.near }, + set(value) { this.data.near = value } + }); + Object.defineProperty(this, "far", { + get() { return this.data.far }, + set(value) { this.data.far = value } + }); + Object.defineProperty(this, "zoom", { + get() { return this.data.zoom }, + set(value) { this.data.zoom = value } + }); + + this.updateProjectionMatrix(); } updateProjectionMatrix() { @@ -47,6 +78,9 @@ export class CombinedCamera extends PerspectiveCamera { if (!this.perspectiveProjection) this.perspectiveProjection = new Matrix4(); + if (!this.data) + this.data = {}; + //copied from PerspectiveCamera const near = this.near; let top = near * Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom; @@ -117,4 +151,31 @@ export class CombinedCamera extends PerspectiveCamera { //ignore } + /** + * @returns {number} + */ + get ortho() { + return this.data.ortho; + } + + /** + * @param value {number} + */ + set ortho(value) { + this.data.ortho = value; + } + + /** + * @returns {number} + */ + get distance() { + return this.data.distance; + } + + /** + * @param value {number} + */ + set distance(value) { + this.data.distance = value; + } } \ No newline at end of file