1use super::super::{
2 ExperimentalShader, GlobalsLayouts, PipelineModes, Renderer, Texture, Vertex as VertexTrait,
3};
4use bytemuck::{Pod, Zeroable};
5use std::mem;
6use vek::*;
7
8#[repr(C)]
9#[derive(Copy, Clone, Debug, Zeroable, Pod)]
10pub struct Vertex {
11 pos: [f32; 2],
12}
13
14impl Vertex {
15 pub fn new(pos: Vec2<f32>) -> Self {
16 Self {
17 pos: pos.into_array(),
18 }
19 }
20
21 fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
22 const ATTRIBUTES: [wgpu::VertexAttribute; 1] = wgpu::vertex_attr_array![0 => Float32x2];
23 wgpu::VertexBufferLayout {
24 array_stride: Self::STRIDE,
25 step_mode: wgpu::VertexStepMode::Vertex,
26 attributes: &ATTRIBUTES,
27 }
28 }
29}
30
31impl VertexTrait for Vertex {
32 const QUADS_INDEX: Option<wgpu::IndexFormat> = Some(wgpu::IndexFormat::Uint32);
33 const STRIDE: wgpu::BufferAddress = mem::size_of::<Self>() as wgpu::BufferAddress;
34}
35
36pub struct LodData {
37 pub map: Texture,
38 pub alt: Texture,
39 pub horizon: Texture,
40 pub tgt_detail: u32,
41 pub weather: Texture,
42}
43
44impl LodData {
45 pub fn dummy(renderer: &mut Renderer) -> Self {
46 let map_size = Vec2::new(1, 1);
47 let map_image = [0];
49 let alt_image = [0];
50 let horizon_image = [0x_00_01_00_01];
51
52 Self::new(
53 renderer,
54 map_size,
55 &map_image,
56 &alt_image,
57 &horizon_image,
58 Vec2::new(1, 1),
59 1,
60 )
62 }
63
64 pub fn new(
65 renderer: &mut Renderer,
66 map_size: Vec2<u32>,
67 lod_base: &[u32],
68 lod_alt: &[u32],
69 lod_horizon: &[u32],
70 weather_size: Vec2<u32>,
71 tgt_detail: u32,
72 ) -> Self {
74 let mut create_texture = |format, data, filter| {
75 let texture_info = wgpu::TextureDescriptor {
76 label: None,
77 size: wgpu::Extent3d {
78 width: map_size.x,
79 height: map_size.y,
80 depth_or_array_layers: 1,
81 },
82 mip_level_count: 1,
83 sample_count: 1,
84 dimension: wgpu::TextureDimension::D2,
85 format,
86 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
87 view_formats: &[],
88 };
89
90 let sampler_info = wgpu::SamplerDescriptor {
91 label: None,
92 address_mode_u: wgpu::AddressMode::ClampToEdge,
93 address_mode_v: wgpu::AddressMode::ClampToEdge,
94 address_mode_w: wgpu::AddressMode::ClampToEdge,
95 mag_filter: filter,
96 min_filter: filter,
97 mipmap_filter: wgpu::FilterMode::Nearest,
98 border_color: Some(wgpu::SamplerBorderColor::TransparentBlack),
99 ..Default::default()
100 };
101
102 let view_info = wgpu::TextureViewDescriptor {
103 label: None,
104 format: Some(format),
105 dimension: Some(wgpu::TextureViewDimension::D2),
106 usage: None,
107 aspect: wgpu::TextureAspect::All,
108 base_mip_level: 0,
109 mip_level_count: None,
110 base_array_layer: 0,
111 array_layer_count: None,
112 };
113
114 renderer.create_texture_with_data_raw(
115 &texture_info,
116 &view_info,
117 &sampler_info,
118 bytemuck::cast_slice(data),
119 )
120 };
121 let map = create_texture(
122 wgpu::TextureFormat::Rgba8UnormSrgb,
123 lod_base,
124 wgpu::FilterMode::Linear,
125 );
126 let alt = create_texture(
129 wgpu::TextureFormat::Rgba8Unorm,
130 lod_alt,
131 wgpu::FilterMode::Linear,
132 );
133 let horizon = create_texture(
136 wgpu::TextureFormat::Rgba8Unorm,
137 lod_horizon,
138 wgpu::FilterMode::Linear,
139 );
140 let weather = {
143 let texture_info = wgpu::TextureDescriptor {
144 label: None,
145 size: wgpu::Extent3d {
146 width: weather_size.x,
147 height: weather_size.y,
148 depth_or_array_layers: 1,
149 },
150 mip_level_count: 1,
151 sample_count: 1,
152 dimension: wgpu::TextureDimension::D2,
153 format: wgpu::TextureFormat::Rgba8Unorm,
154 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
155 view_formats: &[],
156 };
157
158 let sampler_info = wgpu::SamplerDescriptor {
159 label: None,
160 address_mode_u: wgpu::AddressMode::ClampToBorder,
161 address_mode_v: wgpu::AddressMode::ClampToBorder,
162 address_mode_w: wgpu::AddressMode::ClampToBorder,
163 mag_filter: wgpu::FilterMode::Linear,
164 min_filter: wgpu::FilterMode::Linear,
165 mipmap_filter: wgpu::FilterMode::Nearest,
166 border_color: Some(wgpu::SamplerBorderColor::TransparentBlack),
167 ..Default::default()
168 };
169
170 let view_info = wgpu::TextureViewDescriptor {
171 label: None,
172 format: Some(wgpu::TextureFormat::Rgba8Unorm),
173 dimension: Some(wgpu::TextureViewDimension::D2),
174 usage: None,
175 aspect: wgpu::TextureAspect::All,
176 base_mip_level: 0,
177 mip_level_count: None,
178 base_array_layer: 0,
179 array_layer_count: None,
180 };
181
182 renderer.create_texture_with_data_raw(
183 &texture_info,
184 &view_info,
185 &sampler_info,
186 vec![0; weather_size.x as usize * weather_size.y as usize * 4].as_slice(),
187 )
188 };
189 Self {
190 map,
191 alt,
192 horizon,
193 tgt_detail,
194 weather,
195 }
196 }
197}
198
199pub struct LodTerrainPipeline {
200 pub pipeline: wgpu::RenderPipeline,
201}
202
203impl LodTerrainPipeline {
204 pub fn new(
205 device: &wgpu::Device,
206 vs_module: &wgpu::ShaderModule,
207 fs_module: &wgpu::ShaderModule,
208 global_layout: &GlobalsLayouts,
209 format: wgpu::TextureFormat,
210 pipeline_modes: &PipelineModes,
211 ) -> Self {
212 let render_pipeline_layout =
213 device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
214 label: Some("Lod terrain pipeline layout"),
215 push_constant_ranges: &[],
216 bind_group_layouts: &[&global_layout.globals, &global_layout.shadow_textures],
217 });
218
219 let samples = pipeline_modes.aa.samples();
220
221 let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
222 label: Some("Lod terrain pipeline"),
223 layout: Some(&render_pipeline_layout),
224 vertex: wgpu::VertexState {
225 module: vs_module,
226 entry_point: Some("main"),
227 buffers: &[Vertex::desc()],
228 compilation_options: Default::default(),
229 },
230 primitive: wgpu::PrimitiveState {
231 topology: wgpu::PrimitiveTopology::TriangleList,
232 strip_index_format: None,
233 front_face: wgpu::FrontFace::Ccw,
234 cull_mode: Some(wgpu::Face::Back),
235 unclipped_depth: false,
236 polygon_mode: if pipeline_modes
237 .experimental_shaders
238 .contains(&ExperimentalShader::Wireframe)
239 {
240 wgpu::PolygonMode::Line
241 } else {
242 wgpu::PolygonMode::Fill
243 },
244 conservative: false,
245 },
246 depth_stencil: Some(wgpu::DepthStencilState {
247 format: wgpu::TextureFormat::Depth32Float,
248 depth_write_enabled: true,
249 depth_compare: wgpu::CompareFunction::GreaterEqual,
250 stencil: wgpu::StencilState {
251 front: wgpu::StencilFaceState::IGNORE,
252 back: wgpu::StencilFaceState::IGNORE,
253 read_mask: !0,
254 write_mask: 0,
255 },
256 bias: wgpu::DepthBiasState {
257 constant: 0,
258 slope_scale: 0.0,
259 clamp: 0.0,
260 },
261 }),
262 multisample: wgpu::MultisampleState {
263 count: samples,
264 mask: !0,
265 alpha_to_coverage_enabled: false,
266 },
267 fragment: Some(wgpu::FragmentState {
268 module: fs_module,
269 entry_point: Some("main"),
270 targets: &[
271 Some(wgpu::ColorTargetState {
272 format,
273 blend: None,
274 write_mask: wgpu::ColorWrites::ALL,
275 }),
276 Some(wgpu::ColorTargetState {
277 format: wgpu::TextureFormat::Rgba8Uint,
278 blend: None,
279 write_mask: wgpu::ColorWrites::ALL,
280 }),
281 ],
282 compilation_options: Default::default(),
283 }),
284 multiview: None,
285 cache: None,
286 });
287
288 Self {
289 pipeline: render_pipeline,
290 }
291 }
292}