mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
feat(hud): Cyber HUD theme with GPU contact sonar (#706)
Add the opt-in Cyber HUD layout with coordinated map and cockpit panel styling, GPU-only contact sonar (rings, range, power, opacity, sector) with native-rendering fallback, and set_cyber_sonar voice controls. Sonar visual style inspired by kk376's tactical naval sonar (#214). Co-authored-by: Sameh Khamis <[email protected]> Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
74 files changed
+7320
-90
No files matched your search
@@ -1,4 +1,9 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import {
|
||||
createCyberSonarSampler,
|
||||
isCyberContactSonarActive as isCyberSonarActive,
|
||||
CYBER_SONAR_RENDER_INTERVAL_MS,
|
||||
} from '../cyberSonar.js';
|
||||
import {
|
||||
getKeyholeFadeTuning,
|
||||
getKeyholeGeometry,
|
||||
@@ -170,6 +175,7 @@ let _resizeObserver = null;
|
||||
let _mutationObserver = null;
|
||||
let _observedOccluderElements = new WeakSet();
|
||||
let _occluderRefreshTimer = null;
|
||||
let _sonarRenderTimer = null;
|
||||
let _cockpitModeHandler = null;
|
||||
let _windowResizeHandler = null;
|
||||
let _cockpitActive = false;
|
||||
@@ -2443,7 +2449,7 @@ function paintCustomLane(lane) {
|
||||
}
|
||||
}
|
||||
|
||||
function paintEntryItem(item, keyhole) {
|
||||
function paintEntryItem(item, keyhole, sonar) {
|
||||
const { record, placement } = item;
|
||||
const entry = record.entry;
|
||||
let keyholeAlpha = 1;
|
||||
@@ -2468,7 +2474,8 @@ function paintEntryItem(item, keyhole) {
|
||||
item.temporalAlpha *
|
||||
record.distanceAlpha *
|
||||
record.altitudeAlpha *
|
||||
keyholeAlpha;
|
||||
keyholeAlpha *
|
||||
(sonar ? sonar.label(sonar.at(placement.anchorX, placement.anchorY)) : 1);
|
||||
if (finalAlpha <= 0.001) return;
|
||||
if (record.paintScale === 1) {
|
||||
paintOverlayEntry(
|
||||
@@ -2508,6 +2515,9 @@ function paintEntryItem(item, keyhole) {
|
||||
|
||||
function paintFrame(keyhole) {
|
||||
const started = nowMs();
|
||||
const sonar = isCyberSonarActive()
|
||||
? createCyberSonarSampler(_canvasWidth, _canvasHeight, started)
|
||||
: null;
|
||||
clearCanvas(true, false);
|
||||
_detectionSurfacePrepared = false;
|
||||
if (
|
||||
@@ -2528,7 +2538,7 @@ function paintFrame(keyhole) {
|
||||
// retains its former z5 position below every ordinary host entry at z6.
|
||||
paintCustomLane(lane);
|
||||
while (itemIndex < _paintCount && _paintQueue[itemIndex].lane === lane) {
|
||||
paintEntryItem(_paintQueue[itemIndex], keyhole);
|
||||
paintEntryItem(_paintQueue[itemIndex], keyhole, sonar);
|
||||
itemIndex++;
|
||||
}
|
||||
}
|
||||
@@ -2581,6 +2591,10 @@ function resetFrameDiagnostics() {
|
||||
}
|
||||
|
||||
function drawWorldOverlay() {
|
||||
if (_sonarRenderTimer !== null) {
|
||||
clearTimeout(_sonarRenderTimer);
|
||||
_sonarRenderTimer = null;
|
||||
}
|
||||
if (_destroyed || !_viewer || !_canvas || !_ctx) return;
|
||||
const timestamp = nowMs();
|
||||
if (!overlayHasPaintWork(timestamp)) {
|
||||
@@ -2622,6 +2636,15 @@ function drawWorldOverlay() {
|
||||
_diagnostics.projectionMs = nowMs() - projectionStarted;
|
||||
solveDomains(timestamp);
|
||||
paintFrame(keyhole);
|
||||
// Labels-only layers need a bounded sweep refresh even with detection off.
|
||||
// Empty/hidden hosts and teardown never retain scanner render demand.
|
||||
if (_paintRectCount > 0 && isCyberSonarActive()) {
|
||||
_sonarRenderTimer = setTimeout(() => {
|
||||
_sonarRenderTimer = null;
|
||||
if (!_destroyed && isCyberSonarActive())
|
||||
_viewer?.scene?.requestRender?.();
|
||||
}, CYBER_SONAR_RENDER_INTERVAL_MS);
|
||||
}
|
||||
const animationsRemaining =
|
||||
activeFadeCount(timestamp) + activeLeaderAnimationCount(timestamp);
|
||||
if (animationsRemaining > 0) _viewer.scene.requestRender?.();
|
||||
@@ -2679,6 +2702,8 @@ export function initWorldOverlay(viewer) {
|
||||
|
||||
/** Remove all listeners, observers, entries, diagnostics, and overlay DOM. */
|
||||
export function destroyWorldOverlay() {
|
||||
if (_sonarRenderTimer !== null) clearTimeout(_sonarRenderTimer);
|
||||
_sonarRenderTimer = null;
|
||||
// Tearing down a host that was never initialized must not arm the
|
||||
// post-destroy guard: sources are allowed to publish before the first
|
||||
// `initWorldOverlay`, and that buffering has to survive a stray destroy.
|
||||
|
||||
Reference in new issue
Block a user