1#[derive(Copy, Clone, Debug, PartialEq, Eq)]
3pub struct Viewport {
4 pub x: u32,
5 pub y: u32,
6 pub width: u32,
7 pub height: u32,
8}
9
10impl Viewport {
11 pub fn full(framebuffer: [u32; 2]) -> Self {
12 Self {
13 x: 0,
14 y: 0,
15 width: framebuffer[0],
16 height: framebuffer[1],
17 }
18 }
19
20 pub fn right_of_left_panel(panel_width: u32, framebuffer: [u32; 2]) -> Self {
22 let panel = panel_width.min(framebuffer[0]);
23 Self {
24 x: panel,
25 y: 0,
26 width: framebuffer[0] - panel,
27 height: framebuffer[1],
28 }
29 }
30
31 pub fn apply(&self, rp: &mut wgpu::RenderPass<'_>) {
32 rp.set_viewport(
33 self.x as f32,
34 self.y as f32,
35 self.width as f32,
36 self.height as f32,
37 0.0,
38 1.0,
39 );
40 }
41
42 pub fn resolution_f32(&self) -> [f32; 2] {
43 [self.width as f32, self.height as f32]
44 }
45
46 pub fn split_horizontal(&self, n: u32) -> impl Iterator<Item = Viewport> {
48 let viewport = *self;
49 (0..n).map(move |i| {
50 let width = viewport.width / n;
51 Viewport {
52 x: viewport.x + i * width,
53 width: if i + 1 == n {
54 viewport.width - i * width
55 } else {
56 width
57 },
58 ..viewport
59 }
60 })
61 }
62
63 pub fn split_vertical(&self, n: u32) -> impl Iterator<Item = Viewport> {
64 let viewport = *self;
65 (0..n).map(move |i| {
66 let height = viewport.height / n;
67 Viewport {
68 y: viewport.y + i * height,
69 height: if i + 1 == n {
70 viewport.height - i * height
71 } else {
72 height
73 },
74 ..viewport
75 }
76 })
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn right_of_left_panel_clamps_when_panel_exceeds_framebuffer() {
86 let v = Viewport::right_of_left_panel(2000, [1280, 720]);
87 assert_eq!(v.x, 1280);
88 assert_eq!(v.width, 0);
89 }
90
91 #[test]
92 fn split_horizontal_tiles_without_gaps() {
93 let v = Viewport {
94 x: 100,
95 y: 50,
96 width: 17,
97 height: 30,
98 };
99 let cells: Vec<_> = v.split_horizontal(5).collect();
100 assert_eq!(cells.len(), 5);
101 assert_eq!(cells.first().unwrap().x, 100);
102 assert_eq!(
103 cells.last().unwrap().x + cells.last().unwrap().width,
104 100 + 17
105 );
106 for win in cells.windows(2) {
107 assert_eq!(win[0].x + win[0].width, win[1].x);
108 }
109 assert_eq!(cells[0].width, 3);
110 assert_eq!(cells[4].width, 5);
111 }
112
113 #[test]
114 fn split_horizontal_n_zero_returns_empty() {
115 let v = Viewport::full([100, 50]);
116 assert!(v.split_horizontal(0).next().is_none());
117 }
118}