WIP: clip_rect

This commit is contained in:
Emil Ernerfeldt 2020-04-20 23:33:16 +02:00
parent ffc1768e40
commit 2f02446f6f
14 changed files with 307 additions and 198 deletions

Binary file not shown.

View file

@ -82,7 +82,7 @@ impl Context {
} }
} }
pub fn drain_paint_lists(&self) -> Vec<PaintCmd> { pub fn drain_paint_lists(&self) -> Vec<(Rect, PaintCmd)> {
let memory = self.memory.lock(); let memory = self.memory.lock();
self.graphics.lock().drain(&memory.window_order).collect() self.graphics.lock().drain(&memory.window_order).collect()
} }
@ -224,7 +224,10 @@ impl Context {
} }
pub fn add_paint_cmd(&self, layer: Layer, paint_cmd: PaintCmd) { pub fn add_paint_cmd(&self, layer: Layer, paint_cmd: PaintCmd) {
self.graphics.lock().layer(layer).push(paint_cmd) self.graphics
.lock()
.layer(layer)
.push((Rect::everything(), paint_cmd))
} }
} }

View file

@ -1,9 +1,10 @@
use std::sync::Arc; use std::sync::Arc;
use crate::{layout, mesher::Mesher, widgets::*, *}; use crate::{layout, mesher::*, widgets::*, *};
#[derive(Clone, Copy, Default)] #[derive(Clone, Copy, Default)]
struct Stats { struct Stats {
num_batches: usize,
num_vertices: usize, num_vertices: usize,
num_triangles: usize, num_triangles: usize,
} }
@ -55,16 +56,20 @@ impl Emigui {
} }
} }
pub fn paint(&mut self) -> Mesh { pub fn paint(&mut self) -> PaintBatches {
let mesher_options = MesherOptions {
anti_alias: self.anti_alias,
aa_size: 1.0 / self.last_input.pixels_per_point,
};
let paint_commands = self.ctx.drain_paint_lists(); let paint_commands = self.ctx.drain_paint_lists();
let mut mesher = Mesher::new(self.last_input.pixels_per_point); let batches = mesh_paint_commands(&mesher_options, &self.ctx.fonts, paint_commands);
mesher.options.anti_alias = self.anti_alias; self.stats = Default::default();
self.stats.num_batches = batches.len();
mesher.paint(&self.ctx.fonts, &paint_commands); for (_, mesh) in &batches {
let mesh = mesher.mesh; self.stats.num_vertices += mesh.vertices.len();
self.stats.num_vertices = mesh.vertices.len(); self.stats.num_triangles += mesh.indices.len() / 3;
self.stats.num_triangles = mesh.indices.len() / 3; }
mesh batches
} }
pub fn ui(&mut self, region: &mut Region) { pub fn ui(&mut self, region: &mut Region) {
@ -104,6 +109,7 @@ impl Emigui {
region.cursor().x, region.cursor().x,
region.cursor().y, region.cursor().y,
)); ));
region.add(label!("num_batches: {}", self.stats.num_batches));
region.add(label!("num_vertices: {}", self.stats.num_vertices)); region.add(label!("num_vertices: {}", self.stats.num_vertices));
region.add(label!("num_triangles: {}", self.stats.num_triangles)); region.add(label!("num_triangles: {}", self.stats.num_triangles));
}); });

View file

