spacemap 0.1.9 → 0.1.10
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/README.md +1 -1
- package/dist/spacemap.iife.js +207 -91
- package/dist/spacemap.js +207 -91
- package/index.d.ts +4 -0
- package/index.js +591 -49
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*! spacemap SDK — https://spacemap.co — Mozilla Public License 2.0. Bundles MIT and ISC libraries: THIRD_PARTY_NOTICES.txt in the spacemap npm package. */
|
|
2
|
-
import { ACESFilmicToneMapping, AdditiveBlending, AmbientLight, ArrowHelper, BackSide, Box3, BufferAttribute, BufferGeometry, CanvasTexture, Color, CubeTexture, CustomBlending, DataTexture, DepthTexture, DirectionalLight, DoubleSide, Euler, Float32BufferAttribute, FloatType, FrontSide, Group, HalfFloatType, InstancedBufferAttribute, InstancedMesh, Line, LineBasicMaterial, LineLoop, LinearFilter, LinearMipmapLinearFilter, LinearSRGBColorSpace, MathUtils, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshStandardMaterial, NoBlending, NoColorSpace, NormalBlending, OneFactor, OneMinusSrcAlphaFactor, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, RGBAFormat, RawShaderMaterial, Raycaster, RedFormat, RingGeometry, SRGBColorSpace, Scene, ShaderChunk, ShaderMaterial, ShadowMaterial, Shape, ShapeGeometry, ShapeUtils, SphereGeometry, Sprite, SpriteMaterial, TOUCH, Texture, TextureLoader, Uint16BufferAttribute, UnsignedByteType, Vector2, Vector3, Vector4, WebGLRenderTarget, WebGLRenderer } from "three";
|
|
2
|
+
import { ACESFilmicToneMapping, AdditiveBlending, AmbientLight, ArrowHelper, BackSide, Box3, BufferAttribute, BufferGeometry, CanvasTexture, Color, CubeTexture, CustomBlending, DataArrayTexture, DataTexture, DepthTexture, DirectionalLight, DoubleSide, Euler, Float32BufferAttribute, FloatType, FrontSide, Group, HalfFloatType, InstancedBufferAttribute, InstancedMesh, Line, LineBasicMaterial, LineLoop, LinearFilter, LinearMipmapLinearFilter, LinearSRGBColorSpace, MathUtils, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshStandardMaterial, NearestFilter, NoBlending, NoColorSpace, NormalBlending, OneFactor, OneMinusSrcAlphaFactor, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, RGBAFormat, RawShaderMaterial, Raycaster, RedFormat, RepeatWrapping, RingGeometry, SRGBColorSpace, Scene, ShaderChunk, ShaderMaterial, ShadowMaterial, Shape, ShapeGeometry, ShapeUtils, SphereGeometry, Sprite, SpriteMaterial, TOUCH, Texture, TextureLoader, Uint16BufferAttribute, UnsignedByteType, Vector2, Vector3, Vector4, WebGLRenderTarget, WebGLRenderer } from "three";
|
|
3
3
|
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
|
4
4
|
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
|
|
5
5
|
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
|
|
@@ -20,6 +20,7 @@ var DEFAULT_HOST = {
|
|
|
20
20
|
dataUrl: "https://static.spacemap.co",
|
|
21
21
|
imagesUrl: "https://images.spacemap.co",
|
|
22
22
|
liveUrl: "https://live.spacemap.co",
|
|
23
|
+
tilesUrl: "",
|
|
23
24
|
locale: () => "en",
|
|
24
25
|
messages: {
|
|
25
26
|
body_note_no_model: () => "no model available",
|
|
@@ -66,6 +67,7 @@ function configureHost(overrides) {
|
|
|
66
67
|
current$1.dataUrl = current$1.dataUrl.replace(/\/$/, "");
|
|
67
68
|
current$1.imagesUrl = current$1.imagesUrl.replace(/\/$/, "");
|
|
68
69
|
current$1.liveUrl = current$1.liveUrl.replace(/\/$/, "");
|
|
70
|
+
current$1.tilesUrl = current$1.tilesUrl.replace(/\/$/, "");
|
|
69
71
|
}
|
|
70
72
|
function host() {
|
|
71
73
|
return current$1;
|
|
@@ -2963,6 +2965,14 @@ function get_custom_elements_slots(element) {
|
|
|
2963
2965
|
function dataBase() {
|
|
2964
2966
|
return host().dataUrl;
|
|
2965
2967
|
}
|
|
2968
|
+
function tilesBase() {
|
|
2969
|
+
return host().tilesUrl;
|
|
2970
|
+
}
|
|
2971
|
+
function tileUrl(tiles, cap, level, x, y, frame) {
|
|
2972
|
+
const month = frame === void 0 ? "" : `${String(frame).padStart(2, "0")}/`;
|
|
2973
|
+
const chart = cap && `${cap}/`;
|
|
2974
|
+
return `${tilesBase()}/v1/tiles/${tiles.id}/${month}${chart}${level}/${x}/${y}.webp?v=${tiles.version}`;
|
|
2975
|
+
}
|
|
2966
2976
|
var versions = {};
|
|
2967
2977
|
function setDataVersions(v) {
|
|
2968
2978
|
versions = v ?? {};
|
|
@@ -6933,7 +6943,7 @@ var VisibilityController = class {
|
|
|
6933
6943
|
}
|
|
6934
6944
|
ratioVisibility(body, camDistThreeJS, pinned) {
|
|
6935
6945
|
if (!pinned && this.getLayers().hidesBody(body.data.objectType, body.data.parentId)) return VISIBILITY.HIDE;
|
|
6936
|
-
if (body.data.orbitalSource === OrbitalSource.SPICE_PROBE) return this.getProbeVisibility(body);
|
|
6946
|
+
if (body.data.orbitalSource === OrbitalSource.SPICE_PROBE) return this.getProbeVisibility(body, camDistThreeJS);
|
|
6937
6947
|
const earthFilter = this.getEarthSatGroupFilter();
|
|
6938
6948
|
if (earthFilter && body.data.parentId === "naif-399" && !earthFilter.has(body.data.id)) return VISIBILITY.HIDE;
|
|
6939
6949
|
const ot = body.data.objectType;
|
|
@@ -6958,7 +6968,7 @@ var VisibilityController = class {
|
|
|
6958
6968
|
const tier = computeVisibilityFromRatio(camDistThreeJS / 10 / refA, this.scaledSystem, 50, isFocused);
|
|
6959
6969
|
return tier === VISIBILITY.CLOSE ? VISIBILITY.FULL : tier;
|
|
6960
6970
|
}
|
|
6961
|
-
getProbeVisibility(body) {
|
|
6971
|
+
getProbeVisibility(body, camDistThreeJS) {
|
|
6962
6972
|
const ps = this.getProbeStore();
|
|
6963
6973
|
if ((ps ? ps.containingSystemAt(body.data.id, this.currentJd) : null) === EARTH_SYSTEM_NAIF && this.getEarthSatGroupFilter()) return VISIBILITY.HIDE;
|
|
6964
6974
|
const isFocused = body.data.id === this.focusedBodyIdPlain;
|
|
@@ -6974,7 +6984,7 @@ var VisibilityController = class {
|
|
|
6974
6984
|
if (!parent?.position || !body.position) return VISIBILITY.FULL;
|
|
6975
6985
|
const distToParent = f64dist(body.position, parent.position) / 10;
|
|
6976
6986
|
if (distToParent === 0) return VISIBILITY.FULL;
|
|
6977
|
-
return
|
|
6987
|
+
return camDistThreeJS / 10 / distToParent <= this.scaledPlanetary[VISIBILITY.FULL] * (isFocused ? 5 : 1) ? VISIBILITY.FULL : VISIBILITY.HIDE;
|
|
6978
6988
|
}
|
|
6979
6989
|
isProbeInFocusedSystem(body) {
|
|
6980
6990
|
const parentId = body.data.parentId;
|
|
@@ -8179,19 +8189,11 @@ function extendProbeTrailBuffer(buf, sample, lastJd, lastPos, headJd) {
|
|
|
8179
8189
|
//#endregion
|
|
8180
8190
|
//#region src/lib/scene/objects/trail/points.ts
|
|
8181
8191
|
var NUM_TRAIL_POINTS = 512;
|
|
8182
|
-
function
|
|
8183
|
-
if (curve.length === 0) return [];
|
|
8184
|
-
const anchor = body.trailAnchor ?? body.position;
|
|
8185
|
-
if (!anchor) return [];
|
|
8186
|
-
const bodyLocal = [
|
|
8187
|
-
anchor[0] - cx,
|
|
8188
|
-
anchor[1] - cy,
|
|
8189
|
-
anchor[2] - cz
|
|
8190
|
-
];
|
|
8192
|
+
function nearestStart(curve, at) {
|
|
8191
8193
|
let nearest = 0;
|
|
8192
8194
|
let best = Infinity;
|
|
8193
8195
|
for (let j = 0; j < curve.length; j++) {
|
|
8194
|
-
const d = (curve[j][0] -
|
|
8196
|
+
const d = (curve[j][0] - at[0]) ** 2 + (curve[j][1] - at[1]) ** 2 + (curve[j][2] - at[2]) ** 2;
|
|
8195
8197
|
if (d < best) {
|
|
8196
8198
|
best = d;
|
|
8197
8199
|
nearest = j;
|
|
@@ -8199,7 +8201,18 @@ function buildTrailPoints(body, curve, isOpenCurve, cx, cy, cz) {
|
|
|
8199
8201
|
}
|
|
8200
8202
|
const prev = Math.max(nearest - 1, 0);
|
|
8201
8203
|
const next = Math.min(nearest + 1, curve.length - 1);
|
|
8202
|
-
|
|
8204
|
+
return (curve[prev][0] - at[0]) ** 2 + (curve[prev][1] - at[1]) ** 2 + (curve[prev][2] - at[2]) ** 2 < (curve[next][0] - at[0]) ** 2 + (curve[next][1] - at[1]) ** 2 + (curve[next][2] - at[2]) ** 2 ? prev : nearest;
|
|
8205
|
+
}
|
|
8206
|
+
function buildTrailPoints(body, curve, isOpenCurve, cx, cy, cz, start) {
|
|
8207
|
+
if (curve.length === 0) return [];
|
|
8208
|
+
const anchor = body.trailAnchor ?? body.position;
|
|
8209
|
+
if (!anchor) return [];
|
|
8210
|
+
const bodyLocal = [
|
|
8211
|
+
anchor[0] - cx,
|
|
8212
|
+
anchor[1] - cy,
|
|
8213
|
+
anchor[2] - cz
|
|
8214
|
+
];
|
|
8215
|
+
const trailStart = start ?? nearestStart(curve, bodyLocal);
|
|
8203
8216
|
const points = [bodyLocal];
|
|
8204
8217
|
if (isOpenCurve) for (let k = 0; k < 512 - 1; k++) {
|
|
8205
8218
|
const idx = Math.max(trailStart - k, 0);
|
|
@@ -8295,12 +8308,16 @@ var ChunkLoader = class {
|
|
|
8295
8308
|
const parentKey = `naif-${body.parentId}`;
|
|
8296
8309
|
const objType = body.objectType;
|
|
8297
8310
|
const primaryId = objType === ObjectType.MOON && body.parentId >= 1 && body.parentId <= 9 ? `naif-${body.parentId * 100 + 99}` : null;
|
|
8298
|
-
const
|
|
8311
|
+
const elementsAt = (record, at) => {
|
|
8312
|
+
if (!primaryId) return chebyshevOsculatingElements(record, record.parentId, at);
|
|
8313
|
+
const primary = cheb.body(primaryId, at);
|
|
8314
|
+
return primary ? chebyshevOsculatingElements(record, record.parentId, at, primary) : null;
|
|
8315
|
+
};
|
|
8316
|
+
const elements = elementsAt(body, jd);
|
|
8299
8317
|
const ownId = body.id;
|
|
8300
8318
|
const ownRederive = (newJd) => {
|
|
8301
8319
|
const fresh = cheb.body(ownId, newJd);
|
|
8302
|
-
|
|
8303
|
-
return chebyshevOsculatingElements(fresh, fresh.parentId, newJd, primaryId ? cheb.body(primaryId, newJd) ?? void 0 : void 0);
|
|
8320
|
+
return fresh ? elementsAt(fresh, newJd) : null;
|
|
8304
8321
|
};
|
|
8305
8322
|
const fallbackA = Math.hypot(offset[0], offset[1], offset[2]) / 10;
|
|
8306
8323
|
const data = {
|
|
@@ -8950,6 +8967,14 @@ var ChunkWindow = class {
|
|
|
8950
8967
|
done
|
|
8951
8968
|
};
|
|
8952
8969
|
}
|
|
8970
|
+
loadingAt(jd, zone) {
|
|
8971
|
+
if (this.inflight.size === 0) return false;
|
|
8972
|
+
for (const [name, params] of this.zoneParams) {
|
|
8973
|
+
if (zone !== void 0 && name !== zone) continue;
|
|
8974
|
+
if (this.inflight.has(chunkKey(name, chunkIndexForJd(params, jd)))) return true;
|
|
8975
|
+
}
|
|
8976
|
+
return false;
|
|
8977
|
+
}
|
|
8953
8978
|
pendingCurrent(jd) {
|
|
8954
8979
|
if (this.inflight.size === 0) return RESOLVED;
|
|
8955
8980
|
let pending = null;
|
|
@@ -9021,6 +9046,10 @@ var ChebyshevStore = class extends ChunkWindow {
|
|
|
9021
9046
|
end: params.end_jd
|
|
9022
9047
|
};
|
|
9023
9048
|
}
|
|
9049
|
+
isLoading(objectId, jd) {
|
|
9050
|
+
const zone = this.idToZone.get(objectId);
|
|
9051
|
+
return zone !== void 0 && this.loadingAt(jd, zone);
|
|
9052
|
+
}
|
|
9024
9053
|
resolve(objectId, jd) {
|
|
9025
9054
|
const zone = this.idToZone.get(objectId);
|
|
9026
9055
|
if (zone === void 0) return null;
|
|
@@ -10059,6 +10088,7 @@ var RENDER_TIER_PRESETS = {
|
|
|
10059
10088
|
bloomScale: .5,
|
|
10060
10089
|
pointBudget: 4e5,
|
|
10061
10090
|
maxTextureTier: "medium",
|
|
10091
|
+
tileWindows: 3,
|
|
10062
10092
|
maxSkyboxFace: 2048
|
|
10063
10093
|
},
|
|
10064
10094
|
medium: {
|
|
@@ -10068,6 +10098,7 @@ var RENDER_TIER_PRESETS = {
|
|
|
10068
10098
|
bloomScale: .75,
|
|
10069
10099
|
pointBudget: 9e5,
|
|
10070
10100
|
maxTextureTier: "medium",
|
|
10101
|
+
tileWindows: 4,
|
|
10071
10102
|
maxSkyboxFace: 2048
|
|
10072
10103
|
},
|
|
10073
10104
|
high: {
|
|
@@ -10077,6 +10108,7 @@ var RENDER_TIER_PRESETS = {
|
|
|
10077
10108
|
bloomScale: 1,
|
|
10078
10109
|
pointBudget: Infinity,
|
|
10079
10110
|
maxTextureTier: "high",
|
|
10111
|
+
tileWindows: 6,
|
|
10080
10112
|
maxSkyboxFace: Infinity
|
|
10081
10113
|
}
|
|
10082
10114
|
};
|
|
@@ -10084,6 +10116,10 @@ function maxTextureTier() {
|
|
|
10084
10116
|
if (isLowEndDevice()) return "low";
|
|
10085
10117
|
return currentRenderTier().maxTextureTier;
|
|
10086
10118
|
}
|
|
10119
|
+
function maxTileWindows() {
|
|
10120
|
+
if (isLowEndDevice()) return 0;
|
|
10121
|
+
return currentRenderTier().tileWindows;
|
|
10122
|
+
}
|
|
10087
10123
|
function resolveRenderTier() {
|
|
10088
10124
|
const measured = sceneSettings().atmosphereCalibration?.tier;
|
|
10089
10125
|
if (measured === "low" || measured === "medium") return measured;
|
|
@@ -15429,6 +15465,491 @@ function detachSelfShadow(uniforms) {
|
|
|
15429
15465
|
uniforms.uSelfScale.value = 0;
|
|
15430
15466
|
}
|
|
15431
15467
|
|
|
15468
|
+
//#endregion
|
|
15469
|
+
//#region src/lib/scene/lod/tile-window.ts
|
|
15470
|
+
var WINDOW_TILES = 4;
|
|
15471
|
+
var MAP = 0;
|
|
15472
|
+
var NORTH = 1;
|
|
15473
|
+
var SOUTH = 2;
|
|
15474
|
+
var CHART_FOLDER = [
|
|
15475
|
+
"",
|
|
15476
|
+
"north",
|
|
15477
|
+
"south"
|
|
15478
|
+
];
|
|
15479
|
+
var FIRST_TILE_LEVEL = 3;
|
|
15480
|
+
var HOLD_TILES = .75;
|
|
15481
|
+
var BASE_WIDTH_PX = 2048;
|
|
15482
|
+
var CAP_EDGE = Math.SQRT2 - 1;
|
|
15483
|
+
var CAP_ENTER_DEG = 62;
|
|
15484
|
+
var CAP_LEAVE_DEG = 58;
|
|
15485
|
+
var BOTH_CHARTS_DEG = 45;
|
|
15486
|
+
function chartColumns(chart, level) {
|
|
15487
|
+
return chart === 0 ? 2 << level : 1 << level - 1;
|
|
15488
|
+
}
|
|
15489
|
+
function chartRows(chart, level) {
|
|
15490
|
+
return chart === 0 ? 1 << level : 1 << level - 1;
|
|
15491
|
+
}
|
|
15492
|
+
function neededLevel(radiusScene, dist, projScale, maxLevel) {
|
|
15493
|
+
const height = Math.max(dist - radiusScene, radiusScene * 1e-6);
|
|
15494
|
+
const widthPx = 2 * Math.PI * radiusScene * projScale / height;
|
|
15495
|
+
return Math.min(Math.ceil(Math.log2(widthPx / BASE_WIDTH_PX)), maxLevel);
|
|
15496
|
+
}
|
|
15497
|
+
function chartPoint(chart, x, y, z) {
|
|
15498
|
+
if (chart === 0) {
|
|
15499
|
+
const east = Math.atan2(z, -x) / (2 * Math.PI);
|
|
15500
|
+
return {
|
|
15501
|
+
x: east < 0 ? east + 1 : east,
|
|
15502
|
+
y: Math.acos(Math.min(Math.max(y, -1), 1)) / Math.PI
|
|
15503
|
+
};
|
|
15504
|
+
}
|
|
15505
|
+
const side = chart === 1 ? 1 : -1;
|
|
15506
|
+
const scale = .5 / (CAP_EDGE * (1 + side * y));
|
|
15507
|
+
return {
|
|
15508
|
+
x: .5 + x * scale,
|
|
15509
|
+
y: .5 + side * z * scale
|
|
15510
|
+
};
|
|
15511
|
+
}
|
|
15512
|
+
function cameraChart(y, previous) {
|
|
15513
|
+
const cap = y >= 0 ? 1 : 2;
|
|
15514
|
+
return Math.asin(Math.min(Math.abs(y), 1)) * 180 / Math.PI > (previous === cap ? CAP_LEAVE_DEG : CAP_ENTER_DEG) ? cap : 0;
|
|
15515
|
+
}
|
|
15516
|
+
function windowChain(level, count, chart, y) {
|
|
15517
|
+
const chain = [];
|
|
15518
|
+
for (let z = level; z >= 3 && chain.length < count; z--) chain.push({
|
|
15519
|
+
chart,
|
|
15520
|
+
level: z
|
|
15521
|
+
});
|
|
15522
|
+
const reached = chain.length > 0 && chain[chain.length - 1].level === 3;
|
|
15523
|
+
const both = Math.abs(y) > Math.sin(BOTH_CHARTS_DEG * Math.PI / 180);
|
|
15524
|
+
if (reached && both && chain.length < count) {
|
|
15525
|
+
const cap = y >= 0 ? 1 : 2;
|
|
15526
|
+
chain.push({
|
|
15527
|
+
chart: chart === 0 ? cap : 0,
|
|
15528
|
+
level: 3
|
|
15529
|
+
});
|
|
15530
|
+
}
|
|
15531
|
+
return chain;
|
|
15532
|
+
}
|
|
15533
|
+
function placeAxis(at, count, wraps, kept) {
|
|
15534
|
+
const last = Math.max(count - 4, 0);
|
|
15535
|
+
if (kept !== void 0) {
|
|
15536
|
+
let off = at - (kept + 4 / 2);
|
|
15537
|
+
if (wraps) off -= count * Math.round(off / count);
|
|
15538
|
+
if (!wraps && (kept === 0 && off < 0 || kept === last && off > 0) || Math.abs(off) <= HOLD_TILES) return kept;
|
|
15539
|
+
}
|
|
15540
|
+
const first = Math.round(at - 4 / 2);
|
|
15541
|
+
return wraps ? (first % count + count) % count : Math.min(Math.max(first, 0), last);
|
|
15542
|
+
}
|
|
15543
|
+
function placeWindow(chart, level, x, y, previous) {
|
|
15544
|
+
const columns = chartColumns(chart, level);
|
|
15545
|
+
const rows = chartRows(chart, level);
|
|
15546
|
+
const kept = previous?.chart === chart && previous.level === level ? previous : void 0;
|
|
15547
|
+
const tx0 = placeAxis(x * columns, columns, chart === 0, kept?.tx0);
|
|
15548
|
+
const ty0 = placeAxis(y * rows, rows, false, kept?.ty0);
|
|
15549
|
+
if (kept && kept.tx0 === tx0 && kept.ty0 === ty0) return kept;
|
|
15550
|
+
return {
|
|
15551
|
+
chart,
|
|
15552
|
+
level,
|
|
15553
|
+
tx0,
|
|
15554
|
+
ty0
|
|
15555
|
+
};
|
|
15556
|
+
}
|
|
15557
|
+
function slotTile(placement, sx, sy) {
|
|
15558
|
+
const columns = chartColumns(placement.chart, placement.level);
|
|
15559
|
+
const dx = ((sx - placement.tx0) % 4 + 4) % 4;
|
|
15560
|
+
const dy = ((sy - placement.ty0) % 4 + 4) % 4;
|
|
15561
|
+
return {
|
|
15562
|
+
x: (placement.tx0 + dx) % columns,
|
|
15563
|
+
y: placement.ty0 + dy
|
|
15564
|
+
};
|
|
15565
|
+
}
|
|
15566
|
+
|
|
15567
|
+
//#endregion
|
|
15568
|
+
//#region src/lib/scene/objects/surface/tile-overlay.ts
|
|
15569
|
+
var MAX_WINDOWS = 6;
|
|
15570
|
+
var MAX_DRAWN = MAX_WINDOWS + 1;
|
|
15571
|
+
var MAX_INFLIGHT = 6;
|
|
15572
|
+
var MAX_FAILURES = 4;
|
|
15573
|
+
var FETCH_TIMEOUT_S = 30;
|
|
15574
|
+
var IDLE_DISPOSE_S = 5;
|
|
15575
|
+
var FEATHER_TILES = .5;
|
|
15576
|
+
var MAX_ANISOTROPY = 16;
|
|
15577
|
+
var SLOTS = 4 * 4;
|
|
15578
|
+
var PARS = `
|
|
15579
|
+
varying vec3 vTileDir;
|
|
15580
|
+
uniform sampler2DArray uTileMap;
|
|
15581
|
+
uniform sampler2DArray uTileMask;
|
|
15582
|
+
uniform vec4 uTileGrid[ ${MAX_DRAWN} ];
|
|
15583
|
+
uniform vec4 uTileWindow[ ${MAX_DRAWN} ];
|
|
15584
|
+
// Most taps of the anisotropic filter, and a tile's side in pixels.
|
|
15585
|
+
uniform vec2 uTileFilter;
|
|
15586
|
+
|
|
15587
|
+
// Long and short half-axes of the footprint whose sides are fx and fy. The
|
|
15588
|
+
// two sides alone would do where the stretch runs along the screen's axes;
|
|
15589
|
+
// around a pole it runs every way, and each side then holds most of it.
|
|
15590
|
+
void tileAxes( vec2 fx, vec2 fy, out vec2 major, out vec2 minor ) {
|
|
15591
|
+
float p = fx.x * fx.x + fy.x * fy.x;
|
|
15592
|
+
float q = fx.y * fx.y + fy.y * fy.y;
|
|
15593
|
+
float r = fx.x * fx.y + fy.x * fy.y;
|
|
15594
|
+
float det = fx.x * fy.y - fx.y * fy.x;
|
|
15595
|
+
float hi = 0.5 * ( p + q ) + sqrt( 0.25 * ( p - q ) * ( p - q ) + r * r );
|
|
15596
|
+
float lo = det * det / max( hi, 1e-30 );
|
|
15597
|
+
vec2 axis = p >= q ? vec2( hi - q, r ) : vec2( r, hi - p );
|
|
15598
|
+
float len = length( axis );
|
|
15599
|
+
axis = len > 0.0 ? axis / len : vec2( 1.0, 0.0 );
|
|
15600
|
+
major = axis * sqrt( hi );
|
|
15601
|
+
minor = vec2( - axis.y, axis.x ) * sqrt( lo );
|
|
15602
|
+
}
|
|
15603
|
+
|
|
15604
|
+
vec3 tileColour( vec3 below ) {
|
|
15605
|
+
if ( uTileWindow[ 0 ].w < 0.5 ) return below;
|
|
15606
|
+
|
|
15607
|
+
// Where the fragment is on each chart, as fractions from the chart's
|
|
15608
|
+
// north-west corner, and what a screen pixel spans there. Both come from
|
|
15609
|
+
// the direction of the fragment rather than its interpolated coordinates:
|
|
15610
|
+
// those have one slope per triangle, which near a pole differs enough
|
|
15611
|
+
// between the two triangles of a grid cell to pick different levels, and
|
|
15612
|
+
// they jump at the 180° meridian.
|
|
15613
|
+
vec3 dir = normalize( vTileDir );
|
|
15614
|
+
vec3 ddx = dFdx( dir );
|
|
15615
|
+
vec3 ddy = dFdy( dir );
|
|
15616
|
+
|
|
15617
|
+
float flat2 = max( dir.x * dir.x + dir.z * dir.z, 1e-12 );
|
|
15618
|
+
float east = 1.0 / ( 2.0 * PI * flat2 );
|
|
15619
|
+
float south = - 1.0 / ( PI * sqrt( flat2 ) );
|
|
15620
|
+
vec2 mapAt = vec2( fract( atan( dir.z, - dir.x ) / ( 2.0 * PI ) ), acos( clamp( dir.y, - 1.0, 1.0 ) ) / PI );
|
|
15621
|
+
vec2 mapDx = vec2( ( dir.z * ddx.x - dir.x * ddx.z ) * east, ddx.y * south );
|
|
15622
|
+
vec2 mapDy = vec2( ( dir.z * ddy.x - dir.x * ddy.z ) * east, ddy.y * south );
|
|
15623
|
+
|
|
15624
|
+
// The cap of the fragment's own hemisphere, seen from above its pole.
|
|
15625
|
+
float side = dir.y < 0.0 ? - 1.0 : 1.0;
|
|
15626
|
+
float fold = 1.0 + side * dir.y;
|
|
15627
|
+
vec2 plane = vec2( dir.x, side * dir.z );
|
|
15628
|
+
float capScale = 0.5 / ( ${CAP_EDGE.toFixed(8)} * fold );
|
|
15629
|
+
vec2 capAt = 0.5 + plane * capScale;
|
|
15630
|
+
vec2 capDx = ( vec2( ddx.x, side * ddx.z ) - plane * ( side * ddx.y / fold ) ) * capScale;
|
|
15631
|
+
vec2 capDy = ( vec2( ddy.x, side * ddy.z ) - plane * ( side * ddy.y / fold ) ) * capScale;
|
|
15632
|
+
|
|
15633
|
+
float rows = ${4 .toFixed(1)};
|
|
15634
|
+
vec3 colour = vec3( 0.0 );
|
|
15635
|
+
float covered = 0.0;
|
|
15636
|
+
for ( int i = 0; i < ${MAX_DRAWN}; i ++ ) {
|
|
15637
|
+
vec4 window = uTileWindow[ i ];
|
|
15638
|
+
if ( window.w < 0.5 ) break;
|
|
15639
|
+
vec4 grid = uTileGrid[ i ];
|
|
15640
|
+
bool onMap = window.x < 0.5;
|
|
15641
|
+
// The other pole's cap.
|
|
15642
|
+
if ( ! onMap && ( window.x < 1.5 ) != ( side > 0.0 ) ) continue;
|
|
15643
|
+
vec2 tile = ( onMap ? mapAt : capAt ) * grid.xy;
|
|
15644
|
+
vec2 dx = ( onMap ? mapDx : capDx ) * grid.xy * uTileFilter.y;
|
|
15645
|
+
vec2 dy = ( onMap ? mapDy : capDy ) * grid.xy * uTileFilter.y;
|
|
15646
|
+
|
|
15647
|
+
// Level this fragment asks of the window, from the short axis of its
|
|
15648
|
+
// footprint in the window's pixels: the long axis is the anisotropic
|
|
15649
|
+
// filter's to cover, as far as its taps reach. The window fades in
|
|
15650
|
+
// over the level below its own, as a mipmap would.
|
|
15651
|
+
vec2 major;
|
|
15652
|
+
vec2 minor;
|
|
15653
|
+
tileAxes( dx, dy, major, minor );
|
|
15654
|
+
float foot = max( length( minor ), length( major ) / uTileFilter.x );
|
|
15655
|
+
float weight = clamp( 1.0 - log2( max( foot, 1e-6 ) ), 0.0, 1.0 );
|
|
15656
|
+
if ( weight <= 0.0 ) continue;
|
|
15657
|
+
|
|
15658
|
+
// Half a pixel in from a pole of the map: past it the filter would
|
|
15659
|
+
// read the far row.
|
|
15660
|
+
if ( onMap ) tile.y = clamp( tile.y, 0.0005, grid.y - 0.0005 );
|
|
15661
|
+
// Offset from the window's north-west corner; the map's longitude wraps.
|
|
15662
|
+
vec2 rel = tile - grid.zw;
|
|
15663
|
+
if ( onMap ) rel.x = mod( rel.x, grid.x );
|
|
15664
|
+
if ( rel.x < 0.0 || rel.x > rows || rel.y < 0.0 || rel.y > rows ) continue;
|
|
15665
|
+
// Distance to the window's edge, in tiles. A pole of the map is no
|
|
15666
|
+
// edge: nothing lies past it.
|
|
15667
|
+
vec2 near = min( rel, rows - rel );
|
|
15668
|
+
if ( onMap && grid.w < 0.5 ) near.y = rows - rel.y;
|
|
15669
|
+
if ( onMap && grid.w + rows > grid.y - 0.5 ) near.y = grid.w < 0.5 ? rows : rel.y;
|
|
15670
|
+
float edge = min( near.x, near.y );
|
|
15671
|
+
|
|
15672
|
+
ivec3 slot = ivec3( int( mod( tile.x, rows ) ), int( mod( tile.y, rows ) ), int( window.y ) );
|
|
15673
|
+
float alpha = weight * texelFetch( uTileMask, slot, 0 ).r * smoothstep( 0.0, ${FEATHER_TILES.toFixed(2)}, edge );
|
|
15674
|
+
if ( alpha <= 0.0 ) continue;
|
|
15675
|
+
|
|
15676
|
+
// The texture repeats every window: a tile sits in the slot its own
|
|
15677
|
+
// column and row pick, north up.
|
|
15678
|
+
vec3 st = vec3( tile.x / rows, - tile.y / rows, window.y );
|
|
15679
|
+
vec2 texel = vec2( 1.0, - 1.0 ) / ( rows * uTileFilter.y );
|
|
15680
|
+
colour += ( 1.0 - covered ) * alpha * textureGrad( uTileMap, st, major * texel, minor * texel ).rgb;
|
|
15681
|
+
covered += ( 1.0 - covered ) * alpha;
|
|
15682
|
+
if ( covered > 0.995 ) break;
|
|
15683
|
+
}
|
|
15684
|
+
return colour + ( 1.0 - covered ) * below;
|
|
15685
|
+
}
|
|
15686
|
+
`;
|
|
15687
|
+
var MAP_FRAGMENT = `
|
|
15688
|
+
#ifdef USE_MAP
|
|
15689
|
+
vec4 sampledDiffuseColor = texture2D( map, vMapUv );
|
|
15690
|
+
sampledDiffuseColor.rgb = tileColour( sampledDiffuseColor.rgb );
|
|
15691
|
+
diffuseColor *= sampledDiffuseColor;
|
|
15692
|
+
#endif
|
|
15693
|
+
`;
|
|
15694
|
+
function createOverlay(material) {
|
|
15695
|
+
const overlay = {
|
|
15696
|
+
material,
|
|
15697
|
+
uniforms: {
|
|
15698
|
+
uTileMap: { value: null },
|
|
15699
|
+
uTileMask: { value: null },
|
|
15700
|
+
uTileGrid: { value: Array.from({ length: MAX_DRAWN }, () => new Vector4()) },
|
|
15701
|
+
uTileWindow: { value: Array.from({ length: MAX_DRAWN }, () => new Vector4()) },
|
|
15702
|
+
uTileFilter: { value: new Vector2(1, 1) }
|
|
15703
|
+
},
|
|
15704
|
+
inflight: 0,
|
|
15705
|
+
failures: 0,
|
|
15706
|
+
failed: /* @__PURE__ */ new Set(),
|
|
15707
|
+
dead: false,
|
|
15708
|
+
lastUsed: 0
|
|
15709
|
+
};
|
|
15710
|
+
chainShaderHook(material, "surfaceTiles", (shader) => {
|
|
15711
|
+
Object.assign(shader.uniforms, overlay.uniforms);
|
|
15712
|
+
shader.vertexShader = shader.vertexShader.replace("#include <common>", "#include <common>\nvarying vec3 vTileDir;").replace("#include <begin_vertex>", "#include <begin_vertex>\nvTileDir = position;");
|
|
15713
|
+
shader.fragmentShader = shader.fragmentShader.replace("#include <map_pars_fragment>", `#include <map_pars_fragment>\n${PARS}`).replace("#include <map_fragment>", MAP_FRAGMENT);
|
|
15714
|
+
});
|
|
15715
|
+
return overlay;
|
|
15716
|
+
}
|
|
15717
|
+
function createStore(tileSize, layers, renderer) {
|
|
15718
|
+
const size = tileSize * 4;
|
|
15719
|
+
const texture = new DataArrayTexture(null, size, size, layers);
|
|
15720
|
+
texture.source.dataReady = false;
|
|
15721
|
+
texture.format = RGBAFormat;
|
|
15722
|
+
texture.type = UnsignedByteType;
|
|
15723
|
+
texture.colorSpace = SRGBColorSpace;
|
|
15724
|
+
texture.wrapS = texture.wrapT = RepeatWrapping;
|
|
15725
|
+
texture.minFilter = texture.magFilter = LinearFilter;
|
|
15726
|
+
texture.generateMipmaps = false;
|
|
15727
|
+
texture.anisotropy = Math.min(MAX_ANISOTROPY, renderer.capabilities.getMaxAnisotropy());
|
|
15728
|
+
texture.needsUpdate = true;
|
|
15729
|
+
const mask = new DataArrayTexture(new Uint8Array(SLOTS * layers), 4, 4, layers);
|
|
15730
|
+
mask.format = RedFormat;
|
|
15731
|
+
mask.type = UnsignedByteType;
|
|
15732
|
+
mask.minFilter = mask.magFilter = NearestFilter;
|
|
15733
|
+
mask.unpackAlignment = 1;
|
|
15734
|
+
mask.needsUpdate = true;
|
|
15735
|
+
return {
|
|
15736
|
+
texture,
|
|
15737
|
+
mask,
|
|
15738
|
+
windows: [],
|
|
15739
|
+
free: Array.from({ length: layers }, (_, layer) => layer),
|
|
15740
|
+
tileSize
|
|
15741
|
+
};
|
|
15742
|
+
}
|
|
15743
|
+
function setLoaded(store, layer, slot, loaded) {
|
|
15744
|
+
store.mask.image.data[layer * SLOTS + slot] = loaded ? 255 : 0;
|
|
15745
|
+
store.mask.needsUpdate = true;
|
|
15746
|
+
}
|
|
15747
|
+
function isLoaded(store, layer, slot) {
|
|
15748
|
+
return store.mask.image.data[layer * SLOTS + slot] !== 0;
|
|
15749
|
+
}
|
|
15750
|
+
function retarget(store, win, placement, frame) {
|
|
15751
|
+
if (win.placement === placement && win.frame === frame) return;
|
|
15752
|
+
win.placement = placement;
|
|
15753
|
+
win.frame = frame;
|
|
15754
|
+
for (let slot = 0; slot < SLOTS; slot++) {
|
|
15755
|
+
const { x, y } = slotTile(placement, slot % 4, Math.floor(slot / 4));
|
|
15756
|
+
const key = `${frame ?? 0}/${win.chart}/${win.level}/${x}/${y}`;
|
|
15757
|
+
if (win.wanted[slot] === key) continue;
|
|
15758
|
+
win.wanted[slot] = key;
|
|
15759
|
+
setLoaded(store, win.layer, slot, false);
|
|
15760
|
+
const stale = win.pending.get(slot);
|
|
15761
|
+
if (stale) {
|
|
15762
|
+
stale.abort.abort();
|
|
15763
|
+
win.pending.delete(slot);
|
|
15764
|
+
}
|
|
15765
|
+
}
|
|
15766
|
+
}
|
|
15767
|
+
function release(store, win) {
|
|
15768
|
+
for (const { abort } of win.pending.values()) abort.abort();
|
|
15769
|
+
win.pending.clear();
|
|
15770
|
+
for (let slot = 0; slot < SLOTS; slot++) setLoaded(store, win.layer, slot, false);
|
|
15771
|
+
store.free.push(win.layer);
|
|
15772
|
+
}
|
|
15773
|
+
function settled(overlay, store, win) {
|
|
15774
|
+
for (let slot = 0; slot < SLOTS; slot++) {
|
|
15775
|
+
const key = win.wanted[slot];
|
|
15776
|
+
if (!key) return false;
|
|
15777
|
+
if (!isLoaded(store, win.layer, slot) && !overlay.failed.has(key)) return false;
|
|
15778
|
+
}
|
|
15779
|
+
return true;
|
|
15780
|
+
}
|
|
15781
|
+
async function fetchTile(url, signal) {
|
|
15782
|
+
const response = await fetch(url, { signal });
|
|
15783
|
+
if (!response.ok) throw new Error(`tile ${response.status}`);
|
|
15784
|
+
return createImageBitmap(await response.blob(), {
|
|
15785
|
+
imageOrientation: "flipY",
|
|
15786
|
+
premultiplyAlpha: "none",
|
|
15787
|
+
colorSpaceConversion: "none"
|
|
15788
|
+
});
|
|
15789
|
+
}
|
|
15790
|
+
var copyAt = new Vector3();
|
|
15791
|
+
var queue$1 = [];
|
|
15792
|
+
function pump(overlay, store, tiles, win, x, y, renderer, invalidate) {
|
|
15793
|
+
const placement = win.placement;
|
|
15794
|
+
if (!placement) return;
|
|
15795
|
+
const columns = chartColumns(win.chart, win.level);
|
|
15796
|
+
const cx = x * columns;
|
|
15797
|
+
const cy = y * chartRows(win.chart, win.level);
|
|
15798
|
+
queue$1.length = 0;
|
|
15799
|
+
for (let slot = 0; slot < SLOTS; slot++) {
|
|
15800
|
+
const key = win.wanted[slot];
|
|
15801
|
+
if (!key || win.pending.has(slot) || overlay.failed.has(key)) continue;
|
|
15802
|
+
if (isLoaded(store, win.layer, slot)) continue;
|
|
15803
|
+
const tile = slotTile(placement, slot % 4, Math.floor(slot / 4));
|
|
15804
|
+
let dx = tile.x + .5 - cx;
|
|
15805
|
+
if (win.chart === 0) dx -= columns * Math.round(dx / columns);
|
|
15806
|
+
queue$1.push({
|
|
15807
|
+
slot,
|
|
15808
|
+
far: Math.hypot(dx, tile.y + .5 - cy)
|
|
15809
|
+
});
|
|
15810
|
+
}
|
|
15811
|
+
queue$1.sort((a, b) => a.far - b.far);
|
|
15812
|
+
for (const { slot } of queue$1) {
|
|
15813
|
+
if (overlay.inflight >= MAX_INFLIGHT) return;
|
|
15814
|
+
const key = win.wanted[slot];
|
|
15815
|
+
const sx = slot % 4;
|
|
15816
|
+
const sy = Math.floor(slot / 4);
|
|
15817
|
+
const tile = slotTile(placement, sx, sy);
|
|
15818
|
+
const abort = new AbortController();
|
|
15819
|
+
let timedOut = false;
|
|
15820
|
+
const timer = setTimeout(() => {
|
|
15821
|
+
timedOut = true;
|
|
15822
|
+
abort.abort();
|
|
15823
|
+
}, FETCH_TIMEOUT_S * 1e3);
|
|
15824
|
+
win.pending.set(slot, {
|
|
15825
|
+
key,
|
|
15826
|
+
abort
|
|
15827
|
+
});
|
|
15828
|
+
overlay.inflight++;
|
|
15829
|
+
const folder = CHART_FOLDER[win.chart];
|
|
15830
|
+
fetchTile(tileUrl(tiles, folder, win.level, tile.x, tile.y, win.frame), abort.signal).then((bitmap) => {
|
|
15831
|
+
if (win.wanted[slot] === key && !abort.signal.aborted) {
|
|
15832
|
+
const source = new Texture(bitmap);
|
|
15833
|
+
source.colorSpace = SRGBColorSpace;
|
|
15834
|
+
source.flipY = false;
|
|
15835
|
+
source.generateMipmaps = false;
|
|
15836
|
+
copyAt.set(sx * store.tileSize, (4 - 1 - sy) * store.tileSize, win.layer);
|
|
15837
|
+
renderer.copyTextureToTexture(source, store.texture, null, copyAt);
|
|
15838
|
+
source.dispose();
|
|
15839
|
+
setLoaded(store, win.layer, slot, true);
|
|
15840
|
+
overlay.failures = 0;
|
|
15841
|
+
invalidate();
|
|
15842
|
+
}
|
|
15843
|
+
bitmap.close();
|
|
15844
|
+
}).catch(() => {
|
|
15845
|
+
if (abort.signal.aborted && !timedOut) return;
|
|
15846
|
+
overlay.failed.add(key);
|
|
15847
|
+
if (++overlay.failures >= MAX_FAILURES) overlay.dead = true;
|
|
15848
|
+
}).finally(() => {
|
|
15849
|
+
clearTimeout(timer);
|
|
15850
|
+
overlay.inflight--;
|
|
15851
|
+
if (win.pending.get(slot)?.key === key) win.pending.delete(slot);
|
|
15852
|
+
});
|
|
15853
|
+
}
|
|
15854
|
+
}
|
|
15855
|
+
function switchOff(overlay) {
|
|
15856
|
+
for (const link of overlay.uniforms.uTileWindow.value) link.w = 0;
|
|
15857
|
+
}
|
|
15858
|
+
function rest(bo, overlay, now) {
|
|
15859
|
+
switchOff(overlay);
|
|
15860
|
+
if (now - overlay.lastUsed > IDLE_DISPOSE_S * 1e3) disposeTileOverlay(bo);
|
|
15861
|
+
}
|
|
15862
|
+
function disposeTileOverlay(bo) {
|
|
15863
|
+
const overlay = bo.tileOverlay;
|
|
15864
|
+
if (!overlay) return;
|
|
15865
|
+
switchOff(overlay);
|
|
15866
|
+
const store = overlay.store;
|
|
15867
|
+
if (!store) return;
|
|
15868
|
+
for (const win of store.windows) for (const { abort } of win.pending.values()) abort.abort();
|
|
15869
|
+
store.texture.dispose();
|
|
15870
|
+
store.mask.dispose();
|
|
15871
|
+
overlay.store = void 0;
|
|
15872
|
+
overlay.uniforms.uTileMap.value = null;
|
|
15873
|
+
overlay.uniforms.uTileMask.value = null;
|
|
15874
|
+
}
|
|
15875
|
+
function tilesServe(bo) {
|
|
15876
|
+
const tiles = bo.surfaceTiles;
|
|
15877
|
+
return !!tiles && tiles.max_level >= 3 && tilesBase() !== "" && maxTileWindows() > 0 && !bo.tileOverlay?.dead && textureAllowed(tiles.distribution);
|
|
15878
|
+
}
|
|
15879
|
+
var inverse = new Matrix4();
|
|
15880
|
+
var over = new Vector3();
|
|
15881
|
+
function updateTileOverlay(bo, camera, renderer, projScale, drawable, invalidate) {
|
|
15882
|
+
const tiles = bo.surfaceTiles;
|
|
15883
|
+
const mesh = bo.mesh;
|
|
15884
|
+
const material = mesh?.material;
|
|
15885
|
+
const level = tiles && mesh && material?.map && drawable && tilesServe(bo) ? neededLevel(bo.radiusScene, bo.cachedDist, projScale, tiles.max_level) : -1;
|
|
15886
|
+
const now = performance.now();
|
|
15887
|
+
if (!tiles || !mesh || !material || level < 3) {
|
|
15888
|
+
if (bo.tileOverlay) rest(bo, bo.tileOverlay, now);
|
|
15889
|
+
return;
|
|
15890
|
+
}
|
|
15891
|
+
if (bo.tileOverlay && bo.tileOverlay.material !== material) {
|
|
15892
|
+
disposeTileOverlay(bo);
|
|
15893
|
+
bo.tileOverlay = void 0;
|
|
15894
|
+
}
|
|
15895
|
+
const overlay = bo.tileOverlay ??= createOverlay(material);
|
|
15896
|
+
overlay.lastUsed = now;
|
|
15897
|
+
const levels = tiles.max_level - 3 + 1;
|
|
15898
|
+
const count = Math.min(maxTileWindows(), MAX_WINDOWS, levels + 1);
|
|
15899
|
+
if (overlay.store && overlay.store.texture.image.depth !== count + 1) disposeTileOverlay(bo);
|
|
15900
|
+
const store = overlay.store ??= createStore(tiles.tile_size, count + 1, renderer);
|
|
15901
|
+
overlay.uniforms.uTileMap.value = store.texture;
|
|
15902
|
+
overlay.uniforms.uTileMask.value = store.mask;
|
|
15903
|
+
overlay.uniforms.uTileFilter.value.set(store.texture.anisotropy, tiles.tile_size);
|
|
15904
|
+
over.copy(camera.position).applyMatrix4(inverse.copy(mesh.matrixWorld).invert()).normalize();
|
|
15905
|
+
const cap = over.y >= 0 ? 1 : 2;
|
|
15906
|
+
overlay.chart = cameraChart(over.y, overlay.chart);
|
|
15907
|
+
const chain = windowChain(level, count, overlay.chart, over.y);
|
|
15908
|
+
const frame = tiles.frames ? bo.textureFrame : void 0;
|
|
15909
|
+
const held = (link) => store.windows.find((win) => win.chart === link.chart && win.level === link.level);
|
|
15910
|
+
store.windows = store.windows.filter((win) => {
|
|
15911
|
+
win.rank = chain.findIndex((link) => link.chart === win.chart && link.level === win.level);
|
|
15912
|
+
if (win.rank >= 0) return true;
|
|
15913
|
+
win.rank = chain.length;
|
|
15914
|
+
const heir = chain.find((link) => link.level === win.level);
|
|
15915
|
+
const heirWindow = heir && held(heir);
|
|
15916
|
+
const near = win.chart === 0 || win.chart === cap;
|
|
15917
|
+
if (heir && near && !(heirWindow && settled(overlay, store, heirWindow))) return true;
|
|
15918
|
+
release(store, win);
|
|
15919
|
+
return false;
|
|
15920
|
+
});
|
|
15921
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
15922
|
+
const link = chain[i];
|
|
15923
|
+
let win = held(link);
|
|
15924
|
+
if (!win) {
|
|
15925
|
+
const layer = store.free.pop();
|
|
15926
|
+
if (layer === void 0) continue;
|
|
15927
|
+
win = {
|
|
15928
|
+
layer,
|
|
15929
|
+
...link,
|
|
15930
|
+
rank: i,
|
|
15931
|
+
wanted: new Array(SLOTS),
|
|
15932
|
+
pending: /* @__PURE__ */ new Map()
|
|
15933
|
+
};
|
|
15934
|
+
store.windows.push(win);
|
|
15935
|
+
}
|
|
15936
|
+
const point = chartPoint(link.chart, over.x, over.y, over.z);
|
|
15937
|
+
retarget(store, win, placeWindow(link.chart, link.level, point.x, point.y, win.placement), frame);
|
|
15938
|
+
pump(overlay, store, tiles, win, point.x, point.y, renderer, invalidate);
|
|
15939
|
+
}
|
|
15940
|
+
store.windows.sort((a, b) => b.level - a.level || a.rank - b.rank);
|
|
15941
|
+
for (let i = 0; i < MAX_DRAWN; i++) {
|
|
15942
|
+
const win = store.windows[i];
|
|
15943
|
+
const link = overlay.uniforms.uTileWindow.value[i];
|
|
15944
|
+
if (!win?.placement) {
|
|
15945
|
+
link.w = 0;
|
|
15946
|
+
continue;
|
|
15947
|
+
}
|
|
15948
|
+
overlay.uniforms.uTileGrid.value[i].set(chartColumns(win.chart, win.level), chartRows(win.chart, win.level), win.placement.tx0, win.placement.ty0);
|
|
15949
|
+
link.set(win.chart, win.layer, win.level, 1);
|
|
15950
|
+
}
|
|
15951
|
+
}
|
|
15952
|
+
|
|
15432
15953
|
//#endregion
|
|
15433
15954
|
//#region src/lib/scene/objects/body/lifecycle.ts
|
|
15434
15955
|
function disposeMaterial(mat) {
|
|
@@ -15562,6 +16083,8 @@ function downgradeBodyMesh(bo, scene, clickables, meshToBody) {
|
|
|
15562
16083
|
detachSelfShadow(bo.selfShadow);
|
|
15563
16084
|
bo.selfShadow = null;
|
|
15564
16085
|
}
|
|
16086
|
+
disposeTileOverlay(bo);
|
|
16087
|
+
bo.tileOverlay = void 0;
|
|
15565
16088
|
bo.terrainWindow = null;
|
|
15566
16089
|
mesh.removeFromParent();
|
|
15567
16090
|
mesh.geometry.dispose();
|
|
@@ -16269,6 +16792,7 @@ async function loadBodyTexture(bo, textureLoader, currentJd, scene, maxTextureSi
|
|
|
16269
16792
|
if (!sceneSettings().showSurfaceTexture) return;
|
|
16270
16793
|
if (!surface) return;
|
|
16271
16794
|
bo.textureBundleId = surface.id === bodyId ? void 0 : surface.id;
|
|
16795
|
+
bo.surfaceTiles = surface.tiles;
|
|
16272
16796
|
bo.availableTiers ??= surface.tiers ?? [...TIER_NAMES];
|
|
16273
16797
|
bo.availableFrames = surface.frames;
|
|
16274
16798
|
await swapBodyTexture(bo, "low", textureFrameForJd(currentJd, bo.availableFrames), textureLoader);
|
|
@@ -16288,6 +16812,7 @@ function unloadBodyTexture(bo) {
|
|
|
16288
16812
|
bo.textureLoadGen = (bo.textureLoadGen ?? 0) + 1;
|
|
16289
16813
|
const material = bo.mesh.material;
|
|
16290
16814
|
unloadSiblingLayer("topography", bo);
|
|
16815
|
+
disposeTileOverlay(bo);
|
|
16291
16816
|
if (!material.map) return;
|
|
16292
16817
|
material.map.dispose();
|
|
16293
16818
|
material.map = null;
|
|
@@ -17631,9 +18156,11 @@ function makeTrail(body, color, basisPos = [
|
|
|
17631
18156
|
const { orbitElements, orbitCenter, data } = body;
|
|
17632
18157
|
let curve;
|
|
17633
18158
|
let isOpenCurve;
|
|
18159
|
+
let start;
|
|
17634
18160
|
if (data.satrec) {
|
|
17635
18161
|
curve = sgp4Curve(data.satrec, jd, data.n / 360, 512);
|
|
17636
18162
|
isOpenCurve = true;
|
|
18163
|
+
start = curve.length - 1;
|
|
17637
18164
|
} else {
|
|
17638
18165
|
if (!orbitElements) throw new Error("makeTrail called without orbitElements");
|
|
17639
18166
|
curve = null;
|
|
@@ -17643,7 +18170,7 @@ function makeTrail(body, color, basisPos = [
|
|
|
17643
18170
|
const cy = orbitCenter?.[1] ?? 0;
|
|
17644
18171
|
const cz = orbitCenter?.[2] ?? 0;
|
|
17645
18172
|
const useTrail = isOpenCurve || data.objectType === ObjectType.DWARF_PLANET || data.objectType === ObjectType.MOON || data.objectType === ObjectType.SPACECRAFT || data.objectType === ObjectType.COMET || isAsteroid(data.objectType);
|
|
17646
|
-
const validPoints = curve ? buildTrailPoints(body, curve, isOpenCurve, cx, cy, cz) : [];
|
|
18173
|
+
const validPoints = curve ? buildTrailPoints(body, curve, isOpenCurve, cx, cy, cz, start) : [];
|
|
17647
18174
|
if (curve && validPoints.length < 2) return makeEmptyTrail();
|
|
17648
18175
|
const bufferCapacity = curve ? Math.max(validPoints.length, curve.length) : 512 + 1;
|
|
17649
18176
|
const fullAlphas = new Float32Array(bufferCapacity);
|
|
@@ -17823,6 +18350,7 @@ async function loadSystemData(barycenterId, bodyObjects, scene, textureLoader, c
|
|
|
17823
18350
|
bo.availableTiers = surface.tiers;
|
|
17824
18351
|
bo.availableFrames = surface.frames;
|
|
17825
18352
|
bo.textureBundleId = surface.id === bodyId ? void 0 : surface.id;
|
|
18353
|
+
bo.surfaceTiles = surface.tiles;
|
|
17826
18354
|
if (!bo.textureTier) {
|
|
17827
18355
|
const frame = textureFrameForJd(currentJd, bo.availableFrames);
|
|
17828
18356
|
promises.push(loadBodyTextureTier(bo, "low", frame, textureLoader));
|
|
@@ -19650,15 +20178,17 @@ function refreshTrail(body, line, basisPos, jd, view) {
|
|
|
19650
20178
|
const useTrail = line.userData.useTrail;
|
|
19651
20179
|
const oc = line.userData.orbitCenter;
|
|
19652
20180
|
const cx = oc.x, cy = oc.y, cz = oc.z;
|
|
20181
|
+
let windowStart;
|
|
19653
20182
|
if (body.data.satrec) {
|
|
19654
20183
|
const meanMotion = body.data.n / 360;
|
|
19655
20184
|
const stepDays = meanMotion > 0 ? 1 / meanMotion / 512 : 0;
|
|
19656
|
-
|
|
20185
|
+
let curveJd = line.userData.curveJd;
|
|
19657
20186
|
if (curve.length === 0 || curveJd === void 0 || Math.abs(jd - curveJd) >= stepDays) {
|
|
19658
20187
|
curve = sgp4Curve(body.data.satrec, jd, meanMotion, 512);
|
|
19659
20188
|
line.userData.sourceCurve = curve;
|
|
19660
|
-
line.userData.curveJd = jd;
|
|
20189
|
+
line.userData.curveJd = curveJd = jd;
|
|
19661
20190
|
}
|
|
20191
|
+
windowStart = curve.length - (jd < curveJd ? 2 : 1);
|
|
19662
20192
|
} else if (body.orbitElements) {
|
|
19663
20193
|
if (body.rederiveElements) {
|
|
19664
20194
|
const elementsJd = line.userData.elementsJd ?? jd;
|
|
@@ -19697,7 +20227,7 @@ function refreshTrail(body, line, basisPos, jd, view) {
|
|
|
19697
20227
|
const headY = anchor[1] - cy;
|
|
19698
20228
|
const headZ = anchor[2] - cz;
|
|
19699
20229
|
if (withinTolerance(ud, curve, offX, offY, offZ, headX, headY, headZ, view)) return;
|
|
19700
|
-
const validPoints = buildTrailPoints(body, curve, isOpenCurve, cx, cy, cz);
|
|
20230
|
+
const validPoints = buildTrailPoints(body, curve, isOpenCurve, cx, cy, cz, windowStart);
|
|
19701
20231
|
if (validPoints.length < 2) return;
|
|
19702
20232
|
const { posArr, trailArr, fullArr, capacity } = getTrailWorkingArrays(line);
|
|
19703
20233
|
const bx = cx - basisPos[0], by = cy - basisPos[1], bz = cz - basisPos[2];
|
|
@@ -20998,11 +21528,10 @@ function updatePositions(params) {
|
|
|
20998
21528
|
setVec(focus.focusTargetWorld, p);
|
|
20999
21529
|
const camOff = focus.camTargetOffset;
|
|
21000
21530
|
if (camOff && focus.camTargetWorld) addVec(focus.camTargetWorld, p, camOff);
|
|
21001
|
-
} else if (a.oldPos) {
|
|
21002
|
-
|
|
21003
|
-
focus.focusTruePos[
|
|
21004
|
-
focus.
|
|
21005
|
-
setVec(focus.focusTargetWorld, focus.focusTruePos);
|
|
21531
|
+
} else if (a.oldPos) for (let k = 0; k < 3; k++) {
|
|
21532
|
+
const moved = p[k] - a.oldPos[k];
|
|
21533
|
+
focus.focusTruePos[k] += moved;
|
|
21534
|
+
focus.focusTargetWorld[k] += moved;
|
|
21006
21535
|
}
|
|
21007
21536
|
break;
|
|
21008
21537
|
}
|
|
@@ -21025,8 +21554,10 @@ function updatePositions(params) {
|
|
|
21025
21554
|
refreshTrail(bo.body, line, basis, jd, trailView);
|
|
21026
21555
|
line.userData.refreshDeferred = false;
|
|
21027
21556
|
}
|
|
21557
|
+
const focusLoading = !focusPos && why === "loading";
|
|
21028
21558
|
return {
|
|
21029
|
-
focusUnplaced: focusedBody !== void 0 && !focusPos,
|
|
21559
|
+
focusUnplaced: focusedBody !== void 0 && !focusPos && !focusLoading,
|
|
21560
|
+
focusLoading,
|
|
21030
21561
|
anchorId
|
|
21031
21562
|
};
|
|
21032
21563
|
}
|
|
@@ -21403,11 +21934,14 @@ var Placer = class {
|
|
|
21403
21934
|
if (jd === this.passJd) this.settled.add(id);
|
|
21404
21935
|
return pos;
|
|
21405
21936
|
}
|
|
21937
|
+
under(aboveId) {
|
|
21938
|
+
return (this.ctx.getBody(aboveId) ?? this.bodyObjects.get(aboveId)?.body)?.unplaced === "loading" ? "loading" : "parent";
|
|
21939
|
+
}
|
|
21406
21940
|
seatFeature(body, jd) {
|
|
21407
21941
|
const hostId = body.featureAnchor.hostId;
|
|
21408
21942
|
const host = this.ctx.getBody(hostId);
|
|
21409
21943
|
const hostPos = host && this.place(host, jd);
|
|
21410
|
-
if (!host || !hostPos) return setUnplaced(body,
|
|
21944
|
+
if (!host || !hostPos) return setUnplaced(body, this.under(hostId));
|
|
21411
21945
|
return seatFeatureBody(body, host, hostPos, this.bodyObjects.get(hostId), jd);
|
|
21412
21946
|
}
|
|
21413
21947
|
rideAt(jd) {
|
|
@@ -21438,8 +21972,9 @@ var Placer = class {
|
|
|
21438
21972
|
if (d.orbitalSource === OrbitalSource.SPICE_PROBE) return this.settleProbe(body, bo, jd);
|
|
21439
21973
|
const parentPos = this.at(d.parentId, jd);
|
|
21440
21974
|
if (!parentPos) {
|
|
21441
|
-
|
|
21442
|
-
|
|
21975
|
+
const why = this.under(d.parentId);
|
|
21976
|
+
if (why === "parent") diagnostics.warnOnce("missing-parent", d.id, () => `place[${d.id}]: parent ${d.parentId} has no place`);
|
|
21977
|
+
return setUnplaced(body, why);
|
|
21443
21978
|
}
|
|
21444
21979
|
diagnostics.clear("missing-parent", d.id);
|
|
21445
21980
|
let offset;
|
|
@@ -21449,9 +21984,10 @@ var Placer = class {
|
|
|
21449
21984
|
return this.finish(body, bo, parentPos[0] + offset[0], parentPos[1] + offset[1], parentPos[2] + offset[2], parentPos, jd);
|
|
21450
21985
|
}
|
|
21451
21986
|
chebMiss(id, jd) {
|
|
21452
|
-
const
|
|
21453
|
-
|
|
21454
|
-
|
|
21987
|
+
const store = this.ctx.chebStore;
|
|
21988
|
+
if (store.isLoading(id, jd)) return "loading";
|
|
21989
|
+
const coverage = store.zoneCoverage(id);
|
|
21990
|
+
if (coverage !== null && (jd < coverage.start || jd > coverage.end) && jd === this.passJd) {
|
|
21455
21991
|
this.noData.count++;
|
|
21456
21992
|
if (coverage.start < this.noData.earliestStart) this.noData.earliestStart = coverage.start;
|
|
21457
21993
|
if (coverage.end > this.noData.latestEnd) this.noData.latestEnd = coverage.end;
|
|
@@ -21460,7 +21996,7 @@ var Placer = class {
|
|
|
21460
21996
|
const cov = coverage ? `[${coverage.start.toFixed(1)},${coverage.end.toFixed(1)}]` : "unknown";
|
|
21461
21997
|
return `chebStore.positionScene[${id}] returned null at jd=${jd.toFixed(3)} (coverage=${cov})`;
|
|
21462
21998
|
});
|
|
21463
|
-
return
|
|
21999
|
+
return "no-data";
|
|
21464
22000
|
}
|
|
21465
22001
|
finish(body, bo, x, y, z, parentPos, jd) {
|
|
21466
22002
|
const d = body.data;
|
|
@@ -21523,6 +22059,7 @@ var Placer = class {
|
|
|
21523
22059
|
const zonePref = activeSysId ? (fitCenterNaif) => ctx.bodies.isInSystem(`naif-${fitCenterNaif}`, activeSysId) : void 0;
|
|
21524
22060
|
const located = ctx.probeStore?.probeWithCenter(d.id, jd, zonePref) ?? null;
|
|
21525
22061
|
if (!located) {
|
|
22062
|
+
if (ctx.probeStore?.loadingAt(jd)) return setUnplaced(body, "loading");
|
|
21526
22063
|
setUnplaced(body, "no-data");
|
|
21527
22064
|
diagnostics.warnOnce("probe-unavailable", d.id, () => {
|
|
21528
22065
|
const reason = !ctx.probeStore ? "no ProbeStore" : "no zone has both a loaded chunk and a sub-chunk covering this jd";
|
|
@@ -21534,7 +22071,7 @@ var Placer = class {
|
|
|
21534
22071
|
if (probeLanded && isLandedAt(located.probe, jd)) {
|
|
21535
22072
|
const flyingFrameId = d.parentId;
|
|
21536
22073
|
const landedRender = renderLandedProbe(d, located.probe, probeLanded, jd, (id) => this.at(id, jd), ctx, bodyObjects);
|
|
21537
|
-
if (!landedRender) return setUnplaced(body,
|
|
22074
|
+
if (!landedRender) return setUnplaced(body, this.under(`naif-${probeLanded.bodyNaifId}`));
|
|
21538
22075
|
diagnostics.clear("probe-unavailable", d.id);
|
|
21539
22076
|
if (flyingFrameId !== d.parentId) body.trailBuffer?.clear();
|
|
21540
22077
|
if (bo) {
|
|
@@ -21559,7 +22096,8 @@ var Placer = class {
|
|
|
21559
22096
|
}
|
|
21560
22097
|
const primary = resolveProbePrimary(located.probe, jd, located.fitCenterNaifId, ctx.chebStore ?? null, (id) => this.at(id, jd) !== null);
|
|
21561
22098
|
if (!primary) {
|
|
21562
|
-
|
|
22099
|
+
const center = located.probe.fitCenter?.id;
|
|
22100
|
+
setUnplaced(body, center ? this.under(center) : "parent");
|
|
21563
22101
|
diagnostics.warnOnce("probe-unavailable", d.id, () => `probe ${d.id} (${d.name ?? "unnamed"}): hidden — stamped fit center is not placeable this frame`);
|
|
21564
22102
|
return null;
|
|
21565
22103
|
}
|
|
@@ -21606,7 +22144,7 @@ var Placer = class {
|
|
|
21606
22144
|
if (probeParentChanged) d.parentId = probeParentKey;
|
|
21607
22145
|
const probeParentPos = this.at(probeParentKey, jd);
|
|
21608
22146
|
if (!probeParentPos) {
|
|
21609
|
-
setUnplaced(body,
|
|
22147
|
+
setUnplaced(body, this.under(probeParentKey));
|
|
21610
22148
|
diagnostics.warnOnce("probe-unavailable", d.id, () => `probe ${d.id} (${d.name ?? "unnamed"}): hidden — fit center ${probeParentKey} has no position this frame`);
|
|
21611
22149
|
return null;
|
|
21612
22150
|
}
|
|
@@ -21883,11 +22421,11 @@ function updateAtmosphereShaders(bodyObjects, cameraPosition, visible, realistic
|
|
|
21883
22421
|
spinAxis.set(0, 1, 0).applyQuaternion(bo.mesh.quaternion);
|
|
21884
22422
|
uniforms.uSpinAxis.value.copy(spinAxis);
|
|
21885
22423
|
}
|
|
21886
|
-
const
|
|
21887
|
-
const shellRadius = bo.atmosphere.geometryRadiusScene *
|
|
21888
|
-
const camDist = cameraPosition.distanceTo(
|
|
22424
|
+
const shellCenter = bo.root.position;
|
|
22425
|
+
const shellRadius = bo.atmosphere.geometryRadiusScene * bo.atmosphere.mesh.scale.x;
|
|
22426
|
+
const camDist = cameraPosition.distanceTo(shellCenter);
|
|
21889
22427
|
if (shellRadius > camDist * .1) state.shellProminent = true;
|
|
21890
|
-
if (quality.eclipseShadows) cullShellOccluders(uniforms,
|
|
22428
|
+
if (quality.eclipseShadows) cullShellOccluders(uniforms, shellCenter, sunVec, shellRadius);
|
|
21891
22429
|
const inside = quality.insideView && camDist < shellRadius;
|
|
21892
22430
|
const referenceKm = bo.atmosphere.planetRadiusKm;
|
|
21893
22431
|
const altKm = camDist * ((referenceKm + params.topAltitudeKm) / shellRadius) - referenceKm;
|
|
@@ -21901,7 +22439,7 @@ function updateAtmosphereShaders(bodyObjects, cameraPosition, visible, realistic
|
|
|
21901
22439
|
}
|
|
21902
22440
|
if (inside) {
|
|
21903
22441
|
state.insideShell = true;
|
|
21904
|
-
const sinSunElev = camUp.copy(cameraPosition).sub(
|
|
22442
|
+
const sinSunElev = camUp.copy(cameraPosition).sub(shellCenter).divideScalar(camDist).dot(sunVec);
|
|
21905
22443
|
const dim = skyboxDimFactor(params, altKm, sinSunElev);
|
|
21906
22444
|
state.skyboxIntensity *= dim * (1 - deckBlend);
|
|
21907
22445
|
if (quality.refraction && params.refractivity && !underDeck) {
|
|
@@ -21915,7 +22453,7 @@ function updateAtmosphereShaders(bodyObjects, cameraPosition, visible, realistic
|
|
|
21915
22453
|
const shellRatio = camDist / shellRadius;
|
|
21916
22454
|
if (quality.sunTint && shellRatio < SUN_TINT_MAX_RATIO) {
|
|
21917
22455
|
const planetRadiusScene = shellRadius / (1 + params.topAltitudeKm / referenceKm) * (bo.atmosphere.surfaceRadiusKm / referenceKm);
|
|
21918
|
-
camRel.copy(cameraPosition).sub(
|
|
22456
|
+
camRel.copy(cameraPosition).sub(shellCenter);
|
|
21919
22457
|
const shellSpinAxis = uniforms.uSpinAxis.value;
|
|
21920
22458
|
const shellStretch = uniforms.uStretch.value;
|
|
21921
22459
|
if (sunPathTransmittance(params, camRel, sunVec, planetRadiusScene, bo.atmosphere.surfaceRadiusKm, sunT, shellSpinAxis, shellStretch)) {
|
|
@@ -21924,7 +22462,7 @@ function updateAtmosphereShaders(bodyObjects, cameraPosition, visible, realistic
|
|
|
21924
22462
|
}
|
|
21925
22463
|
if (sunViewTint && shellRatio < bestViewTintRatio) {
|
|
21926
22464
|
bestViewTintRatio = shellRatio;
|
|
21927
|
-
bindViewTint(sunViewTint, params,
|
|
22465
|
+
bindViewTint(sunViewTint, params, shellCenter, planetRadiusScene, bo.atmosphere.surfaceRadiusKm, shellSpinAxis, shellStretch);
|
|
21928
22466
|
}
|
|
21929
22467
|
}
|
|
21930
22468
|
}
|
|
@@ -22251,7 +22789,7 @@ function desiredDemTier(altitudeRadii, current) {
|
|
|
22251
22789
|
if (tierRank(down) < tierRank(current)) return down;
|
|
22252
22790
|
return current;
|
|
22253
22791
|
}
|
|
22254
|
-
function updateTextureLOD(bodyObjects, camera, renderer, ctx, textureLoader, focusedId, jd, appearances) {
|
|
22792
|
+
function updateTextureLOD(bodyObjects, camera, renderer, ctx, textureLoader, focusedId, jd, appearances, invalidate) {
|
|
22255
22793
|
appearances.apply(bodyObjects, textureLoader);
|
|
22256
22794
|
const fovRad = camera.fov * Math.PI / 180;
|
|
22257
22795
|
const projScale = renderer.domElement.clientHeight / (2 * Math.tan(fovRad / 2));
|
|
@@ -22275,7 +22813,8 @@ function updateTextureLOD(bodyObjects, camera, renderer, ctx, textureLoader, foc
|
|
|
22275
22813
|
else if (screenR < 1024 && altitudeRadii > 2) desired = "medium";
|
|
22276
22814
|
else desired = "high";
|
|
22277
22815
|
const currentRank = tierRank(bo.textureTier);
|
|
22278
|
-
const
|
|
22816
|
+
const bodyCap = tilesServe(bo) ? Math.min(tierCap, tierRank("medium")) : tierCap;
|
|
22817
|
+
const desiredRank = Math.min(tierRank(desired), bodyCap);
|
|
22279
22818
|
const desiredFrame = textureFrameForJd(jd, bo.availableFrames);
|
|
22280
22819
|
const frameChanged = desiredFrame !== bo.textureFrame;
|
|
22281
22820
|
const wantsUpgrade = desiredRank > currentRank;
|
|
@@ -22283,6 +22822,7 @@ function updateTextureLOD(bodyObjects, camera, renderer, ctx, textureLoader, foc
|
|
|
22283
22822
|
const target = wantsUpgrade ? highestAvailableTier(desiredRank, bo.availableTiers) : bo.textureTier;
|
|
22284
22823
|
if (target) loadBodyTextureTier(bo, target, desiredFrame, textureLoader);
|
|
22285
22824
|
}
|
|
22825
|
+
updateTileOverlay(bo, camera, renderer, projScale * renderer.getPixelRatio(), settings.showSurfaceTexture && !bo.appearance?.surfaceOwned && !bo.model, invalidate);
|
|
22286
22826
|
const dispTiers = bo.displacementMeta?.tiers;
|
|
22287
22827
|
if (bo.displacementMap && dispTiers?.length && !bo.displacementLoading) {
|
|
22288
22828
|
const maxTex = renderer.capabilities.maxTextureSize;
|
|
@@ -23630,6 +24170,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
23630
24170
|
lastDataVersion = -1;
|
|
23631
24171
|
dateHolds = 0;
|
|
23632
24172
|
focusWasOutOfRange = false;
|
|
24173
|
+
seekAwaitsData = false;
|
|
23633
24174
|
frameIndex = 0;
|
|
23634
24175
|
static WAKE_FRAMES = 30;
|
|
23635
24176
|
static IDLE_HEARTBEAT_FRAMES = 10;
|
|
@@ -24124,7 +24665,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
24124
24665
|
for (const light of this.ambientLights) light.intensity = ambient;
|
|
24125
24666
|
updateUserLocationOcclusion(this.userLocationMarker, this.bodyObjects, this.camera);
|
|
24126
24667
|
const focusedIdLod = nomenclatureBodyId(this.focusController.current, this.bodyObjects);
|
|
24127
|
-
updateTextureLOD(this.bodyObjects, this.camera, this.renderer, this.ctx, this.textureLoader, focusedIdLod, this.clock.jd, this.appearances);
|
|
24668
|
+
updateTextureLOD(this.bodyObjects, this.camera, this.renderer, this.ctx, this.textureLoader, focusedIdLod, this.clock.jd, this.appearances, this.invalidate);
|
|
24128
24669
|
updateSphereLOD(this.bodyObjects, this.camera, this.renderer, this.ctx, focusedIdLod);
|
|
24129
24670
|
updateSunShadowLight(this.bodyObjects, this.focus.focusTruePos, this.ctx, this.shadowLight, this.sunPointLight, distance, this._tmpV3, sceneSettings().realisticLighting, this.sunIntensityScale);
|
|
24130
24671
|
this.updateModelMounts();
|
|
@@ -24641,7 +25182,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
24641
25182
|
this.clock.seeked = false;
|
|
24642
25183
|
return;
|
|
24643
25184
|
}
|
|
24644
|
-
const seeked = this.clock.seeked;
|
|
25185
|
+
const seeked = this.clock.seeked || this.seekAwaitsData;
|
|
24645
25186
|
this.clock.seeked = false;
|
|
24646
25187
|
this.lastUpdatedJd = this.clock.jd;
|
|
24647
25188
|
this.lastUpdatedSystemId = systemId;
|
|
@@ -24668,6 +25209,7 @@ var SceneRenderer = class SceneRenderer {
|
|
|
24668
25209
|
this.pointClouds.maybeRebase();
|
|
24669
25210
|
}
|
|
24670
25211
|
this.syncLandedNomenclature();
|
|
25212
|
+
this.seekAwaitsData = seeked && result.focusLoading;
|
|
24671
25213
|
const losingPlace = result.focusUnplaced && !this.focusWasOutOfRange;
|
|
24672
25214
|
this.focusWasOutOfRange = result.focusUnplaced;
|
|
24673
25215
|
if (allowOorRefocus && seeked && losingPlace && result.anchorId) {
|