diff --git a/Cargo.lock b/Cargo.lock index 9d6a945..e261d68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -282,7 +282,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -336,7 +336,7 @@ checksum = "f548ad2c4031f2902e3edc1f29c29e835829437de49562d8eb5dc5584d3a1043" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -465,7 +465,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -500,7 +500,7 @@ checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -607,6 +607,32 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "basis-universal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555fb05709f4e12fa2f6b93a480facf167eb0ecb2558ba41f610f588e77cbd14" +dependencies = [ + "basis-universal-sys", + "bitflags 1.3.2", + "lazy_static", +] + +[[package]] +name = "basis-universal-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd9bde5e9547958fb0e77d79fc7879edcf91d5e0c8e372ef8959916cf35e8506" +dependencies = [ + "cc", +] + +[[package]] +name = "bcdec_rs" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9934c2b68e46448d814db20e34a840ef9b4e7b3b7c8b1da91161481230f6350" + [[package]] name = "bevy" version = "0.15.1" @@ -694,7 +720,7 @@ dependencies = [ "bevy_macro_utils", "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -761,7 +787,7 @@ checksum = "b962df2a1bef274ae76ec75279eb6f8ef0ffd85b5e4c43433f5d08ba57b3d071" dependencies = [ "bevy_macro_utils", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -810,7 +836,7 @@ dependencies = [ "bevy_macro_utils", "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -855,7 +881,7 @@ dependencies = [ "bevy_macro_utils", "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -965,7 +991,7 @@ checksum = "9bdb3a681c24abace65bf18ed467ad8befbedb42468b32e459811bfdb01e506c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", "toml_edit", ] @@ -1075,7 +1101,7 @@ dependencies = [ "bevy_macro_utils", "proc-macro2", "quote", - "syn", + "syn 2.0.95", "uuid", ] @@ -1134,7 +1160,7 @@ dependencies = [ "bevy_macro_utils", "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -1260,7 +1286,7 @@ checksum = "4a0c3244d543cc964545b7aa074f6fb18a915a7121cf3de5d7ed37a4aae8662d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -1298,7 +1324,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 2.0.95", ] [[package]] @@ -1437,7 +1463,7 @@ checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -1589,7 +1615,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -1857,6 +1883,18 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" +[[package]] +name = "ddsfile" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479dfe1e6737aa9e96c6ac7b69689dc4c32da8383f2c12744739d76afa8b66c4" +dependencies = [ + "bitflags 2.6.0", + "byteorder", + "enum-primitive-derive", + "num-traits", +] + [[package]] name = "derive_more" version = "1.0.0" @@ -1874,7 +1912,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", "unicode-xid", ] @@ -1902,7 +1940,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -2130,7 +2168,7 @@ checksum = "f97b51c5cc57ef7c5f7a0c57c250251c49ee4c28f819f87ac32f4aceabc36792" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -2157,7 +2195,18 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", +] + +[[package]] +name = "enum-primitive-derive" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c375b9c5eadb68d0a6efee2999fef292f45854c3444c86f09d8ab086ba942b0e" +dependencies = [ + "num-traits", + "quote", + "syn 1.0.109", ] [[package]] @@ -2178,7 +2227,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -2189,7 +2238,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -2390,7 +2439,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -2450,7 +2499,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -2697,6 +2746,7 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ + "bytemuck", "cfg-if", "crunchy", ] @@ -2727,6 +2777,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hermit-abi" version = "0.4.0" @@ -2886,7 +2942,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -2943,6 +2999,22 @@ dependencies = [ "quick-error", ] +[[package]] +name = "image_dds" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c6d1a2d80bc7dd2928b2a72a46d71bccbb6becf8ce207522b0b92daf0a417f" +dependencies = [ + "bcdec_rs", + "bytemuck", + "ddsfile", + "half", + "image", + "intel_tex_2", + "strum", + "thiserror 1.0.69", +] + [[package]] name = "imagesize" version = "0.12.0" @@ -2974,6 +3046,15 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "intel_tex_2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd699c0e6adcac28c06db24a220c834c8ec811e0d2d80f0261bb14e01737b4dc" +dependencies = [ + "ispc_rt", +] + [[package]] name = "interpolate_name" version = "0.2.4" @@ -2982,7 +3063,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -2991,6 +3072,16 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "ispc_rt" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d30e08ddfd6fe26c3ee2e856dff022420cd0514ed16f5ccf2dc3e1d5cae578" +dependencies = [ + "libc", + "num_cpus", +] + [[package]] name = "itertools" version = "0.12.1" @@ -3441,7 +3532,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -3474,6 +3565,16 @@ dependencies = [ "libm", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + [[package]] name = "num_enum" version = "0.7.3" @@ -3492,7 +3593,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -3831,7 +3932,7 @@ checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -3884,7 +3985,7 @@ checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi", + "hermit-abi 0.4.0", "pin-project-lite", "rustix", "tracing", @@ -3928,7 +4029,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "483f8c21f64f3ea09fe0f30f5d48c3e8eefe5dac9129f0075f76593b4c1da705" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.95", ] [[package]] @@ -3965,7 +4066,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" dependencies = [ "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -4325,10 +4426,12 @@ dependencies = [ name = "rpack_cli" version = "0.0.0" dependencies = [ + "basis-universal", "bevy_rpack", "clap", "glob", "image", + "image_dds", "serde", "serde_json", "texture_packer", @@ -4385,6 +4488,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + [[package]] name = "ryu" version = "1.0.18" @@ -4435,7 +4544,7 @@ checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -4458,7 +4567,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -4652,6 +4761,28 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.95", +] + [[package]] name = "subtle" version = "2.6.1" @@ -4674,6 +4805,17 @@ dependencies = [ "siphasher", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.95" @@ -4693,7 +4835,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -4773,7 +4915,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -4784,7 +4926,7 @@ checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -4921,7 +5063,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -5226,7 +5368,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 2.0.95", "wasm-bindgen-shared", ] @@ -5261,7 +5403,7 @@ checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5589,7 +5731,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -5600,7 +5742,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -5972,7 +6114,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", "synstructure", ] @@ -6068,7 +6210,7 @@ checksum = "709ab20fc57cb22af85be7b360239563209258430bccf38d8b979c5a2ae3ecce" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", "zbus-lockstep", "zbus_xml", "zvariant 4.2.0", @@ -6083,7 +6225,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.95", "zvariant_utils 2.1.0", ] @@ -6096,7 +6238,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.95", "zbus_names 4.1.0", "zvariant 5.1.0", "zvariant_utils 3.0.2", @@ -6156,7 +6298,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -6176,7 +6318,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", "synstructure", ] @@ -6205,7 +6347,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -6270,7 +6412,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.95", "zvariant_utils 2.1.0", ] @@ -6283,7 +6425,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.95", "zvariant_utils 3.0.2", ] @@ -6295,7 +6437,7 @@ checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.95", ] [[package]] @@ -6308,6 +6450,6 @@ dependencies = [ "quote", "serde", "static_assertions", - "syn", + "syn 2.0.95", "winnow", ] diff --git a/crates/bevy_rpack/src/bevy.rs b/crates/bevy_rpack/src/bevy.rs index e8845f5..6eb16d2 100644 --- a/crates/bevy_rpack/src/bevy.rs +++ b/crates/bevy_rpack/src/bevy.rs @@ -72,7 +72,7 @@ pub enum RpackAtlasAssetError { #[error("could not load asset: {0}")] Io(#[from] std::io::Error), #[error("could not parse asset: {0}")] - ParsinError(#[from] serde_json::Error), + ParsingError(#[from] serde_json::Error), /// A Bevy [`LoadDirectError`](bevy::asset::LoadDirectError) that occured /// while loading a [`RpackAtlasAsset::image`](crate::RpackAtlasAsset::image). #[error("could not load asset: {0}")] @@ -116,8 +116,8 @@ impl AssetLoader for RpackAtlasAssetLoader { .asset_path() .path() .parent() - .unwrap_or(&std::path::Path::new("")) - .join(asset.name); + .unwrap_or(std::path::Path::new("")) + .join(asset.filename); let mut image: Image = load_context .loader() diff --git a/crates/bevy_rpack/src/lib.rs b/crates/bevy_rpack/src/lib.rs index 9ae8a7b..e1e7c05 100644 --- a/crates/bevy_rpack/src/lib.rs +++ b/crates/bevy_rpack/src/lib.rs @@ -23,6 +23,6 @@ pub struct AtlasFrame { #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] pub struct AtlasAsset { pub size: [u32; 2], - pub name: String, + pub filename: String, pub frames: Vec, } diff --git a/crates/rpack/src/app.rs b/crates/rpack/src/app.rs index b0b692f..a90e842 100644 --- a/crates/rpack/src/app.rs +++ b/crates/rpack/src/app.rs @@ -102,9 +102,7 @@ impl TemplateApp { .to_owned() .replace("\\", "/"); - let Some(image) = dynamic_image_from_file(file) else { - return None; - }; + let image = dynamic_image_from_file(file)?; Some(ImageFile { id, image }) } @@ -117,13 +115,19 @@ impl TemplateApp { .flat_map(|f| Self::image_from_dropped_file(f, &prefix)) .collect(); - self.data = Some(Spritesheet::build( - self.config, - &images, - "name".to_owned(), - )); + self.data = Some(Spritesheet::build(self.config, &images, "name")); if let Some(Ok(data)) = &self.data { - ctx.include_bytes("bytes://output.png", data.image_data.clone()); + let mut out_vec = vec![]; + let mut img = + image::DynamicImage::new_rgba8(data.atlas_asset.size[0], data.atlas_asset.size[1]); + image::imageops::overlay(&mut img, &data.image_data, 0, 0); + + img.write_to( + &mut std::io::Cursor::new(&mut out_vec), + image::ImageFormat::Png, + ) + .unwrap(); + ctx.include_bytes("bytes://output.png", out_vec); self.image = Some(Image::from_uri("bytes://output.png").max_size(Vec2::new(256.0, 256.0))); } @@ -134,7 +138,7 @@ impl TemplateApp { let Some(Ok(data)) = &self.data else { return; }; - let data = data.image_data.clone(); + let data = data.image_data.as_bytes().to_vec(); let filename = format!("{}.png", self.name); #[cfg(not(target_arch = "wasm32"))] { @@ -396,9 +400,7 @@ fn file_path(file: &DroppedFile) -> String { fn dynamic_image_from_file(file: &DroppedFile) -> Option { #[cfg(target_arch = "wasm32")] { - let Some(bytes) = file.bytes.as_ref().clone() else { - return None; - }; + let bytes = file.bytes.as_ref().clone()?; if let Ok(r) = ImageImporter::import_from_memory(&bytes.unwrap()) { Some(r.into()) @@ -408,9 +410,7 @@ fn dynamic_image_from_file(file: &DroppedFile) -> Option { } #[cfg(not(target_arch = "wasm32"))] { - let Some(path) = file.path.as_ref() else { - return None; - }; + let path = file.path.as_ref()?; if let Ok(r) = ImageImporter::import_from_file(path) { Some(r) diff --git a/crates/rpack_cli/Cargo.toml b/crates/rpack_cli/Cargo.toml index d706550..10df20b 100644 --- a/crates/rpack_cli/Cargo.toml +++ b/crates/rpack_cli/Cargo.toml @@ -5,14 +5,18 @@ license = "MIT" edition = "2021" [features] -default = ["cli"] +default = ["cli", "dds"] cli = ["dep:clap", "dep:glob"] +basis = ["dep:basis-universal"] +dds = ["dep:image_dds"] [dependencies] -clap = { version = "4", features = ["derive"], optional = true} +clap = { version = "4", features = ["derive"], optional = true } bevy_rpack = { default-features = false, path = "../bevy_rpack" } serde = { version = "1", features = ["derive"] } serde_json = "1" texture_packer = { version = "0.29", features = ["common"] } image = { version = "0.25", features = ["jpeg", "png"] } -glob = {version = "0.3", optional = true} +glob = { version = "0.3", optional = true } +basis-universal = { version = "0.3.1", optional = true } +image_dds = { version = "0.6.2", optional = true } diff --git a/crates/rpack_cli/src/lib.rs b/crates/rpack_cli/src/lib.rs index 971efe9..0f5ca3c 100644 --- a/crates/rpack_cli/src/lib.rs +++ b/crates/rpack_cli/src/lib.rs @@ -1,12 +1,12 @@ use bevy_rpack::{AtlasFrame, SerializableRect}; use image::DynamicImage; use serde_json::Value; -use std::{io::Cursor, path::PathBuf}; +use std::path::Path; use texture_packer::{importer::ImageImporter, TexturePacker, TexturePackerConfig}; #[derive(Clone)] pub struct Spritesheet { - pub image_data: Vec, + pub image_data: DynamicImage, pub atlas_asset: bevy_rpack::AtlasAsset, pub atlas_asset_json: Value, } @@ -18,15 +18,16 @@ pub struct ImageFile { } impl ImageFile { - pub fn at_path

(path: &PathBuf, id: P) -> Option + pub fn at_path

(path: &Path, id: P) -> Option where P: AsRef, { - if let Ok(image) = ImageImporter::import_from_file(&path) { - Some(ImageFile { - image, - id: id.as_ref().to_owned().replace("\\", "/"), - }) + let mut id = id.as_ref().to_owned().replace("\\", "/"); + if let Some((before, _)) = id.split_once('.') { + id = before.to_string(); + } + if let Ok(image) = ImageImporter::import_from_file(path) { + Some(ImageFile { image, id }) } else { None } @@ -34,11 +35,14 @@ impl ImageFile { } impl Spritesheet { - pub fn build( + pub fn build

( config: TexturePackerConfig, images: &[ImageFile], - name: String, - ) -> Result { + filename: P, + ) -> Result + where + P: AsRef, + { let mut packer = TexturePacker::new_skyline(config); for image in images.iter() { if !packer.can_pack(&image.image) { @@ -54,17 +58,13 @@ impl Spritesheet { )); } } - let mut out_vec = vec![]; - let exported_image = - texture_packer::exporter::ImageExporter::export(&packer, None).unwrap(); - let mut img = image::DynamicImage::new_rgba8(config.max_width, config.max_height); - image::imageops::overlay(&mut img, &exported_image, 0, 0); + let Ok(image_data) = texture_packer::exporter::ImageExporter::export(&packer, None) else { + return Err("Failed to export image".to_owned()); + }; - img.write_to(&mut Cursor::new(&mut out_vec), image::ImageFormat::Png) - .unwrap(); let atlas_asset = bevy_rpack::AtlasAsset { - size: [img.width(), img.height()], - name, + size: [image_data.width(), image_data.height()], + filename: filename.as_ref().to_owned(), frames: packer .get_frames() .values() @@ -86,9 +86,147 @@ impl Spritesheet { }; Ok(Spritesheet { - image_data: out_vec.clone(), + image_data, atlas_asset, atlas_asset_json, }) } + + #[cfg(feature = "dds")] + pub fn save_as_dds(&self, output_path: R) + where + R: AsRef, + { + let rgba_image = self.image_data.to_rgba8(); + + let dds = image_dds::dds_from_image( + &rgba_image, + image_dds::ImageFormat::Rgba8Unorm, + image_dds::Quality::Fast, + image_dds::Mipmaps::GeneratedAutomatic, + ) + .unwrap(); + + let mut writer = + std::io::BufWriter::new(std::fs::File::create(output_path.as_ref()).unwrap()); + dds.write(&mut writer).unwrap(); + } + + #[cfg(feature = "basis")] + pub fn save_as_basis(&self, output_path: R) + where + R: AsRef, + { + use basis_universal::{ + BasisTextureFormat, Compressor, TranscodeParameters, Transcoder, + TranscoderTextureFormat, + }; + use image::{EncodableLayout, GenericImageView}; + + let rgba_image = self.image_data.to_rgba8(); + + let channel_count = 4; + let (pixel_width, pixel_height) = self.image_data.dimensions(); + let mut compressor_params = basis_universal::CompressorParams::new(); + compressor_params.set_generate_mipmaps(true); + compressor_params.set_basis_format(BasisTextureFormat::UASTC4x4); + compressor_params.set_uastc_quality_level(basis_universal::UASTC_QUALITY_DEFAULT); + compressor_params.set_print_status_to_stdout(false); + let mut compressor_image = compressor_params.source_image_mut(0); + compressor_image.init( + rgba_image.as_bytes(), + pixel_width, + pixel_height, + channel_count, + ); + + // + // Create the compressor and compress + // + let mut compressor = Compressor::default(); + let compression_time = unsafe { + compressor.init(&compressor_params); + let t0 = std::time::Instant::now(); + compressor.process().unwrap(); + let t1 = std::time::Instant::now(); + t1 - t0 + }; + + // You could write it to disk like this + let basis_file = compressor.basis_file(); + // std::fs::write("example_encoded_image.basis", basis_file).unwrap(); + + let mut transcoder = Transcoder::new(); + let mip_level_count = transcoder.image_level_count(basis_file, 0); + println!( + "Compressed {} mip levels to {} total bytes in {} ms", + mip_level_count, + compressor.basis_file_size(), + compression_time.as_secs_f64() * 1000.0 + ); + + let userdata = transcoder.user_data(basis_file).unwrap(); + println!("Basis file has user data {:?}", userdata); + + // + // Now lets transcode it back to raw images + // + transcoder.prepare_transcoding(basis_file).unwrap(); + + let t0 = std::time::Instant::now(); + let result = transcoder + .transcode_image_level( + basis_file, + TranscoderTextureFormat::ASTC_4x4_RGBA, + TranscodeParameters { + image_index: 0, + level_index: 0, + ..Default::default() + }, + ) + .unwrap(); + let t1 = std::time::Instant::now(); + + println!( + "Transcoded mip level 0 to ASTC_4x4_RGBA: {} bytes {} ms", + result.len(), + (t1 - t0).as_secs_f64() * 1000.0 + ); + + let t0 = std::time::Instant::now(); + let result = transcoder + .transcode_image_level( + basis_file, + TranscoderTextureFormat::RGBA32, + TranscodeParameters { + image_index: 0, + level_index: 0, + ..Default::default() + }, + ) + .unwrap(); + let t1 = std::time::Instant::now(); + + println!( + "Transcoded mip level 0 to RGBA32: {} bytes {} ms", + result.len(), + (t1 - t0).as_secs_f64() * 1000.0 + ); + + transcoder.end_transcoding(); + + let description = transcoder + .image_level_description(basis_file, 0, 0) + .unwrap(); + let image = image::RgbaImage::from_raw( + description.original_width, + description.original_height, + result, + ) + .unwrap(); + // TODO THIS DOESNT WORK, NEED TO FIX THIS + image + .save_with_format(output_path.as_ref(), image::ImageFormat::Png) + .unwrap(); + } } diff --git a/crates/rpack_cli/src/main.rs b/crates/rpack_cli/src/main.rs index d979bc3..2364819 100644 --- a/crates/rpack_cli/src/main.rs +++ b/crates/rpack_cli/src/main.rs @@ -1,23 +1,54 @@ -use std::io::Write; +use std::{fmt::Display, io::Write, path::Path}; -use clap::Parser; +use clap::{Parser, ValueEnum}; use rpack_cli::{ImageFile, Spritesheet}; +#[derive(Clone, Debug, Default, Copy, ValueEnum)] +pub enum SaveImageFormat { + #[default] + Png, + Dds, +} + +impl Display for SaveImageFormat { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + SaveImageFormat::Png => f.write_str(".png"), + SaveImageFormat::Dds => f.write_str(".dds"), + } + } +} + +impl From for image::ImageFormat { + fn from(val: SaveImageFormat) -> Self { + match val { + SaveImageFormat::Png => image::ImageFormat::Png, + SaveImageFormat::Dds => image::ImageFormat::Dds, + } + } +} + /// Build rpack tilemaps with ease #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { /// Name of the tilemap to build, when no value is provided uses 'tilemap' - #[arg(short, long)] + #[arg(action)] name: Option, /// size of the tilemap, default: 512 #[arg(long)] size: Option, + /// Image format + #[clap(short, long)] + format: Option, } fn main() { let args = Args::parse(); let name = args.name.unwrap_or("tilemap".to_owned()); + let format = args.format.unwrap_or_default(); + let atlas_filename = format!("{}{}", name, format); + let atlas_json_filename = format!("{}.png", name); let size = args.size.unwrap_or(512); let images: Vec = glob::glob("**/*png") @@ -38,23 +69,41 @@ fn main() { texture_outlines: false, }, &images, - name.clone(), + &atlas_filename, ) .expect("Failed to build spritesheet"); - let mut file = std::fs::File::create(format!("{}.png", name)).unwrap(); - let write_result = file.write_all(&spritesheet.image_data); - if write_result.is_err() { - eprintln!( - "Could not make atlas, error: {:?}", - write_result.unwrap_err() - ); - } else { - println!("Output texture stored in {:?}", file); + if Path::new(&atlas_json_filename).exists() { + std::fs::remove_file(&atlas_json_filename).expect("Could not remove the old file"); + } + if Path::new(&atlas_filename).exists() { + std::fs::remove_file(&atlas_filename).expect("Could not remove the old file"); + } + match format { + SaveImageFormat::Dds => { + #[cfg(feature = "dds")] + spritesheet.save_as_dds(&atlas_filename); + #[cfg(not(feature = "dds"))] + panic!("Program is compiled without support for dds. Compile it yourself with feature `dds` enabled."); + } + f => { + let write_result = spritesheet + .image_data + .save_with_format(&atlas_filename, f.into()); + + if write_result.is_err() { + eprintln!( + "Could not make atlas, error: {:?}", + write_result.unwrap_err() + ); + } else { + println!("Output texture stored in {}", atlas_json_filename); + } + } } let json = serde_json::to_string_pretty(&spritesheet.atlas_asset_json).unwrap(); let mut file = std::fs::File::create(format!("{}.rpack.json", name)).unwrap(); - let write_result = file.write_all(&json.as_bytes()); + let write_result = file.write_all(json.as_bytes()); if write_result.is_err() { eprintln!( "Could not make atlas, error: {:?}",