2019-02-16 03:01:42 +00:00
|
|
|
// TODO: cache entire UI render (would be somewhat pointless if we are planning on constantly animated ui)
|
|
|
|
// TODO: figure out proper way to propagate events down to the ui
|
2019-01-30 12:11:34 +00:00
|
|
|
|
|
|
|
// Library
|
|
|
|
use image::DynamicImage;
|
2019-02-12 04:14:55 +00:00
|
|
|
use conrod_core::{
|
|
|
|
Ui as CrUi,
|
|
|
|
UiBuilder,
|
|
|
|
UiCell,
|
|
|
|
image::{Map, Id as ImgId},
|
2019-02-16 03:01:42 +00:00
|
|
|
widget::{Id as WidgId, id::Generator},
|
|
|
|
render::Primitive,
|
|
|
|
event::Input,
|
|
|
|
input::{Global, Widget},
|
2019-02-12 04:14:55 +00:00
|
|
|
};
|
2019-01-30 12:11:34 +00:00
|
|
|
|
|
|
|
// Crate
|
|
|
|
use crate::{
|
|
|
|
Error,
|
|
|
|
render::{
|
|
|
|
RenderError,
|
|
|
|
Renderer,
|
|
|
|
Model,
|
|
|
|
Texture,
|
|
|
|
UiPipeline,
|
2019-02-12 04:14:55 +00:00
|
|
|
UiLocals,
|
|
|
|
Consts,
|
2019-01-30 12:11:34 +00:00
|
|
|
create_ui_quad_mesh,
|
|
|
|
},
|
2019-02-16 03:01:42 +00:00
|
|
|
window::Window,
|
2019-01-30 12:11:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum UiError {
|
|
|
|
RenderError(RenderError),
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Cache {
|
|
|
|
model: Model<UiPipeline>,
|
|
|
|
blank_texture: Texture<UiPipeline>,
|
|
|
|
}
|
|
|
|
|
2019-02-16 03:01:42 +00:00
|
|
|
// TODO: Should functions be returning UiError instead of Error?
|
2019-01-30 12:11:34 +00:00
|
|
|
impl Cache {
|
|
|
|
pub fn new(renderer: &mut Renderer) -> Result<Self, Error> {
|
|
|
|
Ok(Self {
|
|
|
|
model: renderer.create_model(&create_ui_quad_mesh())?,
|
|
|
|
blank_texture: renderer.create_texture(&DynamicImage::new_rgba8(1, 1))?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn model(&self) -> &Model<UiPipeline> { &self.model }
|
|
|
|
pub fn blank_texture(&self) -> &Texture<UiPipeline> { &self.blank_texture }
|
|
|
|
}
|
|
|
|
|
2019-02-16 03:01:42 +00:00
|
|
|
pub enum UiPrimitive {
|
|
|
|
Image(Consts<UiLocals>, ImgId)
|
|
|
|
}
|
|
|
|
|
2019-01-30 12:11:34 +00:00
|
|
|
pub struct Ui {
|
2019-02-12 04:14:55 +00:00
|
|
|
ui: CrUi,
|
|
|
|
image_map: Map<Texture<UiPipeline>>,
|
2019-01-30 12:11:34 +00:00
|
|
|
cache: Cache,
|
2019-02-16 03:01:42 +00:00
|
|
|
// Primatives to draw on the next render
|
|
|
|
ui_primitives: Vec<UiPrimitive>,
|
2019-01-30 12:11:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Ui {
|
2019-02-16 03:01:42 +00:00
|
|
|
pub fn new(window: &mut Window) -> Result<Self, Error> {
|
|
|
|
// Retrieve the logical size of the window content
|
|
|
|
let (w, h) = window.logical_size();
|
2019-01-30 12:11:34 +00:00
|
|
|
Ok(Self {
|
2019-02-16 03:01:42 +00:00
|
|
|
ui: UiBuilder::new([w, h]).build(),
|
2019-02-12 04:14:55 +00:00
|
|
|
image_map: Map::new(),
|
2019-02-16 03:01:42 +00:00
|
|
|
cache: Cache::new(window.renderer_mut())?,
|
|
|
|
ui_primitives: vec![],
|
2019-01-30 12:11:34 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-02-12 04:14:55 +00:00
|
|
|
pub fn new_image(&mut self, renderer: &mut Renderer, image: &DynamicImage) -> Result<ImgId, Error> {
|
|
|
|
Ok(self.image_map.insert(renderer.create_texture(image)?))
|
|
|
|
}
|
|
|
|
|
2019-02-16 03:01:42 +00:00
|
|
|
pub fn id_generator(&mut self) -> Generator {
|
|
|
|
self.ui.widget_id_generator()
|
2019-02-12 04:14:55 +00:00
|
|
|
}
|
|
|
|
|
2019-02-16 03:01:42 +00:00
|
|
|
pub fn set_widgets(&mut self) -> UiCell {
|
|
|
|
self.ui.set_widgets()
|
2019-02-12 04:14:55 +00:00
|
|
|
}
|
|
|
|
|
2019-02-16 03:01:42 +00:00
|
|
|
pub fn handle_event(&mut self, event: Input) {
|
|
|
|
self.ui.handle_event(event);
|
|
|
|
}
|
2019-02-12 04:14:55 +00:00
|
|
|
|
2019-02-16 03:01:42 +00:00
|
|
|
pub fn widget_input(&self, id: WidgId) -> Widget {
|
|
|
|
self.ui.widget_input(id)
|
2019-01-30 12:11:34 +00:00
|
|
|
}
|
|
|
|
|
2019-02-16 03:01:42 +00:00
|
|
|
pub fn global_input(&self) -> &Global {
|
|
|
|
self.ui.global_input()
|
|
|
|
}
|
2019-02-12 04:14:55 +00:00
|
|
|
|
2019-02-16 03:01:42 +00:00
|
|
|
pub fn maintain(&mut self, renderer: &mut Renderer) {
|
|
|
|
let ref mut ui = self.ui;
|
|
|
|
// removed this because ui will resize itself now that it recieves events
|
|
|
|
// update window size
|
|
|
|
//let res = renderer.get_resolution().map(|e| e as f64);
|
|
|
|
//if res[0] != ui.win_w || res[1] != ui.win_h {
|
|
|
|
// ui.win_w = res[0];
|
|
|
|
// ui.win_h = res[1];
|
|
|
|
// ui.needs_redraw();
|
|
|
|
//}
|
|
|
|
// Gather primatives and recreate locals only if ui_changed
|
|
|
|
if let Some(mut primitives) = ui.draw_if_changed() {
|
|
|
|
self.ui_primitives.clear();
|
2019-02-12 04:14:55 +00:00
|
|
|
while let Some(prim) = primitives.next() {
|
2019-02-16 03:01:42 +00:00
|
|
|
// Transform from conrod to our render coords
|
|
|
|
// Conrod uses the center of the screen as the origin
|
|
|
|
// Up & Right are positive directions
|
|
|
|
let x = prim.rect.left();
|
|
|
|
let y = prim.rect.top();
|
|
|
|
let (w, h) = prim.rect.w_h();
|
|
|
|
let bounds = [
|
|
|
|
(x / ui.win_w + 0.5) as f32,
|
|
|
|
(-1.0 * (y / ui.win_h) + 0.5) as f32,
|
|
|
|
(w / ui.win_w) as f32,
|
|
|
|
(h / ui.win_h) as f32
|
|
|
|
];
|
|
|
|
// TODO: Remove this
|
|
|
|
let new_ui_locals = renderer.create_consts(&[UiLocals::new(bounds)])
|
|
|
|
.expect("Could not create new const for ui locals");
|
|
|
|
use conrod_core::render::{PrimitiveKind};
|
|
|
|
// TODO: Use scizzor
|
|
|
|
let Primitive {kind, scizzor, id, ..} = prim;
|
2019-02-12 04:14:55 +00:00
|
|
|
match kind {
|
|
|
|
PrimitiveKind::Image { image_id, color, source_rect } => {
|
2019-02-16 03:01:42 +00:00
|
|
|
//renderer.update_consts(&mut self.locals, &[UiLocals::new(
|
|
|
|
// [0.0, 0.0, 1.0, 1.0],
|
|
|
|
// )]);
|
|
|
|
self.ui_primitives.push(UiPrimitive::Image(new_ui_locals, image_id));
|
2019-02-12 04:14:55 +00:00
|
|
|
}
|
2019-02-16 03:01:42 +00:00
|
|
|
_ => {}
|
|
|
|
// TODO: Add these
|
|
|
|
//PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);}
|
|
|
|
//PrimitiveKind::Rectangle { color } => {println!("primitive kind rect[x:{},y:{},w:{},h:{}] with color {:?} and id {:?}", x, y, w, h, color, id);}
|
|
|
|
//PrimitiveKind::Text {..} => {println!("primitive kind text with id {:?}", id);}
|
|
|
|
//PrimitiveKind::TrianglesMultiColor {..} => {println!("primitive kind multicolor with id {:?}", id);}
|
|
|
|
//PrimitiveKind::TrianglesSingleColor {..} => {println!("primitive kind singlecolor with id {:?}", id);}
|
2019-02-12 04:14:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-30 12:11:34 +00:00
|
|
|
}
|
2019-02-16 03:01:42 +00:00
|
|
|
|
|
|
|
pub fn render(&self, renderer: &mut Renderer) {
|
|
|
|
self.ui_primitives.iter().for_each(|ui_primitive| match ui_primitive {
|
|
|
|
UiPrimitive::Image(ui_locals, image_id) => {
|
|
|
|
let tex = self.image_map.get(&image_id).expect("Image does not exist in image map");
|
|
|
|
renderer.render_ui_element(&self.cache.model(), &ui_locals, &tex);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2019-01-30 12:11:34 +00:00
|
|
|
}
|