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