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 usage: None,
105 aspect: wgpu::TextureAspect::All,
106 base_mip_level: 0,
107 mip_level_count: None,
108 base_array_layer: 0,
109 array_layer_count: None,
110 };
111
112 renderer.create_texture_with_data_raw(
113 &texture_info,
114 &view_info,
115 &sampler_info,
116 bytemuck::cast_slice(data),
117 )
118 };
119 let map = create_texture(
120 wgpu::TextureFormat::Rgba8UnormSrgb,
121 lod_base,
122 wgpu::FilterMode::Linear,
123 );
124 let alt = create_texture(
127 wgpu::TextureFormat::Rgba8Unorm,
128 lod_alt,
129 wgpu::FilterMode::Linear,
130 );
131 let horizon = create_texture(
134 wgpu::TextureFormat::Rgba8Unorm,
135 lod_horizon,
136 wgpu::FilterMode::Linear,
137 );
138 let weather = {
141 let texture_info = wgpu::TextureDescriptor {
142 label: None,
143 size: wgpu::Extent3d {
144 width: weather_size.x,
145 height: weather_size.y,
146 depth_or_array_layers: 1,
147 },
148 mip_level_count: 1,
149 sample_count: 1,
150 dimension: wgpu::TextureDimension::D2,
151 format: wgpu::TextureFormat::Rgba8Unorm,
152 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
153 view_formats: &[],
154 };
155
156 let sampler_info = wgpu::SamplerDescriptor {
157 label: None,
158 address_mode_u: wgpu::AddressMode::ClampToBorder,
159 address_mode_v: wgpu::AddressMode::ClampToBorder,
160 address_mode_w: wgpu::AddressMode::ClampToBorder,
161 mag_filter: wgpu::FilterMode::Linear,
162 min_filter: wgpu::FilterMode::Linear,
163 mipmap_filter: wgpu::FilterMode::Nearest,
164 border_color: Some(wgpu::SamplerBorderColor::TransparentBlack),
165 ..Default::default()
166 };
167
168 let view_info = wgpu::TextureViewDescriptor {
169 label: None,
170 format: Some(wgpu::TextureFormat::Rgba8Unorm),
171 dimension: Some(wgpu::TextureViewDimension::D2),
172 usage: None,
173 aspect: wgpu::TextureAspect::All,
174 base_mip_level: 0,
175 mip_level_count: None,
176 base_array_layer: 0,
177 array_layer_count: None,
178 };
179
180 renderer.create_texture_with_data_raw(
181 &texture_info,
182 &view_info,
183 &sampler_info,
184 vec![0; weather_size.x as usize * weather_size.y as usize * 4].as_slice(),
185 )
186 };
187 Self {
188 map,
189 alt,
190 horizon,
191 tgt_detail,
192 weather,
193 }
194 }
195}
196
197pub struct LodTerrainPipeline {
198 pub pipeline: wgpu::RenderPipeline,
199}
200
201impl LodTerrainPipeline {
202 pub fn new(
203 device: &wgpu::Device,
204 vs_module: &wgpu::ShaderModule,
205 fs_module: &wgpu::ShaderModule,
206 global_layout: &GlobalsLayouts,
207 aa_mode: AaMode,
208 format: wgpu::TextureFormat,
209 ) -> Self {
210 let render_pipeline_layout =
211 device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
212 label: Some("Lod terrain pipeline layout"),
213 push_constant_ranges: &[],
214 bind_group_layouts: &[&global_layout.globals, &global_layout.shadow_textures],
215 });
216
217 let samples = aa_mode.samples();
218
219 let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
220 label: Some("Lod terrain pipeline"),
221 layout: Some(&render_pipeline_layout),
222 vertex: wgpu::VertexState {
223 module: vs_module,
224 entry_point: Some("main"),
225 buffers: &[Vertex::desc()],
226 compilation_options: Default::default(),
227 },
228 primitive: wgpu::PrimitiveState {
229 topology: wgpu::PrimitiveTopology::TriangleList,
230 strip_index_format: None,
231 front_face: wgpu::FrontFace::Ccw,
232 cull_mode: Some(wgpu::Face::Back),
233 unclipped_depth: false,
234 polygon_mode: wgpu::PolygonMode::Fill,
235 conservative: false,
236 },
237 depth_stencil: Some(wgpu::DepthStencilState {
238 format: wgpu::TextureFormat::Depth32Float,
239 depth_write_enabled: true,
240 depth_compare: wgpu::CompareFunction::GreaterEqual,
241 stencil: wgpu::StencilState {
242 front: wgpu::StencilFaceState::IGNORE,
243 back: wgpu::StencilFaceState::IGNORE,
244 read_mask: !0,
245 write_mask: 0,
246 },
247 bias: wgpu::DepthBiasState {
248 constant: 0,
249 slope_scale: 0.0,
250 clamp: 0.0,
251 },
252 }),
253 multisample: wgpu::MultisampleState {
254 count: samples,
255 mask: !0,
256 alpha_to_coverage_enabled: false,
257 },
258 fragment: Some(wgpu::FragmentState {
259 module: fs_module,
260 entry_point: Some("main"),
261 targets: &[
262 Some(wgpu::ColorTargetState {
263 format,
264 blend: None,
265 write_mask: wgpu::ColorWrites::ALL,
266 }),
267 Some(wgpu::ColorTargetState {
268 format: wgpu::TextureFormat::Rgba8Uint,
269 blend: None,
270 write_mask: wgpu::ColorWrites::ALL,
271 }),
272 ],
273 compilation_options: Default::default(),
274 }),
275 multiview: None,
276 cache: None,
277 });
278
279 Self {
280 pipeline: render_pipeline,
281 }
282 }
283}