@ -1,6 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::{Id, PaintCmd}; use crate::{math::Rect, Id, PaintCmd};
// TODO: support multiple windows // TODO: support multiple windows
#[derive(Clone, Copy, Eq, PartialEq, Hash)] #[derive(Clone, Copy, Eq, PartialEq, Hash)]
@ -11,7 +11,8 @@ pub enum Layer {
Popup, Popup,
} }
type PaintList = Vec<PaintCmd>; /// Each PaintCmd is paired with a clip rectangle.
type PaintList = Vec<(Rect, PaintCmd)>;
/// TODO: improve this /// TODO: improve this
#[derive(Clone, Default)] #[derive(Clone, Default)]
@ -30,7 +31,10 @@ impl GraphicLayers {
} }
} }
pub fn drain(&mut self, window_oreder: &[Id]) -> impl ExactSizeIterator<Item = PaintCmd> { pub fn drain(
&mut self,
window_oreder: &[Id],
) -> impl ExactSizeIterator<Item = (Rect, PaintCmd)> {
let mut all_commands: Vec<_> = self.bg.drain(..).collect(); let mut all_commands: Vec<_> = self.bg.drain(..).collect();
for id in window_oreder { for id in window_oreder {

View file

@ -70,6 +70,7 @@ pub enum Align {
/// Right/Bottom /// Right/Bottom
/// Note: requires a bounded/known available_width. /// Note: requires a bounded/known available_width.
Max, Max,
// TODO: Justified
} }
impl Default for Align { impl Default for Align {
@ -123,11 +124,14 @@ where
let mut graphics = ctx.graphics.lock(); let mut graphics = ctx.graphics.lock();
graphics.layer(layer).insert( graphics.layer(layer).insert(
where_to_put_background, where_to_put_background,
PaintCmd::Rect { (
corner_radius: 5.0, Rect::everything(),
fill_color: Some(style.background_fill_color()), PaintCmd::Rect {
outline: Some(Outline::new(1.0, color::WHITE)), corner_radius: 5.0,
rect, fill_color: Some(style.background_fill_color()),
}, outline: Some(Outline::new(1.0, color::WHITE)),
rect,
},
),
); );
} }

View file

@ -35,7 +35,7 @@ pub use {
layout::Align, layout::Align,
math::*, math::*,
memory::Memory, memory::Memory,
mesher::{Mesh, Vertex}, mesher::{Mesh, PaintBatches, Vertex},
region::Region, region::Region,
style::Style, style::Style,
texture_atlas::Texture, texture_atlas::Texture,

View file

@ -4,6 +4,13 @@ pub struct Vec2 {
pub y: f32, pub y: f32,
} }
impl PartialEq for Vec2 {
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y
}
}
impl Eq for Vec2 {}
impl Vec2 { impl Vec2 {
pub fn splat(v: impl Into<f32>) -> Vec2 { pub fn splat(v: impl Into<f32>) -> Vec2 {
let v: f32 = v.into(); let v: f32 = v.into();
@ -153,6 +160,13 @@ pub struct Pos2 {
// implicit w = 1 // implicit w = 1
} }
impl PartialEq for Pos2 {
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y
}
}
impl Eq for Pos2 {}
impl Pos2 { impl Pos2 {
pub fn dist(self: Pos2, other: Pos2) -> f32 { pub fn dist(self: Pos2, other: Pos2) -> f32 {
(self - other).length() (self - other).length()
@ -238,13 +252,30 @@ pub fn pos2(x: f32, y: f32) -> Pos2 {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct Rect { pub struct Rect {
min: Pos2, min: Pos2,
max: Pos2, max: Pos2,
} }
impl Rect { impl Rect {
/// Infinite rectangle that contains everything
pub fn everything() -> Self {
let inf = std::f32::INFINITY;
Self {
min: pos2(-inf, -inf),
max: pos2(inf, inf),
}
}
pub fn nothing() -> Self {
let inf = std::f32::INFINITY;
Self {
min: pos2(inf, inf),
max: pos2(-inf, -inf),
}
}
pub fn from_min_max(min: Pos2, max: Pos2) -> Self { pub fn from_min_max(min: Pos2, max: Pos2) -> Self {
Rect { min, max: max } Rect { min, max: max }
} }

View file

@ -15,8 +15,6 @@ pub struct Vertex {
pub color: Color, pub color: Color,
} }
// ----------------------------------------------------------------------------
#[derive(Clone, Debug, Default, Serialize)] #[derive(Clone, Debug, Default, Serialize)]
pub struct Mesh { pub struct Mesh {
/// Draw as triangles (i.e. the length is a multiple of three) /// Draw as triangles (i.e. the length is a multiple of three)
@ -24,6 +22,11 @@ pub struct Mesh {
pub vertices: Vec<Vertex>, pub vertices: Vec<Vertex>,
} }
/// Grouped by clip rectangles, in pixel coordinates
pub type PaintBatches = Vec<(Rect, Mesh)>;
// ----------------------------------------------------------------------------
impl Mesh { impl Mesh {
pub fn append(&mut self, mesh: &Mesh) { pub fn append(&mut self, mesh: &Mesh) {
let index_offset = self.vertices.len() as u32; let index_offset = self.vertices.len() as u32;
@ -373,139 +376,141 @@ pub fn paint_path(
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
pub struct Mesher { pub fn mesh_command(
pub options: MesherOptions, options: &MesherOptions,
fonts: &Fonts,
/// Where the output goes command: PaintCmd,
pub mesh: Mesh, out_mesh: &mut Mesh,
} ) {
match command {
impl Mesher { PaintCmd::Circle {
pub fn new(pixels_per_point: f32) -> Mesher { center,
Mesher { fill_color,
options: MesherOptions { outline,
anti_alias: true, radius,
aa_size: 1.0 / pixels_per_point, } => {
}, let mut path = Path::default();
mesh: Default::default(), path.add_circle(center, radius);
if let Some(color) = fill_color {
fill_closed_path(out_mesh, options, &path.0, color);
}
if let Some(outline) = outline {
paint_path(
out_mesh,
options,
Closed,
&path.0,
outline.color,
outline.width,
);
}
} }
} PaintCmd::Mesh(mesh) => {
out_mesh.append(&mesh);
pub fn paint(&mut self, fonts: &Fonts, commands: &[PaintCmd]) { }
let mut path = Path::default(); PaintCmd::Line {
points,
for cmd in commands { color,
match cmd { width,
PaintCmd::Circle { } => {
center, let n = points.len();
fill_color, if n >= 2 {
outline, let mut path = Path::default();
radius, path.add_line(&points);
} => { paint_path(out_mesh, options, Open, &path.0, color, width);
path.clear(); }
path.add_circle(*center, *radius); }
if let Some(color) = fill_color { PaintCmd::Path {
fill_closed_path(&mut self.mesh, &self.options, &path.0, *color); path,
} closed,
if let Some(outline) = outline { fill_color,
paint_path( outline,
&mut self.mesh, } => {
&self.options, if let Some(fill_color) = fill_color {
Closed, debug_assert!(
&path.0,
outline.color,
outline.width,
);
}
}
PaintCmd::Mesh(cmd_frame) => {
self.mesh.append(cmd_frame);
}
PaintCmd::Line {
points,
color,
width,
} => {
let n = points.len();
if n >= 2 {
path.clear();
path.add_line(points);
paint_path(&mut self.mesh, &self.options, Open, &path.0, *color, *width);
}
}
PaintCmd::Path {
path,
closed, closed,
fill_color, "You asked to fill a path that is not closed. That makes no sense."
outline, );
} => { fill_closed_path(out_mesh, options, &path.0, fill_color);
if let Some(fill_color) = fill_color { }
debug_assert!( if let Some(outline) = outline {
*closed, paint_path(
"You asked to fill a path that is not closed. That makes no sense." out_mesh,
); options,
fill_closed_path(&mut self.mesh, &self.options, &path.0, *fill_color); Closed,
} &path.0,
if let Some(outline) = outline { outline.color,
paint_path( outline.width,
&mut self.mesh, );
&self.options, }
Closed, }
&path.0, PaintCmd::Rect {
outline.color, corner_radius,
outline.width, fill_color,
); outline,
} rect,
} } => {
PaintCmd::Rect { let mut path = Path::default();
corner_radius, path.add_rounded_rectangle(&rect, corner_radius);
fill_color, if let Some(fill_color) = fill_color {
outline, fill_closed_path(out_mesh, options, &path.0, fill_color);
rect, }
} => { if let Some(outline) = outline {
path.clear(); paint_path(
path.add_rounded_rectangle(rect, *corner_radius); out_mesh,
if let Some(fill_color) = fill_color { options,
fill_closed_path(&mut self.mesh, &self.options, &path.0, *fill_color); Closed,
} &path.0,
if let Some(outline) = outline { outline.color,
paint_path( outline.width,
&mut self.mesh, );
&self.options, }
Closed, }
&path.0, PaintCmd::Text {
outline.color, color,
outline.width, pos,
); text,
} text_style,
} x_offsets,
PaintCmd::Text { } => {
color, let font = &fonts[text_style];
pos, for (c, x_offset) in text.chars().zip(x_offsets.iter()) {
text, if let Some(glyph) = font.uv_rect(c) {
text_style, let mut top_left = Vertex {
x_offsets, pos: pos + glyph.offset + vec2(*x_offset, 0.0),
} => { uv: glyph.min,
let font = &fonts[*text_style]; color: color,
for (c, x_offset) in text.chars().zip(x_offsets.iter()) { };
if let Some(glyph) = font.uv_rect(c) { top_left.pos.x = font.round_to_pixel(top_left.pos.x); // Pixel-perfection.
let mut top_left = Vertex { top_left.pos.y = font.round_to_pixel(top_left.pos.y); // Pixel-perfection.
pos: *pos + glyph.offset + vec2(*x_offset, 0.0), let bottom_right = Vertex {
uv: glyph.min, pos: top_left.pos + glyph.size,
color: *color, uv: glyph.max,
}; color: color,
top_left.pos.x = font.round_to_pixel(top_left.pos.x); // Pixel-perfection. };
top_left.pos.y = font.round_to_pixel(top_left.pos.y); // Pixel-perfection. out_mesh.add_rect(top_left, bottom_right);
let bottom_right = Vertex {
pos: top_left.pos + glyph.size,
uv: glyph.max,
color: *color,
};
self.mesh.add_rect(top_left, bottom_right);
}
}
} }
} }
} }
} }
} }
pub fn mesh_paint_commands(
options: &MesherOptions,
fonts: &Fonts,
commands: Vec<(Rect, PaintCmd)>,
) -> Vec<(Rect, Mesh)> {
let mut batches = PaintBatches::default();
for (clip_rect, cmd) in commands {
// TODO: cull(clip_rect, cmd)
if batches.is_empty() || batches.last().unwrap().0 != clip_rect {
batches.push((clip_rect, Mesh::default()));
}
let out_mesh = &mut batches.last_mut().unwrap().1;
mesh_command(options, fonts, cmd, out_mesh);
}
batches
}

View file

@ -61,11 +61,20 @@ impl Region {
/// Can be used for free painting. /// Can be used for free painting.
/// NOTE: all coordinates are screen coordinates! /// NOTE: all coordinates are screen coordinates!
pub fn add_paint_cmd(&mut self, paint_cmd: PaintCmd) { pub fn add_paint_cmd(&mut self, paint_cmd: PaintCmd) {
self.ctx.graphics.lock().layer(self.layer).push(paint_cmd) self.ctx
.graphics
.lock()
.layer(self.layer)
.push((self.clip_rect(), paint_cmd))
} }
pub fn add_paint_cmds(&mut self, mut cmds: Vec<PaintCmd>) { pub fn add_paint_cmds(&mut self, mut cmds: Vec<PaintCmd>) {
self.ctx.graphics.lock().layer(self.layer).append(&mut cmds) let clip_rect = self.clip_rect();
self.ctx
.graphics
.lock()
.layer(self.layer)
.extend(cmds.drain(..).map(|cmd| (clip_rect, cmd)));
} }
/// Options for this region, and any child regions we may spawn. /// Options for this region, and any child regions we may spawn.
@ -85,6 +94,13 @@ impl Region {
&*self.ctx.fonts &*self.ctx.fonts
} }
/// Screen-space rectangle for clipping what we paint in this region.
/// This is used, for instance, to avoid painting outside a window that is smaller
/// than its contents.
pub fn clip_rect(&self) -> Rect {
self.rect
}
pub fn available_width(&self) -> f32 { pub fn available_width(&self) -> f32 {
self.rect.max().x - self.cursor.x self.rect.max().x - self.cursor.x
} }

View file

@ -123,12 +123,15 @@ impl Window {
let corner_radius = style.window.corner_radius; let corner_radius = style.window.corner_radius;
graphics.layer(layer).insert( graphics.layer(layer).insert(
where_to_put_background, where_to_put_background,
PaintCmd::Rect { (
corner_radius, Rect::everything(),
fill_color: Some(style.background_fill_color()), PaintCmd::Rect {
outline: Some(Outline::new(1.0, color::WHITE)), corner_radius,
rect: state.rect, fill_color: Some(style.background_fill_color()),
}, outline: Some(Outline::new(1.0, color::WHITE)),
rect: state.rect,
},
),
); );
let corner_interact = if self.resizeable { let corner_interact = if self.resizeable {
@ -148,12 +151,15 @@ impl Window {
path.add_point(corner_center, vec2(-1.0, 0.0)); path.add_point(corner_center, vec2(-1.0, 0.0));
graphics.layer(layer).insert( graphics.layer(layer).insert(
where_to_put_background + 1, where_to_put_background + 1,
PaintCmd::Path { (
path, Rect::everything(),
closed: true, PaintCmd::Path {
fill_color: style.interact_fill_color(&corner_interact), path,
outline: style.interact_outline(&corner_interact), closed: true,
}, fill_color: style.interact_fill_color(&corner_interact),
outline: style.interact_outline(&corner_interact),
},
),
); );
corner_interact corner_interact
} else { } else {

View file

@ -1,8 +1,8 @@
#![allow(deprecated)] // legacy implement_vertex macro #![allow(deprecated)] // legacy implement_vertex macro
use { use {
emigui::Mesh, emigui::{Mesh, PaintBatches, Rect},
glium::{implement_vertex, index::PrimitiveType, program, texture, uniform, Surface}, glium::{implement_vertex, index::PrimitiveType, program, texture, uniform, Frame, Surface},
}; };
pub struct Painter { pub struct Painter {
@ -17,29 +17,36 @@ impl Painter {
140 => { 140 => {
vertex: " vertex: "
#version 140 #version 140
uniform vec4 u_clip_rect; // min_x, min_y, max_x, max_y
uniform vec2 u_screen_size; uniform vec2 u_screen_size;
uniform vec2 u_tex_size; uniform vec2 u_tex_size;
in vec2 a_pos; in vec2 a_pos;
in vec4 a_color; in vec4 a_color;
in vec2 a_tc; in vec2 a_tc;
out vec2 v_pos;
out vec4 v_color; out vec4 v_color;
out vec2 v_tc; out vec2 v_tc;
out vec4 v_clip_rect;
void main() { void main() {
gl_Position = vec4( gl_Position = vec4(
2.0 * a_pos.x / u_screen_size.x - 1.0, 2.0 * a_pos.x / u_screen_size.x - 1.0,
1.0 - 2.0 * a_pos.y / u_screen_size.y, 1.0 - 2.0 * a_pos.y / u_screen_size.y,
0.0, 0.0,
1.0); 1.0);
v_pos = a_pos;
v_color = a_color / 255.0; v_color = a_color / 255.0;
v_tc = a_tc / u_tex_size; v_tc = a_tc / u_tex_size;
v_clip_rect = u_clip_rect;
} }
", ",
fragment: " fragment: "
#version 140 #version 140
uniform sampler2D u_sampler; uniform sampler2D u_sampler;
in vec2 v_pos;
in vec4 v_color; in vec4 v_color;
in vec2 v_tc; in vec2 v_tc;
in vec4 v_clip_rect;
out vec4 f_color; out vec4 f_color;
// glium expects linear output. // glium expects linear output.
@ -51,6 +58,10 @@ impl Painter {
} }
void main() { void main() {
if (v_pos.x < v_clip_rect.x) { discard; }
if (v_pos.y < v_clip_rect.y) { discard; }
// if (v_pos.x < v_clip_rect.z) { discard; } // TODO
// if (v_pos.y > v_clip_rect.w) { discard; } // TODO
f_color = v_color; f_color = v_color;
f_color.rgb = linear_from_srgb(f_color.rgb); f_color.rgb = linear_from_srgb(f_color.rgb);
f_color.a *= texture(u_sampler, v_tc).r; f_color.a *= texture(u_sampler, v_tc).r;
@ -61,6 +72,7 @@ impl Painter {
110 => { 110 => {
vertex: " vertex: "
#version 110 #version 110
uniform vec4 u_clip_rect; // min_x, min_y, max_x, max_y
uniform vec2 u_screen_size; uniform vec2 u_screen_size;
uniform vec2 u_tex_size; uniform vec2 u_tex_size;
attribute vec2 a_pos; attribute vec2 a_pos;
@ -104,6 +116,7 @@ impl Painter {
100 => { 100 => {
vertex: " vertex: "
#version 100 #version 100
uniform mediump vec4 u_clip_rect; // min_x, min_y, max_x, max_y
uniform mediump vec2 u_screen_size; uniform mediump vec2 u_screen_size;
uniform mediump vec2 u_tex_size; uniform mediump vec2 u_tex_size;
attribute mediump vec2 a_pos; attribute mediump vec2 a_pos;
@ -177,9 +190,30 @@ impl Painter {
self.current_texture_id = Some(texture.id); self.current_texture_id = Some(texture.id);
} }
pub fn paint(&mut self, display: &glium::Display, mesh: Mesh, texture: &emigui::Texture) { pub fn paint_batches(
&mut self,
display: &glium::Display,
batches: PaintBatches,
texture: &emigui::Texture,
) {
self.upload_texture(display, texture); self.upload_texture(display, texture);
let mut target = display.draw();
target.clear_color(0.0, 0.0, 0.0, 0.0);
for (clip_rect, mesh) in batches {
self.paint_batch(&mut target, display, &clip_rect, &mesh, texture)
}
target.finish().unwrap();
}
fn paint_batch(
&mut self,
target: &mut Frame,
display: &glium::Display,
clip_rect: &Rect,
mesh: &Mesh,
texture: &emigui::Texture,
) {
let vertex_buffer = { let vertex_buffer = {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct Vertex { struct Vertex {
@ -213,6 +247,8 @@ impl Painter {
let height_points = height_pixels as f32 / pixels_per_point; let height_points = height_pixels as f32 / pixels_per_point;
let uniforms = uniform! { let uniforms = uniform! {
u_clip_rect_min: [clip_rect.min().x, clip_rect.min().y],
u_clip_rect_max: [clip_rect.max().x, clip_rect.max().y],
u_screen_size: [width_points, height_points], u_screen_size: [width_points, height_points],
u_tex_size: [texture.width as f32, texture.height as f32], u_tex_size: [texture.width as f32, texture.height as f32],
u_sampler: &self.texture, u_sampler: &self.texture,
@ -223,8 +259,6 @@ impl Painter {
..Default::default() ..Default::default()
}; };
let mut target = display.draw();
target.clear_color(0.0, 0.0, 0.0, 0.0);
target target
.draw( .draw(
&vertex_buffer, &vertex_buffer,
@ -234,6 +268,5 @@ impl Painter {
&params, &params,
) )
.unwrap(); .unwrap();
target.finish().unwrap();
} }
} }

View file

@ -4,7 +4,7 @@ use {
web_sys::{WebGlBuffer, WebGlProgram, WebGlRenderingContext, WebGlShader, WebGlTexture}, web_sys::{WebGlBuffer, WebGlProgram, WebGlRenderingContext, WebGlShader, WebGlTexture},
}; };
use emigui::{Color, Mesh, Texture}; use emigui::{Color, Mesh, PaintBatches, Rect, Texture};
type Gl = WebGlRenderingContext; type Gl = WebGlRenderingContext;
@ -143,10 +143,10 @@ impl Painter {
self.current_texture_id = Some(texture.id); self.current_texture_id = Some(texture.id);
} }
pub fn paint( pub fn paint_batches(
&mut self, &mut self,
bg_color: Color, bg_color: Color,
mesh: Mesh, batches: PaintBatches,
texture: &Texture, texture: &Texture,
pixels_per_point: f32, pixels_per_point: f32,
) -> Result<(), JsValue> { ) -> Result<(), JsValue> {
@ -195,13 +195,15 @@ impl Painter {
); );
gl.clear(Gl::COLOR_BUFFER_BIT); gl.clear(Gl::COLOR_BUFFER_BIT);
for mesh in mesh.split_to_u16() { for (clip_rect, mesh) in batches {
self.paint_mesh(&mesh)?; for mesh in mesh.split_to_u16() {
self.paint_mesh(&clip_rect, &mesh)?;
}
} }
Ok(()) Ok(())
} }
fn paint_mesh(&mut self, mesh: &Mesh) -> Result<(), JsValue> { fn paint_mesh(&mut self, _clip_rec: &Rect, mesh: &Mesh) -> Result<(), JsValue> {
let indices: Vec<u16> = mesh.indices.iter().map(|idx| *idx as u16).collect(); let indices: Vec<u16> = mesh.indices.iter().map(|idx| *idx as u16).collect();
let mut positions: Vec<f32> = Vec::with_capacity(2 * mesh.vertices.len()); let mut positions: Vec<f32> = Vec::with_capacity(2 * mesh.vertices.len());

View file

@ -102,10 +102,11 @@ fn main() {
.show(region.ctx(), |region| { .show(region.ctx(), |region| {
region region
.add_label("This window may shrink so small that its contents no longer fit."); .add_label("This window may shrink so small that its contents no longer fit.");
region.add_label("Maybe you can no longer read this, for instance");
region.add_label("And this line may be way too far down.");
}); });
let mesh = emigui.paint(); painter.paint_batches(&display, emigui.paint(), emigui.texture());
painter.paint(&display, mesh, emigui.texture());
let cursor = *emigui.ctx.cursor_icon.lock(); let cursor = *emigui.ctx.cursor_icon.lock();
let cursor = match cursor { let cursor = match cursor {

View file

@ -46,39 +46,37 @@ impl State {
let mut region = region.centered_column(region.available_width().min(480.0)); let mut region = region.centered_column(region.available_width().min(480.0));
region.set_align(Align::Min); region.set_align(Align::Min);
region.add(label!("Emigui!").text_style(TextStyle::Heading)); region.add(label!("Emigui!").text_style(TextStyle::Heading));
region.add(label!("Emigui is an immediate mode GUI written in Rust, compiled to WebAssembly, rendered with WebGL.")); region.add_label("Emigui is an immediate mode GUI written in Rust, compiled to WebAssembly, rendered with WebGL.");
region.add(label!( region.add_label(
"Everything you see is rendered as textured triangles. There is no DOM. There are no HTML elements." "Everything you see is rendered as textured triangles. There is no DOM. There are no HTML elements."
)); );
region.add(label!("This not JavaScript. This is Rust code, running at 60 Hz. This is the web page, reinvented with game tech.")); region.add_label("This not JavaScript. This is Rust code, running at 60 Hz. This is the web page, reinvented with game tech.");
region.add(label!( region.add_label("This is also work in progress, and not ready for production... yet :)");
"This is also work in progress, and not ready for production... yet :)"
));
region.add(Separator::new()); region.add(Separator::new());
self.example_app.ui(&mut region); self.example_app.ui(&mut region);
self.emigui.ui(&mut region); self.emigui.ui(&mut region);
region.set_align(Align::Min); region.set_align(Align::Min);
region.add(label!("WebGl painter info:")); region.add_label("WebGl painter info:");
region.indent(|region| { region.indent(|region| {
region.add(label!(self.webgl_painter.debug_info())); region.add_label(self.webgl_painter.debug_info());
}); });
region.add( region.add(
label!("Everything: {:.1} ms", self.everything_ms).text_style(TextStyle::Monospace), label!("Everything: {:.1} ms", self.everything_ms).text_style(TextStyle::Monospace),
); );
Window::new("Test window").show(region.ctx(), |region| { // TODO: Make it even simpler to show a window
region.add(label!("Grab the window and move it around!"));
region.add(label!( Window::new("Test window").show(region.ctx(), |region| {
"This window can be reisized, but not smaller than the contents." region.add_label("Grab the window and move it around!");
));
region.add_label("This window can be reisized, but not smaller than the contents.");
}); });
Window::new("Another test window") Window::new("Another test window")
.default_pos(pos2(400.0, 100.0)) .default_pos(pos2(400.0, 100.0))
.show(region.ctx(), |region| { .show(region.ctx(), |region| {
region.add(label!("This might be on top of the other window?")); region.add_label("This might be on top of the other window?");
region.add(label!("Second line of text")); region.add_label("Second line of text");
}); });
let bg_color = srgba(16, 16, 16, 255); let bg_color = srgba(16, 16, 16, 255);