From b99a8dea39227dbb5b6c014715956b428e9f80a0 Mon Sep 17 00:00:00 2001 From: Imbris Date: Sat, 4 May 2019 10:28:21 -0400 Subject: [PATCH] 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); } }