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 @@
-
-
+
+
-
-
+
@@ -22,7 +21,7 @@
-
+
1748662734805
-
+
+
+ 1748704540785
+
+
+
+ 1748704540785
+
+
@@ -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;