1use collision::center_point;
2use context::Window;
3use sdl2::rect::Rect;
4
5fn calc_viewport_point(center_coord: f64, window_coord: f64, map_coord: f64) -> f64 {
8 let half = window_coord / 2.0;
9
10 ((center_coord - half).max(0.0))
11 .min((map_coord - window_coord).min((center_coord - half).abs()))
12}
13
14#[derive(Clone)]
17pub struct Viewport {
18 pub x: i32,
20 pub y: i32,
22 pub window_dimensions: (i32, i32),
24 pub map_dimensions: (i32, i32),
26}
27
28impl Viewport {
29 pub fn new(window: &Window, map_dimensions: (i32, i32)) -> Viewport {
30 Viewport {
31 x: 0,
32 y: 0,
33 window_dimensions: (window.width as i32, window.height as i32),
34 map_dimensions: map_dimensions,
35 }
36 }
37
38 pub fn set_position(&mut self, new_center: (i32, i32)) {
39 let new_x = calc_viewport_point(new_center.0 as f64,
40 self.window_dimensions.0 as f64,
41 self.map_dimensions.0 as f64);
42 let new_y = calc_viewport_point(new_center.1 as f64,
43 self.window_dimensions.1 as f64,
44 self.map_dimensions.1 as f64);
45
46 self.x = new_x as i32;
47 self.y = new_y as i32;
48 }
49
50 pub fn in_viewport(&self, point: (i32, i32)) -> bool {
52 let margin = 32;
53
54 let (v_min_x, v_max_x) = (self.x - margin, self.x + self.window_dimensions.0);
55 let (v_min_y, v_max_y) = (self.y - margin, self.y + self.window_dimensions.1);
56
57 point.0 >= v_min_x && point.0 <= v_max_x && point.1 >= v_min_y && point.1 <= v_max_y
58 }
59
60 pub fn relative_point(&self, map_point: (i32, i32)) -> (i32, i32) {
62 (map_point.0 - self.x, map_point.1 - self.y)
63 }
64
65 pub fn constrain_to_viewport(&self, rect: &Rect) -> Option<Rect> {
67 let rect_points = [(rect.x(), rect.y()),
68 (rect.x() + (rect.width() as i32), rect.y()),
69 (rect.x(), rect.y() + (rect.height() as i32)),
70 (rect.x() + (rect.width() as i32), rect.y() + (rect.height() as i32))];
71
72 let mut in_viewport = false;
73 for point in rect_points.iter() {
74 if self.in_viewport(*point) {
75 in_viewport = true;
76 break;
77 }
78 }
79
80 if in_viewport {
81 let center = center_point(rect);
82 let (x, y) = self.relative_point((center.0 as i32, center.1 as i32));
83 Some(Rect::new_unwrap(x, y, rect.width(), rect.height()))
84 } else {
85 None
86 }
87 }
88}