diff --git a/Cargo.lock b/Cargo.lock index 43f883b..e7d6abc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,12 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "ahash" version = "0.8.3" @@ -146,6 +152,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + [[package]] name = "bitflags" version = "1.3.2" @@ -164,6 +176,12 @@ version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + [[package]] name = "byteorder" version = "1.4.3" @@ -246,6 +264,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "colorchoice" version = "1.0.0" @@ -261,6 +285,49 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + [[package]] name = "crossbeam-utils" version = "0.8.15" @@ -270,6 +337,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "derivative" version = "2.2.0" @@ -354,6 +427,12 @@ dependencies = [ "sfml", ] +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + [[package]] name = "emath" version = "0.21.0" @@ -415,6 +494,22 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "exr" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd2162b720141a91a054640662d3edce3d50a944a50ffca5313cd951abb35b4" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + [[package]] name = "fastrand" version = "1.9.0" @@ -424,6 +519,29 @@ dependencies = [ "instant", ] +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "pin-project", + "spin", +] + [[package]] name = "fnv" version = "1.0.7" @@ -457,6 +575,12 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + [[package]] name = "futures-task" version = "0.3.28" @@ -520,8 +644,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", ] [[package]] @@ -585,6 +721,15 @@ dependencies = [ "system-deps", ] +[[package]] +name = "half" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +dependencies = [ + "crunchy", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -616,6 +761,15 @@ dependencies = [ "spin", ] +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.3.1" @@ -628,6 +782,25 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "image" +version = "0.24.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-rational", + "num-traits", + "png", + "qoi", + "tiff", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -653,7 +826,7 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.1", "libc", "windows-sys 0.48.0", ] @@ -664,7 +837,7 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.1", "io-lifetimes", "rustix", "windows-sys 0.48.0", @@ -679,6 +852,15 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" +dependencies = [ + "rayon", +] + [[package]] name = "js-sys" version = "0.3.61" @@ -688,6 +870,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + [[package]] name = "libc" version = "0.2.141" @@ -752,6 +940,7 @@ dependencies = [ "fnv", "gamedebug_core", "hecs", + "image", "log", "num-traits", "rand", @@ -761,6 +950,8 @@ dependencies = [ "serde", "sfml", "sfml-xt", + "texture_packer", + "walkdir", "worldgen", "zstd", ] @@ -771,12 +962,60 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom", +] + [[package]] name = "nohash-hasher" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -786,6 +1025,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + [[package]] name = "objc" version = "0.2.7" @@ -877,6 +1126,26 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -895,6 +1164,18 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "png" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" +dependencies = [ + "bitflags", + "crc32fast", + "flate2", + "miniz_oxide", +] + [[package]] name = "polling" version = "2.7.0" @@ -926,6 +1207,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + [[package]] name = "quote" version = "1.0.26" @@ -971,6 +1261,28 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -1077,6 +1389,15 @@ dependencies = [ "serde", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -1134,6 +1455,12 @@ dependencies = [ "sfml", ] +[[package]] +name = "simd-adler32" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" + [[package]] name = "slab" version = "0.4.8" @@ -1164,6 +1491,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "strsim" @@ -1215,6 +1545,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "texture_packer" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28afa0d0b184ff1ba02bf420a4d096e880f4566ded90198cbc4b7f32ba17fa9b" +dependencies = [ + "image", +] + [[package]] name = "thiserror" version = "1.0.40" @@ -1235,6 +1574,17 @@ dependencies = [ "syn 2.0.15", ] +[[package]] +name = "tiff" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "toml" version = "0.7.3" @@ -1305,6 +1655,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1387,6 +1747,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + [[package]] name = "widestring" version = "1.0.2" @@ -1609,3 +1975,12 @@ dependencies = [ "libc", "pkg-config", ] + +[[package]] +name = "zune-inflate" +version = "0.2.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01728b79fb9b7e28a8c11f715e1cd8dc2cda7416a007d66cac55cebb3a8ac6b" +dependencies = [ + "simd-adler32", +] diff --git a/Cargo.toml b/Cargo.toml index acdbd5b..4aed34a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,9 @@ env_logger = "0.10.0" zstd = "0.12.3" clap = { version = "4.2.2", features = ["derive"] } directories = "5.0.0" +texture_packer = "0.25.0" +walkdir = "2.3.3" +image = "0.24.6" [dependencies.s2dc] #git = "https://github.com/crumblingstatue/s2dc.git" diff --git a/res/graphics/light2.png b/res/graphics/light/1.png similarity index 100% rename from res/graphics/light2.png rename to res/graphics/light/1.png diff --git a/res/graphics/tiles.png b/res/graphics/tiles.png deleted file mode 100644 index e5f9e0a..0000000 Binary files a/res/graphics/tiles.png and /dev/null differ diff --git a/res/graphics/tiles/dirt.png b/res/graphics/tiles/dirt.png new file mode 100644 index 0000000..7795ff1 Binary files /dev/null and b/res/graphics/tiles/dirt.png differ diff --git a/res/graphics/tiles/stone.png b/res/graphics/tiles/stone.png new file mode 100644 index 0000000..f8aa68e Binary files /dev/null and b/res/graphics/tiles/stone.png differ diff --git a/res/graphics/tiles/unknown.png b/res/graphics/tiles/unknown.png new file mode 100644 index 0000000..991c377 Binary files /dev/null and b/res/graphics/tiles/unknown.png differ diff --git a/src/app.rs b/src/app.rs index 701db21..31e7b91 100644 --- a/src/app.rs +++ b/src/app.rs @@ -59,7 +59,7 @@ impl App { Ok(Self { rw, should_quit: false, - game: GameState::new(args.world_name, path), + game: GameState::new(args.world_name, path, &res), res, sf_egui, input: Input::default(), diff --git a/src/game.rs b/src/game.rs index 81c2288..ab2c282 100644 --- a/src/game.rs +++ b/src/game.rs @@ -50,16 +50,16 @@ impl GameState { } pub(crate) fn draw_world(&mut self, rt: &mut RenderTexture, res: &mut Res) { self.light_sources.clear(); - let mut s = Sprite::with_texture(&res.tile_atlas); + let mut s = Sprite::with_texture(&res.atlas.tex); for_each_tile_on_screen(self.camera_offset, rt.size(), |tp, sp| { let tile = self.world.tile_at_mut(tp, &self.worldgen); s.set_position(sp.to_sf_vec()); if tile.bg != Tile::EMPTY { - s.set_texture_rect(self.tile_db[tile.bg].atlas_offset.to_sf_rect()); + s.set_texture_rect(self.tile_db[tile.bg].tex_rect.to_sf()); rt.draw(&s); } if tile.mid != Tile::EMPTY { - s.set_texture_rect(self.tile_db[tile.mid].atlas_offset.to_sf_rect()); + s.set_texture_rect(self.tile_db[tile.mid].tex_rect.to_sf()); if let Some(light) = self.tile_db[tile.mid].light { let pos = ScreenVec { x: sp.x + light.x, @@ -70,7 +70,7 @@ impl GameState { rt.draw(&s); } if tile.fg != Tile::EMPTY { - s.set_texture_rect(self.tile_db[tile.fg].atlas_offset.to_sf_rect()); + s.set_texture_rect(self.tile_db[tile.fg].tex_rect.to_sf()); rt.draw(&s); } }); @@ -106,8 +106,9 @@ impl GameState { self.ambient_light, 255, )); + let mut s = Sprite::with_texture(&res.atlas.tex); + s.set_texture_rect(res.atlas.rects["light/1"].to_sf()); for ls in &self.light_sources { - let mut s = Sprite::with_texture(&res.light_texture); let flicker = smoothwave(self.world.ticks, 40) as f32 / 64.0; s.set_scale((4. + flicker, 4. + flicker)); s.set_origin((128., 128.)); @@ -116,9 +117,11 @@ impl GameState { } } - pub(crate) fn new(world_name: String, path: PathBuf) -> GameState { + pub(crate) fn new(world_name: String, path: PathBuf, res: &Res) -> GameState { let mut spawn_point = WorldPos::SURFACE_CENTER; spawn_point.y -= 1104; + let mut tile_db = TileDb::load_or_default(); + tile_db.update_rects(&res.atlas.rects); Self { camera_offset: spawn_point, world: World::new(spawn_point, &world_name, path), @@ -129,7 +132,7 @@ impl GameState { worldgen: Worldgen::from_seed(0), ambient_light: 0, light_sources: Vec::new(), - tile_db: TileDb::load_or_default(), + tile_db, } } } diff --git a/src/main.rs b/src/main.rs index 33f4ce7..c417982 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ mod math; mod player; mod res; mod stringfmt; +mod texture_atlas; mod tiles; mod world; mod worldgen; diff --git a/src/math.rs b/src/math.rs index 6ff2a10..622e55b 100644 --- a/src/math.rs +++ b/src/math.rs @@ -1,5 +1,8 @@ +use std::fmt::Debug; + use egui_inspect::derive::Inspect; use num_traits::{Num, Signed}; +use serde::{Deserialize, Serialize}; use crate::world::{TPosSc, TilePos}; @@ -81,6 +84,24 @@ pub fn smoothwave + PartialOrd + Copy>(input: T, max: T) -> T } } +#[derive(Serialize, Deserialize, Debug, Inspect, Default, Clone, Copy)] +pub struct IntRect { + pub x: i32, + pub y: i32, + pub w: i32, + pub h: i32, +} +impl IntRect { + pub(crate) fn to_sf(&self) -> sfml::graphics::Rect { + sfml::graphics::Rect:: { + left: self.x, + top: self.y, + width: self.w, + height: self.h, + } + } +} + #[test] fn test_smooth_wave() { assert_eq!(smoothwave(0, 100), 0); diff --git a/src/res.rs b/src/res.rs index 3d725a5..be8a15f 100644 --- a/src/res.rs +++ b/src/res.rs @@ -1,9 +1,10 @@ -use sfml::{audio::Music, graphics::Texture, SfBox}; +use sfml::audio::Music; + +use crate::texture_atlas::AtlasBundle; #[derive(Debug)] pub struct Res { - pub tile_atlas: SfBox, - pub light_texture: SfBox, + pub atlas: AtlasBundle, pub surf_music: Music<'static>, pub und_music: Music<'static>, } @@ -11,8 +12,7 @@ pub struct Res { impl Res { pub fn load() -> anyhow::Result { Ok(Self { - tile_atlas: Texture::from_file("res/graphics/tiles.png")?, - light_texture: Texture::from_file("res/graphics/light2.png")?, + atlas: AtlasBundle::new()?, surf_music: Music::from_file("res/music/music.ogg").unwrap(), und_music: Music::from_file("res/music/cave2.ogg").unwrap(), }) diff --git a/src/texture_atlas.rs b/src/texture_atlas.rs new file mode 100644 index 0000000..a4535c6 --- /dev/null +++ b/src/texture_atlas.rs @@ -0,0 +1,102 @@ +use std::{collections::HashMap, path::Path}; + +use crate::math::IntRect; +use sfml::{graphics::Texture, SfBox}; +use texture_packer::{texture::Texture as _, TexturePacker, TexturePackerConfig}; + +pub type RectMap = HashMap; + +#[derive(Debug)] +pub struct AtlasBundle { + pub tex: SfBox, + // Key could be `tiles/dirt` for example, derived from folder+filename without extension + pub rects: RectMap, +} + +impl AtlasBundle { + pub fn new() -> anyhow::Result { + let cfg = TexturePackerConfig { + max_width: 4096, + max_height: 4096, + allow_rotation: false, + border_padding: 0, + texture_padding: 1, + texture_extrusion: 0, + trim: true, + texture_outlines: false, + }; + let mut packer = TexturePacker::new_skyline(cfg); + walk_graphics(|path| { + let img = image::open(path).unwrap(); + let key = path_img_key(path); + packer.pack_own(key, img).unwrap(); + dbg!(path); + }); + let mut rects = HashMap::new(); + let mut tex = Texture::new().unwrap(); + if !tex.create(packer.width(), packer.height()) { + panic!("Failed to create texture"); + } + let pixbuf = make_pix_buf(&packer); + unsafe { + tex.update_from_pixels(&pixbuf, packer.width(), packer.height(), 0, 0); + } + for (k, frame) in packer.get_frames() { + rects.insert( + k.clone(), + IntRect { + x: frame.frame.x as i32, + y: frame.frame.y as i32, + w: frame.frame.w as i32, + h: frame.frame.h as i32, + }, + ); + } + Ok(AtlasBundle { tex, rects }) + } +} + +fn make_pix_buf(packer: &TexturePacker) -> Vec { + let (w, h) = (packer.width(), packer.height()); + let px_size = 4; + let mut vec = vec![0; w as usize * h as usize * px_size as usize]; + dbg!(w, h); + for y in 0..h { + for x in 0..w { + let idx = ((y * w + x) * px_size) as usize; + if let Some(px) = packer.get(x, y) { + vec[idx..idx + px_size as usize].copy_from_slice(&px.0); + } + } + } + vec +} + +fn path_img_key(path: &Path) -> String { + let mut rev_iter = path.components().rev(); + let fname = rev_iter.next().unwrap(); + let folder = rev_iter.next().unwrap(); + let fname: &Path = fname.as_ref(); + let folder: &Path = folder.as_ref(); + folder + .join(fname.file_stem().unwrap()) + .display() + .to_string() +} + +#[test] +fn test_path_img_key() { + assert_eq!( + &path_img_key("/home/person/res/graphics/tiles/foo.png".as_ref()), + "tiles/foo" + ); +} + +fn walk_graphics(mut f: impl FnMut(&Path)) { + for en in walkdir::WalkDir::new("res/graphics") { + let en = en.unwrap(); + if en.file_type().is_file() { + f(en.path()); + } + } +} diff --git a/src/tiles.rs b/src/tiles.rs index af5101f..dcb25de 100644 --- a/src/tiles.rs +++ b/src/tiles.rs @@ -4,11 +4,11 @@ use std::ops::Index; use egui_inspect::derive::Inspect; use serde::{Deserialize, Serialize}; -use sfml::graphics::IntRect; use crate::{ graphics::{ScreenSc, ScreenVec}, - math::TILE_SIZE, + math::{IntRect, TILE_SIZE}, + texture_atlas::RectMap, world::TileId, }; @@ -17,9 +17,11 @@ pub struct TileDef { pub bb: Option, /// Whether the tile emits light, and the light source offset pub light: Option, - pub atlas_offset: AtlasOffset, /// Platform behavior: Horizontally passable, vertically passable upwards pub platform: bool, + #[serde(default)] + pub graphic_name: String, + pub tex_rect: IntRect, } const DEFAULT_TILE_BB: TileBb = TileBb { @@ -44,9 +46,18 @@ pub struct TileDb { impl Default for TileDb { fn default() -> Self { + let unknown = TileDef { + bb: None, + light: Some(ScreenVec { + x: TILE_SIZE as ScreenSc / 2, + y: TILE_SIZE as ScreenSc / 2, + }), + platform: false, + graphic_name: String::from("tiles/unknown"), + tex_rect: IntRect::default(), + }; Self { - // Add empty/air tile - db: vec![EMPTY], + db: vec![EMPTY, unknown], } } } @@ -56,52 +67,26 @@ const EMPTY: TileDef = TileDef { light: None, // Rendering empty tile is actually special cased, and no rendering is done. // But just in case, put the offset to UNKNOWN - atlas_offset: UNKNOWN_ATLAS_OFF, + tex_rect: IntRect { + x: 0, + y: 0, + w: 0, + h: 0, + }, platform: false, + graphic_name: String::new(), }; impl Index for TileDb { type Output = TileDef; fn index(&self, index: TileId) -> &Self::Output { - self.db.get(index as usize).unwrap_or(&UNKNOWN_TILE) + self.db.get(index as usize).unwrap_or_else(|| { + &self.db[1] // Unknown tile def is stored at index 1 + }) } } -#[derive(Debug, Inspect, Serialize, Deserialize)] -pub struct AtlasOffset { - pub x: u16, - pub y: u16, -} -impl AtlasOffset { - pub(crate) fn to_sf_rect(&self) -> IntRect { - IntRect { - left: self.x as i32, - top: self.y as i32, - width: TILE_SIZE as i32, - height: TILE_SIZE as i32, - } - } -} - -impl Default for AtlasOffset { - fn default() -> Self { - UNKNOWN_ATLAS_OFF - } -} - -const UNKNOWN_ATLAS_OFF: AtlasOffset = AtlasOffset { x: 320, y: 0 }; - -static UNKNOWN_TILE: TileDef = TileDef { - bb: None, - light: Some(ScreenVec { - x: TILE_SIZE as ScreenSc / 2, - y: TILE_SIZE as ScreenSc / 2, - }), - atlas_offset: UNKNOWN_ATLAS_OFF, - platform: false, -}; - const PATH: &str = "tiles.dat"; impl TileDb { @@ -129,4 +114,12 @@ impl TileDb { Err(e) => log::warn!("Failed to save tile db: {e}"), } } + + pub(crate) fn update_rects(&mut self, rects: &RectMap) { + for def in &mut self.db { + if !def.graphic_name.is_empty() { + def.tex_rect = rects[&def.graphic_name]; + } + } + } } diff --git a/src/world.rs b/src/world.rs index 2fe90ed..f7546c7 100644 --- a/src/world.rs +++ b/src/world.rs @@ -78,7 +78,7 @@ impl World { chk.at_mut(local) } pub fn save(&self) { - let result = std::fs::create_dir(&self.path); + let result = std::fs::create_dir_all(&self.path); log::info!("{result:?}"); self.save_meta(); self.player.save(&self.path); diff --git a/src/worldgen.rs b/src/worldgen.rs index 1ccb862..97ad339 100644 --- a/src/worldgen.rs +++ b/src/worldgen.rs @@ -34,7 +34,7 @@ impl Worldgen { .add( Tile::new(Tl { bg: 9, - mid: 2, + mid: 3, fg: 6, }) .when(constraint!(nm.clone(), < -0.8)), @@ -43,7 +43,7 @@ impl Worldgen { .add( Tile::new(Tl { bg: 9, - mid: 2, + mid: 3, fg: 0, }) .when(constraint!(nm.clone(), < -0.1)), @@ -52,7 +52,7 @@ impl Worldgen { .add( Tile::new(Tl { bg: 7, - mid: 1, + mid: 2, fg: 0, }) .when(constraint!(nm, < 0.45)), diff --git a/tiles.dat b/tiles.dat index daf63fb..883db81 100644 Binary files a/tiles.dat and b/tiles.dat differ