apply scizzor from conrod, replace [T; 4] with vek::Aabr<T> for ui rects

Former-commit-id: 4eaa8832ddda40882cc45c3a08c5de2fa5e68682
This commit is contained in:
Imbris 2019-03-20 01:13:42 -04:00
parent d82adb7e71
commit b0009f9e14
4 changed files with 149 additions and 60 deletions

View File

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

View File

@ -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]),

View File

@ -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(),

View File

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