From 26b393a719ea06626609eda4041f09459ac10479 Mon Sep 17 00:00:00 2001 From: core Date: Sat, 31 May 2025 12:41:35 -0400 Subject: [PATCH] feat: client-side rendering --- .idea/workspace.xml | 22 ++++++--- client/package.json | 2 +- client/src/lib/Map.svelte | 65 ++++++++++++++++++++++---- client/src/lib/map/default_palettes.ts | 8 ++++ client/src/lib/map/fragment.glsl | 63 ++++++++++--------------- client/src/lib/map/vertex.glsl | 6 --- crates/pal/src/lib.rs | 1 + 7 files changed, 106 insertions(+), 61 deletions(-) create mode 100644 client/src/lib/map/default_palettes.ts diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 6b74e62..c45829e 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -7,13 +7,12 @@ - - + + - - + - @@ -177,6 +184,7 @@ - \ No newline at end of file diff --git a/client/package.json b/client/package.json index 6f1f43e..a7af3cf 100644 --- a/client/package.json +++ b/client/package.json @@ -4,7 +4,7 @@ "version": "0.0.1", "type": "module", "scripts": { - "dev": "vite dev", + "dev": "bun update:protobuf && bun update:wxbox-pal && vite dev", "build": "vite build", "preview": "vite preview", "prepare": "svelte-kit sync || echo ''", diff --git a/client/src/lib/Map.svelte b/client/src/lib/Map.svelte index 99f2666..a43ba69 100644 --- a/client/src/lib/Map.svelte +++ b/client/src/lib/Map.svelte @@ -17,6 +17,8 @@ import type { DigitalRadarData, Radial } from './generated_interop/digitalRadarData'; import {forwardGeodesic, radToDeg} from "$lib/vincenty"; import {degToRad} from "$lib/vincenty.js"; + import init_palette_parser_wasm, {parse_palette} from "$lib/map/pal/wxbox_pal"; + import {WXBOX_STANDARD_REF} from "$lib/map/default_palettes"; const BELOW_THRESHOLD = -9999.0; const RANGE_FOLDED = -9998.0; @@ -167,6 +169,8 @@ if (container.messageType.oneofKind == 'digitalRadarData') { const drd: DigitalRadarData = container.messageType.digitalRadarData; + await init_palette_parser_wasm(); + const dataLayer = { id: 'dataGl', type: 'custom', @@ -187,14 +191,6 @@ this.aPos = gl.getAttribLocation(this.program, 'a_pos'); - /* - 110.574 km = 1 deg - deg = 1/110.574 km - - 111.320 * cos(latitude) km = 1 deg - - */ - const lat = 38.976111; const long = -77.4875; @@ -214,7 +210,7 @@ if (radial.product && radial.product.data && radial.product.data.data) { const angle_a = radial.azimuthAngleDegrees; - const angle_b = angle_a + radial.azimuthSpacingDegrees * 1.2; + const angle_b = (i == drd.radials.length - 1) ? drd.radials[0].azimuthAngleDegrees : drd.radials[i+1].azimuthAngleDegrees; const start_range = radial.product.data.startRange; // m const sample_interval = radial.product.data.sampleInterval; // m @@ -294,10 +290,61 @@ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.uniform1i(gl.getUniformLocation(this.program, 'data'), 10); + // parse, transform, and send over the palette + const palette = parse_palette(WXBOX_STANDARD_REF); + gl.uniform1i(gl.getUniformLocation(this.program, 'paletteLength'), palette.length); + const rboundsData: number[] = []; + const rcolorData: number[] = []; + const rcolor2Data: number[] = []; + for (const paletteEntry of palette) { + const [bounds, color] = paletteEntry; + rboundsData.push(...bounds); + rcolorData.push(...[color[0].red, color[0].green, color[0].blue, color[0].alpha]); + rcolor2Data.push(...[color[1].red, color[1].green, color[1].blue, color[1].alpha]); + } + // create the bounds texture first + const boundsData = new Float32Array(rboundsData); + gl.activeTexture(gl.TEXTURE0 + 11); + this.boundsTexture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.boundsTexture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RG32F, 1, palette.length, 0, gl.RG, gl.FLOAT, boundsData); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.uniform1i(gl.getUniformLocation(this.program, 'bounds'), 11); + // then the colorData texture + const colorData = new Uint8Array(rcolorData); + gl.activeTexture(gl.TEXTURE0 + 12); + this.colorDataTexture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.colorDataTexture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 1, palette.length, 0, gl.RGBA, gl.UNSIGNED_BYTE, colorData); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.uniform1i(gl.getUniformLocation(this.program, 'colorData'), 12); + // then the colorData2 texture + const color2Data = new Uint8Array(rcolor2Data); + gl.activeTexture(gl.TEXTURE0 + 13); + this.color2DataTexture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.color2DataTexture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 1, palette.length, 0, gl.RGBA, gl.UNSIGNED_BYTE, color2Data); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.uniform1i(gl.getUniformLocation(this.program, 'color2Data'), 13); }, render(gl, args) { gl.activeTexture(gl.TEXTURE0 + 10); gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.activeTexture(gl.TEXTURE0 + 11); + gl.bindTexture(gl.TEXTURE_2D, this.boundsTexture); + gl.activeTexture(gl.TEXTURE0 + 12); + gl.bindTexture(gl.TEXTURE_2D, this.colorDataTexture); + gl.activeTexture(gl.TEXTURE0 + 13); + gl.bindTexture(gl.TEXTURE_2D, this.color2DataTexture); gl.useProgram(this.program); gl.uniformMatrix4fv( diff --git a/client/src/lib/map/default_palettes.ts b/client/src/lib/map/default_palettes.ts new file mode 100644 index 0000000..af2c295 --- /dev/null +++ b/client/src/lib/map/default_palettes.ts @@ -0,0 +1,8 @@ +export const WXBOX_STANDARD_REF = `Color4: 10 164 164 255 0 100 100 192 255 +Color4: 20 64 128 255 255 32 64 128 255 +Color4: 30 0 255 0 255 0 128 0 255 +Color4: 40 255 255 0 255 255 128 0 255 +Color4: 50 255 0 0 255 160 0 0 255 +Color4: 60 255 0 255 255 128 0 128 255 +Color4: 70 255 255 255 255 128 128 128 255 +Color4: 80 128 128 128 255`; \ No newline at end of file diff --git a/client/src/lib/map/fragment.glsl b/client/src/lib/map/fragment.glsl index 4825006..9097a43 100644 --- a/client/src/lib/map/fragment.glsl +++ b/client/src/lib/map/fragment.glsl @@ -7,12 +7,16 @@ const float PI = 3.14159265358979323846264338327950288; layout(location = 0) out vec4 fragColor; in vec2 raw_pos; -in vec4 vertexColor; flat in int azimuthNumber; flat in float azimuthAngle; uniform sampler2D data; +uniform sampler2D bounds; +uniform sampler2D colorData; +uniform sampler2D color2Data; +uniform int paletteLength; + uniform float radarLat; uniform float radarLng; @@ -27,18 +31,8 @@ Wgs84Coordinates rawPosToWgs84(vec2 raw_pos) { return Wgs84Coordinates(lat,lng); } -float haversineDistance(Wgs84Coordinates from, Wgs84Coordinates to, float radius) { - return 2.0 * radius * asin(sqrt(pow(2.0, sin((to.lat-from.lat)/2.0)) + cos(from.lat) * cos(to.lat) * pow(2.0, sin((to.lng - from.lng)/2.0)))); -} - const float R = 6371000.0; // m -float random (vec2 st) { - return fract(sin(dot(st.xy, - vec2(12.9898,78.233)))* - 43758.5453123); -} - void main() { Wgs84Coordinates thisPixelCoordinates = rawPosToWgs84(raw_pos); Wgs84Coordinates radarCoordinates = Wgs84Coordinates(radarLat,radarLng); @@ -65,37 +59,30 @@ void main() { fragColor = vec4(0,0,0,0); return; } - int selector = int(mod(float(azimuthNumber), 2.0)); - - if (selector == 0) { - fragColor = vec4(float(azimuthAngle) / 360.0, 0, 0, 1); - } else if (selector == 1) { - fragColor = vec4(0,float(azimuthAngle) / 360.0, 0,1); - } else { - fragColor = vec4(0,0,float(azimuthAngle)/360.0,1); - } int gate_number = int(floor((distance_meters - 2125.0) / 250.0)); float rawValue = texelFetch(data, ivec2(gate_number, azimuthNumber), 0).r; - if (rawValue > 80.0) { - fragColor = vec4(128.0 / 255.0, 128.0 / 255.0, 128.0 / 255.0, 1.0); - } else if (rawValue > 70.0) { - fragColor = vec4(1.0, 1.0, 1.0, 1.0); - } else if (rawValue > 60.0) { - fragColor = vec4(1.0, 0.0, 1.0, 1.0); - } else if (rawValue > 50.0) { - fragColor = vec4(1.0, 0.0, 0.0, 1.0); - } else if (rawValue > 40.0) { - fragColor = vec4(1.0, 1.0, 0.0, 1.0); - } else if (rawValue > 30.0) { - fragColor = vec4(0.0, 1.0, 0.0, 1.0); - } else if (rawValue > 20.0) { - fragColor = vec4(64.0 / 255.0, 128.0 / 255.0, 1.0, 1.0); - } else if (rawValue > 10.0) { - fragColor = vec4(164.0 / 255.0, 164.0 / 255.0, 1.0, 1.0); - } else { - fragColor = vec4(0.0, 0.0, 0.0, 0.0); + // colorize! + for (int i = paletteLength; i > 0; i--) { + vec2 rangeBounds = texelFetch(bounds, ivec2(0, i), 0).rg; + float lower = rangeBounds.r; + float higher = rangeBounds.g; + if (rawValue >= lower && rawValue < higher) { + float mapped_end = higher - lower; + float mapped_point = rawValue - lower; + float t = mapped_point / mapped_end; + + vec4 color_start = texelFetch(colorData, ivec2(0, i), 0); + vec4 color_end = texelFetch(color2Data, ivec2(0, i), 0); + + + + fragColor = mix(color_start, color_end, t); + return; + } } + fragColor = vec4(0,0,0,0); + return; } \ No newline at end of file diff --git a/client/src/lib/map/vertex.glsl b/client/src/lib/map/vertex.glsl index a2bff5f..dd035d5 100644 --- a/client/src/lib/map/vertex.glsl +++ b/client/src/lib/map/vertex.glsl @@ -6,7 +6,6 @@ uniform mat4 u_matrix; in vec2 a_pos; out vec2 raw_pos; -out vec4 vertexColor; flat out int azimuthNumber; flat out float azimuthAngle; @@ -21,9 +20,4 @@ void main() { gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0); azimuthAngle = triangleAzimuthLookup[gl_VertexID / 3]; azimuthNumber = gl_VertexID / 3; - - float randColor = rand(vec2(triangleAzimuthLookup[gl_VertexID/3] / 720.0,triangleAzimuthLookup[gl_VertexID/3] / 720.0)); - float randColor2 = rand(vec2(randColor, randColor)); - float randColor3 = rand(vec2(randColor, randColor)); - vertexColor = vec4(randColor,randColor2,randColor3,1.0); } \ No newline at end of file diff --git a/crates/pal/src/lib.rs b/crates/pal/src/lib.rs index 8cef220..ebff002 100644 --- a/crates/pal/src/lib.rs +++ b/crates/pal/src/lib.rs @@ -1,5 +1,6 @@ pub mod default_palettes; pub mod parser; +#[cfg(feature = "wasm")] mod wasm; pub use ordered_float::OrderedFloat;