Pārlūkot izejas kodu

Support drawing markers

Johannes Hofmann 7 gadus atpakaļ
vecāks
revīzija
c430500e69
11 mainītis faili ar 235 papildinājumiem un 10 dzēšanām
  1. 27
    0
      Cargo.lock
  2. 1
    0
      Cargo.toml
  3. Binārs
      img/marker.png
  4. 9
    0
      shader/marker.frag
  5. 12
    0
      shader/marker.vert
  6. 6
    0
      src/context.rs
  7. 7
    0
      src/coord.rs
  8. 1
    0
      src/main.rs
  9. 1
    2
      src/map_view.rs
  10. 167
    8
      src/map_view_gl.rs
  11. 4
    0
      src/tile_atlas.rs

+ 27
- 0
Cargo.lock Parādīt failu

@@ -24,6 +24,11 @@ dependencies = [
24 24
  "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
25 25
 ]
26 26
 
27
+[[package]]
28
+name = "approx"
29
+version = "0.1.1"
30
+source = "registry+https://github.com/rust-lang/crates.io-index"
31
+
27 32
 [[package]]
28 33
 name = "arrayvec"
29 34
 version = "0.4.7"
@@ -104,6 +109,16 @@ dependencies = [
104 109
  "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)",
105 110
 ]
106 111
 
112
+[[package]]
113
+name = "cgmath"
114
+version = "0.16.1"
115
+source = "registry+https://github.com/rust-lang/crates.io-index"
116
+dependencies = [
117
+ "approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
118
+ "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
119
+ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
120
+]
121
+
107 122
 [[package]]
108 123
 name = "clap"
109 124
 version = "2.31.2"
@@ -259,6 +274,7 @@ dependencies = [
259 274
 name = "deltamap"
260 275
 version = "0.1.0"
261 276
 dependencies = [
277
+ "cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
262 278
  "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
263 279
  "directories 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
264 280
  "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -786,6 +802,14 @@ dependencies = [
786 802
  "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
787 803
 ]
788 804
 
805
+[[package]]
806
+name = "num-traits"
807
+version = "0.1.43"
808
+source = "registry+https://github.com/rust-lang/crates.io-index"
809
+dependencies = [
810
+ "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
811
+]
812
+
789 813
 [[package]]
790 814
 name = "num-traits"
791 815
 version = "0.2.4"
@@ -1708,6 +1732,7 @@ dependencies = [
1708 1732
 "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
1709 1733
 "checksum android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407"
1710 1734
 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
1735
+"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94"
1711 1736
 "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
1712 1737
 "checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1"
1713 1738
 "checksum base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9263aa6a38da271eec5c91a83ce1e800f093c8535788d403d626d8d5c3f8f007"
@@ -1720,6 +1745,7 @@ dependencies = [
1720 1745
 "checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba"
1721 1746
 "checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18"
1722 1747
 "checksum cgl 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "80f05e25f9631fdee56693110feda284a49308ca1e768857a0ad3906cfc1502a"
1748
+"checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c"
1723 1749
 "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
1724 1750
 "checksum cocoa 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b44bd25bd275e9d74a5dff8ca55f2fb66c9ad5e12170d58697701df21a56e0e"
1725 1751
 "checksum color_quant 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a475fc4af42d83d28adf72968d9bcfaf035a1a9381642d8e85d8a04957767b0d"
@@ -1795,6 +1821,7 @@ dependencies = [
1795 1821
 "checksum num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac0ea58d64a89d9d6b7688031b3be9358d6c919badcf7fbb0527ccfd891ee45"
1796 1822
 "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
1797 1823
 "checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"
1824
+"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
1798 1825
 "checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28"
1799 1826
 "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
1800 1827
 "checksum objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "877f30f37acef6749b1841cceab289707f211aecfc756553cd63976190e6cc2e"

+ 1
- 0
Cargo.toml Parādīt failu

@@ -11,6 +11,7 @@ A simple map viewer
11 11
 license = "GPL-3.0"
12 12
 
13 13
 [dependencies]
14
+cgmath = "0.16"
14 15
 clap = "2.29"
15 16
 env_logger = "0.5.0-rc.2"
16 17
 gl = "0.10"

Binārs
img/marker.png Parādīt failu


+ 9
- 0
shader/marker.frag Parādīt failu

@@ -0,0 +1,9 @@
1
+#version 100
2
+precision mediump float;
3
+
4
+varying vec2 v_tex;
5
+uniform sampler2D tex;
6
+
7
+void main() {
8
+    gl_FragColor = texture2D(tex, v_tex.xy).rgba;
9
+}

+ 12
- 0
shader/marker.vert Parādīt failu

@@ -0,0 +1,12 @@
1
+#version 100
2
+precision mediump float;
3
+
4
+attribute vec2 position;
5
+attribute vec2 tex_coord;
6
+
7
+varying vec2 v_tex;
8
+
9
+void main() {
10
+    gl_Position = vec4(position, 0.0, 1.0);
11
+    v_tex = tex_coord;
12
+}

+ 6
- 0
src/context.rs Parādīt failu

@@ -75,6 +75,12 @@ impl Context {
75 75
         info!("OpenGL version: {}", cx.gl_version());
76 76
         debug!("MAX_TEXTURE_SIZE: {}", cx.max_texture_size());
77 77
 
78
+        //TODO move somewhere else
79
+        unsafe {
80
+            cx.gl.Enable(gl::BLEND);
81
+            cx.gl.BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
82
+        }
83
+
78 84
         cx
79 85
     }
80 86
 

+ 7
- 0
src/coord.rs Parādīt failu

@@ -62,6 +62,13 @@ impl ScreenCoord {
62 62
         self.x = self.x.floor();
63 63
         self.y = self.y.floor();
64 64
     }
65
+
66
+    pub fn is_inside(&self, rect: &ScreenRect) -> bool {
67
+        self.x >= rect.x &&
68
+        self.y >= rect.y &&
69
+        self.x < rect.x + rect.width &&
70
+        self.y < rect.y + rect.height
71
+    }
65 72
 }
66 73
 
67 74
 /// A rectangle in screen coordinates.

+ 1
- 0
src/main.rs Parādīt failu

@@ -1,3 +1,4 @@
1
+extern crate cgmath;
1 2
 #[macro_use]
2 3
 extern crate clap;
3 4
 extern crate directories;

+ 1
- 2
src/map_view.rs Parādīt failu

@@ -100,8 +100,7 @@ impl MapView {
100 100
         let mut top_left_tile_screen_coord = self.tile_screen_position(&top_left_tile);
101 101
         let tile_screen_size = f64::powf(2.0, self.zoom - f64::from(uzoom)) * f64::from(self.tile_size);
102 102
 
103
-        // only snap to pixel grid if zoom has integral value
104
-        if snap_to_pixel && (self.zoom - (self.zoom + 0.5).floor()).abs() < 1e-10 {
103
+        if snap_to_pixel {
105 104
             top_left_tile_screen_coord.snap_to_pixel();
106 105
         }
107 106
 

+ 167
- 8
src/map_view_gl.rs Parādīt failu

@@ -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;

+ 4
- 0
src/tile_atlas.rs Parādīt failu

@@ -256,6 +256,10 @@ impl TileAtlas {
256 256
             y2: f64::from(slot.y * sub_coord.size + sub_coord.y + 1) * scale_y,
257 257
         }
258 258
     }
259
+
260
+    pub fn texture(&self) -> &Texture {
261
+        &self.texture
262
+    }
259 263
 }
260 264
 
261 265
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]