|
|
@@ -1,7 +1,9 @@
|
|
1
|
1
|
use ::std::ffi::CStr;
|
|
2
|
2
|
use buffer::{Buffer, DrawMode};
|
|
|
3
|
+use cgmath::{Matrix3, Point2, Transform, vec2, vec3};
|
|
3
|
4
|
use context::Context;
|
|
4
|
|
-use coord::{ScreenCoord, View};
|
|
|
5
|
+use coord::{MapCoord, ScreenCoord, ScreenRect, View};
|
|
|
6
|
+use image;
|
|
5
|
7
|
use map_view::MapView;
|
|
6
|
8
|
use program::Program;
|
|
7
|
9
|
use texture::{Texture, TextureFormat};
|
|
|
@@ -22,6 +24,18 @@ pub struct MapViewGl {
|
|
22
|
24
|
tile_buffer: Buffer,
|
|
23
|
25
|
tile_cache: TileCache,
|
|
24
|
26
|
tile_atlas: TileAtlas,
|
|
|
27
|
+ marker_buffer: Buffer,
|
|
|
28
|
+ marker_program: Program,
|
|
|
29
|
+ marker_tex: Texture,
|
|
|
30
|
+ markers: Vec<MapCoord>,
|
|
|
31
|
+ last_draw_type: DrawType,
|
|
|
32
|
+}
|
|
|
33
|
+
|
|
|
34
|
+#[derive(Debug, Eq, PartialEq)]
|
|
|
35
|
+enum DrawType {
|
|
|
36
|
+ Null,
|
|
|
37
|
+ Tiles,
|
|
|
38
|
+ Markers
|
|
25
|
39
|
}
|
|
26
|
40
|
|
|
27
|
41
|
impl MapViewGl {
|
|
|
@@ -90,8 +104,37 @@ impl MapViewGl {
|
|
90
|
104
|
);
|
|
91
|
105
|
check_gl_errors!(cx);
|
|
92
|
106
|
|
|
93
|
|
- tile_program.enable_vertex_attribs(cx);
|
|
94
|
|
- tile_program.set_vertex_attribs(cx, &tile_buffer);
|
|
|
107
|
+
|
|
|
108
|
+ let marker_buffer = Buffer::new(cx, &[], 0);
|
|
|
109
|
+ cx.bind_buffer(marker_buffer.id());
|
|
|
110
|
+ check_gl_errors!(cx);
|
|
|
111
|
+
|
|
|
112
|
+ let mut marker_program = Program::new(
|
|
|
113
|
+ cx,
|
|
|
114
|
+ include_bytes!("../shader/marker.vert"),
|
|
|
115
|
+ include_bytes!("../shader/marker.frag"),
|
|
|
116
|
+ ).unwrap();
|
|
|
117
|
+ check_gl_errors!(cx);
|
|
|
118
|
+
|
|
|
119
|
+ let marker_tex = {
|
|
|
120
|
+ let img = image::load_from_memory(
|
|
|
121
|
+ include_bytes!("../img/marker.png"),
|
|
|
122
|
+ ).unwrap();
|
|
|
123
|
+ Texture::new(cx, &img).unwrap()
|
|
|
124
|
+ };
|
|
|
125
|
+
|
|
|
126
|
+ marker_program.add_texture(cx, &marker_tex, CStr::from_bytes_with_nul(b"tex\0").unwrap());
|
|
|
127
|
+
|
|
|
128
|
+ marker_program.add_attribute(
|
|
|
129
|
+ cx,
|
|
|
130
|
+ CStr::from_bytes_with_nul(b"position\0").unwrap(),
|
|
|
131
|
+ &VertexAttribParams::new(2, 4, 0)
|
|
|
132
|
+ );
|
|
|
133
|
+ marker_program.add_attribute(
|
|
|
134
|
+ cx,
|
|
|
135
|
+ CStr::from_bytes_with_nul(b"tex_coord\0").unwrap(),
|
|
|
136
|
+ &VertexAttribParams::new(2, 4, 2)
|
|
|
137
|
+ );
|
|
95
|
138
|
|
|
96
|
139
|
MapViewGl {
|
|
97
|
140
|
map_view,
|
|
|
@@ -100,6 +143,11 @@ impl MapViewGl {
|
|
100
|
143
|
tile_buffer,
|
|
101
|
144
|
tile_cache: TileCache::new(move |_tile| update_func(), use_network),
|
|
102
|
145
|
tile_atlas: TileAtlas::new(cx, atlas_tex, 256, use_async),
|
|
|
146
|
+ marker_buffer,
|
|
|
147
|
+ marker_program,
|
|
|
148
|
+ marker_tex,
|
|
|
149
|
+ markers: vec![],
|
|
|
150
|
+ last_draw_type: DrawType::Null,
|
|
103
|
151
|
}
|
|
104
|
152
|
}
|
|
105
|
153
|
|
|
|
@@ -109,6 +157,10 @@ impl MapViewGl {
|
|
109
|
157
|
cx.set_viewport(0, 0, width, height);
|
|
110
|
158
|
}
|
|
111
|
159
|
|
|
|
160
|
+ pub fn add_marker(&mut self, map_coord: MapCoord) {
|
|
|
161
|
+ self.markers.push(map_coord);
|
|
|
162
|
+ }
|
|
|
163
|
+
|
|
112
|
164
|
pub fn viewport_in_map(&self) -> bool {
|
|
113
|
165
|
self.map_view.viewport_in_map()
|
|
114
|
166
|
}
|
|
|
@@ -117,17 +169,21 @@ impl MapViewGl {
|
|
117
|
169
|
self.tile_atlas.double_texture_size(cx)
|
|
118
|
170
|
}
|
|
119
|
171
|
|
|
120
|
|
- /// Returns `Err` when tile cache is too small for this view.
|
|
121
|
|
- /// Returns the number of OpenGL draw calls, which can be decreased to `1` by increasing the
|
|
122
|
|
- /// size of the tile atlas.
|
|
123
|
|
- pub fn draw(&mut self, cx: &mut Context, source: &TileSource) -> Result<usize, usize> {
|
|
|
172
|
+ fn draw_tiles(&mut self, cx: &mut Context, source: &TileSource, snap_to_pixel: bool) -> Result<usize, usize> {
|
|
|
173
|
+ if self.last_draw_type != DrawType::Tiles {
|
|
|
174
|
+ self.last_draw_type = DrawType::Tiles;
|
|
|
175
|
+ self.tile_program.enable_vertex_attribs(cx);
|
|
|
176
|
+ self.tile_program.set_vertex_attribs(cx, &self.tile_buffer);
|
|
|
177
|
+ cx.set_active_texture_unit(self.tile_atlas.texture().unit());
|
|
|
178
|
+ }
|
|
|
179
|
+
|
|
124
|
180
|
self.tile_cache.set_view_location(View {
|
|
125
|
181
|
source_id: source.id(),
|
|
126
|
182
|
zoom: self.map_view.tile_zoom(),
|
|
127
|
183
|
center: self.map_view.center,
|
|
128
|
184
|
});
|
|
129
|
185
|
|
|
130
|
|
- let visible_tiles = self.map_view.visible_tiles(true);
|
|
|
186
|
+ let visible_tiles = self.map_view.visible_tiles(snap_to_pixel);
|
|
131
|
187
|
let mut remainder = visible_tiles.as_slice();
|
|
132
|
188
|
let mut num_draws = 0;
|
|
133
|
189
|
let mut max_tiles_to_use = self.tile_cache.max_tiles();
|
|
|
@@ -223,6 +279,109 @@ impl MapViewGl {
|
|
223
|
279
|
}
|
|
224
|
280
|
}
|
|
225
|
281
|
|
|
|
282
|
+ fn draw_marker(&mut self, cx: &mut Context, snap_to_pixel: bool) {
|
|
|
283
|
+ if self.last_draw_type != DrawType::Markers {
|
|
|
284
|
+ self.last_draw_type = DrawType::Markers;
|
|
|
285
|
+ cx.set_active_texture_unit(self.marker_tex.unit());
|
|
|
286
|
+ self.marker_program.enable_vertex_attribs(cx);
|
|
|
287
|
+ self.marker_program.set_vertex_attribs(cx, &self.marker_buffer);
|
|
|
288
|
+ }
|
|
|
289
|
+
|
|
|
290
|
+ let mut vertex_data: Vec<f32> = vec![];
|
|
|
291
|
+
|
|
|
292
|
+ let marker_size = vec2::<f64>(40.0, 50.0);
|
|
|
293
|
+ let marker_offset = vec2::<f64>(-20.0, -50.0);
|
|
|
294
|
+
|
|
|
295
|
+ let scale_x = 2.0 / self.viewport_size.0 as f32;
|
|
|
296
|
+ let scale_y = -2.0 / self.viewport_size.1 as f32;
|
|
|
297
|
+
|
|
|
298
|
+ let tex_mat: Matrix3<f32> = Matrix3::from_cols(
|
|
|
299
|
+ vec3(marker_size.x as f32, 0.0, 0.0),
|
|
|
300
|
+ vec3(0.0, marker_size.y as f32, 0.0),
|
|
|
301
|
+ vec3(marker_offset.x as f32, marker_offset.y as f32, 1.0),
|
|
|
302
|
+ );
|
|
|
303
|
+
|
|
|
304
|
+ let screen_mat: Matrix3<f32> = Matrix3::from_cols(
|
|
|
305
|
+ vec3(scale_x, 0.0, 0.0),
|
|
|
306
|
+ vec3(0.0, scale_y, 0.0),
|
|
|
307
|
+ vec3(-1.0, 1.0, 1.0),
|
|
|
308
|
+ );
|
|
|
309
|
+
|
|
|
310
|
+ let t1 = Point2::new(0.0f32, 0.0);
|
|
|
311
|
+ let t2 = Point2::new(1.0f32, 0.0);
|
|
|
312
|
+ let t3 = Point2::new(1.0f32, 1.0);
|
|
|
313
|
+ let t4 = Point2::new(0.0f32, 1.0);
|
|
|
314
|
+
|
|
|
315
|
+ let visible_rect = ScreenRect {
|
|
|
316
|
+ x: marker_offset.x,
|
|
|
317
|
+ y: marker_offset.y,
|
|
|
318
|
+ width: f64::from(self.viewport_size.0) + marker_size.x,
|
|
|
319
|
+ height: f64::from(self.viewport_size.1) + marker_size.y,
|
|
|
320
|
+ };
|
|
|
321
|
+
|
|
|
322
|
+ for m in &self.markers {
|
|
|
323
|
+ let screen_pos = {
|
|
|
324
|
+ let mut sp = self.map_view.map_to_screen_coord(*m);
|
|
|
325
|
+ if snap_to_pixel {
|
|
|
326
|
+ let topleft = self.map_view.map_to_screen_coord(MapCoord::new(0.0, 0.0));
|
|
|
327
|
+ let mut snapped = topleft;
|
|
|
328
|
+ snapped.snap_to_pixel();
|
|
|
329
|
+
|
|
|
330
|
+ sp.x += snapped.x - topleft.x;
|
|
|
331
|
+ sp.y += snapped.y - topleft.y;
|
|
|
332
|
+ }
|
|
|
333
|
+ sp
|
|
|
334
|
+ };
|
|
|
335
|
+
|
|
|
336
|
+ if !screen_pos.is_inside(&visible_rect) {
|
|
|
337
|
+ continue;
|
|
|
338
|
+ }
|
|
|
339
|
+ let trans_mat: Matrix3<f32> = Matrix3::from_cols(
|
|
|
340
|
+ vec3(0.0, 0.0, 0.0),
|
|
|
341
|
+ vec3(0.0, 0.0, 0.0),
|
|
|
342
|
+ vec3(screen_pos.x as f32, screen_pos.y as f32, 0.0),
|
|
|
343
|
+ );
|
|
|
344
|
+ let mat: Matrix3<f32> = screen_mat * (tex_mat + trans_mat);
|
|
|
345
|
+
|
|
|
346
|
+ let p1: Point2<f32> = mat.transform_point(t1);
|
|
|
347
|
+ let p2: Point2<f32> = mat.transform_point(t2);
|
|
|
348
|
+ let p3: Point2<f32> = mat.transform_point(t3);
|
|
|
349
|
+ let p4: Point2<f32> = mat.transform_point(t4);
|
|
|
350
|
+
|
|
|
351
|
+ vertex_data.extend::<&[f32; 2]>(p1.as_ref());
|
|
|
352
|
+ vertex_data.extend::<&[f32; 2]>(t1.as_ref());
|
|
|
353
|
+ vertex_data.extend::<&[f32; 2]>(p2.as_ref());
|
|
|
354
|
+ vertex_data.extend::<&[f32; 2]>(t2.as_ref());
|
|
|
355
|
+ vertex_data.extend::<&[f32; 2]>(p3.as_ref());
|
|
|
356
|
+ vertex_data.extend::<&[f32; 2]>(t3.as_ref());
|
|
|
357
|
+ vertex_data.extend::<&[f32; 2]>(p1.as_ref());
|
|
|
358
|
+ vertex_data.extend::<&[f32; 2]>(t1.as_ref());
|
|
|
359
|
+ vertex_data.extend::<&[f32; 2]>(p3.as_ref());
|
|
|
360
|
+ vertex_data.extend::<&[f32; 2]>(t3.as_ref());
|
|
|
361
|
+ vertex_data.extend::<&[f32; 2]>(p4.as_ref());
|
|
|
362
|
+ vertex_data.extend::<&[f32; 2]>(t4.as_ref());
|
|
|
363
|
+ }
|
|
|
364
|
+
|
|
|
365
|
+ self.marker_buffer.set_data(cx, &vertex_data, vertex_data.len() / 4);
|
|
|
366
|
+ self.marker_buffer.draw(cx, &self.marker_program, DrawMode::Triangles);
|
|
|
367
|
+ }
|
|
|
368
|
+
|
|
|
369
|
+ /// Returns `Err` when tile cache is too small for this view.
|
|
|
370
|
+ /// Returns the number of OpenGL draw calls, which can be decreased to `1` by increasing the
|
|
|
371
|
+ /// size of the tile atlas.
|
|
|
372
|
+ pub fn draw(&mut self, cx: &mut Context, source: &TileSource) -> Result<usize, usize> {
|
|
|
373
|
+ // only snap to pixel grid if zoom has integral value
|
|
|
374
|
+ let snap_to_pixel = (self.map_view.zoom - (self.map_view.zoom + 0.5).floor()).abs() < 1e-10;
|
|
|
375
|
+
|
|
|
376
|
+ let ret = self.draw_tiles(cx, source, snap_to_pixel);
|
|
|
377
|
+
|
|
|
378
|
+ if !self.markers.is_empty() {
|
|
|
379
|
+ self.draw_marker(cx, snap_to_pixel);
|
|
|
380
|
+ }
|
|
|
381
|
+
|
|
|
382
|
+ ret
|
|
|
383
|
+ }
|
|
|
384
|
+
|
|
226
|
385
|
pub fn step_zoom(&mut self, steps: i32, step_size: f64) {
|
|
227
|
386
|
let new_zoom = {
|
|
228
|
387
|
let z = (self.map_view.zoom + f64::from(steps) * step_size) / step_size;
|