Fix compilation in winit and demo module

This commit is contained in:
Maximilian Ammann 2022-09-25 17:41:59 +02:00
parent c6eadbf2cc
commit c663416d05
27 changed files with 481 additions and 366 deletions

View File

@ -1,37 +1,41 @@
use maplibre::headless::map::HeadlessMap;
use maplibre::headless::window::HeadlessMapWindowConfig;
use maplibre::kernel::KernelBuilder;
use maplibre::render::builder::RenderBuilder;
use maplibre::style::Style;
use maplibre::{
coords::{LatLon, WorldTileCoords},
error::Error,
headless::{HeadlessEnvironment, HeadlessMapWindowConfig},
io::apc::SchedulerAsyncProcedureCall,
platform::{http_client::ReqwestHttpClient, scheduler::TokioScheduler},
render::settings::{RendererSettings, TextureFormat},
util::grid::google_mercator,
window::WindowSize,
MapBuilder,
};
use maplibre_winit::winit::WinitEnvironment;
use tile_grid::{extent_wgs84_to_merc, Extent, GridIterator};
pub async fn run_headless(tile_size: u32, min: LatLon, max: LatLon) {
let client = ReqwestHttpClient::new(None);
let mut map =
MapBuilder::<HeadlessEnvironment<_, _, _, SchedulerAsyncProcedureCall<_, _>>>::new()
.with_map_window_config(HeadlessMapWindowConfig {
size: WindowSize::new(tile_size, tile_size).unwrap(),
})
.with_http_client(client.clone())
.with_apc(SchedulerAsyncProcedureCall::new(
client,
TokioScheduler::new(),
)) // FIXME (wasm-executor): avoid passing client and scheduler here
.with_scheduler(TokioScheduler::new())
.with_renderer_settings(RendererSettings {
texture_format: TextureFormat::Rgba8UnormSrgb,
..RendererSettings::default()
})
.build()
.initialize_headless()
.await;
let kernel = KernelBuilder::new()
.with_map_window_config(HeadlessMapWindowConfig::new(
WindowSize::new(tile_size, tile_size).unwrap(),
))
.with_http_client(client.clone())
.with_apc(SchedulerAsyncProcedureCall::new(
client,
TokioScheduler::new(),
))
.with_scheduler(TokioScheduler::new())
.build();
let renderer = RenderBuilder::new()
.build()
.initialize_headless_with(&kernel)
.await
.expect("Failed to initialize renderer");
let mut map = HeadlessMap::new(Style::default(), renderer, kernel).unwrap();
let tile_limits = google_mercator().tile_limits(
extent_wgs84_to_merc(&Extent {
@ -46,18 +50,11 @@ pub async fn run_headless(tile_size: u32, min: LatLon, max: LatLon) {
for (z, x, y) in GridIterator::new(10, 10, tile_limits) {
let coords = WorldTileCoords::from((x as i32, y as i32, z.into()));
println!("Rendering {}", &coords);
map.map_schedule
.fetch_process(&coords)
let tile = map
.fetch_tile(coords, &["water"])
.await
.expect("Failed to fetch and process!");
match map.map_schedule_mut().update_and_redraw() {
Ok(_) => {}
Err(Error::Render(e)) => {
eprintln!("{}", e);
if e.should_exit() {}
}
e => eprintln!("{:?}", e),
};
map.render_tile(tile);
}
}

View File

@ -3,7 +3,7 @@
use std::time::Duration;
use cgmath::Vector2;
use maplibre::context::ViewState;
use maplibre::world::ViewState;
use winit::event::{DeviceEvent, KeyboardInput, TouchPhase, WindowEvent};
use crate::input::{

View File

@ -1,7 +1,7 @@
use std::time::Duration;
use cgmath::{EuclideanSpace, Point3, Vector2, Vector3, Zero};
use maplibre::{context::ViewState, render::camera::Camera};
use maplibre::{render::camera::Camera, world::ViewState};
use winit::event::{ElementState, MouseButton};
use super::UpdateState;
@ -45,17 +45,17 @@ impl UpdateState for PanHandler {
};
if self.start_camera_position.is_none() {
self.start_camera_position = Some(state.camera.position.to_vec());
self.start_camera_position = Some(state.camera().position().to_vec());
}
if let Some(start_camera_position) = self.start_camera_position {
state.camera.position = Point3::from_vec(
state.camera_mut().move_to(Point3::from_vec(
start_camera_position + Vector3::new(delta.x, delta.y, 0.0),
);
));
}
}
} else {
self.reference_camera = Some(state.camera.clone());
self.reference_camera = Some(state.camera().clone());
}
}
}

View File

@ -1,6 +1,6 @@
use std::time::Duration;
use maplibre::context::ViewState;
use maplibre::world::ViewState;
use super::UpdateState;

View File

@ -1,7 +1,7 @@
use std::time::Duration;
use cgmath::Vector2;
use maplibre::context::ViewState;
use maplibre::world::ViewState;
use winit::event::{ElementState, MouseButton};
use crate::input::UpdateState;
@ -66,7 +66,7 @@ impl UpdateState for QueryHandler {
let _z = state.visible_level(); // FIXME: can be wrong, if tiles of different z are visible
let _zoom = state.zoom();
if let Some(_coordinates) = state.camera.window_to_world_at_ground(
if let Some(_coordinates) = state.camera().window_to_world_at_ground(
&window_position,
&inverted_view_proj,
false,

View File

@ -1,7 +1,7 @@
use std::time::Duration;
use cgmath::{Vector3, Zero};
use maplibre::context::ViewState;
use maplibre::world::ViewState;
use super::UpdateState;
@ -17,7 +17,7 @@ impl UpdateState for ShiftHandler {
let dt = dt.as_secs_f64() * (1.0 / self.speed);
let delta = self.camera_translate * dt;
state.camera.position += delta;
state.camera_mut().move_relative(delta);
self.camera_translate -= delta;
}
}

View File

@ -1,7 +1,7 @@
use std::time::Duration;
use cgmath::{Deg, Rad, Zero};
use maplibre::context::ViewState;
use maplibre::world::ViewState;
use super::UpdateState;
@ -17,7 +17,7 @@ impl UpdateState for TiltHandler {
let dt = dt.as_secs_f64() * (1.0 / self.speed);
let delta = self.delta_pitch * dt;
state.camera.pitch += Rad::from(delta);
state.camera_mut().pitch_self(delta);
self.delta_pitch -= delta;
}
}

View File

@ -1,7 +1,7 @@
use std::time::Duration;
use cgmath::{Vector2, Vector3};
use maplibre::{context::ViewState, coords::Zoom};
use maplibre::{coords::Zoom, world::ViewState};
use super::UpdateState;
@ -24,7 +24,7 @@ impl UpdateState for ZoomHandler {
let view_proj = state.view_projection();
let inverted_view_proj = view_proj.invert();
if let Some(cursor_position) = state.camera.window_to_world_at_ground(
if let Some(cursor_position) = state.camera().window_to_world_at_ground(
&window_position,
&inverted_view_proj,
false,
@ -37,7 +37,7 @@ impl UpdateState for ZoomHandler {
cursor_position.z,
) - cursor_position;
state.camera.position += delta;
state.camera_mut().move_relative(delta);
}
}
}

View File

@ -1,6 +1,7 @@
use std::{cell::RefCell, marker::PhantomData, ops::Deref, rc::Rc};
use crate::input::{InputController, UpdateState};
use instant::Instant;
use maplibre::event_loop::{EventLoop, EventLoopProxy};
use maplibre::map::Map;
use maplibre::{
environment::Environment,
error::Error,
@ -10,15 +11,17 @@ use maplibre::{
source_client::HttpClient,
transferables::{DefaultTransferables, Transferables},
},
map_schedule::InteractiveMapSchedule,
window::{EventLoop, HeadedMapWindow, MapWindowConfig},
window::{HeadedMapWindow, MapWindowConfig},
};
use std::{cell::RefCell, marker::PhantomData, ops::Deref, rc::Rc};
use winit::{
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::ControlFlow,
};
use crate::input::{InputController, UpdateState};
pub type RawWinitWindow = winit::window::Window;
pub type RawWinitEventLoop<ET> = winit::event_loop::EventLoop<ET>;
pub type RawEventLoopProxy<ET> = winit::event_loop::EventLoopProxy<ET>;
#[cfg(target_arch = "wasm32")]
mod web;
@ -32,14 +35,19 @@ pub use noweb::*;
pub use web::*;
#[cfg(not(target_arch = "wasm32"))]
pub struct WinitMapWindowConfig {
pub struct WinitMapWindowConfig<ET> {
title: String,
phantom_et: PhantomData<ET>,
}
#[cfg(not(target_arch = "wasm32"))]
impl WinitMapWindowConfig {
impl<ET> WinitMapWindowConfig<ET> {
pub fn new(title: String) -> Self {
Self { title }
Self {
title,
phantom_et: Default::default(),
}
}
}
@ -55,151 +63,157 @@ impl WinitMapWindowConfig {
}
}
pub struct WinitMapWindow {
window: WinitWindow,
event_loop: Option<WinitEventLoop>,
pub struct WinitMapWindow<ET: 'static> {
window: RawWinitWindow,
event_loop: Option<WinitEventLoop<ET>>,
}
impl WinitMapWindow {
pub fn take_event_loop(&mut self) -> Option<WinitEventLoop> {
impl<ET> WinitMapWindow<ET> {
pub fn take_event_loop(&mut self) -> Option<WinitEventLoop<ET>> {
self.event_loop.take()
}
}
pub type WinitWindow = winit::window::Window;
pub type WinitEventLoop = winit::event_loop::EventLoop<()>;
pub struct WinitEnvironment<
S: Scheduler,
HC: HttpClient,
T: Transferables,
APC: AsyncProcedureCall<T, HC>,
> {
phantom_s: PhantomData<S>,
phantom_hc: PhantomData<HC>,
phantom_t: PhantomData<T>,
phantom_apc: PhantomData<APC>,
pub struct WinitEventLoop<ET: 'static> {
event_loop: RawWinitEventLoop<ET>,
}
impl<S: Scheduler, HC: HttpClient, T: Transferables, APC: AsyncProcedureCall<T, HC>> Environment
for WinitEnvironment<S, HC, T, APC>
{
type MapWindowConfig = WinitMapWindowConfig;
type AsyncProcedureCall = APC;
type Scheduler = S;
type HttpClient = HC;
type Transferables = T;
}
impl<ET: 'static> EventLoop<ET> for WinitEventLoop<ET> {
type EventLoopProxy = WinitEventLoopProxy<ET>;
///Main (platform-specific) main loop which handles:
///* Input (Mouse/Keyboard)
///* Platform Events like suspend/resume
///* Render a new frame
impl<E: Environment> EventLoop<E> for WinitMapWindow
where
E::MapWindowConfig: MapWindowConfig<MapWindow = WinitMapWindow>,
{
fn run(
fn run<E>(
mut self,
map_schedule: Rc<RefCell<InteractiveMapSchedule<E>>>,
mut window: <E::MapWindowConfig as MapWindowConfig>::MapWindow,
mut map: Map<E>,
max_frames: Option<u64>,
) {
) where
E: Environment,
<E::MapWindowConfig as MapWindowConfig>::MapWindow: HeadedMapWindow,
{
let mut last_render_time = Instant::now();
let mut current_frame: u64 = 0;
let mut input_controller = InputController::new(0.2, 100.0, 0.1);
self.take_event_loop()
.unwrap()
.run(move |event, _, control_flow| {
let mut map_schedule = map_schedule.deref().borrow_mut();
self.event_loop
.run(move |event, window_target, control_flow| {
#[cfg(target_os = "android")]
if !map_schedule.is_initialized() && event == Event::Resumed {
if !map.is_initialized() && event == Event::Resumed {
use tokio::{runtime::Handle, task};
task::block_in_place(|| {
Handle::current().block_on(async {
map_schedule.late_init().await;
map.late_init().await;
})
});
return;
}
match event {
Event::DeviceEvent {
ref event,
.. // We're not using device_id currently
} => {
input_controller.device_input(event);
}
Event::DeviceEvent {
ref event,
.. // We're not using device_id currently
} => {
input_controller.device_input(event);
}
Event::WindowEvent {
ref event,
window_id,
} if window_id == self.inner().id() => {
if !input_controller.window_input(event) {
match event {
WindowEvent::CloseRequested
| WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape),
Event::WindowEvent {
ref event,
window_id,
} if window_id == window.id().into() => {
if !input_controller.window_input(event) {
match event {
WindowEvent::CloseRequested
| WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape),
..
},
..
},
..
} => *control_flow = ControlFlow::Exit,
WindowEvent::Resized(physical_size) => {
map_schedule.resize(physical_size.width, physical_size.height);
} => *control_flow = ControlFlow::Exit,
WindowEvent::Resized(physical_size) => {
// FIXME map.resize(physical_size.width, physical_size.height);
}
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
// FIXME map.resize(new_inner_size.width, new_inner_size.height);
}
_ => {}
}
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
map_schedule.resize(new_inner_size.width, new_inner_size.height);
}
_ => {}
}
}
}
Event::RedrawRequested(_) => {
let now = Instant::now();
let dt = now - last_render_time;
last_render_time = now;
Event::RedrawRequested(_) => {
let now = Instant::now();
let dt = now - last_render_time;
last_render_time = now;
input_controller.update_state(map_schedule.view_state_mut(), dt);
// FIXME input_controller.update_state(map.view_state_mut(), dt);
match map_schedule.update_and_redraw() {
Ok(_) => {}
Err(Error::Render(e)) => {
eprintln!("{}", e);
if e.should_exit() {
match map.run_schedule() {
Ok(_) => {}
Err(Error::Render(e)) => {
eprintln!("{}", e);
if e.should_exit() {
*control_flow = ControlFlow::Exit;
}
}
e => eprintln!("{:?}", e)
};
if let Some(max_frames) = max_frames {
if current_frame >= max_frames {
log::info!("Exiting because maximum frames reached.");
*control_flow = ControlFlow::Exit;
}
}
e => eprintln!("{:?}", e)
};
if let Some(max_frames) = max_frames {
if current_frame >= max_frames {
log::info!("Exiting because maximum frames reached.");
*control_flow = ControlFlow::Exit;
current_frame += 1;
}
current_frame += 1;
}
Event::Suspended => {
// FIXME unimplemented!()
}
Event::Resumed => {
// FIXME unimplemented!()
}
Event::MainEventsCleared => {
// RedrawRequested will only trigger once, unless we manually
// request it.
window.request_redraw();
}
_ => {}
}
Event::Suspended => {
map_schedule.suspend();
}
Event::Resumed => {
map_schedule.resume(&self);
}
Event::MainEventsCleared => {
// RedrawRequested will only trigger once, unless we manually
// request it.
self.inner().request_redraw();
}
_ => {}
}
});
}
fn create_proxy(&self) -> Self::EventLoopProxy {
WinitEventLoopProxy {
proxy: self.event_loop.create_proxy(),
}
}
}
pub struct WinitEventLoopProxy<ET: 'static> {
proxy: RawEventLoopProxy<ET>,
}
impl<ET: 'static> EventLoopProxy<ET> for WinitEventLoopProxy<ET> {
fn send_event(&self, event: ET) {
self.proxy.send_event(event); // FIXME: Handle unwrap
}
}
pub struct WinitEnvironment<S: Scheduler, HC: HttpClient, APC: AsyncProcedureCall<HC>, ET> {
phantom_s: PhantomData<S>,
phantom_hc: PhantomData<HC>,
phantom_apc: PhantomData<APC>,
phantom_et: PhantomData<ET>,
}
impl<S: Scheduler, HC: HttpClient, APC: AsyncProcedureCall<HC>, ET: 'static> Environment
for WinitEnvironment<S, HC, APC, ET>
{
type MapWindowConfig = WinitMapWindowConfig<ET>;
type AsyncProcedureCall = APC;
type Scheduler = S;
type HttpClient = HC;
}

View File

@ -3,18 +3,23 @@
//! * Platform Events like suspend/resume
//! * Render a new frame
use maplibre::event_loop::EventLoop;
use maplibre::headless::map::HeadlessMap;
use maplibre::kernel::{Kernel, KernelBuilder};
use maplibre::map::Map;
use maplibre::render::builder::RenderBuilder;
use maplibre::style::Style;
use maplibre::{
io::apc::SchedulerAsyncProcedureCall,
platform::{http_client::ReqwestHttpClient, run_multithreaded, scheduler::TokioScheduler},
window::{HeadedMapWindow, MapWindow, MapWindowConfig, WindowSize},
MapBuilder,
};
use winit::window::WindowBuilder;
use super::{WinitEventLoop, WinitMapWindow, WinitMapWindowConfig, WinitWindow};
use crate::winit::WinitEnvironment;
use super::{RawWinitEventLoop, RawWinitWindow, WinitMapWindow, WinitMapWindowConfig};
use crate::winit::{WinitEnvironment, WinitEventLoop};
impl MapWindow for WinitMapWindow {
impl<T> MapWindow for WinitMapWindow<T> {
fn size(&self) -> WindowSize {
let size = self.window.inner_size();
#[cfg(target_os = "android")]
@ -29,27 +34,37 @@ impl MapWindow for WinitMapWindow {
window_size
}
}
impl HeadedMapWindow for WinitMapWindow {
type RawWindow = WinitWindow;
impl<T> HeadedMapWindow for WinitMapWindow<T> {
type RawWindow = RawWinitWindow;
fn inner(&self) -> &Self::RawWindow {
fn raw(&self) -> &Self::RawWindow {
&self.window
}
fn request_redraw(&self) {
self.window.request_redraw()
}
fn id(&self) -> u64 {
self.window.id().into()
}
}
impl MapWindowConfig for WinitMapWindowConfig {
type MapWindow = WinitMapWindow;
impl<ET: 'static> MapWindowConfig for WinitMapWindowConfig<ET> {
type MapWindow = WinitMapWindow<ET>;
fn create(&self) -> Self::MapWindow {
let event_loop = WinitEventLoop::new();
let raw_event_loop = winit::event_loop::EventLoopBuilder::<ET>::with_user_event().build();
let window = WindowBuilder::new()
.with_title(&self.title)
.build(&event_loop)
.build(&raw_event_loop)
.unwrap();
Self::MapWindow {
window,
event_loop: Some(event_loop),
event_loop: Some(WinitEventLoop {
event_loop: raw_event_loop,
}),
}
}
}
@ -57,7 +72,7 @@ impl MapWindowConfig for WinitMapWindowConfig {
pub fn run_headed_map(cache_path: Option<String>) {
run_multithreaded(async {
let client = ReqwestHttpClient::new(cache_path);
MapBuilder::<WinitEnvironment<_, _, _, SchedulerAsyncProcedureCall<_, _>>>::new()
let kernel: Kernel<WinitEnvironment<_, _, _, ()>> = KernelBuilder::new()
.with_map_window_config(WinitMapWindowConfig::new("maplibre".to_string()))
.with_http_client(client.clone())
.with_apc(SchedulerAsyncProcedureCall::new(
@ -65,9 +80,21 @@ pub fn run_headed_map(cache_path: Option<String>) {
TokioScheduler::new(),
))
.with_scheduler(TokioScheduler::new())
.build();
let uninitialized = RenderBuilder::new()
.build()
.initialize()
.initialize_with(&kernel)
.await
.run()
.expect("Failed to initialize renderer");
let result = uninitialized.unwarp();
let mut window = result.window;
let renderer = result.renderer;
window.event_loop.take().unwrap().run(
window,
Map::new(Style::default(), kernel, renderer).unwrap(),
None,
)
})
}

View File

@ -1,13 +1,13 @@
use maplibre::window::{HeadedMapWindow, MapWindow, MapWindowConfig, WindowSize};
use winit::{platform::web::WindowBuilderExtWebSys, window::WindowBuilder};
use super::{WinitEventLoop, WinitMapWindow, WinitMapWindowConfig, WinitWindow};
use super::{RawWinitEventLoop, RawWinitWindow, WinitMapWindow, WinitMapWindowConfig};
impl MapWindowConfig for WinitMapWindowConfig {
type MapWindow = WinitMapWindow;
fn create(&self) -> Self::MapWindow {
let event_loop = WinitEventLoop::new();
let event_loop = RawWinitEventLoop::new();
let window: winit::window::Window = WindowBuilder::new()
.with_canvas(Some(get_canvas(&self.canvas_id)))
@ -31,9 +31,9 @@ impl MapWindow for WinitMapWindow {
}
}
impl HeadedMapWindow for WinitMapWindow {
type RawWindow = WinitWindow;
type RawWindow = RawWinitWindow;
fn inner(&self) -> &Self::RawWindow {
fn raw(&self) -> &Self::RawWindow {
&self.window
}
}

View File

@ -1,3 +1,5 @@
use crate::event_loop::EventLoopConfig;
use crate::kernel::Kernel;
use crate::{
io::{
apc::AsyncProcedureCall,
@ -13,63 +15,7 @@ use crate::{
pub trait Environment: 'static {
type MapWindowConfig: MapWindowConfig;
type AsyncProcedureCall: AsyncProcedureCall<Self::Transferables, Self::HttpClient>;
type AsyncProcedureCall: AsyncProcedureCall<Self::HttpClient>;
type Scheduler: Scheduler;
type HttpClient: HttpClient;
type Transferables: Transferables;
}
pub struct Kernel<E: Environment> {
pub map_window_config: E::MapWindowConfig,
pub apc: E::AsyncProcedureCall,
pub scheduler: E::Scheduler,
pub source_client: SourceClient<E::HttpClient>,
}
pub struct KernelBuilder<E: Environment> {
map_window_config: Option<E::MapWindowConfig>,
apc: Option<E::AsyncProcedureCall>,
scheduler: Option<E::Scheduler>,
http_client: Option<E::HttpClient>,
}
impl<E: Environment> KernelBuilder<E> {
pub fn new() -> Self {
Self {
scheduler: None,
apc: None,
http_client: None,
map_window_config: None,
}
}
pub fn with_map_window_config(mut self, map_window_config: E::MapWindowConfig) -> Self {
self.map_window_config = Some(map_window_config);
self
}
pub fn with_scheduler(mut self, scheduler: E::Scheduler) -> Self {
self.scheduler = Some(scheduler);
self
}
pub fn with_apc(mut self, apc: E::AsyncProcedureCall) -> Self {
self.apc = Some(apc);
self
}
pub fn with_http_client(mut self, http_client: E::HttpClient) -> Self {
self.http_client = Some(http_client);
self
}
pub fn build(self) -> Kernel<E> {
Kernel {
scheduler: self.scheduler.unwrap(), // TODO: Remove unwrap
apc: self.apc.unwrap(), // TODO: Remove unwrap
source_client: SourceClient::new(HttpSourceClient::new(self.http_client.unwrap())), // TODO: Remove unwrap
map_window_config: self.map_window_config.unwrap(), // TODO: Remove unwrap
}
}
}

View File

@ -0,0 +1,29 @@
use crate::environment::Environment;
use crate::map::Map;
use crate::window::{HeadedMapWindow, MapWindowConfig};
pub trait EventLoopConfig {
type EventType: 'static;
type EventLoopProxy: EventLoopProxy<Self::EventType>;
fn create_proxy() -> Self::EventLoopProxy;
}
pub trait EventLoopProxy<T: 'static> {
fn send_event(&self, event: T);
}
pub trait EventLoop<T: 'static> {
type EventLoopProxy: EventLoopProxy<T>;
fn run<E>(
self,
window: <E::MapWindowConfig as MapWindowConfig>::MapWindow,
map: Map<E>,
max_frames: Option<u64>,
) where
E: Environment,
<E::MapWindowConfig as MapWindowConfig>::MapWindow: HeadedMapWindow;
fn create_proxy(&self) -> Self::EventLoopProxy;
}

View File

@ -1,7 +1,6 @@
use crate::environment::Environment;
use crate::headless::window::HeadlessMapWindowConfig;
use crate::io::apc::SchedulerAsyncProcedureCall;
use crate::io::transferables::DefaultTransferables;
use crate::platform::http_client::ReqwestHttpClient;
use crate::platform::scheduler::TokioScheduler;
@ -12,5 +11,4 @@ impl Environment for HeadlessEnvironment {
type AsyncProcedureCall = SchedulerAsyncProcedureCall<Self::HttpClient, Self::Scheduler>;
type Scheduler = TokioScheduler;
type HttpClient = ReqwestHttpClient;
type Transferables = DefaultTransferables;
}

View File

@ -1,9 +1,9 @@
use crate::io::pipeline::Processable;
use crate::kernel::Kernel;
use crate::render::builder::UninitializedRenderer;
use crate::{
context::MapContext,
coords::{WorldCoords, WorldTileCoords, Zoom, TILE_SIZE},
environment::Kernel,
error::Error,
headless::{
environment::HeadlessEnvironment, graph_node::CopySurfaceBufferNode,

View File

@ -48,10 +48,11 @@ pub type AsyncProcedureFuture = Pin<Box<(dyn Future<Output = ()> + 'static)>>;
pub type AsyncProcedure<C> = fn(input: Input, context: C) -> AsyncProcedureFuture;
pub trait AsyncProcedureCall<T: Transferables, HC: HttpClient>: 'static {
type Context: Context<T, HC> + Send;
pub trait AsyncProcedureCall<HC: HttpClient>: 'static {
type Context: Context<Self::Transferables, HC> + Send;
type Transferables: Transferables;
fn receive(&mut self) -> Option<Message<T>>;
fn receive(&self) -> Option<Message<Self::Transferables>>;
fn schedule(&self, input: Input, procedure: AsyncProcedure<Self::Context>);
}
@ -91,12 +92,11 @@ impl<HC: HttpClient, S: Scheduler> SchedulerAsyncProcedureCall<HC, S> {
}
}
impl<HC: HttpClient, S: Scheduler> AsyncProcedureCall<DefaultTransferables, HC>
for SchedulerAsyncProcedureCall<HC, S>
{
type Context = SchedulerContext<DefaultTransferables, HC>;
impl<HC: HttpClient, S: Scheduler> AsyncProcedureCall<HC> for SchedulerAsyncProcedureCall<HC, S> {
type Context = SchedulerContext<Self::Transferables, HC>;
type Transferables = DefaultTransferables;
fn receive(&mut self) -> Option<Message<DefaultTransferables>> {
fn receive(&self) -> Option<Message<DefaultTransferables>> {
let transferred = self.channel.1.try_recv().ok()?;
Some(transferred)
}

56
maplibre/src/kernel.rs Normal file
View File

@ -0,0 +1,56 @@
use crate::environment::Environment;
use crate::io::source_client::{HttpSourceClient, SourceClient};
pub struct Kernel<E: Environment> {
pub map_window_config: E::MapWindowConfig,
pub apc: E::AsyncProcedureCall,
pub scheduler: E::Scheduler,
pub source_client: SourceClient<E::HttpClient>,
}
pub struct KernelBuilder<E: Environment> {
map_window_config: Option<E::MapWindowConfig>,
apc: Option<E::AsyncProcedureCall>,
scheduler: Option<E::Scheduler>,
http_client: Option<E::HttpClient>,
}
impl<E: Environment> KernelBuilder<E> {
pub fn new() -> Self {
Self {
scheduler: None,
apc: None,
http_client: None,
map_window_config: None,
}
}
pub fn with_map_window_config(mut self, map_window_config: E::MapWindowConfig) -> Self {
self.map_window_config = Some(map_window_config);
self
}
pub fn with_scheduler(mut self, scheduler: E::Scheduler) -> Self {
self.scheduler = Some(scheduler);
self
}
pub fn with_apc(mut self, apc: E::AsyncProcedureCall) -> Self {
self.apc = Some(apc);
self
}
pub fn with_http_client(mut self, http_client: E::HttpClient) -> Self {
self.http_client = Some(http_client);
self
}
pub fn build(self) -> Kernel<E> {
Kernel {
scheduler: self.scheduler.unwrap(), // TODO: Remove unwrap
apc: self.apc.unwrap(), // TODO: Remove unwrap
source_client: SourceClient::new(HttpSourceClient::new(self.http_client.unwrap())), // TODO: Remove unwrap
map_window_config: self.map_window_config.unwrap(), // TODO: Remove unwrap
}
}
}

View File

@ -42,6 +42,8 @@ pub mod environment;
// Used for benchmarking
pub mod benchmarking;
pub mod event_loop;
pub mod kernel;
pub mod map;
pub mod world;

View File

@ -1,15 +1,18 @@
use crate::context::MapContext;
use crate::coords::{LatLon, WorldCoords, Zoom, TILE_SIZE};
use crate::environment::{Environment, Kernel};
use crate::environment::Environment;
use crate::error::Error;
use crate::headless::environment::HeadlessEnvironment;
use crate::kernel::Kernel;
use crate::render::{create_default_render_graph, register_default_render_stages, Renderer};
use crate::schedule::{Schedule, Stage};
use crate::stages::register_stages;
use crate::style::Style;
use crate::world::World;
use std::rc::Rc;
pub struct Map<E: Environment> {
kernel: Kernel<E>,
kernel: Rc<Kernel<E>>,
schedule: Schedule,
map_context: MapContext,
}
@ -31,6 +34,10 @@ impl<E: Environment> Map<E> {
let graph = create_default_render_graph().unwrap(); // TODO: Remove unwrap
register_default_render_stages(graph, &mut schedule);
let kernel = Rc::new(kernel);
register_stages::<E>(&mut schedule, kernel.clone());
Ok(Self {
kernel,
map_context: MapContext {

View File

@ -1,5 +1,5 @@
use crate::environment::Kernel;
use crate::error::Error;
use crate::kernel::Kernel;
use crate::{
environment::Environment,
render::{
@ -9,17 +9,20 @@ use crate::{
style::Style,
window::{HeadedMapWindow, MapWindow, MapWindowConfig},
};
use std::marker::PhantomData;
pub struct RenderBuilder {
pub struct RenderBuilder<MWC: MapWindowConfig> {
wgpu_settings: Option<WgpuSettings>,
renderer_settings: Option<RendererSettings>,
phatom_mwc: PhantomData<MWC>,
}
impl RenderBuilder {
impl<MWC: MapWindowConfig> RenderBuilder<MWC> {
pub fn new() -> Self {
Self {
wgpu_settings: None,
renderer_settings: None,
phatom_mwc: Default::default(),
}
}
@ -33,21 +36,22 @@ impl RenderBuilder {
self
}
pub fn build(self) -> UninitializedRenderer {
pub fn build(self) -> UninitializedRenderer<MWC> {
UninitializedRenderer {
window: None,
wgpu_settings: self.wgpu_settings.unwrap_or_default(),
renderer_settings: self.renderer_settings.unwrap_or_default(),
}
}
}
pub enum InitializationResult {
Initialized(Renderer),
Uninizalized(UninitializedRenderer),
pub enum InitializationResult<MWC: MapWindowConfig> {
Initialized(InitializedRenderer<MWC>),
Uninizalized(UninitializedRenderer<MWC>),
}
impl InitializationResult {
pub fn unwarp(self) -> Renderer {
impl<MWC: MapWindowConfig> InitializationResult<MWC> {
pub fn unwarp(self) -> InitializedRenderer<MWC> {
match self {
InitializationResult::Initialized(renderer) => renderer,
InitializationResult::Uninizalized(_) => panic!("Renderer is not initialized"),
@ -55,55 +59,55 @@ impl InitializationResult {
}
}
pub struct UninitializedRenderer {
pub struct UninitializedRenderer<MWC: MapWindowConfig> {
window: Option<MWC::MapWindow>,
wgpu_settings: WgpuSettings,
renderer_settings: RendererSettings,
}
impl UninitializedRenderer {
impl<MWC: MapWindowConfig> UninitializedRenderer<MWC>
where
MWC::MapWindow: MapWindow + HeadedMapWindow,
{
/// Initializes the whole rendering pipeline for the given configuration.
/// Returns the initialized map, ready to be run.
async fn initialize<MWC: MapWindowConfig>(
self,
map_window_config: &MWC,
) -> Result<InitializationResult, Error>
where
MWC::MapWindow: MapWindow + HeadedMapWindow,
{
async fn initialize(self, map_window_config: &MWC) -> Result<InitializationResult<MWC>, Error> {
let window = map_window_config.create();
#[cfg(target_os = "android")]
let renderer = Ok(InitializationResult::Uninizalized(self));
{
Ok(InitializationResult::Uninizalized(self))
}
#[cfg(not(target_os = "android"))]
let renderer = Ok(InitializationResult::Initialized(
Renderer::initialize(
{
let renderer = Renderer::initialize(
&window,
self.wgpu_settings.clone(),
self.renderer_settings.clone(),
)
.await?,
));
renderer
.await?;
Ok(InitializationResult::Initialized(InitializedRenderer {
window,
renderer,
}))
}
}
pub async fn initialize_with<E: Environment>(
pub async fn initialize_with<E>(
self,
kernel: &Kernel<E>,
) -> Result<InitializationResult, Error>
) -> Result<InitializationResult<MWC>, Error>
where
<E::MapWindowConfig as MapWindowConfig>::MapWindow: MapWindow + HeadedMapWindow,
E: Environment<MapWindowConfig = MWC>,
{
self.initialize(&kernel.map_window_config).await
}
}
#[cfg(feature = "headless")]
impl UninitializedRenderer {
async fn initialize_headless<MWC: MapWindowConfig>(
self,
map_window_config: MWC,
) -> Result<Renderer, Error> {
impl<MWC: MapWindowConfig> UninitializedRenderer<MWC> {
async fn initialize_headless(self, map_window_config: &MWC) -> Result<Renderer, Error> {
let window = map_window_config.create();
Ok(Renderer::initialize_headless(
@ -114,13 +118,15 @@ impl UninitializedRenderer {
.await?)
}
pub async fn initialize_headless_with<E: Environment>(
self,
kernel: &Kernel<E>,
) -> Result<InitializationResult, Error>
pub async fn initialize_headless_with<E>(self, kernel: &Kernel<E>) -> Result<Renderer, Error>
where
<E::MapWindowConfig as MapWindowConfig>::MapWindow: MapWindow + HeadedMapWindow,
E: Environment<MapWindowConfig = MWC>,
{
self.initialize(&kernel.map_window_config).await
self.initialize_headless(&kernel.map_window_config).await
}
}
pub struct InitializedRenderer<MWC: MapWindowConfig> {
pub window: MWC::MapWindow,
pub renderer: Renderer,
}

View File

@ -1,6 +1,6 @@
//! Main camera
use cgmath::{prelude::*, AbsDiffEq, Matrix4, Point2, Point3, Vector2, Vector3, Vector4};
use cgmath::{prelude::*, AbsDiffEq, Matrix4, Point2, Point3, Rad, Vector2, Vector3, Vector4};
use crate::util::{
math::{bounds_from_points, Aabb2, Aabb3, Plane},
@ -68,12 +68,12 @@ impl ModelViewProjection {
#[derive(Debug, Clone)]
pub struct Camera {
pub position: Point3<f64>, // The z axis never changes, the zoom is used instead
pub yaw: cgmath::Rad<f64>,
pub pitch: cgmath::Rad<f64>,
position: Point3<f64>, // The z axis never changes, the zoom is used instead
yaw: cgmath::Rad<f64>,
pitch: cgmath::Rad<f64>,
pub width: f64,
pub height: f64,
width: f64,
height: f64,
}
impl SignificantlyDifferent for Camera {
@ -103,6 +103,14 @@ impl Camera {
}
}
pub fn move_to(&mut self, point: Point3<f64>) {
self.position = point;
}
pub fn move_relative(&mut self, delta: Vector3<f64>) {
self.position += delta;
}
pub fn resize(&mut self, width: u32, height: u32) {
self.width = width as f64;
self.height = height as f64;
@ -347,6 +355,26 @@ impl Camera {
Point2::new(max_x, max_y),
))
}
pub fn position(&self) -> Point3<f64> {
self.position
}
pub fn yaw(&self) -> cgmath::Rad<f64> {
self.yaw
}
pub fn yaw_self<P: Into<Rad<f64>>>(&mut self, delta: P) {
self.yaw += delta.into();
}
pub fn pitch(&self) -> cgmath::Rad<f64> {
self.pitch
}
pub fn pitch_self<P: Into<Rad<f64>>>(&mut self, delta: P) {
self.pitch += delta.into();
}
}
pub struct Perspective {

View File

@ -45,7 +45,8 @@ impl Stage for UploadStage {
bytemuck::cast_slice(&[ShaderGlobals::new(ShaderCamera::new(
view_proj.downcast().into(),
view_state
.camera_position()
.camera()
.position()
.to_homogeneous()
.cast::<f32>()
.unwrap() // TODO: Remove unwrap

View File

@ -10,6 +10,7 @@ use std::{
use geozero::{mvt::tile, GeozeroDatasource};
use request_stage::RequestStage;
use crate::kernel::Kernel;
use crate::{
coords::{WorldCoords, WorldTileCoords, Zoom, ZoomLevel},
environment::Environment,
@ -37,16 +38,9 @@ mod populate_tile_store_stage;
mod request_stage;
/// Register stages required for requesting and preparing new tiles.
pub fn register_stages<E: Environment>(
schedule: &mut Schedule,
http_source_client: HttpSourceClient<E::HttpClient>,
apc: Rc<RefCell<E::AsyncProcedureCall>>,
) {
schedule.add_stage(
"request",
RequestStage::<E>::new(http_source_client, apc.clone()),
);
schedule.add_stage("populate_tile_store", PopulateTileStore::<E>::new(apc));
pub fn register_stages<E: Environment>(schedule: &mut Schedule, kernel: Rc<Kernel<E>>) {
schedule.add_stage("request", RequestStage::<E>::new(kernel.clone()));
schedule.add_stage("populate_tile_store", PopulateTileStore::<E>::new(kernel));
}
pub struct HeadedPipelineProcessor<T: Transferables, HC: HttpClient, C: Context<T, HC>> {

View File

@ -2,6 +2,7 @@
use std::{borrow::BorrowMut, cell::RefCell, ops::Deref, rc::Rc};
use crate::kernel::Kernel;
use crate::{
context::MapContext,
environment::Environment,
@ -15,12 +16,12 @@ use crate::{
};
pub struct PopulateTileStore<E: Environment> {
apc: Rc<RefCell<E::AsyncProcedureCall>>,
kernel: Rc<Kernel<E>>,
}
impl<E: Environment> PopulateTileStore<E> {
pub fn new(apc: Rc<RefCell<E::AsyncProcedureCall>>) -> Self {
Self { apc }
pub fn new(kernel: Rc<Kernel<E>>) -> Self {
Self { kernel }
}
}
@ -34,39 +35,37 @@ impl<E: Environment> Stage for PopulateTileStore<E> {
..
}: &mut MapContext,
) {
if let Ok(mut apc) = self.apc.deref().try_borrow_mut() {
if let Some(result) = apc.receive() {
match result {
Message::TileTessellated(tranferred) => {
let coords = tranferred.coords();
tile_repository.success(coords);
tracing::trace!("Tile at {} finished loading", coords);
log::warn!("Tile at {} finished loading", coords);
}
// FIXME: deduplicate
Message::UnavailableLayer(tranferred) => {
let layer: StoredLayer = tranferred.to_stored_layer();
tracing::debug!(
"Layer {} at {} reached main thread",
layer.layer_name(),
layer.get_coords()
);
tile_repository.put_tessellated_layer(layer);
}
Message::TessellatedLayer(data) => {
let layer: StoredLayer = data.to_stored_layer();
tracing::debug!(
"Layer {} at {} reached main thread",
layer.layer_name(),
layer.get_coords()
);
log::warn!(
"Layer {} at {} reached main thread",
layer.layer_name(),
layer.get_coords()
);
tile_repository.put_tessellated_layer(layer);
}
if let Some(result) = self.kernel.apc.receive() {
match result {
Message::TileTessellated(tranferred) => {
let coords = tranferred.coords();
tile_repository.success(coords);
tracing::trace!("Tile at {} finished loading", coords);
log::warn!("Tile at {} finished loading", coords);
}
// FIXME: deduplicate
Message::UnavailableLayer(tranferred) => {
let layer: StoredLayer = tranferred.to_stored_layer();
tracing::debug!(
"Layer {} at {} reached main thread",
layer.layer_name(),
layer.get_coords()
);
tile_repository.put_tessellated_layer(layer);
}
Message::TessellatedLayer(data) => {
let layer: StoredLayer = data.to_stored_layer();
tracing::debug!(
"Layer {} at {} reached main thread",
layer.layer_name(),
layer.get_coords()
);
log::warn!(
"Layer {} at {} reached main thread",
layer.layer_name(),
layer.get_coords()
);
tile_repository.put_tessellated_layer(layer);
}
}
}

View File

@ -12,6 +12,7 @@ use std::{
str::FromStr,
};
use crate::kernel::Kernel;
use crate::{
context::MapContext,
coords::{ViewRegion, WorldTileCoords, ZoomLevel},
@ -33,19 +34,12 @@ use crate::{
};
pub struct RequestStage<E: Environment> {
apc: Rc<RefCell<E::AsyncProcedureCall>>,
http_source_client: HttpSourceClient<E::HttpClient>,
kernel: Rc<Kernel<E>>,
}
impl<E: Environment> RequestStage<E> {
pub fn new(
http_source_client: HttpSourceClient<E::HttpClient>,
apc: Rc<RefCell<E::AsyncProcedureCall>>,
) -> Self {
Self {
apc,
http_source_client,
}
pub fn new(kernel: Rc<Kernel<E>>) -> Self {
Self { kernel }
}
}
@ -75,7 +69,13 @@ impl<E: Environment> Stage for RequestStage<E> {
}
}
pub fn schedule<E: Environment, C: Context<E::Transferables, E::HttpClient>>(
pub fn schedule<
E: Environment,
C: Context<
<E::AsyncProcedureCall as AsyncProcedureCall<E::HttpClient>>::Transferables,
E::HttpClient,
>,
>(
input: Input,
context: C,
) -> AsyncProcedureFuture {
@ -106,12 +106,14 @@ pub fn schedule<E: Environment, C: Context<E::Transferables, E::HttpClient>>(
log::error!("{:?}", &e);
for to_load in &input.layers {
tracing::warn!("layer {} at {} unavailable", to_load, coords);
context.send(Message::UnavailableLayer(
<E::Transferables as Transferables>::UnavailableLayer::new(
context.send(
Message::UnavailableLayer(<<E::AsyncProcedureCall as AsyncProcedureCall<
E::HttpClient,
>>::Transferables as Transferables>::UnavailableLayer::new(
input.coords,
to_load.to_string(),
),
));
)),
);
}
}
}
@ -156,7 +158,7 @@ impl<E: Environment> RequestStage<E> {
tile_repository.create_tile(coords);
tracing::info!("new tile request: {}", &coords);
self.apc.deref().borrow().schedule(
self.kernel.apc.schedule(
Input::TileRequest(TileRequest {
coords,
layers: layers.clone(),
@ -164,7 +166,6 @@ impl<E: Environment> RequestStage<E> {
schedule::<
E,
<E::AsyncProcedureCall as AsyncProcedureCall<
E::Transferables,
E::HttpClient,
>>::Context,
>,

View File

@ -17,6 +17,11 @@ pub trait HeadedMapWindow: MapWindow {
type RawWindow: HasRawWindowHandle + HasRawDisplayHandle;
fn raw(&self) -> &Self::RawWindow;
// TODO: Can we avoid this?
fn request_redraw(&self);
fn id(&self) -> u64;
}
/// A configuration for a window which determines the corresponding implementation of a

View File

@ -1,4 +1,5 @@
use cgmath::{Angle, Point3};
use std::ops::{Deref, DerefMut};
use crate::{
coords::{LatLon, ViewRegion, WorldCoords, Zoom, ZoomLevel, TILE_SIZE},
@ -124,14 +125,23 @@ impl ViewState {
*self.zoom
}
pub fn camera_position(&self) -> Point3<f64> {
self.camera.position
}
pub fn did_zoom_change(&self) -> bool {
self.zoom.did_change(0.05)
}
pub fn update_zoom(&mut self, new_zoom: Zoom) {
*self.zoom = new_zoom;
log::info!("zoom: {}", new_zoom);
}
pub fn camera(&self) -> &Camera {
self.camera.deref()
}
pub fn camera_mut(&mut self) -> &mut Camera {
self.camera.deref_mut()
}
pub fn did_camera_change(&self) -> bool {
self.camera.did_change(0.05)
}
@ -140,9 +150,4 @@ impl ViewState {
self.camera.update_reference();
self.zoom.update_reference();
}
pub fn update_zoom(&mut self, new_zoom: Zoom) {
*self.zoom = new_zoom;
log::info!("zoom: {}", new_zoom);
}
}