Fix radio globe texture rendering
This commit is contained in:
parent
fef207e9df
commit
b8268b4999
2 changed files with 17 additions and 3 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||||
import Globe from 'globe.gl';
|
import Globe from 'globe.gl';
|
||||||
import { CanvasTexture, LinearFilter } from 'three';
|
import { CanvasTexture, Color, LinearFilter, SRGBColorSpace } from 'three';
|
||||||
import { TileTextureManager } from './TileTextureManager';
|
import { TileTextureManager } from './TileTextureManager';
|
||||||
|
|
||||||
// ── Types ──
|
// ── Types ──
|
||||||
|
|
@ -160,7 +160,7 @@ export default function RadioTab({ data }: { data: any }) {
|
||||||
const accentRgb = style.getPropertyValue('--accent-rgb').trim();
|
const accentRgb = style.getPropertyValue('--accent-rgb').trim();
|
||||||
globeRef.current
|
globeRef.current
|
||||||
.pointColor(() => `rgba(${accentRgb}, 0.85)`)
|
.pointColor(() => `rgba(${accentRgb}, 0.85)`)
|
||||||
.atmosphereColor(`rgba(${accentRgb}, 0.25)`);
|
.atmosphereColor(`rgb(${accentRgb})`);
|
||||||
}
|
}
|
||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
|
|
@ -215,7 +215,7 @@ export default function RadioTab({ data }: { data: any }) {
|
||||||
|
|
||||||
const globe = new Globe(containerRef.current)
|
const globe = new Globe(containerRef.current)
|
||||||
.backgroundColor('rgba(0,0,0,0)')
|
.backgroundColor('rgba(0,0,0,0)')
|
||||||
.atmosphereColor(`rgba(${initRgb}, 0.25)`)
|
.atmosphereColor(`rgb(${initRgb})`)
|
||||||
.atmosphereAltitude(0.12)
|
.atmosphereAltitude(0.12)
|
||||||
.pointsData(places)
|
.pointsData(places)
|
||||||
// Radio Garden geo format: [lng, lat]
|
// Radio Garden geo format: [lng, lat]
|
||||||
|
|
@ -237,9 +237,11 @@ export default function RadioTab({ data }: { data: any }) {
|
||||||
const texture = new CanvasTexture(tileMgr.canvas);
|
const texture = new CanvasTexture(tileMgr.canvas);
|
||||||
texture.minFilter = LinearFilter;
|
texture.minFilter = LinearFilter;
|
||||||
texture.generateMipmaps = false;
|
texture.generateMipmaps = false;
|
||||||
|
texture.colorSpace = SRGBColorSpace;
|
||||||
tileTextureRef.current = texture;
|
tileTextureRef.current = texture;
|
||||||
const mat = globe.globeMaterial() as any;
|
const mat = globe.globeMaterial() as any;
|
||||||
mat.map = texture;
|
mat.map = texture;
|
||||||
|
mat.color = new Color(0xffffff);
|
||||||
mat.needsUpdate = true;
|
mat.needsUpdate = true;
|
||||||
|
|
||||||
// Start loading tiles (progressive: zoom 1 → 2 → 3)
|
// Start loading tiles (progressive: zoom 1 → 2 → 3)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
// Proxy through our server (CDN requires Referer: radio.garden)
|
// Proxy through our server (CDN requires Referer: radio.garden)
|
||||||
const TILE_CDN = '/api/radio/tile';
|
const TILE_CDN = '/api/radio/tile';
|
||||||
|
const FALLBACK_TEXTURE = '/earth-night.jpg';
|
||||||
|
|
||||||
// ── Mercator math ──
|
// ── Mercator math ──
|
||||||
|
|
||||||
|
|
@ -51,6 +52,7 @@ export class TileTextureManager {
|
||||||
// Ocean background
|
// Ocean background
|
||||||
this.ctx.fillStyle = '#070b15';
|
this.ctx.fillStyle = '#070b15';
|
||||||
this.ctx.fillRect(0, 0, width, height);
|
this.ctx.fillRect(0, 0, width, height);
|
||||||
|
this.drawFallbackTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Load base layers progressively (zoom 1 → 3) */
|
/** Load base layers progressively (zoom 1 → 3) */
|
||||||
|
|
@ -108,6 +110,16 @@ export class TileTextureManager {
|
||||||
await Promise.all(batch);
|
await Promise.all(batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private drawFallbackTexture(): void {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
if (this.drawn.size > 0) return;
|
||||||
|
this.ctx.drawImage(img, 0, 0, this.width, this.height);
|
||||||
|
this.scheduleUpdate();
|
||||||
|
};
|
||||||
|
img.src = FALLBACK_TEXTURE;
|
||||||
|
}
|
||||||
|
|
||||||
private loadTile(z: number, x: number, y: number): Promise<void> {
|
private loadTile(z: number, x: number, y: number): Promise<void> {
|
||||||
const k = `${z}/${x}/${y}`;
|
const k = `${z}/${x}/${y}`;
|
||||||
if (this.cache.has(k) || this.loading.has(k)) return Promise.resolve();
|
if (this.cache.has(k) || this.loading.has(k)) return Promise.resolve();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue