@jdultra/threedtiles 3.0.6 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +2 -0
- package/index.html +0 -43
- package/package.json +10 -5
- package/src/decoder/B3DMDecoder.js +3 -6
- package/{skybox → src/images/skybox}/back.png +0 -0
- package/{skybox → src/images/skybox}/bottom.png +0 -0
- package/{skybox → src/images/skybox}/front.png +0 -0
- package/{skybox → src/images/skybox}/left.png +0 -0
- package/{skybox → src/images/skybox}/right.png +0 -0
- package/{skybox → src/images/skybox}/top.png +0 -0
- package/src/index.js +26 -73
- package/src/tileset/OGC3DTile.js +105 -120
- package/src/tileset/TileLoader.js +188 -0
- package/src/tileset/TilesetStats.js +65 -0
- package/webpack.config.js +10 -10
- package/src/cache/Cache.js +0 -44
package/index.html
CHANGED
|
@@ -4,53 +4,10 @@
|
|
|
4
4
|
<head>
|
|
5
5
|
<meta charset="utf-8" />
|
|
6
6
|
<title>Three 3DTiles viewer sample</title>
|
|
7
|
-
<style>
|
|
8
|
-
.slidecontainer {
|
|
9
|
-
width: 100%;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.slider {
|
|
13
|
-
-webkit-appearance: none;
|
|
14
|
-
width: 100%;
|
|
15
|
-
height: 15px;
|
|
16
|
-
border-radius: 5px;
|
|
17
|
-
background: #d3d3d3;
|
|
18
|
-
outline: none;
|
|
19
|
-
opacity: 0.7;
|
|
20
|
-
-webkit-transition: .2s;
|
|
21
|
-
transition: opacity .2s;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.slider:hover {
|
|
25
|
-
opacity: 1;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
.slider::-webkit-slider-thumb {
|
|
29
|
-
-webkit-appearance: none;
|
|
30
|
-
appearance: none;
|
|
31
|
-
width: 25px;
|
|
32
|
-
height: 25px;
|
|
33
|
-
border-radius: 50%;
|
|
34
|
-
background: #0439aa;
|
|
35
|
-
cursor: pointer;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.slider::-moz-range-thumb {
|
|
39
|
-
width: 25px;
|
|
40
|
-
height: 25px;
|
|
41
|
-
border-radius: 50%;
|
|
42
|
-
background: #04AA6D;
|
|
43
|
-
cursor: pointer;
|
|
44
|
-
}
|
|
45
|
-
</style>
|
|
46
7
|
</head>
|
|
47
8
|
|
|
48
9
|
<body>
|
|
49
10
|
<div id="screen"></div>
|
|
50
|
-
<div style="position: absolute; top: 1%; z-index: 100; right:1%; ">
|
|
51
|
-
<input type="range" min="0.1" max="4" value="1.0", step="0.1" class="slider" id="lodMultiplier" >
|
|
52
|
-
<p style="color: #0439aa;">LOD multiplier: <span id="multiplierValue"></span></p>
|
|
53
|
-
</div>
|
|
54
11
|
<div style="position: absolute; bottom: 1%; z-index: 100;">
|
|
55
12
|
<a href="https://openheritage3d.org/project.php?id=taz6-n215">ORIGINAL MODEL</a>
|
|
56
13
|
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jdultra/threedtiles",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "An OGC 3DTiles viewer for Three.js",
|
|
5
5
|
"main": "tileset.js",
|
|
6
6
|
"scripts": {
|
|
@@ -24,10 +24,15 @@
|
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"gltf-validator": ">=2.0.0-dev.3.3",
|
|
27
|
+
"js-utils-z": "1.2.1",
|
|
27
28
|
"lodash": ">=4.17.20",
|
|
29
|
+
"lru-cache": "^7.4.1",
|
|
30
|
+
"mnemonist": "^0.39.0",
|
|
31
|
+
"path-browserify": "^1.0.1",
|
|
28
32
|
"regenerator-runtime": ">=0.13.7",
|
|
33
|
+
"set-interval-async": "^2.0.3",
|
|
29
34
|
"three": "0.131.0",
|
|
30
|
-
"
|
|
35
|
+
"uuid": "^8.3.2"
|
|
31
36
|
},
|
|
32
37
|
"devDependencies": {
|
|
33
38
|
"@babel/core": "^7.12.9",
|
|
@@ -38,9 +43,9 @@
|
|
|
38
43
|
"html-loader": "^1.3.2",
|
|
39
44
|
"html-webpack-plugin": "^4.5.0",
|
|
40
45
|
"mini-css-extract-plugin": "^1.3.1",
|
|
41
|
-
"webpack": "
|
|
42
|
-
"webpack-cli": "
|
|
43
|
-
"webpack-dev-server": "
|
|
46
|
+
"webpack": "^5.65.0",
|
|
47
|
+
"webpack-cli": "4.9.1",
|
|
48
|
+
"webpack-dev-server": "^4.7.4",
|
|
44
49
|
"whatwg-fetch": "^3.5.0"
|
|
45
50
|
}
|
|
46
51
|
}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
2
|
-
import * as THREE from 'three';
|
|
3
2
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
4
3
|
import { LegacyGLTFLoader } from './LegacyGLTFLoader.js';
|
|
5
|
-
import { Color, DoubleSide, BufferAttribute, Mesh } from "three";
|
|
6
|
-
import { BufferGeometryUtils } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
7
4
|
|
|
8
5
|
const gltfLoader = new GLTFLoader();
|
|
9
6
|
const dracoLoader = new DRACOLoader();
|
|
10
|
-
dracoLoader.setDecoderPath( '/
|
|
7
|
+
dracoLoader.setDecoderPath( 'https://www.gstatic.com/draco/versioned/decoders/1.4.3/' );
|
|
11
8
|
gltfLoader.setDRACOLoader( dracoLoader );
|
|
12
9
|
const legacyGLTFLoader = new LegacyGLTFLoader();
|
|
13
10
|
const B3DMDecoder = {
|
|
@@ -106,7 +103,7 @@ const B3DMDecoder = {
|
|
|
106
103
|
* @param {*} scene
|
|
107
104
|
* @returns
|
|
108
105
|
*/
|
|
109
|
-
function mergeColoredObject(scene) {
|
|
106
|
+
/*function mergeColoredObject(scene) {
|
|
110
107
|
|
|
111
108
|
const coloredMeshes = {};
|
|
112
109
|
const texturedMeshes = {};
|
|
@@ -213,7 +210,7 @@ function mergeColoredObject(scene) {
|
|
|
213
210
|
console.log();
|
|
214
211
|
scene.matrix = new THREE.Matrix4();
|
|
215
212
|
return scene;
|
|
216
|
-
}
|
|
213
|
+
}*/
|
|
217
214
|
|
|
218
215
|
export { B3DMDecoder }
|
|
219
216
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/index.js
CHANGED
|
@@ -1,75 +1,31 @@
|
|
|
1
1
|
import "regenerator-runtime/runtime.js";
|
|
2
2
|
import * as THREE from 'three';
|
|
3
3
|
import Stats from 'three/examples/jsm/libs/stats.module.js';
|
|
4
|
+
import TilesetStats from './tileset/TilesetStats';
|
|
4
5
|
import { OGC3DTile } from "./tileset/OGC3DTile";
|
|
6
|
+
import { TileLoader } from "./tileset/TileLoader";
|
|
5
7
|
import { MapControls, OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
|
|
6
8
|
|
|
7
9
|
|
|
10
|
+
|
|
11
|
+
|
|
8
12
|
const scene = initScene();
|
|
13
|
+
const tilesetStats = TilesetStats();
|
|
9
14
|
const domContainer = initDomContainer("screen");
|
|
10
15
|
const camera = initCamera();
|
|
11
16
|
const ogc3DTiles = initTileset(scene);
|
|
12
|
-
initLODMultiplierSlider(ogc3DTiles);
|
|
13
17
|
const controller = initController(camera, domContainer);
|
|
14
|
-
const skybox = initSkybox(controller, camera, scene);
|
|
15
18
|
|
|
16
19
|
const stats = initStats(domContainer);
|
|
17
20
|
const renderer = initRenderer(camera, domContainer);
|
|
18
21
|
|
|
19
22
|
animate();
|
|
20
23
|
|
|
21
|
-
function initSkybox(controller, camera, scene) {
|
|
22
|
-
const geometry = new THREE.BoxGeometry(8000, 8000, 8000);
|
|
23
|
-
const textures = [
|
|
24
|
-
loadTexture("./skybox/back.png"),
|
|
25
|
-
loadTexture("./skybox/front.png"),
|
|
26
|
-
loadTexture("./skybox/top.png"),
|
|
27
|
-
loadTexture("./skybox/bottom.png"),
|
|
28
|
-
loadTexture("./skybox/right.png"),
|
|
29
|
-
loadTexture("./skybox/left.png"),
|
|
30
|
-
];
|
|
31
|
-
function loadTexture(url) {
|
|
32
|
-
return new THREE.TextureLoader().load(url, (texture => {
|
|
33
|
-
texture.wrapS = THREE.ClampToEdgeWrapping;
|
|
34
|
-
texture.wrapT = THREE.ClampToEdgeWrapping;
|
|
35
|
-
texture.magFilter = THREE.LinearFilter;
|
|
36
|
-
texture.minFilter = THREE.LinearFilter;
|
|
37
|
-
}))
|
|
38
24
|
|
|
39
|
-
}
|
|
40
|
-
const materials = [];
|
|
41
|
-
textures.forEach(tex => {
|
|
42
|
-
materials.push(new THREE.MeshBasicMaterial({ map: tex, side: THREE.BackSide }));
|
|
43
|
-
})
|
|
44
|
-
const mesh = new THREE.Mesh(geometry, materials);
|
|
45
|
-
mesh.position.copy(camera.position);
|
|
46
|
-
controller.addEventListener("change", () => {
|
|
47
|
-
mesh.position.copy(camera.position);
|
|
48
|
-
});
|
|
49
|
-
scene.add(mesh);
|
|
50
|
-
return mesh;
|
|
51
|
-
}
|
|
52
|
-
function initLODMultiplierSlider(tileset) {
|
|
53
|
-
var slider = document.getElementById("lodMultiplier");
|
|
54
|
-
var output = document.getElementById("multiplierValue");
|
|
55
|
-
output.innerHTML = slider.value;
|
|
56
|
-
|
|
57
|
-
slider.oninput = () => {
|
|
58
|
-
tileset.setGeometricErrorMultiplier(slider.value)
|
|
59
|
-
output.innerHTML = slider.value;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
25
|
function initScene() {
|
|
63
26
|
const scene = new THREE.Scene();
|
|
64
|
-
scene.background = new THREE.Color(
|
|
65
|
-
scene.add(new THREE.AmbientLight(0xFFFFFF, 0
|
|
66
|
-
|
|
67
|
-
var dirLight = new THREE.DirectionalLight(0xffffff, 0.5);
|
|
68
|
-
dirLight.position.set(-400, 500, -100);
|
|
69
|
-
dirLight.target.position.set(0, 0, 0);
|
|
70
|
-
|
|
71
|
-
scene.add(dirLight);
|
|
72
|
-
scene.add(dirLight.target);
|
|
27
|
+
scene.background = new THREE.Color(0x000000);
|
|
28
|
+
scene.add(new THREE.AmbientLight(0xFFFFFF, 1.0));
|
|
73
29
|
return scene;
|
|
74
30
|
}
|
|
75
31
|
|
|
@@ -109,16 +65,15 @@ function initRenderer(camera, dom) {
|
|
|
109
65
|
}
|
|
110
66
|
|
|
111
67
|
function initStats(dom) {
|
|
112
|
-
const stats =
|
|
113
|
-
|
|
68
|
+
const stats = Stats();
|
|
69
|
+
document.body.appendChild(stats.dom);
|
|
114
70
|
return stats;
|
|
115
71
|
}
|
|
116
72
|
|
|
117
73
|
|
|
118
74
|
function initCamera() {
|
|
119
75
|
const camera = new THREE.PerspectiveCamera(70, window.offsetWidth / window.offsetHeight, 1, 10000);
|
|
120
|
-
camera.position.set(
|
|
121
|
-
camera.lookAt(-100, 0, 0);
|
|
76
|
+
camera.position.set(10, 10, 10);
|
|
122
77
|
|
|
123
78
|
return camera;
|
|
124
79
|
}
|
|
@@ -127,34 +82,33 @@ function initTileset(scene) {
|
|
|
127
82
|
|
|
128
83
|
const ogc3DTile = new OGC3DTile({
|
|
129
84
|
url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
|
|
130
|
-
//url: "https://storage.googleapis.com/ogc-3d-tiles/castleX/tileset.json",
|
|
131
|
-
//url: "./apartment/tileset.json",
|
|
132
|
-
//url: "https://storage.googleapis.com/ogc-3d-tiles/berlinSubsetTiled/tileset.json",
|
|
133
|
-
//url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
|
|
134
|
-
//url: "https://s3.us-east-2.wasabisys.com/construkted-assets/arkcnfuk9fw/tileset.json",
|
|
135
|
-
//url: "https://s3.us-east-2.wasabisys.com/construkted-assets/a73faxnydqk/tileset.json",
|
|
136
|
-
//url: "https://s3.us-east-2.wasabisys.com/construkted-assets/e63mubnpmg/tileset.json",
|
|
137
|
-
//url: "https://assets.cesium.com/697512/tileset.json?v=1",
|
|
138
|
-
//url:"https://a.3d.blc.shc.eu/WAB/base_layer/cesium_mesh_2020/tileset.json",
|
|
139
85
|
geometricErrorMultiplier: 1,
|
|
140
86
|
loadOutsideView: true,
|
|
141
|
-
|
|
87
|
+
tileLoader: new TileLoader(mesh => {
|
|
142
88
|
//// Insert code to be called on every newly decoded mesh e.g.:
|
|
143
89
|
mesh.material.wireframe = false;
|
|
144
90
|
mesh.material.side = THREE.DoubleSide;
|
|
145
|
-
}
|
|
91
|
+
}, tilesetStats),
|
|
92
|
+
stats: tilesetStats
|
|
146
93
|
});
|
|
94
|
+
|
|
147
95
|
|
|
148
96
|
//// The OGC3DTile object is a threejs Object3D so you may do all the usual opperations like transformations e.g.:
|
|
149
97
|
//ogc3DTile.translateOnAxis(new THREE.Vector3(0,1,0), -10)
|
|
150
98
|
//ogc3DTile.translateOnAxis(new THREE.Vector3(1,0,0), -65)
|
|
151
99
|
//ogc3DTile.translateOnAxis(new THREE.Vector3(0,0,1), -80)
|
|
152
|
-
//ogc3DTile.scale.set(0.
|
|
153
|
-
//ogc3DTile.rotateOnAxis(new THREE.Vector3(1, 0, 0),
|
|
100
|
+
//ogc3DTile.scale.set(0.0001,0.0001,0.0001);
|
|
101
|
+
// ogc3DTile.rotateOnAxis(new THREE.Vector3(1, 0, 0), Math.PI * 0.5) // Z-UP to Y-UP
|
|
102
|
+
// ogc3DTile.translateOnAxis(new THREE.Vector3(1,0,0), -16.5)
|
|
103
|
+
// ogc3DTile.translateOnAxis(new THREE.Vector3(0,1,0), 0)
|
|
104
|
+
// ogc3DTile.translateOnAxis(new THREE.Vector3(0,0,1), -9.5)
|
|
154
105
|
//// It's up to the user to call updates on the tileset. You might call them whenever the camera moves or at regular time intervals like here
|
|
155
106
|
|
|
107
|
+
|
|
108
|
+
|
|
156
109
|
var interval ;
|
|
157
110
|
document.addEventListener('keyup', (e) => {
|
|
111
|
+
console.log(camera.position)
|
|
158
112
|
if(!e.key || e.key !== "p") return;
|
|
159
113
|
if(!!interval){
|
|
160
114
|
clearInterval(interval);
|
|
@@ -166,10 +120,9 @@ function initTileset(scene) {
|
|
|
166
120
|
function startInterval(){
|
|
167
121
|
interval = setInterval(function () {
|
|
168
122
|
ogc3DTile.update(camera);
|
|
169
|
-
},
|
|
123
|
+
}, 25);
|
|
170
124
|
}
|
|
171
125
|
startInterval();
|
|
172
|
-
|
|
173
126
|
|
|
174
127
|
scene.add(ogc3DTile)
|
|
175
128
|
return ogc3DTile;
|
|
@@ -178,9 +131,9 @@ function initTileset(scene) {
|
|
|
178
131
|
function initController(camera, dom) {
|
|
179
132
|
const controller = new OrbitControls(camera, dom);
|
|
180
133
|
|
|
181
|
-
controller.target.set(-
|
|
134
|
+
controller.target.set(-11.50895,0.058452500000001, 3.1369285);
|
|
182
135
|
controller.minDistance = 1;
|
|
183
|
-
controller.maxDistance =
|
|
136
|
+
controller.maxDistance = 5000;
|
|
184
137
|
controller.update();
|
|
185
138
|
return controller;
|
|
186
139
|
}
|
|
@@ -191,7 +144,7 @@ function animate() {
|
|
|
191
144
|
|
|
192
145
|
camera.updateMatrixWorld();
|
|
193
146
|
renderer.render(scene, camera);
|
|
194
|
-
|
|
147
|
+
tilesetStats.update();
|
|
195
148
|
stats.update();
|
|
196
149
|
|
|
197
150
|
}
|
package/src/tileset/OGC3DTile.js
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import { OBB } from "../geometry/obb";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { TileLoader } from "./TileLoader";
|
|
4
|
+
import { v4 as uuidv4 } from "uuid";
|
|
5
|
+
import { setIntervalAsync } from 'set-interval-async/dynamic';
|
|
6
|
+
// import { clearIntervalAsync } from 'set-interval-async';
|
|
5
7
|
const path = require('path');
|
|
6
8
|
|
|
7
|
-
const tilesToLoad = [];
|
|
8
|
-
function scheduleLoadTile(tile) {
|
|
9
|
-
tilesToLoad.push(tile);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
setInterval(() => {
|
|
13
|
-
const tile = tilesToLoad.shift();
|
|
14
|
-
if (!!tile) tile.load();
|
|
15
|
-
}, 5)
|
|
16
|
-
|
|
17
9
|
const tempSphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0, 1));
|
|
18
10
|
|
|
19
11
|
|
|
@@ -30,13 +22,41 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
30
22
|
* parentRefinement: optional,
|
|
31
23
|
* geometricErrorMultiplier: Double,
|
|
32
24
|
* loadOutsideView: Boolean,
|
|
33
|
-
*
|
|
25
|
+
* tileLoader : TileLoader,
|
|
26
|
+
* stats: TilesetStats,
|
|
27
|
+
* meshCallback: function
|
|
34
28
|
* } properties
|
|
35
29
|
*/
|
|
36
30
|
constructor(properties) {
|
|
37
31
|
super();
|
|
32
|
+
const self = this;
|
|
33
|
+
this.uuid = uuidv4();
|
|
34
|
+
if (!!properties.tileLoader) {
|
|
35
|
+
this.tileLoader = properties.tileLoader;
|
|
36
|
+
} else {
|
|
37
|
+
this.tileLoader = new TileLoader(!properties.meshCallback ?
|
|
38
|
+
mesh => {
|
|
39
|
+
mesh.material.wireframe = false;
|
|
40
|
+
mesh.material.side = THREE.DoubleSide;
|
|
41
|
+
} : properties.meshCallback);
|
|
42
|
+
}
|
|
38
43
|
// set properties general to the entire tileset
|
|
39
44
|
this.geometricErrorMultiplier = !!properties.geometricErrorMultiplier ? properties.geometricErrorMultiplier : 1.0;
|
|
45
|
+
if (properties.stats) {
|
|
46
|
+
// Automatic geometric error multiplier
|
|
47
|
+
this.stats = properties.stats;
|
|
48
|
+
setIntervalAsync(() => {
|
|
49
|
+
const framerate = self.stats.fps();
|
|
50
|
+
if (framerate < 0) return;
|
|
51
|
+
if (framerate < 58) {
|
|
52
|
+
self.setGeometricErrorMultiplier(Math.max(0.05, self.geometricErrorMultiplier - 0.05));
|
|
53
|
+
} else if (framerate > 58) {
|
|
54
|
+
self.setGeometricErrorMultiplier(self.geometricErrorMultiplier + 0.05);
|
|
55
|
+
}
|
|
56
|
+
self.setGeometricErrorMultiplier(self.geometricErrorMultiplier * (self.stats.fps() / 60));
|
|
57
|
+
}, 1000);
|
|
58
|
+
}
|
|
59
|
+
|
|
40
60
|
this.meshCallback = properties.meshCallback;
|
|
41
61
|
this.loadOutsideView = properties.loadOutsideView;
|
|
42
62
|
|
|
@@ -51,11 +71,10 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
51
71
|
this.json; // the json corresponding to this tile
|
|
52
72
|
this.materialVisibility = false;
|
|
53
73
|
this.inFrustum = true;
|
|
54
|
-
this.level = properties.level? properties.level : 0;
|
|
74
|
+
this.level = properties.level ? properties.level : 0;
|
|
55
75
|
this.hasMeshContent = false; // true when the provided json has a content field pointing to a B3DM file
|
|
56
76
|
this.hasUnloadedJSONContent = false; // true when the provided json has a content field pointing to a JSON file that is not yet loaded
|
|
57
77
|
|
|
58
|
-
const self = this;
|
|
59
78
|
if (!!properties.json) { // If this tile is created as a child of another tile, properties.json is not null
|
|
60
79
|
self.setup(properties);
|
|
61
80
|
} else if (properties.url) { // If only the url to the tileset.json is provided
|
|
@@ -95,9 +114,9 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
95
114
|
}
|
|
96
115
|
// decode transform
|
|
97
116
|
if (!!this.json.transform) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
this.
|
|
117
|
+
let mat = new THREE.Matrix4();
|
|
118
|
+
mat.elements = this.json.transform;
|
|
119
|
+
this.applyMatrix4(mat);
|
|
101
120
|
}
|
|
102
121
|
// decode volume
|
|
103
122
|
if (!!this.json.boundingVolume) {
|
|
@@ -124,11 +143,13 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
124
143
|
} else {
|
|
125
144
|
this.hasMeshContent = true;
|
|
126
145
|
}
|
|
127
|
-
|
|
146
|
+
this.load();
|
|
147
|
+
//scheduleLoadTile(this);
|
|
128
148
|
}
|
|
129
149
|
}
|
|
130
150
|
load() {
|
|
131
151
|
var self = this;
|
|
152
|
+
if (self.deleted) return;
|
|
132
153
|
if (!!self.json.content) {
|
|
133
154
|
let url;
|
|
134
155
|
if (!!self.json.content.uri) {
|
|
@@ -146,24 +167,24 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
146
167
|
}
|
|
147
168
|
|
|
148
169
|
if (!!url) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
170
|
+
if (url.includes(".b3dm")) {
|
|
171
|
+
self.contentURL = url;
|
|
172
|
+
self.tileLoader.get(this.uuid, url, mesh => {
|
|
173
|
+
if (!!self.deleted) return;
|
|
174
|
+
mesh.traverse((o) => {
|
|
175
|
+
if (o.isMesh) {
|
|
176
|
+
o.material.visible = false;
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
self.add(mesh);
|
|
180
|
+
self.meshContent = mesh;
|
|
181
|
+
})
|
|
182
|
+
} else if (url.includes(".json")) {
|
|
183
|
+
self.controller = new AbortController();
|
|
184
|
+
fetch(url, { signal: self.controller.signal }).then(result => {
|
|
185
|
+
if (!result.ok) {
|
|
186
|
+
throw new Error(`couldn't load "${properties.url}". Request failed with status ${result.status} : ${result.statusText}`);
|
|
187
|
+
}
|
|
167
188
|
result.json().then(json => {
|
|
168
189
|
// when json content is downloaded, it is inserted into this tile's original JSON as a child
|
|
169
190
|
// and the content object is deleted from the original JSON
|
|
@@ -173,54 +194,40 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
173
194
|
delete self.json.content;
|
|
174
195
|
self.hasUnloadedJSONContent = false;
|
|
175
196
|
}).catch(error => { });
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
197
|
+
}).catch(error => { });
|
|
198
|
+
}
|
|
199
|
+
|
|
179
200
|
}
|
|
180
201
|
}
|
|
181
202
|
}
|
|
182
203
|
|
|
183
|
-
|
|
184
|
-
var self = this;
|
|
204
|
+
dispose() {
|
|
185
205
|
|
|
186
|
-
self
|
|
206
|
+
const self = this;
|
|
207
|
+
self.deleted = true;
|
|
208
|
+
this.traverse(function (element) {
|
|
209
|
+
if (!!element.contentURL) {
|
|
210
|
+
self.tileLoader.invalidate(element.contentURL, element.uuid);
|
|
211
|
+
}
|
|
187
212
|
if (!!element.controller) { // abort tile request
|
|
188
213
|
element.controller.abort();
|
|
189
214
|
}
|
|
190
|
-
if (element.material) {
|
|
191
|
-
// dispose materials
|
|
192
|
-
if (element.material.length) {
|
|
193
|
-
for (let i = 0; i < element.material.length; ++i) {
|
|
194
|
-
element.material[i].dispose();
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
element.material.dispose()
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
if (element.geometry) {
|
|
203
|
-
// dispose geometry
|
|
204
|
-
element.geometry.dispose();
|
|
205
215
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
object.parent = null;
|
|
213
|
-
|
|
214
|
-
object.dispatchEvent({ type: 'removed' });
|
|
216
|
+
});
|
|
217
|
+
this.parent = null;
|
|
218
|
+
this.dispatchEvent({ type: 'removed' });
|
|
219
|
+
}
|
|
220
|
+
disposeChildren() {
|
|
221
|
+
var self = this;
|
|
215
222
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if (!!
|
|
223
|
+
self.childrenTiles.forEach(tile => tile.dispose());
|
|
224
|
+
self.childrenTiles = [];
|
|
225
|
+
self.children = [];
|
|
226
|
+
if (!!self.meshContent) self.children.push(self.meshContent);
|
|
220
227
|
}
|
|
221
228
|
|
|
222
229
|
|
|
223
|
-
update(camera){
|
|
230
|
+
update(camera) {
|
|
224
231
|
const frustum = new THREE.Frustum();
|
|
225
232
|
frustum.setFromProjectionMatrix(new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
|
|
226
233
|
this._update(camera, frustum);
|
|
@@ -228,19 +235,19 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
228
235
|
_update(camera, frustum) {
|
|
229
236
|
const self = this;
|
|
230
237
|
|
|
238
|
+
self.childrenTiles.forEach(child => child._update(camera, frustum));
|
|
231
239
|
if (!!self.boundingVolume && !!self.geometricError) {
|
|
232
|
-
|
|
240
|
+
self.metric = self.calculateUpdateMetric(camera, frustum);
|
|
233
241
|
}
|
|
234
242
|
|
|
235
|
-
|
|
236
|
-
self.
|
|
237
|
-
|
|
238
|
-
trimTree(metric);
|
|
243
|
+
updateNodeVisibility(self.metric);
|
|
244
|
+
updateTree(self.metric);
|
|
245
|
+
trimTree(self.metric);
|
|
239
246
|
|
|
240
247
|
|
|
241
248
|
function updateTree(metric) {
|
|
242
249
|
// If this tile does not have mesh content but it has children
|
|
243
|
-
if(metric<0 && self.hasMeshContent) return;
|
|
250
|
+
if (metric < 0 && self.hasMeshContent) return;
|
|
244
251
|
if (!self.hasMeshContent || (metric < self.geometricError && !!self.meshContent)) {
|
|
245
252
|
if (!!self.json && !!self.json.children && self.childrenTiles.length != self.json.children.length) {
|
|
246
253
|
loadJsonChildren();
|
|
@@ -255,7 +262,7 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
255
262
|
if (!self.hasMeshContent) return;
|
|
256
263
|
|
|
257
264
|
// mesh content not yet loaded
|
|
258
|
-
if(!self.meshContent) {
|
|
265
|
+
if (!self.meshContent) {
|
|
259
266
|
return;
|
|
260
267
|
}
|
|
261
268
|
|
|
@@ -264,7 +271,7 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
264
271
|
self.inFrustum = false;
|
|
265
272
|
self.changeContentVisibility(!!self.loadOutsideView);
|
|
266
273
|
return;
|
|
267
|
-
}else{
|
|
274
|
+
} else {
|
|
268
275
|
self.inFrustum = true;
|
|
269
276
|
}
|
|
270
277
|
|
|
@@ -282,7 +289,7 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
282
289
|
// if children are visible and have been displayed, can be hidden
|
|
283
290
|
var allChildrenReady = true;
|
|
284
291
|
self.childrenTiles.every(child => {
|
|
285
|
-
|
|
292
|
+
|
|
286
293
|
if (!child.isReady()) {
|
|
287
294
|
allChildrenReady = false;
|
|
288
295
|
return false;
|
|
@@ -291,8 +298,9 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
291
298
|
});
|
|
292
299
|
if (allChildrenReady) {
|
|
293
300
|
self.changeContentVisibility(false);
|
|
294
|
-
}else{
|
|
295
|
-
self.changeContentVisibility(true);
|
|
301
|
+
} else {
|
|
302
|
+
//self.changeContentVisibility(true);
|
|
303
|
+
|
|
296
304
|
}
|
|
297
305
|
}
|
|
298
306
|
}
|
|
@@ -309,7 +317,7 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
309
317
|
return;
|
|
310
318
|
}
|
|
311
319
|
}
|
|
312
|
-
|
|
320
|
+
|
|
313
321
|
}
|
|
314
322
|
|
|
315
323
|
function loadJsonChildren() {
|
|
@@ -321,9 +329,9 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
321
329
|
json: childJSON,
|
|
322
330
|
rootPath: self.rootPath,
|
|
323
331
|
geometricErrorMultiplier: self.geometricErrorMultiplier,
|
|
324
|
-
meshCallback: self.meshCallback,
|
|
325
332
|
loadOutsideView: self.loadOutsideView,
|
|
326
|
-
level:self.level+1
|
|
333
|
+
level: self.level + 1,
|
|
334
|
+
tileLoader: self.tileLoader
|
|
327
335
|
});
|
|
328
336
|
self.childrenTiles.push(childTile);
|
|
329
337
|
self.add(childTile);
|
|
@@ -338,13 +346,13 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
338
346
|
*/
|
|
339
347
|
isReady() {
|
|
340
348
|
// if outside frustum
|
|
341
|
-
if(!this.inFrustum) return true;
|
|
349
|
+
if (!this.inFrustum) return true;
|
|
342
350
|
|
|
343
351
|
// if json is not done loading
|
|
344
352
|
if (this.hasUnloadedJSONContent) return false;
|
|
345
353
|
|
|
346
354
|
// if this tile has no mesh content or if it's marked as visible false, look at children
|
|
347
|
-
if ((!this.hasMeshContent || !this.meshContent || !this.materialVisibility) && this.childrenTiles.length>0) {
|
|
355
|
+
if ((!this.hasMeshContent || !this.meshContent || !this.materialVisibility) && this.childrenTiles.length > 0) {
|
|
348
356
|
var allChildrenReady = true;
|
|
349
357
|
this.childrenTiles.every(child => {
|
|
350
358
|
if (!child.isReady()) {
|
|
@@ -357,11 +365,11 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
357
365
|
}
|
|
358
366
|
|
|
359
367
|
// if this tile has no mesh content
|
|
360
|
-
if(!this.hasMeshContent){
|
|
368
|
+
if (!this.hasMeshContent) {
|
|
361
369
|
return true;
|
|
362
370
|
}
|
|
363
371
|
// if mesh content not yet loaded
|
|
364
|
-
if(!this.meshContent) {
|
|
372
|
+
if (!this.meshContent) {
|
|
365
373
|
return false;
|
|
366
374
|
}
|
|
367
375
|
|
|
@@ -375,11 +383,12 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
375
383
|
return true;
|
|
376
384
|
}
|
|
377
385
|
|
|
378
|
-
return
|
|
379
|
-
|
|
386
|
+
return true;
|
|
387
|
+
|
|
380
388
|
}
|
|
381
389
|
|
|
382
|
-
|
|
390
|
+
|
|
391
|
+
|
|
383
392
|
|
|
384
393
|
changeContentVisibility(visibility) {
|
|
385
394
|
const self = this;
|
|
@@ -437,8 +446,8 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
437
446
|
if (distance == 0) {
|
|
438
447
|
return 0;
|
|
439
448
|
}
|
|
440
|
-
const scale = this.matrixWorld.getMaxScaleOnAxis
|
|
441
|
-
return ((distance / 100) / this.geometricErrorMultiplier)/scale;
|
|
449
|
+
const scale = this.matrixWorld.getMaxScaleOnAxis();
|
|
450
|
+
return ((distance / 100) / this.geometricErrorMultiplier) / scale;
|
|
442
451
|
} else if (this.boundingVolume instanceof THREE.Box3) {
|
|
443
452
|
// Region
|
|
444
453
|
// Region not supported
|
|
@@ -453,28 +462,4 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
453
462
|
this.childrenTiles.forEach(child => child.setGeometricErrorMultiplier(geometricErrorMultiplier));
|
|
454
463
|
}
|
|
455
464
|
}
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
*
|
|
459
|
-
* @param {Integer} size a number of vertices
|
|
460
|
-
*/
|
|
461
|
-
function createMeshCache(size = 5000000, meshCallback = ()=>{}){
|
|
462
|
-
/* return new Cache(
|
|
463
|
-
(url, self)=>{
|
|
464
|
-
fetch(url, { signal: self.controller.signal }).then(result => {
|
|
465
|
-
if (!result.ok) {
|
|
466
|
-
throw new Error(`couldn't load "${properties.url}". Request failed with status ${result.status} : ${result.statusText}`);
|
|
467
|
-
}
|
|
468
|
-
result.arrayBuffer().then(buffer => B3DMDecoder.parseB3DM(buffer, self.meshCallback)).then(mesh => {
|
|
469
|
-
mesh.traverse((o) => {
|
|
470
|
-
if (o.isMesh) {
|
|
471
|
-
o.material.visible = false;
|
|
472
|
-
}
|
|
473
|
-
});
|
|
474
|
-
return mesh;
|
|
475
|
-
}).catch(error => { });
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
) */
|
|
479
|
-
}
|
|
480
|
-
export { OGC3DTile, createMeshCache };
|
|
465
|
+
export { OGC3DTile };
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { LinkedHashMap } from 'js-utils-z';
|
|
2
|
+
import { B3DMDecoder } from "../decoder/B3DMDecoder";
|
|
3
|
+
import { setIntervalAsync } from 'set-interval-async/dynamic';
|
|
4
|
+
|
|
5
|
+
const ready = [];
|
|
6
|
+
const downloads = [];
|
|
7
|
+
function scheduleDownload(f) {
|
|
8
|
+
downloads.unshift(f);
|
|
9
|
+
}
|
|
10
|
+
function download() {
|
|
11
|
+
if(downloads.length <=0) return;
|
|
12
|
+
const nextDownload = downloads.shift();
|
|
13
|
+
if (!!nextDownload && nextDownload.shouldDoDownload()) {
|
|
14
|
+
nextDownload.doDownload();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function meshReceived(cache, register, key) {
|
|
18
|
+
ready.unshift([cache, register, key]);
|
|
19
|
+
}
|
|
20
|
+
function loadBatch() {
|
|
21
|
+
for (let i = 0; i < 1; i++) {
|
|
22
|
+
const data = ready.shift();
|
|
23
|
+
if (!data) return;
|
|
24
|
+
const cache = data[0];
|
|
25
|
+
const register = data[1];
|
|
26
|
+
const key = data[2];
|
|
27
|
+
const mesh = cache.get(key);
|
|
28
|
+
if (!!mesh) {
|
|
29
|
+
Object.keys(register[key]).forEach(tile => {
|
|
30
|
+
const callback = register[key][tile];
|
|
31
|
+
if (!!callback) {
|
|
32
|
+
callback(mesh);
|
|
33
|
+
register[key][tile] = null;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
setIntervalAsync(() => {
|
|
40
|
+
loadBatch();
|
|
41
|
+
}, 10)
|
|
42
|
+
setIntervalAsync(() => {
|
|
43
|
+
download();
|
|
44
|
+
}, 10)
|
|
45
|
+
|
|
46
|
+
class TileLoader {
|
|
47
|
+
constructor(meshCallback, stats) {
|
|
48
|
+
this.meshCallback = meshCallback;
|
|
49
|
+
this.cache = new LinkedHashMap();
|
|
50
|
+
this.maxSize = 1000;
|
|
51
|
+
this.stats = stats;
|
|
52
|
+
this.register = {};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get(tileIdentifier, path, callback) {
|
|
56
|
+
const self = this;
|
|
57
|
+
const key = simplifyPath(path);
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
if (!path.includes(".b3dm")) {
|
|
61
|
+
console.error("the 3DTiles cache can only be used to load B3DM data");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!self.register[key]) {
|
|
65
|
+
self.register[key] = {};
|
|
66
|
+
}
|
|
67
|
+
if (!!self.register[key][tileIdentifier]) {
|
|
68
|
+
console.error(" a tile should only be loaded once");
|
|
69
|
+
}
|
|
70
|
+
self.register[key][tileIdentifier] = callback;
|
|
71
|
+
|
|
72
|
+
const cachedObject = self.cache.get(key);
|
|
73
|
+
if (!!cachedObject) {
|
|
74
|
+
meshReceived(self.cache, self.register, key);
|
|
75
|
+
} else if (Object.keys(self.register[key]).length == 1) {
|
|
76
|
+
scheduleDownload({
|
|
77
|
+
"shouldDoDownload":()=>{
|
|
78
|
+
return Object.keys(self.register[key]).length > 0;
|
|
79
|
+
},
|
|
80
|
+
"doDownload": () => {
|
|
81
|
+
fetch(path).then(result => {
|
|
82
|
+
if (!result.ok) {
|
|
83
|
+
console.error("could not load tile with path : " + path)
|
|
84
|
+
throw new Error(`couldn't load "${path}". Request failed with status ${result.status} : ${result.statusText}`);
|
|
85
|
+
}
|
|
86
|
+
result.arrayBuffer().then(buffer => B3DMDecoder.parseB3DM(buffer, self.meshCallback)).then(mesh => {
|
|
87
|
+
self.cache.put(key, mesh);
|
|
88
|
+
self.checkSize();
|
|
89
|
+
meshReceived(self.cache, self.register, key);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
meshReceived(key, mesh) {
|
|
99
|
+
const self = this;
|
|
100
|
+
Object.keys(self.register[key]).forEach(tile => {
|
|
101
|
+
const callback = self.register[key][tile];
|
|
102
|
+
if (!!callback) {
|
|
103
|
+
callback(mesh);
|
|
104
|
+
self.register[key][tile] = null;
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
invalidate(path, tileIdentifier) {
|
|
110
|
+
const key = simplifyPath(path);
|
|
111
|
+
delete this.register[key][tileIdentifier];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
checkSize() {
|
|
115
|
+
const self = this;
|
|
116
|
+
|
|
117
|
+
let i = 0;
|
|
118
|
+
function memOverflowCheck(){
|
|
119
|
+
if(!!self.stats && self.stats.memory()>0){
|
|
120
|
+
if(self.stats.memory()/self.stats.maxMemory()<0.25){
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
return self.cache.size() > self.maxSize;
|
|
126
|
+
}
|
|
127
|
+
while (memOverflowCheck() && i < self.cache.size()) {
|
|
128
|
+
i++;
|
|
129
|
+
const entry = self.cache.head();
|
|
130
|
+
if (Object.keys(self.register[entry.key]).length > 0) {
|
|
131
|
+
self.cache.remove(entry.key);
|
|
132
|
+
self.cache.put(entry.key, entry.value);
|
|
133
|
+
} else {
|
|
134
|
+
self.cache.remove(entry.key);
|
|
135
|
+
delete self.register[entry.key];
|
|
136
|
+
entry.value.traverse((o) => {
|
|
137
|
+
|
|
138
|
+
if (o.material) {
|
|
139
|
+
// dispose materials
|
|
140
|
+
if (o.material.length) {
|
|
141
|
+
for (let i = 0; i < o.material.length; ++i) {
|
|
142
|
+
o.material[i].dispose();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
o.material.dispose()
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (o.geometry) {
|
|
150
|
+
// dispose geometry
|
|
151
|
+
o.geometry.dispose();
|
|
152
|
+
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function simplifyPath(main_path) {
|
|
161
|
+
|
|
162
|
+
var parts = main_path.split('/'),
|
|
163
|
+
new_path = [],
|
|
164
|
+
length = 0;
|
|
165
|
+
for (var i = 0; i < parts.length; i++) {
|
|
166
|
+
var part = parts[i];
|
|
167
|
+
if (part === '.' || part === '' || part === '..') {
|
|
168
|
+
if (part === '..' && length > 0) {
|
|
169
|
+
length--;
|
|
170
|
+
}
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
new_path[length++] = part;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (length === 0) {
|
|
177
|
+
return '/';
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
var result = '';
|
|
181
|
+
for (var i = 0; i < length; i++) {
|
|
182
|
+
result += '/' + new_path[i];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return result;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export { TileLoader };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
var TilesetStats = function () {
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var beginTime = ( performance || Date ).now(), prevTime = beginTime, frames = 0;
|
|
5
|
+
|
|
6
|
+
var fps = -1;
|
|
7
|
+
|
|
8
|
+
if ( self.performance && self.performance.memory ) {
|
|
9
|
+
|
|
10
|
+
var mem = -1;
|
|
11
|
+
var maxMem = -1;
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
|
|
18
|
+
begin: function () {
|
|
19
|
+
|
|
20
|
+
beginTime = ( performance || Date ).now();
|
|
21
|
+
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
end: function () {
|
|
25
|
+
|
|
26
|
+
frames ++;
|
|
27
|
+
|
|
28
|
+
var time = ( performance || Date ).now();
|
|
29
|
+
|
|
30
|
+
if ( time >= prevTime + 1000 ) {
|
|
31
|
+
|
|
32
|
+
fps = ( frames * 1000 ) / ( time - prevTime );
|
|
33
|
+
|
|
34
|
+
prevTime = time;
|
|
35
|
+
frames = 0;
|
|
36
|
+
|
|
37
|
+
if ( !!mem ) {
|
|
38
|
+
|
|
39
|
+
var memory = performance.memory;
|
|
40
|
+
mem = memory.usedJSHeapSize;
|
|
41
|
+
maxMem = memory.jsHeapSizeLimit;
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return time;
|
|
48
|
+
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
update: function () {
|
|
52
|
+
|
|
53
|
+
beginTime = this.end();
|
|
54
|
+
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
fps: ()=>fps,
|
|
58
|
+
memory: ()=>mem,
|
|
59
|
+
maxMemory: ()=>maxMem
|
|
60
|
+
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export default TilesetStats;
|
package/webpack.config.js
CHANGED
|
@@ -83,19 +83,13 @@ module.exports = {
|
|
|
83
83
|
}]
|
|
84
84
|
},
|
|
85
85
|
{
|
|
86
|
-
test: /\.(png|gif)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
options: {
|
|
90
|
-
name: "images/[name].[contenthash].[ext]"
|
|
91
|
-
}
|
|
92
|
-
}]
|
|
93
|
-
}
|
|
86
|
+
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
|
87
|
+
type: 'asset/resource',
|
|
88
|
+
},
|
|
94
89
|
],
|
|
95
90
|
},
|
|
96
91
|
optimization: {
|
|
97
92
|
minimizer: [new TerserPlugin({
|
|
98
|
-
cache: true,
|
|
99
93
|
parallel: true,
|
|
100
94
|
terserOptions: {
|
|
101
95
|
ecma: undefined,
|
|
@@ -119,8 +113,14 @@ module.exports = {
|
|
|
119
113
|
devServer: {
|
|
120
114
|
hot: true,
|
|
121
115
|
open: true,
|
|
122
|
-
openPage: "",
|
|
123
116
|
port: DEFAULT_WEBPACK_PORT
|
|
117
|
+
},
|
|
118
|
+
resolve: {
|
|
119
|
+
extensions: [".js", ".jsx", ".json", ".ts", ".tsx"],// other stuff
|
|
120
|
+
fallback: {
|
|
121
|
+
"fs": false,
|
|
122
|
+
"path": require.resolve("path-browserify")
|
|
123
|
+
}
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
};
|
package/src/cache/Cache.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { LinkedHashMap } from 'js-utils-z';
|
|
3
|
-
|
|
4
|
-
class Cache {
|
|
5
|
-
constructor(loader, counter, dispose, max) {
|
|
6
|
-
this.loader = loader;
|
|
7
|
-
this.counter = counter;
|
|
8
|
-
this.dispose = dispose;
|
|
9
|
-
this.max = max;
|
|
10
|
-
this.currentSize = 0;
|
|
11
|
-
this.objects = new LinkedHashMap();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
get(name){
|
|
15
|
-
if(this.objects.has(name)){
|
|
16
|
-
const item = this.objects.remove(name);
|
|
17
|
-
item.users++;
|
|
18
|
-
this.objects.put(name, item, false);
|
|
19
|
-
return new Promise.resolve({dispose:()=>item.users--,content:item.content});
|
|
20
|
-
}else{
|
|
21
|
-
return this.loader(name).then(content=>{
|
|
22
|
-
const item = { users: 1, content: content };
|
|
23
|
-
this.objects.put(name, item, false);
|
|
24
|
-
currentSize+=this.counter(item);
|
|
25
|
-
checkSize();
|
|
26
|
-
return {dispose:()=>item.users--,content:item.content};
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
checkSize(){
|
|
32
|
-
let object = this.objects.head();
|
|
33
|
-
while(this.currentSize > this.max && !!object){
|
|
34
|
-
if(object.value.users <=0){
|
|
35
|
-
const item = this.objects.remove(object.key);
|
|
36
|
-
this.currentSize -= this.counter(item.content);
|
|
37
|
-
this.dispose(item.content);
|
|
38
|
-
}
|
|
39
|
-
object = object.next();
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export{Cache};
|