diff --git a/package-lock.json b/package-lock.json
index 3be4330..e890e94 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,21 +1,22 @@
{
"name": "immersive",
- "version": "0.0.5",
+ "version": "0.0.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "immersive",
- "version": "0.0.5",
+ "version": "0.0.7",
"dependencies": {
- "@babylonjs/core": "^7.3.1",
- "@babylonjs/gui": "^7.3.1",
+ "@babylonjs/core": "^7.6.0",
+ "@babylonjs/gui": "^7.6.0",
"@babylonjs/havok": "1.3.4",
- "@babylonjs/inspector": "^7.3.1",
- "@babylonjs/loaders": "^7.3.1",
- "@babylonjs/materials": "^7.3.1",
- "@babylonjs/procedural-textures": "^7.3.1",
- "@babylonjs/serializers": "^7.3.1",
+ "@babylonjs/inspector": "^7.6.0",
+ "@babylonjs/loaders": "^7.6.0",
+ "@babylonjs/materials": "^7.6.0",
+ "@babylonjs/procedural-textures": "^7.6.0",
+ "@babylonjs/serializers": "^7.6.0",
+ "@maptiler/client": "1.8.1",
"@picovoice/cobra-web": "^2.0.3",
"@picovoice/eagle-web": "^1.0.0",
"@picovoice/web-voice-processor": "^4.0.9",
@@ -55,14 +56,14 @@
}
},
"node_modules/@babylonjs/core": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-7.5.0.tgz",
- "integrity": "sha512-iP/z+j1eRrpv5g/JyqxMAuT7UVdfBWPHZ0Bl/89onq9hZmeyckHM+gXNpepo4sFrxoDefdAblh5eyVbN6iiXDg=="
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-7.6.0.tgz",
+ "integrity": "sha512-Pr5TlHQBdTYLkw+HmWZo1V6VYnP48wxEGBAscHcgZuuETo2ITCmsRLv0o+XY0QL1eAL8grQBM5eOkAInNt4SvA=="
},
"node_modules/@babylonjs/gui": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-7.5.0.tgz",
- "integrity": "sha512-kqS9HtveyG7W918u+h01JZBv9cDoPda3/o/vjbiZOUHem71Lj5MR7WeVr8bSRPbVRyj3mUdL2o1w2tYRPiDC/w==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-7.6.0.tgz",
+ "integrity": "sha512-5r954RVrnEvSCw/WKwl6CdKb5PIVEMyF6WKS+bDku3PrwaoTUqkd1jlhmyaH6k2bL/bcoaz25ts04TK6YrbmXA==",
"peerDependencies": {
"@babylonjs/core": "^7.0.0"
}
@@ -88,9 +89,9 @@
}
},
"node_modules/@babylonjs/inspector": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-7.5.0.tgz",
- "integrity": "sha512-B1ACpoljYX5Y3DHJZgCwfkhlS4M5xb9VJKtH3mN+VgXEt5AnOMT2F8pXJNz9ICQC7XhIxo34JL52OnE5iOhlvw==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-7.6.0.tgz",
+ "integrity": "sha512-utytbidkVhYXNhVY5XOuGIHCPdmHrHw9q1rr9+P7nwUUwTtl3duAQiU8TE/w/6MUejg97kyN6lBGRqXAWpL5nA==",
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.1.0",
"@fortawesome/free-regular-svg-icons": "^6.0.0",
@@ -108,34 +109,34 @@
}
},
"node_modules/@babylonjs/loaders": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-7.5.0.tgz",
- "integrity": "sha512-rVkYkiT3XSGJ1s0rEuUCN3BXJGI4RexKXUrTp1cy0CVj3B2DvNt9pzET4038BmVp8N3EDPBd9+bPZenduicsPw==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-7.6.0.tgz",
+ "integrity": "sha512-7tt/ImGExADJx5wGs/3vz8tijg1FHuVT2c/8dp0Q+qv3v47KJIgCOtggoXCVDTo+xYj2fQWtucmXwkNhIizg7w==",
"peerDependencies": {
"@babylonjs/core": "^7.0.0",
"babylonjs-gltf2interface": "^7.0.0"
}
},
"node_modules/@babylonjs/materials": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-7.5.0.tgz",
- "integrity": "sha512-IGYQt+0qaX4ZVTyMge4IjZnHcPpwf85/J+fg4QBUz0BoUgrFAvi0nXJl43X7FJaj0H2BJSaERBZm/kK2K9bKqA==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-7.6.0.tgz",
+ "integrity": "sha512-o5PcKNf/NE+P81E1fQyuoNrCND6dV5RJZga03JzHIs48/+2veq11Dj4FGAOinmqQwe/0U2yrl3v4hsRVwt4YtQ==",
"peerDependencies": {
"@babylonjs/core": "^7.0.0"
}
},
"node_modules/@babylonjs/procedural-textures": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@babylonjs/procedural-textures/-/procedural-textures-7.5.0.tgz",
- "integrity": "sha512-xvJ/gQJBy1mgTJYc/YkzzdzJoK/L/wBi/rtW9o9ckLe+cjw5UQ0gIGEUIJlgIx2GX7hPVjKd73uN2l5LcWYVsA==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@babylonjs/procedural-textures/-/procedural-textures-7.6.0.tgz",
+ "integrity": "sha512-37Dheb8kGX0lWRevFw3mqMtuoJrJ+TT2bEQB/9BOmAKS2yEb2xlLlswkn7UaB4oHax8XzaY9N63zTSzzWj978Q==",
"peerDependencies": {
"@babylonjs/core": "^7.0.0"
}
},
"node_modules/@babylonjs/serializers": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-7.5.0.tgz",
- "integrity": "sha512-DCQmT8RnBmF7jxIOhXjEmHL4dFmPrypBdMEoI9eVenQfLwBlRim4tbzHlHSwmk1DOy+ENxqODZzhzh4EmUaS4A==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-7.6.0.tgz",
+ "integrity": "sha512-U/umdH2dAcEuyb1OcaemV2LOgIohsoWAgUriub0SxA+DLlpiyEt6HUSvM+aX/90UyGNz5Dpb4VZXbqBIrUa0Hg==",
"peerDependencies": {
"@babylonjs/core": "^7.0.0",
"babylonjs-gltf2interface": "^7.0.0"
@@ -572,6 +573,14 @@
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
+ "node_modules/@maptiler/client": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/@maptiler/client/-/client-1.8.1.tgz",
+ "integrity": "sha512-G1z2xCBwT5WU1CqeukY3R4g1saSjKzi6tmg24LJWZHP81RQ4quVvwdmsx829BxITlFbFhND+BSphFgrDGmwhcA==",
+ "dependencies": {
+ "quick-lru": "^7.0.0"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -2579,6 +2588,17 @@
}
]
},
+ "node_modules/quick-lru": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-7.0.0.tgz",
+ "integrity": "sha512-MX8gB7cVYTrYcFfAnfLlhRd0+Toyl8yX8uBx1MrX7K0jegiz9TumwOK27ldXrgDlHRdVi+MqU9Ssw6dr4BNreg==",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
diff --git a/package.json b/package.json
index 62d12e6..12fbb2a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "immersive",
"private": true,
- "version": "0.0.6",
+ "version": "0.0.7",
"type": "module",
"engines": {
"node": ">=18.0.0"
@@ -16,17 +16,18 @@
"havok": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps"
},
"dependencies": {
- "@babylonjs/core": "^7.3.1",
- "@babylonjs/gui": "^7.3.1",
+ "@babylonjs/core": "^7.6.0",
+ "@babylonjs/gui": "^7.6.0",
"@babylonjs/havok": "1.3.4",
- "@babylonjs/inspector": "^7.3.1",
- "@babylonjs/loaders": "^7.3.1",
- "@babylonjs/materials": "^7.3.1",
- "@babylonjs/procedural-textures": "^7.3.1",
- "@babylonjs/serializers": "^7.3.1",
+ "@babylonjs/inspector": "^7.6.0",
+ "@babylonjs/loaders": "^7.6.0",
+ "@babylonjs/materials": "^7.6.0",
+ "@babylonjs/procedural-textures": "^7.6.0",
+ "@babylonjs/serializers": "^7.6.0",
"@picovoice/cobra-web": "^2.0.3",
"@picovoice/eagle-web": "^1.0.0",
"@picovoice/web-voice-processor": "^4.0.9",
+ "@maptiler/client": "1.8.1",
"@typed-mxgraph/typed-mxgraph": "^1.0.8",
"@types/dom-to-image": "^2.6.7",
"@types/file-saver": "^2.0.6",
diff --git a/public/assets/icons/point.png b/public/assets/icons/point.png
new file mode 100644
index 0000000..5c53ba2
Binary files /dev/null and b/public/assets/icons/point.png differ
diff --git a/public/assets/icons/video.png b/public/assets/icons/video.png
new file mode 100644
index 0000000..dc2829e
Binary files /dev/null and b/public/assets/icons/video.png differ
diff --git a/public/assets/icons/video.svg b/public/assets/icons/video.svg
new file mode 100644
index 0000000..a5149ba
--- /dev/null
+++ b/public/assets/icons/video.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/public/assets/models/tinker.obj b/public/assets/models/tinker.obj
new file mode 100644
index 0000000..650d6dc
--- /dev/null
+++ b/public/assets/models/tinker.obj
@@ -0,0 +1,300 @@
+# Object Export From Tinkercad Server 2015
+
+mtllib obj.mtl
+
+o obj_0
+v 4 3.5 4
+v 4 3.568 3.482
+v 4 3.768 3
+v 4 4.086 2.586
+v 4 4.5 2.268
+v 4 4.982 2.068
+v 4 5.5 2
+v 4 6.018 2.068
+v 4 6.5 2.268
+v 4 6.914 2.586
+v 4 7.232 3
+v 4 7.432 3.482
+v 4 7.5 4
+v 4 7.432 4.518
+v 4 7.232 5
+v 4 6.914 5.414
+v 4 6.5 5.732
+v 4 6.018 5.932
+v 4 5.5 6
+v 4 4.982 5.932
+v 4 4.5 5.732
+v 4 4.086 5.414
+v 4 3.768 5
+v 4 3.568 4.518
+v -8.308 4.5 7.952
+v 1 4.7272 4.2072
+v -8.587 4.5 7.81
+v 1 4.7 4
+v -8.81 4.5 7.587
+v 1 4.8072 4.4
+v -8.952 4.5 7.308
+v 1 4.9344 4.5656
+v -9 4.5 7.0043
+v 0.952 6.5 7.308
+v 1 5.1 4.6928
+v 1 6.5 7.0043
+v 0.81 6.5 7.587
+v 1 5.2928 4.7728
+v 0.587 6.5 7.81
+v 0.308 6.5 7.952
+v 1 5.5 4.8
+v 0.0033 6.5 8
+v 1 5.7072 4.7728
+v 1 5.9 4.6928
+v 1 6.0656 4.5656
+v 1 6.1928 4.4
+v 1 4.5 7.0043
+v 0.952 4.5 7.308
+v 0.81 4.5 7.587
+v 0.587 4.5 7.81
+v 0.308 4.5 7.952
+v 1 6.2728 4.2072
+v 0.0033 4.5 8
+v 1 6.3 4
+v -8.0043 4.5 0
+v -8.952 4.5 0.692
+v -9 4.5 0.9967
+v 1 6.2728 3.7928
+v -8.81 4.5 0.413
+v -8.587 4.5 0.19
+v 1 6.1928 3.6
+v -8.308 4.5 0.048
+v 1 6.0656 3.4344
+v 1 5.9 3.3072
+v -8.0043 6.5 8
+v -8.308 6.5 7.952
+v 1 5.7072 3.2272
+v -8.587 6.5 7.81
+v 1 5.5 3.2
+v -8.81 6.5 7.587
+v -8.952 6.5 7.308
+v 1 5.2928 3.2272
+v -9 6.5 7.0043
+v 1 5.1 3.3072
+v 1 4.9344 3.4344
+v 1 4.8072 3.6
+v 1 4.7272 3.7928
+v -9 6.5 0.9967
+v -8.0043 4.5 8
+v 0.81 6.5 0.413
+v 0.587 6.5 0.19
+v 0.952 6.5 0.692
+v 1 6.5 0.9967
+v 0.0033 6.5 0
+v 0.0033 4.5 0
+v 0.308 4.5 0.048
+v -8.0043 6.5 0
+v 0.587 4.5 0.19
+v 0.81 4.5 0.413
+v 0.952 4.5 0.692
+v 1 4.5 0.9967
+v -8.952 6.5 0.692
+v -8.81 6.5 0.413
+v -8.587 6.5 0.19
+v -8.308 6.5 0.048
+v 0.308 6.5 0.048
+# 96 vertices
+
+g group_0_8273816
+
+usemtl color_8273816
+s 0
+
+f 1 2 3
+f 1 3 4
+f 1 4 5
+f 1 5 6
+f 1 6 7
+f 1 7 8
+f 1 8 9
+f 1 9 10
+f 1 10 11
+f 1 11 12
+f 1 12 13
+f 1 13 14
+f 1 14 15
+f 1 15 16
+f 1 16 17
+f 1 17 18
+f 1 18 19
+f 1 19 20
+f 1 20 21
+f 1 21 22
+f 1 22 23
+f 1 23 24
+f 28 1 26
+f 24 26 1
+f 23 30 26
+f 23 26 24
+f 22 32 30
+f 22 30 23
+f 32 22 35
+f 21 35 22
+f 49 48 37
+f 35 21 38
+f 20 38 21
+f 19 41 38
+f 19 38 20
+f 41 19 43
+f 18 43 19
+f 34 48 36
+f 17 44 43
+f 17 43 18
+f 34 37 48
+f 16 45 44
+f 16 44 17
+f 49 37 39
+f 45 16 46
+f 15 46 16
+f 53 40 42
+f 36 48 47
+f 49 39 50
+f 51 50 40
+f 39 40 50
+f 46 15 52
+f 14 52 15
+f 40 53 51
+f 52 54 36
+f 83 36 54
+f 54 58 83
+f 58 61 83
+f 61 63 83
+f 93 60 59
+f 64 83 63
+f 69 72 91
+f 72 74 91
+f 73 33 71
+f 74 75 91
+f 75 76 91
+f 25 65 66
+f 66 68 27
+f 66 27 25
+f 29 27 70
+f 68 70 27
+f 91 76 77
+f 91 77 28
+f 70 71 31
+f 70 31 29
+f 71 33 31
+f 65 25 79
+f 57 33 78
+f 73 78 33
+f 42 65 53
+f 53 65 79
+f 81 88 86
+f 80 89 88
+f 80 88 81
+f 89 80 90
+f 82 90 80
+f 82 83 90
+f 91 90 83
+f 84 86 85
+f 55 87 85
+f 84 85 87
+f 95 87 55
+f 86 91 85
+f 88 91 86
+f 89 90 88
+f 91 88 90
+f 92 56 78
+f 93 56 92
+f 94 60 93
+f 94 95 60
+f 62 60 95
+f 56 55 57
+f 91 57 85
+f 62 95 55
+f 55 85 57
+f 59 55 56
+f 60 62 59
+f 55 59 62
+f 78 56 57
+f 93 59 56
+f 29 31 27
+f 33 27 31
+f 27 33 25
+f 13 54 52
+f 13 52 14
+f 54 13 58
+f 12 58 13
+f 49 50 57
+f 51 57 50
+f 53 57 51
+f 79 33 53
+f 61 58 11
+f 12 11 58
+f 63 61 10
+f 11 10 61
+f 10 9 64
+f 10 64 63
+f 49 57 48
+f 91 47 57
+f 25 33 79
+f 57 53 33
+f 47 48 57
+f 9 8 67
+f 9 67 64
+f 96 73 81
+f 84 73 96
+f 69 67 7
+f 8 7 67
+f 80 81 73
+f 7 6 72
+f 7 72 69
+f 74 72 5
+f 6 5 72
+f 93 92 94
+f 78 94 92
+f 95 78 87
+f 65 42 83
+f 75 74 4
+f 5 4 74
+f 66 83 68
+f 70 68 83
+f 4 3 76
+f 4 76 75
+f 39 37 40
+f 42 40 37
+f 42 37 34
+f 3 2 77
+f 3 77 76
+f 34 36 42
+f 28 77 1
+f 2 1 77
+f 36 83 42
+f 65 83 66
+f 71 70 83
+f 73 71 83
+f 82 80 73
+f 83 82 73
+f 87 78 84
+f 94 78 95
+f 73 84 78
+f 96 86 84
+f 81 86 96
+f 67 69 83
+f 64 67 83
+f 69 91 83
+f 91 28 47
+f 28 26 47
+f 26 30 47
+f 30 32 47
+f 38 41 47
+f 32 35 47
+f 35 38 47
+f 41 36 47
+f 41 43 36
+f 43 44 36
+f 44 45 36
+f 45 46 36
+f 46 52 36
+# 188 faces
+
+ #end of obj_0
+
diff --git a/public/assets/textures/rockford.jpeg b/public/assets/textures/rockford.jpeg
new file mode 100644
index 0000000..26400a6
Binary files /dev/null and b/public/assets/textures/rockford.jpeg differ
diff --git a/public/sw.js b/public/sw.js
index bf02b55..ae9a474 100644
--- a/public/sw.js
+++ b/public/sw.js
@@ -2,6 +2,7 @@ importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.1.0/workbox
const VERSION = '8';
const CACHE = "deepdiagram";
const IMAGEDELIVERY_CACHE = "deepdiagram-images";
+const MAPTILE_CACHE = 'maptiler';
// TODO: replace the following with the correct offline fallback page i.e.: const offlineFallbackPage = "offline.html";
const offlineFallbackPage = "/";
@@ -43,7 +44,27 @@ workbox.routing.registerRoute(
cacheName: CACHE
})
);
-console.warn('workbox');
+
+workbox.routing.registerRoute(
+ new RegExp('.*api.maptiler.com/.*'),
+ new workbox.strategies.CacheFirst({
+ plugins: [
+ new workbox.expiration.ExpirationPlugin({
+ maxEntries: 256,
+ maxAgeSeconds: 60 * 60 * 24 * 30,
+ purgeOnQuotaError: true,
+ matchOptions: {
+ ignoreVary: true
+ }
+ }),
+ new workbox.cacheableResponse.CacheableResponsePlugin({
+ statuses: [0, 200]
+ })
+ ],
+ cacheName: MAPTILE_CACHE
+
+ })
+);
workbox.routing.registerRoute(
new RegExp('/assets/.*'),
diff --git a/src/menus/cameraMenu.ts b/src/menus/cameraMenu.ts
index 3356506..1b0f73c 100644
--- a/src/menus/cameraMenu.ts
+++ b/src/menus/cameraMenu.ts
@@ -1,45 +1,96 @@
-import {Color3, DynamicTexture, Mesh, MeshBuilder, Scene, StandardMaterial, Vector3} from "@babylonjs/core";
+import {Color3, DynamicTexture, MeshBuilder, Scene, StandardMaterial, Vector3} from "@babylonjs/core";
import log, {Logger} from "loglevel";
+import {MaptilerMap} from "../objects/maptilerMap";
export class CameraMenu {
private readonly scene: Scene;
- private xr;
- private controllers;
private readonly logger: Logger = log.getLogger('CameraMenu');
- constructor(scene, xr, controllers) {
+ constructor(scene) {
this.scene = scene;
- this.xr = xr;
- this.controllers = controllers;
- this.buildMenu(1, new Vector3(0, 1, 0));
+ //this.buildMenu(3, new Vector3(-1, 2, 0));
//this.buildMenu(4, new Vector3(0,2,0));
//this.buildMenu(5, new Vector3(1,2,0));
- //this.buildMenu(6, new Vector3(1,1,0));
+ //this.buildMenu(6, new Vector3(2,2,0));
+ //this.buildIcon();
+ //this.loadIcon();
+
+ this.buildMap();
}
+ private buildMap() {
+ const maptilerMap = new MaptilerMap('YnvhjBiU8oCWP0GXNdHL', this.scene, 'map-node', 3);
+ maptilerMap.node.position.y = 1;
+ maptilerMap.node.position.z = -4;
+ maptilerMap.node.rotation.y = Math.PI;
+ maptilerMap.node.rotation.x = Math.PI / 6;
+ maptilerMap.node.scaling = new Vector3(1, 1, 1);
+ //maptilerMap.setLocation('loves park, il' , 15);
+ maptilerMap.setLocation('rockford, il', 12).then(() => {
+ maptilerMap.plotPoint(42.33181896128866, -88.86844896012006);
+ });
+
+ }
+
+ //https://maps.geoapify.com/v1/staticmap?style=osm-carto&scaleFactor=2&width=4096&height=4096¢er=lonlat:-89.0940,42.2711&zoom=12.4318&apiKey=d548c5ed24604be6a9dd0d989631f783
+ private buildIcon() {
+ const icon = MeshBuilder.CreatePlane('camera-icon', {width: .1, height: .1}, this.scene);
+ icon.position = new Vector3(0, 3, 0);
+ icon.metadata = {grabbable: true};
+ const material = new StandardMaterial('icon-material', this.scene);
+
+ material.backFaceCulling = false;
+ const texture = new DynamicTexture('icon-texture', {width: 256, height: 256}, this.scene);
+ //const texture = new DynamicTexture('/assets/icons/video.png', this.scene);
+
+ const image = new Image();
+ //image.setAttribute('width', '256');
+ //image.setAttribute('height', '256');
+ //image.width=32;
+ //image.height=32;
+ image.src = '/assets/icons/video.png';
+ image.onload = () => {
+ texture.getContext().drawImage(image, 0, 0);
+ texture.update();
+ }
+
+ material.emissiveColor = new Color3(.1, .1, .8);
+ material.opacityTexture = texture;
+ icon.material = material;
+ material.disableLighting = true;
+
+ //material.diffuseTexture = texture;
+ //material.disableLighting;
+ //material.emissiveColor = new Color3(1, 1, 1);
+ //texture.uScale = 1;
+ //texture.vScale = 1;
+
+
+ }
private buildMenu(camnum: number, position: Vector3) {
- const camerasphere = MeshBuilder.CreateSphere("camerasphere", {
- diameter: 10,
- slice: .5,
- sideOrientation: Mesh.DOUBLESIDE
- }, this.scene);
+ const camerasphere = MeshBuilder.CreatePlane('camera-' + camnum, {width: 1, height: 1}, this.scene);
camerasphere.position = position;
const material = new StandardMaterial("cameramaterial", this.scene);
- material.emissiveColor = new Color3(1, 1, 1);
-
+ //material.emissiveColor = new Color3(1, 1, 1);
+ material.backFaceCulling = false;
const texture = new DynamicTexture('texture', {width: 1600, height: 1600}, this.scene);
- material.diffuseTexture = texture;
+ material.emissiveTexture = texture;
+ material.disableLighting = true;
const img = new Image();
- img.src = 'https://cameras.immersiveidea.com/mjpg/video.mjpg?camera=' + camnum + '×tamp=1698497537140';
+
+ img.setAttribute('crossorigin', 'anonymous');
+ img.src = 'https://cameras.immersiveidea.com/mjpg/video.mjpg?camera=' + camnum;
+
const ctx = texture.getContext();
img.onload = () => {
- ctx.drawImage(img, 250, 0, 2112, 1940, 0, 0, 1600, 1600);
+
+ ctx.drawImage(img, 0, 0);
texture.update();
window.setInterval((texture, img, ctx) => {
- ctx.drawImage(img, 250, 0, 2112, 1940, 0, 0, 1600, 1600);
+ ctx.drawImage(img, 0, 0);
texture.update();
- }, 60, texture, img, ctx);
+ }, 1000, texture, img, ctx);
}
texture.onLoadObservable.add(() => {
diff --git a/src/objects/cameraIcon.ts b/src/objects/cameraIcon.ts
new file mode 100644
index 0000000..692b3e0
--- /dev/null
+++ b/src/objects/cameraIcon.ts
@@ -0,0 +1,66 @@
+import {
+ AbstractMesh,
+ ActionManager,
+ Color3,
+ ExecuteCodeAction,
+ InstancedMesh,
+ Mesh,
+ Scene,
+ SceneLoader,
+ StandardMaterial,
+ TransformNode,
+ Vector3
+} from "@babylonjs/core";
+import {DefaultScene} from "../defaultScene";
+import {CameraWindow} from "./cameraWindow";
+
+export class CameraIcon {
+ private static _baseMesh: AbstractMesh;
+ private readonly _scene: Scene;
+ private _cam: CameraWindow;
+
+ constructor(scene: Scene, mapNode: TransformNode, position: Vector3) {
+ this._scene = scene;
+ if (!CameraIcon._baseMesh) {
+ this.loadIcon();
+ }
+ const newInstance = new InstancedMesh('cam', CameraIcon._baseMesh as Mesh);
+ newInstance.setParent(mapNode);
+ newInstance.position = position;
+ newInstance.actionManager = new ActionManager(this._scene);
+ newInstance.actionManager.registerAction(new ExecuteCodeAction(ActionManager.OnPickTrigger, () => {
+ if (this._cam) {
+ this._cam.dispose();
+ this._cam = null;
+ } else {
+ this._cam = new CameraWindow(scene, null, 'https://cameras.immersiveidea.com/mjpg/video.mjpg?camera=3');
+ this._cam.mesh.position.x = newInstance.absolutePosition.x;
+ this._cam.mesh.position.z = newInstance.absolutePosition.z;
+ this._cam.mesh.position.y = newInstance.absolutePosition.y + .5;
+ }
+ }));
+
+ //newInstance.billboardMode = Mesh.BILLBOARDMODE_ALL;
+ }
+
+ private loadIcon() {
+ SceneLoader.ImportMesh('', '/assets/models/', 'tinker.obj', this._scene,
+ (newMesh) => {
+ const myMesh = newMesh[0].getChildren()[0] as Mesh;
+ //myMesh.position = new Vector3(0, 1.5, 0);
+ myMesh.metadata = {grabbable: true};
+ const SCALE = .006;
+ myMesh.scaling = new Vector3(SCALE, SCALE, SCALE);
+ myMesh.rotation.x = Math.PI / 2;
+ const material = new StandardMaterial('icon-material', DefaultScene.Scene);
+ material.emissiveColor = new Color3(.1, .1, .9);
+ material.disableLighting = true;
+ myMesh.material = material;
+ myMesh.name = 'cam';
+ myMesh.setEnabled(false);
+ myMesh.setParent(null);
+ newMesh[0].dispose();
+ CameraIcon._baseMesh = myMesh;
+ })
+ }
+}
diff --git a/src/objects/cameraWindow.ts b/src/objects/cameraWindow.ts
new file mode 100644
index 0000000..a87805e
--- /dev/null
+++ b/src/objects/cameraWindow.ts
@@ -0,0 +1,59 @@
+import {AbstractMesh, DynamicTexture, MeshBuilder, Scene, StandardMaterial, TransformNode} from "@babylonjs/core";
+
+export class CameraWindow {
+ private readonly _scene: Scene;
+ private readonly _url: string;
+ private readonly _parent: TransformNode;
+ private readonly _intervalId: number;
+ private _cameraMesh: AbstractMesh;
+ private _img: HTMLImageElement;
+
+ constructor(scene: Scene, parent: TransformNode, url: string) {
+ this._scene = scene;
+ this._parent = parent;
+ this._url = url;
+ this.build();
+
+ }
+
+ public get mesh() {
+ return this._cameraMesh;
+ }
+
+ public dispose() {
+ window.clearInterval(this._intervalId);
+ this._cameraMesh.dispose(false, true);
+ this._img.remove();
+ }
+
+ private build() {
+ this._cameraMesh = MeshBuilder.CreatePlane('cam-' + this._url, {width: 1, height: 1}, this._scene);
+ this._cameraMesh.parent = this._parent;
+ //camerasphere.position = position;
+ const material = new StandardMaterial("cameramaterial", this._scene);
+ //material.emissiveColor = new Color3(1, 1, 1);
+ material.backFaceCulling = false;
+ const texture = new DynamicTexture('texture', {width: 1600, height: 1600}, this._scene);
+ material.emissiveTexture = texture;
+ material.disableLighting = true;
+ this._img = new Image();
+
+ this._img.setAttribute('crossorigin', 'anonymous');
+ //img.src = 'https://cameras.immersiveidea.com/mjpg/video.mjpg?camera=' + camnum;
+ this._img.src = this._url;
+ const ctx = texture.getContext();
+ this._img.onload = () => {
+ ctx.drawImage(this._img, 0, 0);
+ texture.update();
+ window.setInterval((texture, img, ctx) => {
+ ctx.drawImage(img, 0, 0);
+ texture.update();
+ }, 1000, texture, this._img, ctx);
+ }
+
+ texture.onLoadObservable.add(() => {
+
+ });
+ this._cameraMesh.material = material;
+ }
+}
\ No newline at end of file
diff --git a/src/objects/diagramObject.ts b/src/objects/diagramObject.ts
index 2cc9c1f..b5a81f9 100644
--- a/src/objects/diagramObject.ts
+++ b/src/objects/diagramObject.ts
@@ -1,9 +1,55 @@
-import {Scene} from "@babylonjs/core";
+import {AbstractMesh, Scene} from "@babylonjs/core";
+import {DiagramEntity} from "../diagram/types/diagramEntity";
+import {buildMeshFromDiagramEntity} from "../diagram/functions/buildMeshFromDiagramEntity";
+import {toDiagramEntity} from "../diagram/functions/toDiagramEntity";
+type DiagramObjectOptionsType = {
+ diagramEntity?: DiagramEntity,
+ mesh?: AbstractMesh
+}
export class DiagramObject {
- private scene: Scene;
+ private _scene: Scene;
- constructor(scene: Scene) {
- this.scene = scene;
+ constructor(scene: Scene, options?: DiagramObjectOptionsType) {
+ this._scene = scene;
+ if (options) {
+ if (options.diagramEntity) {
+ this.fromDiagramEntity(options.diagramEntity);
+ }
+ if (options.mesh) {
+ this._mesh = options.mesh;
+ this._diagramEntity = this.diagramEntity;
+ }
+ }
+ }
+
+ private _mesh: AbstractMesh;
+
+ public get mesh(): AbstractMesh {
+ return this._mesh;
+ }
+
+ private _diagramEntity: DiagramEntity;
+
+ public get diagramEntity(): DiagramEntity {
+ if (!this._diagramEntity) {
+ if (this._mesh) {
+ this._diagramEntity = toDiagramEntity(this._mesh);
+ }
+ }
+ return this._diagramEntity;
+ }
+
+ public fromDiagramEntity(entity: DiagramEntity): DiagramObject {
+ this._diagramEntity = entity;
+ this._mesh = buildMeshFromDiagramEntity(this._diagramEntity, this._scene);
+ return this;
+ }
+
+ public dispose() {
+ this._mesh.dispose(false, true);
+ this._mesh = null;
+ this._diagramEntity = null;
+ this._scene = null;
}
}
\ No newline at end of file
diff --git a/src/objects/maptilerMap.ts b/src/objects/maptilerMap.ts
new file mode 100644
index 0000000..27f873a
--- /dev/null
+++ b/src/objects/maptilerMap.ts
@@ -0,0 +1,256 @@
+import * as mapTilerClient from '@maptiler/client';
+import {
+ AbstractMesh,
+ MeshBuilder,
+ Observable,
+ Scene,
+ StandardMaterial,
+ Texture,
+ TransformNode,
+ Vector2,
+ Vector3
+} from "@babylonjs/core";
+import {CameraIcon} from "./cameraIcon";
+
+export type MaptilerMapTile = {
+ lat: number,
+ lon: number,
+ zoom: number,
+ url: string,
+ x: number,
+ y: number,
+ bounds: Vector2[];
+}
+
+
+export class MaptilerMap {
+ public readonly onReadyObservable = new Observable();
+ private _lat: number;
+ private _lon: number;
+ private _min: Vector2;
+ private _max: Vector2;
+ private _zoom: number;
+ //private _bounds: Vector2[];
+ private readonly _scene: Scene;
+ private _tileXYCount: number = 2;
+ private readonly _baseNode: TransformNode;
+ private readonly _key: string;
+ private _pendingPoints: Array = [];
+ private _points: Vector2[] = [];
+
+ public constructor(key: string, scene: Scene, name: string = 'map-node', tileXYCount: number = 2) {
+ this._scene = scene;
+ this._key = key;
+ this._tileXYCount = tileXYCount;
+ this._baseNode = new TransformNode(name, this._scene);
+ this.onReadyObservable.addOnce(this.buildNodes.bind(this));
+ this.onReadyObservable.addOnce(this.waitForMeshAdded.bind(this));
+ }
+
+ private _startFallback: number = 10;
+
+ public set startFallback(value: number) {
+ this._startFallback = value;
+ }
+
+ private _fallbackInterval: number = 10;
+
+ public set fallbackInterval(value: number) {
+ this._fallbackInterval = value;
+ }
+
+ public get node(): TransformNode {
+ return this._baseNode;
+ }
+
+ public async setLocation(name: string, zoom: number = 18): Promise {
+ mapTilerClient.config.apiKey = this._key;
+ const result = await mapTilerClient.geocoding.forward(name)
+ if (result.features.length > 0) {
+ this.setInitialData(result.features[0].center[1], result.features[0].center[0], zoom);
+ const tileXY = await this.getTileXY(this._lat, this._lon);
+ const output = this.getTile(tileXY[0], tileXY[1], zoom);
+ this.onReadyObservable.notifyObservers({
+ lat: this._lat,
+ lon: this._lon,
+ zoom: zoom,
+ x: tileXY[0],
+ y: tileXY[1],
+ url: output,
+ bounds: []
+ });
+ } else {
+ console.error(JSON.stringify(result));
+ }
+ }
+
+ public async setLocationByLatLon(lat: number, lon: number, zoom: number = 18): Promise {
+ this.setInitialData(lat, lon, zoom);
+ const tileXY = this.getTileXY(lat, lon);
+ const imageUrl = this.getTile(tileXY[0], tileXY[1], zoom);
+ this.onReadyObservable.notifyObservers({
+ lat: this._lat,
+ lon: this._lon,
+ zoom: zoom,
+ x: tileXY[0],
+ y: tileXY[1],
+ url: imageUrl,
+ bounds: []
+ });
+ }
+
+ public async plotPoint(lat: number, lon: number) {
+ const len = this._points.push(new Vector2(lat, lon));
+ this._pendingPoints.push(len - 1);
+ }
+
+ public getTile(x: number, y: number, z: number) {
+ return `https://api.maptiler.com/maps/streets-v2/256/${z}/${x}/${y}@2x.png?key=${this._key}`;
+ }
+
+ private waitForMeshAdded() {
+ this._scene.onAfterRenderObservable.add(() => {
+ if (this._pendingPoints.length > 0) {
+ this._pendingPoints = this._pendingPoints.filter((item) => {
+ const point = this._points[item];
+ const tileXY = this.getTileXY(point.x, point.y);
+ console.log(tileXY);
+ const mesh = this._scene.getMeshByName(`map-${tileXY[0]}-${tileXY[1]}-plane`);
+ const oldPoint = this._scene.getMeshByName(`map-${point.x}-${point.y}-point`);
+ if (!mesh) {
+ console.error(`map-${tileXY[0]}-${tileXY[1]}-plane not found`);
+ return true;
+ } else {
+ if (!oldPoint) {
+ const pixelx = lonOnTile(point.y, this._zoom) % 1;
+ const pixely = latOnTile(point.x, this._zoom) % 1;
+ console.log(`pixelx: ${pixelx}, pixely: ${pixely} found`);
+ try {
+ const newIcon = new CameraIcon(this._scene, this._baseNode,
+ new Vector3(mesh.position.x - .5 + pixelx, mesh.position.y + .5 - pixely, mesh.position.z - .05));
+ return false;
+ } catch (err) {
+ return true;
+ }
+ } else {
+ return false;
+ //oldPoint.dispose(false, true);
+ }
+ }
+ });
+ }
+ }, -1, false, this);
+ }
+
+ private buildNodes(data: MaptilerMapTile) {
+ this.buildMapTile(0, 0, data.url, data.x, data.y).parent = this._baseNode;
+ let time = this._startFallback;
+ const tiles = this._tileXYCount;
+ if (this._tileXYCount < 1) {
+ return;
+ }
+ for (let x = -tiles; x < (tiles + 1); x++) {
+ for (let y = -tiles; y < (tiles + 1); y++) {
+ if (x !== 0 || y !== 0) {
+ const url = this.getTile(data.x + x, data.y + y, data.zoom);
+ window.setTimeout((that) => {
+ that.buildMapTile(x, -y, url, data.x + x, data.y + y).parent = this._baseNode;
+ }, time += this._fallbackInterval, this);
+ }
+ }
+ }
+
+ }
+
+ private getTileXY(lat: number, lon: number): number[] {
+ return [Math.floor(lonOnTile(lon, this._zoom)), Math.floor(latOnTile(lat, this._zoom))];
+ }
+
+ private setInitialData(lat: number, lon: number, zoom: number) {
+
+ this._baseNode.getChildren().forEach((child) => {
+ child.dispose(false, true);
+ });
+ this._lat = lat;
+ this._lon = lon;
+ this._zoom = zoom;
+ }
+
+ private buildMapTile(x: number, y: number, url: string, xTile: number, yTile: number): AbstractMesh {
+ const map = MeshBuilder.CreatePlane(`map-${xTile}-${yTile}-plane`, {width: 1, height: 1}, this._scene);
+ const mapMaterial = new StandardMaterial(`map-${xTile}-${yTile}-material`, this._scene);
+ const mapTexture = new Texture(url, this._scene);
+ const lon = tile2long(xTile, this._zoom);
+ const lat = tile2lat(yTile, this._zoom);
+ if (!this._min || lat < this._min.x || lon < this._min.y) {
+ this._min = new Vector2(lat, lon);
+ console.log(`min: ${lat}, ${lon}`);
+ }
+ const maxLat = tile2lat(yTile + 1, this._zoom);
+ const maxLon = tile2long(xTile + 1, this._zoom);
+ if (!this._max || maxLat > this._max.y || maxLon > this._max.y) {
+ this._min = new Vector2(maxLat, maxLon);
+ console.log(`max: ${maxLat}, ${maxLon}`);
+ }
+ map.metadata = {
+ mapTile: {x: xTile, y: yTile}, bounds:
+ {
+ topleft:
+ {lat: lat, lon: lon},
+ bottomright:
+ {
+ lat: tile2lat(yTile + 1, this._zoom),
+ lon: tile2long(xTile + 1, this._zoom)
+ }
+ }
+ };
+ mapTexture.name = `map-${xTile}-${yTile}-texture`;
+ mapMaterial.emissiveTexture = mapTexture;
+ mapMaterial.disableLighting = true;
+ mapMaterial.backFaceCulling = false;
+ map.material = mapMaterial;
+ map.position.x = x;
+ map.position.y = y;
+ map.isPickable = true;
+ return map;
+ }
+}
+
+function tile2long(x, z) {
+ return (x / Math.pow(2, z) * 360 - 180);
+}
+
+function tile2lat(y, z) {
+ var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
+ return (180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))));
+}
+
+const EARTH_CIR_METERS = 40075016.686;
+const TILE_SIZE = 512;
+const degreesPerMeter = 360 / EARTH_CIR_METERS;
+const LIMIT_Y = toDegrees(Math.atan(Math.sinh(Math.PI))) // around 85.0511...
+
+function toRadians(degrees) {
+ return degrees * Math.PI / 180;
+}
+
+function toDegrees(radians) {
+ return (radians / Math.PI) * 180
+}
+
+
+function lonOnTile(lon, zoom) {
+ return ((lon + 180) / 360) * Math.pow(2, zoom)
+}
+
+function latOnTile(lat, zoom) {
+ return (
+ ((1 -
+ Math.log(
+ Math.tan((lat * Math.PI) / 180) + 1 / Math.cos((lat * Math.PI) / 180)
+ ) /
+ Math.PI) /
+ 2) *
+ Math.pow(2, zoom)
+ )
+}
diff --git a/src/toolbox/functions/buildColor.ts b/src/toolbox/functions/buildColor.ts
index 65db685..8c57c46 100644
--- a/src/toolbox/functions/buildColor.ts
+++ b/src/toolbox/functions/buildColor.ts
@@ -8,9 +8,10 @@ export function buildColor(color: Color3, scene: Scene, parent: TransformNode, i
const height = .1;
const material = new StandardMaterial("material-" + color.toHexString(), scene);
material.diffuseColor = color;
- material.ambientColor = color;
- material.roughness = .1;
- material.maxSimultaneousLights = 1;
+
+ // material.ambientColor = color;
+ //material.roughness = .1;
+ //material.maxSimultaneousLights = 2;
const colorBoxMesh = MeshBuilder.CreatePlane("toolbox-color-" + color.toHexString(), {
width: width,
diff --git a/src/util/customEnvironment.ts b/src/util/customEnvironment.ts
index 2d5cb50..082d00b 100644
--- a/src/util/customEnvironment.ts
+++ b/src/util/customEnvironment.ts
@@ -1,13 +1,13 @@
import {
Color3,
GroundMesh,
- HemisphericLight,
Material,
MeshBuilder,
Observable,
PBRMaterial,
PhysicsAggregate,
PhysicsShapeType,
+ PointLight,
PointsCloudSystem,
Scene,
Sound,
@@ -33,13 +33,14 @@ export class CustomEnvironment {
if (loading) {
loading.remove();
}
- this.scene.ambientColor = new Color3(.2, .2, .2);
- const light = new HemisphericLight("light1", new Vector3(1, 2, 1), this.scene);
- light.groundColor = new Color3(.1, .1, .1)
- light.diffuse = new Color3(1, 1, 1);
- light.setDirectionToTarget(new Vector3(.4, .5, .5).normalize());
- light.intensity = .5;
-
+ this.scene.ambientColor = new Color3(1, 1, 1);
+ //const light = new HemisphericLight("light1", new Vector3(1, 2, 1), this.scene);
+ //light.groundColor = new Color3(.1, .1, .1)
+ //light.diffuse = new Color3(1, 1, 1);
+ //light.setDirectionToTarget(new Vector3(.4, .5, .5).normalize());
+ //light.intensity = .7;
+ const light = new PointLight("light1", new Vector3(0, 10, 10), this.scene);
+ const light2 = new PointLight("light1", new Vector3(0, 10, -10), this.scene);
const physics = new CustomPhysics(this.scene, config);
physics
.initializeAsync()
diff --git a/src/vrApp.ts b/src/vrApp.ts
index 6b30bc5..20be695 100644
--- a/src/vrApp.ts
+++ b/src/vrApp.ts
@@ -60,6 +60,7 @@ export class VrApp {
initEnvironment(diagramManager, spinner);
const gamepadManager = new GamepadManager(scene);
addSceneInspector();
+ //const camMenu = new CameraMenu(scene);
const el = document.querySelector('#download');
if (el) {
el.addEventListener('click', () => {