Fix compilation issues and cleanup

This commit is contained in:
Maximilian Ammann 2022-09-25 16:25:00 +02:00
parent 4879d9c0b4
commit c6eadbf2cc
13 changed files with 189 additions and 275 deletions

View File

@ -6,3 +6,10 @@ pub struct MapContext {
pub world: World, pub world: World,
pub renderer: Renderer, pub renderer: Renderer,
} }
impl MapContext {
pub fn resize(&mut self, width: u32, height: u32) {
self.world.view_state.resize(width, height);
self.renderer.resize(width, height)
}
}

View File

@ -15,6 +15,15 @@ pub enum Error {
Render(RenderError), Render(RenderError),
} }
impl<E> From<E> for Error
where
E: Into<RenderError>,
{
fn from(e: E) -> Self {
Error::Render(e.into())
}
}
impl From<TessellationError> for Error { impl From<TessellationError> for Error {
fn from(e: TessellationError) -> Self { fn from(e: TessellationError) -> Self {
Error::Tesselation(e) Error::Tesselation(e)

View File

@ -1,4 +1,5 @@
use crate::io::pipeline::Processable; use crate::io::pipeline::Processable;
use crate::render::builder::UninitializedRenderer;
use crate::{ use crate::{
context::MapContext, context::MapContext,
coords::{WorldCoords, WorldTileCoords, Zoom, TILE_SIZE}, coords::{WorldCoords, WorldTileCoords, Zoom, TILE_SIZE},
@ -28,19 +29,19 @@ use crate::{
use std::collections::HashSet; use std::collections::HashSet;
pub struct HeadlessMap { pub struct HeadlessMap {
window_size: WindowSize,
kernel: Kernel<HeadlessEnvironment>, kernel: Kernel<HeadlessEnvironment>,
map_context: MapContext,
schedule: Schedule, schedule: Schedule,
map_context: MapContext,
} }
impl HeadlessMap { impl HeadlessMap {
pub fn new( pub fn new(
style: Style, style: Style,
window_size: WindowSize,
renderer: Renderer, renderer: Renderer,
kernel: Kernel<HeadlessEnvironment>, kernel: Kernel<HeadlessEnvironment>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let window_size = renderer.state().surface().size();
let world = World::new( let world = World::new(
window_size, window_size,
WorldCoords::from((TILE_SIZE / 2., TILE_SIZE / 2.)), WorldCoords::from((TILE_SIZE / 2., TILE_SIZE / 2.)),
@ -67,7 +68,6 @@ impl HeadlessMap {
); );
Ok(Self { Ok(Self {
window_size,
kernel, kernel,
map_context: MapContext { map_context: MapContext {
style, style,
@ -94,7 +94,7 @@ impl HeadlessMap {
pub async fn fetch_tile( pub async fn fetch_tile(
&self, &self,
coords: WorldTileCoords, coords: WorldTileCoords,
source_layers: HashSet<String>, source_layers: &[&str],
) -> Result<StoredTile, Error> { ) -> Result<StoredTile, Error> {
let source_client = &self.kernel.source_client; let source_client = &self.kernel.source_client;
@ -107,7 +107,10 @@ impl HeadlessMap {
( (
TileRequest { TileRequest {
coords: WorldTileCoords::default(), coords: WorldTileCoords::default(),
layers: source_layers, layers: source_layers
.iter()
.map(|layer| layer.to_string())
.collect::<HashSet<String>>(),
}, },
data, data,
), ),

View File

@ -1,6 +1,6 @@
mod environment;
mod graph_node; mod graph_node;
mod stage; mod stage;
mod window;
pub mod environment;
pub mod map; pub mod map;
pub mod window;

View File

@ -1,7 +1,13 @@
use crate::window::{MapWindow, MapWindowConfig, WindowSize}; use crate::window::{MapWindow, MapWindowConfig, WindowSize};
pub struct HeadlessMapWindowConfig { pub struct HeadlessMapWindowConfig {
pub size: WindowSize, size: WindowSize,
}
impl HeadlessMapWindowConfig {
pub fn new(size: WindowSize) -> Self {
Self { size }
}
} }
impl MapWindowConfig for HeadlessMapWindowConfig { impl MapWindowConfig for HeadlessMapWindowConfig {

View File

@ -16,14 +16,15 @@
//! maplibre = "0.0.2" //! maplibre = "0.0.2"
//! ``` //! ```
// Internal modules
pub(crate) mod tessellation;
pub mod context; pub mod context;
pub mod coords; pub mod coords;
pub mod error; pub mod error;
#[cfg(feature = "headless")] #[cfg(feature = "headless")]
pub mod headless; pub mod headless;
pub mod io; pub mod io;
// Exposed because of input handlers in maplibre-winit
pub mod map_schedule;
pub mod platform; pub mod platform;
// TODO: Exposed because of camera // TODO: Exposed because of camera
pub mod render; pub mod render;
@ -41,9 +42,8 @@ pub mod environment;
// Used for benchmarking // Used for benchmarking
pub mod benchmarking; pub mod benchmarking;
// Internal modules pub mod map;
pub(crate) mod tessellation; pub mod world;
mod world;
// Export tile format // Export tile format
pub use geozero::mvt::tile; pub use geozero::mvt::tile;

View File

@ -1,47 +1,50 @@
/// The [`Map`] defines the public interface of the map renderer. use crate::context::MapContext;
// DO NOT IMPLEMENT INTERNALS ON THIS STRUCT. use crate::coords::{LatLon, WorldCoords, Zoom, TILE_SIZE};
use crate::environment::{Environment, Kernel};
use crate::error::Error;
use crate::headless::environment::HeadlessEnvironment;
use crate::render::{create_default_render_graph, register_default_render_stages, Renderer};
use crate::schedule::{Schedule, Stage};
use crate::style::Style;
use crate::world::World;
pub struct Map<E: Environment> { pub struct Map<E: Environment> {
// FIXME (wasm-executor): Avoid RefCell, change ownership model! kernel: Kernel<E>,
map_schedule: Rc<RefCell<InteractiveMapSchedule<E>>>, schedule: Schedule,
window: RefCell<Option<<E::MapWindowConfig as MapWindowConfig>::MapWindow>>, map_context: MapContext,
} }
impl<E: Environment> Map<E> impl<E: Environment> Map<E> {
where pub fn new(style: Style, kernel: Kernel<E>, renderer: Renderer) -> Result<Self, Error> {
<E::MapWindowConfig as MapWindowConfig>::MapWindow: EventLoop<E>, let window_size = renderer.state().surface().size();
{
/// Starts the [`crate::map_schedule::MapState`] Runnable with the configured event loop. let center = style.center.unwrap_or_default();
pub fn run(&self) { let world = World::new_at(
self.run_with_optionally_max_frames(None); window_size,
LatLon::new(center[0], center[1]),
style.zoom.map(|zoom| Zoom::new(zoom)).unwrap_or_default(),
cgmath::Deg::<f64>(style.pitch.unwrap_or_default()),
);
let mut schedule = Schedule::default();
let graph = create_default_render_graph().unwrap(); // TODO: Remove unwrap
register_default_render_stages(graph, &mut schedule);
Ok(Self {
kernel,
map_context: MapContext {
style,
world,
renderer,
},
schedule,
})
} }
/// Starts the [`crate::map_schedule::MapState`] Runnable with the configured event loop. #[tracing::instrument(name = "update_and_redraw", skip_all)]
/// pub fn run_schedule(&mut self) -> Result<(), Error> {
/// # Arguments self.schedule.run(&mut self.map_context);
/// Ok(())
/// * `max_frames` - Maximum number of frames per second.
pub fn run_with_max_frames(&self, max_frames: u64) {
self.run_with_optionally_max_frames(Some(max_frames));
} }
/// Starts the MapState Runnable with the configured event loop.
///
/// # Arguments
///
/// * `max_frames` - Optional maximum number of frames per second.
pub fn run_with_optionally_max_frames(&self, max_frames: Option<u64>) {
self.window
.borrow_mut()
.take()
.unwrap() // FIXME (wasm-executor): Remove unwrap
.run(self.map_schedule.clone(), max_frames);
}
pub fn map_schedule(&self) -> Rc<RefCell<InteractiveMapSchedule<E>>> {
self.map_schedule.clone()
}
/* pub fn map_schedule_mut(&mut self) -> &mut InteractiveMapSchedule<E> {
&mut self.map_schedule
}*/
} }

View File

@ -1,146 +1,14 @@
use std::{cell::RefCell, marker::PhantomData, mem, rc::Rc}; /* pub fn resume(&mut self, window: &<E::MapWindowConfig as MapWindowConfig>::MapWindow) {
use crate::{
context::MapContext,
coords::{LatLon, WorldCoords, Zoom, TILE_SIZE},
environment::Environment,
error::Error,
io::{
scheduler::Scheduler,
source_client::{HttpClient, HttpSourceClient},
tile_repository::TileRepository,
},
render::{
create_default_render_graph, register_default_render_stages,
settings::{RendererSettings, WgpuSettings},
Renderer,
},
schedule::{Schedule, Stage},
stages::register_stages,
style::Style,
window::{HeadedMapWindow, MapWindowConfig, WindowSize},
world::{ViewState, World},
};
/// Stores the state of the map, dispatches tile fetching and caching, tessellation and drawing.
pub struct InteractiveMapSchedule<E: Environment> {
map_window_config: E::MapWindowConfig,
// FIXME (wasm-executor): avoid RefCell, change ownership model
pub apc: Rc<RefCell<E::AsyncProcedureCall>>,
map_context: EventuallyMapContext,
schedule: Schedule,
suspended: bool,
}
impl<E: Environment> InteractiveMapSchedule<E> {
pub fn new(window_size: WindowSize, renderer: Option<Renderer>, style: Style) -> Self {
let center = style.center.unwrap_or_default();
let world = World::new_at(
window_size,
LatLon::new(center[0], center[1]),
style.zoom.map(|zoom| Zoom::new(zoom)).unwrap_or_default(),
cgmath::Deg::<f64>(style.pitch.unwrap_or_default()),
);
let mut schedule = Schedule::default();
let apc = Rc::new(RefCell::new(apc));
let http_source_client: HttpSourceClient<E::HttpClient> =
HttpSourceClient::new(http_client);
register_stages::<E>(&mut schedule, http_source_client, apc.clone());
let graph = create_default_render_graph().unwrap(); // TODO: Remove unwrap
register_default_render_stages(graph, &mut schedule);
Self {
apc,
map_window_config,
map_context: match renderer {
None => EventuallyMapContext::Premature(PrematureMapContext {
world,
style,
wgpu_settings,
renderer_settings,
}),
Some(renderer) => EventuallyMapContext::Full(MapContext {
world,
style,
renderer,
}),
},
schedule,
suspended: false,
}
}
#[tracing::instrument(name = "update_and_redraw", skip_all)]
pub fn update_and_redraw(&mut self) -> Result<(), Error> {
if self.suspended {
return Ok(());
}
if let EventuallyMapContext::Full(map_context) = &mut self.map_context {
self.schedule.run(map_context)
}
Ok(())
}
pub fn resize(&mut self, width: u32, height: u32) {
if let EventuallyMapContext::Full(map_context) = &mut self.map_context {
let view_state = &mut map_context.view_state;
view_state.perspective.resize(width, height);
view_state.camera.resize(width, height);
map_context.renderer.resize(width, height)
}
}
pub fn is_initialized(&self) -> bool {
match &self.map_context {
EventuallyMapContext::Full(_) => true,
_ => false,
}
}
pub fn view_state_mut(&mut self) -> &mut ViewState {
match &mut self.map_context {
EventuallyMapContext::Full(MapContext { view_state, .. }) => view_state,
EventuallyMapContext::Premature(PrematureMapContext { view_state, .. }) => view_state,
_ => panic!("should not happen"),
}
}
pub fn apc(&self) -> &Rc<RefCell<E::AsyncProcedureCall>> {
&self.apc
}
}
impl<E: Environment> InteractiveMapSchedule<E>
where
<E::MapWindowConfig as MapWindowConfig>::MapWindow: HeadedMapWindow,
{
pub fn suspend(&mut self) {
self.suspended = true;
}
pub fn resume(&mut self, window: &<E::MapWindowConfig as MapWindowConfig>::MapWindow) {
if let EventuallyMapContext::Full(map_context) = &mut self.map_context { if let EventuallyMapContext::Full(map_context) = &mut self.map_context {
let renderer = &mut map_context.renderer; let renderer = &mut map_context.renderer;
renderer.state.recreate_surface(window, &renderer.instance); renderer.state.recreate_surface(window, &renderer.instance);
self.suspended = false;
}
} }
}*/
pub async fn late_init(&mut self) -> bool { /* pub async fn late_init(&mut self) -> bool {
match &self.map_context { match &self.map_context {
EventuallyMapContext::Full(_) => false, EventuallyMapContext::Full(_) => false,
EventuallyMapContext::Premature(PrematureMapContext { EventuallyMapContext::Uninizalized(PrematureMapContext {
wgpu_settings, wgpu_settings,
renderer_settings, renderer_settings,
.. ..
@ -155,44 +23,4 @@ where
} }
EventuallyMapContext::_Uninitialized => false, EventuallyMapContext::_Uninitialized => false,
} }
} }*/
}
pub struct PrematureMapContext {
world: World,
style: Style,
wgpu_settings: WgpuSettings,
renderer_settings: RendererSettings,
}
pub enum EventuallyMapContext {
Full(MapContext),
Premature(PrematureMapContext),
_Uninitialized,
}
impl EventuallyMapContext {
pub fn make_full(&mut self, renderer: Renderer) {
let context = mem::replace(self, EventuallyMapContext::_Uninitialized);
match context {
EventuallyMapContext::Full(_) => {}
EventuallyMapContext::Premature(PrematureMapContext {
view_state,
style,
tile_repository,
..
}) => {
*self = EventuallyMapContext::Full(MapContext {
view_state,
style,
tile_repository,
renderer,
});
}
EventuallyMapContext::_Uninitialized => {}
}
}
}

View File

@ -1,3 +1,5 @@
use crate::environment::Kernel;
use crate::error::Error;
use crate::{ use crate::{
environment::Environment, environment::Environment,
render::{ render::{
@ -14,6 +16,13 @@ pub struct RenderBuilder {
} }
impl RenderBuilder { impl RenderBuilder {
pub fn new() -> Self {
Self {
wgpu_settings: None,
renderer_settings: None,
}
}
pub fn with_renderer_settings(mut self, renderer_settings: RendererSettings) -> Self { pub fn with_renderer_settings(mut self, renderer_settings: RendererSettings) -> Self {
self.renderer_settings = Some(renderer_settings); self.renderer_settings = Some(renderer_settings);
self self
@ -32,6 +41,20 @@ impl RenderBuilder {
} }
} }
pub enum InitializationResult {
Initialized(Renderer),
Uninizalized(UninitializedRenderer),
}
impl InitializationResult {
pub fn unwarp(self) -> Renderer {
match self {
InitializationResult::Initialized(renderer) => renderer,
InitializationResult::Uninizalized(_) => panic!("Renderer is not initialized"),
}
}
}
pub struct UninitializedRenderer { pub struct UninitializedRenderer {
wgpu_settings: WgpuSettings, wgpu_settings: WgpuSettings,
renderer_settings: RendererSettings, renderer_settings: RendererSettings,
@ -40,41 +63,64 @@ pub struct UninitializedRenderer {
impl UninitializedRenderer { impl UninitializedRenderer {
/// Initializes the whole rendering pipeline for the given configuration. /// Initializes the whole rendering pipeline for the given configuration.
/// Returns the initialized map, ready to be run. /// Returns the initialized map, ready to be run.
pub async fn initialize<MWC: MapWindowConfig>(self, map_window_config: MWC) -> Option<Renderer> async fn initialize<MWC: MapWindowConfig>(
self,
map_window_config: &MWC,
) -> Result<InitializationResult, Error>
where where
MWC::MapWindow: MapWindow + HeadedMapWindow, MWC::MapWindow: MapWindow + HeadedMapWindow,
{ {
let window = map_window_config.create(); let window = map_window_config.create();
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
let renderer = None; let renderer = Ok(InitializationResult::Uninizalized(self));
#[cfg(not(target_os = "android"))] #[cfg(not(target_os = "android"))]
let renderer = Renderer::initialize( let renderer = Ok(InitializationResult::Initialized(
Renderer::initialize(
&window, &window,
self.wgpu_settings.clone(), self.wgpu_settings.clone(),
self.renderer_settings.clone(), self.renderer_settings.clone(),
) )
.await .await?,
.ok(); ));
renderer renderer
} }
pub async fn initialize_with<E: Environment>(
self,
kernel: &Kernel<E>,
) -> Result<InitializationResult, Error>
where
<E::MapWindowConfig as MapWindowConfig>::MapWindow: MapWindow + HeadedMapWindow,
{
self.initialize(&kernel.map_window_config).await
}
} }
#[cfg(feature = "headless")] #[cfg(feature = "headless")]
impl UninitializedRenderer { impl UninitializedRenderer {
pub async fn initialize_headless<MWC: MapWindowConfig>( async fn initialize_headless<MWC: MapWindowConfig>(
self, self,
map_window_config: MWC, map_window_config: MWC,
) -> Option<Renderer> { ) -> Result<Renderer, Error> {
let window = map_window_config.create(); let window = map_window_config.create();
Renderer::initialize_headless( Ok(Renderer::initialize_headless(
&window, &window,
self.wgpu_settings.clone(), self.wgpu_settings.clone(),
self.renderer_settings.clone(), self.renderer_settings.clone(),
) )
.await .await?)
.ok() }
pub async fn initialize_headless_with<E: Environment>(
self,
kernel: &Kernel<E>,
) -> Result<InitializationResult, Error>
where
<E::MapWindowConfig as MapWindowConfig>::MapWindow: MapWindow + HeadedMapWindow,
{
self.initialize(&kernel.map_window_config).await
} }
} }

View File

@ -6,13 +6,15 @@ use crate::{error::Error, render::graph::RenderGraphError};
pub enum RenderError { pub enum RenderError {
Surface(wgpu::SurfaceError), Surface(wgpu::SurfaceError),
Graph(RenderGraphError), Graph(RenderGraphError),
Device(wgpu::RequestDeviceError),
} }
impl fmt::Display for RenderError { impl fmt::Display for RenderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
RenderError::Surface(e) => write!(f, "{}", e), RenderError::Surface(e) => write!(f, "{}", e),
RenderError::Graph(e) => write!(f, "{}", e), RenderError::Graph(e) => write!(f, "{:?}", e),
RenderError::Device(e) => write!(f, "{}", e),
} }
} }
} }
@ -29,8 +31,20 @@ impl RenderError {
} }
} }
impl From<RenderGraphError> for RenderError {
fn from(e: RenderGraphError) -> Self {
RenderError::Graph(e)
}
}
impl From<wgpu::SurfaceError> for Error { impl From<wgpu::SurfaceError> for Error {
fn from(e: wgpu::SurfaceError) -> Self { fn from(e: wgpu::SurfaceError) -> Self {
Error::Render(RenderError::Surface(e)) Error::Render(RenderError::Surface(e))
} }
} }
impl From<wgpu::RequestDeviceError> for Error {
fn from(e: wgpu::RequestDeviceError) -> Self {
Error::Render(RenderError::Device(e))
}
}

View File

@ -50,7 +50,7 @@ impl WindowHead {
where where
MW: MapWindow + HeadedMapWindow, MW: MapWindow + HeadedMapWindow,
{ {
self.surface = unsafe { instance.create_surface(window.inner()) }; self.surface = unsafe { instance.create_surface(window.raw()) };
} }
pub fn surface(&self) -> &wgpu::Surface { pub fn surface(&self) -> &wgpu::Surface {
&self.surface &self.surface
@ -140,7 +140,7 @@ impl Surface {
present_mode: wgpu::PresentMode::Fifo, // VSync present_mode: wgpu::PresentMode::Fifo, // VSync
}; };
let surface = unsafe { instance.create_surface(window.inner()) }; let surface = unsafe { instance.create_surface(window.raw()) };
Self { Self {
size, size,

View File

@ -4,7 +4,7 @@ use std::{cell::RefCell, rc::Rc};
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
use crate::{environment::Environment, map_schedule::InteractiveMapSchedule}; use crate::environment::Environment;
/// Window of a certain [`WindowSize`]. This can either be a proper window or a headless one. /// Window of a certain [`WindowSize`]. This can either be a proper window or a headless one.
pub trait MapWindow { pub trait MapWindow {
@ -16,7 +16,7 @@ pub trait MapWindow {
pub trait HeadedMapWindow: MapWindow { pub trait HeadedMapWindow: MapWindow {
type RawWindow: HasRawWindowHandle + HasRawDisplayHandle; type RawWindow: HasRawWindowHandle + HasRawDisplayHandle;
fn inner(&self) -> &Self::RawWindow; fn raw(&self) -> &Self::RawWindow;
} }
/// A configuration for a window which determines the corresponding implementation of a /// A configuration for a window which determines the corresponding implementation of a
@ -27,13 +27,6 @@ pub trait MapWindowConfig: 'static {
fn create(&self) -> Self::MapWindow; fn create(&self) -> Self::MapWindow;
} }
/// The event loop is responsible for processing events and propagating them to the map renderer.
/// Only non-headless windows use an [`EventLoop`].
pub trait EventLoop<E: Environment> {
// FIXME (wasm-executor): Avoid Rc, change ownership model
fn run(self, map_schedule: Rc<RefCell<InteractiveMapSchedule<E>>>, max_frames: Option<u64>);
}
/// Window size with a width and an height in pixels. /// Window size with a width and an height in pixels.
#[derive(Clone, Copy, Eq, PartialEq)] #[derive(Clone, Copy, Eq, PartialEq)]
pub struct WindowSize { pub struct WindowSize {

View File

@ -99,6 +99,11 @@ impl ViewState {
} }
} }
pub fn resize(&mut self, width: u32, height: u32) {
self.perspective.resize(width, height);
self.camera.resize(width, height);
}
pub fn create_view_region(&self) -> Option<ViewRegion> { pub fn create_view_region(&self) -> Option<ViewRegion> {
self.camera self.camera
.view_region_bounding_box(&self.view_projection().invert()) .view_region_bounding_box(&self.view_projection().invert())