mirror of
https://github.com/maplibre/maplibre-rs.git
synced 2025-12-08 19:05:57 +00:00
Add support for wasm
This commit is contained in:
parent
2de2203ded
commit
7c70ab0ce5
1199
Cargo.lock
generated
1199
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
21
Cargo.toml
21
Cargo.toml
@ -7,25 +7,30 @@ resolver = "2"
|
||||
|
||||
[features]
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
console_error_panic_hook = "0.1"
|
||||
winit = { version = "0.25", features = ["web-sys"] }
|
||||
web-sys = "0.3"
|
||||
js-sys = "0.3"
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen-futures = "0.4"
|
||||
console_log = { version = "0.2", features = ["color"] }
|
||||
|
||||
[dependencies]
|
||||
|
||||
# Futures
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
futures = "0.3.5"
|
||||
pollster = "0.2"
|
||||
|
||||
# Wanted by lyon experiment
|
||||
|
||||
|
||||
# Vector riles
|
||||
vector-tile = { path = "libs/vector_tile" }
|
||||
geo = "0.18.0"
|
||||
geo-types = "0.7"
|
||||
proj = "0.24"
|
||||
mbutiles = "0.1.1"
|
||||
# proj = "0.24" FIXME: Incompatible with wasm
|
||||
# mbutiles = "0.1.1" FIXME: Incompatible with wasm
|
||||
|
||||
# Rendering
|
||||
winit = "0.25"
|
||||
winit = { version = "0.25" }
|
||||
wgpu = "0.11"
|
||||
lyon = { version = "0.17", features = ["extra"] }
|
||||
lyon_path = "0.17"
|
||||
@ -40,7 +45,7 @@ hexdump = "0.1"
|
||||
bytemuck = "1.2.0"
|
||||
|
||||
# Network
|
||||
reqwest = { version = "0.11", features = ["gzip"] }
|
||||
# reqwest = { version = "0.11", features = ["gzip"] } FIXME: Incompatible with wasm
|
||||
|
||||
# Serialization
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "1.56.1"
|
||||
targets = [ "x86_64-unknown-linux-gnu" ]
|
||||
targets = [ "wasm32-unknown-unknown", "x86_64-unknown-linux-gnu" ]
|
||||
|
||||
@ -1,5 +1,43 @@
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use js_sys;
|
||||
use log::{info, trace};
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub struct FPSMeter {
|
||||
start: f64,
|
||||
next_report: f64,
|
||||
frame_count: u32,
|
||||
pub time_secs: f64,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
impl FPSMeter {
|
||||
pub fn new() -> Self {
|
||||
let start = (js_sys::Date::now() / 1000.0) as f64;
|
||||
Self {
|
||||
start,
|
||||
next_report: start + 1.0,
|
||||
frame_count: 0,
|
||||
time_secs: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_and_print(&mut self) {
|
||||
self.frame_count += 1;
|
||||
let now = (js_sys::Date::now() / 1000.0) as f64;
|
||||
self.time_secs = now - self.start;
|
||||
if now >= self.next_report {
|
||||
info!("{} FPS", self.frame_count);
|
||||
self.frame_count = 0;
|
||||
self.next_report = now + 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub struct FPSMeter {
|
||||
start: Instant,
|
||||
next_report: Instant,
|
||||
@ -7,6 +45,7 @@ pub struct FPSMeter {
|
||||
pub time_secs: f32,
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl FPSMeter {
|
||||
pub fn new() -> Self {
|
||||
let start = Instant::now();
|
||||
@ -23,7 +62,7 @@ impl FPSMeter {
|
||||
let now = Instant::now();
|
||||
self.time_secs = (now - self.start).as_secs_f32();
|
||||
if now >= self.next_report {
|
||||
println!("{} FPS", self.frame_count);
|
||||
info!("{} FPS", self.frame_count);
|
||||
self.frame_count = 0;
|
||||
self.next_report = now + Duration::from_secs(1);
|
||||
}
|
||||
|
||||
51
src/main.rs
51
src/main.rs
@ -1,6 +1,7 @@
|
||||
use log::info;
|
||||
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
|
||||
use winit::event_loop::{ControlFlow, EventLoop};
|
||||
use winit::window::Window;
|
||||
use winit::window::{WindowBuilder};
|
||||
|
||||
use crate::state::State;
|
||||
|
||||
@ -11,20 +12,42 @@ mod shader;
|
||||
mod shader_ffi;
|
||||
mod state;
|
||||
mod tesselation;
|
||||
mod tile_downloader;
|
||||
mod texture;
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
println!("== wgpu example ==");
|
||||
println!("Controls:");
|
||||
println!(" Arrow keys: scrolling");
|
||||
println!(" PgUp/PgDown: zoom in/out");
|
||||
println!(" a/z: increase/decrease the stroke width");
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod web;
|
||||
mod platform_constants;
|
||||
|
||||
async fn setup() {
|
||||
info!("== mapr ==");
|
||||
info!("Controls:");
|
||||
info!(" Arrow keys: scrolling");
|
||||
info!(" PgUp/PgDown: zoom in/out");
|
||||
info!(" a/z: increase/decrease the stroke width");
|
||||
|
||||
let event_loop = EventLoop::new();
|
||||
let window = Window::new(&event_loop).unwrap();
|
||||
let mut state = pollster::block_on(State::new(&window));
|
||||
|
||||
let window = WindowBuilder::new()
|
||||
.with_title("A fantastic window!")
|
||||
.build(&event_loop)
|
||||
.unwrap();
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
use winit::platform::web::WindowExtWebSys;
|
||||
|
||||
let canvas = window.canvas();
|
||||
|
||||
let window = web_sys::window().unwrap();
|
||||
let document = window.document().unwrap();
|
||||
let body = document.body().unwrap();
|
||||
|
||||
body.append_child(&canvas)
|
||||
.expect("Append canvas to HTML body");
|
||||
}
|
||||
|
||||
//let mut state = pollster::block_on(State::new(&window));
|
||||
let mut state = State::new(&window).await;
|
||||
|
||||
window.request_redraw();
|
||||
|
||||
@ -78,3 +101,9 @@ fn main() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn main() {
|
||||
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
|
||||
|
||||
pollster::block_on(setup());
|
||||
}
|
||||
|
||||
5
src/platform_constants.rs
Normal file
5
src/platform_constants.rs
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub const COLOR_TEXTURE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Bgra8Unorm;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub const COLOR_TEXTURE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Bgra8UnormSrgb;
|
||||
@ -1,4 +1,5 @@
|
||||
use wgpu::{ColorTargetState, FragmentState, ShaderModule, ShaderModuleDescriptor, VertexAttribute, VertexBufferLayout, VertexState};
|
||||
use crate::platform_constants::COLOR_TEXTURE_FORMAT;
|
||||
|
||||
use crate::shader_ffi::GpuVertex;
|
||||
|
||||
@ -27,7 +28,7 @@ const MAP_VERTEX_SHADER_BUFFERS: [VertexBufferLayout; 1] = [wgpu::VertexBufferLa
|
||||
}];
|
||||
|
||||
const MAP_VERTEX_COLOR_TARGETS: [ColorTargetState; 1] = [wgpu::ColorTargetState {
|
||||
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
||||
format: COLOR_TEXTURE_FORMAT,
|
||||
blend: None,
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
}];
|
||||
|
||||
35
src/state.rs
35
src/state.rs
@ -1,8 +1,9 @@
|
||||
use std::io::Cursor;
|
||||
use std::ops::Range;
|
||||
|
||||
use lyon::math::Vector;
|
||||
use lyon::tessellation::VertexBuffers;
|
||||
use vector_tile::parse_tile;
|
||||
use vector_tile::{parse_tile, parse_tile_reader};
|
||||
use wgpu::util::DeviceExt;
|
||||
use winit::dpi::PhysicalSize;
|
||||
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
|
||||
@ -12,6 +13,7 @@ use winit::window::Window;
|
||||
use crate::fps_meter::FPSMeter;
|
||||
use crate::multisampling::create_multisampled_framebuffer;
|
||||
use crate::piplines::*;
|
||||
use crate::platform_constants::COLOR_TEXTURE_FORMAT;
|
||||
use crate::shader::*;
|
||||
use crate::shader_ffi::*;
|
||||
use crate::tesselation::{RustLogo, Tesselated};
|
||||
@ -72,6 +74,8 @@ pub struct State {
|
||||
scene: SceneParams,
|
||||
}
|
||||
|
||||
const TEST_TILES: &[u8] = include_bytes!("../test-data/12-2176-1425.pbf");
|
||||
|
||||
impl State {
|
||||
pub async fn new(window: &Window) -> Self {
|
||||
let sample_count = 4;
|
||||
@ -83,7 +87,8 @@ impl State {
|
||||
let mut geometry: VertexBuffers<GpuVertex, u16> = VertexBuffers::new();
|
||||
|
||||
let (stroke_range, fill_range) = if true {
|
||||
let tile = parse_tile("test-data/12-2176-1425.pbf").expect("failed loading tile");
|
||||
//let tile = parse_tile("test-data/12-2176-1425.pbf").expect("failed loading tile");
|
||||
let tile = parse_tile_reader(&mut Cursor::new(TEST_TILES));
|
||||
(
|
||||
0..tile.tesselate_stroke(&mut geometry, stroke_prim_id),
|
||||
0..0,
|
||||
@ -247,7 +252,7 @@ impl State {
|
||||
|
||||
let surface_config = wgpu::SurfaceConfiguration {
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
||||
format: COLOR_TEXTURE_FORMAT,
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
present_mode: wgpu::PresentMode::Mailbox,
|
||||
@ -255,7 +260,8 @@ impl State {
|
||||
|
||||
surface.configure(&device, &surface_config);
|
||||
|
||||
let depth_texture = Texture::create_depth_texture(&device, &surface_config, "depth_texture", sample_count);
|
||||
let depth_texture =
|
||||
Texture::create_depth_texture(&device, &surface_config, "depth_texture", sample_count);
|
||||
|
||||
let multisampled_render_target = if sample_count > 1 {
|
||||
Some(create_multisampled_framebuffer(
|
||||
@ -289,7 +295,7 @@ impl State {
|
||||
indices_uniform_buffer,
|
||||
fps_meter: FPSMeter::new(),
|
||||
stroke_range,
|
||||
cpu_primitives
|
||||
cpu_primitives,
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,7 +307,12 @@ impl State {
|
||||
self.surface.configure(&self.device, &self.surface_config);
|
||||
|
||||
// Re-configure depth buffer
|
||||
self.depth_texture = Texture::create_depth_texture(&self.device, &self.surface_config, "depth_texture", self.sample_count);
|
||||
self.depth_texture = Texture::create_depth_texture(
|
||||
&self.device,
|
||||
&self.surface_config,
|
||||
"depth_texture",
|
||||
self.sample_count,
|
||||
);
|
||||
|
||||
// Re-configure multi-sampling buffer
|
||||
self.multisampled_render_target = if self.sample_count > 1 {
|
||||
@ -364,9 +375,9 @@ impl State {
|
||||
scene.target_stroke_width *= 0.8;
|
||||
true
|
||||
}
|
||||
_key => false
|
||||
_key => false,
|
||||
},
|
||||
_evt => false
|
||||
_evt => false,
|
||||
};
|
||||
|
||||
found
|
||||
@ -390,10 +401,7 @@ impl State {
|
||||
&self.globals_uniform_buffer,
|
||||
0,
|
||||
bytemuck::cast_slice(&[Globals {
|
||||
resolution: [
|
||||
self.size.width as f32,
|
||||
self.size.height as f32,
|
||||
],
|
||||
resolution: [self.size.width as f32, self.size.height as f32],
|
||||
zoom: scene.zoom,
|
||||
scroll_offset: scene.scroll.to_array(),
|
||||
_pad: 0.0,
|
||||
@ -465,8 +473,7 @@ impl State {
|
||||
|
||||
pub fn update(&mut self) {
|
||||
let scene = &mut self.scene;
|
||||
let time_secs = self.fps_meter.time_secs;
|
||||
|
||||
let time_secs = self.fps_meter.time_secs as f32;
|
||||
|
||||
scene.zoom += (scene.target_zoom - scene.zoom) / 3.0;
|
||||
scene.scroll = scene.scroll + (scene.target_scroll - scene.scroll) / 3.0;
|
||||
|
||||
6
src/web/console.rs
Normal file
6
src/web/console.rs
Normal file
@ -0,0 +1,6 @@
|
||||
extern crate console_error_panic_hook;
|
||||
use std::panic;
|
||||
|
||||
pub fn init_console_error_panic_hook() {
|
||||
panic::set_hook(Box::new(console_error_panic_hook::hook));
|
||||
}
|
||||
14
src/web/mod.rs
Normal file
14
src/web/mod.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
use log::{Level, warn};
|
||||
|
||||
mod console;
|
||||
|
||||
#[wasm_bindgen(start)]
|
||||
pub fn run() {
|
||||
console_log::init_with_level(Level::Info).expect("error initializing log");
|
||||
console::init_console_error_panic_hook();
|
||||
|
||||
wasm_bindgen_futures::spawn_local(async {
|
||||
super::setup().await;
|
||||
});
|
||||
}
|
||||
3
web/.gitignore
vendored
Normal file
3
web/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.ts
|
||||
*.js
|
||||
*.wasm
|
||||
12
web/mapr.html
Normal file
12
web/mapr.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<title>mapr Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="module">
|
||||
import init from "./mapr.js";
|
||||
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user