From bf802a3a8e8aad611a4d64db23dca78e5bb83415 Mon Sep 17 00:00:00 2001
From: Imbris <hank.aa7@gmail.com>
Date: Wed, 20 Mar 2019 01:13:42 -0400
Subject: [PATCH] apply scizzor from conrod, replace [T; 4] with vek::Aabr<T>
 for ui rects

Former-commit-id: 4eaa8832ddda40882cc45c3a08c5de2fa5e68682
---
 voxygen/src/hud/chat.rs            |   1 -
 voxygen/src/render/pipelines/ui.rs |  16 +--
 voxygen/src/render/renderer.rs     |   8 +-
 voxygen/src/ui/mod.rs              | 184 +++++++++++++++++++++--------
 4 files changed, 149 insertions(+), 60 deletions(-)

diff --git a/voxygen/src/hud/chat.rs b/voxygen/src/hud/chat.rs
index f0a27dd42d..d951ed5ea3 100644
--- a/voxygen/src/hud/chat.rs
+++ b/voxygen/src/hud/chat.rs
@@ -108,7 +108,6 @@ impl Chat {
             .set(self.ids.message_box_bg, ui_widgets);
         let (mut items, scrollbar) = List::flow_down(self.messages.len())
             .middle_of(self.ids.message_box_bg)
-            // Why does scrollbar disappear when the list is the exact same height as its contents?
             .scrollbar_next_to()
             .scrollbar_thickness(20.0)
             .scrollbar_color(Color::Rgba(0.0, 0.0, 0.0, 1.0))
diff --git a/voxygen/src/render/pipelines/ui.rs b/voxygen/src/render/pipelines/ui.rs
index 76decb247a..7a1c72fb5d 100644
--- a/voxygen/src/render/pipelines/ui.rs
+++ b/voxygen/src/render/pipelines/ui.rs
@@ -1,4 +1,3 @@
-// Library
 use gfx::{
     self,
     // Macros
@@ -8,8 +7,7 @@ use gfx::{
     gfx_pipeline,
     gfx_pipeline_inner,
 };
-
-// Local
+use vek::*;
 use super::super::{
         Pipeline,
         TgtColorFmt,
@@ -68,8 +66,7 @@ impl Mode {
     }
 }
 
-// TODO: don't use [f32; 4] for rectangle as the format (eg 2 points vs point + dims) is ambiguous
-pub fn push_quad_to_mesh(mesh: &mut Mesh<UiPipeline>, rect: [f32; 4], uv_rect: [f32; 4], color: [f32; 4], mode: Mode) {
+pub fn push_quad_to_mesh(mesh: &mut Mesh<UiPipeline>, rect: Aabr<f32>, uv_rect: Aabr<f32>, color: [f32; 4], mode: Mode) {
     let mode_val = mode.value();
     let v = |pos, uv| {
         Vertex {
@@ -79,8 +76,13 @@ pub fn push_quad_to_mesh(mesh: &mut Mesh<UiPipeline>, rect: [f32; 4], uv_rect: [
             mode: mode_val,
         }
     };
-    let (l, t, r, b) = (rect[0], rect[1], rect[2], rect[3]);
-    let (uv_l, uv_t, uv_r, uv_b) = (uv_rect[0], uv_rect[1], uv_rect[2], uv_rect[3]);
+    let aabr_to_lbrt = |aabr: Aabr<f32>| (
+        aabr.min.x, aabr.min.y,
+        aabr.max.x, aabr.max.y,
+    );
+
+    let (l, b, r, t) = aabr_to_lbrt(rect);
+    let (uv_l, uv_b, uv_r, uv_t) = aabr_to_lbrt(uv_rect);
     mesh.push_quad(Quad::new(
         v([r, t], [uv_r, uv_t]),
         v([l, t], [uv_l, uv_t]),
diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs
index b8b5296c81..86a4ed7fa5 100644
--- a/voxygen/src/render/renderer.rs
+++ b/voxygen/src/render/renderer.rs
@@ -1,12 +1,9 @@
-// Library
 use vek::*;
 use gfx::{
     self,
     traits::{Device, FactoryExt},
 };
 use image;
-
-// Local
 use super::{
     consts::Consts,
     mesh::Mesh,
@@ -268,14 +265,15 @@ impl Renderer {
         &mut self,
         model: &Model<ui::UiPipeline>,
         tex: &Texture<ui::UiPipeline>,
+        scissor: Aabr<u16>,
     ) {
-        let (width, height) = self.get_resolution().map(|e| e).into_tuple();
+        let Aabr { min, max } = scissor;
         self.encoder.draw(
             &model.slice,
             &self.ui_pipeline.pso,
             &ui::pipe::Data {
                 vbuf: model.vbuf.clone(),
-                scissor: gfx::Rect { x: 0, y: 0, w: width, h: height },
+                scissor: gfx::Rect { x: min.x, y: min.y, w: max.x - min.x, h: max.y - min.y },
                 tex: (tex.srv.clone(), tex.sampler.clone()),
                 tgt_color: self.tgt_color_view.clone(),
                 tgt_depth: self.tgt_depth_view.clone(),
diff --git a/voxygen/src/ui/mod.rs b/voxygen/src/ui/mod.rs
index 027896b108..9399be660f 100644
--- a/voxygen/src/ui/mod.rs
+++ b/voxygen/src/ui/mod.rs
@@ -69,10 +69,31 @@ impl Cache {
     pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphCache<'static>, &Texture<UiPipeline>) { (&mut self.glyph_cache, &self.glyph_cache_tex) }
 }
 
-pub enum DrawCommand {
-    Image(Model<UiPipeline>, ImgId),
+enum DrawKind {
+    Image(ImgId),
     // Text and non-textured geometry
-    Plain(Model<UiPipeline>),
+    Plain,
+}
+enum DrawCommand {
+    Draw {
+        kind: DrawKind,
+        model: Model<UiPipeline>,
+    },
+    Scissor(Aabr<u16>),
+}
+impl DrawCommand {
+    fn image(model: Model<UiPipeline>, img_id: ImgId) -> DrawCommand {
+        DrawCommand::Draw {
+            kind: DrawKind::Image(img_id),
+            model,
+        }
+    }
+    fn plain(model: Model<UiPipeline>) -> DrawCommand {
+        DrawCommand::Draw {
+            kind: DrawKind::Plain,
+            model,
+        }
+    }
 }
 
 // How to scale the ui
@@ -109,14 +130,18 @@ impl Scale {
     pub fn scaling_mode(&mut self, mode: ScaleMode) {
         self.mode = mode;
     }
-    // Calculate factor to transform from logical coordinates to our scaled coordinates
-    fn scale_factor(&self) -> f64 {
+    // Calculate factor to transform between logical coordinates and our scaled coordinates
+    fn scale_factor_logical(&self) -> f64 {
         match self.mode {
             ScaleMode::Absolute(scale) => scale / self.dpi_factor,
             ScaleMode::DpiFactor => 1.0,
             ScaleMode::RelativeToWindow(dims) => (self.window_dims.x / dims.x).min(self.window_dims.y / dims.y),
         }
     }
+    // Calculate factor to transform between physical coordinates and our scaled coordinates
+    fn scale_factor_physical(&self) -> f64 {
+        self.scale_factor_logical() * self.dpi_factor
+    }
     // Updates internal window size (and/or dpi_factor)
     fn window_resized(&mut self, new_dims: Vec2<f64>, renderer: &Renderer) {
         self.dpi_factor = renderer.get_resolution().x as f64 / new_dims.x;
@@ -124,11 +149,11 @@ impl Scale {
     }
     // Get scaled window size
     fn scaled_window_size(&self) -> Vec2<f64> {
-        self.window_dims / self.scale_factor()
+        self.window_dims / self.scale_factor_logical()
     }
     // Transform point from logical to scaled coordinates
     fn scale_point(&self, point: Vec2<f64>) -> Vec2<f64> {
-        point / self.scale_factor()
+        point / self.scale_factor_logical()
     }
 }
 
@@ -225,23 +250,70 @@ impl Ui {
 
             let mut current_img = None;
 
+            let window_scizzor = default_scissor(renderer);
+            let mut current_scizzor = window_scizzor;
+
             // Switches to the `Plain` state and completes the previous `Command` if not already in the
             // `Plain` state.
             macro_rules! switch_to_plain_state {
                 () => {
                     if let Some(image_id) = current_img.take() {
-                        self.draw_commands.push(DrawCommand::Image(renderer.create_model(&mesh).unwrap(), image_id));
+                        self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap(), image_id));
                         mesh.clear();
                     }
                 };
             }
 
+            let p_scale_factor = self.scale.scale_factor_physical();
+
             while let Some(prim) = primitives.next() {
-                // TODO: Use scizzor
                 let Primitive {kind, scizzor, id, rect} = prim;
+
+                // Check for a change in the scizzor
+                let new_scizzor = {
+                    let (l, b, w, h) = scizzor.l_b_w_h();
+                    // Calculate minimum x and y coordinates while
+                    //  - flipping y axis (from +up to +down)
+                    //  - moving origin to top-left corner (from middle)
+                    let min_x = ui.win_w / 2.0 + l;
+                    let min_y = ui.win_h / 2.0 - b - h;
+                    Aabr {
+                        min: Vec2 {
+                            x: (min_x * p_scale_factor) as u16,
+                            y: (min_y * p_scale_factor) as u16,
+                        },
+                        max: Vec2 {
+                            x: ((min_x + w) * p_scale_factor) as u16,
+                            y: ((min_y + h) * p_scale_factor) as u16,
+                        }
+                    }
+                    .intersection(window_scizzor)
+                };
+                if new_scizzor != current_scizzor {
+                    // Finish the current command
+                    match current_img.take() {
+                        None =>
+                            self.draw_commands.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap())),
+                        Some(image_id) =>
+                            self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap(), image_id)),
+                    }
+                    mesh.clear();
+
+                    // Update the scizzor and produce a command.
+                    current_scizzor = new_scizzor;
+                    self.draw_commands.push(DrawCommand::Scissor(new_scizzor));
+                }
+
                 // Functions for converting for conrod scalar coords to GL vertex coords (-1.0 to 1.0)
                 let vx = |x: f64| (x / ui.win_w * 2.0) as f32;
                 let vy = |y: f64| (y / ui.win_h * 2.0) as f32;
+                let gl_aabr = |rect: conrod_core::Rect| {
+                    let (l, r, b, t) = rect.l_r_b_t();
+                    Aabr {
+                        min: Vec2::new(vx(l), vy(b)),
+                        max: Vec2::new(vx(r), vy(t)),
+                    }
+                };
 
                 use conrod_core::render::PrimitiveKind;
                 match kind {
@@ -255,13 +327,13 @@ impl Ui {
                             Some(image_id) if image_id == new_image_id => (),
                             // If we were in the `Plain` drawing state, switch to Image drawing state.
                             None => {
-                                self.draw_commands.push(DrawCommand::Plain(renderer.create_model(&mesh).unwrap()));
+                                self.draw_commands.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap()));
                                 mesh.clear();
                                 current_img = Some(new_image_id);
                             }
                             // If we were drawing a different image, switch state to draw *this* image.
                             Some(image_id) => {
-                                self.draw_commands.push(DrawCommand::Image(renderer.create_model(&mesh).unwrap(), image_id));
+                                self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap(), image_id));
                                 mesh.clear();
                                 current_img = Some(new_image_id);
                             }
@@ -286,13 +358,14 @@ impl Ui {
                             }
                             None => (0.0, 1.0, 0.0, 1.0),
                         };
-                        // Convert from conrod Scalar range to GL range -1.0 to 1.0.
-                        let (l, r, b, t) = rect.l_r_b_t();
-                        let (l, r, b, t) = (vx(l), vx(r), vy(b), vy(t));
+                        let uv = Aabr {
+                            min: Vec2::new(uv_l, uv_b),
+                            max: Vec2::new(uv_r, uv_t),
+                        };
                         push_ui_quad_to_mesh(
                             &mut mesh,
-                            [l, t , r, b],
-                            [uv_l, uv_t, uv_r, uv_b],
+                            gl_aabr(rect),
+                            uv,
                             color,
                             UiMode::Image,
                         );
@@ -300,7 +373,7 @@ impl Ui {
                     }
                     PrimitiveKind::Text { color, text, font_id } => {
                         switch_to_plain_state!();
-                        // Get screen width
+                        // Get screen width and height
                         let (screen_w, screen_h) = renderer.get_resolution().map(|e| e as f32).into_tuple();
                         // Calculate dpi factor
                         let dpi_factor = screen_w / ui.win_w as f32;
@@ -326,22 +399,24 @@ impl Ui {
 
                         for g in positioned_glyphs {
                             if let Ok(Some((uv_rect, screen_rect))) = glyph_cache.rect_for(font_id.index(), g) {
-                                let (uv_l, uv_r, uv_t, uv_b) = (
-                                    uv_rect.min.x,
-                                    uv_rect.max.x,
-                                    uv_rect.min.y,
-                                    uv_rect.max.y,
-                                );
-                                let (l, t, r, b) = (
-                                    (screen_rect.min.x as f32 / screen_w - 0.5) *  2.0,
-                                    (screen_rect.min.y as f32 / screen_h - 0.5) * -2.0,
-                                    (screen_rect.max.x as f32 / screen_w - 0.5) *  2.0,
-                                    (screen_rect.max.y as f32 / screen_h - 0.5) * -2.0,
-                                );
+                                let uv = Aabr {
+                                    min: Vec2::new(uv_rect.min.x, uv_rect.max.y),
+                                    max: Vec2::new(uv_rect.max.x, uv_rect.min.y),
+                                };
+                                let rect = Aabr {
+                                    min: Vec2::new(
+                                        (screen_rect.min.x as f32 / screen_w - 0.5) *  2.0,
+                                        (screen_rect.max.y as f32 / screen_h - 0.5) * -2.0,
+                                    ),
+                                    max: Vec2::new(
+                                        (screen_rect.max.x as f32 / screen_w - 0.5) *  2.0,
+                                        (screen_rect.min.y as f32 / screen_h - 0.5) * -2.0,
+                                    ),
+                                };
                                 push_ui_quad_to_mesh(
                                     &mut mesh,
-                                    [l, t , r, b],
-                                    [uv_l, uv_t, uv_r, uv_b],
+                                    rect,
+                                    uv,
                                     color,
                                     UiMode::Text,
                                 );
@@ -358,13 +433,13 @@ impl Ui {
 
                         switch_to_plain_state!();
 
-                        // Convert from conrod Scalar range to GL range -1.0 to 1.0.
-                        let (l, r, b, t) = rect.l_r_b_t();
-                        let (l, r, b, t) = (vx(l), vx(r), vy(b), vy(t));
                         push_ui_quad_to_mesh(
                             &mut mesh,
-                            [l, t , r, b],
-                            [0.0, 0.0, 0.0, 0.0],
+                            gl_aabr(rect),
+                            Aabr {
+                                min: Vec2::new(0.0, 0.0),
+                                max: Vec2::new(0.0, 0.0),
+                            },
                             color,
                             UiMode::Geometry,
                         );
@@ -401,12 +476,12 @@ impl Ui {
                     //PrimitiveKind::TrianglesMultiColor {..} => {println!("primitive kind multicolor with id {:?}", id);}
                 }
             }
-            // Enter the final command.
+            // Enter the final command
             match current_img {
                 None =>
-                    self.draw_commands.push(DrawCommand::Plain(renderer.create_model(&mesh).unwrap())),
+                    self.draw_commands.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap())),
                 Some(image_id) =>
-                    self.draw_commands.push(DrawCommand::Image(renderer.create_model(&mesh).unwrap(), image_id)),
+                    self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap(), image_id)),
             }
 
             // Handle window resizing
@@ -419,17 +494,32 @@ impl Ui {
     }
 
     pub fn render(&self, renderer: &mut Renderer) {
+        let mut scissor = default_scissor(renderer);
         for draw_command in self.draw_commands.iter() {
             match draw_command {
-                DrawCommand::Image(model, image_id) => {
-                    let tex = self.image_map.get(&image_id).expect("Image does not exist in image map");
-                    renderer.render_ui_element(&model, &tex);
-                },
-                DrawCommand::Plain(model) => {
-                    let tex = self.cache.glyph_cache_tex();
-                    renderer.render_ui_element(&model, &tex);
-                },
+                DrawCommand::Scissor(scizzor) => {
+                    scissor = *scizzor;
+                }
+                DrawCommand::Draw { kind, model } => {
+                    let tex = match kind {
+                        DrawKind::Image(image_id) => {
+                            self.image_map.get(&image_id).expect("Image does not exist in image map")
+                        }
+                        DrawKind::Plain => {
+                            self.cache.glyph_cache_tex()
+                        }
+                    };
+                    renderer.render_ui_element(&model, &tex, scissor);
+                }
             }
         }
     }
 }
+
+fn default_scissor(renderer: &mut Renderer) -> Aabr<u16> {
+    let (screen_w, screen_h) = renderer.get_resolution().map(|e| e as u16).into_tuple();
+    Aabr {
+        min: Vec2 { x: 0, y: 0 },
+        max: Vec2 { x: screen_w, y: screen_h }
+    }
+}