1use std::rc::Rc;
2
3use thiserror::Error;
4
5use crate::{
6 context::MapContext,
7 coords::{LatLon, WorldCoords, Zoom},
8 environment::Environment,
9 kernel::Kernel,
10 plugin::Plugin,
11 render::{
12 builder::{
13 InitializationResult, InitializedRenderer, RendererBuilder, UninitializedRenderer,
14 },
15 error::RenderError,
16 graph::RenderGraphError,
17 view_state::ViewState,
18 },
19 schedule::{Schedule, Stage, StageError},
20 style::Style,
21 tcs::world::World,
22 window::{HeadedMapWindow, MapWindow, MapWindowConfig, WindowCreateError},
23};
24
25#[derive(Error, Debug)]
26pub enum MapError {
27 #[error("renderer was already set for this map")]
29 RendererAlreadySet,
30 #[error("renderer is not fully initialized")]
31 RendererNotReady,
32 #[error("initializing render graph failed")]
33 RenderGraphInit(RenderGraphError),
34 #[error("initializing device failed")]
35 DeviceInit(RenderError),
36 #[error("creating window failed")]
37 Window(#[from] WindowCreateError),
38 #[error("executing stage must not error")]
39 StageError(#[from] StageError),
40}
41
42pub enum CurrentMapContext {
43 Ready(MapContext),
44 Pending {
45 style: Style,
46 renderer_builder: RendererBuilder,
47 },
48}
49
50pub struct Map<E: Environment> {
51 kernel: Rc<Kernel<E>>,
52 schedule: Schedule,
53 map_context: CurrentMapContext,
54 window: <E::MapWindowConfig as MapWindowConfig>::MapWindow,
55
56 plugins: Vec<Box<dyn Plugin<E>>>,
57}
58
59impl<E: Environment> Map<E>
60where
61 <<E as Environment>::MapWindowConfig as MapWindowConfig>::MapWindow: HeadedMapWindow,
62{
63 pub fn new(
64 style: Style,
65 kernel: Kernel<E>,
66 renderer_builder: RendererBuilder,
67 plugins: Vec<Box<dyn Plugin<E>>>,
68 ) -> Result<Self, MapError> {
69 let schedule = Schedule::default();
70
71 let window = kernel.map_window_config().create()?;
72
73 let kernel = Rc::new(kernel);
74
75 let map = Self {
76 kernel,
77 schedule,
78 map_context: CurrentMapContext::Pending {
79 style,
80 renderer_builder,
81 },
82 window,
83 plugins,
84 };
85 Ok(map)
86 }
87
88 pub async fn initialize_renderer(&mut self) -> Result<(), MapError> {
89 match &mut self.map_context {
90 CurrentMapContext::Ready(_) => Err(MapError::RendererAlreadySet),
91 CurrentMapContext::Pending {
92 style,
93 renderer_builder,
94 } => {
95 let init_result = renderer_builder
96 .clone() .build()
98 .initialize_renderer::<E::MapWindowConfig>(&self.window)
99 .await
100 .map_err(MapError::DeviceInit)?;
101
102 let window_size = self.window.size();
103
104 let center = style.center.unwrap_or_default();
105 let initial_zoom = style.zoom.map(Zoom::new).unwrap_or_default();
106 let view_state = ViewState::new(
107 window_size,
108 WorldCoords::from_lat_lon(LatLon::new(center[0], center[1]), initial_zoom),
109 initial_zoom,
110 cgmath::Deg::<f64>(style.pitch.unwrap_or_default()),
111 cgmath::Rad(0.6435011087932844),
112 );
113
114 let mut world = World::default();
115
116 match init_result {
117 InitializationResult::Initialized(InitializedRenderer {
118 mut renderer, ..
119 }) => {
120 for plugin in &self.plugins {
121 plugin.build(
122 &mut self.schedule,
123 self.kernel.clone(),
124 &mut world,
125 &mut renderer.render_graph,
126 );
127 }
128
129 self.map_context = CurrentMapContext::Ready(MapContext {
130 world,
131 view_state,
132 style: std::mem::take(style),
133 renderer,
134 });
135 }
136 InitializationResult::Uninitialized(UninitializedRenderer { .. }) => {}
137 _ => panic!("Rendering context gone"),
138 };
139 Ok(())
140 }
141 }
142 }
143
144 pub fn window_mut(&mut self) -> &mut <E::MapWindowConfig as MapWindowConfig>::MapWindow {
145 &mut self.window
146 }
147 pub fn window(&self) -> &<E::MapWindowConfig as MapWindowConfig>::MapWindow {
148 &self.window
149 }
150
151 pub fn is_initialized(&self) -> bool {
152 match &self.map_context {
153 CurrentMapContext::Ready(_) => true,
154 CurrentMapContext::Pending { .. } => false,
155 }
156 }
157
158 pub fn reset(&mut self) {
161 self.schedule.clear();
162 match &self.map_context {
163 CurrentMapContext::Ready(c) => {
164 self.map_context = CurrentMapContext::Pending {
165 style: c.style.clone(),
166 renderer_builder: RendererBuilder::new()
167 .with_renderer_settings(c.renderer.settings.clone())
168 .with_wgpu_settings(c.renderer.wgpu_settings.clone()),
169 }
170 }
171 CurrentMapContext::Pending { .. } => {}
172 }
173 }
174
175 #[tracing::instrument(name = "update_and_redraw", skip_all)]
176 pub fn run_schedule(&mut self) -> Result<(), MapError> {
177 match &mut self.map_context {
178 CurrentMapContext::Ready(map_context) => {
179 self.schedule.run(map_context)?;
180 Ok(())
181 }
182 CurrentMapContext::Pending { .. } => Err(MapError::RendererNotReady),
183 }
184 }
185
186 pub fn context(&self) -> Result<&MapContext, MapError> {
187 match &self.map_context {
188 CurrentMapContext::Ready(map_context) => Ok(map_context),
189 CurrentMapContext::Pending { .. } => Err(MapError::RendererNotReady),
190 }
191 }
192
193 pub fn context_mut(&mut self) -> Result<&mut MapContext, MapError> {
194 match &mut self.map_context {
195 CurrentMapContext::Ready(map_context) => Ok(map_context),
196 CurrentMapContext::Pending { .. } => Err(MapError::RendererNotReady),
197 }
198 }
199
200 pub fn kernel(&self) -> &Rc<Kernel<E>> {
201 &self.kernel
202 }
203}