Merge branch 'imbris/ui_changes' into 'master'

UI Cache Updates and Warning Cleanup

See merge request veloren/veloren!296
This commit is contained in:
Joshua Barretto 2019-07-03 08:56:14 +00:00
commit fc73f71e60
7 changed files with 308 additions and 154 deletions

View File

@ -282,6 +282,11 @@ impl Renderer {
model.update(&mut self.encoder, mesh, offset) model.update(&mut self.encoder, mesh, offset)
} }
/// Return the maximum supported texture size.
pub fn max_texture_size(&self) -> usize {
self.factory.get_capabilities().max_texture_size
}
/// 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

@ -6,6 +6,13 @@ use crate::{
use conrod_core::text::GlyphCache; use conrod_core::text::GlyphCache;
use vek::*; use vek::*;
// Multiplied by current window size
const GLYPH_CACHE_SIZE: u16 = 1;
const GRAPHIC_CACHE_SIZE: u16 = 2;
// Glyph cache tolerances
const SCALE_TOLERANCE: f32 = 0.1;
const POSITION_TOLERANCE: f32 = 0.1;
pub struct Cache { pub struct Cache {
glyph_cache: GlyphCache<'static>, glyph_cache: GlyphCache<'static>,
glyph_cache_tex: Texture<UiPipeline>, glyph_cache_tex: Texture<UiPipeline>,
@ -17,17 +24,21 @@ pub struct Cache {
impl Cache { impl Cache {
pub fn new(renderer: &mut Renderer) -> Result<Self, Error> { pub fn new(renderer: &mut Renderer) -> Result<Self, Error> {
let (w, h) = renderer.get_resolution().into_tuple(); 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); let max_texture_size = renderer.max_texture_size();
let graphic_cache_dims =
Vec2::new(w, h).map(|e| (e * GRAPHIC_CACHE_SIZE).min(max_texture_size as u16));
let glyph_cache_dims =
Vec2::new(w, h).map(|e| (e * GLYPH_CACHE_SIZE).min(max_texture_size as u16));
Ok(Self { Ok(Self {
glyph_cache: GlyphCache::builder() glyph_cache: GlyphCache::builder()
.dimensions(w as u32, h as u32) .dimensions(glyph_cache_dims.x as u32, glyph_cache_dims.y as u32)
.scale_tolerance(SCALE_TOLERANCE) .scale_tolerance(SCALE_TOLERANCE)
.position_tolerance(POSITION_TOLERANCE) .position_tolerance(POSITION_TOLERANCE)
.build(), .build(),
glyph_cache_tex: renderer.create_dynamic_texture((w, h).into())?, glyph_cache_tex: renderer.create_dynamic_texture(glyph_cache_dims.map(|e| e as u16))?,
graphic_cache: GraphicCache::new(graphic_cache_dims), graphic_cache: GraphicCache::new(graphic_cache_dims),
graphic_cache_tex: renderer.create_dynamic_texture(graphic_cache_dims)?, graphic_cache_tex: renderer.create_dynamic_texture(graphic_cache_dims)?,
}) })
@ -47,8 +58,28 @@ impl Cache {
pub fn add_graphic(&mut self, graphic: Graphic) -> GraphicId { pub fn add_graphic(&mut self, graphic: Graphic) -> GraphicId {
self.graphic_cache.add_graphic(graphic) self.graphic_cache.add_graphic(graphic)
} }
pub fn clear_graphic_cache(&mut self, renderer: &mut Renderer, new_size: Vec2<u16>) { // Resizes and clears the GraphicCache
self.graphic_cache.clear_cache(new_size); pub fn resize_graphic_cache(&mut self, renderer: &mut Renderer) -> Result<(), Error> {
self.graphic_cache_tex = renderer.create_dynamic_texture(new_size).unwrap(); let max_texture_size = renderer.max_texture_size();
let cache_dims = renderer
.get_resolution()
.map(|e| (e * GRAPHIC_CACHE_SIZE).min(max_texture_size as u16));
self.graphic_cache.clear_cache(cache_dims);
self.graphic_cache_tex = renderer.create_dynamic_texture(cache_dims)?;
Ok(())
}
// Resizes and clears the GlyphCache
pub fn resize_glyph_cache(&mut self, renderer: &mut Renderer) -> Result<(), Error> {
let max_texture_size = renderer.max_texture_size();
let cache_dims = renderer
.get_resolution()
.map(|e| (e * GLYPH_CACHE_SIZE).min(max_texture_size as u16));
self.glyph_cache = GlyphCache::builder()
.dimensions(cache_dims.x as u32, cache_dims.y as u32)
.scale_tolerance(SCALE_TOLERANCE)
.position_tolerance(POSITION_TOLERANCE)
.build();
self.glyph_cache_tex = renderer.create_dynamic_texture(cache_dims.map(|e| e as u16))?;
Ok(())
} }
} }

View File

@ -1,10 +1,12 @@
use dot_vox::DotVoxData; use dot_vox::DotVoxData;
use fnv::FnvHashMap; use fnv::FnvHashMap;
use guillotiere::{size2, Allocation, AtlasAllocator}; use guillotiere::{size2, AllocId, Allocation, AtlasAllocator};
use image::DynamicImage; use image::{DynamicImage, RgbaImage};
use log::{error, warn};
use std::sync::Arc; use std::sync::Arc;
use vek::*; use vek::*;
#[derive(Clone)]
pub enum Graphic { pub enum Graphic {
Image(Arc<DynamicImage>), Image(Arc<DynamicImage>),
Voxel(Arc<DotVoxData>, Option<u8>), Voxel(Arc<DotVoxData>, Option<u8>),
@ -16,19 +18,39 @@ pub struct Id(u32);
type Parameters = (Id, Vec2<u16>, Aabr<u64>); type Parameters = (Id, Vec2<u16>, Aabr<u64>);
pub struct CachedDetails {
// Id used by AtlasAllocator
alloc_id: AllocId,
// Last frame this was used on
frame: u32,
// Where in the cache texture this is
aabr: Aabr<u16>,
}
pub struct GraphicCache { pub struct GraphicCache {
atlas: AtlasAllocator,
graphic_map: FnvHashMap<Id, Graphic>, graphic_map: FnvHashMap<Id, Graphic>,
rect_map: FnvHashMap<Parameters, Aabr<u16>>,
next_id: u32, next_id: u32,
atlas: AtlasAllocator,
cache_map: FnvHashMap<Parameters, CachedDetails>,
// The current frame
current_frame: u32,
unused_entries_this_frame: Option<Vec<Option<(u32, Parameters)>>>,
soft_cache: FnvHashMap<Parameters, RgbaImage>,
transfer_ready: Vec<(Parameters, Aabr<u16>)>,
} }
impl GraphicCache { impl GraphicCache {
pub fn new(size: Vec2<u16>) -> Self { pub fn new(size: Vec2<u16>) -> Self {
Self { Self {
atlas: AtlasAllocator::new(size2(i32::from(size.x), i32::from(size.y))),
graphic_map: FnvHashMap::default(), graphic_map: FnvHashMap::default(),
rect_map: FnvHashMap::default(),
next_id: 0, next_id: 0,
atlas: AtlasAllocator::new(size2(i32::from(size.x), i32::from(size.y))),
cache_map: FnvHashMap::default(),
current_frame: 0,
unused_entries_this_frame: None,
soft_cache: FnvHashMap::default(),
transfer_ready: Vec::new(),
} }
} }
pub fn add_graphic(&mut self, graphic: Graphic) -> Id { pub fn add_graphic(&mut self, graphic: Graphic) -> Id {
@ -44,77 +66,177 @@ impl GraphicCache {
self.graphic_map.get(&id) self.graphic_map.get(&id)
} }
pub fn clear_cache(&mut self, new_size: Vec2<u16>) { pub fn clear_cache(&mut self, new_size: Vec2<u16>) {
self.rect_map.clear(); self.soft_cache.clear();
self.transfer_ready.clear();
self.cache_map.clear();
self.atlas = AtlasAllocator::new(size2(i32::from(new_size.x), i32::from(new_size.y))); self.atlas = AtlasAllocator::new(size2(i32::from(new_size.x), i32::from(new_size.y)));
} }
pub fn cache_res<F>(
pub fn queue_res(
&mut self, &mut self,
graphic_id: Id, graphic_id: Id,
dims: Vec2<u16>, dims: Vec2<u16>,
source: Aabr<f64>, source: Aabr<f64>,
mut cacher: F, ) -> Option<Aabr<u16>> {
) -> Option<Aabr<u16>> let key = (graphic_id, dims, source.map(|e| e.to_bits())); // TODO: Replace this with rounded representation of source
if let Some(details) = self.cache_map.get_mut(&key) {
// Update frame
details.frame = self.current_frame;
Some(details.aabr)
} else {
// Create image if it doesn't already exist
if !self.soft_cache.contains_key(&key) {
self.soft_cache.insert(
key,
match self.graphic_map.get(&graphic_id) {
Some(Graphic::Blank) => return None,
// Render image at requested resolution
// TODO: Use source aabr.
Some(Graphic::Image(ref image)) => image
.resize_exact(
u32::from(dims.x),
u32::from(dims.y),
image::FilterType::Nearest,
)
.to_rgba(),
Some(Graphic::Voxel(ref vox, min_samples)) => {
super::renderer::draw_vox(&vox.as_ref().into(), dims, *min_samples)
}
None => {
warn!("A graphic was requested via an id which is not in use");
return None;
}
},
);
}
let aabr_from_alloc_rect = |rect: guillotiere::Rectangle| {
let (min, max) = (rect.min, rect.max);
Aabr {
min: Vec2::new(min.x as u16, min.y as u16),
max: Vec2::new(max.x as u16, max.y as u16),
}
};
// Allocate rectangle.
let (alloc_id, aabr) = match self
.atlas
.allocate(size2(i32::from(dims.x), i32::from(dims.y)))
{
Some(Allocation { id, rectangle }) => (id, aabr_from_alloc_rect(rectangle)),
// Out of room.
// 1) Remove unused allocations
// TODO: Make more room.
// 2) Rearrange rectangles (see comments below)
// 3) Expand cache size
None => {
// 1) Remove unused allocations
if self.unused_entries_this_frame.is_none() {
self.unused_entries_this_frame = {
let mut unused = self
.cache_map
.iter()
.filter_map(|(key, details)| {
if details.frame < self.current_frame - 1 {
Some(Some((details.frame, *key)))
} else {
None
}
})
.collect::<Vec<_>>();
unused
.sort_unstable_by(|a, b| a.map(|(f, _)| f).cmp(&b.map(|(f, _)| f)));
Some(unused)
};
}
let mut allocation = None;
// Fight the checker!
let current_frame = self.current_frame;
// Will always be Some
if let Some(ref mut unused_entries) = self.unused_entries_this_frame {
// Deallocate from oldest to newest
for key in unused_entries
.iter_mut()
.filter_map(|e| e.take().map(|(_, key)| key))
{
// Check if still in cache map and it has not been used since the vec was built
if self
.cache_map
.get(&key)
.filter(|d| d.frame != current_frame)
.is_some()
{
if let Some(alloc_id) =
self.cache_map.remove(&key).map(|d| d.alloc_id)
{
// Deallocate
self.atlas.deallocate(alloc_id);
// Try to allocate
allocation = self
.atlas
.allocate(size2(i32::from(dims.x), i32::from(dims.y)));
}
}
}
// 2) Rearrange rectangles
// This needs to be done infrequently and be based on whether rectangles have been removed
// Maybe find a way to calculate whether there is a significant amount of fragmentation
// Or consider dropping the use of an atlas and moving to a hashmap of individual textures :/
// if allocation.is_none() {
//
// }
}
match allocation {
Some(Allocation { id, rectangle }) => (id, aabr_from_alloc_rect(rectangle)),
None => {
warn!("Can't find space for an image in the graphic cache");
return None;
}
}
}
};
self.transfer_ready.push((key, aabr));
// Insert area into map for retrieval.
self.cache_map.insert(
key,
CachedDetails {
alloc_id,
frame: self.current_frame,
aabr,
},
);
Some(aabr)
}
}
// Anything not queued since the last call to this will be removed if there is not enough space in the cache
pub fn cache_queued<F>(&mut self, mut cacher: F)
where where
F: FnMut(Aabr<u16>, &[[u8; 4]]), F: FnMut(Aabr<u16>, &[[u8; 4]]),
{ {
match self // Cached queued
.rect_map // TODO: combine nearby transfers
.get(&(graphic_id, dims, source.map(|e| e.to_bits()))) // TODO: Replace this with rounded representation of source for (key, target_aarb) in self.transfer_ready.drain(..) {
{ if let Some(image) = self.soft_cache.get(&key) {
Some(aabr) => Some(*aabr), cacher(
None => match self.graphic_map.get(&graphic_id) { target_aarb,
Some(graphic) => { &image.pixels().map(|p| p.data).collect::<Vec<[u8; 4]>>(),
// Allocate rectangle. );
let aabr = match self } else {
.atlas error!("Image queued for transfer to gpu cache but it doesn't exist (this should never occur)");
.allocate(size2(i32::from(dims.x), i32::from(dims.y))) }
{
Some(Allocation { id: _, rectangle }) => {
let (min, max) = (rectangle.min, rectangle.max);
Aabr {
min: Vec2::new(min.x as u16, min.y as u16),
max: Vec2::new(max.x as u16, max.y as u16),
}
}
// Out of room.
// TODO: Make more room.
// 1) Expand cache size
// 2) Remove unused allocations
// 3) Rearrange rectangles
None => return None,
};
// Render image.
// TODO: Use source.
let data = match graphic {
Graphic::Image(ref image) => image
.resize_exact(
u32::from(aabr.size().w),
u32::from(aabr.size().h),
image::FilterType::Nearest,
)
.to_rgba()
// TODO: might be a better way to do this
.pixels()
.map(|p| p.data)
.collect::<Vec<[u8; 4]>>(),
Graphic::Voxel(ref vox, min_samples) =>
super::renderer::draw_vox(&vox.as_ref().into(), aabr.size().into(), *min_samples),
Graphic::Blank => return None,
};
// Draw to allocated area.
cacher(aabr, &data);
// Insert area into map for retrieval.
self.rect_map
.insert((graphic_id, dims, source.map(|e| e.to_bits())), aabr);
// Return area.
Some(aabr)
}
None => None,
},
} }
// Increment frame
self.current_frame += 1;
// Reset unused entries
self.unused_entries_this_frame = None;
} }
} }

View File

@ -11,19 +11,20 @@ struct Voxel {
mvp: Mat4<f32>, mvp: Mat4<f32>,
} }
// TODO: use norm or remove it
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct Vert { struct Vert {
pos: Vec3<f32>, pos: Vec3<f32>,
col: Rgb<f32>, col: Rgb<f32>,
norm: Vec3<f32>, //norm: Vec3<f32>,
ao_level: u8, ao_level: u8,
} }
impl Vert { impl Vert {
fn new(pos: Vec3<f32>, col: Rgb<f32>, norm: Vec3<f32>, ao_level: u8) -> Self { fn new(pos: Vec3<f32>, col: Rgb<f32>, _norm: Vec3<f32>, ao_level: u8) -> Self {
Vert { Vert {
pos, pos,
col, col,
norm, //norm,
ao_level, ao_level,
} }
} }
@ -40,7 +41,7 @@ impl<'a> Pipeline for Voxel {
Vert { Vert {
pos, pos,
col, col,
norm: _, //norm: _,
ao_level, ao_level,
}: &Self::Vertex, }: &Self::Vertex,
) -> ([f32; 3], Self::VsOut) { ) -> ([f32; 3], Self::VsOut) {
@ -57,11 +58,7 @@ impl<'a> Pipeline for Voxel {
} }
} }
pub fn draw_vox( pub fn draw_vox(segment: &Segment, output_size: Vec2<u16>, min_samples: Option<u8>) -> RgbaImage {
segment: &Segment,
output_size: Vec2<u16>,
min_samples: Option<u8>,
) -> Vec<[u8; 4]> {
let scale = min_samples.map_or(1.0, |s| s as f32).sqrt().ceil() as usize; 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 dims = output_size.map(|e| e as usize * scale).into_array();
let mut color = Buffer2d::new(dims, [0; 4]); let mut color = Buffer2d::new(dims, [0; 4]);
@ -85,33 +82,29 @@ pub fn draw_vox(
&mut depth, &mut depth,
); );
if scale > 1 { let image = DynamicImage::ImageRgba8(
DynamicImage::ImageRgba8( RgbaImage::from_vec(
RgbaImage::from_vec( dims[0] as u32,
dims[0] as u32, dims[1] as u32,
dims[1] as u32, color
color .as_ref()
.as_ref() .iter()
.iter() .flatten()
.flatten() .cloned()
.cloned() .collect::<Vec<u8>>(),
.collect::<Vec<u8>>(),
)
.unwrap(),
) )
.resize_exact( .unwrap(),
);
if scale > 1 {
image.resize_exact(
output_size.x as u32, output_size.x as u32,
output_size.y as u32, output_size.y as u32,
image::FilterType::Triangle, image::FilterType::Triangle,
) )
.to_rgba()
.pixels()
.map(|p| p.data)
.collect::<Vec<[u8; 4]>>()
} else { } else {
// TODO: Remove clone. image
color.as_ref().to_vec()
} }
.to_rgba()
} }
fn ao_level(side1: bool, corner: bool, side2: bool) -> u8 { fn ao_level(side1: bool, corner: bool, side2: bool) -> u8 {

View File

@ -101,6 +101,8 @@ pub struct Ui {
ingame_locals: Vec<Consts<UiLocals>>, ingame_locals: Vec<Consts<UiLocals>>,
// Window size for updating scaling // Window size for updating scaling
window_resized: Option<Vec2<f64>>, window_resized: Option<Vec2<f64>>,
// Used to delay cache resizing until after current frame is drawn
need_cache_resize: bool,
// Scaling of the ui // Scaling of the ui
scale: Scale, scale: Scale,
} }
@ -122,6 +124,7 @@ impl Ui {
default_globals: renderer.create_consts(&[Globals::default()])?, default_globals: renderer.create_consts(&[Globals::default()])?,
ingame_locals: Vec::new(), ingame_locals: Vec::new(),
window_resized: None, window_resized: None,
need_cache_resize: false,
scale, scale,
}) })
} }
@ -216,6 +219,15 @@ impl Ui {
None => return, None => return,
}; };
if self.need_cache_resize {
// Resize graphic cache
self.cache.resize_graphic_cache(renderer).unwrap();
// Resize glyph cache
self.cache.resize_glyph_cache(renderer).unwrap();
self.need_cache_resize = false;
}
self.draw_commands.clear(); self.draw_commands.clear();
let mut mesh = Mesh::new(); let mut mesh = Mesh::new();
@ -344,7 +356,7 @@ impl Ui {
PrimitiveKind::Image { PrimitiveKind::Image {
image_id, image_id,
color, color,
source_rect, source_rect: _, // TODO: <-- use this
} => { } => {
let graphic_id = self let graphic_id = self
.image_map .image_map
@ -391,35 +403,25 @@ impl Ui {
max: Vec2::new(uv_r, uv_t), max: Vec2::new(uv_r, uv_t),
} }
}; };
// TODO: get dims from graphic_cache (or have it return floats directly)
let (cache_w, cache_h) = let (cache_w, cache_h) =
cache_tex.get_dimensions().map(|e| e as f32).into_tuple(); cache_tex.get_dimensions().map(|e| e as f32).into_tuple();
// Cache graphic at particular resolution. // Cache graphic at particular resolution.
let uv_aabr = match graphic_cache.cache_res( let uv_aabr =
*graphic_id, match graphic_cache.queue_res(*graphic_id, resolution, source_aabr) {
resolution, Some(aabr) => Aabr {
source_aabr, min: Vec2::new(
|aabr, data| { aabr.min.x as f32 / cache_w,
let offset = aabr.min.into_array(); aabr.max.y as f32 / cache_h,
let size = aabr.size().into_array(); ),
if let Err(err) = renderer.update_texture(cache_tex, offset, size, data) max: Vec2::new(
{ aabr.max.x as f32 / cache_w,
warn!("Failed to update texture: {:?}", err); aabr.min.y as f32 / cache_h,
} ),
}, },
) { None => continue,
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,
};
mesh.push_quad(create_ui_quad(gl_aabr(rect), uv_aabr, color, UiMode::Image)); mesh.push_quad(create_ui_quad(gl_aabr(rect), uv_aabr, color, UiMode::Image));
} }
@ -630,22 +632,31 @@ impl Ui {
.create_dynamic_model(mesh.vertices().len() * 4 / 3) .create_dynamic_model(mesh.vertices().len() * 4 / 3)
.unwrap(); .unwrap();
} }
renderer.update_model(&self.model, &mesh, 0).unwrap();
// Update model with new mesh. // Update model with new mesh.
renderer.update_model(&self.model, &mesh, 0).unwrap();
// Move cached graphics to the gpu
let (graphic_cache, cache_tex) = self.cache.graphic_cache_mut_and_tex();
graphic_cache.cache_queued(|aabr, data| {
let offset = aabr.min.into_array();
let size = aabr.size().into_array();
if let Err(err) = renderer.update_texture(cache_tex, offset, size, data) {
warn!("Failed to update texture: {:?}", err);
}
});
// Handle window resizing. // Handle window resizing.
if let Some(new_dims) = self.window_resized.take() { if let Some(new_dims) = self.window_resized.take() {
let (old_w, old_h) = self.scale.scaled_window_size().into_tuple();
self.scale.window_resized(new_dims, renderer); self.scale.window_resized(new_dims, renderer);
let (w, h) = self.scale.scaled_window_size().into_tuple(); let (w, h) = self.scale.scaled_window_size().into_tuple();
self.ui.handle_event(Input::Resize(w, h)); self.ui.handle_event(Input::Resize(w, h));
let res = renderer.get_resolution();
// Avoid panic in graphic cache when minimizing. // Avoid panic in graphic cache when minimizing.
if res.x > 0 && res.y > 0 { // Avoid resetting cache if window size didn't change
self.cache // Somewhat inefficient for elements that won't change size after a window resize
.clear_graphic_cache(renderer, renderer.get_resolution().map(|e| e * 4)); let res = renderer.get_resolution();
} self.need_cache_resize = res.x > 0 && res.y > 0 && !(old_w == w && old_h == h);
// TODO: Probably need to resize glyph cache, see conrod's gfx backend for reference.
} }
} }

