diff --git a/Cargo.lock b/Cargo.lock index 2b1eb01f7a3e6b0de30b7b0ffe52eb358e6307b8..d190fa91354e8677b847b62f33693b5bb5a7cce0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1870,6 +1870,7 @@ dependencies = [ "bevy", "derivative", "flo_binding", + "kayak_font", "kayak_render_macros", "morphorm", "resources", diff --git a/Cargo.toml b/Cargo.toml index 01e8e8ea5ddf90b1f9ee108803eeedf008e8d951..1aadade977b5a319e34f5905e1d8294319e24315 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,16 +11,16 @@ members = ["bevy_kayak_ui", "kayak_core", "kayak_render_macros", "kayak_font"] default = ["bevy_renderer"] bevy_renderer = [ "bevy_kayak_ui", - "kayak_font", "kayak_core/bevy_renderer", + "kayak_font/bevy_renderer", "bevy", ] [dependencies] bevy = { version = "0.6.0", optional = true } -kayak_core = { path = "kayak_core" } bevy_kayak_ui = { path = "bevy_kayak_ui", optional = true } -kayak_font = { path = "kayak_font", optional = true } +kayak_core = { path = "kayak_core" } +kayak_font = { path = "kayak_font" } kayak_render_macros = { path = "kayak_render_macros" } [dev-dependencies] diff --git a/bevy_kayak_ui/src/render/mod.rs b/bevy_kayak_ui/src/render/mod.rs index 476057abc98ba36f255d7212d66015bfb258563d..0a3babef1e0b257b28274aed1c8ca039584d9397 100644 --- a/bevy_kayak_ui/src/render/mod.rs +++ b/bevy_kayak_ui/src/render/mod.rs @@ -23,17 +23,17 @@ mod ui_pass_driver; pub mod unified; pub mod node { - pub const UI_PASS_DEPENDENCIES: &str = "ui_pass_dependencies"; - pub const UI_PASS_DRIVER: &str = "ui_pass_driver"; + pub const UI_PASS_DEPENDENCIES: &str = "kayak_ui_pass_dependencies"; + pub const UI_PASS_DRIVER: &str = "kayak_ui_pass_driver"; } pub mod draw_ui_graph { - pub const NAME: &str = "draw_ui"; + pub const NAME: &str = "kayak_draw_ui"; pub mod input { - pub const VIEW_ENTITY: &str = "view_entity"; + pub const VIEW_ENTITY: &str = "kayak_view_entity"; } pub mod node { - pub const MAIN_PASS: &str = "ui_pass"; + pub const MAIN_PASS: &str = "kayak_ui_pass"; } } diff --git a/bevy_kayak_ui/src/render/unified/font/extract.rs b/bevy_kayak_ui/src/render/unified/font/extract.rs index 783d149b26f84432d5829a19fa9b9c7e67ecd003..02228407791349f4055ad6b65565b4f0c75332fc 100644 --- a/bevy_kayak_ui/src/render/unified/font/extract.rs +++ b/bevy_kayak_ui/src/render/unified/font/extract.rs @@ -45,20 +45,22 @@ pub fn extract_texts( let chars_layouts = font.get_layout( CoordinateSystem::PositiveYDown, Alignment::Start, - Vec2::new(layout.posx, layout.posy + line_height), - Vec2::new(layout.width, layout.height), + (layout.posx, layout.posy + line_height), + (layout.width, layout.height), content, line_height, font_size, ); for char_layout in chars_layouts { + let position = Vec2::new(char_layout.position.0, char_layout.position.1); + let size = Vec2::new(char_layout.size.0, char_layout.size.1); extracted_texts.push(ExtractQuadBundle { extracted_quad: ExtractedQuad { font_handle: Some(font_handle.clone()), rect: Rect { - min: char_layout.position, - max: char_layout.position + char_layout.size, + min: position, + max: position + size, }, color: to_bevy_color(background_color), vertex_index: 0, diff --git a/bevy_kayak_ui/src/render/unified/font/mod.rs b/bevy_kayak_ui/src/render/unified/font/mod.rs index 657c25a178e1bf73725f949668bcec0d79ab4ea0..62c83741a9946ee6c017cf552c9e3b4df62078f8 100644 --- a/bevy_kayak_ui/src/render/unified/font/mod.rs +++ b/bevy_kayak_ui/src/render/unified/font/mod.rs @@ -7,7 +7,7 @@ use bevy::{ RenderApp, RenderStage, }, }; -use kayak_font::{FontTextureCache, KayakFontPlugin}; +use kayak_font::bevy::{FontTextureCache, KayakFontPlugin}; mod extract; mod font_mapping; diff --git a/bevy_kayak_ui/src/render/unified/pipeline.rs b/bevy_kayak_ui/src/render/unified/pipeline.rs index 9898e8c78278e58aaf93a5cdfe961e6b510bf7fd..57155b46d281765e94a3195c9afd0b25552f74a1 100644 --- a/bevy_kayak_ui/src/render/unified/pipeline.rs +++ b/bevy_kayak_ui/src/render/unified/pipeline.rs @@ -32,7 +32,10 @@ use bevy::{ utils::HashMap, }; use bytemuck::{Pod, Zeroable}; -use kayak_font::{FontRenderingPipeline, FontTextureCache, KayakFont}; +use kayak_font::{ + bevy::{FontRenderingPipeline, FontTextureCache}, + KayakFont, +}; use super::{Dpi, UNIFIED_SHADER_HANDLE}; use crate::{render::ui_pass::TransparentUI, WindowSize}; diff --git a/kayak_core/Cargo.toml b/kayak_core/Cargo.toml index 4057eeeeebc3d51c27159679665554f01008e441..610e7c9a043b544be58667ca759b46ae5c019f31 100644 --- a/kayak_core/Cargo.toml +++ b/kayak_core/Cargo.toml @@ -7,13 +7,14 @@ edition = "2021" [features] default = [] -bevy_renderer = ["bevy"] +bevy_renderer = ["bevy", "kayak_font/bevy_renderer"] [dependencies] as-any = "0.2" derivative = "2.2" bevy = { version = "0.6.0", optional = true } flo_binding = { git = "https://github.com/StarArawn/flo_binding.git", rev = "c78431a56df5ec082b7e1c271871e6c0ac75e81e" } +kayak_font = { path = "../kayak_font" } kayak_render_macros = { path = "../kayak_render_macros" } morphorm = { git = "https://github.com/geom3trik/morphorm", rev = "1243152d4cebea46fd3e5098df26402c73acae91" } resources = "1.1" diff --git a/kayak_font/Cargo.toml b/kayak_font/Cargo.toml index f3c489619cf4c7f9be64e8e085319b71e8374134..7f27ef978a4015e94ce876e9f4ee766d8ec16a6d 100644 --- a/kayak_font/Cargo.toml +++ b/kayak_font/Cargo.toml @@ -5,10 +5,14 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +default = ["bevy_renderer"] +bevy_renderer = ["bevy"] + [dependencies] anyhow = { version = "1.0" } -bevy = { version = "0.6.0" } +bevy = { version = "0.6.0", optional = true } bytemuck = "1.7.2" -serde = "1.0" +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_path_to_error = "0.1" diff --git a/kayak_font/examples/bevy.rs b/kayak_font/examples/bevy.rs index af68adb3adac1f841da7aef788dc76efc53a7fe9..9e000354e81af6e7cf0ed5c9ef0f1326f8a9760b 100644 --- a/kayak_font/examples/bevy.rs +++ b/kayak_font/examples/bevy.rs @@ -5,7 +5,7 @@ use bevy::{ window::WindowDescriptor, DefaultPlugins, }; -use kayak_font::{Alignment, KayakFont, KayakFontPlugin}; +use kayak_font::{Alignment, KayakFont, bevy::KayakFontPlugin}; mod renderer; use renderer::FontRenderPlugin; diff --git a/kayak_font/examples/renderer/extract.rs b/kayak_font/examples/renderer/extract.rs index c5f8e342791f9d8ddd5aeae53416421420cd1b31..3e874c97cb7b16e6f8e739d097a79bb57a82dc25 100644 --- a/kayak_font/examples/renderer/extract.rs +++ b/kayak_font/examples/renderer/extract.rs @@ -1,6 +1,6 @@ use bevy::{ prelude::{Assets, Commands, Handle, Query, Res}, - sprite::Rect, + sprite::Rect, math::Vec2, }; use kayak_font::{CoordinateSystem, KayakFont}; @@ -21,20 +21,23 @@ pub fn extract( let layouts = font.get_layout( CoordinateSystem::PositiveYUp, text.horz_alignment, - text.position, - text.size, + (text.position.x, text.position.y), + (text.size.x, text.size.y), &text.content, text.line_height, text.font_size, ); for layout in layouts { + let position = Vec2::new(layout.position.0, layout.position.1); + let size = Vec2::new(layout.size.0, layout.size.1); + extracted_texts.push(ExtractCharBundle { extracted_quad: ExtractedChar { font_handle: Some(font_handle.clone()), rect: Rect { - min: layout.position, - max: layout.position + layout.size, + min: position, + max: position + size, }, color: text.color, vertex_index: 0, diff --git a/kayak_font/examples/renderer/mod.rs b/kayak_font/examples/renderer/mod.rs index ae223b2ee3b11c514c88d12d7f6d8b61cb0c2e06..dec8300fd080f6cd14ab66e885f83878177a8ab5 100644 --- a/kayak_font/examples/renderer/mod.rs +++ b/kayak_font/examples/renderer/mod.rs @@ -11,7 +11,7 @@ use bevy::{ RenderApp, RenderStage, }, }; -use kayak_font::FontTextureCache; +use kayak_font::bevy::FontTextureCache; use self::pipeline::{DrawUI, FontPipeline, QuadMeta}; diff --git a/kayak_font/examples/renderer/pipeline.rs b/kayak_font/examples/renderer/pipeline.rs index 2b023fe306b8bd838425fc74370ba9841741be9f..7062e6e1d86910318b602836f9e3d4de2998f2bd 100644 --- a/kayak_font/examples/renderer/pipeline.rs +++ b/kayak_font/examples/renderer/pipeline.rs @@ -28,7 +28,10 @@ use bevy::{ sprite::Rect, }; use bytemuck::{Pod, Zeroable}; -use kayak_font::{FontRenderingPipeline, FontTextureCache, KayakFont}; +use kayak_font::{ + bevy::{FontRenderingPipeline, FontTextureCache}, + KayakFont, +}; use super::FONT_SHADER_HANDLE; @@ -169,7 +172,7 @@ impl FromWorld for FontPipeline { }, depth_stencil: None, multisample: MultisampleState { - count: 1, + count: 4, mask: !0, alpha_to_coverage_enabled: false, }, diff --git a/kayak_font/src/font.rs b/kayak_font/src/font.rs index 1481c1a121cd146ed360ab6b47ab833c8f95826d..72307f34aad6def3f477b542bdb3ecd90aa3272a 100644 --- a/kayak_font/src/font.rs +++ b/kayak_font/src/font.rs @@ -1,15 +1,11 @@ use std::collections::HashMap; -use bevy::{ - asset::{AssetLoader, AssetPath, BoxedFuture, LoadContext, LoadedAsset}, - math::Vec2, - prelude::Handle, - reflect::TypeUuid, - render::texture::Image, -}; +#[cfg(feature = "bevy_renderer")] +use bevy::{prelude::Handle, reflect::TypeUuid, render::texture::Image}; use crate::Sdf; +#[cfg(feature = "bevy_renderer")] #[derive(Debug, Clone, TypeUuid)] #[uuid = "4fe4732c-6731-49bb-bafc-4690d636b848"] pub struct KayakFont { @@ -18,10 +14,17 @@ pub struct KayakFont { char_ids: HashMap<char, u32>, } +#[cfg(not(feature = "bevy_renderer"))] +#[derive(Debug, Clone)] +pub struct KayakFont { + pub sdf: Sdf, + char_ids: HashMap<char, u32>, +} + #[derive(Default, Debug, Clone, Copy)] pub struct LayoutRect { - pub position: Vec2, - pub size: Vec2, + pub position: (f32, f32), + pub size: (f32, f32), pub content: char, } @@ -39,9 +42,10 @@ pub enum Alignment { } impl KayakFont { - pub fn new(sdf: Sdf, atlas_image: Handle<Image>) -> Self { + pub fn new(sdf: Sdf, #[cfg(feature = "bevy_renderer")] atlas_image: Handle<Image>) -> Self { Self { sdf, + #[cfg(feature = "bevy_renderer")] atlas_image, char_ids: HashMap::default(), } @@ -68,8 +72,8 @@ impl KayakFont { Some(val) => ( val.left, val.top, - val.size().x * font_size, - val.size().y * font_size, + val.size().0 * font_size, + val.size().1 * font_size, ), None => (0.0, 0.0, 0.0, 0.0), }; @@ -85,8 +89,8 @@ impl KayakFont { &self, axis_alignment: CoordinateSystem, alignment: Alignment, - position: Vec2, - max_size: Vec2, + position: (f32, f32), + max_size: (f32, f32), content: &String, line_height: f32, font_size: f32, @@ -94,7 +98,7 @@ impl KayakFont { let mut positions_and_size = Vec::new(); let max_glyph_size = self.sdf.max_glyph_size(); let font_ratio = font_size / self.sdf.atlas.size; - let resized_max_glyph_size = (max_glyph_size.x * font_ratio, max_glyph_size.y * font_ratio); + let resized_max_glyph_size = (max_glyph_size.0 * font_ratio, max_glyph_size.1 * font_ratio); // TODO: Make this configurable? let split_chars = vec![' ', '\t', '-', '\n']; @@ -117,7 +121,7 @@ impl KayakFont { let mut last_width = 0.0; for word in content.split(&split_chars[..]) { let word_width = self.get_word_width(word, font_size); - if x + word_width > max_size.x { + if x + word_width > max_size.0 { y -= shift_sign * line_height; line_widths.push((x, line_starting_index, positions_and_size.len())); line_starting_index = positions_and_size.len(); @@ -130,8 +134,8 @@ impl KayakFont { Some(val) => ( val.left, val.top, - val.size().x * font_size, - val.size().y * font_size, + val.size().0 * font_size, + val.size().1 * font_size, ), None => (0.0, 0.0, 0.0, 0.0), }; @@ -142,8 +146,8 @@ impl KayakFont { let position_y = y + (shift_sign * top * font_size); positions_and_size.push(LayoutRect { - position: Vec2::new(position_x, position_y), - size: Vec2::new(resized_max_glyph_size.0, resized_max_glyph_size.1), + position: (position_x, position_y), + size: (resized_max_glyph_size.0, resized_max_glyph_size.1), content: c, }); @@ -172,50 +176,17 @@ impl KayakFont { for (line_width, starting_index, end_index) in line_widths { let shift_x = match alignment { Alignment::Start => 0.0, - Alignment::Middle => (max_size.x - line_width) / 2.0, - Alignment::End => max_size.x - line_width, + Alignment::Middle => (max_size.0 - line_width) / 2.0, + Alignment::End => max_size.0 - line_width, }; for i in starting_index..end_index { let layout_rect = &mut positions_and_size[i]; - layout_rect.position.x += position.x + shift_x; - layout_rect.position.y += position.y; + layout_rect.position.0 += position.0 + shift_x; + layout_rect.position.1 += position.1; } } positions_and_size } } - -#[derive(Default)] -pub struct KayakFontLoader; - -impl AssetLoader for KayakFontLoader { - fn load<'a>( - &'a self, - bytes: &'a [u8], - load_context: &'a mut LoadContext, - ) -> BoxedFuture<'a, Result<(), anyhow::Error>> { - Box::pin(async move { - let path = load_context.path(); - let path = path.with_extension("png"); - let atlas_image_path = AssetPath::new(path, None); - let mut font = KayakFont::new( - Sdf::from_bytes(bytes), - load_context.get_handle(atlas_image_path.clone()), - ); - - font.generate_char_ids(); - - load_context - .set_default_asset(LoadedAsset::new(font).with_dependency(atlas_image_path)); - - Ok(()) - }) - } - - fn extensions(&self) -> &[&str] { - static EXTENSIONS: &[&str] = &["kayak_font"]; - EXTENSIONS - } -} diff --git a/kayak_font/src/glyph.rs b/kayak_font/src/glyph.rs index f883522fc5e9932423ad33cb4ab672ac45ed70ae..c0b16386e91f46159901d3d1e3849b199b512ea1 100644 --- a/kayak_font/src/glyph.rs +++ b/kayak_font/src/glyph.rs @@ -1,4 +1,3 @@ -use bevy::math::Vec2; use serde::{Deserialize, Deserializer}; fn from_u32<'de, D>(deserializer: D) -> Result<char, D::Error> @@ -40,7 +39,7 @@ impl Rect { self.top - self.bottom } - pub fn size(&self) -> Vec2 { - Vec2::new(self.width(), self.height()) + pub fn size(&self) -> (f32, f32) { + (self.width(), self.height()) } } diff --git a/kayak_font/src/lib.rs b/kayak_font/src/lib.rs index 2582c37f13b1f5b6a7b91c9be57132b9831af143..71f18cf7ceae55dd5471934d37ef2260012d33a6 100644 --- a/kayak_font/src/lib.rs +++ b/kayak_font/src/lib.rs @@ -2,144 +2,183 @@ mod atlas; mod font; mod glyph; mod metrics; -mod renderer; mod sdf; pub use atlas::*; -use bevy::{ - prelude::{ - AddAsset, AssetEvent, Assets, Commands, EventReader, Handle, Local, Plugin, Res, ResMut, - }, - render::{ - render_resource::{FilterMode, TextureFormat, TextureUsages}, - texture::Image, - RenderApp, RenderStage, - }, - utils::HashSet, -}; pub use font::*; pub use glyph::*; pub use metrics::*; pub use sdf::*; -pub use renderer::*; +#[cfg(feature = "bevy_renderer")] +mod renderer; -pub struct KayakFontPlugin; +#[cfg(feature = "bevy_renderer")] +pub mod bevy { + pub use crate::renderer::*; + use crate::{KayakFont, Sdf}; + use bevy::{ + asset::{AssetLoader, AssetPath, BoxedFuture, LoadContext, LoadedAsset}, + prelude::{ + AddAsset, AssetEvent, Assets, Commands, EventReader, Handle, Local, Plugin, Res, ResMut, + }, + render::{ + render_resource::{FilterMode, TextureFormat, TextureUsages}, + texture::Image, + RenderApp, RenderStage, + }, + utils::HashSet, + }; + pub struct KayakFontPlugin; -impl Plugin for KayakFontPlugin { - fn build(&self, app: &mut bevy::prelude::App) { - app.add_asset::<KayakFont>() - .add_asset_loader(KayakFontLoader) - .add_system(init_font_texture); + impl Plugin for KayakFontPlugin { + fn build(&self, app: &mut bevy::prelude::App) { + app.add_asset::<KayakFont>() + .add_asset_loader(KayakFontLoader) + .add_system(init_font_texture); - let render_app = app.sub_app_mut(RenderApp); - render_app - .init_resource::<FontTextureCache>() - .init_resource::<ExtractedFonts>() - .add_system_to_stage(RenderStage::Extract, extract_fonts) - .add_system_to_stage(RenderStage::Prepare, prepare_fonts); + let render_app = app.sub_app_mut(RenderApp); + render_app + .init_resource::<FontTextureCache>() + .init_resource::<ExtractedFonts>() + .add_system_to_stage(RenderStage::Extract, extract_fonts) + .add_system_to_stage(RenderStage::Prepare, prepare_fonts); + } } -} -pub fn init_font_texture( - mut not_processed: Local<Vec<Handle<KayakFont>>>, - mut font_events: EventReader<AssetEvent<KayakFont>>, - mut images: ResMut<Assets<Image>>, - fonts: Res<Assets<KayakFont>>, -) { - // quick and dirty, run this for all textures anytime a texture is created. - for event in font_events.iter() { - match event { - AssetEvent::Created { handle } => { - not_processed.push(handle.clone_weak()); + pub fn init_font_texture( + mut not_processed: Local<Vec<Handle<KayakFont>>>, + mut font_events: EventReader<AssetEvent<KayakFont>>, + mut images: ResMut<Assets<Image>>, + fonts: Res<Assets<KayakFont>>, + ) { + // quick and dirty, run this for all textures anytime a texture is created. + for event in font_events.iter() { + match event { + AssetEvent::Created { handle } => { + not_processed.push(handle.clone_weak()); + } + _ => (), } - _ => (), } - } - let not_processed_fonts = not_processed.drain(..).collect::<Vec<_>>(); - for font_handle in not_processed_fonts { - if let Some(font) = fonts.get(&font_handle) { - if let Some(mut texture) = images.get_mut(&font.atlas_image) { - texture.texture_descriptor.format = TextureFormat::Rgba8Unorm; - texture.sampler_descriptor.min_filter = FilterMode::Linear; - texture.sampler_descriptor.mipmap_filter = FilterMode::Linear; - texture.sampler_descriptor.mag_filter = FilterMode::Linear; - texture.texture_descriptor.usage = TextureUsages::TEXTURE_BINDING - | TextureUsages::COPY_DST - | TextureUsages::COPY_SRC; - } else { - not_processed.push(font_handle.clone_weak()); + let not_processed_fonts = not_processed.drain(..).collect::<Vec<_>>(); + for font_handle in not_processed_fonts { + if let Some(font) = fonts.get(&font_handle) { + if let Some(mut texture) = images.get_mut(&font.atlas_image) { + texture.texture_descriptor.format = TextureFormat::Rgba8Unorm; + texture.sampler_descriptor.min_filter = FilterMode::Linear; + texture.sampler_descriptor.mipmap_filter = FilterMode::Linear; + texture.sampler_descriptor.mag_filter = FilterMode::Linear; + texture.texture_descriptor.usage = TextureUsages::TEXTURE_BINDING + | TextureUsages::COPY_DST + | TextureUsages::COPY_SRC; + } else { + not_processed.push(font_handle.clone_weak()); + } } } } -} -#[derive(Default)] -pub struct ExtractedFonts { - pub fonts: Vec<(Handle<KayakFont>, KayakFont)>, -} + #[derive(Default)] + pub struct ExtractedFonts { + pub fonts: Vec<(Handle<KayakFont>, KayakFont)>, + } -fn extract_fonts( - mut not_processed: Local<Vec<Handle<KayakFont>>>, - mut commands: Commands, - font_assets: Res<Assets<KayakFont>>, - mut events: EventReader<AssetEvent<KayakFont>>, - textures: Res<Assets<Image>>, -) { - let mut extracted_fonts = ExtractedFonts { fonts: Vec::new() }; - let mut changed_assets = HashSet::default(); - let mut removed = Vec::new(); - for event in events.iter() { - match event { - AssetEvent::Created { handle } => { - changed_assets.insert(handle.clone_weak()); - } - AssetEvent::Modified { handle } => { - changed_assets.insert(handle.clone_weak()); - } - AssetEvent::Removed { handle } => { - if !changed_assets.remove(handle) { - removed.push(handle.clone_weak()); + fn extract_fonts( + mut not_processed: Local<Vec<Handle<KayakFont>>>, + mut commands: Commands, + font_assets: Res<Assets<KayakFont>>, + mut events: EventReader<AssetEvent<KayakFont>>, + textures: Res<Assets<Image>>, + ) { + let mut extracted_fonts = ExtractedFonts { fonts: Vec::new() }; + let mut changed_assets = HashSet::default(); + let mut removed = Vec::new(); + for event in events.iter() { + match event { + AssetEvent::Created { handle } => { + changed_assets.insert(handle.clone_weak()); + } + AssetEvent::Modified { handle } => { + changed_assets.insert(handle.clone_weak()); + } + AssetEvent::Removed { handle } => { + if !changed_assets.remove(handle) { + removed.push(handle.clone_weak()); + } } } } - } - for handle in not_processed.drain(..) { - changed_assets.insert(handle); - } + for handle in not_processed.drain(..) { + changed_assets.insert(handle); + } - for handle in changed_assets { - let font_asset = font_assets.get(&handle).unwrap(); - if let Some(image) = textures.get(&font_asset.atlas_image) { - if !image - .texture_descriptor - .usage - .contains(TextureUsages::COPY_SRC) - || image.texture_descriptor.format != TextureFormat::Rgba8Unorm - { + for handle in changed_assets { + let font_asset = font_assets.get(&handle).unwrap(); + if let Some(image) = textures.get(&font_asset.atlas_image) { + if !image + .texture_descriptor + .usage + .contains(TextureUsages::COPY_SRC) + || image.texture_descriptor.format != TextureFormat::Rgba8Unorm + { + not_processed.push(handle); + continue; + } + } else { not_processed.push(handle); continue; } - } else { - not_processed.push(handle); - continue; + + let font = font_asset.clone(); + extracted_fonts.fonts.push((handle, font)); } - let font = font_asset.clone(); - extracted_fonts.fonts.push((handle, font)); + commands.insert_resource(extracted_fonts); } - commands.insert_resource(extracted_fonts); -} + fn prepare_fonts( + mut extracted_fonts: ResMut<ExtractedFonts>, + mut font_texture_cache: ResMut<FontTextureCache>, + ) { + let fonts: Vec<_> = extracted_fonts.fonts.drain(..).collect(); + for (handle, font) in fonts { + font_texture_cache.add(handle, font); + } + } -fn prepare_fonts( - mut extracted_fonts: ResMut<ExtractedFonts>, - mut font_texture_cache: ResMut<FontTextureCache>, -) { - let fonts: Vec<_> = extracted_fonts.fonts.drain(..).collect(); - for (handle, font) in fonts { - font_texture_cache.add(handle, font); + #[derive(Default)] + pub struct KayakFontLoader; + + impl AssetLoader for KayakFontLoader { + fn load<'a>( + &'a self, + bytes: &'a [u8], + load_context: &'a mut LoadContext, + ) -> BoxedFuture<'a, Result<(), anyhow::Error>> { + Box::pin(async move { + let path = load_context.path(); + let path = path.with_extension("png"); + let atlas_image_path = AssetPath::new(path, None); + let mut font = KayakFont::new( + Sdf::from_bytes(bytes), + load_context.get_handle(atlas_image_path.clone()), + ); + + font.generate_char_ids(); + + load_context + .set_default_asset(LoadedAsset::new(font).with_dependency(atlas_image_path)); + + Ok(()) + }) + } + + fn extensions(&self) -> &[&str] { + static EXTENSIONS: &[&str] = &["kayak_font"]; + EXTENSIONS + } } } diff --git a/kayak_font/src/renderer/font_texture_cache.rs b/kayak_font/src/renderer/font_texture_cache.rs index 1a2ad1e16744da55c25fd036ae57d87276e69a60..38a4c6211e2bc9395629ebf19f8148b34f382467 100644 --- a/kayak_font/src/renderer/font_texture_cache.rs +++ b/kayak_font/src/renderer/font_texture_cache.rs @@ -84,7 +84,7 @@ impl FontTextureCache { queue, pipeline, atlas_texture, - font.sdf.max_glyph_size(), + Vec2::new(font.sdf.max_glyph_size().0, font.sdf.max_glyph_size().1), ); } else { was_processed = false; @@ -291,8 +291,8 @@ impl FontTextureCache { aspect: TextureAspect::All, }, Extent3d { - width: glyph_size.x as u32, - height: glyph_size.y as u32, + width: glyph_size.0 as u32, + height: glyph_size.1 as u32, depth_or_array_layers: 1, }, ); diff --git a/kayak_font/src/sdf.rs b/kayak_font/src/sdf.rs index f8000bbbe8fdbff0c81b78de1dc06b133df135d9..49e545361eae99786c20bb2e102c33eb7f54425a 100644 --- a/kayak_font/src/sdf.rs +++ b/kayak_font/src/sdf.rs @@ -1,5 +1,4 @@ use crate::{atlas::Atlas, glyph::Glyph, metrics::Metrics}; -use bevy::math::Vec2; use serde::Deserialize; #[derive(Deserialize, Debug, Clone)] @@ -10,7 +9,7 @@ pub struct Sdf { kerning: Vec<KerningData>, } -#[derive(serde::Deserialize, Debug, Clone, Copy)] +#[derive(Deserialize, Debug, Clone, Copy)] pub struct KerningData { pub unicode1: u32, pub unicode2: u32, @@ -48,16 +47,16 @@ impl Sdf { value } - pub fn max_glyph_size(&self) -> Vec2 { - let mut size = Vec2::new(0.0, 0.0); + pub fn max_glyph_size(&self) -> (f32, f32) { + let mut size = (0.0, 0.0); self.glyphs.iter().for_each(|glyph| { if let Some(atlas_bounds) = glyph.atlas_bounds { let atlas_size = atlas_bounds.size(); - if atlas_size.x > size.x { - size.x = atlas_size.x; + if atlas_size.0 > size.0 { + size.0 = atlas_size.0; } - if atlas_size.y > size.y { - size.y = atlas_size.y; + if atlas_size.1 > size.1 { + size.1 = atlas_size.1; } } }); @@ -70,7 +69,7 @@ impl Sdf { fn test_sdf_loader() { use crate::SDFType; let sdf = Sdf::from_string(include_str!("../assets/roboto.kayak_font").to_string()); - assert!(sdf.max_glyph_size() == Vec2::new(30.0, 36.0)); + assert!(sdf.max_glyph_size() == (30.0, 36.0)); assert!(sdf.atlas.width == 212); assert!(sdf.atlas.height == 212); assert!(matches!(sdf.atlas.sdf_type, SDFType::Msdf));