1pub mod assets;
2pub mod config;
3mod error;
4pub mod math;
5mod renderer;
6mod scene;
7
8use {
9 crate::{
10 assets::{
11 DrawLight, DrawModel, DrawShadow, InstanceRaw, Model, ModelDesc, ModelStore,
12 ModelVertex, Vertex,
13 },
14 config::WindowSize,
15 renderer::{CameraRig, Material, ShadowRig, SkyRig},
16 scene::{Light, LightRig, WindRig},
17 },
18 std::sync::Arc,
19 wgpu::{
20 Adapter, BindGroupLayout, CommandEncoder, Device, PipelineLayout, Queue, RenderPass,
21 RenderPipeline, Surface, SurfaceCapabilities, SurfaceConfiguration, SurfaceTexture,
22 TextureFormat, TextureView,
23 },
24};
25pub use {
26 assets::{Ingot, Instance, TypeModel},
27 cgmath::{Deg, Matrix4, Point3, Quaternion, Rotation3, Vector3, ortho},
28 error::SurfaceError,
29 winit::{dpi::PhysicalSize, keyboard::KeyCode},
30};
31
32pub struct State {
33 pub window_surface: wgpu::Surface<'static>,
34 pub device: Arc<wgpu::Device>,
35 pub queue: Arc<wgpu::Queue>,
36 pub config: wgpu::SurfaceConfiguration,
37 pub is_surface_configuration: bool,
38 pub render_pipeline: wgpu::RenderPipeline,
39 pub texture_bind_group_layout: Arc<wgpu::BindGroupLayout>,
40 pub depth_texture: renderer::Texture,
41 pub last_render_time: web_time::Instant,
42 pub camera: CameraRig,
43 pub light: LightRig,
44 pub wind: WindRig,
45 pub shadow: ShadowRig,
46 pub sky: SkyRig,
47 pub(crate) models: ModelStore,
48}
49
50impl State {
51 pub async fn new(
52 target: impl raw_window_handle::HasWindowHandle
53 + raw_window_handle::HasDisplayHandle
54 + wgpu::WasmNotSendSync
55 + 'static,
56 window_size: WindowSize,
57 ) -> anyhow::Result<Self> {
58 let mut instance_desc: wgpu::InstanceDescriptor =
59 wgpu::InstanceDescriptor::new_without_display_handle();
60 #[cfg(target_arch = "wasm32")]
61 {
62 instance_desc.backends = wgpu::Backends::GL | wgpu::Backends::BROWSER_WEBGPU;
63 }
64 #[cfg(all(not(target_arch = "wasm32"), not(feature = "rpi")))]
65 {
66 instance_desc.backends = wgpu::Backends::PRIMARY;
67 }
68 #[cfg(all(not(target_arch = "wasm32"), feature = "rpi"))]
69 {
70 instance_desc.backends = wgpu::Backends::GL;
71 }
72 let backend_instance: wgpu::Instance = wgpu::Instance::new(instance_desc);
73
74 let window_surface: Surface = backend_instance.create_surface(target)?;
76
77 let adapter: Adapter = backend_instance
79 .request_adapter(&wgpu::RequestAdapterOptions {
80 power_preference: wgpu::PowerPreference::default(),
81 force_fallback_adapter: false,
82 compatible_surface: Some(&window_surface),
83 })
84 .await?;
85
86 let (device, queue) = adapter
88 .request_device(&wgpu::DeviceDescriptor {
89 label: None,
90 required_features: wgpu::Features::empty(),
93 required_limits: adapter.limits(),
98 experimental_features: wgpu::ExperimentalFeatures::disabled(),
99 memory_hints: Default::default(),
100 trace: wgpu::Trace::Off,
101 })
102 .await?;
103 let device: Arc<Device> = Arc::new(device);
104 let queue: Arc<Queue> = Arc::new(queue);
105
106 let surface_caps: SurfaceCapabilities = window_surface.get_capabilities(&adapter);
108
109 let surface_format: TextureFormat = surface_caps
111 .formats
112 .iter()
113 .find(|f| f.is_srgb())
114 .copied()
115 .unwrap_or(surface_caps.formats[0]);
116
117 let config: SurfaceConfiguration = wgpu::SurfaceConfiguration {
119 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
120 format: surface_format,
121 width: window_size.width,
122 height: window_size.height,
123 present_mode: surface_caps.present_modes[0],
124 desired_maximum_frame_latency: 2,
125 alpha_mode: surface_caps.alpha_modes[0],
126 view_formats: vec![surface_format.add_srgb_suffix()],
127 };
128
129 let texture_bind_group_layout: Arc<BindGroupLayout> =
132 Arc::new(Material::bind_group_layout(&device));
133
134 let camera: CameraRig = CameraRig::new(&device, config.width as f32 / config.height as f32);
135
136 let depth_texture: renderer::Texture =
137 renderer::Texture::create_depth_texture(&device, &config, "depth_texture");
138
139 let sky: SkyRig = SkyRig::new(&device, &queue, &config, &camera.layout).await?;
140
141 let light: LightRig = LightRig::new(
142 &device,
143 &camera.layout,
144 &texture_bind_group_layout,
145 sky.hdr.format(),
146 );
147
148 let shadow: ShadowRig = ShadowRig::new(&device, &light.layout);
149
150 let wind: WindRig = WindRig::new(&device);
151
152 let pipeline_render_layout: PipelineLayout =
154 device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
155 bind_group_layouts: &[
156 Some(&texture_bind_group_layout),
157 Some(&camera.layout),
158 Some(&light.layout),
159 Some(&shadow.layout),
160 Some(&wind.layout),
161 ],
162 label: Some("render_pipeline_layout"),
163 ..Default::default()
164 });
165
166 let render_pipeline: RenderPipeline = renderer::create_render_pipeline(
167 &device,
168 &pipeline_render_layout,
169 sky.hdr.format(),
170 Some(renderer::Texture::DEPTH_FORMAT),
171 &[ModelVertex::desc(), InstanceRaw::desc()],
172 wgpu::PrimitiveTopology::TriangleList,
173 wgpu::include_wgsl!("shaders/shaders.wgsl"),
174 wgpu::CompareFunction::Less,
175 );
176
177 Ok(Self {
178 window_surface,
179 device,
180 queue,
181 config,
182 is_surface_configuration: false,
183 render_pipeline,
184 texture_bind_group_layout,
185 depth_texture,
186 last_render_time: web_time::Instant::now(),
187 camera,
188 light,
189 wind,
190 shadow,
191 sky,
192 models: ModelStore::new(),
193 })
194 }
195
196 pub fn resize(&mut self, height: u32, width: u32) {
197 if height > 0 && width > 0 {
198 self.config.height = height;
199 self.config.width = width;
200
201 self.window_surface.configure(&self.device, &self.config);
202
203 self.camera
204 .set_aspect(self.config.width as f32 / self.config.height as f32);
205
206 self.depth_texture = renderer::Texture::create_depth_texture(
207 &self.device,
208 &self.config,
209 "depth_texture",
210 );
211
212 self.sky.hdr.resize(&self.device, width, height);
213 self.is_surface_configuration = true;
214 }
215 }
216
217 pub fn render(&mut self) -> Result<(), SurfaceError> {
218 self.render_with_overlay(&mut |_, _, _, _| {})
219 }
220
221 pub fn render_with_overlay(
222 &mut self,
223 overlay: &mut dyn FnMut(
224 &wgpu::Device,
225 &wgpu::Queue,
226 &mut wgpu::CommandEncoder,
227 &wgpu::TextureView,
228 ),
229 ) -> Result<(), SurfaceError> {
230 if !self.is_surface_configuration {
231 return Ok(());
232 }
233
234 let mut encoder: CommandEncoder =
235 self.device
236 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
237 label: Some("encoder"),
238 });
239
240 {
241 let mut shadow_render_pass: RenderPass =
242 encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
243 label: Some("Shadow_render_pass"),
244 color_attachments: &[],
245 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
246 view: &self.shadow.texture.view,
247 depth_ops: Some(wgpu::Operations {
248 load: wgpu::LoadOp::Clear(1.0),
249 store: wgpu::StoreOp::Store,
250 }),
251 stencil_ops: None,
252 }),
253 timestamp_writes: None,
254 occlusion_query_set: None,
255 multiview_mask: None,
256 });
257
258 shadow_render_pass.set_pipeline(&self.shadow.pipeline);
259 shadow_render_pass.set_bind_group(0, &self.light.bind_group, &[]);
260 for model in self.models.static_loaded() {
261 shadow_render_pass.draw_shadow_model(model, &self.light.bind_group);
262 }
263 }
264 {
265 let mut render_pass: RenderPass =
266 encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
267 label: Some("render_pass"),
268 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
269 view: self.sky.hdr.view(),
270 depth_slice: None,
271 resolve_target: None,
272 ops: wgpu::Operations {
273 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
274 store: wgpu::StoreOp::Store,
275 },
276 })],
277 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
278 view: &self.depth_texture.view,
279 depth_ops: Some(wgpu::Operations {
280 load: wgpu::LoadOp::Clear(1.0),
281 store: wgpu::StoreOp::Store,
282 }),
283 stencil_ops: None,
284 }),
285 timestamp_writes: None,
286 occlusion_query_set: None,
287 multiview_mask: None,
288 });
289
290 render_pass.set_pipeline(&self.light.pipeline);
291 for model in self.models.light_loaded() {
292 render_pass.draw_light_model(
293 model,
294 &self.camera.bind_group,
295 &self.light.bind_group,
296 );
297 }
298
299 render_pass.set_pipeline(&self.render_pipeline);
300 for model in self.models.static_loaded() {
301 render_pass.draw_model(
302 model,
303 &self.camera.bind_group,
304 &self.light.bind_group,
305 &self.shadow.bind_group,
306 &self.wind.bind_group,
307 );
308 }
309
310 render_pass.set_pipeline(&self.sky.pipeline);
313 render_pass.set_bind_group(0, &self.camera.bind_group, &[]);
314 render_pass.set_bind_group(1, &self.sky.bind_group, &[]);
315 render_pass.draw(0..3, 0..1);
316 }
317
318 let ouput: SurfaceTexture = match self.window_surface.get_current_texture() {
319 wgpu::CurrentSurfaceTexture::Success(t)
320 | wgpu::CurrentSurfaceTexture::Suboptimal(t) => t,
321 wgpu::CurrentSurfaceTexture::Timeout | wgpu::CurrentSurfaceTexture::Occluded => {
324 return Ok(());
325 }
326 wgpu::CurrentSurfaceTexture::Outdated => return Err(SurfaceError::Outdated),
327 wgpu::CurrentSurfaceTexture::Lost => return Err(SurfaceError::Lost),
328 wgpu::CurrentSurfaceTexture::Validation => return Err(SurfaceError::Validation),
329 };
330 let view: TextureView = ouput.texture.create_view(&wgpu::TextureViewDescriptor {
331 format: Some(self.config.format.add_srgb_suffix()),
332 ..Default::default()
333 });
334
335 self.sky.hdr.process(&mut encoder, &view);
336 overlay(&self.device, &self.queue, &mut encoder, &view);
337 self.queue.submit(std::iter::once(encoder.finish()));
338
339 ouput.present();
340
341 Ok(())
342 }
343
344 pub fn spawn_model(&mut self, model_desc: ModelDesc) -> Ingot<Model> {
345 self.models.spawn(
346 &self.device,
347 &self.queue,
348 &self.texture_bind_group_layout,
349 model_desc,
350 )
351 }
352
353 pub fn light_handle(&mut self) -> Light {
354 Light
355 }
356
357 pub fn set_wind(&mut self, direction: [f32; 2], intensity: f32) {
360 self.wind.set(direction, intensity);
361 }
362
363 pub fn evolbe(&mut self) {
366 self.models.collect_loaded();
367
368 let now: web_time::Instant = web_time::Instant::now();
369 let dt: web_time::Duration = now - self.last_render_time;
370 self.last_render_time = now;
371
372 self.camera.update(&self.queue, dt);
373 self.light.update(&self.queue);
374 self.wind.update(&self.queue);
375 }
376}