diff --git a/kayak_font/Cargo.toml b/kayak_font/Cargo.toml index b34b8f34c20329eb311955a7ad43dc325636c27c..428924f199a59dbf75fd363ea6b939b38f549c14 100644 --- a/kayak_font/Cargo.toml +++ b/kayak_font/Cargo.toml @@ -3,18 +3,13 @@ name = "kayak_font" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [features] default = ["bevy_renderer"] bevy_renderer = ["bevy"] [dependencies] anyhow = { version = "1.0" } -bytemuck = "1.7.2" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -serde_path_to_error = "0.1" +nanoserde = "0.1.30" unicode-segmentation = "1.9" # Provides UAX #14 line break segmentation @@ -22,7 +17,6 @@ xi-unicode = "0.3" [dependencies.bevy] version = "0.8.0" -git = "https://github.com/bevyengine/bevy.git" optional = true default-features = false features = [ @@ -30,3 +24,7 @@ features = [ "bevy_render", "bevy_core_pipeline" ] + +[dev-dependencies] +bevy = "0.8" +bytemuck = "1.12.0" diff --git a/kayak_font/examples/bevy.rs b/kayak_font/examples/bevy.rs index 2266e62439fe3c9b9e8453a5915892ddebe12fa6..d5092614f4cbf3a3125fabb47e3e485df06cb8b2 100644 --- a/kayak_font/examples/bevy.rs +++ b/kayak_font/examples/bevy.rs @@ -1,10 +1,10 @@ use bevy::{ - math::{const_vec2, Vec2}, + math::Vec2, prelude::{ - App as BevyApp, AssetServer, Commands, Component, Handle, Input, KeyCode, Query, Res, - ResMut, Sprite, SpriteBundle, Transform, With, Without, + App as BevyApp, AssetServer, Camera2dBundle, Commands, Component, Handle, Input, KeyCode, + Query, Res, ResMut, Sprite, SpriteBundle, Transform, With, Without, }, - render::{camera::OrthographicCameraBundle, color::Color}, + render::color::Color, window::WindowDescriptor, DefaultPlugins, }; @@ -15,8 +15,8 @@ use renderer::{FontRenderPlugin, Text}; mod renderer; const FONT_SIZE: f32 = 24.0; -const INITIAL_SIZE: Vec2 = const_vec2!([400.0, 300.0]); -const INITIAL_POS: Vec2 = const_vec2!([-200.0, 0.0]); +const INITIAL_SIZE: Vec2 = Vec2::from_array([400.0, 300.0]); +const INITIAL_POS: Vec2 = Vec2::from_array([-200.0, 0.0]); const INSTRUCTIONS: &str = "Press 'A' and 'D' to shrink and grow the text box.\nPress 'Space' to cycle text alignment."; @@ -24,7 +24,7 @@ const INSTRUCTIONS: &str = struct Instructions; fn startup(mut commands: Commands, asset_server: Res<AssetServer>) { - commands.spawn_bundle(OrthographicCameraBundle::new_2d()); + commands.spawn_bundle(Camera2dBundle::default()); let font_handle: Handle<KayakFont> = asset_server.load("roboto.kayak_font"); diff --git a/kayak_font/examples/renderer/extract.rs b/kayak_font/examples/renderer/extract.rs index 999133619a4caf5c60df8484547647fe396af2e6..0c90bdb96b4592ee1ca552c9ee9de046ad0446df 100644 --- a/kayak_font/examples/renderer/extract.rs +++ b/kayak_font/examples/renderer/extract.rs @@ -1,7 +1,7 @@ use bevy::{ math::Vec2, prelude::{Assets, Commands, Handle, Query, Res}, - sprite::Rect, + sprite::Rect, render::Extract, }; use kayak_font::{KayakFont, TextProperties}; @@ -12,8 +12,8 @@ use super::{ pub fn extract( mut commands: Commands, - fonts: Res<Assets<KayakFont>>, - texts: Query<(&Text, &Handle<KayakFont>)>, + fonts: Extract<Res<Assets<KayakFont>>>, + texts: Extract<Query<(&Text, &Handle<KayakFont>)>>, ) { let mut extracted_texts = Vec::new(); diff --git a/kayak_font/examples/renderer/mod.rs b/kayak_font/examples/renderer/mod.rs index dec8300fd080f6cd14ab66e885f83878177a8ab5..10ccaff55844b4b5635db7eb7c2703f4f40c676c 100644 --- a/kayak_font/examples/renderer/mod.rs +++ b/kayak_font/examples/renderer/mod.rs @@ -1,5 +1,5 @@ use bevy::{ - core_pipeline::Transparent2d, + core_pipeline::core_2d::Transparent2d, prelude::{Assets, HandleUntyped, Plugin, Res, ResMut}, reflect::TypeUuid, render::{ diff --git a/kayak_font/examples/renderer/pipeline.rs b/kayak_font/examples/renderer/pipeline.rs index c37222150640f813d45b86b18697c696a792ae9e..32f5efd9e7ae27cdf9aba430ab28eea7b4942881 100644 --- a/kayak_font/examples/renderer/pipeline.rs +++ b/kayak_font/examples/renderer/pipeline.rs @@ -1,12 +1,10 @@ -use bevy::render::render_resource::std140::AsStd140; use bevy::{ - core::FloatOrd, - core_pipeline::Transparent2d, + core_pipeline::core_2d::Transparent2d, ecs::system::{ lifetimeless::{Read, SQuery, SRes}, SystemState, }, - math::{const_vec3, Mat4, Quat, Vec2, Vec3, Vec4}, + math::{Mat4, Quat, Vec2, Vec3, Vec4}, prelude::{Bundle, Component, Entity, FromWorld, Handle, Query, Res, ResMut, World}, render::{ color::Color, @@ -18,7 +16,7 @@ use bevy::{ BufferVec, CachedRenderPipelineId, ColorTargetState, ColorWrites, FragmentState, FrontFace, MultisampleState, PipelineCache, PolygonMode, PrimitiveState, PrimitiveTopology, RenderPipelineDescriptor, SamplerBindingType, Shader, ShaderStages, - TextureFormat, TextureSampleType, TextureViewDimension, VertexAttribute, + ShaderType, TextureFormat, TextureSampleType, TextureViewDimension, VertexAttribute, VertexBufferLayout, VertexFormat, VertexState, VertexStepMode, }, renderer::{RenderDevice, RenderQueue}, @@ -26,6 +24,7 @@ use bevy::{ view::{ViewUniformOffset, ViewUniforms}, }, sprite::Rect, + utils::FloatOrd, }; use bytemuck::{Pod, Zeroable}; use kayak_font::{ @@ -43,12 +42,12 @@ pub struct FontPipeline { } const QUAD_VERTEX_POSITIONS: &[Vec3] = &[ - const_vec3!([0.0, 0.0, 0.0]), - const_vec3!([1.0, 1.0, 0.0]), - const_vec3!([0.0, 1.0, 0.0]), - const_vec3!([0.0, 0.0, 0.0]), - const_vec3!([1.0, 0.0, 0.0]), - const_vec3!([1.0, 1.0, 0.0]), + Vec3::from_array([0.0, 0.0, 0.0]), + Vec3::from_array([1.0, 1.0, 0.0]), + Vec3::from_array([0.0, 1.0, 0.0]), + Vec3::from_array([0.0, 0.0, 0.0]), + Vec3::from_array([1.0, 0.0, 0.0]), + Vec3::from_array([1.0, 1.0, 0.0]), ]; impl FontRenderingPipeline for FontPipeline { @@ -70,8 +69,6 @@ impl FromWorld for FontPipeline { ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: true, - // TODO: change this to ViewUniform::std140_size_static once crevice fixes this! - // Context: https://github.com/LPGhatguy/crevice/issues/29 min_binding_size: BufferSize::new(144), }, count: None, @@ -143,7 +140,7 @@ impl FromWorld for FontPipeline { shader: FONT_SHADER_HANDLE.typed::<Shader>(), shader_defs: vec![], entry_point: "fragment".into(), - targets: vec![ColorTargetState { + targets: vec![Some(ColorTargetState { format: TextureFormat::bevy_default(), blend: Some(BlendState { color: BlendComponent { @@ -158,7 +155,7 @@ impl FromWorld for FontPipeline { }, }), write_mask: ColorWrites::ALL, - }], + })], }), layout: Some(vec![view_layout.clone(), font_image_layout.clone()]), primitive: PrimitiveState { @@ -213,7 +210,7 @@ struct QuadVertex { } #[repr(C)] -#[derive(Copy, Clone, AsStd140)] +#[derive(Copy, Clone, ShaderType)] struct QuadType { pub t: i32, } diff --git a/kayak_font/examples/renderer/shader.wgsl b/kayak_font/examples/renderer/shader.wgsl index 5213429eb5757c9c107e851fde4292f9dcfd527c..7d251ec2d1c8821a3c1dd5eb709428a2d1b24f3f 100644 --- a/kayak_font/examples/renderer/shader.wgsl +++ b/kayak_font/examples/renderer/shader.wgsl @@ -1,26 +1,27 @@ struct View { - view_proj: mat4x4<f32>; - world_position: vec3<f32>; -}; -[[group(0), binding(0)]] + view_proj: mat4x4<f32>, + world_position: vec3<f32>, +} + +@group(0) @binding(0) var<uniform> view: View; struct VertexOutput { - [[builtin(position)]] position: vec4<f32>; - [[location(0)]] color: vec4<f32>; - [[location(1)]] uv: vec3<f32>; - [[location(2)]] pos: vec2<f32>; - [[location(3)]] size: vec2<f32>; - [[location(4)]] screen_position: vec2<f32>; - [[location(5)]] border_radius: f32; + @builtin(position) position: vec4<f32>, + @location(0) color: vec4<f32>, + @location(1) uv: vec3<f32>, + @location(2) pos: vec2<f32>, + @location(3) size: vec2<f32>, + @location(4) screen_position: vec2<f32>, + @location(5) border_radius: f32, }; -[[stage(vertex)]] +@vertex fn vertex( - [[location(0)]] vertex_position: vec3<f32>, - [[location(1)]] vertex_color: vec4<f32>, - [[location(2)]] vertex_uv: vec4<f32>, - [[location(3)]] vertex_pos_size: vec4<f32>, + @location(0) vertex_position: vec3<f32>, + @location(1) vertex_color: vec4<f32>, + @location(2) vertex_uv: vec4<f32>, + @location(3) vertex_pos_size: vec4<f32>, ) -> VertexOutput { var out: VertexOutput; out.color = vertex_color; @@ -33,13 +34,13 @@ fn vertex( return out; } -[[group(1), binding(0)]] +@group(1) @binding(0) var font_texture: texture_2d_array<f32>; -[[group(1), binding(1)]] +@group(1) @binding(1) var font_sampler: sampler; -[[stage(fragment)]] -fn fragment(in: VertexOutput) -> [[location(0)]] vec4<f32> { +@fragment +fn fragment(in: VertexOutput) -> @location(0) vec4<f32> { var px_range = 2.5; var tex_dimensions = textureDimensions(font_texture); var msdf_unit = vec2<f32>(px_range, px_range) / vec2<f32>(f32(tex_dimensions.x), f32(tex_dimensions.y)); diff --git a/kayak_font/src/atlas.rs b/kayak_font/src/atlas.rs index 97e6f5421b7f42a9879a8d1c77502d8d6be67be2..e710863f88bd5b9e2dd6e47d2a5c8d5c9e759f7e 100644 --- a/kayak_font/src/atlas.rs +++ b/kayak_font/src/atlas.rs @@ -1,33 +1,33 @@ -use serde::Deserialize; +use nanoserde::DeJson; -#[derive(Deserialize, Debug, Copy, Clone, PartialEq)] +#[derive(DeJson, Debug, Copy, Clone, PartialEq)] pub enum SDFType { - #[serde(alias = "msdf")] + #[nserde(rename = "msdf")] Msdf, } -#[derive(Deserialize, Debug, Copy, Clone, PartialEq)] +#[derive(DeJson, Debug, Copy, Clone, PartialEq)] pub enum Origin { - #[serde(alias = "bottom")] + #[nserde(rename = "bottom")] Bottom, - #[serde(alias = "left")] + #[nserde(rename = "left")] Left, - #[serde(alias = "right")] + #[nserde(rename = "right")] Right, - #[serde(alias = "top")] + #[nserde(rename = "top")] Top, } -#[derive(Deserialize, Debug, Copy, Clone, PartialEq)] +#[derive(DeJson, Debug, Copy, Clone, PartialEq)] pub struct Atlas { - #[serde(alias = "type")] + #[nserde(rename = "type")] pub sdf_type: SDFType, - #[serde(alias = "distanceRange")] + #[nserde(rename = "distanceRange")] pub distance_range: f32, - #[serde(alias = "size")] + #[nserde(rename = "size")] pub font_size: f32, pub width: u32, pub height: u32, - #[serde(alias = "yOrigin")] + #[nserde(rename = "yOrigin")] pub y_origin: Origin, } diff --git a/kayak_font/src/bevy/font_texture.rs b/kayak_font/src/bevy/font_texture.rs index c0868a91b5bcd9297c7e9e33b6b2ee80840a45e2..26110bf83642556c3e0064a0e1210f014c9dc5fc 100644 --- a/kayak_font/src/bevy/font_texture.rs +++ b/kayak_font/src/bevy/font_texture.rs @@ -1,6 +1,7 @@ use crate::KayakFont; use bevy::prelude::{AssetEvent, Assets, EventReader, Handle, Image, Local, Res, ResMut}; -use bevy::render::render_resource::{FilterMode, TextureFormat, TextureUsages}; +use bevy::render::render_resource::{FilterMode, SamplerDescriptor, TextureFormat, TextureUsages}; +use bevy::render::texture::ImageSampler; pub fn init_font_texture( mut not_processed: Local<Vec<Handle<KayakFont>>>, @@ -23,9 +24,13 @@ pub fn init_font_texture( if let Some(font) = fonts.get(&font_handle) { if let Some(mut texture) = images.get_mut(&font.atlas_image) { texture.texture_descriptor.format = TextureFormat::Rgba8Unorm; - texture.sampler_descriptor.min_filter = FilterMode::Linear; - texture.sampler_descriptor.mipmap_filter = FilterMode::Linear; - texture.sampler_descriptor.mag_filter = FilterMode::Linear; + texture.sampler_descriptor = ImageSampler::Descriptor(SamplerDescriptor { + label: Some("Present Sampler"), + mag_filter: FilterMode::Linear, + min_filter: FilterMode::Linear, + + ..Default::default() + }); texture.texture_descriptor.usage = TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST | TextureUsages::COPY_SRC; diff --git a/kayak_font/src/bevy/renderer/extract.rs b/kayak_font/src/bevy/renderer/extract.rs index 16a9dbe7c2979fb10c7080a2c6327be692415495..490ba4c04d7e6af21cec68b27781fc64f27156b8 100644 --- a/kayak_font/src/bevy/renderer/extract.rs +++ b/kayak_font/src/bevy/renderer/extract.rs @@ -1,7 +1,10 @@ use crate::bevy::renderer::FontTextureCache; use crate::KayakFont; use bevy::prelude::{AssetEvent, Assets, Commands, EventReader, Handle, Image, Local, Res, ResMut}; -use bevy::render::render_resource::{TextureFormat, TextureUsages}; +use bevy::render::{ + render_resource::{TextureFormat, TextureUsages}, + Extract, +}; use bevy::utils::HashSet; #[derive(Default)] @@ -12,9 +15,9 @@ pub struct ExtractedFonts { pub(crate) fn extract_fonts( mut not_processed: Local<Vec<Handle<KayakFont>>>, mut commands: Commands, - font_assets: Res<Assets<KayakFont>>, - mut events: EventReader<AssetEvent<KayakFont>>, - textures: Res<Assets<Image>>, + font_assets: Extract<Res<Assets<KayakFont>>>, + mut events: Extract<EventReader<AssetEvent<KayakFont>>>, + textures: Extract<Res<Assets<Image>>>, ) { let mut extracted_fonts = ExtractedFonts { fonts: Vec::new() }; let mut changed_assets = HashSet::default(); diff --git a/kayak_font/src/bevy/renderer/font_texture_cache.rs b/kayak_font/src/bevy/renderer/font_texture_cache.rs index 5b18fbcee6181a72ddf3a791e85f4462b52af7f7..3d105f5731a424c271551ebb1ca82299553ab69c 100644 --- a/kayak_font/src/bevy/renderer/font_texture_cache.rs +++ b/kayak_font/src/bevy/renderer/font_texture_cache.rs @@ -1,6 +1,6 @@ use crate::{KayakFont, Sdf}; use bevy::{ - math::{Size, Vec2}, + math::Vec2, prelude::{Handle, Res}, render::{ render_asset::RenderAssets, @@ -150,9 +150,9 @@ impl FontTextureCache { texture, sampler, texture_view, - size: Size { - width: size.0 as f32, - height: size.1 as f32, + size: Vec2 { + x: size.0 as f32, + y: size.1 as f32, }, texture_format: format, }; @@ -195,9 +195,9 @@ impl FontTextureCache { texture, sampler, texture_view, - size: Size { - width: 1.0, - height: 1.0, + size: Vec2 { + x: 1.0, + y: 1.0, }, texture_format: TextureFormat::Rgba8Unorm, }; diff --git a/kayak_font/src/glyph.rs b/kayak_font/src/glyph.rs index 54301e01624311b438128e23d74fd7779867ded9..0975e26be28c112d2838940fe7ebfa8ef096836b 100644 --- a/kayak_font/src/glyph.rs +++ b/kayak_font/src/glyph.rs @@ -1,28 +1,50 @@ -use serde::{Deserialize, Deserializer}; - -fn from_u32<'de, D>(deserializer: D) -> Result<char, D::Error> -where - D: Deserializer<'de>, -{ - let number: u32 = Deserialize::deserialize(deserializer)?; - match char::from_u32(number) { - Some(c) => Ok(c), - None => Err(serde::de::Error::custom("Can't deserialize char from u32!")), +use nanoserde::{DeJson, DeJsonErr, DeJsonState, SerJson, SerJsonState}; + +pub struct UnicodeChar(char); + +impl DeJson for UnicodeChar { + fn de_json(state: &mut DeJsonState, input: &mut std::str::Chars) -> Result<Self, DeJsonErr> { + u32::de_json(state, input).and_then(|a| { + if let Some(a) = char::from_u32(a) { + Ok(Self(a)) + } else { + Err(state.err_parse("Not unicode")) + } + }) + } +} + +impl SerJson for UnicodeChar { + fn ser_json(&self, d: usize, s: &mut SerJsonState) { + let out = self.0 as u32; + out.ser_json(d, s) + } +} + +impl From<&char> for UnicodeChar { + fn from(c: &char) -> Self { + Self(*c) + } +} + +impl From<&UnicodeChar> for char { + fn from(uc: &UnicodeChar) -> Self { + uc.0 } } -#[derive(Deserialize, Debug, Clone, Copy, PartialEq)] +#[derive(DeJson, Debug, Clone, Copy, PartialEq)] pub struct Glyph { - #[serde(deserialize_with = "from_u32")] + #[nserde(proxy = "UnicodeChar")] pub unicode: char, pub advance: f32, - #[serde(alias = "atlasBounds")] + #[nserde(rename = "atlasBounds")] pub atlas_bounds: Option<Rect>, - #[serde(alias = "planeBounds")] + #[nserde(rename = "planeBounds")] pub plane_bounds: Option<Rect>, } -#[derive(Deserialize, Default, Clone, Copy, Debug, PartialEq)] +#[derive(DeJson, Default, Clone, Copy, Debug, PartialEq)] pub struct Rect { pub left: f32, pub bottom: f32, diff --git a/kayak_font/src/metrics.rs b/kayak_font/src/metrics.rs index 0e042bbe8f095f982ccba0f226752a1deef2f077..83d307f6206bb9231492057ea2d960fda28306b6 100644 --- a/kayak_font/src/metrics.rs +++ b/kayak_font/src/metrics.rs @@ -1,15 +1,15 @@ -use serde::Deserialize; +use nanoserde::DeJson; -#[derive(Deserialize, Debug, Copy, Clone, PartialEq)] +#[derive(DeJson, Debug, Copy, Clone, PartialEq)] pub struct Metrics { - #[serde(alias = "emSize")] + #[nserde(rename = "emSize")] em_size: f32, - #[serde(alias = "lineHeight")] + #[nserde(rename = "lineHeight")] line_height: f32, ascender: f32, descender: f32, - #[serde(alias = "underlineY")] + #[nserde(rename = "underlineY")] underline_y: f32, - #[serde(alias = "underlineThickness")] + #[nserde(rename = "underlineThickness")] underline_thickness: f32, } diff --git a/kayak_font/src/sdf.rs b/kayak_font/src/sdf.rs index 13fe4d912cde34e5de6098841b79ada628fb0cd4..ec6ed8e5ccb63a14dd280830516dd03a81f64805 100644 --- a/kayak_font/src/sdf.rs +++ b/kayak_font/src/sdf.rs @@ -1,7 +1,7 @@ use crate::{atlas::Atlas, glyph::Glyph, metrics::Metrics}; -use serde::Deserialize; +use nanoserde::DeJson; -#[derive(Deserialize, Debug, Clone, PartialEq)] +#[derive(DeJson, Debug, Clone, PartialEq)] pub struct Sdf { pub atlas: Atlas, metrics: Metrics, @@ -9,7 +9,7 @@ pub struct Sdf { kerning: Vec<KerningData>, } -#[derive(Deserialize, Debug, Clone, Copy, PartialEq)] +#[derive(DeJson, Debug, Clone, Copy, PartialEq)] pub struct KerningData { pub unicode1: u32, pub unicode2: u32, @@ -18,14 +18,10 @@ pub struct KerningData { 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), - ) { + let value: Sdf = match DeJson::deserialize_json(data.as_str()) { Ok(v) => v, Err(err) => { - let path = err.path().to_string(); - dbg!(err); - panic!("failed to deserialize json! path: {}", path); + panic!("{}", dbg!(err)); } }; @@ -33,14 +29,10 @@ impl Sdf { } pub fn from_bytes(data: &[u8]) -> Sdf { - let value: Sdf = match serde_path_to_error::deserialize( - &mut serde_json::Deserializer::from_slice(&data), - ) { + let value: Sdf = match DeJson::deserialize_json(std::str::from_utf8(data).unwrap()) { Ok(v) => v, Err(err) => { - let path = err.path().to_string(); - dbg!(err); - panic!("failed to deserialize json! path: {}", path); + panic!("{}", dbg!(err)); } }; @@ -49,6 +41,7 @@ impl Sdf { pub fn max_glyph_size(&self) -> (f32, f32) { let mut size = (0.0, 0.0); + self.glyphs.iter().for_each(|glyph| { if let Some(atlas_bounds) = glyph.atlas_bounds { let atlas_size = atlas_bounds.size();