Stop recreating vertex buffers for ui

Former-commit-id: 6e9326d1bca942e4da70281e3d86b624f9d2504a
This commit is contained in:
Imbris 2019-05-04 10:28:21 -04:00
parent a3d6e2eb90
commit 78fd9da4ce
4 changed files with 356 additions and 285 deletions

View File

@ -10,7 +10,7 @@ mod util;
pub use self::{ pub use self::{
consts::Consts, consts::Consts,
mesh::{Mesh, Quad, Tri}, mesh::{Mesh, Quad, Tri},
model::Model, model::{DynamicModel, Model},
pipelines::{ pipelines::{
figure::{BoneData as FigureBoneData, FigurePipeline, Locals as FigureLocals}, figure::{BoneData as FigureBoneData, FigurePipeline, Locals as FigureLocals},
postprocess::{ postprocess::{
@ -40,6 +40,7 @@ pub enum RenderError {
UpdateError(gfx::UpdateError<usize>), UpdateError(gfx::UpdateError<usize>),
TexUpdateError(gfx::UpdateError<[u16; 3]>), TexUpdateError(gfx::UpdateError<[u16; 3]>),
CombinedError(gfx::CombinedError), CombinedError(gfx::CombinedError),
BufferCreationError(gfx::buffer::CreationError),
} }
/// Used to represent a specific rendering configuration. /// Used to represent a specific rendering configuration.

View File

@ -1,8 +1,11 @@
// Library use super::{gfx_backend, mesh::Mesh, Pipeline, RenderError};
use gfx::{self, traits::FactoryExt}; use gfx::{
buffer::Role,
// Local memory::{Bind, Usage},
use super::{gfx_backend, mesh::Mesh, Pipeline}; traits::FactoryExt,
Factory,
};
use std::ops::Range;
/// Represents a mesh that has been sent to the GPU. /// Represents a mesh that has been sent to the GPU.
pub struct Model<P: Pipeline> { pub struct Model<P: Pipeline> {
@ -24,3 +27,43 @@ impl<P: Pipeline> Model<P> {
} }
} }
} }
/// Represents a mesh on the GPU which can be updated dynamically
pub struct DynamicModel<P: Pipeline> {
pub vbuf: gfx::handle::Buffer<gfx_backend::Resources, P::Vertex>,
}
impl<P: Pipeline> DynamicModel<P> {
pub fn new(factory: &mut gfx_backend::Factory, size: usize) -> Result<Self, RenderError> {
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<usize>) -> Model<P> {
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<gfx_backend::Resources, gfx_backend::CommandBuffer>,
mesh: &Mesh<P>,
offset: usize,
) -> Result<(), RenderError> {
encoder
.update_buffer(&self.vbuf, mesh.vertices(), offset)
.map_err(|err| RenderError::UpdateError(err))
}
}

View File

@ -2,7 +2,7 @@ use super::{
consts::Consts, consts::Consts,
gfx_backend, gfx_backend,
mesh::Mesh, mesh::Mesh,
model::Model, model::{DynamicModel, Model},
pipelines::{figure, postprocess, skybox, terrain, ui, Globals}, pipelines::{figure, postprocess, skybox, terrain, ui, Globals},
texture::Texture, texture::Texture,
Pipeline, RenderError, Pipeline, RenderError,
@ -12,7 +12,6 @@ use gfx::{
handle::Sampler, handle::Sampler,
traits::{Device, Factory, FactoryExt}, traits::{Device, Factory, FactoryExt},
}; };
use image;
use vek::*; use vek::*;
/// Represents the format of the pre-processed color target. /// Represents the format of the pre-processed color target.
@ -246,6 +245,24 @@ impl Renderer {
Ok(Model::new(&mut self.factory, mesh)) Ok(Model::new(&mut self.factory, mesh))
} }
/// Create a new dynamic model with the specified size
pub fn create_dynamic_model<P: Pipeline>(
&mut self,
size: usize,
) -> Result<DynamicModel<P>, RenderError> {
DynamicModel::new(&mut self.factory, size)
}
/// Update a dynamic model with a mesh and a offset
pub fn update_model<P: Pipeline>(
&mut self,
model: &DynamicModel<P>,
mesh: &Mesh<P>,
offset: usize,
) -> Result<(), RenderError> {
model.update(&mut self.encoder, mesh, offset)
}
/// Create a new texture from the provided image. /// Create a new texture from the provided image.
pub fn create_texture<P: Pipeline>( pub fn create_texture<P: Pipeline>(
&mut self, &mut self,

View File

@ -17,7 +17,8 @@ pub use widgets::toggle_button::ToggleButton;
use crate::{ use crate::{
render::{ 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, window::Window,
Error, Error,
@ -36,6 +37,7 @@ use conrod_core::{
}; };
use graphic::Id as GraphicId; use graphic::Id as GraphicId;
use scale::Scale; use scale::Scale;
use std::ops::Range;
use std::sync::Arc; use std::sync::Arc;
use util::{linear_to_srgb, srgb_to_linear}; use util::{linear_to_srgb, srgb_to_linear};
use vek::*; use vek::*;
@ -51,23 +53,20 @@ enum DrawKind {
Plain, Plain,
} }
enum DrawCommand { enum DrawCommand {
Draw { Draw { kind: DrawKind, verts: Range<usize> },
kind: DrawKind,
model: Model<UiPipeline>,
},
Scissor(Aabr<u16>), Scissor(Aabr<u16>),
} }
impl DrawCommand { impl DrawCommand {
fn image(model: Model<UiPipeline>) -> DrawCommand { fn image(verts: Range<usize>) -> DrawCommand {
DrawCommand::Draw { DrawCommand::Draw {
kind: DrawKind::Image, kind: DrawKind::Image,
model, verts,
} }
} }
fn plain(model: Model<UiPipeline>) -> DrawCommand { fn plain(verts: Range<usize>) -> DrawCommand {
DrawCommand::Draw { DrawCommand::Draw {
kind: DrawKind::Plain, kind: DrawKind::Plain,
model, verts,
} }
} }
} }
@ -87,6 +86,8 @@ pub struct Ui {
cache: Cache, cache: Cache,
// Draw commands for the next render // Draw commands for the next render
draw_commands: Vec<DrawCommand>, draw_commands: Vec<DrawCommand>,
// Model for drawing the ui
model: DynamicModel<UiPipeline>,
// Stores new window size for updating scaling // Stores new window size for updating scaling
window_resized: Option<Vec2<f64>>, window_resized: Option<Vec2<f64>>,
// Scaling of the ui // Scaling of the ui
@ -102,8 +103,9 @@ impl Ui {
ui: UiBuilder::new(win_dims).build(), ui: UiBuilder::new(win_dims).build(),
image_map: Map::new(), image_map: Map::new(),
cache: Cache::new(window.renderer_mut())?, cache: Cache::new(window.renderer_mut())?,
window_resized: None,
draw_commands: vec![], draw_commands: vec![],
model: window.renderer_mut().create_dynamic_model(100)?,
window_resized: None,
scale, scale,
}) })
} }
@ -192,308 +194,315 @@ impl Ui {
} }
pub fn maintain(&mut self, renderer: &mut Renderer) { 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 // Regenerate draw commands and associated models only if the ui changed
if let Some(mut primitives) = ui.draw_if_changed() { let mut primitives = match self.ui.draw_if_changed() {
self.draw_commands.clear(); Some(primitives) => primitives,
let mut mesh = Mesh::new(); None => return,
};
// TODO: this could be removed entirely if the draw call just used both textures self.draw_commands.clear();
// however this allows for flexibility if we want to interleave other draw calls later let mut mesh = Mesh::new();
enum State {
Image, // TODO: this could be removed entirely if the draw call just used both textures
Plain, // 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); while let Some(prim) = primitives.next() {
let mut current_scizzor = window_scizzor; let Primitive {
kind,
scizzor,
rect,
..
} = prim;
// Switches to the `Plain` state and completes the previous `Command` if not already in the // Check for a change in the scizzor
// `Plain` state. let new_scizzor = {
macro_rules! switch_to_plain_state { let (l, b, w, h) = scizzor.l_b_w_h();
() => { // Calculate minimum x and y coordinates while
if let State::Image = current_state { // - flipping y axis (from +up to +down)
self.draw_commands // - moving origin to top-left corner (from middle)
.push(DrawCommand::image(renderer.create_model(&mesh).unwrap())); let min_x = self.ui.win_w / 2.0 + l;
mesh.clear(); let min_y = self.ui.win_h / 2.0 - b - h;
current_state = State::Plain; 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(); // Functions for converting for conrod scalar coords to GL vertex coords (-1.0 to 1.0)
let ui_win_w = self.ui.win_w;
while let Some(prim) = primitives.next() { let ui_win_h = self.ui.win_h;
let Primitive { let vx = |x: f64| (x / ui_win_w * 2.0) as f32;
kind, let vy = |y: f64| (y / ui_win_h * 2.0) as f32;
scizzor, let gl_aabr = |rect: conrod_core::Rect| {
rect, let (l, r, b, t) = rect.l_r_b_t();
.. Aabr {
} = prim; min: Vec2::new(vx(l), vy(b)),
max: Vec2::new(vx(r), vy(t)),
// 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) use conrod_core::render::PrimitiveKind;
let vx = |x: f64| (x / ui.win_w * 2.0) as f32; match kind {
let vy = |y: f64| (y / ui.win_h * 2.0) as f32; PrimitiveKind::Image {
let gl_aabr = |rect: conrod_core::Rect| { image_id,
let (l, r, b, t) = rect.l_r_b_t(); color,
Aabr { source_rect,
min: Vec2::new(vx(l), vy(b)), } => {
max: Vec2::new(vx(r), vy(t)), 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; // Switch to the image state if we are not in it already
match kind { if let State::Plain = current_state {
PrimitiveKind::Image { self.draw_commands
image_id, .push(DrawCommand::plain(start..mesh.vertices().len()));
color, start = mesh.vertices().len();
source_rect, current_state = State::Image;
} => { }
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) { let color =
Some(Graphic::Blank) | None => continue, 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 // Cache graphic at particular resolution
if let State::Plain = current_state { let uv_aabr = match graphic_cache.cache_res(
self.draw_commands *graphic_id,
.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap())); resolution,
mesh.clear(); source_aabr,
current_state = State::Image; |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( mesh.push_quad(create_ui_quad(gl_aabr(rect), uv_aabr, color, UiMode::Image));
color.unwrap_or(conrod_core::color::WHITE).to_fsa().into(), }
); 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( let positioned_glyphs = text.positioned_glyphs(dpi_factor);
(rect.w() * p_scale_factor) as u16, let (glyph_cache, cache_tex) = self.cache.glyph_cache_mut_and_tex();
(rect.h() * p_scale_factor) as u16, // Queue the glyphs to be cached
); for glyph in positioned_glyphs {
// Transform the source rectangle into uv coordinate glyph_cache.queue_glyph(font_id.index(), glyph.clone());
// 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();
// Cache graphic at particular resolution glyph_cache
let uv_aabr = match graphic_cache.cache_res( .cache_queued(|rect, data| {
*graphic_id, let offset = [rect.min.x as u16, rect.min.y as u16];
resolution, let size = [rect.width() as u16, rect.height() as u16];
source_aabr,
|aabr, data| { let new_data = data
let offset = aabr.min.into_array(); .iter()
let size = aabr.size().into_array(); .map(|x| [255, 255, 255, *x])
renderer.update_texture(cache_tex, offset, size, &data); .collect::<Vec<[u8; 4]>>();
},
) { renderer.update_texture(cache_tex, offset, size, &new_data);
Some(aabr) => Aabr { })
.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( min: Vec2::new(
aabr.min.x as f32 / cache_w, (screen_rect.min.x as f32 / screen_w - 0.5) * 2.0,
aabr.max.y as f32 / cache_h, (screen_rect.max.y as f32 / screen_h - 0.5) * -2.0,
), ),
max: Vec2::new( max: Vec2::new(
aabr.max.x as f32 / cache_w, (screen_rect.max.x as f32 / screen_w - 0.5) * 2.0,
aabr.min.y as f32 / cache_h, (screen_rect.min.y as f32 / screen_h - 0.5) * -2.0,
), ),
}, };
None => continue, mesh.push_quad(create_ui_quad(rect, uv, color, UiMode::Text));
}; }
mesh.push_quad(create_ui_quad(
gl_aabr(rect),
uv_aabr,
color,
UiMode::Image,
));
} }
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, color,
text, UiMode::Geometry,
font_id, ));
} => { }
switch_to_plain_state!(); PrimitiveKind::TrianglesSingleColor { color, triangles } => {
// Get screen width and height // Don't draw transparent triangle or switch state if there are actually no triangles
let (screen_w, screen_h) = let color = srgb_to_linear(Rgba::from(Into::<[f32; 4]>::into(color)));
renderer.get_resolution().map(|e| e as f32).into_tuple(); if triangles.is_empty() || color[3] == 0.0 {
// Calculate dpi factor continue;
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::<Vec<[u8; 4]>>();
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));
}
}
} }
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( for tri in triangles {
gl_aabr(rect), let p1 = Vec2::new(vx(tri[0][0]), vy(tri[0][1]));
Aabr { let p2 = Vec2::new(vx(tri[1][0]), vy(tri[1][1]));
min: Vec2::new(0.0, 0.0), let p3 = Vec2::new(vx(tri[2][0]), vy(tri[2][1]));
max: Vec2::new(0.0, 0.0), // If triangle is clockwise reverse it
}, let (v1, v2): (Vec3<f32>, Vec3<f32>) = ((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, color,
UiMode::Geometry, 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<f32>, Vec3<f32>) =
((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 { // Enter the final command
State::Plain => DrawCommand::plain(renderer.create_model(&mesh).unwrap()), self.draw_commands.push(match current_state {
State::Image => DrawCommand::image(renderer.create_model(&mesh).unwrap()), State::Plain => DrawCommand::plain(start..mesh.vertices().len()),
}); State::Image => DrawCommand::image(start..mesh.vertices().len()),
});
// Handle window resizing // create a larger dynamic model if the mesh is larger than the current model size
if let Some(new_dims) = self.window_resized.take() { if self.model.vbuf.len() < mesh.vertices().len() {
self.scale.window_resized(new_dims, renderer); self.model = renderer
let (w, h) = self.scale.scaled_window_size().into_tuple(); .create_dynamic_model(mesh.vertices().len() * 4 / 3)
self.ui.handle_event(Input::Resize(w, h)); .unwrap();
}
renderer.update_model(&self.model, &mesh, 0).unwrap();
// Update model with new mesh
let res = renderer.get_resolution(); // Handle window resizing
// Avoid panic in graphic cache when minimizing if let Some(new_dims) = self.window_resized.take() {
if res.x > 0 && res.y > 0 { self.scale.window_resized(new_dims, renderer);
self.cache let (w, h) = self.scale.scaled_window_size().into_tuple();
.clear_graphic_cache(renderer, renderer.get_resolution().map(|e| e * 4)); self.ui.handle_event(Input::Resize(w, h));
}
// TODO: probably need to resize glyph cache, see conrod's gfx backend for reference 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) => { DrawCommand::Scissor(scizzor) => {
scissor = *scizzor; scissor = *scizzor;
} }
DrawCommand::Draw { kind, model } => { DrawCommand::Draw { kind, verts } => {
let tex = match kind { let tex = match kind {
DrawKind::Image => self.cache.graphic_cache_tex(), DrawKind::Image => self.cache.graphic_cache_tex(),
DrawKind::Plain => self.cache.glyph_cache_tex(), DrawKind::Plain => self.cache.glyph_cache_tex(),
}; };
let model = self.model.submodel(verts.clone());
renderer.render_ui_element(&model, &tex, scissor); renderer.render_ui_element(&model, &tex, scissor);
} }
} }