View File

@ -48,10 +48,6 @@ impl Scale {
pub fn scale_factor_physical(&self) -> f64 { pub fn scale_factor_physical(&self) -> f64 {
self.scale_factor_logical() * self.dpi_factor self.scale_factor_logical() * self.dpi_factor
} }
// Get the dpi factor (ratio between physical and logical coordinates)
pub fn dpi_factor(&self) -> f64 {
self.dpi_factor
}
// Updates internal window size (and/or dpi_factor). // Updates internal window size (and/or dpi_factor).
pub fn window_resized(&mut self, new_dims: Vec2<f64>, renderer: &Renderer) { pub fn window_resized(&mut self, new_dims: Vec2<f64>, renderer: &Renderer) {
self.dpi_factor = renderer.get_resolution().x as f64 / new_dims.x; self.dpi_factor = renderer.get_resolution().x as f64 / new_dims.x;

View File

@ -1,8 +1,5 @@
use conrod_core::{ use conrod_core::{
builder_methods, builder_methods, position::Dimension, widget, Position, Ui, UiCell, Widget, WidgetCommon,
position::Dimension,
widget::{self, Id},
Position, Ui, UiCell, Widget, WidgetCommon,
}; };
use vek::*; use vek::*;
@ -18,12 +15,11 @@ pub trait Ingameable: Widget + Sized {
fn prim_count(&self) -> usize; fn prim_count(&self) -> usize;
// Note this is not responsible for the 3d positioning // Note this is not responsible for the 3d positioning
// Only call this directly if using IngameAnchor // Only call this directly if using IngameAnchor
fn set_ingame(self, id: widget::Id, parent_id: Id, ui: &mut UiCell) -> Self::Event { fn set_ingame(self, id: widget::Id, ui: &mut UiCell) -> Self::Event {
self self
// should pass focus to the window if these are clicked // should pass focus to the window if these are clicked
// (they are not displayed where conrod thinks they are) // (they are not displayed where conrod thinks they are)
.graphics_for(ui.window) .graphics_for(ui.window)
//.parent(parent_id) // TODO: Is this needed?
.set(id, ui) .set(id, ui)
} }
fn position_ingame(self, pos: Vec3<f32>) -> Ingame<Self> { fn position_ingame(self, pos: Vec3<f32>) -> Ingame<Self> {
@ -104,7 +100,7 @@ impl<W: Ingameable> Widget for Ingame<W> {
} }
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event { fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs { id, state, ui, .. } = args; let widget::UpdateArgs { state, ui, .. } = args;
let Ingame { let Ingame {
widget, parameters, .. widget, parameters, ..
} = self; } = self;
@ -116,19 +112,19 @@ impl<W: Ingameable> Widget for Ingame<W> {
}); });
} }
widget.set_ingame(state.id.unwrap(), id, ui) widget.set_ingame(state.id.unwrap(), ui)
} }
fn default_x_position(&self, ui: &Ui) -> Position { fn default_x_position(&self, _: &Ui) -> Position {
Position::Absolute(0.0) Position::Absolute(0.0)
} }
fn default_y_position(&self, ui: &Ui) -> Position { fn default_y_position(&self, _: &Ui) -> Position {
Position::Absolute(0.0) Position::Absolute(0.0)
} }
fn default_x_dimension(&self, ui: &Ui) -> Dimension { fn default_x_dimension(&self, _: &Ui) -> Dimension {
Dimension::Absolute(1.0) Dimension::Absolute(1.0)
} }
fn default_y_dimension(&self, ui: &Ui) -> Dimension { fn default_y_dimension(&self, _: &Ui) -> Dimension {
Dimension::Absolute(1.0) Dimension::Absolute(1.0)
} }
} }