From 00049e064ff12a9c9b93674670410045b4ddaa7c Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Fri, 24 Jan 2025 15:23:43 -0600 Subject: [PATCH] svg support --- Cargo.lock | 252 ++++++++++++++++++- crates/client/Cargo.toml | 1 + crates/client/src/lib.rs | 2 +- crates/client/src/rendering/assets_wasm.rs | 52 +++- crates/client/src/rendering/renderer.rs | 6 +- crates/client/src/rendering/texture.rs | 23 +- crates/client/src/textures/hearty.svg | 278 +++++++++++++++++++++ 7 files changed, 583 insertions(+), 31 deletions(-) create mode 100644 crates/client/src/textures/hearty.svg diff --git a/Cargo.lock b/Cargo.lock index 0d2be2277c56817b7fe36dd714c19d327cdc0bca..a47363d41ea9e64c0300a14ef99fa137694b980c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1502,7 +1502,7 @@ dependencies = [ "fs4", "hex", "is_executable", - "siphasher", + "siphasher 0.3.11", "tar", "ureq", "zip", @@ -1732,9 +1732,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.7.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "bytestring" @@ -2200,6 +2200,15 @@ dependencies = [ "libc", ] +[[package]] +name = "core_maths" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b02505ccb8c50b0aa21ace0fc08c3e53adebd4e58caa18a36152803c7709a3" +dependencies = [ + "libm", +] + [[package]] name = "cpufeatures" version = "0.2.12" @@ -2364,6 +2373,12 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +[[package]] +name = "data-url" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" + [[package]] name = "deflate64" version = "0.1.9" @@ -2871,6 +2886,12 @@ dependencies = [ "miniz_oxide 0.7.4", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + [[package]] name = "fnv" version = "1.0.7" @@ -2883,6 +2904,29 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +[[package]] +name = "fontconfig-parser" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7" +dependencies = [ + "roxmltree", +] + +[[package]] +name = "fontdb" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3a6f9af55fb97ad673fb7a69533eb2f967648a06fa21f8c9bb2cd6d33975716" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser 0.24.1", +] + [[package]] name = "foreign-types" version = "0.3.2" @@ -3579,7 +3623,7 @@ dependencies = [ "color_quant", "exr", "gif", - "image-webp", + "image-webp 0.2.0", "num-traits", "png", "qoi", @@ -3591,6 +3635,16 @@ dependencies = [ "zune-jpeg", ] +[[package]] +name = "image-webp" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79afb8cbee2ef20f59ccd477a218c12a93943d075b492015ecb1bb81f8ee904" +dependencies = [ + "byteorder-lite", + "quick-error", +] + [[package]] name = "image-webp" version = "0.2.0" @@ -3601,6 +3655,12 @@ dependencies = [ "quick-error", ] +[[package]] +name = "imagesize" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" + [[package]] name = "imgref" version = "1.11.0" @@ -3829,6 +3889,16 @@ dependencies = [ "libc", ] +[[package]] +name = "kurbo" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89234b2cc610a7dd927ebde6b41dd1a5d4214cffaef4cf1fb2195d592f92518f" +dependencies = [ + "arrayvec", + "smallvec", +] + [[package]] name = "language-tags" version = "0.3.2" @@ -4860,7 +4930,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" dependencies = [ - "ttf-parser", + "ttf-parser 0.25.1", ] [[package]] @@ -4978,9 +5048,15 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ - "siphasher", + "siphasher 0.3.11", ] +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + [[package]] name = "pin-project" version = "1.1.7" @@ -5506,11 +5582,31 @@ dependencies = [ "winreg", ] +[[package]] +name = "resvg" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a325d5e8d1cebddd070b13f44cec8071594ab67d1012797c121f27a669b7958" +dependencies = [ + "gif", + "image-webp 0.1.3", + "log", + "pico-args", + "rgb", + "svgtypes", + "tiny-skia", + "usvg", + "zune-jpeg", +] + [[package]] name = "rgb" version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +dependencies = [ + "bytemuck", +] [[package]] name = "ring" @@ -5567,6 +5663,12 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + [[package]] name = "rs-snowflake" version = "0.6.0" @@ -5654,6 +5756,24 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +[[package]] +name = "rustybuzz" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85d1ccd519e61834798eb52c4e886e8c2d7d698dd3d6ce0b1b47eb8557f1181" +dependencies = [ + "bitflags 2.6.0", + "bytemuck", + "core_maths", + "log", + "smallvec", + "ttf-parser 0.24.1", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] + [[package]] name = "ryu" version = "1.0.18" @@ -5903,12 +6023,27 @@ dependencies = [ "quote", ] +[[package]] +name = "simplecss" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" +dependencies = [ + "log", +] + [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -6075,6 +6210,7 @@ version = "0.1.0" dependencies = [ "bevy_ecs 0.15.1", "console_error_panic_hook", + "crossbeam", "egui", "egui-wgpu", "egui-winit", @@ -6083,6 +6219,7 @@ dependencies = [ "nalgebra 0.33.2", "pollster", "reqwest", + "resvg", "serde", "serde_json", "starkingdoms-common", @@ -6090,6 +6227,7 @@ dependencies = [ "tracing", "tracing-subscriber", "tracing-web", + "tungstenite 0.26.1", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -6135,7 +6273,7 @@ dependencies = [ "toml 0.8.19", "tracing-subscriber", "tracing-tracy", - "tungstenite", + "tungstenite 0.21.0", ] [[package]] @@ -6149,6 +6287,9 @@ name = "strict-num" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] [[package]] name = "stringprep" @@ -6185,6 +6326,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20e16a0f46cf5fd675563ef54f26e83e20f2366bcf027bcb3cc3ed2b98aaf2ca" +[[package]] +name = "svgtypes" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc" +dependencies = [ + "kurbo", + "siphasher 1.0.1", +] + [[package]] name = "syn" version = "1.0.109" @@ -6436,6 +6587,7 @@ dependencies = [ "bytemuck", "cfg-if", "log", + "png", "tiny-skia-path", ] @@ -6773,6 +6925,15 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "ttf-parser" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a" +dependencies = [ + "core_maths", +] + [[package]] name = "ttf-parser" version = "0.25.1" @@ -6798,6 +6959,24 @@ dependencies = [ "utf-8", ] +[[package]] +name = "tungstenite" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413083a99c579593656008130e29255e54dcaae495be556cc26888f211648c24" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand", + "sha1", + "thiserror 2.0.9", + "utf-8", +] + [[package]] name = "type-map" version = "0.5.0" @@ -6825,6 +7004,18 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +[[package]] +name = "unicode-bidi-mirroring" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64af057ad7466495ca113126be61838d8af947f41d93a949980b2389a118082f" + +[[package]] +name = "unicode-ccc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "260bc6647b3893a9a90668360803a15f96b85a5257b1c3a0c3daf6ae2496de42" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -6846,12 +7037,24 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +[[package]] +name = "unicode-script" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" + [[package]] name = "unicode-segmentation" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + [[package]] name = "unicode-width" version = "0.1.13" @@ -6906,6 +7109,33 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "usvg" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447e703d7223b067607655e625e0dbca80822880248937da65966194c4864e6" +dependencies = [ + "base64 0.22.1", + "data-url", + "flate2", + "fontdb", + "imagesize", + "kurbo", + "log", + "pico-args", + "roxmltree", + "rustybuzz", + "simplecss", + "siphasher 1.0.1", + "strict-num", + "svgtypes", + "tiny-skia-path", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "xmlwriter", +] + [[package]] name = "utf-8" version = "0.7.6" @@ -7085,7 +7315,7 @@ dependencies = [ "serde_derive", "serde_ignored", "serde_json", - "siphasher", + "siphasher 0.3.11", "strsim 0.10.0", "toml 0.7.8", "ureq", @@ -8068,6 +8298,12 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "539a77ee7c0de333dcc6da69b177380a0b81e0dacfa4f7344c465a36871ee601" +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + [[package]] name = "xtask" version = "0.1.0" diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index fbc9571cb4d0d2831e2c3339c30a148baadbd57e..7e1c4ab9d0423d1502cf60cbd7c87a458f0dd83e 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -25,6 +25,7 @@ starkingdoms-common = { version = "0.1", path = "../common" } serde = "1" serde_json = "1" crossbeam = "0.8.4" +resvg = "0.44.0" # WASM dependencies [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/crates/client/src/lib.rs b/crates/client/src/lib.rs index d15614e7aefbe1ced72a270063c6f4dfcbacb621..56bea3221f85c6dab3819a863e17a541f9e4392a 100644 --- a/crates/client/src/lib.rs +++ b/crates/client/src/lib.rs @@ -81,7 +81,7 @@ pub fn start() { radians: 45.0_f32.to_radians() }, texture: SpriteTexture { - texture: "happy-tree".to_string(), + texture: "hearty".to_string(), }, }); diff --git a/crates/client/src/rendering/assets_wasm.rs b/crates/client/src/rendering/assets_wasm.rs index ecb40ed4bc258735dc682ebdef9a33f8e0addd1c..529ead7c04ac726a432819f0758735221c642907 100644 --- a/crates/client/src/rendering/assets_wasm.rs +++ b/crates/client/src/rendering/assets_wasm.rs @@ -1,13 +1,11 @@ use std::{collections::HashMap, fmt::Display, sync::{Arc, Mutex}}; use bevy_ecs::system::Resource; -use futures::channel::oneshot::{Receiver, Sender}; +use futures::channel::oneshot::Receiver; use image::EncodableLayout; -use tracing::info; +use resvg::{tiny_skia, usvg}; use wasm_bindgen_futures::spawn_local; -use super::texture::{self, Texture}; - #[derive(Debug, Clone)] pub enum AssetError { AssetNotFound, @@ -23,10 +21,17 @@ impl Display for AssetError { } impl std::error::Error for AssetError {} +#[derive(Debug, Clone)] +pub struct ImgData { + pub bytes: Vec, + pub width: u32, + pub height: u32, +} + #[derive(Resource)] pub struct Assets { - texture_receivers: Arc>>>>, - textures: Arc>>>, + texture_receivers: Arc>>>, + textures: Arc>>, } impl Assets { @@ -36,7 +41,7 @@ impl Assets { texture_receivers: Arc::new(Mutex::new(HashMap::new())), } } - pub fn get(&self, local_path: impl Into) -> Option> { + pub fn get(&self, local_path: impl Into) -> Option { let (tx, rx) = futures::channel::oneshot::channel(); let local_path = local_path.into(); let contains_texture = { @@ -73,8 +78,37 @@ impl Assets { Ok(bytes) => bytes, Err(e) => todo!(), }.to_vec(); - textures.lock().unwrap().insert(local_path, bytes.clone()); - tx.send(bytes).unwrap(); + if local_path.ends_with(".svg") { + let opt = usvg::Options { + default_size: usvg::Size::from_wh(20.0, 20.0).unwrap(), + ..Default::default() + }; + let tree = usvg::Tree::from_data(&bytes, &opt).expect("Couldn't parse svg"); + let tree_size = tree.size().to_int_size(); + let size = usvg::Size::from_wh(1000.0, 1000.0).unwrap().to_int_size(); + assert!(size.width() > 0 && size.height() > 0); + tracing::warn!("{:?}", size); + let mut pixmap = tiny_skia::Pixmap::new(size.width(), size.height()).expect("Failed to construct pixmap"); + resvg::render(&tree, tiny_skia::Transform::from_scale((size.width() as f32)/(tree_size.height() as f32), (size.height() as f32)/(tree_size.height() as f32)), &mut pixmap.as_mut()); + let data = ImgData { + bytes: pixmap.data().to_vec(), + width: size.width(), + height: size.height(), + }; + + textures.lock().unwrap().insert(local_path, data.clone()); + tx.send(data).unwrap(); + } else if local_path.ends_with(".png") { + let img = image::load_from_memory(&bytes).unwrap(); + let rgba = img.to_rgba8(); + let data = ImgData { + bytes: rgba.as_bytes().to_vec(), + width: rgba.width(), + height: rgba.height(), + }; + textures.lock().unwrap().insert(local_path, data.clone()); + tx.send(data).unwrap(); + } }); None } else if !contains_texture { diff --git a/crates/client/src/rendering/renderer.rs b/crates/client/src/rendering/renderer.rs index 44f6f6d8cdb750827af75217747e97fbd9640050..87234d08e3ef7e0c702c60af4683ebb7c3dad8e7 100644 --- a/crates/client/src/rendering/renderer.rs +++ b/crates/client/src/rendering/renderer.rs @@ -303,6 +303,10 @@ impl Renderer { Some(b) => b, None => continue, } + "hearty" => match assets.get("hearty.svg") { + Some(b) => b, + None => continue, + } u => panic!("unknown texture {u}, has it been added in rendering::renderer::::render()?") }; /*let b: &[u8] = match tex.texture.as_str() { @@ -312,7 +316,7 @@ impl Renderer { u => panic!("unknown texture {u}, has it been added in rendering::renderer::::render()?") };*/ texture::Texture::new( - &b, + b, &tex.texture, &self.device, &self.queue, diff --git a/crates/client/src/rendering/texture.rs b/crates/client/src/rendering/texture.rs index a83309c6178913df76b0512fa629e446da64dde8..7d8bba3f1b8457ff3253ff5f4b29c40bd10b8d29 100644 --- a/crates/client/src/rendering/texture.rs +++ b/crates/client/src/rendering/texture.rs @@ -5,6 +5,8 @@ use wgpu::{ SamplerDescriptor, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, }; +use super::assets::ImgData; + #[derive(Debug)] pub struct Texture { pub texture: wgpu::Texture, @@ -12,24 +14,21 @@ pub struct Texture { } impl Texture { pub fn new( - bytes: &[u8], + rgba: ImgData, label: &str, device: &Device, queue: &Queue, mip_generator: &mut MipGenerator, ) -> Self { - let img = image::load_from_memory(bytes).unwrap(); - let rgba = img.to_rgba8(); - - let max_size = rgba.width().max(rgba.height()); + let max_size = rgba.width.max(rgba.height); let log_factor = if max_size == 0 { 0 } else { max_size.ilog2() }; let optimal_mip_levels = 1 + log_factor; let texture = device.create_texture(&TextureDescriptor { label: Some(label), size: Extent3d { - width: rgba.width(), - height: rgba.height(), + width: rgba.width, + height: rgba.height, depth_or_array_layers: 1, }, mip_level_count: optimal_mip_levels, @@ -48,15 +47,15 @@ impl Texture { origin: Origin3d::ZERO, aspect: Default::default(), }, - rgba.as_bytes(), + &rgba.bytes, ImageDataLayout { offset: 0, - bytes_per_row: Some(rgba.width() * 4), - rows_per_image: Some(rgba.height()), + bytes_per_row: Some(rgba.width * 4), + rows_per_image: Some(rgba.height), }, Extent3d { - width: rgba.width(), - height: rgba.height(), + width: rgba.width, + height: rgba.height, depth_or_array_layers: 1, }, ); diff --git a/crates/client/src/textures/hearty.svg b/crates/client/src/textures/hearty.svg new file mode 100644 index 0000000000000000000000000000000000000000..895220915275cb63e2ce7ad4ddfecf136e7aa4dc --- /dev/null +++ b/crates/client/src/textures/hearty.svg @@ -0,0 +1,278 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +