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 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),
}
impl<E> From<E> for Error
where
E: Into<RenderError>,
{
fn from(e: E) -> Self {
Error::Render(e.into())
}
}
impl From<TessellationError> for Error {
fn from(e: TessellationError) -> Self {
Error::Tesselation(e)

View File

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

View File

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

View File

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

View File

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

View File

@ -1,47 +1,50 @@
/// The [`Map`] defines the public interface of the map renderer.
// DO NOT IMPLEMENT INTERNALS ON THIS STRUCT.
use crate::context::MapContext;
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> {
// FIXME (wasm-executor): Avoid RefCell, change ownership model!
map_schedule: Rc<RefCell<InteractiveMapSchedule<E>>>,
window: RefCell<Option<<E::MapWindowConfig as MapWindowConfig>::MapWindow>>,
kernel: Kernel<E>,
schedule: Schedule,
map_context: MapContext,
}
impl<E: Environment> Map<E>
where
<E::MapWindowConfig as MapWindowConfig>::MapWindow: EventLoop<E>,
{
/// Starts the [`crate::map_schedule::MapState`] Runnable with the configured event loop.
pub fn run(&self) {
self.run_with_optionally_max_frames(None);
impl<E: Environment> Map<E> {
pub fn new(style: Style, kernel: Kernel<E>, renderer: Renderer) -> Result<Self, Error> {
let window_size = renderer.state().surface().size();
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 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.
///
/// # Arguments
///
/// * `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));
#[tracing::instrument(name = "update_and_redraw", skip_all)]
pub fn run_schedule(&mut self) -> Result<(), Error> {
self.schedule.run(&mut self.map_context);
Ok(())
}
/// 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,198 +1,26 @@
use std::{cell::RefCell, marker::PhantomData, mem, rc::Rc};
/* pub fn resume(&mut self, window: &<E::MapWindowConfig as MapWindowConfig>::MapWindow) {
if let EventuallyMapContext::Full(map_context) = &mut self.map_context {
let renderer = &mut map_context.renderer;
renderer.state.recreate_surface(window, &renderer.instance);
}
}*/
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,
/* pub async fn late_init(&mut self) -> bool {
match &self.map_context {
EventuallyMapContext::Full(_) => false,
EventuallyMapContext::Uninizalized(PrematureMapContext {
wgpu_settings,
renderer_settings,
..
}) => {
let window = self.map_window_config.create();
let renderer =
Renderer::initialize(&window, wgpu_settings.clone(), renderer_settings.clone())
.await
.unwrap(); // TODO: Remove unwrap
self.map_context.make_full(renderer);
true
}
EventuallyMapContext::_Uninitialized => 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 {
let renderer = &mut map_context.renderer;
renderer.state.recreate_surface(window, &renderer.instance);
self.suspended = false;
}
}
pub async fn late_init(&mut self) -> bool {
match &self.map_context {
EventuallyMapContext::Full(_) => false,
EventuallyMapContext::Premature(PrematureMapContext {
wgpu_settings,
renderer_settings,
..
}) => {
let window = self.map_window_config.create();
let renderer =
Renderer::initialize(&window, wgpu_settings.clone(), renderer_settings.clone())
.await
.unwrap(); // TODO: Remove unwrap
self.map_context.make_full(renderer);
true
}
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::{
environment::Environment,
render::{
@ -14,6 +16,13 @@ pub struct 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 {
self.renderer_settings = Some(renderer_settings);
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 {
wgpu_settings: WgpuSettings,
renderer_settings: RendererSettings,
@ -40,41 +63,64 @@ pub struct UninitializedRenderer {
impl UninitializedRenderer {
/// Initializes the whole rendering pipeline for the given configuration.
/// 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
MWC::MapWindow: MapWindow + HeadedMapWindow,
{
let window = map_window_config.create();
#[cfg(target_os = "android")]
let renderer = None;
let renderer = Ok(InitializationResult::Uninizalized(self));
#[cfg(not(target_os = "android"))]
let renderer = Renderer::initialize(
&window,
self.wgpu_settings.clone(),
self.renderer_settings.clone(),
)
.await
.ok();
let renderer = Ok(InitializationResult::Initialized(
Renderer::initialize(
&window,
self.wgpu_settings.clone(),
self.renderer_settings.clone(),
)
.await?,
));
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")]
impl UninitializedRenderer {
pub async fn initialize_headless<MWC: MapWindowConfig>(
async fn initialize_headless<MWC: MapWindowConfig>(
self,
map_window_config: MWC,
) -> Option<Renderer> {
) -> Result<Renderer, Error> {
let window = map_window_config.create();
Renderer::initialize_headless(
Ok(Renderer::initialize_headless(
&window,
self.wgpu_settings.clone(),
self.renderer_settings.clone(),
)
.await
.ok()
.await?)
}
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 {
Surface(wgpu::SurfaceError),
Graph(RenderGraphError),
Device(wgpu::RequestDeviceError),
}
impl fmt::Display for RenderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
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 {
fn from(e: wgpu::SurfaceError) -> Self {
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
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 {
&self.surface
@ -140,7 +140,7 @@ impl Surface {
present_mode: wgpu::PresentMode::Fifo, // VSync
};
let surface = unsafe { instance.create_surface(window.inner()) };
let surface = unsafe { instance.create_surface(window.raw()) };
Self {
size,

View File

@ -4,7 +4,7 @@ use std::{cell::RefCell, rc::Rc};
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.
pub trait MapWindow {
@ -16,7 +16,7 @@ pub trait MapWindow {
pub trait HeadedMapWindow: MapWindow {
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
@ -27,13 +27,6 @@ pub trait MapWindowConfig: 'static {
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.
#[derive(Clone, Copy, Eq, PartialEq)]
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> {
self.camera
.view_region_bounding_box(&self.view_projection().invert())