From 616245c32334e966c6565e9bc11249dcb55392e9 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 16 Jan 2019 17:09:12 -0600 Subject: [PATCH] Refactor: create Texture struct --- TODO.md | 2 +- emigui/src/emigui.rs | 4 +- emigui/src/font.rs | 8 ++- emigui/src/fonts.rs | 28 ++++---- emigui/src/lib.rs | 1 + emigui/src/texture_atlas.rs | 125 +++++++++++++++++++----------------- emigui_wasm/src/webgl.rs | 21 +++--- 7 files changed, 102 insertions(+), 87 deletions(-) diff --git a/TODO.md b/TODO.md index f482eb97..b1f4f11a 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,6 @@ # Code * Break off example app from emigui_wasm -* Add Rect type to GuiCmd. Every thing has a bounding rectangle, even text +* Try it on iPhone * Dynamic fonts: * Font options (sizes) * Read ttf via web? diff --git a/emigui/src/emigui.rs b/emigui/src/emigui.rs index 3265dba9..30f834ed 100644 --- a/emigui/src/emigui.rs +++ b/emigui/src/emigui.rs @@ -6,7 +6,7 @@ use crate::{ style, types::GuiInput, widgets::*, - Frame, RawInput, + Frame, RawInput, Texture, }; #[derive(Clone, Copy, Default)] @@ -55,7 +55,7 @@ impl Emigui { } } - pub fn texture(&self) -> (u16, u16, &[u8]) { + pub fn texture(&self) -> &Texture { self.data.fonts.texture() } diff --git a/emigui/src/font.rs b/emigui/src/font.rs index 82b42890..72b04c06 100644 --- a/emigui/src/font.rs +++ b/emigui/src/font.rs @@ -98,11 +98,12 @@ impl Font { let glyph_pos = atlas_lock.allocate((glyph_width, glyph_height)); + let texture = atlas_lock.texture_mut(); glyph.draw(|x, y, v| { if v > 0.0 { let px = glyph_pos.0 + x as usize; let py = glyph_pos.1 + y as usize; - atlas_lock[(px, py)] = (v * 255.0).round() as u8; + texture[(px, py)] = (v * 255.0).round() as u8; } }); @@ -271,7 +272,8 @@ impl Font { } pub fn debug_print_all_chars(&self) { - let atlas_lock = self.atlas.lock().unwrap(); + let mut atlas_lock = self.atlas.lock().unwrap(); + let texture_mut = atlas_lock.texture_mut(); let max_width = 160; let scale = Scale::uniform(self.scale as f32); @@ -295,7 +297,7 @@ impl Font { if let Some(uv) = glyph.uv { for x in uv.min.0..=uv.max.0 { for y in uv.min.1..=uv.max.1 { - let pixel = atlas_lock[(x as usize, y as usize)]; + let pixel = texture_mut[(x as usize, y as usize)]; let rx = uv.offset.0 + x as i16 - uv.min.0 as i16; let ry = uv.offset.1 + y as i16 - uv.min.1 as i16; let px = (cursor_x + rx as f32).round(); diff --git a/emigui/src/fonts.rs b/emigui/src/fonts.rs index 05119df3..cb4cbfcb 100644 --- a/emigui/src/fonts.rs +++ b/emigui/src/fonts.rs @@ -3,7 +3,10 @@ use std::{ sync::{Arc, Mutex}, }; -use crate::{font::Font, texture_atlas::TextureAtlas}; +use crate::{ + font::Font, + texture_atlas::{Texture, TextureAtlas}, +}; /// TODO: rename #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize)] @@ -16,7 +19,7 @@ pub enum TextStyle { pub struct Fonts { fonts: BTreeMap, - texture: (u16, u16, Vec), + texture: Texture, } impl Fonts { @@ -25,27 +28,30 @@ impl Fonts { // Make one white pixel for use for various stuff: let pos = atlas.allocate((1, 1)); - atlas[pos] = 255; + atlas.texture_mut()[pos] = 255; let atlas = Arc::new(Mutex::new(atlas)); // TODO: figure out a way to make the wasm smaller despite including a font. - // let font_data = include_bytes!("../fonts/ProggyClean.ttf"); // Use 13 for this. NOTHING ELSE. - // let font_data = include_bytes!("../fonts/DejaVuSans.ttf"); - let font_data = include_bytes!("../fonts/Roboto-Regular.ttf"); + // let typeface_data = include_bytes!("../fonts/ProggyClean.ttf"); // Use 13 for this. NOTHING ELSE. + // let typeface_data = include_bytes!("../fonts/DejaVuSans.ttf"); + let typeface_data = include_bytes!("../fonts/Roboto-Regular.ttf"); let mut fonts = BTreeMap::new(); - fonts.insert(TextStyle::Body, Font::new(atlas.clone(), font_data, 20)); + fonts.insert(TextStyle::Body, Font::new(atlas.clone(), typeface_data, 20)); fonts.insert(TextStyle::Button, fonts[&TextStyle::Body].clone()); - fonts.insert(TextStyle::Heading, Font::new(atlas.clone(), font_data, 30)); + fonts.insert( + TextStyle::Heading, + Font::new(atlas.clone(), typeface_data, 30), + ); - let texture = atlas.lock().unwrap().clone().into_texture(); + let texture = atlas.lock().unwrap().clone().texture().clone(); Fonts { fonts, texture } } - pub fn texture(&self) -> (u16, u16, &[u8]) { - (self.texture.0, self.texture.1, &self.texture.2) + pub fn texture(&self) -> &Texture { + &self.texture } } diff --git a/emigui/src/lib.rs b/emigui/src/lib.rs index c7404868..613b987b 100644 --- a/emigui/src/lib.rs +++ b/emigui/src/lib.rs @@ -23,5 +23,6 @@ pub use crate::{ layout::{Align, LayoutOptions, Region}, mesher::{Frame, Vertex}, style::Style, + texture_atlas::Texture, types::RawInput, }; diff --git a/emigui/src/texture_atlas.rs b/emigui/src/texture_atlas.rs index 2d7098b0..659da946 100644 --- a/emigui/src/texture_atlas.rs +++ b/emigui/src/texture_atlas.rs @@ -1,63 +1,13 @@ -/// A texture pixels, used for fonts. #[derive(Clone, Default)] -pub struct TextureAtlas { - width: usize, - height: usize, - pixels: Vec, - - /// Used for when adding new rects - cursor: (usize, usize), - row_height: usize, +pub struct Texture { + /// e.g. a hash of the data. Use this to detect changes! + pub id: u64, // TODO + pub width: usize, + pub height: usize, + pub pixels: Vec, } -impl TextureAtlas { - pub fn new(width: usize, height: usize) -> Self { - TextureAtlas { - width, - height, - pixels: vec![0; width * height], - ..Default::default() - } - } - - pub fn width(&self) -> usize { - self.width - } - - pub fn height(&self) -> usize { - self.height - } - - pub fn into_texture(self) -> (u16, u16, Vec) { - (self.width as u16, self.height as u16, self.pixels) - } - - /// Returns the coordinates of where the rect ended up. - pub fn allocate(&mut self, (w, h): (usize, usize)) -> (usize, usize) { - assert!(w <= self.width); - if self.cursor.0 + w > self.width { - // New row: - self.cursor.0 = 0; - self.cursor.1 += self.row_height; - self.row_height = 0; - } - - self.row_height = self.row_height.max(h); - while self.cursor.1 + self.row_height >= self.height { - self.height *= 2; - } - - if self.width * self.height > self.pixels.len() { - self.pixels.resize(self.width * self.height, 0); - } - - let pos = self.cursor; - self.cursor.0 += w; - (pos.0 as usize, pos.1 as usize) - } -} - -impl std::ops::Index<(usize, usize)> for TextureAtlas { +impl std::ops::Index<(usize, usize)> for Texture { type Output = u8; fn index(&self, (x, y): (usize, usize)) -> &u8 { @@ -67,10 +17,69 @@ impl std::ops::Index<(usize, usize)> for TextureAtlas { } } -impl std::ops::IndexMut<(usize, usize)> for TextureAtlas { +impl std::ops::IndexMut<(usize, usize)> for Texture { fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut u8 { assert!(x < self.width); assert!(y < self.height); &mut self.pixels[y * self.width + x] } } + +/// A texture pixels, used for fonts. +#[derive(Clone, Default)] +pub struct TextureAtlas { + texture: Texture, + + /// Used for when adding new rects + cursor: (usize, usize), + row_height: usize, +} + +impl TextureAtlas { + pub fn new(width: usize, height: usize) -> Self { + TextureAtlas { + texture: Texture { + id: 0, + width, + height, + pixels: vec![0; width * height], + }, + ..Default::default() + } + } + + pub fn texture(&self) -> &Texture { + &self.texture + } + + pub fn texture_mut(&mut self) -> &mut Texture { + &mut self.texture + } + + /// Returns the coordinates of where the rect ended up. + pub fn allocate(&mut self, (w, h): (usize, usize)) -> (usize, usize) { + assert!(w <= self.texture.width); + if self.cursor.0 + w > self.texture.width { + // New row: + self.cursor.0 = 0; + self.cursor.1 += self.row_height; + self.row_height = 0; + } + + self.row_height = self.row_height.max(h); + while self.cursor.1 + self.row_height >= self.texture.height { + self.texture.height *= 2; + } + + if self.texture.width * self.texture.height > self.texture.pixels.len() { + self.texture + .pixels + .resize(self.texture.width * self.texture.height, 0); + } + + let pos = self.cursor; + self.cursor.0 += w; + self.texture.id += 1; // TODO: hash this ? + (pos.0 as usize, pos.1 as usize) + } +} diff --git a/emigui_wasm/src/webgl.rs b/emigui_wasm/src/webgl.rs index c6a394d0..3e4bddee 100644 --- a/emigui_wasm/src/webgl.rs +++ b/emigui_wasm/src/webgl.rs @@ -4,7 +4,7 @@ use { web_sys::{WebGlBuffer, WebGlProgram, WebGlRenderingContext, WebGlShader, WebGlTexture}, }; -use emigui::Frame; +use emigui::{Frame, Texture}; type Gl = WebGlRenderingContext; @@ -32,10 +32,7 @@ impl Painter { ) } - pub fn new( - canvas_id: &str, - (tex_width, tex_height, pixels): (u16, u16, &[u8]), - ) -> Result { + pub fn new(canvas_id: &str, texture: &Texture) -> Result { let document = web_sys::window().unwrap().document().unwrap(); let canvas = document.get_element_by_id(canvas_id).unwrap(); let canvas: web_sys::HtmlCanvasElement = canvas.dyn_into::()?; @@ -47,11 +44,11 @@ impl Painter { // -------------------------------------------------------------------- - let texture = gl.create_texture().unwrap(); - gl.bind_texture(Gl::TEXTURE_2D, Some(&texture)); + let gl_texture = gl.create_texture().unwrap(); + gl.bind_texture(Gl::TEXTURE_2D, Some(&gl_texture)); // TODO: remove once https://github.com/rustwasm/wasm-bindgen/issues/1005 is fixed. - let mut pixels: Vec<_> = pixels.iter().cloned().collect(); + let mut pixels: Vec<_> = texture.pixels.iter().cloned().collect(); let level = 0; let internal_format = Gl::ALPHA; @@ -62,8 +59,8 @@ impl Painter { Gl::TEXTURE_2D, level, internal_format as i32, - tex_width as i32, - tex_height as i32, + texture.width as i32, + texture.height as i32, border, src_format, src_type, @@ -122,13 +119,13 @@ impl Painter { Ok(Painter { canvas, gl, - texture, + texture: gl_texture, program, index_buffer, pos_buffer, tc_buffer, color_buffer, - tex_size: (tex_width, tex_height), + tex_size: (texture.width as u16, texture.height as u16), }) }