mirror of
https://github.com/griffi-gh/kubi.git
synced 2024-11-25 08:18:43 -06:00
update ftm stuff
This commit is contained in:
parent
769d7e84e9
commit
1c52273ce2
|
@ -1,6 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
use glam::{Vec2, Vec4, vec2};
|
||||
use crate::text::TextRenderer;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum UiDrawCommand {
|
||||
|
@ -62,7 +61,7 @@ pub struct UiDrawPlan {
|
|||
}
|
||||
|
||||
impl UiDrawPlan {
|
||||
pub fn build(calls: &UiDrawCommands, tr: &mut TextRenderer) -> Self {
|
||||
pub fn build(calls: &UiDrawCommands) -> Self {
|
||||
let mut call = UiDrawCall::default();
|
||||
for command in &calls.commands {
|
||||
match command {
|
||||
|
|
|
@ -13,7 +13,6 @@ use element::UiElement;
|
|||
use state::StateRepo;
|
||||
use event::UiEvent;
|
||||
use draw::{UiDrawCommands, UiDrawPlan};
|
||||
use text::TextRenderer;
|
||||
|
||||
// pub struct ElementContext<'a> {
|
||||
// pub state: &'a mut StateRepo,
|
||||
|
@ -29,7 +28,7 @@ pub struct KubiUi {
|
|||
draw_commands: UiDrawCommands,
|
||||
draw_plan: UiDrawPlan,
|
||||
draw_plan_modified: bool,
|
||||
font_renderer: TextRenderer,
|
||||
// ftm: FontTextureManager,
|
||||
}
|
||||
|
||||
impl KubiUi {
|
||||
|
@ -43,7 +42,7 @@ impl KubiUi {
|
|||
draw_commands: UiDrawCommands::default(),
|
||||
draw_plan: UiDrawPlan::default(),
|
||||
draw_plan_modified: false,
|
||||
font_renderer: TextRenderer::default(),
|
||||
// ftm: FontTextureManager::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +66,7 @@ impl KubiUi {
|
|||
if self.draw_commands.commands == self.prev_draw_commands.commands {
|
||||
return
|
||||
}
|
||||
self.draw_plan = UiDrawPlan::build(&self.draw_commands, &mut self.font_renderer);
|
||||
self.draw_plan = UiDrawPlan::build(&self.draw_commands);
|
||||
self.draw_plan_modified = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,90 +1,2 @@
|
|||
use std::sync::Arc;
|
||||
use fontdue::{Font, Metrics};
|
||||
use glam::{IVec2, UVec2, uvec2, ivec2};
|
||||
use hashbrown::HashMap;
|
||||
use rect_packer::DensePacker;
|
||||
|
||||
#[cfg(feature = "builtin_font")]
|
||||
const BIN_FONT: &[u8] = include_bytes!("../assets/font/ProggyTiny.ttf");
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct FontHandle(pub(crate) usize);
|
||||
|
||||
#[cfg(feature = "builtin_font")]
|
||||
pub const BUILTIN_FONT: FontHandle = FontHandle(0);
|
||||
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
struct GlyphCacheKey {
|
||||
font_index: usize,
|
||||
character: char,
|
||||
size: u8,
|
||||
}
|
||||
|
||||
struct GlyphCacheEntry {
|
||||
pub data: Vec<u8>,
|
||||
pub metrics: Metrics,
|
||||
pub texture_position: IVec2,
|
||||
pub texture_size: UVec2,
|
||||
}
|
||||
|
||||
pub struct TextRenderer {
|
||||
fonts: Vec<Font>,
|
||||
glyph_cache: HashMap<GlyphCacheKey, Arc<GlyphCacheEntry>>,
|
||||
packer: DensePacker,
|
||||
font_texture: Vec<u8>,
|
||||
font_texture_size: UVec2,
|
||||
}
|
||||
|
||||
impl TextRenderer {
|
||||
pub fn new(size: UVec2) -> Self {
|
||||
let mut renderer = TextRenderer {
|
||||
fonts: Vec::new(),
|
||||
glyph_cache: HashMap::new(),
|
||||
packer: DensePacker::new(size.x as i32, size.y as i32),
|
||||
font_texture: vec![0; (size.x * size.y) as usize],
|
||||
font_texture_size: size,
|
||||
};
|
||||
#[cfg(feature = "builtin_font")]
|
||||
{
|
||||
let font = Font::from_bytes(BIN_FONT, fontdue::FontSettings::default()).unwrap();
|
||||
renderer.add_font(font);
|
||||
}
|
||||
renderer
|
||||
}
|
||||
|
||||
/// Add a (fontdue) font to the renderer.
|
||||
pub fn add_font(&mut self, font: Font) -> FontHandle {
|
||||
self.fonts.push(font);
|
||||
FontHandle(self.fonts.len() - 1)
|
||||
}
|
||||
|
||||
/// Either looks up the glyph in the cache or renders it and adds it to the cache.
|
||||
pub fn glyph(&mut self, font: FontHandle, character: char, size: u8) -> Arc<GlyphCacheEntry> {
|
||||
let key = GlyphCacheKey {
|
||||
font_index: font.0,
|
||||
character,
|
||||
size,
|
||||
};
|
||||
if let Some(entry) = self.glyph_cache.get(&key) {
|
||||
return Arc::clone(entry);
|
||||
}
|
||||
let font = &self.fonts[key.font_index];
|
||||
let (metrics, bitmap) = font.rasterize(character, size as f32);
|
||||
let texture_position = self.packer.pack(metrics.width as i32, metrics.height as i32, false).unwrap();
|
||||
let texture_size = uvec2(metrics.width as u32, metrics.height as u32);
|
||||
let entry = Arc::new(GlyphCacheEntry {
|
||||
data: bitmap,
|
||||
metrics,
|
||||
texture_position: ivec2(texture_position.x, texture_position.y),
|
||||
texture_size,
|
||||
});
|
||||
self.glyph_cache.insert_unique_unchecked(key, Arc::clone(&entry));
|
||||
entry
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TextRenderer {
|
||||
fn default() -> Self {
|
||||
Self::new(uvec2(2048, 2048))
|
||||
}
|
||||
}
|
||||
pub mod font;
|
||||
pub mod ftm;
|
||||
|
|
38
kubi-ui/src/text/font.rs
Normal file
38
kubi-ui/src/text/font.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use fontdue::Font;
|
||||
|
||||
#[cfg(feature = "builtin_font")]
|
||||
const BIN_FONT: &[u8] = include_bytes!("../../assets/font/ProggyTiny.ttf");
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct FontHandle(pub(crate) usize);
|
||||
|
||||
#[cfg(feature = "builtin_font")]
|
||||
pub const BUILTIN_FONT: FontHandle = FontHandle(0);
|
||||
|
||||
pub struct FontManager {
|
||||
fonts: Vec<Font>,
|
||||
}
|
||||
|
||||
impl FontManager {
|
||||
pub fn new() -> Self {
|
||||
let mut this = Self {
|
||||
fonts: Vec::new(),
|
||||
};
|
||||
#[cfg(feature = "builtin_font")]
|
||||
{
|
||||
let font = Font::from_bytes(BIN_FONT, fontdue::FontSettings::default()).unwrap();
|
||||
this.add_font(font);
|
||||
};
|
||||
this
|
||||
}
|
||||
|
||||
/// Add a (fontdue) font to the renderer.
|
||||
pub fn add_font(&mut self, font: Font) -> FontHandle {
|
||||
self.fonts.push(font);
|
||||
FontHandle(self.fonts.len() - 1)
|
||||
}
|
||||
|
||||
pub fn get(&self, handle: FontHandle) -> Option<&Font> {
|
||||
self.fonts.get(handle.0)
|
||||
}
|
||||
}
|
96
kubi-ui/src/text/ftm.rs
Normal file
96
kubi-ui/src/text/ftm.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
use std::sync::Arc;
|
||||
use fontdue::{Font, Metrics};
|
||||
use glam::{IVec2, UVec2, uvec2, ivec2};
|
||||
use hashbrown::HashMap;
|
||||
use rect_packer::DensePacker;
|
||||
|
||||
use super::font::{FontHandle, FontManager};
|
||||
|
||||
|
||||
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
struct GlyphCacheKey {
|
||||
font_index: usize,
|
||||
character: char,
|
||||
size: u8,
|
||||
}
|
||||
|
||||
struct GlyphCacheEntry {
|
||||
pub data: Vec<u8>,
|
||||
pub metrics: Metrics,
|
||||
pub position: IVec2,
|
||||
pub size: UVec2,
|
||||
}
|
||||
|
||||
pub struct FontTextureManager {
|
||||
glyph_cache: HashMap<GlyphCacheKey, Arc<GlyphCacheEntry>>,
|
||||
packer: DensePacker,
|
||||
font_texture: Vec<u8>,
|
||||
font_texture_size: UVec2,
|
||||
modified: bool,
|
||||
}
|
||||
|
||||
impl FontTextureManager {
|
||||
pub fn new(size: UVec2) -> Self {
|
||||
let mut renderer = FontTextureManager {
|
||||
glyph_cache: HashMap::new(),
|
||||
packer: DensePacker::new(size.x as i32, size.y as i32),
|
||||
font_texture: vec![0; (size.x * size.y) as usize],
|
||||
font_texture_size: size,
|
||||
modified: false,
|
||||
};
|
||||
renderer
|
||||
}
|
||||
|
||||
/// Either looks up the glyph in the cache or renders it and adds it to the cache.
|
||||
fn glyph_allocate(&mut self, font_manager: &FontManager, font_handle: FontHandle, character: char, size: u8) -> (bool, Arc<GlyphCacheEntry>) {
|
||||
let key = GlyphCacheKey {
|
||||
font_index: font_handle.0,
|
||||
character,
|
||||
size,
|
||||
};
|
||||
if let Some(entry) = self.glyph_cache.get(&key) {
|
||||
return (false, Arc::clone(entry));
|
||||
}
|
||||
let font = font_manager.get(font_handle).unwrap();
|
||||
let (metrics, bitmap) = font.rasterize(character, size as f32);
|
||||
let texture_position = self.packer.pack(metrics.width as i32, metrics.height as i32, false).unwrap();
|
||||
let texture_size = uvec2(metrics.width as u32, metrics.height as u32);
|
||||
let entry = Arc::new(GlyphCacheEntry {
|
||||
data: bitmap,
|
||||
metrics,
|
||||
position: ivec2(texture_position.x, texture_position.y),
|
||||
size: texture_size,
|
||||
});
|
||||
self.glyph_cache.insert_unique_unchecked(key, Arc::clone(&entry));
|
||||
(true, entry)
|
||||
}
|
||||
|
||||
/// Place glyph onto the font texture.
|
||||
fn glyph_place(&mut self, entry: &GlyphCacheEntry) {
|
||||
let tex_size = self.font_texture_size;
|
||||
let GlyphCacheEntry { size, position, .. } = entry;
|
||||
for y in 0..size.y {
|
||||
for x in 0..size.x {
|
||||
let src = (size.x * y + x) as usize;
|
||||
let dst = (tex_size.x * (y + position.y as u32) + (x + position.x as u32)) as usize;
|
||||
self.font_texture[dst] = entry.data[src];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn glyph(&mut self, font_manager: &FontManager, font_handle: FontHandle, character: char, size: u8) -> Arc<GlyphCacheEntry> {
|
||||
let (is_new, glyph) = self.glyph_allocate(font_manager, font_handle, character, size);
|
||||
if is_new {
|
||||
self.glyph_place(&glyph);
|
||||
self.modified = true;
|
||||
}
|
||||
glyph
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FontTextureManager {
|
||||
fn default() -> Self {
|
||||
Self::new(uvec2(2048, 2048))
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue