@jdultra/threedtiles 3.0.7 → 3.1.2
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/README.md +50 -4
- package/index.html +1 -43
- package/manifest.json +4 -0
- 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 +24 -73
- package/src/tileset/OGC3DTile.js +88 -104
- 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/README.md
CHANGED
|
@@ -14,7 +14,7 @@ import { OGC3DTile } from "./tileset/OGC3DTile";
|
|
|
14
14
|
...
|
|
15
15
|
|
|
16
16
|
const ogc3DTile = new OGC3DTile({
|
|
17
|
-
url: "https://
|
|
17
|
+
url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json"
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
scene.add(ogc3DTile);
|
|
@@ -33,6 +33,9 @@ setInterval(function () {
|
|
|
33
33
|
- Allows tilesets transformations. Translate, scale and rotate a tilesets in real-time.
|
|
34
34
|
- callback on loaded geometry to assign a custom material or use the meshes for computations.
|
|
35
35
|
- Optionally load low detail tiles outside of view frustum for correct shadows and basic mesh present when the camera moves quickly.
|
|
36
|
+
- Share a cache between tileset instances
|
|
37
|
+
- Automatically tune the geometric error multiplier to 60 FPS
|
|
38
|
+
- Automatic scaling of the cache
|
|
36
39
|
|
|
37
40
|
### geometric Error Multiplier
|
|
38
41
|
The geometric error multiplier allows you to multiply the geometric error by a factor.
|
|
@@ -43,20 +46,43 @@ you may also set this value at initialization:
|
|
|
43
46
|
|
|
44
47
|
```
|
|
45
48
|
const ogc3DTile = new OGC3DTile({
|
|
46
|
-
url: "https://
|
|
49
|
+
url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
|
|
47
50
|
geometricErrorMultiplier: 2.0
|
|
48
51
|
});
|
|
49
52
|
```
|
|
50
53
|
A lower value will result in lower detail tiles being loaded and a higher value results in higher detail tiles being loaded.
|
|
51
54
|
A value of 1.0 is the default.
|
|
52
55
|
|
|
56
|
+
#### Automatic Geometric error multiplier
|
|
57
|
+
In order to reach a steady 60 FPS, you can specify a TilesetStats object.
|
|
58
|
+
This object is basically the Stats object from the Three.js samples without the UI component.
|
|
59
|
+
It must be updated in the animate function and given to the tileset at construction.
|
|
60
|
+
```
|
|
61
|
+
import TilesetStats from '@jdultra/threedtiles/src/tileset/TilesetStats';
|
|
62
|
+
|
|
63
|
+
const tilesetStats = TilesetStats();
|
|
64
|
+
|
|
65
|
+
const ogc3DTile = new OGC3DTile({
|
|
66
|
+
url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
|
|
67
|
+
stats: tilesetStats
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
function animate() {
|
|
71
|
+
|
|
72
|
+
...
|
|
73
|
+
|
|
74
|
+
tilesetStats.update();
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
|
|
53
79
|
### load tiles outside of view
|
|
54
80
|
By default, only the tiles that intersect the view frustum are loaded. When the camera moves, the scene will have to load the missing tiles.
|
|
55
81
|
Instead of this behaviour, you can force the lowest possible LODs to be loaded for tiles around the view so that there are no gaps in the mesh when the camera moves or when displaying shadows.
|
|
56
82
|
|
|
57
83
|
```
|
|
58
84
|
const ogc3DTile = new OGC3DTile({
|
|
59
|
-
url: "https://
|
|
85
|
+
url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
|
|
60
86
|
loadOutsideView: true
|
|
61
87
|
});
|
|
62
88
|
```
|
|
@@ -66,13 +92,33 @@ Add a callback on loaded tiles in order to set a material or do some logic on th
|
|
|
66
92
|
|
|
67
93
|
```
|
|
68
94
|
const ogc3DTile = new OGC3DTile({
|
|
69
|
-
url: "https://
|
|
95
|
+
url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
|
|
70
96
|
meshCallback: mesh => {
|
|
71
97
|
mesh.material.wireframe = true;
|
|
72
98
|
}
|
|
73
99
|
});
|
|
74
100
|
```
|
|
75
101
|
|
|
102
|
+
### Cache
|
|
103
|
+
You may instanciate a cache through the TileLoader class and re-use it for several or all your tilesets.
|
|
104
|
+
The limitation is that all the tilesets using the same cache will have the same callback.
|
|
105
|
+
|
|
106
|
+
If a TilesetStats object is passed, it will be used to monitor the size of the cache when the browser allows it, otherwise, each cache is limitted to 1000 items.
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
import { TileLoader } from "@jdultra/threedtiles/src/tileset/TileLoader";
|
|
110
|
+
|
|
111
|
+
const ogc3DTile = new OGC3DTile({
|
|
112
|
+
url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
|
|
113
|
+
tileLoader: new TileLoader(mesh => {
|
|
114
|
+
//// Insert code to be called on every newly decoded mesh e.g.:
|
|
115
|
+
mesh.material.wireframe = false;
|
|
116
|
+
mesh.material.side = THREE.DoubleSide;
|
|
117
|
+
}, tilesetStats),
|
|
118
|
+
meshCallback: mesh => { mesh.material.wireframe = true;} // This callback will not be used as the callback provided to the TileLoader takes priority
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
76
122
|
### Transformations
|
|
77
123
|
The OGC 3DTile object is a regular three.js Object3D so it can be transformed via the standard three.js API:
|
|
78
124
|
|
package/index.html
CHANGED
|
@@ -4,53 +4,11 @@
|
|
|
4
4
|
<head>
|
|
5
5
|
<meta charset="utf-8" />
|
|
6
6
|
<title>Three 3DTiles viewer sample</title>
|
|
7
|
-
<
|
|
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>
|
|
7
|
+
<link rel="manifest" href="manifest.json">
|
|
46
8
|
</head>
|
|
47
9
|
|
|
48
10
|
<body>
|
|
49
11
|
<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
12
|
<div style="position: absolute; bottom: 1%; z-index: 100;">
|
|
55
13
|
<a href="https://openheritage3d.org/project.php?id=taz6-n215">ORIGINAL MODEL</a>
|
|
56
14
|
</div>
|
package/manifest.json
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jdultra/threedtiles",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.2",
|
|
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,28 @@
|
|
|
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
|
|
|
8
10
|
const scene = initScene();
|
|
11
|
+
const tilesetStats = TilesetStats();
|
|
9
12
|
const domContainer = initDomContainer("screen");
|
|
10
13
|
const camera = initCamera();
|
|
11
14
|
const ogc3DTiles = initTileset(scene);
|
|
12
|
-
initLODMultiplierSlider(ogc3DTiles);
|
|
13
15
|
const controller = initController(camera, domContainer);
|
|
14
|
-
const skybox = initSkybox(controller, camera, scene);
|
|
15
16
|
|
|
16
17
|
const stats = initStats(domContainer);
|
|
17
18
|
const renderer = initRenderer(camera, domContainer);
|
|
18
19
|
|
|
19
20
|
animate();
|
|
20
21
|
|
|
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
|
-
|
|
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
22
|
function initScene() {
|
|
63
23
|
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);
|
|
24
|
+
scene.background = new THREE.Color(0x000000);
|
|
25
|
+
scene.add(new THREE.AmbientLight(0xFFFFFF, 1.0));
|
|
73
26
|
return scene;
|
|
74
27
|
}
|
|
75
28
|
|
|
@@ -109,16 +62,15 @@ function initRenderer(camera, dom) {
|
|
|
109
62
|
}
|
|
110
63
|
|
|
111
64
|
function initStats(dom) {
|
|
112
|
-
const stats =
|
|
113
|
-
|
|
65
|
+
const stats = Stats();
|
|
66
|
+
document.body.appendChild(stats.dom);
|
|
114
67
|
return stats;
|
|
115
68
|
}
|
|
116
69
|
|
|
117
70
|
|
|
118
71
|
function initCamera() {
|
|
119
72
|
const camera = new THREE.PerspectiveCamera(70, window.offsetWidth / window.offsetHeight, 1, 10000);
|
|
120
|
-
camera.position.set(
|
|
121
|
-
camera.lookAt(-100, 0, 0);
|
|
73
|
+
camera.position.set(10, 10, 10);
|
|
122
74
|
|
|
123
75
|
return camera;
|
|
124
76
|
}
|
|
@@ -127,33 +79,33 @@ function initTileset(scene) {
|
|
|
127
79
|
|
|
128
80
|
const ogc3DTile = new OGC3DTile({
|
|
129
81
|
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: "https://storage.googleapis.com/ogc-3d-tiles/berlinSubsetTiled/tileset.json",
|
|
132
|
-
//url: "https://storage.googleapis.com/ogc-3d-tiles/ayutthaya/tileset.json",
|
|
133
|
-
//url: "https://s3.us-east-2.wasabisys.com/construkted-assets/arkcnfuk9fw/tileset.json",
|
|
134
|
-
//url: "https://s3.us-east-2.wasabisys.com/construkted-assets/a73faxnydqk/tileset.json",
|
|
135
|
-
//url: "https://s3.us-east-2.wasabisys.com/construkted-assets/e63mubnpmg/tileset.json",
|
|
136
|
-
//url: "https://assets.cesium.com/697512/tileset.json?v=1",
|
|
137
|
-
//url:"https://a.3d.blc.shc.eu/WAB/base_layer/cesium_mesh_2020/tileset.json",
|
|
138
82
|
geometricErrorMultiplier: 1,
|
|
139
83
|
loadOutsideView: true,
|
|
140
|
-
|
|
84
|
+
tileLoader: new TileLoader(mesh => {
|
|
141
85
|
//// Insert code to be called on every newly decoded mesh e.g.:
|
|
142
86
|
mesh.material.wireframe = false;
|
|
143
87
|
mesh.material.side = THREE.DoubleSide;
|
|
144
|
-
}
|
|
88
|
+
}, tilesetStats),
|
|
89
|
+
stats: tilesetStats
|
|
145
90
|
});
|
|
91
|
+
|
|
146
92
|
|
|
147
93
|
//// The OGC3DTile object is a threejs Object3D so you may do all the usual opperations like transformations e.g.:
|
|
148
94
|
//ogc3DTile.translateOnAxis(new THREE.Vector3(0,1,0), -10)
|
|
149
95
|
//ogc3DTile.translateOnAxis(new THREE.Vector3(1,0,0), -65)
|
|
150
96
|
//ogc3DTile.translateOnAxis(new THREE.Vector3(0,0,1), -80)
|
|
151
|
-
//ogc3DTile.scale.set(0.
|
|
152
|
-
//ogc3DTile.rotateOnAxis(new THREE.Vector3(1, 0, 0),
|
|
97
|
+
//ogc3DTile.scale.set(0.0001,0.0001,0.0001);
|
|
98
|
+
// ogc3DTile.rotateOnAxis(new THREE.Vector3(1, 0, 0), Math.PI * 0.5) // Z-UP to Y-UP
|
|
99
|
+
// ogc3DTile.translateOnAxis(new THREE.Vector3(1,0,0), -16.5)
|
|
100
|
+
// ogc3DTile.translateOnAxis(new THREE.Vector3(0,1,0), 0)
|
|
101
|
+
// ogc3DTile.translateOnAxis(new THREE.Vector3(0,0,1), -9.5)
|
|
153
102
|
//// 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
|
|
154
103
|
|
|
104
|
+
|
|
105
|
+
|
|
155
106
|
var interval ;
|
|
156
107
|
document.addEventListener('keyup', (e) => {
|
|
108
|
+
console.log(camera.position)
|
|
157
109
|
if(!e.key || e.key !== "p") return;
|
|
158
110
|
if(!!interval){
|
|
159
111
|
clearInterval(interval);
|
|
@@ -165,10 +117,9 @@ function initTileset(scene) {
|
|
|
165
117
|
function startInterval(){
|
|
166
118
|
interval = setInterval(function () {
|
|
167
119
|
ogc3DTile.update(camera);
|
|
168
|
-
},
|
|
120
|
+
}, 25);
|
|
169
121
|
}
|
|
170
122
|
startInterval();
|
|
171
|
-
|
|
172
123
|
|
|
173
124
|
scene.add(ogc3DTile)
|
|
174
125
|
return ogc3DTile;
|
|
@@ -177,9 +128,9 @@ function initTileset(scene) {
|
|
|
177
128
|
function initController(camera, dom) {
|
|
178
129
|
const controller = new OrbitControls(camera, dom);
|
|
179
130
|
|
|
180
|
-
controller.target.set(-
|
|
131
|
+
controller.target.set(-11.50895,0.058452500000001, 3.1369285);
|
|
181
132
|
controller.minDistance = 1;
|
|
182
|
-
controller.maxDistance =
|
|
133
|
+
controller.maxDistance = 5000;
|
|
183
134
|
controller.update();
|
|
184
135
|
return controller;
|
|
185
136
|
}
|
|
@@ -190,7 +141,7 @@ function animate() {
|
|
|
190
141
|
|
|
191
142
|
camera.updateMatrixWorld();
|
|
192
143
|
renderer.render(scene, camera);
|
|
193
|
-
|
|
144
|
+
tilesetStats.update();
|
|
194
145
|
stats.update();
|
|
195
146
|
|
|
196
147
|
}
|
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,42 @@ 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
|
+
|
|
49
|
+
setIntervalAsync(() => {
|
|
50
|
+
if (!!document.hidden) return;
|
|
51
|
+
const framerate = self.stats.fps();
|
|
52
|
+
if (framerate < 0) return;
|
|
53
|
+
if (framerate < 58) {
|
|
54
|
+
self.setGeometricErrorMultiplier(Math.max(0.05, self.geometricErrorMultiplier - 0.05));
|
|
55
|
+
} else if (framerate > 58) {
|
|
56
|
+
self.setGeometricErrorMultiplier(self.geometricErrorMultiplier + 0.05);
|
|
57
|
+
}
|
|
58
|
+
}, 1000);
|
|
59
|
+
}
|
|
60
|
+
|
|
40
61
|
this.meshCallback = properties.meshCallback;
|
|
41
62
|
this.loadOutsideView = properties.loadOutsideView;
|
|
42
63
|
|
|
@@ -55,7 +76,6 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
55
76
|
this.hasMeshContent = false; // true when the provided json has a content field pointing to a B3DM file
|
|
56
77
|
this.hasUnloadedJSONContent = false; // true when the provided json has a content field pointing to a JSON file that is not yet loaded
|
|
57
78
|
|
|
58
|
-
const self = this;
|
|
59
79
|
if (!!properties.json) { // If this tile is created as a child of another tile, properties.json is not null
|
|
60
80
|
self.setup(properties);
|
|
61
81
|
} else if (properties.url) { // If only the url to the tileset.json is provided
|
|
@@ -95,9 +115,9 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
95
115
|
}
|
|
96
116
|
// decode transform
|
|
97
117
|
if (!!this.json.transform) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
this.
|
|
118
|
+
let mat = new THREE.Matrix4();
|
|
119
|
+
mat.elements = this.json.transform;
|
|
120
|
+
this.applyMatrix4(mat);
|
|
101
121
|
}
|
|
102
122
|
// decode volume
|
|
103
123
|
if (!!this.json.boundingVolume) {
|
|
@@ -124,11 +144,13 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
124
144
|
} else {
|
|
125
145
|
this.hasMeshContent = true;
|
|
126
146
|
}
|
|
127
|
-
|
|
147
|
+
this.load();
|
|
148
|
+
//scheduleLoadTile(this);
|
|
128
149
|
}
|
|
129
150
|
}
|
|
130
151
|
load() {
|
|
131
152
|
var self = this;
|
|
153
|
+
if (self.deleted) return;
|
|
132
154
|
if (!!self.json.content) {
|
|
133
155
|
let url;
|
|
134
156
|
if (!!self.json.content.uri) {
|
|
@@ -146,24 +168,24 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
146
168
|
}
|
|
147
169
|
|
|
148
170
|
if (!!url) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
171
|
+
if (url.includes(".b3dm")) {
|
|
172
|
+
self.contentURL = url;
|
|
173
|
+
self.tileLoader.get(this.uuid, url, mesh => {
|
|
174
|
+
if (!!self.deleted) return;
|
|
175
|
+
mesh.traverse((o) => {
|
|
176
|
+
if (o.isMesh) {
|
|
177
|
+
o.material.visible = false;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
self.add(mesh);
|
|
181
|
+
self.meshContent = mesh;
|
|
182
|
+
})
|
|
183
|
+
} else if (url.includes(".json")) {
|
|
184
|
+
self.controller = new AbortController();
|
|
185
|
+
fetch(url, { signal: self.controller.signal }).then(result => {
|
|
186
|
+
if (!result.ok) {
|
|
187
|
+
throw new Error(`couldn't load "${properties.url}". Request failed with status ${result.status} : ${result.statusText}`);
|
|
188
|
+
}
|
|
167
189
|
result.json().then(json => {
|
|
168
190
|
// when json content is downloaded, it is inserted into this tile's original JSON as a child
|
|
169
191
|
// and the content object is deleted from the original JSON
|
|
@@ -173,50 +195,36 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
173
195
|
delete self.json.content;
|
|
174
196
|
self.hasUnloadedJSONContent = false;
|
|
175
197
|
}).catch(error => { });
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
198
|
+
}).catch(error => { });
|
|
199
|
+
}
|
|
200
|
+
|
|
179
201
|
}
|
|
180
202
|
}
|
|
181
203
|
}
|
|
182
204
|
|
|
183
|
-
|
|
184
|
-
var self = this;
|
|
205
|
+
dispose() {
|
|
185
206
|
|
|
186
|
-
self
|
|
207
|
+
const self = this;
|
|
208
|
+
self.deleted = true;
|
|
209
|
+
this.traverse(function (element) {
|
|
210
|
+
if (!!element.contentURL) {
|
|
211
|
+
self.tileLoader.invalidate(element.contentURL, element.uuid);
|
|
212
|
+
}
|
|
187
213
|
if (!!element.controller) { // abort tile request
|
|
188
214
|
element.controller.abort();
|
|
189
215
|
}
|
|
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
|
-
|
|
206
|
-
}
|
|
207
|
-
}));
|
|
208
|
-
for (let i = 0; i < this.childrenTiles.length; i++) {
|
|
209
216
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
217
|
+
});
|
|
218
|
+
this.parent = null;
|
|
219
|
+
this.dispatchEvent({ type: 'removed' });
|
|
220
|
+
}
|
|
221
|
+
disposeChildren() {
|
|
222
|
+
var self = this;
|
|
215
223
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if (!!
|
|
224
|
+
self.childrenTiles.forEach(tile => tile.dispose());
|
|
225
|
+
self.childrenTiles = [];
|
|
226
|
+
self.children = [];
|
|
227
|
+
if (!!self.meshContent) self.children.push(self.meshContent);
|
|
220
228
|
}
|
|
221
229
|
|
|
222
230
|
|
|
@@ -228,14 +236,14 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
228
236
|
_update(camera, frustum) {
|
|
229
237
|
const self = this;
|
|
230
238
|
|
|
239
|
+
self.childrenTiles.forEach(child => child._update(camera, frustum));
|
|
231
240
|
if (!!self.boundingVolume && !!self.geometricError) {
|
|
232
|
-
|
|
241
|
+
self.metric = self.calculateUpdateMetric(camera, frustum);
|
|
233
242
|
}
|
|
234
243
|
|
|
235
|
-
updateNodeVisibility(metric);
|
|
236
|
-
updateTree(metric);
|
|
237
|
-
self.
|
|
238
|
-
trimTree(metric);
|
|
244
|
+
updateNodeVisibility(self.metric);
|
|
245
|
+
updateTree(self.metric);
|
|
246
|
+
trimTree(self.metric);
|
|
239
247
|
|
|
240
248
|
|
|
241
249
|
function updateTree(metric) {
|
|
@@ -293,7 +301,7 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
293
301
|
self.changeContentVisibility(false);
|
|
294
302
|
} else {
|
|
295
303
|
//self.changeContentVisibility(true);
|
|
296
|
-
|
|
304
|
+
|
|
297
305
|
}
|
|
298
306
|
}
|
|
299
307
|
}
|
|
@@ -322,9 +330,9 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
322
330
|
json: childJSON,
|
|
323
331
|
rootPath: self.rootPath,
|
|
324
332
|
geometricErrorMultiplier: self.geometricErrorMultiplier,
|
|
325
|
-
meshCallback: self.meshCallback,
|
|
326
333
|
loadOutsideView: self.loadOutsideView,
|
|
327
|
-
level: self.level + 1
|
|
334
|
+
level: self.level + 1,
|
|
335
|
+
tileLoader: self.tileLoader
|
|
328
336
|
});
|
|
329
337
|
self.childrenTiles.push(childTile);
|
|
330
338
|
self.add(childTile);
|
|
@@ -376,7 +384,7 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
376
384
|
return true;
|
|
377
385
|
}
|
|
378
386
|
|
|
379
|
-
return
|
|
387
|
+
return true;
|
|
380
388
|
|
|
381
389
|
}
|
|
382
390
|
|
|
@@ -455,28 +463,4 @@ class OGC3DTile extends THREE.Object3D {
|
|
|
455
463
|
this.childrenTiles.forEach(child => child.setGeometricErrorMultiplier(geometricErrorMultiplier));
|
|
456
464
|
}
|
|
457
465
|
}
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
*
|
|
461
|
-
* @param {Integer} size a number of vertices
|
|
462
|
-
*/
|
|
463
|
-
function createMeshCache(size = 5000000, meshCallback = () => { }) {
|
|
464
|
-
/* return new Cache(
|
|
465
|
-
(url, self)=>{
|
|
466
|
-
fetch(url, { signal: self.controller.signal }).then(result => {
|
|
467
|
-
if (!result.ok) {
|
|
468
|
-
throw new Error(`couldn't load "${properties.url}". Request failed with status ${result.status} : ${result.statusText}`);
|
|
469
|
-
}
|
|
470
|
-
result.arrayBuffer().then(buffer => B3DMDecoder.parseB3DM(buffer, self.meshCallback)).then(mesh => {
|
|
471
|
-
mesh.traverse((o) => {
|
|
472
|
-
if (o.isMesh) {
|
|
473
|
-
o.material.visible = false;
|
|
474
|
-
}
|
|
475
|
-
});
|
|
476
|
-
return mesh;
|
|
477
|
-
}).catch(error => { });
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
) */
|
|
481
|
-
}
|
|
482
|
-
export { OGC3DTile, createMeshCache };
|
|
466
|
+
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};
|