From caea30a34f9626c5a2a0dda17c3330c7efd35f5e Mon Sep 17 00:00:00 2001 From: Imbris Date: Thu, 25 Apr 2019 09:25:56 -0400 Subject: [PATCH 1/7] make ui ignore resize to <1.0 events Former-commit-id: d4baa8234f6c25f2c28c07c1dbf06e6c191a4127 --- voxygen/src/ui/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voxygen/src/ui/mod.rs b/voxygen/src/ui/mod.rs index 71c2d2db64..8f296d0672 100644 --- a/voxygen/src/ui/mod.rs +++ b/voxygen/src/ui/mod.rs @@ -309,7 +309,7 @@ impl Ui { } pub fn handle_event(&mut self, event: Event) { match event.0 { - Input::Resize(w, h) => self.window_resized = Some(Vec2::new(w, h)), + Input::Resize(w, h) if w > 1.0 && h > 1.0 => self.window_resized = Some(Vec2::new(w, h)), Input::Touch(touch) => self.ui.handle_event(Input::Touch(Touch { xy: self.scale.scale_point(touch.xy.into()).into_array(), ..touch From 13350856db938d1fd037835f3e2c9ceee68b788e Mon Sep 17 00:00:00 2001 From: Imbris Date: Thu, 25 Apr 2019 16:20:44 -0400 Subject: [PATCH 2/7] small cleanup Former-commit-id: 2996ce0cf33337bf52810f1e52b2c02d6eba5c7f --- voxygen/src/ui/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/voxygen/src/ui/mod.rs b/voxygen/src/ui/mod.rs index 8f296d0672..c3d9225a32 100644 --- a/voxygen/src/ui/mod.rs +++ b/voxygen/src/ui/mod.rs @@ -375,8 +375,8 @@ impl Ui { let Primitive { kind, scizzor, - id: _id, rect, + ... } = prim; // Check for a change in the scizzor @@ -441,7 +441,7 @@ impl Ui { _ => {} } - // Switch to the `Image` state for this image if we're not in it already. + // Switch to the image state if we are not in it already if let State::Plain = current_state { self.draw_commands .push(DrawCommand::plain(renderer.create_model(&mesh).unwrap())); From 89c06e8359edfa3ac652d5b39c2405773a29cc1b Mon Sep 17 00:00:00 2001 From: Imbris Date: Fri, 26 Apr 2019 00:29:35 -0400 Subject: [PATCH 3/7] split up voxygen/src/ui/mod.rs Former-commit-id: e220b1ce38f93fbb295c9aae3591e4b3899f57e4 --- voxygen/src/ui/cache.rs | 54 ++++++++++++ voxygen/src/ui/event.rs | 47 +++++++++++ voxygen/src/ui/mod.rs | 180 ++++------------------------------------ voxygen/src/ui/scale.rs | 65 +++++++++++++++ 4 files changed, 183 insertions(+), 163 deletions(-) create mode 100644 voxygen/src/ui/cache.rs create mode 100644 voxygen/src/ui/event.rs create mode 100644 voxygen/src/ui/scale.rs diff --git a/voxygen/src/ui/cache.rs b/voxygen/src/ui/cache.rs new file mode 100644 index 0000000000..b111222768 --- /dev/null +++ b/voxygen/src/ui/cache.rs @@ -0,0 +1,54 @@ +use super::graphic::{Graphic, GraphicCache, Id as GraphicId}; +use crate::{ + render::{Renderer, Texture, UiPipeline}, + Error, +}; +use conrod_core::text::GlyphCache; +use vek::*; + +pub struct Cache { + glyph_cache: GlyphCache<'static>, + glyph_cache_tex: Texture, + graphic_cache: GraphicCache, + graphic_cache_tex: Texture, +} + +// TODO: Should functions be returning UiError instead of Error? +impl Cache { + pub fn new(renderer: &mut Renderer) -> Result { + let (w, h) = renderer.get_resolution().into_tuple(); + const SCALE_TOLERANCE: f32 = 0.1; + const POSITION_TOLERANCE: f32 = 0.1; + + let graphic_cache_dims = Vec2::new(w * 4, h * 4); + Ok(Self { + glyph_cache: GlyphCache::builder() + .dimensions(w as u32, h as u32) + .scale_tolerance(SCALE_TOLERANCE) + .position_tolerance(POSITION_TOLERANCE) + .build(), + glyph_cache_tex: renderer.create_dynamic_texture((w, h).into())?, + graphic_cache: GraphicCache::new(graphic_cache_dims), + graphic_cache_tex: renderer.create_dynamic_texture(graphic_cache_dims)?, + }) + } + pub fn glyph_cache_tex(&self) -> &Texture { + &self.glyph_cache_tex + } + pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphCache<'static>, &Texture) { + (&mut self.glyph_cache, &self.glyph_cache_tex) + } + pub fn graphic_cache_tex(&self) -> &Texture { + &self.graphic_cache_tex + } + pub fn graphic_cache_mut_and_tex(&mut self) -> (&mut GraphicCache, &Texture) { + (&mut self.graphic_cache, &self.graphic_cache_tex) + } + pub fn add_graphic(&mut self, graphic: Graphic) -> GraphicId { + self.graphic_cache.add_graphic(graphic) + } + pub fn clear_graphic_cache(&mut self, renderer: &mut Renderer, new_size: Vec2) { + self.graphic_cache.clear_cache(new_size); + self.graphic_cache_tex = renderer.create_dynamic_texture(new_size).unwrap(); + } +} diff --git a/voxygen/src/ui/event.rs b/voxygen/src/ui/event.rs new file mode 100644 index 0000000000..161df0ab64 --- /dev/null +++ b/voxygen/src/ui/event.rs @@ -0,0 +1,47 @@ +use conrod_core::{event::Input, input::Button}; +use vek::*; + +#[derive(Clone)] +pub struct Event(pub Input); +impl Event { + pub fn try_from(event: glutin::Event, window: &glutin::GlWindow) -> Option { + use conrod_winit::*; + use winit; + // A wrapper around the winit window that allows us to implement the trait necessary for enabling + // the winit <-> conrod conversion functions. + struct WindowRef<'a>(&'a winit::Window); + + // Implement the `WinitWindow` trait for `WindowRef` to allow for generating compatible conversion + // functions. + impl<'a> conrod_winit::WinitWindow for WindowRef<'a> { + fn get_inner_size(&self) -> Option<(u32, u32)> { + winit::Window::get_inner_size(&self.0).map(Into::into) + } + fn hidpi_factor(&self) -> f32 { + winit::Window::get_hidpi_factor(&self.0) as _ + } + } + convert_event!(event, &WindowRef(window.window())).map(|input| Self(input)) + } + pub fn is_keyboard_or_mouse(&self) -> bool { + match self.0 { + Input::Press(_) + | Input::Release(_) + | Input::Motion(_) + | Input::Touch(_) + | Input::Text(_) => true, + _ => false, + } + } + pub fn is_keyboard(&self) -> bool { + match self.0 { + Input::Press(Button::Keyboard(_)) + | Input::Release(Button::Keyboard(_)) + | Input::Text(_) => true, + _ => false, + } + } + pub fn new_resize(dims: Vec2) -> Self { + Self(Input::Resize(dims.x, dims.y)) + } +} diff --git a/voxygen/src/ui/mod.rs b/voxygen/src/ui/mod.rs index c3d9225a32..689fcf6b29 100644 --- a/voxygen/src/ui/mod.rs +++ b/voxygen/src/ui/mod.rs @@ -1,4 +1,7 @@ +mod cache; +mod event; mod graphic; +mod scale; mod util; mod widgets; #[macro_use] @@ -6,129 +9,41 @@ mod img_ids; #[macro_use] mod font_ids; +pub use event::Event; pub use graphic::Graphic; pub use img_ids::{BlankGraphic, GraphicCreator, ImageGraphic, VoxelGraphic}; -pub(self) use util::{linear_to_srgb, srgb_to_linear}; +pub use scale::ScaleMode; pub use widgets::toggle_button::ToggleButton; use crate::{ render::{ - create_ui_quad, create_ui_tri, Mesh, Model, RenderError, Renderer, Texture, UiMode, - UiPipeline, + create_ui_quad, create_ui_tri, Mesh, Model, RenderError, Renderer, UiMode, UiPipeline, }, window::Window, Error, }; +use cache::Cache; use common::assets; use conrod_core::{ event::Input, graph::Graph, image::{Id as ImgId, Map}, - input::{touch::Touch, Button, Motion, Widget}, + input::{touch::Touch, Motion, Widget}, render::Primitive, - text::{self, GlyphCache}, + text::{self, font}, widget::{id::Generator, Id as WidgId}, Ui as CrUi, UiBuilder, UiCell, }; -use graphic::{GraphicCache, Id as GraphicId}; +use graphic::Id as GraphicId; +use scale::Scale; use std::sync::Arc; +use util::{linear_to_srgb, srgb_to_linear}; use vek::*; #[derive(Debug)] pub enum UiError { RenderError(RenderError), } -#[derive(Clone)] -pub struct Event(Input); -impl Event { - pub fn try_from(event: glutin::Event, window: &glutin::GlWindow) -> Option { - use conrod_winit::*; - use winit; - // A wrapper around the winit window that allows us to implement the trait necessary for enabling - // the winit <-> conrod conversion functions. - struct WindowRef<'a>(&'a winit::Window); - - // Implement the `WinitWindow` trait for `WindowRef` to allow for generating compatible conversion - // functions. - impl<'a> conrod_winit::WinitWindow for WindowRef<'a> { - fn get_inner_size(&self) -> Option<(u32, u32)> { - winit::Window::get_inner_size(&self.0).map(Into::into) - } - fn hidpi_factor(&self) -> f32 { - winit::Window::get_hidpi_factor(&self.0) as _ - } - } - convert_event!(event, &WindowRef(window.window())).map(|input| Self(input)) - } - pub fn is_keyboard_or_mouse(&self) -> bool { - match self.0 { - Input::Press(_) - | Input::Release(_) - | Input::Motion(_) - | Input::Touch(_) - | Input::Text(_) => true, - _ => false, - } - } - pub fn is_keyboard(&self) -> bool { - match self.0 { - Input::Press(Button::Keyboard(_)) - | Input::Release(Button::Keyboard(_)) - | Input::Text(_) => true, - _ => false, - } - } - pub fn new_resize(dims: Vec2) -> Self { - Self(Input::Resize(dims.x, dims.y)) - } -} - -pub struct Cache { - glyph_cache: GlyphCache<'static>, - glyph_cache_tex: Texture, - graphic_cache: graphic::GraphicCache, - graphic_cache_tex: Texture, -} - -// TODO: Should functions be returning UiError instead of Error? -impl Cache { - pub fn new(renderer: &mut Renderer) -> Result { - let (w, h) = renderer.get_resolution().into_tuple(); - const SCALE_TOLERANCE: f32 = 0.1; - const POSITION_TOLERANCE: f32 = 0.1; - - let graphic_cache_dims = Vec2::new(w * 4, h * 4); - Ok(Self { - glyph_cache: GlyphCache::builder() - .dimensions(w as u32, h as u32) - .scale_tolerance(SCALE_TOLERANCE) - .position_tolerance(POSITION_TOLERANCE) - .build(), - glyph_cache_tex: renderer.create_dynamic_texture((w, h).into())?, - graphic_cache: GraphicCache::new(graphic_cache_dims), - graphic_cache_tex: renderer.create_dynamic_texture(graphic_cache_dims)?, - }) - } - pub fn glyph_cache_tex(&self) -> &Texture { - &self.glyph_cache_tex - } - pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphCache<'static>, &Texture) { - (&mut self.glyph_cache, &self.glyph_cache_tex) - } - pub fn graphic_cache_tex(&self) -> &Texture { - &self.graphic_cache_tex - } - pub fn graphic_cache_mut_and_tex(&mut self) -> (&mut GraphicCache, &Texture) { - (&mut self.graphic_cache, &self.graphic_cache_tex) - } - pub fn add_graphic(&mut self, graphic: Graphic) -> GraphicId { - self.graphic_cache.add_graphic(graphic) - } - pub fn clear_graphic_cache(&mut self, renderer: &mut Renderer, new_size: Vec2) { - self.graphic_cache.clear_cache(new_size); - self.graphic_cache_tex = renderer.create_dynamic_texture(new_size).unwrap(); - } -} enum DrawKind { Image, @@ -157,69 +72,6 @@ impl DrawCommand { } } -// How to scale the ui -pub enum ScaleMode { - // Scale against physical size - Absolute(f64), - // Use the dpi factor provided by the windowing system (i.e. use logical size) - DpiFactor, - // Scale based on the window's physical size, but maintain aspect ratio of widgets - // Contains width and height of the "default" window size (ie where there should be no scaling) - RelativeToWindow(Vec2), -} - -struct Scale { - // Type of scaling to use - mode: ScaleMode, - // Current dpi factor - dpi_factor: f64, - // Current logical window size - window_dims: Vec2, -} - -impl Scale { - fn new(window: &Window, mode: ScaleMode) -> Self { - let window_dims = window.logical_size(); - let dpi_factor = window.renderer().get_resolution().x as f64 / window_dims.x; - Scale { - mode, - dpi_factor, - window_dims, - } - } - // Change the scaling mode - pub fn scaling_mode(&mut self, mode: ScaleMode) { - self.mode = mode; - } - // 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, renderer: &Renderer) { - self.dpi_factor = renderer.get_resolution().x as f64 / new_dims.x; - self.window_dims = new_dims; - } - // Get scaled window size - fn scaled_window_size(&self) -> Vec2 { - self.window_dims / self.scale_factor_logical() - } - // Transform point from logical to scaled coordinates - fn scale_point(&self, point: Vec2) -> Vec2 { - point / self.scale_factor_logical() - } -} - pub struct Font(text::Font); impl assets::Asset for Font { fn load(specifier: &str) -> Result { @@ -268,7 +120,7 @@ impl Ui { self.image_map.insert(self.cache.add_graphic(graphic)) } - pub fn new_font(&mut self, mut font: Arc) -> text::font::Id { + pub fn new_font(&mut self, mut font: Arc) -> font::Id { self.ui.fonts.insert(font.as_ref().0.clone()) } @@ -309,7 +161,9 @@ impl Ui { } pub fn handle_event(&mut self, event: Event) { match event.0 { - Input::Resize(w, h) if w > 1.0 && h > 1.0 => self.window_resized = Some(Vec2::new(w, h)), + Input::Resize(w, h) if w > 1.0 && h > 1.0 => { + self.window_resized = Some(Vec2::new(w, h)) + } Input::Touch(touch) => self.ui.handle_event(Input::Touch(Touch { xy: self.scale.scale_point(touch.xy.into()).into_array(), ..touch @@ -376,7 +230,7 @@ impl Ui { kind, scizzor, rect, - ... + .. } = prim; // Check for a change in the scizzor diff --git a/voxygen/src/ui/scale.rs b/voxygen/src/ui/scale.rs new file mode 100644 index 0000000000..2daae0506a --- /dev/null +++ b/voxygen/src/ui/scale.rs @@ -0,0 +1,65 @@ +use crate::{render::Renderer, window::Window}; +use vek::*; + +// How the ui is scaled +pub enum ScaleMode { + // Scale against physical size + Absolute(f64), + // Use the dpi factor provided by the windowing system (i.e. use logical size) + DpiFactor, + // Scale based on the window's physical size, but maintain aspect ratio of widgets + // Contains width and height of the "default" window size (ie where there should be no scaling) + RelativeToWindow(Vec2), +} + +pub struct Scale { + // Type of scaling to use + mode: ScaleMode, + // Current dpi factor + dpi_factor: f64, + // Current logical window size + window_dims: Vec2, +} + +impl Scale { + pub fn new(window: &Window, mode: ScaleMode) -> Self { + let window_dims = window.logical_size(); + let dpi_factor = window.renderer().get_resolution().x as f64 / window_dims.x; + Scale { + mode, + dpi_factor, + window_dims, + } + } + // Change the scaling mode + pub fn scaling_mode(&mut self, mode: ScaleMode) { + self.mode = mode; + } + // Calculate factor to transform between logical coordinates and our scaled coordinates + pub 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 + pub fn scale_factor_physical(&self) -> f64 { + self.scale_factor_logical() * self.dpi_factor + } + // Updates internal window size (and/or dpi_factor) + pub fn window_resized(&mut self, new_dims: Vec2, renderer: &Renderer) { + self.dpi_factor = renderer.get_resolution().x as f64 / new_dims.x; + self.window_dims = new_dims; + } + // Get scaled window size + pub fn scaled_window_size(&self) -> Vec2 { + self.window_dims / self.scale_factor_logical() + } + // Transform point from logical to scaled coordinates + pub fn scale_point(&self, point: Vec2) -> Vec2 { + point / self.scale_factor_logical() + } +} From 9c07dcfceed0562fc3d6730a54ebc11e93b1223a Mon Sep 17 00:00:00 2001 From: Imbris Date: Thu, 2 May 2019 18:42:04 -0400 Subject: [PATCH 4/7] multiply image color by supplied color Former-commit-id: c5e4ccde88d7170db7aa4d3bfce3e0ba1cf5e8c9 --- voxygen/shaders/ui.frag | 20 ++++++++++---------- voxygen/shaders/ui.vert | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/voxygen/shaders/ui.frag b/voxygen/shaders/ui.frag index 778d28d28c..7ef02c68b5 100644 --- a/voxygen/shaders/ui.frag +++ b/voxygen/shaders/ui.frag @@ -9,14 +9,14 @@ uniform sampler2D u_tex; out vec4 tgt_color; void main() { - // Text - if (f_mode == uint(0)) { - tgt_color = f_color * vec4(1.0, 1.0, 1.0, texture(u_tex, f_uv).a); - // Image - } else if (f_mode == uint(1)) { - tgt_color = texture(u_tex, f_uv); - // 2D Geometry - } else if (f_mode == uint(2)) { - tgt_color = f_color; - } + // Text + if (f_mode == uint(0)) { + tgt_color = f_color * vec4(1.0, 1.0, 1.0, texture(u_tex, f_uv).a); + // Image + } else if (f_mode == uint(1)) { + tgt_color = f_color * texture(u_tex, f_uv); + // 2D Geometry + } else if (f_mode == uint(2)) { + tgt_color = f_color; + } } diff --git a/voxygen/shaders/ui.vert b/voxygen/shaders/ui.vert index f2e956e62f..ab90588fc3 100644 --- a/voxygen/shaders/ui.vert +++ b/voxygen/shaders/ui.vert @@ -12,8 +12,8 @@ flat out uint f_mode; out vec4 f_color; void main() { - f_uv = v_uv; - f_color = v_color; - gl_Position = vec4(v_pos, 0.0, 1.0); - f_mode = v_mode; + f_uv = v_uv; + f_color = v_color; + gl_Position = vec4(v_pos, 0.0, 1.0); + f_mode = v_mode; } From b99a8dea39227dbb5b6c014715956b428e9f80a0 Mon Sep 17 00:00:00 2001 From: Imbris Date: Sat, 4 May 2019 10:28:21 -0400 Subject: [PATCH 5/7] Stop recreating vertex buffers for ui Former-commit-id: 6e9326d1bca942e4da70281e3d86b624f9d2504a --- voxygen/src/render/mod.rs | 3 +- voxygen/src/render/model.rs | 53 +++- voxygen/src/render/renderer.rs | 21 +- voxygen/src/ui/mod.rs | 564 +++++++++++++++++---------------- 4 files changed, 356 insertions(+), 285 deletions(-) diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 511bdd2fc5..7c9e50f42c 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -10,7 +10,7 @@ mod util; pub use self::{ consts::Consts, mesh::{Mesh, Quad, Tri}, - model::Model, + model::{DynamicModel, Model}, pipelines::{ figure::{BoneData as FigureBoneData, FigurePipeline, Locals as FigureLocals}, postprocess::{ @@ -40,6 +40,7 @@ pub enum RenderError { UpdateError(gfx::UpdateError), TexUpdateError(gfx::UpdateError<[u16; 3]>), CombinedError(gfx::CombinedError), + BufferCreationError(gfx::buffer::CreationError), } /// Used to represent a specific rendering configuration. diff --git a/voxygen/src/render/model.rs b/voxygen/src/render/model.rs index df7a3d3958..ea5e645230 100644 --- a/voxygen/src/render/model.rs +++ b/voxygen/src/render/model.rs @@ -1,8 +1,11 @@ -// Library -use gfx::{self, traits::FactoryExt}; - -// Local -use super::{gfx_backend, mesh::Mesh, Pipeline}; +use super::{gfx_backend, mesh::Mesh, Pipeline, RenderError}; +use gfx::{ + buffer::Role, + memory::{Bind, Usage}, + traits::FactoryExt, + Factory, +}; +use std::ops::Range; /// Represents a mesh that has been sent to the GPU. pub struct Model { @@ -24,3 +27,43 @@ impl Model

{ } } } + +/// Represents a mesh on the GPU which can be updated dynamically +pub struct DynamicModel { + pub vbuf: gfx::handle::Buffer, +} + +impl DynamicModel

{ + pub fn new(factory: &mut gfx_backend::Factory, size: usize) -> Result { + Ok(Self { + vbuf: factory + .create_buffer(size, Role::Vertex, Usage::Dynamic, Bind::empty()) + .map_err(|err| RenderError::BufferCreationError(err))?, + }) + } + + /// Create a model with a slice of a portion of this model to send to the renderer + pub fn submodel(&self, range: Range) -> Model

{ + Model { + vbuf: self.vbuf.clone(), + slice: gfx::Slice { + start: range.start as u32, + end: range.end as u32, + base_vertex: 0, + instances: None, + buffer: gfx::IndexBuffer::Auto, + }, + } + } + + pub fn update( + &self, + encoder: &mut gfx::Encoder, + mesh: &Mesh

, + offset: usize, + ) -> Result<(), RenderError> { + encoder + .update_buffer(&self.vbuf, mesh.vertices(), offset) + .map_err(|err| RenderError::UpdateError(err)) + } +} diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index bc553ae536..6c860ca069 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -2,7 +2,7 @@ use super::{ consts::Consts, gfx_backend, mesh::Mesh, - model::Model, + model::{DynamicModel, Model}, pipelines::{figure, postprocess, skybox, terrain, ui, Globals}, texture::Texture, Pipeline, RenderError, @@ -12,7 +12,6 @@ use gfx::{ handle::Sampler, traits::{Device, Factory, FactoryExt}, }; -use image; use vek::*; /// Represents the format of the pre-processed color target. @@ -246,6 +245,24 @@ impl Renderer { Ok(Model::new(&mut self.factory, mesh)) } + /// Create a new dynamic model with the specified size + pub fn create_dynamic_model( + &mut self, + size: usize, + ) -> Result, RenderError> { + DynamicModel::new(&mut self.factory, size) + } + + /// Update a dynamic model with a mesh and a offset + pub fn update_model( + &mut self, + model: &DynamicModel

, + mesh: &Mesh

, + offset: usize, + ) -> Result<(), RenderError> { + model.update(&mut self.encoder, mesh, offset) + } + /// Create a new texture from the provided image. pub fn create_texture( &mut self, diff --git a/voxygen/src/ui/mod.rs b/voxygen/src/ui/mod.rs index 689fcf6b29..43c6000cf9 100644 --- a/voxygen/src/ui/mod.rs +++ b/voxygen/src/ui/mod.rs @@ -17,7 +17,8 @@ pub use widgets::toggle_button::ToggleButton; use crate::{ render::{ - create_ui_quad, create_ui_tri, Mesh, Model, RenderError, Renderer, UiMode, UiPipeline, + create_ui_quad, create_ui_tri, DynamicModel, Mesh, RenderError, Renderer, UiMode, + UiPipeline, }, window::Window, Error, @@ -36,6 +37,7 @@ use conrod_core::{ }; use graphic::Id as GraphicId; use scale::Scale; +use std::ops::Range; use std::sync::Arc; use util::{linear_to_srgb, srgb_to_linear}; use vek::*; @@ -51,23 +53,20 @@ enum DrawKind { Plain, } enum DrawCommand { - Draw { - kind: DrawKind, - model: Model, - }, + Draw { kind: DrawKind, verts: Range }, Scissor(Aabr), } impl DrawCommand { - fn image(model: Model) -> DrawCommand { + fn image(verts: Range) -> DrawCommand { DrawCommand::Draw { kind: DrawKind::Image, - model, + verts, } } - fn plain(model: Model) -> DrawCommand { + fn plain(verts: Range) -> DrawCommand { DrawCommand::Draw { kind: DrawKind::Plain, - model, + verts, } } } @@ -87,6 +86,8 @@ pub struct Ui { cache: Cache, // Draw commands for the next render draw_commands: Vec, + // Model for drawing the ui + model: DynamicModel, // Stores new window size for updating scaling window_resized: Option>, // Scaling of the ui @@ -102,8 +103,9 @@ impl Ui { ui: UiBuilder::new(win_dims).build(), image_map: Map::new(), cache: Cache::new(window.renderer_mut())?, - window_resized: None, draw_commands: vec![], + model: window.renderer_mut().create_dynamic_model(100)?, + window_resized: None, scale, }) } @@ -192,308 +194,315 @@ impl Ui { } pub fn maintain(&mut self, renderer: &mut Renderer) { - let ref mut ui = self.ui; // Regenerate draw commands and associated models only if the ui changed - if let Some(mut primitives) = ui.draw_if_changed() { - self.draw_commands.clear(); - let mut mesh = Mesh::new(); + let mut primitives = match self.ui.draw_if_changed() { + Some(primitives) => primitives, + None => return, + }; - // TODO: this could be removed entirely if the draw call just used both textures - // however this allows for flexibility if we want to interleave other draw calls later - enum State { - Image, - Plain, + self.draw_commands.clear(); + let mut mesh = Mesh::new(); + + // TODO: this could be removed entirely if the draw call just used both textures + // however this allows for flexibility if we want to interleave other draw calls later + enum State { + Image, + Plain, + }; + + let mut current_state = State::Plain; + let mut start = 0; + + 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 State::Image = current_state { + self.draw_commands + .push(DrawCommand::image(start..mesh.vertices().len())); + current_state = State::Plain; + start = mesh.vertices().len(); + } }; + } - let mut current_state = State::Plain; + let p_scale_factor = self.scale.scale_factor_physical(); - let window_scizzor = default_scissor(renderer); - let mut current_scizzor = window_scizzor; + while let Some(prim) = primitives.next() { + let Primitive { + kind, + scizzor, + rect, + .. + } = prim; - // 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 State::Image = current_state { - self.draw_commands - .push(DrawCommand::image(renderer.create_model(&mesh).unwrap())); - mesh.clear(); - current_state = State::Plain; - } - }; + // 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 = self.ui.win_w / 2.0 + l; + let min_y = self.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 + self.draw_commands.push(match current_state { + State::Plain => DrawCommand::plain(start..mesh.vertices().len()), + State::Image => DrawCommand::image(start..mesh.vertices().len()), + }); + start = mesh.vertices().len(); + + // Update the scizzor and produce a command. + current_scizzor = new_scizzor; + self.draw_commands.push(DrawCommand::Scissor(new_scizzor)); } - let p_scale_factor = self.scale.scale_factor_physical(); - - while let Some(prim) = primitives.next() { - let Primitive { - kind, - scizzor, - 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 - self.draw_commands.push(match current_state { - State::Plain => DrawCommand::plain(renderer.create_model(&mesh).unwrap()), - State::Image => DrawCommand::image(renderer.create_model(&mesh).unwrap()), - }); - 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 ui_win_w = self.ui.win_w; + let ui_win_h = self.ui.win_h; + 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)), } + }; - // 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 { + PrimitiveKind::Image { + image_id, + color, + source_rect, + } => { + let graphic_id = self + .image_map + .get(&image_id) + .expect("Image does not exist in image map"); + let (graphic_cache, cache_tex) = self.cache.graphic_cache_mut_and_tex(); + + match graphic_cache.get_graphic(*graphic_id) { + Some(Graphic::Blank) | None => continue, + _ => {} } - }; - use conrod_core::render::PrimitiveKind; - match kind { - PrimitiveKind::Image { - image_id, - color, - source_rect, - } => { - let graphic_id = self - .image_map - .get(&image_id) - .expect("Image does not exist in image map"); - let (graphic_cache, cache_tex) = self.cache.graphic_cache_mut_and_tex(); + // Switch to the image state if we are not in it already + if let State::Plain = current_state { + self.draw_commands + .push(DrawCommand::plain(start..mesh.vertices().len())); + start = mesh.vertices().len(); + current_state = State::Image; + } - match graphic_cache.get_graphic(*graphic_id) { - Some(Graphic::Blank) | None => continue, - _ => {} + let color = + srgb_to_linear(color.unwrap_or(conrod_core::color::WHITE).to_fsa().into()); + + let resolution = Vec2::new( + (rect.w() * p_scale_factor) as u16, + (rect.h() * p_scale_factor) as u16, + ); + // Transform the source rectangle into uv coordinate + // TODO: make sure this is right + let source_aabr = { + let (uv_l, uv_r, uv_b, uv_t) = (0.0, 1.0, 0.0, 1.0); /*match source_rect { + Some(src_rect) => { + let (l, r, b, t) = src_rect.l_r_b_t(); + ((l / image_w) as f32, + (r / image_w) as f32, + (b / image_h) as f32, + (t / image_h) as f32) + } + None => (0.0, 1.0, 0.0, 1.0), + };*/ + Aabr { + min: Vec2::new(uv_l, uv_b), + max: Vec2::new(uv_r, uv_t), } + }; + let (cache_w, cache_h) = + cache_tex.get_dimensions().map(|e| e as f32).into_tuple(); - // Switch to the image state if we are not in it already - if let State::Plain = current_state { - self.draw_commands - .push(DrawCommand::plain(renderer.create_model(&mesh).unwrap())); - mesh.clear(); - current_state = State::Image; - } + // Cache graphic at particular resolution + let uv_aabr = match graphic_cache.cache_res( + *graphic_id, + resolution, + source_aabr, + |aabr, data| { + let offset = aabr.min.into_array(); + let size = aabr.size().into_array(); + renderer.update_texture(cache_tex, offset, size, &data); + }, + ) { + Some(aabr) => Aabr { + min: Vec2::new( + aabr.min.x as f32 / cache_w, + aabr.max.y as f32 / cache_h, + ), + max: Vec2::new( + aabr.max.x as f32 / cache_w, + aabr.min.y as f32 / cache_h, + ), + }, + None => continue, + }; - let color = srgb_to_linear( - color.unwrap_or(conrod_core::color::WHITE).to_fsa().into(), - ); + mesh.push_quad(create_ui_quad(gl_aabr(rect), uv_aabr, color, UiMode::Image)); + } + PrimitiveKind::Text { + color, + text, + font_id, + } => { + switch_to_plain_state!(); + // 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; - let resolution = Vec2::new( - (rect.w() * p_scale_factor) as u16, - (rect.h() * p_scale_factor) as u16, - ); - // Transform the source rectangle into uv coordinate - // TODO: make sure this is right - let source_aabr = { - let (uv_l, uv_r, uv_b, uv_t) = (0.0, 1.0, 0.0, 1.0); /*match source_rect { - Some(src_rect) => { - let (l, r, b, t) = src_rect.l_r_b_t(); - ((l / image_w) as f32, - (r / image_w) as f32, - (b / image_h) as f32, - (t / image_h) as f32) - } - None => (0.0, 1.0, 0.0, 1.0), - };*/ - Aabr { - min: Vec2::new(uv_l, uv_b), - max: Vec2::new(uv_r, uv_t), - } - }; - let (cache_w, cache_h) = - cache_tex.get_dimensions().map(|e| e as f32).into_tuple(); + let positioned_glyphs = text.positioned_glyphs(dpi_factor); + let (glyph_cache, cache_tex) = self.cache.glyph_cache_mut_and_tex(); + // Queue the glyphs to be cached + for glyph in positioned_glyphs { + glyph_cache.queue_glyph(font_id.index(), glyph.clone()); + } - // Cache graphic at particular resolution - let uv_aabr = match graphic_cache.cache_res( - *graphic_id, - resolution, - source_aabr, - |aabr, data| { - let offset = aabr.min.into_array(); - let size = aabr.size().into_array(); - renderer.update_texture(cache_tex, offset, size, &data); - }, - ) { - Some(aabr) => Aabr { + glyph_cache + .cache_queued(|rect, data| { + let offset = [rect.min.x as u16, rect.min.y as u16]; + let size = [rect.width() as u16, rect.height() as u16]; + + let new_data = data + .iter() + .map(|x| [255, 255, 255, *x]) + .collect::>(); + + renderer.update_texture(cache_tex, offset, size, &new_data); + }) + .unwrap(); + + let color = srgb_to_linear(color.to_fsa().into()); + + for g in positioned_glyphs { + if let Ok(Some((uv_rect, screen_rect))) = + glyph_cache.rect_for(font_id.index(), g) + { + 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( - aabr.min.x as f32 / cache_w, - aabr.max.y as f32 / cache_h, + (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( - aabr.max.x as f32 / cache_w, - aabr.min.y as f32 / cache_h, + (screen_rect.max.x as f32 / screen_w - 0.5) * 2.0, + (screen_rect.min.y as f32 / screen_h - 0.5) * -2.0, ), - }, - None => continue, - }; - - mesh.push_quad(create_ui_quad( - gl_aabr(rect), - uv_aabr, - color, - UiMode::Image, - )); + }; + mesh.push_quad(create_ui_quad(rect, uv, color, UiMode::Text)); + } } - PrimitiveKind::Text { + } + PrimitiveKind::Rectangle { color } => { + let color = srgb_to_linear(color.to_fsa().into()); + // Don't draw a transparent rectangle + if color[3] == 0.0 { + continue; + } + + switch_to_plain_state!(); + + mesh.push_quad(create_ui_quad( + gl_aabr(rect), + Aabr { + min: Vec2::new(0.0, 0.0), + max: Vec2::new(0.0, 0.0), + }, color, - text, - font_id, - } => { - switch_to_plain_state!(); - // 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; - - let positioned_glyphs = text.positioned_glyphs(dpi_factor); - let (glyph_cache, cache_tex) = self.cache.glyph_cache_mut_and_tex(); - // Queue the glyphs to be cached - for glyph in positioned_glyphs { - glyph_cache.queue_glyph(font_id.index(), glyph.clone()); - } - - glyph_cache - .cache_queued(|rect, data| { - let offset = [rect.min.x as u16, rect.min.y as u16]; - let size = [rect.width() as u16, rect.height() as u16]; - - let new_data = data - .iter() - .map(|x| [255, 255, 255, *x]) - .collect::>(); - - renderer.update_texture(cache_tex, offset, size, &new_data); - }) - .unwrap(); - - let color = srgb_to_linear(color.to_fsa().into()); - - for g in positioned_glyphs { - if let Ok(Some((uv_rect, screen_rect))) = - glyph_cache.rect_for(font_id.index(), g) - { - 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, - ), - }; - mesh.push_quad(create_ui_quad(rect, uv, color, UiMode::Text)); - } - } + UiMode::Geometry, + )); + } + PrimitiveKind::TrianglesSingleColor { color, triangles } => { + // Don't draw transparent triangle or switch state if there are actually no triangles + let color = srgb_to_linear(Rgba::from(Into::<[f32; 4]>::into(color))); + if triangles.is_empty() || color[3] == 0.0 { + continue; } - PrimitiveKind::Rectangle { color } => { - let color = srgb_to_linear(color.to_fsa().into()); - // Don't draw a transparent rectangle - if color[3] == 0.0 { - continue; - } - switch_to_plain_state!(); + switch_to_plain_state!(); - mesh.push_quad(create_ui_quad( - gl_aabr(rect), - Aabr { - min: Vec2::new(0.0, 0.0), - max: Vec2::new(0.0, 0.0), - }, + for tri in triangles { + let p1 = Vec2::new(vx(tri[0][0]), vy(tri[0][1])); + let p2 = Vec2::new(vx(tri[1][0]), vy(tri[1][1])); + let p3 = Vec2::new(vx(tri[2][0]), vy(tri[2][1])); + // If triangle is clockwise reverse it + let (v1, v2): (Vec3, Vec3) = ((p2 - p1).into(), (p3 - p1).into()); + let triangle = if v1.cross(v2).z > 0.0 { + [p1.into_array(), p2.into_array(), p3.into_array()] + } else { + [p2.into_array(), p1.into_array(), p3.into_array()] + }; + mesh.push_tri(create_ui_tri( + triangle, + [[0.0; 2]; 3], color, UiMode::Geometry, )); } - PrimitiveKind::TrianglesSingleColor { color, triangles } => { - // Don't draw transparent triangle or switch state if there are actually no triangles - let color = srgb_to_linear(Rgba::from(Into::<[f32; 4]>::into(color))); - if triangles.is_empty() || color[3] == 0.0 { - continue; - } - - switch_to_plain_state!(); - - for tri in triangles { - let p1 = Vec2::new(vx(tri[0][0]), vy(tri[0][1])); - let p2 = Vec2::new(vx(tri[1][0]), vy(tri[1][1])); - let p3 = Vec2::new(vx(tri[2][0]), vy(tri[2][1])); - // If triangle is clockwise reverse it - let (v1, v2): (Vec3, Vec3) = - ((p2 - p1).into(), (p3 - p1).into()); - let triangle = if v1.cross(v2).z > 0.0 { - [p1.into_array(), p2.into_array(), p3.into_array()] - } else { - [p2.into_array(), p1.into_array(), p3.into_array()] - }; - mesh.push_tri(create_ui_tri( - triangle, - [[0.0; 2]; 3], - color, - UiMode::Geometry, - )); - } - } - _ => {} // TODO: Add this - //PrimitiveKind::TrianglesMultiColor {..} => {println!("primitive kind multicolor with id {:?}", id);} - // Other uneeded for now - //PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);} } + _ => {} // TODO: Add this + //PrimitiveKind::TrianglesMultiColor {..} => {println!("primitive kind multicolor with id {:?}", id);} + // Other uneeded for now + //PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);} } - // Enter the final command - self.draw_commands.push(match current_state { - State::Plain => DrawCommand::plain(renderer.create_model(&mesh).unwrap()), - State::Image => DrawCommand::image(renderer.create_model(&mesh).unwrap()), - }); + } + // Enter the final command + self.draw_commands.push(match current_state { + State::Plain => DrawCommand::plain(start..mesh.vertices().len()), + State::Image => DrawCommand::image(start..mesh.vertices().len()), + }); - // Handle window resizing - if let Some(new_dims) = self.window_resized.take() { - self.scale.window_resized(new_dims, renderer); - let (w, h) = self.scale.scaled_window_size().into_tuple(); - self.ui.handle_event(Input::Resize(w, h)); + // create a larger dynamic model if the mesh is larger than the current model size + if self.model.vbuf.len() < mesh.vertices().len() { + self.model = renderer + .create_dynamic_model(mesh.vertices().len() * 4 / 3) + .unwrap(); + } + renderer.update_model(&self.model, &mesh, 0).unwrap(); + // Update model with new mesh - let res = renderer.get_resolution(); - // Avoid panic in graphic cache when minimizing - if res.x > 0 && res.y > 0 { - self.cache - .clear_graphic_cache(renderer, renderer.get_resolution().map(|e| e * 4)); - } - // TODO: probably need to resize glyph cache, see conrod's gfx backend for reference + // Handle window resizing + if let Some(new_dims) = self.window_resized.take() { + self.scale.window_resized(new_dims, renderer); + let (w, h) = self.scale.scaled_window_size().into_tuple(); + self.ui.handle_event(Input::Resize(w, h)); + + let res = renderer.get_resolution(); + // Avoid panic in graphic cache when minimizing + if res.x > 0 && res.y > 0 { + self.cache + .clear_graphic_cache(renderer, renderer.get_resolution().map(|e| e * 4)); } + // TODO: probably need to resize glyph cache, see conrod's gfx backend for reference } } @@ -504,11 +513,12 @@ impl Ui { DrawCommand::Scissor(scizzor) => { scissor = *scizzor; } - DrawCommand::Draw { kind, model } => { + DrawCommand::Draw { kind, verts } => { let tex = match kind { DrawKind::Image => self.cache.graphic_cache_tex(), DrawKind::Plain => self.cache.glyph_cache_tex(), }; + let model = self.model.submodel(verts.clone()); renderer.render_ui_element(&model, &tex, scissor); } } From aed6750885d1db173f0f3e5077f487e15891ab77 Mon Sep 17 00:00:00 2001 From: Imbris Date: Wed, 8 May 2019 21:38:34 -0400 Subject: [PATCH 6/7] add multisampling option to voxel graphics Former-commit-id: d5ca47cd029226d1268c6d860516bfea6f9c5cf6 --- voxygen/src/hud/img_ids.rs | 6 ++++- voxygen/src/ui/graphic/graphic.rs | 7 +++--- voxygen/src/ui/graphic/renderer.rs | 39 +++++++++++++++++++++++++++--- voxygen/src/ui/img_ids.rs | 36 +++++++++++++++++++++++---- voxygen/src/ui/mod.rs | 7 +++--- 5 files changed, 77 insertions(+), 18 deletions(-) diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs index 3acd09b085..468314e232 100644 --- a/voxygen/src/hud/img_ids.rs +++ b/voxygen/src/hud/img_ids.rs @@ -1,4 +1,4 @@ -use crate::ui::{BlankGraphic, ImageGraphic, VoxelGraphic}; +use crate::ui::img_ids::{BlankGraphic, ImageGraphic, VoxelGraphic, VoxelMs9Graphic}; image_ids! { pub struct Imgs { @@ -8,6 +8,8 @@ image_ids! { inv_grid: "/voxygen/element/frames/inv_grid.vox", inv_slot: "/voxygen/element/buttons/inv_slot.vox", + + // Buttons mmap_closed: "/voxygen/element/buttons/button_mmap_closed.vox", mmap_closed_hover: "/voxygen/element/buttons/button_mmap_closed_hover.vox", @@ -52,6 +54,8 @@ image_ids! { button_hover: "/voxygen/element/buttons/button_hover.vox", button_press: "/voxygen/element/buttons/button_press.vox", + + // MiniMap mmap_frame: "/voxygen/element/frames/mmap.vox", mmap_frame_closed: "/voxygen/element/frames/mmap_closed.vox", diff --git a/voxygen/src/ui/graphic/graphic.rs b/voxygen/src/ui/graphic/graphic.rs index 38b80a08e4..71748def81 100644 --- a/voxygen/src/ui/graphic/graphic.rs +++ b/voxygen/src/ui/graphic/graphic.rs @@ -7,7 +7,7 @@ use vek::*; pub enum Graphic { Image(Arc), - Voxel(Arc), + Voxel(Arc, Option), Blank, } @@ -94,9 +94,8 @@ impl GraphicCache { .pixels() .map(|p| p.data) .collect::>(), - Graphic::Voxel(ref vox) => { - super::renderer::draw_vox(&vox.as_ref().into(), aabr.size().into()) - } + Graphic::Voxel(ref vox, min_samples) => + super::renderer::draw_vox(&vox.as_ref().into(), aabr.size().into(), *min_samples), Graphic::Blank => return None, }; diff --git a/voxygen/src/ui/graphic/renderer.rs b/voxygen/src/ui/graphic/renderer.rs index 54945f8b96..ec3118e496 100644 --- a/voxygen/src/ui/graphic/renderer.rs +++ b/voxygen/src/ui/graphic/renderer.rs @@ -4,6 +4,7 @@ use common::{ vol::{ReadVol, SizedVol, Vox}, }; use euc::{buffer::Buffer2d, rasterizer, Pipeline}; +use image::{DynamicImage, RgbaImage}; use vek::*; struct Voxel { @@ -56,8 +57,13 @@ impl<'a> Pipeline for Voxel { } } -pub fn draw_vox(segment: &Segment, output_size: Vec2) -> Vec<[u8; 4]> { - let dims = output_size.map(|e| e as usize).into_array(); +pub fn draw_vox( + segment: &Segment, + output_size: Vec2, + min_samples: Option, +) -> Vec<[u8; 4]> { + let scale = min_samples.map_or(1.0, |s| s as f32).sqrt().ceil() as usize; + let dims = output_size.map(|e| e as usize * scale).into_array(); let mut color = Buffer2d::new(dims, [0; 4]); let mut depth = Buffer2d::new(dims, 1.0); @@ -79,8 +85,33 @@ pub fn draw_vox(segment: &Segment, output_size: Vec2) -> Vec<[u8; 4]> { &mut depth, ); - // TODO: remove this clone - color.as_ref().to_vec() + if scale > 1 { + DynamicImage::ImageRgba8( + RgbaImage::from_vec( + dims[0] as u32, + dims[1] as u32, + color + .as_ref() + .iter() + .flatten() + .cloned() + .collect::>(), + ) + .unwrap(), + ) + .resize_exact( + output_size.x as u32, + output_size.y as u32, + image::FilterType::Triangle, + ) + .to_rgba() + .pixels() + .map(|p| p.data) + .collect::>() + } else { + // TODO: remove clone + color.as_ref().to_vec() + } } fn ao_level(side1: bool, corner: bool, side2: bool) -> u8 { diff --git a/voxygen/src/ui/img_ids.rs b/voxygen/src/ui/img_ids.rs index 04167078d6..4107d4e990 100644 --- a/voxygen/src/ui/img_ids.rs +++ b/voxygen/src/ui/img_ids.rs @@ -3,9 +3,8 @@ use common::assets::{load, Error}; use dot_vox::DotVoxData; use image::DynamicImage; -pub struct BlankGraphic; -pub struct ImageGraphic; -pub struct VoxelGraphic; +pub enum BlankGraphic {} +pub enum ImageGraphic {} pub trait GraphicCreator<'a> { type Specifier; @@ -23,10 +22,37 @@ impl<'a> GraphicCreator<'a> for ImageGraphic { Ok(Graphic::Image(load::(specifier)?)) } } + +pub enum VoxelGraphic {} +pub enum VoxelMsGraphic {} +pub enum VoxelMs4Graphic {} +pub enum VoxelMs9Graphic {} + impl<'a> GraphicCreator<'a> for VoxelGraphic { type Specifier = &'a str; fn new_graphic(specifier: Self::Specifier) -> Result { - Ok(Graphic::Voxel(load::(specifier)?)) + Ok(Graphic::Voxel(load::(specifier)?, None)) + } +} +impl<'a> GraphicCreator<'a> for VoxelMsGraphic { + type Specifier = (&'a str, u8); + fn new_graphic(specifier: Self::Specifier) -> Result { + Ok(Graphic::Voxel( + load::(specifier.0)?, + Some(specifier.1), + )) + } +} +impl<'a> GraphicCreator<'a> for VoxelMs4Graphic { + type Specifier = &'a str; + fn new_graphic(specifier: Self::Specifier) -> Result { + Ok(Graphic::Voxel(load::(specifier)?, Some(4))) + } +} +impl<'a> GraphicCreator<'a> for VoxelMs9Graphic { + type Specifier = &'a str; + fn new_graphic(specifier: Self::Specifier) -> Result { + Ok(Graphic::Voxel(load::(specifier)?, Some(9))) } } @@ -59,7 +85,7 @@ macro_rules! image_ids { impl $Ids { pub fn load(ui: &mut crate::ui::Ui) -> Result { - use crate::ui::GraphicCreator; + use crate::ui::img_ids::GraphicCreator; Ok(Self { $($( $name: ui.add_graphic(<$T>::new_graphic($specifier)?), )*)* }) diff --git a/voxygen/src/ui/mod.rs b/voxygen/src/ui/mod.rs index 43c6000cf9..f151142e53 100644 --- a/voxygen/src/ui/mod.rs +++ b/voxygen/src/ui/mod.rs @@ -5,13 +5,12 @@ mod scale; mod util; mod widgets; #[macro_use] -mod img_ids; +pub mod img_ids; #[macro_use] mod font_ids; pub use event::Event; pub use graphic::Graphic; -pub use img_ids::{BlankGraphic, GraphicCreator, ImageGraphic, VoxelGraphic}; pub use scale::ScaleMode; pub use widgets::toggle_button::ToggleButton; @@ -315,8 +314,8 @@ impl Ui { srgb_to_linear(color.unwrap_or(conrod_core::color::WHITE).to_fsa().into()); let resolution = Vec2::new( - (rect.w() * p_scale_factor) as u16, - (rect.h() * p_scale_factor) as u16, + (rect.w() * p_scale_factor).round() as u16, + (rect.h() * p_scale_factor).round() as u16, ); // Transform the source rectangle into uv coordinate // TODO: make sure this is right From 1948bc639274f2bf285b4900182d455c66931819 Mon Sep 17 00:00:00 2001 From: Imbris Date: Sat, 11 May 2019 10:59:48 -0400 Subject: [PATCH 7/7] fix & remove some unused uses, cursor toggle tweak Former-commit-id: b398b11606d983b7f80364a5689804e3491c218f --- voxygen/src/hud/mod.rs | 14 +++++++------- voxygen/src/menu/char_selection/ui.rs | 13 +++++++------ voxygen/src/menu/main/ui.rs | 9 +++++---- voxygen/src/ui/img_ids.rs | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 83bf5d1079..9a9ce47aca 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -475,6 +475,13 @@ impl Hud { self.show.toggle_ui(); true } + WinEvent::KeyDown(Key::ToggleCursor) => { + self.force_ungrab = !self.force_ungrab; + if self.force_ungrab { + global_state.window.grab_cursor(false); + } + true + } _ if !self.show.ui => false, WinEvent::Zoom(_) => !cursor_grabbed && !self.ui.no_widget_capturing_mouse(), WinEvent::KeyDown(Key::Enter) => { @@ -527,13 +534,6 @@ impl Hud { self.show.toggle_help(); true } - Key::ToggleCursor => { - self.force_ungrab = !self.force_ungrab; - if self.force_ungrab { - global_state.window.grab_cursor(false); - } - true - } _ => false, }, WinEvent::KeyDown(key) | WinEvent::KeyUp(key) => match key { diff --git a/voxygen/src/menu/char_selection/ui.rs b/voxygen/src/menu/char_selection/ui.rs index 10f1591648..469e3a84ea 100644 --- a/voxygen/src/menu/char_selection/ui.rs +++ b/voxygen/src/menu/char_selection/ui.rs @@ -1,17 +1,18 @@ use crate::{ render::Renderer, - ui::{self, BlankGraphic, Graphic, ImageGraphic, ScaleMode, Ui, VoxelGraphic}, + ui::{ + self, + img_ids::{ImageGraphic, VoxelGraphic}, + ScaleMode, Ui, + }, window::Window, }; -use common::{ - assets, - comp::character::{Belt, Character, Chest, Foot, Gender, Hand, Head, Pants, Race, Weapon}, +use common::comp::character::{ + Belt, Character, Chest, Foot, Gender, Hand, Head, Pants, Race, Weapon, }; use conrod_core::{ color, color::TRANSPARENT, - image::Id as ImgId, - text::font::Id as FontId, widget::{text_box::Event as TextBoxEvent, Button, Image, Rectangle, Text, TextBox}, widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget, }; diff --git a/voxygen/src/menu/main/ui.rs b/voxygen/src/menu/main/ui.rs index c8f4f078b2..431b3673cf 100644 --- a/voxygen/src/menu/main/ui.rs +++ b/voxygen/src/menu/main/ui.rs @@ -1,15 +1,16 @@ use crate::{ render::Renderer, - ui::{self, BlankGraphic, Graphic, ImageGraphic, ScaleMode, Ui, VoxelGraphic}, + ui::{ + self, + img_ids::{ImageGraphic, VoxelGraphic}, + ScaleMode, Ui, + }, GlobalState, DEFAULT_PUBLIC_SERVER, }; -use common::assets; use conrod_core::{ color, color::TRANSPARENT, - image::Id as ImgId, position::Relative, - text::font::Id as FontId, widget::{text_box::Event as TextBoxEvent, Button, Image, List, Rectangle, Text, TextBox}, widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget, }; diff --git a/voxygen/src/ui/img_ids.rs b/voxygen/src/ui/img_ids.rs index 4107d4e990..133dafb689 100644 --- a/voxygen/src/ui/img_ids.rs +++ b/voxygen/src/ui/img_ids.rs @@ -87,7 +87,7 @@ macro_rules! image_ids { pub fn load(ui: &mut crate::ui::Ui) -> Result { use crate::ui::img_ids::GraphicCreator; Ok(Self { - $($( $name: ui.add_graphic(<$T>::new_graphic($specifier)?), )*)* + $($( $name: ui.add_graphic(<$T as GraphicCreator>::new_graphic($specifier)?), )*)* }) } }