diff --git a/Cargo.lock b/Cargo.lock index e9ff38dc659b1766bfd5a6c8bec247bab9ab5004..d3b708d5cf91e6b6c7e6307d8772a58bf627cc5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,15 +120,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "arrayvec" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -dependencies = [ - "nodrop", -] - [[package]] name = "arrayvec" version = "0.7.2" @@ -302,8 +293,8 @@ source = "git+https://github.com/bevyengine/bevy?rev=38c7d5eb9e81ab8e1aec0367359 dependencies = [ "Inflector", "bevy_macro_utils", - "quote 1.0.10", - "syn 1.0.81", + "quote", + "syn", ] [[package]] @@ -341,9 +332,9 @@ version = "0.5.0" source = "git+https://github.com/bevyengine/bevy?rev=38c7d5eb9e81ab8e1aec03673599b25a9aa0c69c#38c7d5eb9e81ab8e1aec03673599b25a9aa0c69c" dependencies = [ "bevy_macro_utils", - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -440,6 +431,7 @@ dependencies = [ "crevice", "kayak_components", "kayak_core", + "kayak_font", "kayak_render_macros", "serde", "serde_json", @@ -466,8 +458,8 @@ version = "0.5.0" source = "git+https://github.com/bevyengine/bevy?rev=38c7d5eb9e81ab8e1aec03673599b25a9aa0c69c#38c7d5eb9e81ab8e1aec03673599b25a9aa0c69c" dependencies = [ "cargo-manifest", - "quote 1.0.10", - "syn 1.0.81", + "quote", + "syn", ] [[package]] @@ -538,9 +530,9 @@ version = "0.5.0" source = "git+https://github.com/bevyengine/bevy?rev=38c7d5eb9e81ab8e1aec03673599b25a9aa0c69c#38c7d5eb9e81ab8e1aec03673599b25a9aa0c69c" dependencies = [ "bevy_macro_utils", - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", "uuid", ] @@ -820,8 +812,8 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "regex", "rustc-hash", "shlex", @@ -875,9 +867,9 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e215f8c2f9f79cb53c8335e687ffd07d5bfcb6fe5fc80723762d0be46e7cc54" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1221,9 +1213,9 @@ name = "crevice-derive" version = "0.8.0" source = "git+https://github.com/bevyengine/bevy?rev=38c7d5eb9e81ab8e1aec03673599b25a9aa0c69c#38c7d5eb9e81ab8e1aec03673599b25a9aa0c69c" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1323,10 +1315,10 @@ checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "strsim", - "syn 1.0.81", + "syn", ] [[package]] @@ -1336,8 +1328,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ "darling_core", - "quote 1.0.10", - "syn 1.0.81", + "quote", + "syn", ] [[package]] @@ -1356,9 +1348,9 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1377,9 +1369,9 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f9c37d395456d9c1785499421c6288931b6e3dbc2500acb95b8adaa0e69db3" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1425,16 +1417,6 @@ dependencies = [ "serde", ] -[[package]] -name = "euclid" -version = "0.19.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "596b99621b9477e7a5f94d2d8dd13a9c5c302ac358b822c67a42b6f1054450e1" -dependencies = [ - "euclid_macros", - "num-traits", -] - [[package]] name = "euclid" version = "0.22.6" @@ -1444,17 +1426,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "euclid_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdcb84c18ea5037a1c5a23039b4ff29403abce2e0d6b1daa11cf0bde2b30be15" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", -] - [[package]] name = "event-listener" version = "2.5.1" @@ -1656,9 +1627,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f2a9333e0f9c7bca94dfc20bcf44fa12a61eeec662d6e007563ff748aa59c70" dependencies = [ "inflections", - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1729,7 +1700,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782" dependencies = [ - "euclid 0.22.6", + "euclid", "svg_fmt", ] @@ -1927,13 +1898,10 @@ dependencies = [ name = "kayak_font" version = "0.1.0" dependencies = [ - "arrayvec 0.7.2", - "bitflags", - "fontdue", - "lyon_geom", - "lyon_path", - "png", - "ttf-parser 0.13.3", + "bevy", + "serde", + "serde_json", + "serde_path_to_error", ] [[package]] @@ -1943,9 +1911,9 @@ dependencies = [ "kayak_core", "pretty_assertions", "proc-macro-error", - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -2050,26 +2018,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "lyon_geom" -version = "0.12.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb9bf1f1d43be9a9cc2343a7a096dc113cc25337a13e8f99721b01d1d548b60" -dependencies = [ - "arrayvec 0.4.12", - "euclid 0.19.9", - "num-traits", -] - -[[package]] -name = "lyon_path" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dc8e0746b7cca11960b602f7fe037bb067746a01eab4aa502fed1494544843" -dependencies = [ - "lyon_geom", -] - [[package]] name = "mach" version = "0.2.3" @@ -2295,9 +2243,9 @@ checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" dependencies = [ "darling", "proc-macro-crate 0.1.5", - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -2318,12 +2266,6 @@ dependencies = [ "libc", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "nom" version = "5.1.2" @@ -2367,9 +2309,9 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -2440,9 +2382,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9" dependencies = [ "proc-macro-crate 1.1.0", - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -2585,7 +2527,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb458bb7f6e250e6eb79d5026badc10a3ebb8f9a15d1fff0f13d17c71f4d6dee" dependencies = [ - "unicode-xid 0.2.2", + "unicode-xid", ] [[package]] @@ -2630,9 +2572,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", "version_check", ] @@ -2642,27 +2584,18 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "version_check", ] -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] - [[package]] name = "proc-macro2" version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ - "unicode-xid 0.2.2", + "unicode-xid", ] [[package]] @@ -2671,22 +2604,13 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9926767b8b8244d7b6b64546585121d193c3d0b4856ccd656b7bfa9deb91ab6a" -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", -] - [[package]] name = "quote" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ - "proc-macro2 1.0.32", + "proc-macro2", ] [[package]] @@ -2906,9 +2830,9 @@ version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -3069,11 +2993,11 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "serde", "serde_derive", - "syn 1.0.81", + "syn", ] [[package]] @@ -3083,13 +3007,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" dependencies = [ "base-x", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "serde", "serde_derive", "serde_json", "sha1", - "syn 1.0.81", + "syn", ] [[package]] @@ -3120,26 +3044,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fb1df15f412ee2e9dfc1c504260fa695c1c3f10fe9f4a6ee2d2184d7d6450e2" -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid 0.1.0", -] - [[package]] name = "syn" version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", - "unicode-xid 0.2.2", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] @@ -3166,9 +3079,9 @@ version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -3208,9 +3121,9 @@ version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -3280,12 +3193,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - [[package]] name = "unicode-xid" version = "0.2.2" @@ -3356,9 +3263,9 @@ dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", "wasm-bindgen-shared", ] @@ -3380,7 +3287,7 @@ version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" dependencies = [ - "quote 1.0.10", + "quote", "wasm-bindgen-macro-support", ] @@ -3390,9 +3297,9 @@ version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn 1.0.81", + "proc-macro2", + "quote", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3419,7 +3326,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1577ecc4f6992b9e965878ac594efb24eed2bdf089c11f45b3d1c5f216e2e30" dependencies = [ - "arrayvec 0.7.2", + "arrayvec", "js-sys", "log", "naga", @@ -3440,7 +3347,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bdcbfa4885b32c2b1feb2faeb8b6a76065b752b8f08751b82f994e937687f46" dependencies = [ - "arrayvec 0.7.2", + "arrayvec", "bitflags", "cfg_aliases", "copyless", @@ -3462,7 +3369,7 @@ version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e493835d9edb153d5c8a9d8d016e1811dbe32ddb707a110be1453c7b051d3ec" dependencies = [ - "arrayvec 0.7.2", + "arrayvec", "ash", "bit-set", "bitflags", diff --git a/bevy_kayak_ui/Cargo.toml b/bevy_kayak_ui/Cargo.toml index 074e9d38188e5639ddff6feb01740598a685420e..3e9f474a7985ad0cb1b2c5e5dde3855e1407520d 100644 --- a/bevy_kayak_ui/Cargo.toml +++ b/bevy_kayak_ui/Cargo.toml @@ -9,6 +9,7 @@ bevy = { git = "https://github.com/bevyengine/bevy", rev = "38c7d5eb9e81ab8e1aec kayak_core = { path = "../kayak_core" } kayak_components = { path = "../kayak_components" } kayak_render_macros = { path = "../kayak_render_macros" } +kayak_font = { path = "../kayak_font" } #kayak_font = { path = "../kayak_font" } crevice = { git = "https://github.com/bevyengine/bevy", rev = "38c7d5eb9e81ab8e1aec03673599b25a9aa0c69c" } serde = "1.0" diff --git a/bevy_kayak_ui/src/render/unified/font/extract.rs b/bevy_kayak_ui/src/render/unified/font/extract.rs index be26bc88c30f0324332bd10acdb92620f485bafe..6bc4a3a05128430dd4dae4d2da05d0a307353ced 100644 --- a/bevy_kayak_ui/src/render/unified/font/extract.rs +++ b/bevy_kayak_ui/src/render/unified/font/extract.rs @@ -4,13 +4,14 @@ use bevy::{ sprite2::Rect, }; use kayak_core::render_primitive::RenderPrimitive; +use kayak_font::KayakFont; use crate::{ render::unified::pipeline::{ExtractQuadBundle, ExtractedQuad, UIQuadType}, to_bevy_color, BevyContext, }; -use super::{font::KayakFont, font_mapping::FontMapping}; +use super::font_mapping::FontMapping; pub fn extract_texts( mut commands: Commands, diff --git a/bevy_kayak_ui/src/render/unified/font/font.rs b/bevy_kayak_ui/src/render/unified/font/font.rs deleted file mode 100644 index e081b89a6d21f2633126e510749d861eb01cdb7f..0000000000000000000000000000000000000000 --- a/bevy_kayak_ui/src/render/unified/font/font.rs +++ /dev/null @@ -1,34 +0,0 @@ -use std::collections::HashMap; - -use super::sdf::Sdf; -use bevy::{prelude::Handle, reflect::TypeUuid, render2::texture::Image}; - -#[derive(Debug, Clone, TypeUuid)] -#[uuid = "4fe4732c-6731-49bb-bafc-4690d636b848"] -pub struct KayakFont { - pub sdf: Sdf, - pub atlas_image: Handle<Image>, - char_ids: HashMap<char, u32>, -} - -impl KayakFont { - pub fn new(sdf: Sdf, atlas_image: Handle<Image>) -> Self { - Self { - sdf, - atlas_image, - char_ids: HashMap::default(), - } - } - - pub fn generate_char_ids(&mut self) { - let mut count = 0; - for glyph in self.sdf.glyphs.iter() { - self.char_ids.insert(glyph.unicode, count); - count += 1; - } - } - - pub fn get_char_id(&self, c: char) -> Option<u32> { - self.char_ids.get(&c).and_then(|id| Some(*id)) - } -} diff --git a/bevy_kayak_ui/src/render/unified/font/font_mapping.rs b/bevy_kayak_ui/src/render/unified/font/font_mapping.rs index eeb405ab60d8c6d6d48ab722c9cf0caaa31a33f1..743eedd5436a3e61d1e692e0f03c9b857b9f815c 100644 --- a/bevy_kayak_ui/src/render/unified/font/font_mapping.rs +++ b/bevy_kayak_ui/src/render/unified/font/font_mapping.rs @@ -1,6 +1,5 @@ use bevy::{prelude::Handle, utils::HashMap}; - -use super::font::KayakFont; +use kayak_font::KayakFont; pub struct FontMapping { count: u16, diff --git a/bevy_kayak_ui/src/render/unified/font/mod.rs b/bevy_kayak_ui/src/render/unified/font/mod.rs index 9728e4455d494359384e9783064b132ebaefb62d..5ea79d0c7fb71c92614302edbfe02eb919e7ddbf 100644 --- a/bevy_kayak_ui/src/render/unified/font/mod.rs +++ b/bevy_kayak_ui/src/render/unified/font/mod.rs @@ -12,20 +12,14 @@ use bevy::{ }, utils::HashSet, }; - -use self::{extract::extract_texts, sdf::Sdf}; - -use super::pipeline::UnifiedPipeline; +use kayak_font::{KayakFont, Sdf, FontTextureCache}; mod extract; -mod font; mod font_mapping; -mod font_texture_cache; -mod sdf; -pub use font::*; +use self::extract::extract_texts; +use super::pipeline::UnifiedPipeline; pub use font_mapping::*; -pub(crate) use font_texture_cache::FontTextureCache; #[derive(Default)] pub struct TextRendererPlugin; @@ -169,5 +163,5 @@ fn create_and_update_font_cache_texture( mut font_texture_cache: ResMut<FontTextureCache>, images: Res<RenderAssets<Image>>, ) { - font_texture_cache.process_new(&device, &queue, &pipeline, &images); + font_texture_cache.process_new(&device, &queue, pipeline.into_inner(), &images); } diff --git a/bevy_kayak_ui/src/render/unified/font/sdf/mod.rs b/bevy_kayak_ui/src/render/unified/font/sdf/mod.rs deleted file mode 100644 index 07f9b9af11e7a77120ba74f765fe716093de53a4..0000000000000000000000000000000000000000 --- a/bevy_kayak_ui/src/render/unified/font/sdf/mod.rs +++ /dev/null @@ -1,62 +0,0 @@ -use self::{atlas::Atlas, glyph::Glyph, metrics::Metrics}; -use bevy::math::Vec2; -use serde::Deserialize; - -mod atlas; -mod glyph; -mod metrics; - -#[derive(Deserialize, Debug, Clone)] -pub struct Sdf { - pub atlas: Atlas, - metrics: Metrics, - pub glyphs: Vec<Glyph>, - kerning: Vec<KerningData>, -} - -#[derive(serde::Deserialize, Debug, Clone, Copy)] -pub struct KerningData { - pub unicode1: u32, - pub unicode2: u32, - pub advance: f32, -} - -impl Sdf { - pub fn from_string(data: String) -> Sdf { - let value: Sdf = match serde_path_to_error::deserialize( - &mut serde_json::Deserializer::from_str(&data), - ) { - Ok(v) => v, - Err(err) => { - let path = err.path().to_string(); - dbg!(err); - panic!("failed to deserialize json! path: {}", path); - } - }; - - value - } - - pub fn max_glyph_size(&self) -> Vec2 { - let mut size = Vec2::new(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.y > size.y { - size.y = atlas_size.y; - } - } - }); - - size - } -} - -#[test] -fn test_sdf_loader() { - let sdf = Sdf::from_string(include_str!("../../../../../../msdfgen/test.json").to_string()); - dbg!(sdf.max_glyph_size()); -} diff --git a/bevy_kayak_ui/src/render/unified/pipeline.rs b/bevy_kayak_ui/src/render/unified/pipeline.rs index c2d1819a38d55f87b50010f94871b3f852dd8283..5bf11216b00a6193ba8c11a6677c6edfb475d0a9 100644 --- a/bevy_kayak_ui/src/render/unified/pipeline.rs +++ b/bevy_kayak_ui/src/render/unified/pipeline.rs @@ -31,8 +31,8 @@ use bevy::{ }; use bytemuck::{Pod, Zeroable}; use crevice::std140::AsStd140; +use kayak_font::{FontRenderingPipeline, FontTextureCache, KayakFont}; -use super::font::{FontTextureCache, KayakFont}; use super::UNIFIED_SHADER_HANDLE; use crate::render::ui_pass::TransparentUI; @@ -55,6 +55,12 @@ const QUAD_VERTEX_POSITIONS: &[Vec3] = &[ const_vec3!([1.0, 1.0, 0.0]), ]; +impl FontRenderingPipeline for UnifiedPipeline { + fn get_font_image_layout(&self) -> &BindGroupLayout { + &self.font_image_layout + } +} + impl FromWorld for UnifiedPipeline { fn from_world(world: &mut World) -> Self { let world = world.cell(); @@ -586,7 +592,7 @@ impl Draw<TransparentUI> for DrawUI { let unified_pipeline = unified_pipeline.into_inner(); if let Some(font_handle) = extracted_quad.font_handle.as_ref() { if let Some(image_bindings) = - font_texture_cache.into_inner().bind_groups.get(font_handle) + font_texture_cache.into_inner().get_binding(font_handle) { pass.set_bind_group(1, image_bindings, &[]); } else { diff --git a/kayak_font/Cargo.toml b/kayak_font/Cargo.toml index 79436b77847607641ead408d6144d56d548ac08b..f5ded9aef2a7f94113971945d39f0e85f8665262 100644 --- a/kayak_font/Cargo.toml +++ b/kayak_font/Cargo.toml @@ -6,12 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -arrayvec = "0.7" -bitflags = "1.0" -lyon_path = "0.12" -lyon_geom = "0.12" -fontdue = "0.6" -ttf-parser = "0.13" - -[dev-dependencies] -png = "0.16.3" +bevy = { git = "https://github.com/bevyengine/bevy", rev = "38c7d5eb9e81ab8e1aec03673599b25a9aa0c69c" } +serde = "1.0" +serde_json = "1.0" +serde_path_to_error = "0.1" diff --git a/kayak_font/assets/roboto.json b/kayak_font/assets/roboto.json new file mode 100644 index 0000000000000000000000000000000000000000..60008778e8ac698e344216c88570a2f698dbd4e3 --- /dev/null +++ b/kayak_font/assets/roboto.json @@ -0,0 +1,1529 @@ +{ + "atlas": { + "type": "msdf", + "distanceRange": 2, + "size": 32.875, + "width": 212, + "height": 212, + "yOrigin": "bottom" + }, + "metrics": { + "emSize": 1, + "lineHeight": 1.171875, + "ascender": 0.927734375, + "descender": -0.244140625, + "underlineY": -0.09765625, + "underlineThickness": 0.048828125 + }, + "glyphs": [ + { + "unicode": 32, + "advance": 0.24755859375 + }, + { + "unicode": 33, + "advance": 0.25732421875, + "planeBounds": { + "left": 0.040337044023288991, + "bottom": -0.042654059232414394, + "right": 0.22284654972671103, + "top": 0.7482204654824145 + }, + "atlasBounds": { + "left": 112.5, + "bottom": 120.5, + "right": 118.5, + "top": 146.5 + } + }, + { + "unicode": 34, + "advance": 0.31982421875, + "planeBounds": { + "left": 0.029865917597433435, + "bottom": 0.47730327649714832, + "right": 0.30363017615256649, + "top": 0.78148578600285168 + }, + "atlasBounds": { + "left": 57.5, + "bottom": 6.5, + "right": 66.5, + "top": 16.5 + } + }, + { + "unicode": 35, + "advance": 0.61572265625, + "planeBounds": { + "left": 0.026383896744296635, + "bottom": -0.039968512357414394, + "right": 0.63474891575570347, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 119.5, + "bottom": 120.5, + "right": 139.5, + "top": 146.5 + } + }, + { + "unicode": 36, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.022450726295152143, + "bottom": -0.13959645318441066, + "right": 0.53956099245484801, + "top": 0.86420582818441072 + }, + "atlasBounds": { + "left": 70.5, + "bottom": 178.5, + "right": 87.5, + "top": 211.5 + } + }, + { + "unicode": 37, + "advance": 0.732421875, + "planeBounds": { + "left": 0.02030730156844112, + "bottom": -0.055177637832699571, + "right": 0.71992707343155904, + "top": 0.76611513783269969 + }, + "atlasBounds": { + "left": 188.5, + "bottom": 184.5, + "right": 211.5, + "top": 211.5 + } + }, + { + "unicode": 38, + "advance": 0.62158203125, + "planeBounds": { + "left": 0.014592740019011461, + "bottom": -0.055177637832699571, + "right": 0.65337600998098866, + "top": 0.76611513783269969 + }, + "atlasBounds": { + "left": 36.5, + "bottom": 147.5, + "right": 57.5, + "top": 174.5 + } + }, + { + "unicode": 39, + "advance": 0.17431640625, + "planeBounds": { + "left": 0.010868435123574159, + "bottom": 0.48096538587214832, + "right": 0.16295968987642587, + "top": 0.78514789537785168 + }, + "atlasBounds": { + "left": 67.5, + "bottom": 6.5, + "right": 72.5, + "top": 16.5 + } + }, + { + "unicode": 40, + "advance": 0.341796875, + "planeBounds": { + "left": 0.026547276021863096, + "bottom": -0.26115156398526612, + "right": 0.36114803647813687, + "top": 0.83390547023526618 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 175.5, + "right": 11.5, + "top": 211.5 + } + }, + { + "unicode": 41, + "advance": 0.34765625, + "planeBounds": { + "left": -0.019595302103136911, + "bottom": -0.26115156398526612, + "right": 0.31500545835313687, + "top": 0.83390547023526618 + }, + "atlasBounds": { + "left": 12.5, + "bottom": 175.5, + "right": 23.5, + "top": 211.5 + } + }, + { + "unicode": 42, + "advance": 0.4306640625, + "planeBounds": { + "left": -0.028258116979562771, + "bottom": 0.26080438302043729, + "right": 0.45843389822956265, + "top": 0.74749639822956271 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 0.5, + "right": 16.5, + "top": 16.5 + } + }, + { + "unicode": 43, + "advance": 0.56689453125, + "planeBounds": { + "left": -0.0072351027804181973, + "bottom": 0.025895615494296635, + "right": 0.57071166528041828, + "top": 0.63426063450570347 + }, + "atlasBounds": { + "left": 154.5, + "bottom": 17.5, + "right": 173.5, + "top": 37.5 + } + }, + { + "unicode": 44, + "advance": 0.1962890625, + "planeBounds": { + "left": -0.024188487701996185, + "bottom": -0.1846343646031369, + "right": 0.18873926895199622, + "top": 0.14996639585313687 + }, + "atlasBounds": { + "left": 49.5, + "bottom": 5.5, + "right": 56.5, + "top": 16.5 + } + }, + { + "unicode": 45, + "advance": 0.27587890625, + "planeBounds": { + "left": -0.01488422350285174, + "bottom": 0.22595632574857413, + "right": 0.28929828600285168, + "top": 0.37804758050142584 + }, + "atlasBounds": { + "left": 201.5, + "bottom": 86.5, + "right": 211.5, + "top": 91.5 + } + }, + { + "unicode": 46, + "advance": 0.26318359375, + "planeBounds": { + "left": 0.035210090898288991, + "bottom": -0.042914909101711009, + "right": 0.21771959660171103, + "top": 0.13959459660171103 + }, + "atlasBounds": { + "left": 105.5, + "bottom": 10.5, + "right": 111.5, + "top": 16.5 + } + }, + { + "unicode": 47, + "advance": 0.412109375, + "planeBounds": { + "left": -0.032336100879277595, + "bottom": -0.10090434143298473, + "right": 0.42393766337927752, + "top": 0.75080668518298488 + }, + "atlasBounds": { + "left": 156.5, + "bottom": 183.5, + "right": 171.5, + "top": 211.5 + } + }, + { + "unicode": 48, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.021962445045152143, + "bottom": -0.055177637832699571, + "right": 0.53907271120484801, + "top": 0.76611513783269969 + }, + "atlasBounds": { + "left": 58.5, + "bottom": 147.5, + "right": 75.5, + "top": 174.5 + } + }, + { + "unicode": 49, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.052182041646863096, + "bottom": -0.038259527982414394, + "right": 0.38678280210313687, + "top": 0.7526149967324145 + }, + "atlasBounds": { + "left": 140.5, + "bottom": 120.5, + "right": 151.5, + "top": 146.5 + } + }, + { + "unicode": 50, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.011391991444866975, + "bottom": -0.035085699857414394, + "right": 0.5589205085551332, + "top": 0.7557888248574145 + }, + "atlasBounds": { + "left": 152.5, + "bottom": 120.5, + "right": 170.5, + "top": 146.5 + } + }, + { + "unicode": 51, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.012685101295152145, + "bottom": -0.055177637832699571, + "right": 0.52979536745484801, + "top": 0.76611513783269969 + }, + "atlasBounds": { + "left": 76.5, + "bottom": 147.5, + "right": 93.5, + "top": 174.5 + } + }, + { + "unicode": 52, + "advance": 0.5615234375, + "planeBounds": { + "left": -0.0065026809054181973, + "bottom": -0.039968512357414394, + "right": 0.57144408715541828, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 171.5, + "bottom": 120.5, + "right": 190.5, + "top": 146.5 + } + }, + { + "unicode": 53, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.04002885129515215, + "bottom": -0.044851324857414394, + "right": 0.55713911745484801, + "top": 0.7460231998574145 + }, + "atlasBounds": { + "left": 142.5, + "bottom": 92.5, + "right": 159.5, + "top": 118.5 + } + }, + { + "unicode": 54, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.03050736692015215, + "bottom": -0.044607184232414394, + "right": 0.54761763307984801, + "top": 0.7462673404824145 + }, + "atlasBounds": { + "left": 180.5, + "bottom": 92.5, + "right": 197.5, + "top": 118.5 + } + }, + { + "unicode": 55, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.0040677726948669755, + "bottom": -0.039968512357414394, + "right": 0.5515962898051332, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 146.5, + "bottom": 65.5, + "right": 164.5, + "top": 91.5 + } + }, + { + "unicode": 56, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.022206585670152143, + "bottom": -0.055177637832699571, + "right": 0.53931685182984801, + "top": 0.76611513783269969 + }, + "atlasBounds": { + "left": 118.5, + "bottom": 147.5, + "right": 135.5, + "top": 174.5 + } + }, + { + "unicode": 57, + "advance": 0.5615234375, + "planeBounds": { + "left": 0.013905804420152145, + "bottom": -0.035329840482414394, + "right": 0.53101607057984801, + "top": 0.7555446842324145 + }, + "atlasBounds": { + "left": 44.5, + "bottom": 38.5, + "right": 61.5, + "top": 64.5 + } + }, + { + "unicode": 58, + "advance": 0.2421875, + "planeBounds": { + "left": 0.030571419023288991, + "bottom": -0.040266493880703365, + "right": 0.21308092472671103, + "top": 0.56809852513070347 + }, + "atlasBounds": { + "left": 201.5, + "bottom": 65.5, + "right": 207.5, + "top": 85.5 + } + }, + { + "unicode": 59, + "advance": 0.21142578125, + "planeBounds": { + "left": -0.013202159576996183, + "bottom": -0.18442735563212925, + "right": 0.19972559707699622, + "top": 0.57602891813212931 + }, + "atlasBounds": { + "left": 98.5, + "bottom": 39.5, + "right": 105.5, + "top": 64.5 + } + }, + { + "unicode": 60, + "advance": 0.50830078125, + "planeBounds": { + "left": -0.0084827263545627658, + "bottom": 0.05711869504515215, + "right": 0.47820928885456265, + "top": 0.57422896120484801 + }, + "atlasBounds": { + "left": 174.5, + "bottom": 20.5, + "right": 190.5, + "top": 37.5 + } + }, + { + "unicode": 61, + "advance": 0.548828125, + "planeBounds": { + "left": 0.034486023645437264, + "bottom": 0.15293971304657797, + "right": 0.52117803885456271, + "top": 0.51795872445342206 + }, + "atlasBounds": { + "left": 32.5, + "bottom": 4.5, + "right": 48.5, + "top": 16.5 + } + }, + { + "unicode": 62, + "advance": 0.5224609375, + "planeBounds": { + "left": 0.030579773645437264, + "bottom": 0.05760697629515215, + "right": 0.51727178885456271, + "top": 0.57471724245484801 + }, + "atlasBounds": { + "left": 191.5, + "bottom": 20.5, + "right": 207.5, + "top": 37.5 + } + }, + { + "unicode": 63, + "advance": 0.47216796875, + "planeBounds": { + "left": -0.0087268669795627658, + "bottom": -0.037771246732414394, + "right": 0.47796514822956265, + "top": 0.7531032779824145 + }, + "atlasBounds": { + "left": 62.5, + "bottom": 38.5, + "right": 78.5, + "top": 64.5 + } + }, + { + "unicode": 64, + "advance": 0.89794921875, + "planeBounds": { + "left": 0.012067393169925377, + "bottom": -0.26313160943441061, + "right": 0.89419667073646536, + "top": 0.74067067193441072 + }, + "atlasBounds": { + "left": 88.5, + "bottom": 178.5, + "right": 117.5, + "top": 211.5 + } + }, + { + "unicode": 65, + "advance": 0.65234375, + "planeBounds": { + "left": -0.02339387030655888, + "bottom": -0.039968512357414394, + "right": 0.67622590155655904, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 20.5, + "bottom": 38.5, + "right": 43.5, + "top": 64.5 + } + }, + { + "unicode": 66, + "advance": 0.62255859375, + "planeBounds": { + "left": 0.050698632069866974, + "bottom": -0.039968512357414394, + "right": 0.5982271491801332, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 79.5, + "bottom": 38.5, + "right": 97.5, + "top": 64.5 + } + }, + { + "unicode": 67, + "advance": 0.65087890625, + "planeBounds": { + "left": 0.027604599869296632, + "bottom": -0.055177637832699571, + "right": 0.63596961888070347, + "top": 0.76611513783269969 + }, + "atlasBounds": { + "left": 136.5, + "bottom": 147.5, + "right": 156.5, + "top": 174.5 + } + }, + { + "unicode": 68, + "advance": 0.65576171875, + "planeBounds": { + "left": 0.050626225344581804, + "bottom": -0.039968512357414394, + "right": 0.62857299340541828, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 38.5, + "right": 19.5, + "top": 64.5 + } + }, + { + "unicode": 69, + "advance": 0.568359375, + "planeBounds": { + "left": 0.04979447629515215, + "bottom": -0.039968512357414394, + "right": 0.56690474245484801, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 183.5, + "bottom": 65.5, + "right": 200.5, + "top": 91.5 + } + }, + { + "unicode": 70, + "advance": 0.552734375, + "planeBounds": { + "left": 0.04417924192015215, + "bottom": -0.039968512357414394, + "right": 0.56128950807984801, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 165.5, + "bottom": 65.5, + "right": 182.5, + "top": 91.5 + } + }, + { + "unicode": 71, + "advance": 0.68115234375, + "planeBounds": { + "left": 0.014104458769011461, + "bottom": -0.055177637832699571, + "right": 0.65288772873098866, + "top": 0.76611513783269969 + }, + "atlasBounds": { + "left": 32.5, + "bottom": 119.5, + "right": 53.5, + "top": 146.5 + } + }, + { + "unicode": 72, + "advance": 0.712890625, + "planeBounds": { + "left": 0.051530381119296635, + "bottom": -0.039968512357414394, + "right": 0.65989540013070347, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 125.5, + "bottom": 65.5, + "right": 145.5, + "top": 91.5 + } + }, + { + "unicode": 73, + "advance": 0.27197265625, + "planeBounds": { + "left": 0.044975715898288991, + "bottom": -0.039968512357414394, + "right": 0.22748522160171103, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 205.5, + "bottom": 92.5, + "right": 211.5, + "top": 118.5 + } + }, + { + "unicode": 74, + "advance": 0.5517578125, + "planeBounds": { + "left": -0.0083109924548478552, + "bottom": -0.044851324857414394, + "right": 0.50879927370484801, + "top": 0.7460231998574145 + }, + "atlasBounds": { + "left": 86.5, + "bottom": 65.5, + "right": 103.5, + "top": 91.5 + } + }, + { + "unicode": 75, + "advance": 0.626953125, + "planeBounds": { + "left": 0.050797959244296635, + "bottom": -0.039968512357414394, + "right": 0.65916297825570347, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 65.5, + "bottom": 65.5, + "right": 85.5, + "top": 91.5 + } + }, + { + "unicode": 76, + "advance": 0.5380859375, + "planeBounds": { + "left": 0.039540570045152094, + "bottom": -0.039968512357414394, + "right": 0.5566508362048479, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 47.5, + "bottom": 65.5, + "right": 64.5, + "top": 91.5 + } + }, + { + "unicode": 77, + "advance": 0.873046875, + "planeBounds": { + "left": 0.040842034517585606, + "bottom": -0.039968512357414394, + "right": 0.8317165592324145, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 20.5, + "bottom": 65.5, + "right": 46.5, + "top": 91.5 + } + }, + { + "unicode": 78, + "advance": 0.712890625, + "planeBounds": { + "left": 0.051530381119296635, + "bottom": -0.039968512357414394, + "right": 0.65989540013070347, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 104.5, + "bottom": 65.5, + "right": 124.5, + "top": 91.5 + } + }, + { + "unicode": 79, + "advance": 0.6875, + "planeBounds": { + "left": 0.024114224394011459, + "bottom": -0.055177637832699571, + "right": 0.66289749435598866, + "top": 0.76611513783269969 + }, + "atlasBounds": { + "left": 72.5, + "bottom": 119.5, + "right": 93.5, + "top": 146.5 + } + }, + { + "unicode": 80, + "advance": 0.630859375, + "planeBounds": { + "left": 0.049161381594581804, + "bottom": -0.039968512357414394, + "right": 0.62710814965541828, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 65.5, + "right": 19.5, + "top": 91.5 + } + }, + { + "unicode": 81, + "advance": 0.6875, + "planeBounds": { + "left": 0.021184536894011459, + "bottom": -0.15598079550855509, + "right": 0.65996780685598866, + "top": 0.75656673300855526 + }, + "atlasBounds": { + "left": 134.5, + "bottom": 181.5, + "right": 155.5, + "top": 211.5 + } + }, + { + "unicode": 82, + "advance": 0.61572265625, + "planeBounds": { + "left": 0.051114506594581804, + "bottom": -0.039968512357414394, + "right": 0.62906127465541828, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 160.5, + "bottom": 92.5, + "right": 179.5, + "top": 118.5 + } + }, + { + "unicode": 83, + "advance": 0.59326171875, + "planeBounds": { + "left": 0.0083898972195818027, + "bottom": -0.055177637832699571, + "right": 0.58633666528041828, + "top": 0.76611513783269969 + }, + "atlasBounds": { + "left": 192.5, + "bottom": 147.5, + "right": 211.5, + "top": 174.5 + } + }, + { + "unicode": 84, + "advance": 0.5966796875, + "planeBounds": { + "left": -0.020563509980988541, + "bottom": -0.039968512357414394, + "right": 0.61821975998098866, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 120.5, + "bottom": 92.5, + "right": 141.5, + "top": 118.5 + } + }, + { + "unicode": 85, + "advance": 0.6484375, + "planeBounds": { + "left": 0.036710209719581804, + "bottom": -0.044851324857414394, + "right": 0.61465697778041828, + "top": 0.7460231998574145 + }, + "atlasBounds": { + "left": 100.5, + "bottom": 92.5, + "right": 119.5, + "top": 118.5 + } + }, + { + "unicode": 86, + "advance": 0.63623046875, + "planeBounds": { + "left": -0.03120637030655888, + "bottom": -0.039968512357414394, + "right": 0.66841340155655904, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 76.5, + "bottom": 92.5, + "right": 99.5, + "top": 118.5 + } + }, + { + "unicode": 87, + "advance": 0.88720703125, + "planeBounds": { + "left": -0.0085198580085550802, + "bottom": -0.039968512357414394, + "right": 0.90402767050855526, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 45.5, + "bottom": 92.5, + "right": 75.5, + "top": 118.5 + } + }, + { + "unicode": 88, + "advance": 0.626953125, + "planeBounds": { + "left": -0.0051826506059885393, + "bottom": -0.039968512357414394, + "right": 0.63360061935598866, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 23.5, + "bottom": 92.5, + "right": 44.5, + "top": 118.5 + } + }, + { + "unicode": 89, + "advance": 0.6005859375, + "planeBounds": { + "left": -0.03528435420627371, + "bottom": -0.039968512357414394, + "right": 0.63391716670627374, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 92.5, + "right": 22.5, + "top": 118.5 + } + }, + { + "unicode": 90, + "advance": 0.5986328125, + "planeBounds": { + "left": -0.0034012595057033666, + "bottom": -0.039968512357414394, + "right": 0.60496375950570347, + "top": 0.7509060123574145 + }, + "atlasBounds": { + "left": 191.5, + "bottom": 120.5, + "right": 211.5, + "top": 146.5 + } + }, + { + "unicode": 91, + "advance": 0.26513671875, + "planeBounds": { + "left": 0.026447948847433435, + "bottom": -0.18703214115969582, + "right": 0.30021220740256649, + "top": 0.84718839115969591 + }, + "atlasBounds": { + "left": 37.5, + "bottom": 177.5, + "right": 46.5, + "top": 211.5 + } + }, + { + "unicode": 92, + "advance": 0.41015625, + "planeBounds": { + "left": -0.017199382129277595, + "bottom": -0.10090434143298473, + "right": 0.43907438212927752, + "top": 0.75080668518298488 + }, + "atlasBounds": { + "left": 172.5, + "bottom": 183.5, + "right": 187.5, + "top": 211.5 + } + }, + { + "unicode": 93, + "advance": 0.26513671875, + "planeBounds": { + "left": -0.040202441777566537, + "bottom": -0.18703214115969582, + "right": 0.23356181677756652, + "top": 0.84718839115969591 + }, + "atlasBounds": { + "left": 60.5, + "bottom": 177.5, + "right": 69.5, + "top": 211.5 + } + }, + { + "unicode": 94, + "advance": 0.41796875, + "planeBounds": { + "left": -0.0049199441539924237, + "bottom": 0.32051950897100762, + "right": 0.42093556915399238, + "top": 0.74637502227899244 + }, + "atlasBounds": { + "left": 17.5, + "bottom": 2.5, + "right": 31.5, + "top": 16.5 + } + }, + { + "unicode": 95, + "advance": 0.451171875, + "planeBounds": { + "left": -0.032969195579847906, + "bottom": -0.11291086175142585, + "right": 0.4841410705798479, + "top": 0.039180393001425839 + }, + "atlasBounds": { + "left": 112.5, + "bottom": 11.5, + "right": 129.5, + "top": 16.5 + } + }, + { + "unicode": 96, + "advance": 0.30908203125, + "planeBounds": { + "left": -0.0072434574025665669, + "bottom": 0.57175877792300378, + "right": 0.26652080115256649, + "top": 0.78468653457699622 + }, + "atlasBounds": { + "left": 95.5, + "bottom": 9.5, + "right": 104.5, + "top": 16.5 + } + }, + { + "unicode": 97, + "advance": 0.5439453125, + "planeBounds": { + "left": 0.012685101295152093, + "bottom": -0.055231478730988541, + "right": 0.5297953674548479, + "top": 0.58355179123098866 + }, + "atlasBounds": { + "left": 191.5, + "bottom": 43.5, + "right": 208.5, + "top": 64.5 + } + }, + { + "unicode": 98, + "advance": 0.56103515625, + "planeBounds": { + "left": 0.03343705442015215, + "bottom": -0.040529200332699564, + "right": 0.55054732057984801, + "top": 0.78076357533269969 + }, + "atlasBounds": { + "left": 54.5, + "bottom": 119.5, + "right": 71.5, + "top": 146.5 + } + }, + { + "unicode": 99, + "advance": 0.5234375, + "planeBounds": { + "left": 0.0090229919201521448, + "bottom": -0.055231478730988541, + "right": 0.52613325807984801, + "top": 0.58355179123098866 + }, + "atlasBounds": { + "left": 138.5, + "bottom": 43.5, + "right": 155.5, + "top": 64.5 + } + }, + { + "unicode": 100, + "advance": 0.56396484375, + "planeBounds": { + "left": 0.010731976295152145, + "bottom": -0.040529200332699564, + "right": 0.52784224245484801, + "top": 0.78076357533269969 + }, + "atlasBounds": { + "left": 14.5, + "bottom": 119.5, + "right": 31.5, + "top": 146.5 + } + }, + { + "unicode": 101, + "advance": 0.52978515625, + "planeBounds": { + "left": 0.010976116920152145, + "bottom": -0.055231478730988541, + "right": 0.52808638307984801, + "top": 0.58355179123098866 + }, + "atlasBounds": { + "left": 173.5, + "bottom": 43.5, + "right": 190.5, + "top": 64.5 + } + }, + { + "unicode": 102, + "advance": 0.34716796875, + "planeBounds": { + "left": -0.008753787428707251, + "bottom": -0.030519434707699571, + "right": 0.38668347492870719, + "top": 0.79077334095769969 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 119.5, + "right": 13.5, + "top": 146.5 + } + }, + { + "unicode": 103, + "advance": 0.56103515625, + "planeBounds": { + "left": 0.011464398170152145, + "bottom": -0.24560732533269961, + "right": 0.52857466432984801, + "top": 0.57568545033269969 + }, + "atlasBounds": { + "left": 174.5, + "bottom": 147.5, + "right": 191.5, + "top": 174.5 + } + }, + { + "unicode": 104, + "advance": 0.55078125, + "planeBounds": { + "left": 0.032777039270437264, + "bottom": -0.035646387832699571, + "right": 0.51946905447956271, + "top": 0.78564638783269969 + }, + "atlasBounds": { + "left": 157.5, + "bottom": 147.5, + "right": 173.5, + "top": 174.5 + } + }, + { + "unicode": 105, + "advance": 0.24267578125, + "planeBounds": { + "left": 0.031059700273288991, + "bottom": -0.035085699857414394, + "right": 0.21356920597671103, + "top": 0.7557888248574145 + }, + "atlasBounds": { + "left": 198.5, + "bottom": 92.5, + "right": 204.5, + "top": 118.5 + } + }, + { + "unicode": 106, + "advance": 0.23876953125, + "planeBounds": { + "left": -0.06852275427756653, + "bottom": -0.24823903130941069, + "right": 0.20524150427756652, + "top": 0.75556325005941072 + }, + "atlasBounds": { + "left": 118.5, + "bottom": 178.5, + "right": 127.5, + "top": 211.5 + } + }, + { + "unicode": 107, + "advance": 0.5068359375, + "planeBounds": { + "left": 0.028798382545152094, + "bottom": -0.035646387832699571, + "right": 0.5459086487048479, + "top": 0.78564638783269969 + }, + "atlasBounds": { + "left": 100.5, + "bottom": 147.5, + "right": 117.5, + "top": 174.5 + } + }, + { + "unicode": 108, + "advance": 0.24267578125, + "planeBounds": { + "left": 0.045292263248574161, + "bottom": -0.035646387832699571, + "right": 0.19738351800142587, + "top": 0.78564638783269969 + }, + "atlasBounds": { + "left": 94.5, + "bottom": 147.5, + "right": 99.5, + "top": 174.5 + } + }, + { + "unicode": 109, + "advance": 0.87646484375, + "planeBounds": { + "left": 0.027586034042300436, + "bottom": -0.035139540755703365, + "right": 0.84887880970769969, + "top": 0.57322547825570347 + }, + "atlasBounds": { + "left": 82.5, + "bottom": 17.5, + "right": 109.5, + "top": 37.5 + } + }, + { + "unicode": 110, + "advance": 0.5517578125, + "planeBounds": { + "left": 0.032777039270437264, + "bottom": -0.035139540755703365, + "right": 0.51946905447956271, + "top": 0.57322547825570347 + }, + "atlasBounds": { + "left": 18.5, + "bottom": 17.5, + "right": 34.5, + "top": 37.5 + } + }, + { + "unicode": 111, + "advance": 0.5703125, + "planeBounds": { + "left": 0.011147850819866975, + "bottom": -0.055231478730988541, + "right": 0.5586763679301332, + "top": 0.58355179123098866 + }, + "atlasBounds": { + "left": 119.5, + "bottom": 43.5, + "right": 137.5, + "top": 64.5 + } + }, + { + "unicode": 112, + "advance": 0.56103515625, + "planeBounds": { + "left": 0.03294877317015215, + "bottom": -0.24316591908269961, + "right": 0.55005903932984801, + "top": 0.57812685658269969 + }, + "atlasBounds": { + "left": 18.5, + "bottom": 147.5, + "right": 35.5, + "top": 174.5 + } + }, + { + "unicode": 113, + "advance": 0.568359375, + "planeBounds": { + "left": 0.010487835670152145, + "bottom": -0.24316591908269961, + "right": 0.52759810182984801, + "top": 0.57812685658269969 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 147.5, + "right": 17.5, + "top": 174.5 + } + }, + { + "unicode": 114, + "advance": 0.33837890625, + "planeBounds": { + "left": 0.028744541646863096, + "bottom": -0.035139540755703365, + "right": 0.36334530210313687, + "top": 0.57322547825570347 + }, + "atlasBounds": { + "left": 70.5, + "bottom": 17.5, + "right": 81.5, + "top": 37.5 + } + }, + { + "unicode": 115, + "advance": 0.515625, + "planeBounds": { + "left": 0.013001648645437234, + "bottom": -0.055231478730988541, + "right": 0.49969366385456265, + "top": 0.58355179123098866 + }, + "atlasBounds": { + "left": 156.5, + "bottom": 43.5, + "right": 172.5, + "top": 64.5 + } + }, + { + "unicode": 116, + "advance": 0.32666015625, + "planeBounds": { + "left": -0.03431614632842208, + "bottom": -0.041776823906844049, + "right": 0.330702865078422, + "top": 0.68826119890684423 + }, + "atlasBounds": { + "left": 106.5, + "bottom": 40.5, + "right": 118.5, + "top": 64.5 + } + }, + { + "unicode": 117, + "advance": 0.55126953125, + "planeBounds": { + "left": 0.031068054895437264, + "bottom": -0.044905165755703365, + "right": 0.51776007010456271, + "top": 0.56345985325570347 + }, + "atlasBounds": { + "left": 110.5, + "bottom": 17.5, + "right": 126.5, + "top": 37.5 + } + }, + { + "unicode": 118, + "advance": 0.484375, + "planeBounds": { + "left": -0.017588336204847906, + "bottom": -0.040022353255703365, + "right": 0.4995219299548479, + "top": 0.56834266575570347 + }, + "atlasBounds": { + "left": 35.5, + "bottom": 17.5, + "right": 52.5, + "top": 37.5 + } + }, + { + "unicode": 119, + "advance": 0.75146484375, + "planeBounds": { + "left": -0.020925543607414394, + "bottom": -0.040022353255703365, + "right": 0.7699489811074145, + "top": 0.56834266575570347 + }, + "atlasBounds": { + "left": 127.5, + "bottom": 17.5, + "right": 153.5, + "top": 37.5 + } + }, + { + "unicode": 120, + "advance": 0.49560546875, + "planeBounds": { + "left": -0.011728961204847855, + "bottom": -0.040022353255703365, + "right": 0.50538130495484801, + "top": 0.56834266575570347 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 17.5, + "right": 17.5, + "top": 37.5 + } + }, + { + "unicode": 121, + "advance": 0.47314453125, + "planeBounds": { + "left": -0.022715289329847906, + "bottom": -0.25317568470769958, + "right": 0.4943949768298479, + "top": 0.56811709095769969 + }, + "atlasBounds": { + "left": 94.5, + "bottom": 119.5, + "right": 111.5, + "top": 146.5 + } + }, + { + "unicode": 122, + "advance": 0.49560546875, + "planeBounds": { + "left": 0.0093395392704372342, + "bottom": -0.040022353255703365, + "right": 0.49603155447956265, + "top": 0.56834266575570347 + }, + "atlasBounds": { + "left": 53.5, + "bottom": 17.5, + "right": 69.5, + "top": 37.5 + } + }, + { + "unicode": 123, + "advance": 0.33837890625, + "planeBounds": { + "left": -0.0033102869534220817, + "bottom": -0.21657315678469582, + "right": 0.361708724453422, + "top": 0.81764737553469591 + }, + "atlasBounds": { + "left": 47.5, + "bottom": 177.5, + "right": 59.5, + "top": 211.5 + } + }, + { + "unicode": 124, + "advance": 0.24365234375, + "planeBounds": { + "left": 0.045780544498574161, + "bottom": -0.16672298300855509, + "right": 0.19787179925142587, + "top": 0.74582454550855526 + }, + "atlasBounds": { + "left": 128.5, + "bottom": 181.5, + "right": 133.5, + "top": 211.5 + } + }, + { + "unicode": 125, + "advance": 0.33837890625, + "planeBounds": { + "left": -0.02503880257842208, + "bottom": -0.21657315678469582, + "right": 0.339980208828422, + "top": 0.81764737553469591 + }, + "atlasBounds": { + "left": 24.5, + "bottom": 177.5, + "right": 36.5, + "top": 211.5 + } + }, + { + "unicode": 126, + "advance": 0.68017578125, + "planeBounds": { + "left": 0.020940396269011466, + "bottom": 0.15706318322243343, + "right": 0.65972366623098866, + "top": 0.43082744177756649 + }, + "atlasBounds": { + "left": 73.5, + "bottom": 7.5, + "right": 94.5, + "top": 16.5 + } + } + ], + "kerning": [] +} \ No newline at end of file diff --git a/kayak_font/examples/main.rs b/kayak_font/examples/main.rs deleted file mode 100644 index 2bed82802396a4971c6a7b678c0fcbce6819365f..0000000000000000000000000000000000000000 --- a/kayak_font/examples/main.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::{fs::File, io::BufWriter}; - -use kayak_font::{ - compute_msdf, recolor_contours, rescale_contours, Angle, FlatPathBuilder, PathCollector, Point, - Rect, -}; - -pub fn main() { - let font_data = include_bytes!("../resources/Roboto-Regular.ttf"); - let face = ttf_parser::Face::from_slice(font_data, 0).unwrap(); - - let char_dim: u32 = 64; - - let c = 'A'; - if let Some(glyph) = face.glyph_index(c) { - let mut path_collector = PathCollector::new(); - path_collector.scale = 1.0; //0.0001; //1024 as f32 / face.units_per_em() as f32; - let rect = face.outline_glyph(glyph, &mut path_collector).unwrap(); - let contours = path_collector.build(); - let uv_rect = Rect::new(Point::new(0.0, 0.0), lyon_geom::math::Size::new(1.0, 1.0)); - - let font_rect = Rect::new( - Point::new(rect.x_min as f32, rect.y_min as f32), - lyon_geom::math::Size::new(rect.width() as f32, rect.height() as f32), - ); - - let (contours, _) = rescale_contours(contours, font_rect, uv_rect, 0); - - let contours = recolor_contours(contours, Angle::degrees(3.0), 1); - let msdf = compute_msdf(&contours, char_dim as usize); - - let file = File::create(format!("./test-{}.png", c)).unwrap(); - let ref mut w = BufWriter::new(file); - - let pixels: Vec<u8> = msdf - .iter() - .flat_map(|y| { - y.iter().flat_map(|pixel| { - vec![ - (pixel.0 * 255.0) as u8, - (pixel.1 * 255.0) as u8, - (pixel.2 * 255.0) as u8, - 255u8, - ] - }) - }) - .collect(); - - let mut encoder = png::Encoder::new(w, char_dim, char_dim); - encoder.set_color(png::ColorType::RGBA); - let mut writer = encoder.write_header().unwrap(); - writer.write_image_data(&pixels).unwrap(); - } -} diff --git a/kayak_font/examples/simple.rs b/kayak_font/examples/simple.rs deleted file mode 100644 index 97efddbdff2d524c27beb9bf9a17a6636d0dd145..0000000000000000000000000000000000000000 --- a/kayak_font/examples/simple.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::{fs::File, io::BufWriter}; - -use kayak_font::Font; - -fn main() { - let font_bytes = include_bytes!("../resources/Roboto-Regular.ttf"); - let mut font = Font::new(font_bytes, (64, 64)); - - font.add_character('A'); - font.add_character('B'); - font.add_character('C'); - font.add_character('!'); - font.add_character('&'); - - // Characters that have already been calculated wont be calculated again! - for _ in 0..1000000 { - font.add_character('A'); - } - - let dimensions = font.cache.dimensions; - for (c, _, pixels) in font.get_data_to_process() { - let file = File::create(format!("./test-{}.png", c)).unwrap(); - let ref mut w = BufWriter::new(file); - - let mut encoder = png::Encoder::new(w, dimensions.0, dimensions.1); - encoder.set_color(png::ColorType::RGBA); - let mut writer = encoder.write_header().unwrap(); - writer.write_image_data(&pixels).unwrap(); - } -} diff --git a/kayak_font/resources/Roboto-Regular.ttf b/kayak_font/resources/Roboto-Regular.ttf deleted file mode 100644 index 2b6392ffe8712b9c5450733320cd220d6c0f4bce..0000000000000000000000000000000000000000 Binary files a/kayak_font/resources/Roboto-Regular.ttf and /dev/null differ diff --git a/bevy_kayak_ui/src/render/unified/font/sdf/atlas.rs b/kayak_font/src/atlas.rs similarity index 100% rename from bevy_kayak_ui/src/render/unified/font/sdf/atlas.rs rename to kayak_font/src/atlas.rs diff --git a/kayak_font/src/color_flags.rs b/kayak_font/src/color_flags.rs deleted file mode 100644 index 7322912b4e0c849822302ba5bcc85f374b1af552..0000000000000000000000000000000000000000 --- a/kayak_font/src/color_flags.rs +++ /dev/null @@ -1,62 +0,0 @@ -bitflags::bitflags! { - pub struct ColorFlags: u32 { - const BLACK = 0b000; - const RED = 0b001; - const GREEN = 0b010; - const BLUE = 0b100; - const YELLOW = 0b011; - const MAGENTA = 0b101; - const CYAN = 0b110; - const WHITE = 0b111; - } -} - -impl ColorFlags { - pub(crate) fn switch(self, seed: &mut u64) -> Self { - match self { - ColorFlags::WHITE | ColorFlags::BLACK => { - const START: [ColorFlags; 3] = - [ColorFlags::CYAN, ColorFlags::MAGENTA, ColorFlags::YELLOW]; - let tr = START[(*seed % 3) as usize]; - *seed /= 3; - tr - } - ColorFlags::RED | ColorFlags::GREEN | ColorFlags::BLUE => self ^ ColorFlags::WHITE, - _ => { - let v = self.bits(); - let v = (v << (1 + (*seed & 1))) & 0b111; - let v = match v.count_ones() { - 0 => 0b11, /* Somehow we lost all the bits. Default to yellow */ - 1 => v | 0b001, /* We just shifted a bit off the left side, add one on the right */ - 2 => v, /* We already have 2 bits, nothing to do */ - _ => unreachable!(), /* There should never be 3+ bits set */ - }; - *seed >>= 1; - - Self::from_bits_truncate(v) - } - } - } - - pub(crate) fn switch_banned(self, seed: &mut u64, banned: ColorFlags) -> Self { - let combined = self & banned; - match combined { - ColorFlags::RED | ColorFlags::GREEN | ColorFlags::BLUE => combined ^ ColorFlags::WHITE, - _ => self.switch(seed), - } - } - - pub fn float_color(self) -> [f32; 3] { - match self { - ColorFlags::BLACK => [0.0f32, 0.0f32, 0.0f32], - ColorFlags::RED => [1.0f32, 0.0f32, 0.0f32], - ColorFlags::GREEN => [0.0f32, 1.0f32, 0.0f32], - ColorFlags::BLUE => [0.0f32, 0.0f32, 1.0f32], - ColorFlags::CYAN => [0.0f32, 1.0f32, 1.0f32], - ColorFlags::MAGENTA => [1.0f32, 0.0f32, 1.0f32], - ColorFlags::YELLOW => [1.0f32, 1.0f32, 0.0f32], - ColorFlags::WHITE => [1.0f32, 1.0f32, 1.0f32], - _ => [0.5, 0.7, 0.5], - } - } -} diff --git a/kayak_font/src/contour.rs b/kayak_font/src/contour.rs deleted file mode 100644 index 6b21056bbca0170bc293f4ba54f802b5b6c57cb6..0000000000000000000000000000000000000000 --- a/kayak_font/src/contour.rs +++ /dev/null @@ -1,107 +0,0 @@ -use lyon_geom::math::{Point, Rect}; -use lyon_path::Segment; - -use crate::path_element::PathElement; - -/// A list of path elements forming a closed loop -#[derive(Clone, Debug)] -pub struct Contour { - pub elements: Vec<PathElement>, -} - -impl Contour { - pub fn winding(&self) -> f32 { - let shoelace = |a: Point, b: Point| (b.x - a.x) * (a.y + b.y); - let n = self.elements.len(); - match n { - 0 => 0.0, - 1 => { - let a = self.elements[0].sample(0.0); - let b = self.elements[0].sample(1.0 / 3.0); - let c = self.elements[0].sample(2.0 / 3.0); - - shoelace(a, b) + shoelace(b, c) + shoelace(c, a) - } - 2 => { - let a = self.elements[0].sample(0.0); - let b = self.elements[0].sample(0.5); - let c = self.elements[1].sample(0.0); - let d = self.elements[1].sample(0.5); - - shoelace(a, b) + shoelace(b, c) + shoelace(c, d) + shoelace(d, a) - } - _ => { - let mut total = 0.0; - let mut prev = self.elements[n - 1].sample(0.0); - - for e in &self.elements { - let curr = e.sample(0.0); - total += shoelace(prev, curr); - prev = curr; - } - - total - } - } - .signum() - } -} - -/// Rescale contours so they fit in the provided rectangle. -/// Returns the scaled contours along with the transformation used to rescale the contours -pub fn rescale_contours( - mut contours: Vec<Contour>, - initial_bounds: Rect, - bounds: Rect, - _units_per_em: u16, -) -> (Vec<Contour>, lyon_geom::math::Transform2D) { - // let (new_width, new_height) = if initial_bounds.size.width > initial_bounds.size.height { - // let new_width = 1.0; - // let new_height = aspect_ratio_height( - // initial_bounds.size.height, - // initial_bounds.size.width, - // new_width, - // ); - - // (new_width, new_height) - // } else { - // let new_height = 1.0; - // let new_width = aspect_ratio_width( - // initial_bounds.size.height, - // initial_bounds.size.width, - // new_height, - // ); - - // (new_width, new_height) - // }; - - - // let x_scale = new_width / initial_bounds.size.width; - // let y_scale = new_height / initial_bounds.size.height; - - let initial_scale = initial_bounds.size.height.max(initial_bounds.size.width); - let bounds_scale = bounds.size.width.max(bounds.size.height); - - // let size = 128.0 / units_per_em as f32; - let transformation = lyon_geom::math::Transform2D::create_translation( - -initial_bounds.origin.x as f32, - -initial_bounds.origin.y as f32, - ) - .post_scale(bounds_scale / initial_scale, bounds_scale / initial_scale) - .post_translate(bounds.origin.to_vector()); - for contour in &mut contours { - for mut elem in &mut contour.elements { - elem.segment = match elem.segment { - Segment::Line(s) => Segment::Line(s.transform(&transformation)), - Segment::Quadratic(s) => Segment::Quadratic(s.transform(&transformation)), - Segment::Cubic(s) => Segment::Cubic(s.transform(&transformation)), - Segment::Arc(s) => Segment::Arc(lyon_geom::Arc { - center: transformation.transform_point(&s.center), - ..s - }), - } - } - } - - (contours, transformation) -} diff --git a/kayak_font/src/font.rs b/kayak_font/src/font.rs index 81f4977deef7ebbf16ddec103bc04287ef7c0cac..2a2b06d452d28ce97ae5529d8825216517a7aeda 100644 --- a/kayak_font/src/font.rs +++ b/kayak_font/src/font.rs @@ -1,267 +1,36 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; -use lyon_geom::math::{Angle, Point, Rect, Size}; -use lyon_path::builder::FlatPathBuilder; -use crate::{compute_msdf, recolor_contours, rescale_contours, PathCollector}; +use bevy::{prelude::Handle, reflect::TypeUuid, render2::texture::Image}; -#[derive(Debug, Clone)] -pub struct FontCache { - count: usize, - pub dimensions: (u32, u32), - chars: HashMap<char, (usize, Vec<u8>)>, - needs_processing: HashSet<usize>, - id_to_char_mappings: HashMap<usize, char>, -} - -impl FontCache { - pub fn new(texture_size: (u32, u32)) -> Self { - Self { - count: 0, - dimensions: texture_size, - chars: HashMap::default(), - needs_processing: HashSet::default(), - id_to_char_mappings: HashMap::default(), - } - } - - pub fn add_character(&mut self, c: char) { - self.chars.insert(c, (self.count, vec![])); - self.id_to_char_mappings.insert(self.count, c); - self.count += 1; - } - - fn set_texture(&mut self, c: char, texture_data: Vec<Vec<(f32, f32, f32)>>) { - // let pixels: Vec<u8> = texture_data - // .iter() - // .flat_map(|y| { - // y.iter().flat_map(|pixel| { - // vec![ - // (pixel.0 * 255.0) as u8, - // (pixel.1 * 255.0) as u8, - // (pixel.2 * 255.0) as u8, - // 255u8, - // ] - // }) - // }) - // .collect(); - let pixels = texture_data - .iter() - .flat_map(|x| { - x.iter() - .flat_map(|p| { - vec![ - p.0.to_le_bytes(), - p.1.to_le_bytes(), - p.2.to_le_bytes(), - 1.0f32.to_le_bytes(), - ] - .into_iter() - .flatten() - .collect::<Vec<u8>>() - }) - .collect::<Vec<u8>>() - }) - .collect(); - self.chars.insert(c, (self.count, pixels)); - self.needs_processing.insert(self.count); - self.id_to_char_mappings.insert(self.count, c); - self.count += 1; - } +use crate::Sdf; - pub fn has_character(&self, c: char) -> bool { - self.chars.contains_key(&c) - } - - fn get_dimensions(&self) -> (u32, u32) { - self.dimensions - } +#[derive(Debug, Clone, TypeUuid)] +#[uuid = "4fe4732c-6731-49bb-bafc-4690d636b848"] +pub struct KayakFont { + pub sdf: Sdf, + pub atlas_image: Handle<Image>, + char_ids: HashMap<char, u32>, } -#[derive(Debug, Clone)] -pub struct Font { - internal_face: ttf_parser::Face<'static>, - font: fontdue::Font, - pub cache: FontCache, -} - -impl Font { - pub fn new(font_data: &'static [u8], texture_size: (u32, u32)) -> Font { - Font { - internal_face: ttf_parser::Face::from_slice(&font_data, 0).unwrap(), - font: fontdue::Font::from_bytes(font_data.clone(), fontdue::FontSettings::default()) - .unwrap(), - cache: FontCache::new(texture_size), - } - } - - /// Adds all of the common known characters. - pub fn add_all_common(&mut self) { - let chars = vec![ - '`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '~', '!', '@', '#', - '$', '%', '^', '&', '*', '(', ')', '_', '+', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', '\\', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', - '|', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'A', 'S', 'D', 'F', 'G', - 'H', 'J', 'K', 'L', ':', '"', 'z', 'x', 'c', 'v', 'b', 'n', 'n', 'm', ',', '.', '/', - 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', - ]; - - for char in chars { - self.add_character(char); - } - } - - pub fn get_layout( - &self, - content: &String, - font_size: f32, - original_font_size: f32, - max_glyph_size: (f32, f32), - ) -> Vec<(char, (f32, f32), (f32, f32))> { - let mut layout = - fontdue::layout::Layout::new(fontdue::layout::CoordinateSystem::PositiveYDown); - layout.append( - &[&self.font], - &fontdue::layout::TextStyle::new(content, font_size, 0), - ); - let font_ratio = font_size / original_font_size; - let resized_max_glyph_size = ( - (max_glyph_size.0 * font_ratio).round(), - (max_glyph_size.1 * font_ratio).round(), - ); - - let glyphs = layout.glyphs(); - let glyphs: Vec<_> = glyphs - .iter() - .filter_map(|glyph_position| { - if glyph_position.parent == ' ' { - return None; - } - // let metrics = self.font.metrics(glyph_position.parent, font_size); - - let shift_y = resized_max_glyph_size.1 - glyph_position.height as f32; - Some(( - glyph_position.parent, - (glyph_position.x, glyph_position.y - shift_y), - resized_max_glyph_size, - )) - }) - .collect(); - glyphs - } - - // pub fn get_size(&self, c: char, font_size: f32) -> (f32, f32) { - // if let Some(glyph) = self.internal_face.glyph_index(c) { - // // Collect our path's from the glyph's outline shape. - // let mut path_collector = PathCollector::new(); - // let rect = self - // .internal_face - // .outline_glyph(glyph, &mut path_collector) - // .unwrap(); - // let metrics = font_size / self.font.units_per_em(); - - // (width as f32 * metrics, height as f32 * metrics) - // } else { - // panic!("") - // } - // } - - pub fn get_char_id(&self, c: char) -> usize { - if self.cache.has_character(c) { - if let Some((id, _)) = self.cache.chars.get(&c) { - return *id; - } +impl KayakFont { + pub fn new(sdf: Sdf, atlas_image: Handle<Image>) -> Self { + Self { + sdf, + atlas_image, + char_ids: HashMap::default(), } - panic!("No char found!"); } - pub fn add_character(&mut self, c: char) { - if !self.cache.has_character(c) { - if let Some(glyph) = self.internal_face.glyph_index(c) { - // Collect our path's from the glyph's outline shape. - let mut path_collector = PathCollector::new(); - let rect = self - .internal_face - .outline_glyph(glyph, &mut path_collector) - .unwrap(); - let contours = path_collector.build(); - - // Bounds of our texture in UV's - // TODO: Allow this to change because some people may want texture atlases instead. - let uv_rect = Rect::new(Point::new(0.0, 0.0), Size::new(1.0, 1.0)); - - // Bounds of our rect in font space coords. - let font_rect = Rect::new( - Point::new(rect.x_min as f32, rect.y_min as f32), - Size::new(rect.width() as f32, rect.height() as f32), - ); - - let (contours, _transform) = rescale_contours( - contours, - font_rect, - uv_rect, - self.internal_face.units_per_em(), - ); - let contours = recolor_contours(contours, Angle::degrees(3.0), 1); - let msdf = compute_msdf(&contours, self.cache.get_dimensions().0 as usize); - - self.cache.set_texture(c, msdf); - } + pub fn generate_char_ids(&mut self) { + let mut count = 0; + for glyph in self.sdf.glyphs.iter() { + self.char_ids.insert(glyph.unicode, count); + count += 1; } } - pub fn get_data_to_process<'b>(&'b mut self) -> Vec<(char, usize, &'b Vec<u8>)> { - let data = self - .cache - .needs_processing - .iter() - .filter_map(|unprocessed_id| { - if let Some(c) = self.cache.id_to_char_mappings.get(unprocessed_id) { - if let Some((_, data)) = self.cache.chars.get(c) { - return Some((*c, *unprocessed_id, data)); - } - } - - None - }) - .collect(); - - self.cache.needs_processing.clear(); - - data + pub fn get_char_id(&self, c: char) -> Option<u32> { + self.char_ids.get(&c).and_then(|id| Some(*id)) } - - // Checks the given chars and returns ones that haven't been seen before. - pub fn check_chars(&self, chars: std::str::Chars<'_>) -> Vec<char> { - chars - .into_iter() - .filter(|c| !self.cache.chars.contains_key(&c)) - .collect() - } - - pub fn units_per_em(&self) -> f32 { - self.font.units_per_em() - } -} - -fn get_new_size(org_width: f32, new_width: f32, org_height: f32, new_height: f32) -> (f32, f32) { - let ratio = calculate_ratio(org_width, new_width, org_height, new_height); - // let ratio = new_width / new_height; - (org_width * ratio, org_height * ratio) -} - -pub fn calculate_ratio(org_width: f32, new_width: f32, org_height: f32, new_height: f32) -> f32 { - let area_size; - let image_size; - - if new_height * org_width > new_width * org_height { - area_size = new_height; - image_size = org_height; - } else { - area_size = new_width; - image_size = org_width; - } - - let ratio = area_size / image_size; - ratio } diff --git a/bevy_kayak_ui/src/render/unified/font/sdf/glyph.rs b/kayak_font/src/glyph.rs similarity index 100% rename from bevy_kayak_ui/src/render/unified/font/sdf/glyph.rs rename to kayak_font/src/glyph.rs diff --git a/kayak_font/src/lib.rs b/kayak_font/src/lib.rs index 6a97d016cc79e585a2677afe72f921e420481919..3ffc49344dfbaccbf3cc3b7d34e8d43d20cbc774 100644 --- a/kayak_font/src/lib.rs +++ b/kayak_font/src/lib.rs @@ -1,28 +1,14 @@ -#![allow(dead_code)] -mod color_flags; -mod contour; +mod atlas; mod font; -mod msdf; -mod path_collector; -mod path_element; -mod recolor; +mod glyph; +mod metrics; +mod renderer; mod sdf; -mod ttf_parser; -mod utils; -pub use color_flags::ColorFlags; -pub use contour::{rescale_contours, Contour}; -pub use font::{Font, FontCache}; -pub use lyon_geom::math::{Angle, Point, Rect, Vector}; -pub use lyon_path::builder::FlatPathBuilder; -pub use msdf::compute_msdf; -pub use path_collector::PathCollector; -pub use path_element::PathElement; -pub use recolor::recolor_contours; -pub use sdf::compute_sdf; +pub use atlas::*; +pub use font::*; +pub use glyph::*; +pub use metrics::*; +pub use sdf::*; -pub(crate) fn median(a: f32, b: f32, c: f32) -> f32 { - let min = |a: f32, b: f32| a.min(b); - let max = |a: f32, b: f32| a.max(b); - max(min(a, b), min(max(a, b), c)) -} +pub use renderer::*; diff --git a/bevy_kayak_ui/src/render/unified/font/sdf/metrics.rs b/kayak_font/src/metrics.rs similarity index 100% rename from bevy_kayak_ui/src/render/unified/font/sdf/metrics.rs rename to kayak_font/src/metrics.rs diff --git a/kayak_font/src/msdf.rs b/kayak_font/src/msdf.rs deleted file mode 100644 index 8429e93d4e4fa611b56a998517245cd3676abb84..0000000000000000000000000000000000000000 --- a/kayak_font/src/msdf.rs +++ /dev/null @@ -1,171 +0,0 @@ -use lyon_geom::math::Vector; - -use crate::{contour::Contour, median, utils::EdgeDistance, ColorFlags}; - -/// Computes an MSDF from a list of contours. The returned vectors are a `dim` by `dim` -/// matrix of signed distance values. The output represents the signed distances to the contours -/// within [0, 1] x [0, 1] -pub fn compute_msdf(contours: &[Contour], dim: usize) -> Vec<Vec<(f32, f32, f32)>> { - #[derive(Copy, Clone, PartialEq)] - struct MultiDistance { - r: f32, - g: f32, - b: f32, - med: f32, - } - impl MultiDistance { - fn new(v: f32) -> Self { - Self { - r: v, - g: v, - b: v, - med: v, - } - } - } - let scale: f32 = 1.0 / (dim as f32); - let windings: Vec<i32> = contours.iter().map(|c| c.winding() as i32).collect(); - - (0..dim) - .map(|y| { - let py = (y as f32 + 0.5) * scale; - (0..dim) - .map(|x| { - // We assume there is at least 1 contour - // If there isn't make everything magenta - if contours.len() == 0 { - return (1.0f32, 0.0, 1.0); - } - - let px = (x as f32 + 0.5) * scale; - let p = Vector::new(px, py); - - let mut neg_dist = 1e24f32; - let mut pos_dist = -1e24f32; - let mut d = 1e24f32; - let mut winding = 0; - let mut contour_distances = Vec::new(); - contour_distances.reserve(contours.len()); - - let mut sr = EdgeDistance::new(); - let mut sg = EdgeDistance::new(); - let mut sb = EdgeDistance::new(); - - for (i, contour) in contours.iter().enumerate() { - let mut contour_min_r = EdgeDistance::new(); - let mut contour_min_g = EdgeDistance::new(); - let mut contour_min_b = EdgeDistance::new(); - - for elem in &contour.elements { - let (d, na) = elem.distance(p.to_point()); - - if elem.color.contains(ColorFlags::RED) && d < contour_min_r.dist { - contour_min_r.dist = d; - contour_min_r.edge = Some(&elem); - contour_min_r.nearest_approach = na; - } - if elem.color.contains(ColorFlags::GREEN) && d < contour_min_g.dist { - contour_min_g.dist = d; - contour_min_g.edge = Some(&elem); - contour_min_g.nearest_approach = na; - } - if elem.color.contains(ColorFlags::BLUE) && d < contour_min_b.dist { - contour_min_b.dist = d; - contour_min_b.edge = Some(&elem); - contour_min_b.nearest_approach = na; - } - } - - if contour_min_r.dist < sr.dist { - sr = contour_min_r; - } - if contour_min_g.dist < sg.dist { - sg = contour_min_g; - } - if contour_min_b.dist < sb.dist { - sb = contour_min_b; - } - - let med_min_dist = median( - contour_min_r.dist.distance, - contour_min_g.dist.distance, - contour_min_b.dist.distance, - ) - .abs(); - if med_min_dist < d { - d = med_min_dist; - winding = -windings[i]; - } - - contour_min_r.to_pseudodistance(p); - contour_min_g.to_pseudodistance(p); - contour_min_b.to_pseudodistance(p); - - let med_min_dist = median( - contour_min_r.dist.distance, - contour_min_g.dist.distance, - contour_min_b.dist.distance, - ); - - let mut msd = MultiDistance::new(med_min_dist); - msd.r = contour_min_r.dist.distance; - msd.g = contour_min_g.dist.distance; - msd.b = contour_min_b.dist.distance; - msd.med = med_min_dist; - contour_distances.push(msd); - if windings[i] > 0 - && med_min_dist >= 0.0 - && med_min_dist.abs() < pos_dist.abs() - { - pos_dist = med_min_dist; - } - if windings[i] < 0 - && med_min_dist <= 0.0 - && med_min_dist.abs() < neg_dist.abs() - { - neg_dist = med_min_dist; - } - } - - assert!(contour_distances.len() == windings.len()); - - sr.to_pseudodistance(p); - sg.to_pseudodistance(p); - sb.to_pseudodistance(p); - - let mut mmsd = MultiDistance::new(-1e24); - if pos_dist >= 0.0 && pos_dist.abs() <= neg_dist.abs() { - mmsd.med = -1e24; - winding = 1; - for (csd, cw) in contour_distances.iter().zip(windings.iter()) { - if *cw > 0 && csd.med > mmsd.med && csd.med.abs() < neg_dist.abs() { - mmsd = *csd; - } - } - } else if neg_dist <= 0.0 && neg_dist.abs() <= pos_dist.abs() { - mmsd.med = 1e24; - winding = -1; - for (csd, cw) in contour_distances.iter().zip(windings.iter()) { - if *cw < 0 && csd.med < mmsd.med && csd.med.abs() < pos_dist.abs() { - mmsd = *csd; - } - } - } - for (csd, w) in contour_distances.iter().zip(windings.iter()) { - if *w != winding && csd.med.abs() < mmsd.med.abs() { - mmsd = *csd; - } - } - - if median(sr.dist.distance, sg.dist.distance, sb.dist.distance) == mmsd.med { - mmsd.r = sr.dist.distance; - mmsd.g = sg.dist.distance; - mmsd.b = sb.dist.distance; - } - - (mmsd.r / 0.5, mmsd.g / 0.5, mmsd.b / 0.5) - }) - .collect() - }) - .collect() -} diff --git a/kayak_font/src/path_collector.rs b/kayak_font/src/path_collector.rs deleted file mode 100644 index 077bc44911cf62a3f6db4483a20852c31a446495..0000000000000000000000000000000000000000 --- a/kayak_font/src/path_collector.rs +++ /dev/null @@ -1,134 +0,0 @@ -use lyon_geom::math::{Angle, Point, Vector}; -use lyon_path::{ - builder::{FlatPathBuilder, PathBuilder}, - Segment, -}; - -use crate::{color_flags::ColorFlags, contour::Contour, path_element::PathElement}; - -/// This is a path collector which produces our custom contour type. -pub struct PathCollector { - /// The start point of the last contour - pub(crate) contour_start: Point, - /// The current pen location - pub(crate) pen: Point, - /// in-flight path elements - pub(crate) elements: Vec<PathElement>, - /// Completed contours - pub(crate) contours: Vec<Contour>, - pub scale: f32, -} - -impl PathCollector { - pub fn new() -> Self { - Self { - contour_start: Point::new(0.0, 0.0), - pen: Point::new(0.0, 0.0), - elements: Vec::new(), - contours: Vec::new(), - scale: 1.0, - } - } -} - -impl PathBuilder for PathCollector { - fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) { - self.elements.push(PathElement::new( - Segment::Quadratic(lyon_geom::QuadraticBezierSegment { - from: self.pen * self.scale, - to: to * self.scale, - ctrl: ctrl * self.scale, - }), - ColorFlags::WHITE, - )); - self.pen = to; - } - - fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) { - self.elements.push(PathElement::new( - Segment::Cubic(lyon_geom::CubicBezierSegment { - from: self.pen * self.scale, - to: to * self.scale, - ctrl1: ctrl1 * self.scale, - ctrl2: ctrl2 * self.scale, - }), - ColorFlags::WHITE, - )); - - self.pen = to; - } - - fn arc(&mut self, _center: Point, _radii: Vector, _sweep_angle: Angle, _x_rotation: Angle) { - unimplemented!() - } -} - -impl FlatPathBuilder for PathCollector { - type PathType = Vec<Contour>; - - fn move_to(&mut self, to: Point) { - self.pen = to * self.scale; - self.contour_start = to * self.scale; - } - - fn line_to(&mut self, to: Point) { - self.elements.push(PathElement::new( - Segment::Line(lyon_geom::LineSegment { - from: self.pen * self.scale, - to: to * self.scale, - }), - ColorFlags::WHITE, - )); - self.pen = to * self.scale; - } - - fn close(&mut self) { - if (self.pen - self.contour_start).length() > 1E-14 { - self.elements.push(PathElement::new( - Segment::Line(lyon_geom::LineSegment { - from: self.pen * self.scale, - to: self.contour_start * self.scale, - }), - ColorFlags::WHITE, - )); - } - - self.pen = self.contour_start; - let elements = std::mem::replace(&mut self.elements, Vec::new()); - - self.contours.push(Contour { elements }); - } - - fn build(self) -> Self::PathType { - let mut contours = self.contours; - if self.elements.len() > 0 { - let final_contour = Contour { - elements: self.elements, - }; - - contours.push(final_contour); - } - - contours - } - - fn build_and_reset(&mut self) -> Self::PathType { - let elements = std::mem::replace(&mut self.elements, Vec::new()); - if elements.len() > 0 { - let final_contour = Contour { elements }; - - self.contours.push(final_contour); - } - - let tr = std::mem::replace(&mut self.contours, Vec::new()); - - self.contour_start = Point::new(0.0, 0.0); - self.pen = Point::new(0.0, 0.0); - - tr - } - - fn current_position(&self) -> Point { - self.pen - } -} diff --git a/kayak_font/src/path_element.rs b/kayak_font/src/path_element.rs deleted file mode 100644 index 7500fccbbf88b412570d39a17ab2517b3c213e20..0000000000000000000000000000000000000000 --- a/kayak_font/src/path_element.rs +++ /dev/null @@ -1,191 +0,0 @@ -use crate::{color_flags::ColorFlags, utils::AugmentedDistance}; -use lyon_geom::math::{Point, Vector}; -use lyon_path::Segment; - -#[derive(Clone, Debug, Copy)] -pub struct PathElement { - pub segment: Segment, - pub color: ColorFlags, -} - -impl PathElement { - pub fn new(segment: Segment, color: ColorFlags) -> PathElement { - Self { segment, color } - } - - pub fn sample(&self, t: f32) -> Point { - match self.segment { - Segment::Line(s) => s.sample(t), - Segment::Quadratic(s) => s.sample(t), - Segment::Cubic(s) => s.sample(t), - Segment::Arc(s) => s.sample(t), - } - } - - pub fn direction(&self, f: f32) -> Vector { - use lyon_geom::Segment as SegmentTrait; - let f = f.min(1.0).max(0.0); - match self.segment { - Segment::Line(s) => s.derivative(f), - Segment::Quadratic(s) => s.derivative(f), - Segment::Cubic(s) => s.derivative(f), - Segment::Arc(s) => s.derivative(f), - } - } - - /// Split a path element into 3rds - pub fn split_in_thirds(&self) -> [PathElement; 3] { - macro_rules! segment_case { - ($i:expr, $s:expr) => {{ - let (a, b) = ($i).split(1.0 / 3.0); - let (b, c) = b.split(1.0 / 2.0); - - [a, b, c] - .into_iter() - .map(|x| PathElement::new(($s)(x), self.color)) - .collect() - }}; - } - let segments: arrayvec::ArrayVec<PathElement, 3> = match self.segment { - Segment::Line(s) => segment_case!(s, Segment::Line), - Segment::Quadratic(s) => segment_case!(s, Segment::Quadratic), - Segment::Cubic(s) => segment_case!(s, Segment::Cubic), - Segment::Arc(s) => segment_case!(s, Segment::Arc), - }; - - segments - .into_inner() - .expect("We should have precisely the right capacity") - } - - /// Computes the distance from p to this path element - /// Returns the distance from the point to this path element, - /// and the distance along this element to the closest point. - pub fn distance(&self, p: Point) -> (AugmentedDistance, f32) { - use lyon_geom::{LineSegment, QuadraticBezierSegment}; - match self.segment { - Segment::Line(LineSegment { from: s, to: e }) => { - let aq = p - s; - let ab = e - s; - let f = aq.dot(ab) / ab.dot(ab); - let eq = if f >= 0.5 { p - e } else { p - s }; - - let dist_to_endpoint = eq.length(); - let endpoint_sd = AugmentedDistance::new( - aq.cross(ab).signum() * dist_to_endpoint, - // ab.normalize().cross(eq.normalize()), - ab.normalize().dot(eq.normalize()).abs(), - ); - - if 0.0 < f && f < 1.0 { - let ortho = Vector::new(ab.y, -ab.x).normalize(); - let ortho_dist = ortho.dot(aq); - if ortho_dist.abs() < endpoint_sd.distance.abs() { - (AugmentedDistance::new(ortho_dist, 0.0), f) - } else { - (endpoint_sd, f) - } - } else { - (endpoint_sd, f) - } - } - - Segment::Quadratic(QuadraticBezierSegment { - from: p0, - ctrl: p1, - to: p2, - }) => { - use lyon_geom::utils::cubic_polynomial_roots; - let qa = p0 - p; - let ab = p1 - p0; - let br = (p0 - p1) + (p2 - p1); - let a = br.dot(br); - let b = 3.0 * ab.dot(br); - let c = 2.0 * ab.dot(ab) + qa.dot(br); - let d = qa.dot(ab); - let solutions = cubic_polynomial_roots(a, b, c, d); - - let mut min_dist = ab.cross(qa).signum() * qa.length(); - - let mut f = -qa.dot(ab) / ab.dot(ab); - { - let ec = p2 - p1; - let ep = p2 - p; - let dist = ec.cross(ep).signum() * ep.length(); - if dist.abs() < min_dist.abs() { - min_dist = dist; - f = (p - p1).dot(ec) / ec.dot(ec); - } - } - for t in solutions { - if t <= 0.0 || 1.0 <= t { - continue; - } - let endpoint = p0 + (ab * 2.0 * t) + (br * t * t); - let delta = endpoint - p; - let dist = (p2 - p0).cross(delta).signum() * delta.length(); - - if dist.abs() < min_dist.abs() { - min_dist = dist; - f = t; - } - } - - if 0.0 <= f && f <= 1.0 { - (AugmentedDistance::new(min_dist, 0.0), f) - // (AugmentedDistance::new(200f32, 0.0), f) - } else if f < 0.5 { - ( - AugmentedDistance::new(min_dist, ab.normalize().dot(qa.normalize()).abs()), - f, - ) - } else { - ( - AugmentedDistance::new( - min_dist, - (p2 - p1).normalize().dot((p2 - p).normalize()).abs(), - ), - f, - ) - } - } - - _ => unimplemented!(), - } - } - - pub(crate) fn to_psuedodistance( - &self, - dist: AugmentedDistance, - p: Vector, - near: f32, - ) -> AugmentedDistance { - if near <= 0.0 { - let dir = self.direction(0.0).normalize(); - let aq = p - self.sample(0.0).to_vector(); - let ts = aq.dot(dir); - if ts < 0.0 { - let ds = aq.cross(dir); - if ds.abs() <= dist.distance.abs() { - return AugmentedDistance::new(ds, 0.0); - } - } - - dist - } else if near >= 1.0 { - let dir = self.direction(1.0).normalize(); - let aq = p - self.sample(1.0).to_vector(); - let ts = aq.dot(dir); - if ts > 0.0 { - let ds = aq.cross(dir); - if ds.abs() <= dist.distance.abs() { - return AugmentedDistance::new(ds, 0.0); - } - } - - dist - } else { - dist - } - } -} diff --git a/kayak_font/src/recolor.rs b/kayak_font/src/recolor.rs deleted file mode 100644 index 61cbbe89dea590befa760dc7b36d9ea46451a277..0000000000000000000000000000000000000000 --- a/kayak_font/src/recolor.rs +++ /dev/null @@ -1,124 +0,0 @@ -use lyon_geom::math::{Angle, Vector}; - -use crate::contour::Contour; -use crate::ColorFlags; - -/// Recolor the contours prior to MSDF computation. -/// This function uses a simple technique, -/// again based on Viktor's implementation. -/// It is left as a separate step so you can implement more complex techniques as desired. -pub fn recolor_contours(contours: Vec<Contour>, threshold: Angle, mut seed: u64) -> Vec<Contour> { - let (threshold, _) = threshold.sin_cos(); - - // Determine if a point is a corner, assuming i and o are incoming and - // outgoing normalized direction vectors - let is_corner = |i: Vector, o: Vector| { - let d = i.dot(o); /* |i| |o| cos(t) */ - let c = i.cross(o).abs(); /* |i| |o| sin(t) */ - - // if this corner turns more than 90 degrees (detected by dot product/cos) - // or if it turns more than the threshold angle (detected by cross product/sin) - (d <= 0.0) || (c > threshold) - }; - contours - .into_iter() - .map(|mut c| { - let mut corners = Vec::new(); - let n = c.elements.len(); - // Find all the corners - if n != 0 { - let mut prev_dir = c.elements[n - 1].direction(1.0).normalize(); - for (i, e) in c.elements.iter().enumerate() { - let c_dir = e.direction(0.0).normalize(); - if is_corner(prev_dir, c_dir) { - corners.push(i) - } - prev_dir = e.direction(1.0).normalize(); - } - } - - match corners.len() { - 0 => { - // The whole contour is smooth, and we initialized all colors to white. - // No work to do - c - } - 1 => { - // "Teardrop" case: there is only one sharp corner so we - // just pick 3 colors up front and cycle through them - let mut colors = [ - (ColorFlags::WHITE).switch(&mut seed), - ColorFlags::WHITE, - ColorFlags::WHITE, - ]; - colors[1] = colors[0].switch(&mut seed); - colors[2] = colors[1].switch(&mut seed); - let corner = corners[0]; - match n { - 0 => { - unreachable!(); - } - 1 => { - // Only a single edge segment, but it's a teardrop. - // We split it in 3 to make the colors happen - let mut split = c.elements[0].split_in_thirds(); - split[0].color = colors[0]; - split[1].color = colors[1]; - split[2].color = colors[2]; - - c.elements.clear(); - c.elements.extend_from_slice(&split); - } - 2 => { - // 2 segments. We split it into 6, and assign colors by hand - let mut split0 = c.elements[0].split_in_thirds(); - let mut split1 = c.elements[1].split_in_thirds(); - split0[0].color = colors[0]; - split0[1].color = colors[0]; - split0[2].color = colors[1]; - split1[0].color = colors[1]; - split1[1].color = colors[2]; - split1[2].color = colors[2]; - - c.elements.clear(); - c.elements.extend_from_slice(&split0); - c.elements.extend_from_slice(&split1); - } - _ => { - // We have more than 3 edges to rotate colors through - for (i, e) in c.elements.iter_mut().enumerate() { - // ported from this cursed C++ code: - // contour->edges[(corner+i)%m]->color = (colors+1)[int(3+2.875*i/(m-1)-1.4375+.5)-3]; - let i = (n + i - corner) % n; // Emulate the ( corner + i) % m - let idx_fractional = - 3.5f32 + 2.875f32 * (i as f32) / ((n - 1) as f32) - 1.4375f32; - let idx = idx_fractional.floor() as usize - 2; - e.color = colors[idx]; - } - } - } - c - } - _ => { - // We have 2 or more corners - // Cycle through colors, switching whenever we hit another corner - let n_corners = corners.len(); - let mut spline = 0; - let start = corners[0]; - let mut color = ColorFlags::WHITE; - color = color.switch(&mut seed); - let initial_color = color; - for i in 0..n { - let i = (start + i) % n; - if spline + 1 < n_corners && corners[spline + 1] == i { - spline = spline + 1; - color = color.switch_banned(&mut seed, initial_color); - } - c.elements[i].color = color; - } - c - } - } - }) - .collect() -} diff --git a/bevy_kayak_ui/src/render/unified/font/font_texture_cache.rs b/kayak_font/src/renderer/font_texture_cache.rs similarity index 94% rename from bevy_kayak_ui/src/render/unified/font/font_texture_cache.rs rename to kayak_font/src/renderer/font_texture_cache.rs index e195c2b6b5bdaad8c3e43c8b64e1bc30fcb29b27..e170a25c29476f68ef7b7ec1b77e0fe46b2e272b 100644 --- a/bevy_kayak_ui/src/render/unified/font/font_texture_cache.rs +++ b/kayak_font/src/renderer/font_texture_cache.rs @@ -1,3 +1,4 @@ +use crate::{KayakFont, Sdf}; use bevy::{ math::Vec2, prelude::{Handle, Res}, @@ -16,9 +17,9 @@ use bevy::{ utils::HashMap, }; -use crate::render::unified::pipeline::UnifiedPipeline; - -use super::{font::KayakFont, sdf::Sdf}; +pub trait FontRenderingPipeline { + fn get_font_image_layout(&self) -> &BindGroupLayout; +} pub const MAX_CHARACTERS: u32 = 100; @@ -59,11 +60,15 @@ impl FontTextureCache { } } - pub fn process_new( + pub fn get_binding(&self, handle: &Handle<KayakFont>) -> Option<&BindGroup> { + self.bind_groups.get(handle) + } + + pub fn process_new<T: FontRenderingPipeline>( &mut self, device: &RenderDevice, queue: &RenderQueue, - pipeline: &UnifiedPipeline, + pipeline: &T, render_images: &Res<RenderAssets<Image>>, ) { let new_fonts: Vec<_> = self.new_fonts.drain(..).collect(); @@ -151,10 +156,7 @@ impl FontTextureCache { images.insert(font_handle, image); } - pub fn get_empty( - device: &RenderDevice, - image_layout: &BindGroupLayout, - ) -> (GpuImage, BindGroup) { + pub fn get_empty(device: &RenderDevice, layout: &BindGroupLayout) -> (GpuImage, BindGroup) { let texture_descriptor = TextureDescriptor { label: Some("font_texture_array"), size: Extent3d { @@ -203,20 +205,20 @@ impl FontTextureCache { resource: BindingResource::Sampler(&image.sampler), }, ], - layout: image_layout, + layout, }); (image, binding) } - pub fn create_from_atlas( + pub fn create_from_atlas<T: FontRenderingPipeline>( images: &mut HashMap<Handle<KayakFont>, GpuImage>, bind_groups: &mut HashMap<Handle<KayakFont>, BindGroup>, sdf: &Sdf, font_handle: Handle<KayakFont>, device: &RenderDevice, queue: &RenderQueue, - pipeline: &UnifiedPipeline, + pipeline: &T, atlas_texture: &GpuImage, size: Vec2, ) { @@ -247,7 +249,7 @@ impl FontTextureCache { resource: BindingResource::Sampler(&gpu_image.sampler), }, ], - layout: &pipeline.font_image_layout, + layout: &pipeline.get_font_image_layout(), }); bind_groups.insert(font_handle.clone_weak(), binding); diff --git a/kayak_font/src/renderer/mod.rs b/kayak_font/src/renderer/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..43732619d4845bbe63ba467d5669ca5ab882b029 --- /dev/null +++ b/kayak_font/src/renderer/mod.rs @@ -0,0 +1,2 @@ +mod font_texture_cache; +pub use font_texture_cache::*; diff --git a/kayak_font/src/sdf.rs b/kayak_font/src/sdf.rs index c1cd976de29931814a94af5857e10d47bbf65f0a..129efb18840e32148c6aa85973249ba62b5a6434 100644 --- a/kayak_font/src/sdf.rs +++ b/kayak_font/src/sdf.rs @@ -1,87 +1,61 @@ -use lyon_geom::math::Vector; - -use crate::{contour::Contour, utils::EdgeDistance}; - -/// Computes a SDF from a list of contours. The returned vectors are a `dim` by `dim` -/// matrix of signed distances. The output represents the signed distances to the contours -/// within [0, 1] x [0, 1] -pub fn compute_sdf(contours: &[Contour], dim: usize) -> Vec<Vec<f32>> { - let scale: f32 = 1.0 / (dim as f32); - let windings: Vec<i32> = contours.iter().map(|c| c.winding() as i32).collect(); - - (0..dim) - .map(|y| { - let py = (y as f32 + 0.5) * scale; - (0..dim) - .map(|x| { - if contours.len() == 0 { - return 1.0f32; - } - - let px = (x as f32 + 0.5) * scale; - let p = Vector::new(px, py); - - let mut neg_dist = 1e24f32; - let mut pos_dist = -1e24f32; - let mut winding = 0; - let mut contour_distances = Vec::new(); - contour_distances.reserve(contours.len()); - - for (i, contour) in contours.iter().enumerate() { - let mut contour_min = EdgeDistance::new(); - - for elem in contour.elements.iter() { - let (d, na) = elem.distance(p.to_point()); - - if d < contour_min.dist { - contour_min.dist = d; - contour_min.edge = Some(&elem); - contour_min.nearest_approach = na; - } - } - - // contour_min.to_pseudodistance(p); - let cmdd = contour_min.dist.distance; - - contour_distances.push(cmdd); - - if windings[i] > 0 && cmdd >= 0.0 && cmdd.abs() < pos_dist.abs() { - pos_dist = cmdd; - } - if windings[i] < 0 && cmdd <= 0.0 && cmdd.abs() < neg_dist.abs() { - neg_dist = cmdd; - } - } +use crate::{atlas::Atlas, glyph::Glyph, metrics::Metrics, SDFType}; +use bevy::math::Vec2; +use serde::Deserialize; + +#[derive(Deserialize, Debug, Clone)] +pub struct Sdf { + pub atlas: Atlas, + metrics: Metrics, + pub glyphs: Vec<Glyph>, + kerning: Vec<KerningData>, +} - assert!(contour_distances.len() == windings.len()); +#[derive(serde::Deserialize, Debug, Clone, Copy)] +pub struct KerningData { + pub unicode1: u32, + pub unicode2: u32, + pub advance: f32, +} - let mut md = -1e24; - if pos_dist >= 0.0 && pos_dist.abs() <= neg_dist.abs() { - md = pos_dist; - winding = 1; - for (d, w) in contour_distances.iter().zip(windings.iter()) { - if *w > 0 && *d > md && d.abs() < neg_dist.abs() { - md = *d; - } - } - } else if neg_dist <= 0.0 && neg_dist.abs() <= pos_dist.abs() { - md = neg_dist; - winding = -1; - for (d, w) in contour_distances.iter().zip(windings.iter()) { - if *w < 0 && *d < md && d.abs() < pos_dist.abs() { - md = *d; - } - } - } - for (c, w) in contour_distances.iter().zip(windings.iter()) { - if *w != winding && c.abs() < md.abs() { - md = *c; - } - } +impl Sdf { + pub fn from_string(data: String) -> Sdf { + let value: Sdf = match serde_path_to_error::deserialize( + &mut serde_json::Deserializer::from_str(&data), + ) { + Ok(v) => v, + Err(err) => { + let path = err.path().to_string(); + dbg!(err); + panic!("failed to deserialize json! path: {}", path); + } + }; + + value + } + + pub fn max_glyph_size(&self) -> Vec2 { + let mut size = Vec2::new(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.y > size.y { + size.y = atlas_size.y; + } + } + }); + + size + } +} - md / 0.5 - }) - .collect() - }) - .collect() +#[test] +fn test_sdf_loader() { + let sdf = Sdf::from_string(include_str!("../assets/roboto.json").to_string()); + assert!(sdf.max_glyph_size() == Vec2::new(30.0, 36.0)); + assert!(sdf.atlas.width == 212); + assert!(sdf.atlas.height == 212); + assert!(matches!(sdf.atlas.sdf_type, SDFType::Msdf)); } diff --git a/kayak_font/src/ttf_parser.rs b/kayak_font/src/ttf_parser.rs deleted file mode 100644 index 4c8607ca5ee2ae16ae07e9ac8914d18bbb59a615..0000000000000000000000000000000000000000 --- a/kayak_font/src/ttf_parser.rs +++ /dev/null @@ -1,69 +0,0 @@ -use lyon_geom::math::Point; -use lyon_path::Segment; - -use crate::{ColorFlags, Contour, PathCollector, PathElement}; - -impl ttf_parser::OutlineBuilder for PathCollector { - fn move_to(&mut self, x: f32, y: f32) { - let to = Point::new(x, y); - self.pen = to; - self.contour_start = to; - } - - fn line_to(&mut self, x: f32, y: f32) { - let to = Point::new(x, y) * self.scale; - self.elements.push(PathElement::new( - Segment::Line(lyon_geom::LineSegment { from: self.pen, to }), - ColorFlags::WHITE, - )); - self.pen = to; - } - - fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) { - let ctrl = Point::new(x1, y1) * self.scale; - let to = Point::new(x, y) * self.scale; - self.elements.push(PathElement::new( - Segment::Quadratic(lyon_geom::QuadraticBezierSegment { - from: self.pen, - to, - ctrl, - }), - ColorFlags::WHITE, - )); - self.pen = to; - } - - fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) { - let ctrl1 = Point::new(x1, y1) * self.scale; - let ctrl2 = Point::new(x2, y2) * self.scale; - let to = Point::new(x, y) * self.scale; - self.elements.push(PathElement::new( - Segment::Cubic(lyon_geom::CubicBezierSegment { - from: self.pen, - to, - ctrl1, - ctrl2, - }), - ColorFlags::WHITE, - )); - - self.pen = to; - } - - fn close(&mut self) { - if (self.pen - self.contour_start).length() > 1E-14 { - self.elements.push(PathElement::new( - Segment::Line(lyon_geom::LineSegment { - from: self.pen * self.scale, - to: self.contour_start * self.scale, - }), - ColorFlags::WHITE, - )); - } - - self.pen = self.contour_start; - let elements = std::mem::replace(&mut self.elements, Vec::new()); - - self.contours.push(Contour { elements }); - } -} diff --git a/kayak_font/src/utils.rs b/kayak_font/src/utils.rs deleted file mode 100644 index 5e8e35fc6e0a8cbc7f0da38abb0c571a0039a86c..0000000000000000000000000000000000000000 --- a/kayak_font/src/utils.rs +++ /dev/null @@ -1,61 +0,0 @@ -use lyon_path::math::Vector; - -use crate::path_element::PathElement; - -/// Represents a distance to an edge segment -#[derive(Copy, Clone)] -pub(crate) struct EdgeDistance<'a> { - pub(crate) dist: AugmentedDistance, - pub(crate) edge: Option<&'a PathElement>, - pub(crate) nearest_approach: f32, -} - -impl<'a> EdgeDistance<'a> { - /// Create a new edge point, initialized to infinite distance - pub(crate) fn new() -> Self { - Self { - dist: AugmentedDistance::new(-1e24, 0.0), - edge: None, - nearest_approach: 0.0, - } - } - - pub(crate) fn to_pseudodistance(&mut self, p: Vector) { - match self.edge { - Some(edge) => self.dist = edge.to_psuedodistance(self.dist, p, self.nearest_approach), - None => {} - } - } -} - -/// A signed distance, augmented with the cosine of the angle -/// between the tangent of the edge and the vector from the -/// point of nearest approach to the measured point. -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct AugmentedDistance { - /// The actual distance - pub(crate) distance: f32, - /// The cosine of the angle between the tangent vector of the path segment - /// at the point of closest approach and the vector from the point of - /// closest approach to the point to which distance was measured. This is used to - dot: f32, -} - -impl AugmentedDistance { - pub(crate) fn new(distance: f32, dot: f32) -> Self { - Self { distance, dot } - } -} - -impl std::cmp::PartialOrd for AugmentedDistance { - fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { - use std::cmp::Ordering; - - match self.distance.abs().partial_cmp(&other.distance.abs()) { - Some(Ordering::Less) => Some(Ordering::Less), - Some(Ordering::Greater) => Some(Ordering::Greater), - Some(Ordering::Equal) => self.dot.partial_cmp(&other.dot), - None => None, - } - } -}