use conrod_core::{
Rect,
image,
render,
text,
utils,
};
use piston_graphics;
#[doc(inline)]
pub use piston_graphics::{Context, DrawState, Graphics, ImageSize, Transformed};
pub fn primitives<'a, P, G, T, Img, C, F>(
mut primitives: P,
context: Context,
graphics: &'a mut G,
text_texture_cache: &'a mut T,
glyph_cache: &'a mut text::GlyphCache,
image_map: &'a image::Map<Img>,
mut cache_queued_glyphs: C,
mut texture_from_image: F,
)
where P: render::PrimitiveWalker,
G: Graphics<Texture=T>,
T: ImageSize,
C: FnMut(&mut G, &mut T, text::rt::Rect<u32>, &[u8]),
F: FnMut(&Img) -> &T,
{
let mut glyph_rectangles = Vec::new();
while let Some(prim) = render::PrimitiveWalker::next_primitive(&mut primitives) {
primitive(prim,
context,
graphics,
text_texture_cache,
glyph_cache,
image_map,
&mut glyph_rectangles,
&mut cache_queued_glyphs,
&mut texture_from_image);
}
}
pub fn primitive<'a, Img, G, T, C, F>(
primitive: render::Primitive,
context: Context,
graphics: &'a mut G,
text_texture_cache: &'a mut T,
glyph_cache: &'a mut text::GlyphCache,
image_map: &'a image::Map<Img>,
glyph_rectangles: &mut Vec<([f64; 4], [f64; 4])>,
mut cache_queued_glyphs: C,
mut texture_from_image: F,
)
where G: Graphics<Texture=T>,
T: ImageSize,
C: FnMut(&mut G, &mut T, text::rt::Rect<u32>, &[u8]),
F: FnMut(&Img) -> &T,
{
let render::Primitive { kind, scizzor, rect, .. } = primitive;
let view_size = context.get_view_size();
let context = context.trans(view_size[0] / 2.0, view_size[1] / 2.0).scale(1.0, -1.0);
let context = crop_context(context, scizzor);
match kind {
render::PrimitiveKind::Rectangle { color } => {
let (l, b, w, h) = rect.l_b_w_h();
let lbwh = [l, b, w, h];
let rectangle = piston_graphics::Rectangle::new(color.to_fsa());
rectangle.draw(lbwh, &context.draw_state, context.transform, graphics);
},
render::PrimitiveKind::TrianglesSingleColor { color, triangles } => {
for triangle in triangles {
let polygon = piston_graphics::Polygon::new(color.into());
polygon.draw(&triangle[..], &context.draw_state, context.transform, graphics);
}
},
render::PrimitiveKind::TrianglesMultiColor { triangles } => {
for triangle in triangles {
let color = triangle[0].1.into();
let polygon = piston_graphics::Polygon::new(color);
let points = [triangle[0].0, triangle[1].0, triangle[2].0];
polygon.draw(&points, &context.draw_state, context.transform, graphics);
}
},
render::PrimitiveKind::Text { color, text, font_id } => {
let dpi_factor = context.viewport
.map(|v| v.draw_size[0] as f32 / v.window_size[0] as f32)
.unwrap_or(1.0);
let positioned_glyphs = text.positioned_glyphs(dpi_factor);
let context = context.scale(1.0, -1.0).trans(-view_size[0] / 2.0, -view_size[1] / 2.0);
for glyph in positioned_glyphs.iter() {
glyph_cache.queue_glyph(font_id.index(), glyph.clone());
}
glyph_cache.cache_queued(|rect, data| {
cache_queued_glyphs(graphics, text_texture_cache, rect, data)
}).unwrap();
let cache_id = font_id.index();
let (tex_w, tex_h) = text_texture_cache.get_size();
let color = color.to_fsa();
let rectangles = positioned_glyphs.into_iter()
.filter_map(|g| glyph_cache.rect_for(cache_id, g).ok().unwrap_or(None))
.map(|(uv_rect, screen_rect)| {
let rectangle = {
let div_dpi_factor = |s| (s as f32 / dpi_factor as f32) as f64;
let left = div_dpi_factor(screen_rect.min.x);
let top = div_dpi_factor(screen_rect.min.y);
let right = div_dpi_factor(screen_rect.max.x);
let bottom = div_dpi_factor(screen_rect.max.y);
let w = right - left;
let h = bottom - top;
[left, top, w, h]
};
let source_rectangle = {
let x = (uv_rect.min.x * tex_w as f32) as f64;
let y = (uv_rect.min.y * tex_h as f32) as f64;
let w = ((uv_rect.max.x - uv_rect.min.x) * tex_w as f32) as f64;
let h = ((uv_rect.max.y - uv_rect.min.y) * tex_h as f32) as f64;
[x, y, w, h]
};
(rectangle, source_rectangle)
});
glyph_rectangles.clear();
glyph_rectangles.extend(rectangles);
piston_graphics::image::draw_many(&glyph_rectangles,
color,
text_texture_cache,
&context.draw_state,
context.transform,
graphics);
},
render::PrimitiveKind::Image { image_id, color, source_rect } => {
if let Some(img) = image_map.get(&image_id) {
let mut image = piston_graphics::image::Image::new();
image.color = color.map(|c| c.to_fsa());
if let Some(source_rect) = source_rect {
let (x, y, w, h) = source_rect.x_y_w_h();
image.source_rectangle = Some([x, y, w, h]);
}
let (left, top, w, h) = rect.l_t_w_h();
image.rectangle = Some([0.0, 0.0, w, h]);
let context = context.trans(left, top).scale(1.0, -1.0);
let transform = context.transform;
let draw_state = &context.draw_state;
let tex = texture_from_image(img);
image.draw(tex, draw_state, transform, graphics);
}
},
render::PrimitiveKind::Other(_widget) => {
},
}
}
fn crop_context(context: Context, rect: Rect) -> Context {
use self::utils::map_range;
let Context { draw_state, .. } = context;
let (x, y, w, h) = rect.x_y_w_h();
let view_dim = context.get_view_size();
let draw_dim = match context.viewport {
Some(viewport) => [viewport.draw_size[0] as f64, viewport.draw_size[1] as f64],
None => view_dim,
};
let left = -view_dim[0] / 2.0;
let right = view_dim[0] / 2.0;
let bottom = -view_dim[1] / 2.0;
let top = view_dim[1] / 2.0;
let left_x = x - w as f64 / 2.0;
let top_y = y + h as f64 / 2.0;
let x = map_range(left_x, left, right, 0, draw_dim[0] as i32);
let y = map_range(top_y, top, bottom, 0, draw_dim[1] as i32);
let w_scale = draw_dim[0] / view_dim[0];
let h_scale = draw_dim[1] / view_dim[1];
let w = w * w_scale;
let h = h * h_scale;
let x_neg = if x < 0 { x } else { 0 };
let y_neg = if y < 0 { y } else { 0 };
let mut x = ::std::cmp::max(0, x) as u32;
let mut y = ::std::cmp::max(0, y) as u32;
let mut w = ::std::cmp::max(0, w as i32 + x_neg) as u32;
let mut h = ::std::cmp::max(0, h as i32 + y_neg) as u32;
if let Some(rect) = draw_state.scissor {
let (r_x, r_y, r_w, r_h) = (rect[0], rect[1], rect[2], rect[3]);
if x + w < r_x || r_x + r_w < x || y + h < r_y || r_y + r_h < y {
w = 0;
h = 0;
} else {
let (a_l, a_r, a_b, a_t) = (x, x+w, y, y+h);
let (b_l, b_r, b_b, b_t) = (r_x, r_x+r_w, r_y, r_y+r_h);
let l = if a_l > b_l { a_l } else { b_l };
let r = if a_r < b_r { a_r } else { b_r };
let b = if a_b > b_b { a_b } else { b_b };
let t = if a_t < b_t { a_t } else { b_t };
x = l;
y = b;
w = r - l;
h = t - b;
}
}
Context { draw_state: draw_state.scissor([x, y, w, h]), ..context }
}