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",
"requires": true,
"version": "0.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@babel/code-frame": {
"version": "7.10.4",

View File

@ -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;
});
});
</script>

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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]);

View File

@ -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(`<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.fadeDistanceMin = 0;

View File

@ -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]);

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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() {

View File

@ -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;
}

View File

@ -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(`
<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">
<div class="bm-player-name"></div>
</div>

View File

@ -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 = `<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.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 {
}
}

View File

@ -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]);

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
}
}