author | alfadur |
Sat, 22 Feb 2025 19:39:31 +0300 | |
changeset 16120 | 5febd2bc5372 |
parent 16113 | 36862a9ec59b |
permissions | -rw-r--r-- |
14735 | 1 |
use integral_geometry::{GridIndex, Point, Rect, Size}; |
14726 | 2 |
use land2d::Land2D; |
3 |
use vec2d::Vec2D; |
|
14723 | 4 |
|
14739 | 5 |
use super::{ |
6 |
camera::Camera, |
|
7 |
gl::{ |
|
15783 | 8 |
Buffer, BufferType, BufferUsage, InputElement, InputFormat, InputLayout, PipelineState, |
9 |
Shader, Texture2D, TextureDataType, TextureFilter, TextureFormat, TextureInternalFormat, |
|
10 |
VariableBinding, |
|
14740 | 11 |
}, |
14723 | 12 |
}; |
13 |
||
15782 | 14 |
use std::num::NonZeroU32; |
15 |
||
14723 | 16 |
const VERTEX_SHADER: &'static str = r#" |
17 |
#version 150 |
|
18 |
||
19 |
in vec2 Position; |
|
20 |
in vec3 Uv; |
|
21 |
||
22 |
out vec3 a_Uv; |
|
23 |
||
24 |
//uniform Common { |
|
25 |
uniform mat4 Projection; |
|
26 |
//}; |
|
27 |
||
28 |
void main() |
|
29 |
{ |
|
30 |
a_Uv = Uv; |
|
31 |
gl_Position = Projection * vec4(Position, 0.0, 1.0); |
|
32 |
} |
|
33 |
"#; |
|
34 |
||
35 |
const PIXEL_SHADER: &'static str = r#" |
|
36 |
#version 150 |
|
37 |
||
38 |
in vec3 a_Uv; |
|
39 |
||
40 |
uniform sampler2D Texture; |
|
41 |
||
42 |
out vec4 Target; |
|
43 |
||
44 |
void main() |
|
45 |
{ |
|
46 |
Target = texture2D(Texture, a_Uv.xy); |
|
47 |
} |
|
48 |
"#; |
|
49 |
||
15784 | 50 |
struct MapTile { |
14723 | 51 |
// either index into GL texture array or emulated [Texture; N] |
52 |
texture_index: u32, |
|
53 |
||
54 |
width: u32, |
|
55 |
height: u32, |
|
56 |
} |
|
57 |
||
58 |
#[repr(C)] |
|
59 |
#[derive(Copy, Clone)] |
|
15784 | 60 |
struct TileVertex { |
14723 | 61 |
pos: [f32; 2], |
62 |
// doesn't hurt to include another float, just in case.. |
|
63 |
uv: [f32; 3], |
|
64 |
} |
|
65 |
||
15784 | 66 |
struct DrawTile { |
14723 | 67 |
texture_index: u32, |
68 |
index_len: u32, |
|
69 |
} |
|
70 |
||
71 |
pub struct MapRenderer { |
|
72 |
tiles: Vec<MapTile>, |
|
73 |
textures: Vec<Texture2D>, |
|
74 |
||
75 |
tile_vertex_buffer: Buffer, |
|
76 |
tile_index_buffer: Buffer, |
|
77 |
tile_vertices: Vec<TileVertex>, |
|
78 |
tile_indices: Vec<u16>, |
|
79 |
tile_draw_calls: Vec<DrawTile>, |
|
80 |
index_offset: u16, |
|
81 |
tile_shader: Shader, |
|
82 |
tile_layout: InputLayout, |
|
14726 | 83 |
|
14735 | 84 |
tile_size: Size, |
16113
36862a9ec59b
Update lib-hedgewars-engine to use newer versions of dependencies
unC0Rr
parents:
15784
diff
changeset
|
85 |
num_tile_x: u32, |
14723 | 86 |
} |
87 |
||
88 |
impl MapRenderer { |
|
14735 | 89 |
pub fn new(tile_size: Size) -> Self { |
90 |
debug_assert!(tile_size.is_power_of_two()); |
|
91 |
||
14723 | 92 |
let tile_shader = Shader::new( |
93 |
VERTEX_SHADER, |
|
94 |
Some(PIXEL_SHADER), |
|
95 |
&[ |
|
96 |
VariableBinding::Attribute("Position", 0), |
|
97 |
VariableBinding::Attribute("Uv", 1), |
|
98 |
VariableBinding::Sampler("Texture", 0), |
|
14726 | 99 |
], |
100 |
) |
|
101 |
.unwrap(); |
|
14723 | 102 |
|
14735 | 103 |
let vertex_size = std::mem::size_of::<TileVertex>() as u32; |
14723 | 104 |
let tile_layout = InputLayout::new(vec![ |
105 |
// position |
|
106 |
InputElement { |
|
107 |
shader_slot: 0, |
|
108 |
buffer_slot: 0, |
|
109 |
format: InputFormat::Float(gl::FLOAT, false), |
|
110 |
components: 2, |
|
14735 | 111 |
stride: vertex_size, |
14726 | 112 |
offset: 0, |
14723 | 113 |
}, |
114 |
// uv |
|
115 |
InputElement { |
|
116 |
shader_slot: 1, |
|
117 |
buffer_slot: 0, |
|
118 |
format: InputFormat::Float(gl::FLOAT, false), |
|
119 |
components: 3, |
|
14735 | 120 |
stride: vertex_size, |
14726 | 121 |
offset: 8, |
14723 | 122 |
}, |
123 |
]); |
|
14726 | 124 |
|
14723 | 125 |
MapRenderer { |
126 |
tiles: Vec::new(), |
|
127 |
textures: Vec::new(), |
|
14726 | 128 |
|
15783 | 129 |
tile_vertex_buffer: Buffer::empty(BufferType::Array, BufferUsage::DynamicDraw), |
130 |
tile_index_buffer: Buffer::empty(BufferType::ElementArray, BufferUsage::DynamicDraw), |
|
14723 | 131 |
tile_vertices: Vec::new(), |
132 |
tile_indices: Vec::new(), |
|
133 |
index_offset: 0, |
|
134 |
||
135 |
tile_draw_calls: Vec::new(), |
|
136 |
tile_shader, |
|
137 |
tile_layout, |
|
138 |
||
14735 | 139 |
tile_size, |
14723 | 140 |
num_tile_x: 0, |
141 |
} |
|
142 |
} |
|
143 |
||
144 |
pub fn init(&mut self, land: &Vec2D<u32>) { |
|
145 |
// clear tiles, but keep our textures for potential re-use |
|
146 |
self.tiles.clear(); |
|
147 |
||
14735 | 148 |
let tw = self.tile_size.width; |
149 |
let th = self.tile_size.height; |
|
16113
36862a9ec59b
Update lib-hedgewars-engine to use newer versions of dependencies
unC0Rr
parents:
15784
diff
changeset
|
150 |
let lw = land.width() as u32; |
36862a9ec59b
Update lib-hedgewars-engine to use newer versions of dependencies
unC0Rr
parents:
15784
diff
changeset
|
151 |
let lh = land.height() as u32; |
14735 | 152 |
let num_tile_x = lw / tw; |
153 |
let num_tile_y = lh / th; |
|
14723 | 154 |
|
14735 | 155 |
self.num_tile_x = num_tile_x; |
14723 | 156 |
|
157 |
for y in 0..num_tile_y { |
|
158 |
for x in 0..num_tile_x { |
|
16113
36862a9ec59b
Update lib-hedgewars-engine to use newer versions of dependencies
unC0Rr
parents:
15784
diff
changeset
|
159 |
let idx = (x + y * num_tile_x) as usize; |
14723 | 160 |
|
161 |
let (data, stride) = { |
|
162 |
let bpp = 4; |
|
163 |
||
164 |
let offset = x * tw * bpp + y * th * lw * bpp; |
|
165 |
||
16113
36862a9ec59b
Update lib-hedgewars-engine to use newer versions of dependencies
unC0Rr
parents:
15784
diff
changeset
|
166 |
let data = unsafe { &land.as_bytes()[offset as usize..] }; |
14723 | 167 |
let stride = land.width(); |
168 |
||
15782 | 169 |
(data, NonZeroU32::new(stride as u32)) |
14723 | 170 |
}; |
14726 | 171 |
|
14723 | 172 |
let texture_index = if idx >= self.textures.len() { |
173 |
let texture = Texture2D::with_data( |
|
174 |
data, |
|
175 |
stride, |
|
15307 | 176 |
self.tile_size, |
15782 | 177 |
TextureInternalFormat::Rgba8, |
178 |
TextureFormat::Rgba, |
|
179 |
TextureDataType::UnsignedByte, |
|
180 |
TextureFilter::Nearest, |
|
14723 | 181 |
); |
182 |
||
183 |
let texture_index = self.textures.len(); |
|
184 |
self.textures.push(texture); |
|
185 |
||
186 |
texture_index |
|
187 |
} else { |
|
14735 | 188 |
let texture_region = Rect::at_origin(self.tile_size); |
14723 | 189 |
|
16113
36862a9ec59b
Update lib-hedgewars-engine to use newer versions of dependencies
unC0Rr
parents:
15784
diff
changeset
|
190 |
self.textures[idx as usize].update( |
14726 | 191 |
texture_region, |
192 |
data, |
|
193 |
stride, |
|
15782 | 194 |
TextureFormat::Rgba, |
195 |
TextureDataType::UnsignedByte, |
|
14726 | 196 |
); |
14723 | 197 |
idx |
198 |
}; |
|
199 |
||
200 |
let tile = MapTile { |
|
201 |
texture_index: texture_index as u32, |
|
14726 | 202 |
|
14723 | 203 |
// TODO: are there ever non-power of two textures? |
14735 | 204 |
width: self.tile_size.width as u32, |
205 |
height: self.tile_size.height as u32, |
|
14723 | 206 |
}; |
207 |
self.tiles.push(tile); |
|
208 |
} |
|
209 |
} |
|
210 |
} |
|
211 |
||
14726 | 212 |
pub fn update(&mut self, land: &Land2D<u32>, region: Rect) {} |
14723 | 213 |
|
14739 | 214 |
pub fn render(&mut self, camera: &Camera) { |
215 |
let viewport = camera.viewport(); |
|
14723 | 216 |
self.tile_vertices.clear(); |
217 |
self.tile_indices.clear(); |
|
218 |
self.tile_draw_calls.clear(); |
|
219 |
self.index_offset = 0; |
|
14726 | 220 |
|
14723 | 221 |
for (idx, tile) in self.tiles.iter().enumerate() { |
16113
36862a9ec59b
Update lib-hedgewars-engine to use newer versions of dependencies
unC0Rr
parents:
15784
diff
changeset
|
222 |
let tile_x = idx as u32 % self.num_tile_x; |
36862a9ec59b
Update lib-hedgewars-engine to use newer versions of dependencies
unC0Rr
parents:
15784
diff
changeset
|
223 |
let tile_y = idx as u32 / self.num_tile_x; |
14735 | 224 |
let tile_w = self.tile_size.width; |
225 |
let tile_h = self.tile_size.width; |
|
14723 | 226 |
|
14735 | 227 |
let origin = Point::new((tile_x * tile_w) as i32, (tile_y * tile_h) as i32); |
228 |
let tile_rect = Rect::from_size(origin, self.tile_size); |
|
14723 | 229 |
|
230 |
if viewport.intersects(&tile_rect) { |
|
231 |
// lazy |
|
232 |
//dbg!(origin); |
|
233 |
let tile_x = origin.x as f32; |
|
234 |
let tile_y = origin.y as f32; |
|
235 |
let tile_w = tile_x + tile_w as f32; |
|
236 |
let tile_h = tile_y + tile_h as f32; |
|
237 |
let uv_depth = tile.texture_index as f32; |
|
238 |
||
239 |
//dbg!(tile_x); |
|
14726 | 240 |
let tl = TileVertex { |
241 |
pos: [tile_x, tile_y], |
|
242 |
uv: [0f32, 0f32, uv_depth], |
|
243 |
}; |
|
244 |
let bl = TileVertex { |
|
245 |
pos: [tile_x, tile_h], |
|
246 |
uv: [0f32, 1f32, uv_depth], |
|
247 |
}; |
|
248 |
let br = TileVertex { |
|
249 |
pos: [tile_w, tile_h], |
|
250 |
uv: [1f32, 1f32, uv_depth], |
|
251 |
}; |
|
252 |
let tr = TileVertex { |
|
253 |
pos: [tile_w, tile_y], |
|
254 |
uv: [1f32, 0f32, uv_depth], |
|
255 |
}; |
|
14723 | 256 |
|
257 |
self.tile_vertices.extend(&[tl, bl, br, tr]); |
|
258 |
||
259 |
let i = self.index_offset; |
|
14726 | 260 |
self.tile_indices |
261 |
.extend(&[i + 0, i + 1, i + 2, i + 2, i + 3, i + 0]); |
|
14723 | 262 |
self.index_offset += 4; |
263 |
||
264 |
self.tile_draw_calls.push(DrawTile { |
|
265 |
texture_index: tile.texture_index, |
|
14726 | 266 |
index_len: 6, |
14723 | 267 |
}); |
268 |
} |
|
269 |
} |
|
270 |
||
271 |
self.tile_vertex_buffer.write_typed(&self.tile_vertices); |
|
272 |
self.tile_index_buffer.write_typed(&self.tile_indices); |
|
273 |
||
14726 | 274 |
let _g = self.tile_layout.bind( |
275 |
&[(0, &self.tile_vertex_buffer)], |
|
276 |
Some(&self.tile_index_buffer), |
|
277 |
); |
|
14723 | 278 |
|
14739 | 279 |
let projection = camera.projection(); |
14723 | 280 |
|
281 |
self.tile_shader.bind(); |
|
14740 | 282 |
self.tile_shader |
283 |
.set_matrix("Projection", projection.as_ptr()); |
|
284 |
||
285 |
let _state = PipelineState::new().with_blend(); |
|
14726 | 286 |
|
14723 | 287 |
let mut draw_offset = 0; |
288 |
for draw_call in &self.tile_draw_calls { |
|
289 |
unsafe { |
|
14726 | 290 |
self.tile_shader |
291 |
.bind_texture_2d(0, &self.textures[draw_call.texture_index as usize]); |
|
292 |
||
14723 | 293 |
gl::DrawElements( |
294 |
gl::TRIANGLES, |
|
295 |
draw_call.index_len as i32, |
|
296 |
gl::UNSIGNED_SHORT, |
|
14726 | 297 |
draw_offset as *const _, |
14723 | 298 |
); |
299 |
} |
|
300 |
||
301 |
draw_offset += draw_call.index_len * 2; |
|
302 |
} |
|
303 |
} |
|
304 |
} |