Refactor: create Texture struct
This commit is contained in:
parent
7f83876005
commit
616245c323
7 changed files with 102 additions and 87 deletions
2
TODO.md
2
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?
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<TextStyle, Font>,
|
||||
texture: (u16, u16, Vec<u8>),
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,5 +23,6 @@ pub use crate::{
|
|||
layout::{Align, LayoutOptions, Region},
|
||||
mesher::{Frame, Vertex},
|
||||
style::Style,
|
||||
texture_atlas::Texture,
|
||||
types::RawInput,
|
||||
};
|
||||
|
|
|
@ -1,63 +1,13 @@
|
|||
/// A texture pixels, used for fonts.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct TextureAtlas {
|
||||
width: usize,
|
||||
height: usize,
|
||||
pixels: Vec<u8>,
|
||||
|
||||
/// 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<u8>,
|
||||
}
|
||||
|
||||
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<u8>) {
|
||||
(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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Painter, JsValue> {
|
||||
pub fn new(canvas_id: &str, texture: &Texture) -> Result<Painter, JsValue> {
|
||||
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::<web_sys::HtmlCanvasElement>()?;
|
||||
|
@ -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),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue