wxbox/crates/client/src/map.rs

176 lines
5.9 KiB
Rust
Raw Normal View History

2025-03-07 11:31:46 -05:00
pub mod tiles;
pub mod osm;
use std::io::Cursor;
2025-03-06 22:47:37 -05:00
use eframe::glow;
2025-03-07 11:31:46 -05:00
use image::{DynamicImage, ImageReader};
use poll_promise::Promise;
2025-03-06 22:47:37 -05:00
use tracing::warn;
2025-03-07 11:31:46 -05:00
use crate::map::osm::OSMBaselayer;
use crate::map::tiles::{LayerManager, LayerSource, Tile};
2025-03-06 22:47:37 -05:00
pub struct Map {
2025-03-07 11:31:46 -05:00
pub layer_manager: LayerManager,
2025-03-06 22:47:37 -05:00
program: glow::Program,
vertex_array: glow::VertexArray
}
#[allow(unsafe_code)] // we need unsafe code to use glow
impl Map {
2025-03-07 11:31:46 -05:00
pub fn new(layer_manager: LayerManager, gl: &glow::Context) -> Option<Self> {
2025-03-06 22:47:37 -05:00
use glow::HasContext as _;
let shader_version = egui_glow::ShaderVersion::get(gl);
unsafe {
let program = gl.create_program().expect("Cannot create program");
if !shader_version.is_new_shader_interface() {
warn!(
"Custom 3D painting hasn't been ported to {:?}",
shader_version
);
return None;
}
let (vertex_shader_source, fragment_shader_source) = (
r#"
2025-03-07 11:31:46 -05:00
const vec2 verts[6] = vec2[6](
vec2(-1.0, 1.0),
vec2(1.0, 1.0),
vec2(-1.0, -1.0),
2025-03-06 22:47:37 -05:00
vec2(-1.0, -1.0),
2025-03-07 11:31:46 -05:00
vec2(1.0, 1.0),
2025-03-06 22:47:37 -05:00
vec2(1.0, -1.0)
);
2025-03-07 11:31:46 -05:00
const vec4 colors[6] = vec4[6](
2025-03-06 22:47:37 -05:00
vec4(1.0, 0.0, 0.0, 1.0),
vec4(0.0, 1.0, 0.0, 1.0),
2025-03-07 11:31:46 -05:00
vec4(0.0, 0.0, 1.0, 1.0),
vec4(1.0, 0.0, 1.0, 1.0),
vec4(1.0, 0.0, 0.0, 1.0),
vec4(0.0, 1.0, 0.0, 1.0)
2025-03-06 22:47:37 -05:00
);
out vec4 v_color;
uniform float u_angle;
void main() {
v_color = colors[gl_VertexID];
gl_Position = vec4(verts[gl_VertexID], 0.0, 1.0);
}
"#,
r#"
precision mediump float;
in vec4 v_color;
out vec4 out_color;
void main() {
out_color = v_color;
}
"#,
);
let shader_sources = [
(glow::VERTEX_SHADER, vertex_shader_source),
(glow::FRAGMENT_SHADER, fragment_shader_source),
];
let shaders: Vec<_> = shader_sources
.iter()
.map(|(shader_type, shader_source)| {
let shader = gl
.create_shader(*shader_type)
.expect("Cannot create shader");
gl.shader_source(
shader,
&format!(
"{}\n{}",
shader_version.version_declaration(),
shader_source
),
);
gl.compile_shader(shader);
assert!(
gl.get_shader_compile_status(shader),
"Failed to compile custom_3d_glow {shader_type}: {}",
gl.get_shader_info_log(shader)
);
gl.attach_shader(program, shader);
shader
})
.collect();
gl.link_program(program);
assert!(
gl.get_program_link_status(program),
"{}",
gl.get_program_info_log(program)
);
for shader in shaders {
gl.detach_shader(program, shader);
gl.delete_shader(shader);
}
let vertex_array = gl
.create_vertex_array()
.expect("Cannot create vertex array");
Some(Self {
program,
vertex_array,
2025-03-07 11:31:46 -05:00
layer_manager
2025-03-06 22:47:37 -05:00
})
}
}
pub fn destroy(&self, gl: &glow::Context) {
use glow::HasContext as _;
unsafe {
gl.delete_program(self.program);
gl.delete_vertex_array(self.vertex_array);
}
}
2025-03-07 11:31:46 -05:00
pub fn update_view_data(&mut self, ctx: &egui::Context) {
// test: download 0/0/0 if not already there
let tile = self.layer_manager.tiles.entry((0, 0, 0, OSMBaselayer::SOURCE_ID))
.or_insert_with(|| {
let (sender, promise) = Promise::new();
let request = ehttp::Request::get("https://tile.openstreetmap.org/0/0/0.png");
let ctx = ctx.clone();
ehttp::fetch(request, move | response | {
sender.send(match response {
Ok(r) => match ImageReader::new(Cursor::new(r.bytes)).with_guessed_format() {
Ok(img) => match img.decode() {
Ok(img) => {
ctx.request_repaint(); // wake up the ui
Ok(img)
},
Err(e) => Err(e.to_string()),
},
Err(e) => Err(e.to_string()),
},
Err(e) => Err(e.to_string()),
});
});
Tile {
promise
}
});
}
2025-03-06 22:47:37 -05:00
pub fn paint(&self, gl: &glow::Context, angle: f32) {
use glow::HasContext as _;
unsafe {
gl.use_program(Some(self.program));
gl.uniform_1_f32(
gl.get_uniform_location(self.program, "u_angle").as_ref(),
angle,
);
gl.bind_vertex_array(Some(self.vertex_array));
2025-03-07 11:31:46 -05:00
gl.draw_arrays(glow::TRIANGLES, 0, 6);
2025-03-06 22:47:37 -05:00
}
}
}