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)
This commit is contained in:
Blue (Lukas Rieger) 2021-02-25 22:53:42 +01:00
parent d0789a6133
commit eda14d3c32
No known key found for this signature in database
GPG Key ID: 904C4995F9E1F800
20 changed files with 414 additions and 235 deletions

3
package-lock.json generated
View File

@ -1,7 +1,8 @@
{ {
"name": "bluemap", "name": "bluemap",
"requires": true, "version": "0.1.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true,
"dependencies": { "dependencies": {
"@babel/code-frame": { "@babel/code-frame": {
"version": "7.10.4", "version": "7.10.4",

View File

@ -68,16 +68,16 @@
loadMaps("data/", bluemap.events).then(loadedMaps => { loadMaps("data/", bluemap.events).then(loadedMaps => {
maps = 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.update();
markerManager.setAutoUpdateInterval(1000 * 10); 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.update();
playerManager.setAutoUpdateInterval(1000); playerManager.setAutoUpdateInterval(1000);
bluemap.switchMap(maps[0]).then(() => { bluemap.switchMap(maps[0]).then(() => {
playerManager.worldId = maps[0].world; playerManager.worldId = maps[0].data.world;
}); });
}); });
</script> </script>

View File

@ -22,7 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * 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 {Map} from "./map/Map";
import {SkyboxScene} from "./skybox/SkyboxScene"; import {SkyboxScene} from "./skybox/SkyboxScene";
import {ControlsManager} from "./controls/ControlsManager"; 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 {LOWRES_FRAGMENT_SHADER} from "./map/lowres/LowresFragmentShader";
import {CombinedCamera} from "./util/CombinedCamera"; import {CombinedCamera} from "./util/CombinedCamera";
import {CSS2DRenderer} from "./util/CSS2DRenderer"; import {CSS2DRenderer} from "./util/CSS2DRenderer";
import {MarkerSet} from "./markers/MarkerSet";
export class MapViewer { export class MapViewer {
@ -48,29 +49,33 @@ export class MapViewer {
this.rootElement = element; this.rootElement = element;
this.events = events; 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 = new Stats();
this.stats.hide(); 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 // renderer
this.renderer = new WebGLRenderer({ this.renderer = new WebGLRenderer({
antialias: true, antialias: true,
@ -79,12 +84,12 @@ export class MapViewer {
logarithmicDepthBuffer: true, logarithmicDepthBuffer: true,
}); });
this.renderer.autoClear = false; this.renderer.autoClear = false;
this.renderer.uniforms = this.uniforms; this.renderer.uniforms = this.data.uniforms;
// CSS2D renderer // CSS2D renderer
this.css2dRenderer = new CSS2DRenderer(); 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.camera = new CombinedCamera(75, 1, 0.1, 10000, 0);
this.skyboxCamera = new PerspectiveCamera(75, 1, 0.1, 10000); this.skyboxCamera = new PerspectiveCamera(75, 1, 0.1, 10000);
@ -98,7 +103,7 @@ export class MapViewer {
/** @type {Map} */ /** @type {Map} */
this.map = null; this.map = null;
this.markerScene = new Scene(); this.markers = new MarkerSet("bm-root");
this.lastFrame = 0; this.lastFrame = 0;
@ -142,7 +147,7 @@ export class MapViewer {
*/ */
handleContainerResize = () => { handleContainerResize = () => {
this.renderer.setSize(this.rootElement.clientWidth, this.rootElement.clientHeight); 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); this.css2dRenderer.setSize(this.rootElement.clientWidth, this.rootElement.clientHeight);
@ -170,7 +175,7 @@ export class MapViewer {
this.raycaster.setFromCamera(normalizedScreenPos, this.camera); this.raycaster.setFromCamera(normalizedScreenPos, this.camera);
// check Object3D interactions // 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; let covered = false;
for (let i = 0; i < intersects.length; i++) { for (let i = 0; i < intersects.length; i++) {
if (intersects[i].object){ if (intersects[i].object){
@ -252,7 +257,7 @@ export class MapViewer {
if (this.map && this.map.isLoaded) { if (this.map && this.map.isLoaded) {
//update uniforms //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.render(this.map.lowresTileManager.scene, this.camera);
this.renderer.clearDepth(); this.renderer.clearDepth();
@ -263,8 +268,8 @@ export class MapViewer {
} }
// render markers // render markers
this.renderer.render(this.markerScene, this.camera); this.renderer.render(this.markers, this.camera);
this.css2dRenderer.render(this.markerScene, this.camera); this.css2dRenderer.render(this.markers, this.camera);
} }
/** /**
@ -278,15 +283,13 @@ export class MapViewer {
this.map = map; this.map = map;
if (this.map && this.map.isMap) { 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(() => { .then(() => {
this.skyboxScene.ambientLight = map.ambientLight; this.data.uniforms.skyColor.value = map.data.skyColor;
this.skyboxScene.skyColor = map.skyColor; this.data.uniforms.ambientLight.value = map.data.ambientLight;
this.data.uniforms.hiresTileMap.value.map = map.hiresTileManager.tileMap.texture;
this.uniforms.ambientLight.value = map.ambientLight; this.data.uniforms.hiresTileMap.value.scale.set(map.data.hires.tileSize.x, map.data.hires.tileSize.z);
this.uniforms.hiresTileMap.value.map = map.hiresTileManager.tileMap.texture; this.data.uniforms.hiresTileMap.value.translate.set(map.data.hires.translate.x, map.data.hires.translate.z);
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);
setTimeout(this.updateLoadedMapArea); setTimeout(this.updateLoadedMapArea);
@ -306,13 +309,13 @@ export class MapViewer {
* Loads the given area on the map (and unloads everything outside that area) * Loads the given area on the map (and unloads everything outside that area)
* @param centerX {number} * @param centerX {number}
* @param centerZ {number} * @param centerZ {number}
* @param hiresViewDistance {number} * @param hiresViewDistance {number?}
* @param lowresViewDistance {number} * @param lowresViewDistance {number?}
*/ */
loadMapArea(centerX, centerZ, hiresViewDistance = -1, lowresViewDistance = -1) { loadMapArea(centerX, centerZ, hiresViewDistance = -1, lowresViewDistance = -1) {
this.loadedCenter.set(centerX, centerZ); this.data.loadedCenter.set(centerX, centerZ);
if (hiresViewDistance >= 0) this.loadedHiresViewDistance = hiresViewDistance; if (hiresViewDistance >= 0) this.data.loadedHiresViewDistance = hiresViewDistance;
if (lowresViewDistance >= 0) this.loadedLowresViewDistance = lowresViewDistance; if (lowresViewDistance >= 0) this.data.loadedLowresViewDistance = lowresViewDistance;
this.updateLoadedMapArea(); this.updateLoadedMapArea();
} }
@ -322,22 +325,67 @@ export class MapViewer {
*/ */
updateLoadedMapArea = () => { updateLoadedMapArea = () => {
if (!this.map) return; 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} * @returns {number}
*/ */
get superSampling() { get superSampling() {
return this.superSamplingValue; return this.data.superSampling;
} }
/** /**
* @param value {number} * @param value {number}
*/ */
set superSampling(value) { set superSampling(value) {
this.superSamplingValue = value; this.data.superSampling = value;
this.handleContainerResize(); 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;
}
} }

View File

@ -36,14 +36,20 @@ export class ControlsManager {
constructor(mapViewer, camera) { constructor(mapViewer, camera) {
Object.defineProperty( this, 'isControlsManager', { value: true } ); 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.mapViewer = mapViewer;
this.camera = camera; this.camera = camera;
this.position = new Vector3(0, 0, 0); /** @type {Vector3} */
this.rotation = 0;
this.angle = 0;
this.tilt = 0;
this.lastPosition = this.position.clone(); this.lastPosition = this.position.clone();
this.lastRotation = this.rotation; this.lastRotation = this.rotation;
this.lastAngle = this.angle; this.lastAngle = this.angle;
@ -164,22 +170,22 @@ export class ControlsManager {
isValueChanged() { isValueChanged() {
return !( return !(
this.position.equals(this.lastPosition) && this.data.position.equals(this.lastPosition) &&
this.rotation === this.lastRotation && this.data.rotation === this.lastRotation &&
this.angle === this.lastAngle && this.data.angle === this.lastAngle &&
this.distance === this.lastDistance && this.distance === this.lastDistance &&
this.ortho === this.lastOrtho && this.ortho === this.lastOrtho &&
this.tilt === this.lastTilt this.data.tilt === this.lastTilt
); );
} }
resetValueChanged() { resetValueChanged() {
this.lastPosition.copy(this.position); this.lastPosition.copy(this.data.position);
this.lastRotation = this.rotation; this.lastRotation = this.data.rotation;
this.lastAngle = this.angle; this.lastAngle = this.data.angle;
this.lastDistance = this.distance; this.lastDistance = this.distance;
this.lastOrtho = this.ortho; 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.stop();
this._controls = controls; this._controls = controls;
if (controls) this.data.controls = controls.data || null
if (this._controls && this._controls.start) if (this._controls && this._controls.start)
this._controls.start(this); this._controls.start(this);
@ -230,4 +237,89 @@ export class ControlsManager {
return this._controls; 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;
}
} }

View File

@ -41,9 +41,6 @@ export class MapHeightControls {
this.targetHeight = 0; this.targetHeight = 0;
this.cameraHeight = 0; this.cameraHeight = 0;
this.lastTarget = new Vector2();
this.lastTargetTerrainHeight = 0;
this.minCameraHeight = 0; this.minCameraHeight = 0;
this.distanceTagretHeight = 0; this.distanceTagretHeight = 0;
} }
@ -73,12 +70,7 @@ export class MapHeightControls {
let targetSmoothing = this.targetHeightStiffness / (16.666 / delta); let targetSmoothing = this.targetHeightStiffness / (16.666 / delta);
targetSmoothing = MathUtils.clamp(targetSmoothing, 0, 1); targetSmoothing = MathUtils.clamp(targetSmoothing, 0, 1);
let targetTerrainHeight = this.lastTargetTerrainHeight; let targetTerrainHeight = map.terrainHeightAt(this.manager.position.x, this.manager.position.z) + 3 || 0;
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 targetDelta = targetTerrainHeight - this.targetHeight; let targetDelta = targetTerrainHeight - this.targetHeight;
this.targetHeight += targetDelta * targetSmoothing; this.targetHeight += targetDelta * targetSmoothing;

View File

@ -45,29 +45,28 @@ export class Map {
constructor(id, dataUrl, settingsUrl, texturesUrl, events = null) { constructor(id, dataUrl, settingsUrl, texturesUrl, events = null) {
Object.defineProperty( this, 'isMap', { value: true } ); Object.defineProperty( this, 'isMap', { value: true } );
this.id = id;
this.events = events; this.events = events;
this.dataUrl = dataUrl;
this.settingsUrl = settingsUrl; this.data = {
this.texturesUrl = texturesUrl; id: id,
dataUrl: dataUrl,
this.name = this.id; settingsUrl: settingsUrl,
this.world = "-"; texturesUrl: texturesUrl,
name: id,
this.startPos = {x: 0, z: 0}; world: "-",
this.skyColor = new Color(); startPos: {x: 0, z: 0},
this.ambientLight = 0; skyColor: new Color(),
ambientLight: 0,
this.hires = { hires: {
tileSize: {x: 32, z: 32}, tileSize: {x: 32, z: 32},
scale: {x: 1, z: 1}, scale: {x: 1, z: 1},
translate: {x: 2, z: 2} translate: {x: 2, z: 2}
}; },
this.lowres = { lowres: {
tileSize: {x: 32, z: 32}, tileSize: {x: 32, z: 32},
scale: {x: 1, z: 1}, scale: {x: 1, z: 1},
translate: {x: 2, z: 2} translate: {x: 2, z: 2}
}
}; };
this.raycaster = new Raycaster(); this.raycaster = new Raycaster();
@ -104,29 +103,29 @@ export class Map {
let settingsPromise = settingsFilePromise let settingsPromise = settingsFilePromise
.then(worldSettings => { .then(worldSettings => {
this.name = worldSettings.name ? worldSettings.name : this.name; this.data.name = worldSettings.name ? worldSettings.name : this.data.name;
this.world = worldSettings.world ? worldSettings.world : this.world; this.data.world = worldSettings.world ? worldSettings.world : this.data.world;
this.startPos = {...this.startPos, ...worldSettings.startPos}; this.data.startPos = {...this.data.startPos, ...worldSettings.startPos};
this.skyColor.setRGB( this.data.skyColor.setRGB(
worldSettings.skyColor.r || this.skyColor.r, worldSettings.skyColor.r || this.data.skyColor.r,
worldSettings.skyColor.g || this.skyColor.g, worldSettings.skyColor.g || this.data.skyColor.g,
worldSettings.skyColor.b || this.skyColor.b, 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.hires === undefined) worldSettings.hires = {};
if (worldSettings.lowres === undefined) worldSettings.lowres = {}; if (worldSettings.lowres === undefined) worldSettings.lowres = {};
this.hires = { this.data.hires = {
tileSize: {...this.hires.tileSize, ...worldSettings.hires.tileSize}, tileSize: {...this.data.hires.tileSize, ...worldSettings.hires.tileSize},
scale: {...this.hires.scale, ...worldSettings.hires.scale}, scale: {...this.data.hires.scale, ...worldSettings.hires.scale},
translate: {...this.hires.translate, ...worldSettings.hires.translate} translate: {...this.data.hires.translate, ...worldSettings.hires.translate}
}; };
this.lowres = { this.data.lowres = {
tileSize: {...this.lowres.tileSize, ...worldSettings.lowres.tileSize}, tileSize: {...this.data.lowres.tileSize, ...worldSettings.lowres.tileSize},
scale: {...this.lowres.scale, ...worldSettings.lowres.scale}, scale: {...this.data.lowres.scale, ...worldSettings.lowres.scale},
translate: {...this.lowres.translate, ...worldSettings.lowres.translate} translate: {...this.data.lowres.translate, ...worldSettings.lowres.translate}
}; };
}); });
@ -137,13 +136,13 @@ export class Map {
this.hiresMaterial = this.createHiresMaterial(hiresVertexShader, hiresFragmentShader, uniforms, textures); 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.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.dataUrl}lowres/`, this.lowresMaterial, this.lowres), this.onTileLoad("lowres"), this.onTileUnload("lowres"), 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.hiresTileManager.scene.autoUpdate = false;
this.lowresTileManager.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) { loadMapArea(x, z, hiresViewDistance, lowresViewDistance) {
if (!this.isLoaded) return; if (!this.isLoaded) return;
let hiresX = Math.floor((x - this.hires.translate.x) / this.hires.tileSize.x); let hiresX = Math.floor((x - this.data.hires.translate.x) / this.data.hires.tileSize.x);
let hiresZ = Math.floor((z - this.hires.translate.z) / this.hires.tileSize.z); let hiresZ = Math.floor((z - this.data.hires.translate.z) / this.data.hires.tileSize.z);
let hiresViewX = Math.floor(hiresViewDistance / this.hires.tileSize.x); let hiresViewX = Math.floor(hiresViewDistance / this.data.hires.tileSize.x);
let hiresViewZ = Math.floor(hiresViewDistance / this.hires.tileSize.z); let hiresViewZ = Math.floor(hiresViewDistance / this.data.hires.tileSize.z);
let lowresX = Math.floor((x - this.lowres.translate.x) / this.lowres.tileSize.x); let lowresX = Math.floor((x - this.data.lowres.translate.x) / this.data.lowres.tileSize.x);
let lowresZ = Math.floor((z - this.lowres.translate.z) / this.lowres.tileSize.z); let lowresZ = Math.floor((z - this.data.lowres.translate.z) / this.data.lowres.tileSize.z);
let lowresViewX = Math.floor(lowresViewDistance / this.lowres.tileSize.x); let lowresViewX = Math.floor(lowresViewDistance / this.data.lowres.tileSize.x);
let lowresViewZ = Math.floor(lowresViewDistance / this.lowres.tileSize.z); let lowresViewZ = Math.floor(lowresViewDistance / this.data.lowres.tileSize.z);
this.hiresTileManager.loadAroundTile(hiresX, hiresZ, hiresViewX, hiresViewZ); this.hiresTileManager.loadAroundTile(hiresX, hiresZ, hiresViewX, hiresViewZ);
this.lowresTileManager.loadAroundTile(lowresX, lowresZ, lowresViewX, lowresViewZ); this.lowresTileManager.loadAroundTile(lowresX, lowresZ, lowresViewX, lowresViewZ);
@ -190,20 +189,20 @@ export class Map {
*/ */
loadSettingsFile() { loadSettingsFile() {
return new Promise((resolve, reject) => { 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(); let loader = new FileLoader();
loader.setResponseType("json"); loader.setResponseType("json");
loader.load(this.settingsUrl, loader.load(this.data.settingsUrl,
settings => { settings => {
if (settings.maps && settings.maps[this.id]) { if (settings.maps && settings.maps[this.data.id]) {
resolve(settings.maps[this.id]); resolve(settings.maps[this.data.id]);
} else { } 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() { loadTexturesFile() {
return new Promise((resolve, reject) => { 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(); let loader = new FileLoader();
loader.setResponseType("json"); loader.setResponseType("json");
loader.load(this.texturesUrl, loader.load(this.data.texturesUrl,
resolve, 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.far = 300;
this.raycaster.layers.enableAll(); 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); let tile = this.hiresTileManager.tiles.get(hiresTileHash);
if (!tile || !tile.model) { 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); tile = this.lowresTileManager.tiles.get(lowresTileHash);
} }

View File

@ -39,7 +39,7 @@ export class ExtrudeMarker extends ObjectMarker {
constructor(markerId) { constructor(markerId) {
super(markerId); super(markerId);
Object.defineProperty(this, 'isExtrudeMarker', {value: true}); Object.defineProperty(this, 'isExtrudeMarker', {value: true});
this.markerType = "extrude"; this.data.type = "extrude";
let zero = new Vector2(); let zero = new Vector2();
let shape = new Shape([zero, zero, zero]); let shape = new Shape([zero, zero, zero]);

View File

@ -34,9 +34,9 @@ export class HtmlMarker extends Marker {
constructor(markerId) { constructor(markerId) {
super(markerId); super(markerId);
Object.defineProperty(this, 'isHtmlMarker', {value: true}); Object.defineProperty(this, 'isHtmlMarker', {value: true});
this.markerType = "html"; this.data.type = "html";
this.elementObject = new CSS2DObject(htmlToElement(`<div id="bm-marker-${this.markerId}" class="bm-marker-${this.markerType}"></div>`)); this.elementObject = new CSS2DObject(htmlToElement(`<div id="bm-marker-${this.data.id}" class="bm-marker-${this.data.type}"></div>`));
this.elementObject.onBeforeRender = (renderer, scene, camera) => this.onBeforeRender(renderer, scene, camera); this.elementObject.onBeforeRender = (renderer, scene, camera) => this.onBeforeRender(renderer, scene, camera);
this.fadeDistanceMin = 0; this.fadeDistanceMin = 0;

View File

@ -37,7 +37,7 @@ export class LineMarker extends ObjectMarker {
constructor(markerId) { constructor(markerId) {
super(markerId); super(markerId);
Object.defineProperty(this, 'isLineMarker', {value: true}); Object.defineProperty(this, 'isLineMarker', {value: true});
this.markerType = "line"; this.data.type = "line";
this.line = new LineMarkerLine([0, 0, 0]); this.line = new LineMarkerLine([0, 0, 0]);

View File

@ -33,12 +33,20 @@ export class Marker extends Object3D {
super(); super();
Object.defineProperty(this, 'isMarker', {value: true}); Object.defineProperty(this, 'isMarker', {value: true});
this.markerId = markerId; this.data = {
this.markerType = "marker"; 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 * Updates this marker from the provided data object, usually parsed form json from a markers.json

View File

@ -136,7 +136,7 @@ export class MarkerFileManager extends MarkerManager {
let marker = this.markers.get(markerData.id); let marker = this.markers.get(markerData.id);
// create new if not existent of wrong type // create new if not existent of wrong type
if (!marker || marker.markerType !== markerData.type) { if (!marker || marker.data.type !== markerData.type) {
switch (markerData.type) { switch (markerData.type) {
case "shape" : marker = new ShapeMarker(markerData.id); break; case "shape" : marker = new ShapeMarker(markerData.id); break;
case "extrude" : marker = new ExtrudeMarker(markerData.id); break; case "extrude" : marker = new ExtrudeMarker(markerData.id); break;

View File

@ -95,7 +95,7 @@ export class MarkerManager {
* Removes all markers managed by this marker-manager * Removes all markers managed by this marker-manager
*/ */
clear() { 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} * @param markerSet {MarkerSet}
*/ */
addMarkerSet(markerSet) { addMarkerSet(markerSet) {
this.removeMarkerSet(markerSet.markerSetId); this.removeMarkerSet(markerSet.data.id);
this.markerSets.set(markerSet.markerSetId, markerSet); this.markerSets.set(markerSet.data.id, markerSet);
this.markerScene.add(markerSet) this.markerScene.add(markerSet);
} }
/** /**
@ -132,9 +132,9 @@ export class MarkerManager {
* @param marker {Marker} * @param marker {Marker}
*/ */
addMarker(markerSet, 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); markerSet.add(marker);
} }

View File

@ -22,22 +22,55 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * 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(); super();
Object.defineProperty(this, 'isMarkerSet', {value: true}); Object.defineProperty(this, 'isMarkerSet', {value: true});
this.markerSetId = markerSetId; this.data = {
this.label = markerSetId; id: id,
label: id,
toggleable: true,
defaultHide: false,
markerSets: [],
markers: [],
};
}
this.toggleable = true; add(...object) {
this.defaultHide = false; 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() { dispose() {

View File

@ -35,11 +35,11 @@ export class ObjectMarker extends Marker {
constructor(markerId) { constructor(markerId) {
super(markerId); super(markerId);
Object.defineProperty(this, 'isObjectMarker', {value: true}); Object.defineProperty(this, 'isObjectMarker', {value: true});
this.markerType = "object"; this.data.type = "object";
this.label = null; this.data.label = null;
this.link = null; this.data.link = null;
this.newTab = true; this.data.newTab = true;
} }
onClick(event) { onClick(event) {
@ -49,13 +49,17 @@ export class ObjectMarker extends Marker {
pos.sub(this.position); pos.sub(this.position);
} }
if (this.label) { if (this.data.label) {
let popup = new LabelPopup(this.label); let popup = new LabelPopup(this.data.label);
popup.position.copy(pos); popup.position.copy(pos);
this.add(popup); this.add(popup);
popup.open(); popup.open();
} }
if (this.data.link){
window.open(this.data.link, this.data.newTab ? '_blank' : '_self');
}
return true; return true;
} }

View File

@ -35,12 +35,12 @@ export class PlayerMarker extends Marker {
constructor(markerId, playerUuid) { constructor(markerId, playerUuid) {
super(markerId); super(markerId);
Object.defineProperty(this, 'isPlayerMarker', {value: true}); Object.defineProperty(this, 'isPlayerMarker', {value: true});
this.markerType = "player"; this.data.type = "player";
this.playerUuid = playerUuid; this.playerUuid = playerUuid;
this.elementObject = new CSS2DObject(htmlToElement(` this.elementObject = new CSS2DObject(htmlToElement(`
<div id="bm-marker-${this.markerId}" class="bm-marker-${this.markerType}"> <div id="bm-marker-${this.data.id}" class="bm-marker-${this.data.type}">
<img src="assets/playerheads/${this.playerUuid}.png" alt="playerhead" draggable="false"> <img src="assets/playerheads/${this.playerUuid}.png" alt="playerhead" draggable="false">
<div class="bm-player-name"></div> <div class="bm-player-name"></div>
</div> </div>

View File

@ -32,9 +32,9 @@ export class PoiMarker extends HtmlMarker {
constructor(markerId) { constructor(markerId) {
super(markerId); super(markerId);
Object.defineProperty(this, 'isPoiMarker', {value: true}); Object.defineProperty(this, 'isPoiMarker', {value: true});
this.markerType = "poi"; this.data.type = "poi";
this.html = `<img src="" alt="POI Icon (${this.markerId})" class="bm-marker-poi-icon" draggable="false" style="pointer-events: auto"><div class="bm-marker-poi-label"></div>`; this.html = `<img src="" alt="POI Icon (${this.data.id})" class="bm-marker-poi-icon" draggable="false" style="pointer-events: auto"><div class="bm-marker-poi-label"></div>`;
this.iconElement = this.element.getElementsByTagName("img").item(0); this.iconElement = this.element.getElementsByTagName("img").item(0);
this.labelElement = this.element.getElementsByTagName("div").item(0); this.labelElement = this.element.getElementsByTagName("div").item(0);
@ -43,13 +43,13 @@ export class PoiMarker extends HtmlMarker {
} }
onClick(event) { onClick(event) {
if (this.hightlight) return; if (this.highlight) return;
this.hightlight = true; this.highlight = true;
let eventHandler = evt => { let eventHandler = evt => {
if (evt.path.includes(this.element)) return; if (evt.path.includes(this.element)) return;
this.hightlight = false; this.highlight = false;
window.removeEventListener("mousedown", eventHandler); window.removeEventListener("mousedown", eventHandler);
window.removeEventListener("touchstart", eventHandler); window.removeEventListener("touchstart", eventHandler);
@ -67,7 +67,7 @@ export class PoiMarker extends HtmlMarker {
return true; return true;
} }
set hightlight(highlight) { set highlight(highlight) {
if (highlight) { if (highlight) {
this.element.classList.add("bm-marker-highlight"); this.element.classList.add("bm-marker-highlight");
} else { } else {
@ -75,7 +75,7 @@ export class PoiMarker extends HtmlMarker {
} }
} }
get hightlight() { get highlight() {
return this.element.classList.contains("bm-marker-highlight"); return this.element.classList.contains("bm-marker-highlight");
} }
@ -122,5 +122,4 @@ export class PoiMarker extends HtmlMarker {
} }
} }

View File

@ -39,7 +39,7 @@ export class ShapeMarker extends ObjectMarker {
constructor(markerId) { constructor(markerId) {
super(markerId); super(markerId);
Object.defineProperty(this, 'isShapeMarker', {value: true}); Object.defineProperty(this, 'isShapeMarker', {value: true});
this.markerType = "shape"; this.data.type = "shape";
let zero = new Vector2(); let zero = new Vector2();
let shape = new Shape([zero, zero, zero]); let shape = new Shape([zero, zero, zero]);

View File

@ -23,7 +23,7 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
export const SKY_FRAGMENT_SHADER = ` export const SKY_FRAGMENT_SHADER = `
uniform float sunlight; uniform float sunlightStrength;
uniform float ambientLight; uniform float ambientLight;
uniform vec3 skyColor; uniform vec3 skyColor;
@ -33,7 +33,7 @@ void main() {
float horizonWidth = 0.005; float horizonWidth = 0.005;
float horizonHeight = 0.0; 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); float voidMultiplier = (clamp(vPosition.y - horizonHeight, -horizonWidth, horizonWidth) + horizonWidth) / (horizonWidth * 2.0);
color.rgb *= voidMultiplier; color.rgb *= voidMultiplier;

View File

@ -22,39 +22,23 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * 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_FRAGMENT_SHADER} from './SkyFragmentShader';
import {SKY_VERTEX_SHADER} from './SkyVertexShader'; import {SKY_VERTEX_SHADER} from './SkyVertexShader';
export class SkyboxScene extends Scene { export class SkyboxScene extends Scene {
constructor() { constructor(uniforms) {
super(); super();
this.autoUpdate = false; this.autoUpdate = false;
Object.defineProperty( this, 'isSkyboxScene', { value: true } ); 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
};
let geometry = new SphereGeometry(1, 40, 5); let geometry = new SphereGeometry(1, 40, 5);
let material = new ShaderMaterial({ let material = new ShaderMaterial({
uniforms: { uniforms: uniforms,
sunlight: this.UNIFORM_sunlight,
skyColor: this.UNIFORM_skyColor,
ambientLight: this.UNIFORM_ambientLight,
},
vertexShader: SKY_VERTEX_SHADER, vertexShader: SKY_VERTEX_SHADER,
fragmentShader: SKY_FRAGMENT_SHADER, fragmentShader: SKY_FRAGMENT_SHADER,
side: BackSide side: BackSide
@ -64,46 +48,4 @@ export class SkyboxScene extends Scene {
this.add(skybox); 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;
}
} }

View File

@ -36,8 +36,39 @@ export class CombinedCamera extends PerspectiveCamera {
constructor(fov, aspect, near, far, ortho) { constructor(fov, aspect, near, far, ortho) {
super(fov, aspect, near, far); super(fov, aspect, near, far);
this.ortho = ortho; this.data = {
this.distance = 1; 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() { updateProjectionMatrix() {
@ -47,6 +78,9 @@ export class CombinedCamera extends PerspectiveCamera {
if (!this.perspectiveProjection) if (!this.perspectiveProjection)
this.perspectiveProjection = new Matrix4(); this.perspectiveProjection = new Matrix4();
if (!this.data)
this.data = {};
//copied from PerspectiveCamera //copied from PerspectiveCamera
const near = this.near; const near = this.near;
let top = near * Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom; let top = near * Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom;
@ -117,4 +151,31 @@ export class CombinedCamera extends PerspectiveCamera {
//ignore //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;
}
} }