feat: client-side rendering
This commit is contained in:
parent
61df1e725c
commit
26b393a719
7 changed files with 106 additions and 61 deletions
22
.idea/workspace.xml
generated
22
.idea/workspace.xml
generated
|
@ -7,13 +7,12 @@
|
||||||
<cargoProject FILE="$PROJECT_DIR$/Cargo.toml" />
|
<cargoProject FILE="$PROJECT_DIR$/Cargo.toml" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="2d855648-9644-469a-afa2-59beb52bb1d6" name="Changes" comment="mostly functional v2 rendering">
|
<list default="true" id="2d855648-9644-469a-afa2-59beb52bb1d6" name="Changes" comment="csr rendering v2">
|
||||||
<change afterPath="$PROJECT_DIR$/crates/pal/src/wasm.rs" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/client/src/lib/map/default_palettes.ts" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/Cargo.lock" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.lock" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/client/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/client/package.json" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/client/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/client/package.json" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/client/src/lib/Map.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/client/src/lib/Map.svelte" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/client/src/lib/Map.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/client/src/lib/Map.svelte" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/crates/pal/Cargo.toml" beforeDir="false" afterPath="$PROJECT_DIR$/crates/pal/Cargo.toml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/client/src/lib/map/fragment.glsl" beforeDir="false" afterPath="$PROJECT_DIR$/client/src/lib/map/fragment.glsl" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/crates/pal/src/lib.rs" beforeDir="false" afterPath="$PROJECT_DIR$/crates/pal/src/lib.rs" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/crates/pal/src/lib.rs" beforeDir="false" afterPath="$PROJECT_DIR$/crates/pal/src/lib.rs" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
@ -22,7 +21,7 @@
|
||||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
</component>
|
</component>
|
||||||
<component name="DarkyenusTimeTracker">
|
<component name="DarkyenusTimeTracker">
|
||||||
<option name="totalTimeSeconds" value="11086" />
|
<option name="totalTimeSeconds" value="14770" />
|
||||||
</component>
|
</component>
|
||||||
<component name="FileTemplateManagerImpl">
|
<component name="FileTemplateManagerImpl">
|
||||||
<option name="RECENT_TEMPLATES">
|
<option name="RECENT_TEMPLATES">
|
||||||
|
@ -166,7 +165,15 @@
|
||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1748662734805</updated>
|
<updated>1748662734805</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="4" />
|
<task id="LOCAL-00004" summary="csr rendering v2">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1748704540785</created>
|
||||||
|
<option name="number" value="00004" />
|
||||||
|
<option name="presentableId" value="LOCAL-00004" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1748704540785</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="5" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
@ -177,6 +184,7 @@
|
||||||
<MESSAGE value="feat: client work" />
|
<MESSAGE value="feat: client work" />
|
||||||
<MESSAGE value="debugging" />
|
<MESSAGE value="debugging" />
|
||||||
<MESSAGE value="mostly functional v2 rendering" />
|
<MESSAGE value="mostly functional v2 rendering" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="mostly functional v2 rendering" />
|
<MESSAGE value="csr rendering v2" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="csr rendering v2" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
|
@ -4,7 +4,7 @@
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "bun update:protobuf && bun update:wxbox-pal && vite dev",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"prepare": "svelte-kit sync || echo ''",
|
"prepare": "svelte-kit sync || echo ''",
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
import type { DigitalRadarData, Radial } from './generated_interop/digitalRadarData';
|
import type { DigitalRadarData, Radial } from './generated_interop/digitalRadarData';
|
||||||
import {forwardGeodesic, radToDeg} from "$lib/vincenty";
|
import {forwardGeodesic, radToDeg} from "$lib/vincenty";
|
||||||
import {degToRad} from "$lib/vincenty.js";
|
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 BELOW_THRESHOLD = -9999.0;
|
||||||
const RANGE_FOLDED = -9998.0;
|
const RANGE_FOLDED = -9998.0;
|
||||||
|
@ -167,6 +169,8 @@
|
||||||
if (container.messageType.oneofKind == 'digitalRadarData') {
|
if (container.messageType.oneofKind == 'digitalRadarData') {
|
||||||
const drd: DigitalRadarData = container.messageType.digitalRadarData;
|
const drd: DigitalRadarData = container.messageType.digitalRadarData;
|
||||||
|
|
||||||
|
await init_palette_parser_wasm();
|
||||||
|
|
||||||
const dataLayer = {
|
const dataLayer = {
|
||||||
id: 'dataGl',
|
id: 'dataGl',
|
||||||
type: 'custom',
|
type: 'custom',
|
||||||
|
@ -187,14 +191,6 @@
|
||||||
|
|
||||||
this.aPos = gl.getAttribLocation(this.program, 'a_pos');
|
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 lat = 38.976111;
|
||||||
const long = -77.4875;
|
const long = -77.4875;
|
||||||
|
|
||||||
|
@ -214,7 +210,7 @@
|
||||||
|
|
||||||
if (radial.product && radial.product.data && radial.product.data.data) {
|
if (radial.product && radial.product.data && radial.product.data.data) {
|
||||||
const angle_a = radial.azimuthAngleDegrees;
|
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 start_range = radial.product.data.startRange; // m
|
||||||
const sample_interval = radial.product.data.sampleInterval; // 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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||||
gl.uniform1i(gl.getUniformLocation(this.program, 'data'), 10);
|
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) {
|
render(gl, args) {
|
||||||
gl.activeTexture(gl.TEXTURE0 + 10);
|
gl.activeTexture(gl.TEXTURE0 + 10);
|
||||||
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
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.useProgram(this.program);
|
||||||
|
|
||||||
gl.uniformMatrix4fv(
|
gl.uniformMatrix4fv(
|
||||||
|
|
8
client/src/lib/map/default_palettes.ts
Normal file
8
client/src/lib/map/default_palettes.ts
Normal file
|
@ -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`;
|
|
@ -7,12 +7,16 @@ const float PI = 3.14159265358979323846264338327950288;
|
||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
in vec2 raw_pos;
|
in vec2 raw_pos;
|
||||||
in vec4 vertexColor;
|
|
||||||
flat in int azimuthNumber;
|
flat in int azimuthNumber;
|
||||||
flat in float azimuthAngle;
|
flat in float azimuthAngle;
|
||||||
|
|
||||||
uniform sampler2D data;
|
uniform sampler2D data;
|
||||||
|
|
||||||
|
uniform sampler2D bounds;
|
||||||
|
uniform sampler2D colorData;
|
||||||
|
uniform sampler2D color2Data;
|
||||||
|
uniform int paletteLength;
|
||||||
|
|
||||||
uniform float radarLat;
|
uniform float radarLat;
|
||||||
uniform float radarLng;
|
uniform float radarLng;
|
||||||
|
|
||||||
|
@ -27,18 +31,8 @@ Wgs84Coordinates rawPosToWgs84(vec2 raw_pos) {
|
||||||
return Wgs84Coordinates(lat,lng);
|
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
|
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() {
|
void main() {
|
||||||
Wgs84Coordinates thisPixelCoordinates = rawPosToWgs84(raw_pos);
|
Wgs84Coordinates thisPixelCoordinates = rawPosToWgs84(raw_pos);
|
||||||
Wgs84Coordinates radarCoordinates = Wgs84Coordinates(radarLat,radarLng);
|
Wgs84Coordinates radarCoordinates = Wgs84Coordinates(radarLat,radarLng);
|
||||||
|
@ -65,37 +59,30 @@ void main() {
|
||||||
fragColor = vec4(0,0,0,0);
|
fragColor = vec4(0,0,0,0);
|
||||||
return;
|
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));
|
int gate_number = int(floor((distance_meters - 2125.0) / 250.0));
|
||||||
|
|
||||||
float rawValue = texelFetch(data, ivec2(gate_number, azimuthNumber), 0).r;
|
float rawValue = texelFetch(data, ivec2(gate_number, azimuthNumber), 0).r;
|
||||||
|
|
||||||
if (rawValue > 80.0) {
|
// colorize!
|
||||||
fragColor = vec4(128.0 / 255.0, 128.0 / 255.0, 128.0 / 255.0, 1.0);
|
for (int i = paletteLength; i > 0; i--) {
|
||||||
} else if (rawValue > 70.0) {
|
vec2 rangeBounds = texelFetch(bounds, ivec2(0, i), 0).rg;
|
||||||
fragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
float lower = rangeBounds.r;
|
||||||
} else if (rawValue > 60.0) {
|
float higher = rangeBounds.g;
|
||||||
fragColor = vec4(1.0, 0.0, 1.0, 1.0);
|
if (rawValue >= lower && rawValue < higher) {
|
||||||
} else if (rawValue > 50.0) {
|
float mapped_end = higher - lower;
|
||||||
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
float mapped_point = rawValue - lower;
|
||||||
} else if (rawValue > 40.0) {
|
float t = mapped_point / mapped_end;
|
||||||
fragColor = vec4(1.0, 1.0, 0.0, 1.0);
|
|
||||||
} else if (rawValue > 30.0) {
|
vec4 color_start = texelFetch(colorData, ivec2(0, i), 0);
|
||||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
vec4 color_end = texelFetch(color2Data, ivec2(0, i), 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);
|
fragColor = mix(color_start, color_end, t);
|
||||||
} else {
|
return;
|
||||||
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
}
|
||||||
}
|
}
|
||||||
|
fragColor = vec4(0,0,0,0);
|
||||||
|
return;
|
||||||
}
|
}
|
|
@ -6,7 +6,6 @@ uniform mat4 u_matrix;
|
||||||
in vec2 a_pos;
|
in vec2 a_pos;
|
||||||
|
|
||||||
out vec2 raw_pos;
|
out vec2 raw_pos;
|
||||||
out vec4 vertexColor;
|
|
||||||
flat out int azimuthNumber;
|
flat out int azimuthNumber;
|
||||||
flat out float azimuthAngle;
|
flat out float azimuthAngle;
|
||||||
|
|
||||||
|
@ -21,9 +20,4 @@ void main() {
|
||||||
gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0);
|
gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0);
|
||||||
azimuthAngle = triangleAzimuthLookup[gl_VertexID / 3];
|
azimuthAngle = triangleAzimuthLookup[gl_VertexID / 3];
|
||||||
azimuthNumber = 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);
|
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod default_palettes;
|
pub mod default_palettes;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
#[cfg(feature = "wasm")]
|
||||||
mod wasm;
|
mod wasm;
|
||||||
|
|
||||||
pub use ordered_float::OrderedFloat;
|
pub use ordered_float::OrderedFloat;
|
||||||
|
|
Loading…
Add table
Reference in a new issue