From 437d6249d37fe60dca86ab8d95168837ddf44bdc Mon Sep 17 00:00:00 2001 From: caelunshun Date: Tue, 24 Mar 2020 17:10:42 -0600 Subject: [PATCH 1/5] Work on dev tools GUI for testing out noise parameters --- Cargo.lock | 1245 ++++++++++++++++++++++- imgui.ini | 5 + server/Cargo.toml | 21 +- server/src/devtools.rs | 217 ++++ server/src/lib.rs | 38 + server/src/worldgen/biomes/grid/mod.rs | 132 +++ server/src/worldgen/biomes/grid/zoom.rs | 70 ++ server/src/worldgen/biomes/mod.rs | 2 + server/src/worldgen/devtools/mod.rs | 349 +++++++ server/src/worldgen/mod.rs | 4 +- server/src/worldgen/util.rs | 4 + 11 files changed, 2048 insertions(+), 39 deletions(-) create mode 100644 imgui.ini create mode 100644 server/src/devtools.rs create mode 100644 server/src/worldgen/biomes/grid/mod.rs create mode 100644 server/src/worldgen/biomes/grid/zoom.rs create mode 100644 server/src/worldgen/devtools/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 820afdd1e..63c21ba0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,6 +59,26 @@ dependencies = [ "num-traits 0.2.11", ] +[[package]] +name = "andrew" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7f09f89872c2b6b29e319377b1fbe91c6f5947df19a25596e121cf19a7b35e" +dependencies = [ + "bitflags", + "line_drawing", + "rusttype 0.7.9", + "walkdir", + "xdg", + "xml-rs", +] + +[[package]] +name = "android_glue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" + [[package]] name = "ansi_term" version = "0.11.0" @@ -95,6 +115,12 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7b8a9123b8027467bce0099fe556c628a53c8d83df0507084c31e9ba2e39aff" +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + [[package]] name = "arrayvec" version = "0.5.1" @@ -112,6 +138,21 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "ash" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003d1fb2eb12eb06d4a03dbe02eea67a9fac910fa97932ab9e3a75b96a1ea5e5" +dependencies = [ + "shared_library", +] + +[[package]] +name = "atom" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c86699c3f02778ec07158376991c8f783dd1f2f95c579ffaf0738dc984b2fe2" + [[package]] name = "atty" version = "0.2.14" @@ -200,6 +241,22 @@ dependencies = [ "radium", ] +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" +dependencies = [ + "arrayref", + "byte-tools", +] + [[package]] name = "block-cipher-trait" version = "0.6.2" @@ -227,6 +284,12 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f359dc14ff8911330a51ef78022d376f25ed00248912803b58f00cb1c27f742" +[[package]] +name = "byte-tools" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" + [[package]] name = "byteorder" version = "1.3.2" @@ -248,6 +311,17 @@ dependencies = [ "ppv-lite86", ] +[[package]] +name = "calloop" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa2097be53a00de9e8fc349fea6d76221f398f5c4fa550d420669906962d160" +dependencies = [ + "mio", + "mio-extras", + "nix 0.14.1", +] + [[package]] name = "cast" version = "0.2.3" @@ -321,6 +395,30 @@ dependencies = [ "bitflags", ] +[[package]] +name = "cmake" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" +dependencies = [ + "cc", +] + +[[package]] +name = "cocoa" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29f7768b2d1be17b96158e3285951d366b40211320fb30826a76cb7a0da6400" +dependencies = [ + "bitflags", + "block", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + [[package]] name = "colored" version = "1.9.2" @@ -332,6 +430,12 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "colorful" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bca1619ff57dd7a56b58a8e25ef4199f123e78e503fe1653410350a1b98ae65" + [[package]] name = "const-random" version = "0.1.6" @@ -349,9 +453,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c750ec12b83377637110d5a57f5ae08e895b06c4b16e2bdbf1a94ef717428c59" dependencies = [ "proc-macro-hack", - "rand", + "rand 0.7.3", ] +[[package]] +name = "copyless" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff9c56c9fb2a49c05ef0e431485a22400af20d33226dc0764d891d09e724127" + [[package]] name = "core-foundation" version = "0.6.4" @@ -368,6 +478,31 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" +[[package]] +name = "core-graphics" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9" +dependencies = [ + "bitflags", + "core-foundation", + "foreign-types", + "libc", +] + +[[package]] +name = "core-video-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc065219542086f72d1e9f7aadbbab0989e980263695d129d502082d063a9d0" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "core-graphics", + "libc", + "objc", +] + [[package]] name = "crc32fast" version = "1.2.0" @@ -391,8 +526,8 @@ dependencies = [ "itertools 0.8.2", "lazy_static", "num-traits 0.2.11", - "rand_core", - "rand_os", + "rand_core 0.5.1", + "rand_os 0.2.2", "rand_xoshiro", "rayon", "serde", @@ -518,7 +653,18 @@ version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7dfd2d8b4c82121dfdff120f818e09fc4380b0b7e17a742081a89b94853e87f" dependencies = [ - "nix", + "nix 0.14.1", + "winapi 0.3.8", +] + +[[package]] +name = "d3d12" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7ed48e89905e5e146bcc1951cc3facb9e44aea9adf5dc01078cda1bd24b662" +dependencies = [ + "bitflags", + "libloading", "winapi 0.3.8", ] @@ -566,6 +712,30 @@ dependencies = [ "syn 0.15.44", ] +[[package]] +name = "digest" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" +dependencies = [ + "generic-array 0.9.0", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" +dependencies = [ + "libloading", +] + [[package]] name = "downcast-rs" version = "1.1.1" @@ -612,9 +782,15 @@ dependencies = [ "proc-macro2 1.0.7", "quote 1.0.2", "syn 1.0.13", - "synstructure", + "synstructure 0.12.3", ] +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + [[package]] name = "feather-blocks" version = "0.5.0" @@ -666,12 +842,12 @@ dependencies = [ "nalgebra-glm", "num-derive", "num-traits 0.2.11", - "parking_lot", + "parking_lot 0.10.0", "rayon", "serde", "serde_json", "serde_with", - "smallvec", + "smallvec 1.2.0", "strum 0.18.0", "strum_macros 0.18.0", "thiserror", @@ -744,6 +920,9 @@ dependencies = [ "heapless", "hematite-nbt", "humantime-serde", + "imgui", + "imgui-wgpu", + "imgui-winit-support", "indexmap", "inventory", "itertools 0.9.0", @@ -751,6 +930,7 @@ dependencies = [ "lazy_static", "lock_api", "log", + "minifb", "mojang-api", "multimap", "nalgebra", @@ -759,10 +939,10 @@ dependencies = [ "num-bigint-dig", "num-derive", "num-traits 0.2.11", - "parking_lot", - "rand", + "parking_lot 0.10.0", + "rand 0.7.3", "rand_distr", - "rand_xorshift", + "rand_xorshift 0.2.0", "rayon", "rsa", "rsa-der", @@ -771,7 +951,8 @@ dependencies = [ "simdeez", "simdnoise", "simple_logger", - "smallvec", + "smallvec 1.2.0", + "structopt", "strum 0.18.0", "thiserror", "thread_local", @@ -779,6 +960,8 @@ dependencies = [ "tokio-util", "toml", "uuid", + "wgpu", + "winit", ] [[package]] @@ -867,6 +1050,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -983,6 +1172,15 @@ dependencies = [ "byteorder", ] +[[package]] +name = "generic-array" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" +dependencies = [ + "typenum", +] + [[package]] name = "generic-array" version = "0.12.3" @@ -1012,6 +1210,123 @@ dependencies = [ "wasi", ] +[[package]] +name = "gfx-auxil" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572eee952a9a23c99cfe3e4fd95d277784058a89ac3c77ff6fa3d80a4e321919" +dependencies = [ + "fxhash", + "gfx-hal", + "spirv_cross", +] + +[[package]] +name = "gfx-backend-dx11" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f6df16109433f998a95c4b0c48738100fde9c7ce4c1c4885df1cc78db9115e" +dependencies = [ + "bitflags", + "gfx-auxil", + "gfx-hal", + "libloading", + "log", + "parking_lot 0.9.0", + "range-alloc", + "raw-window-handle", + "smallvec 0.6.13", + "spirv_cross", + "winapi 0.3.8", + "wio", +] + +[[package]] +name = "gfx-backend-dx12" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "305620be6365b7dd8ef8e2bf320174f7aad4a23efb34136ee5b4d4d28bbe1714" +dependencies = [ + "bitflags", + "d3d12", + "gfx-auxil", + "gfx-hal", + "log", + "range-alloc", + "raw-window-handle", + "smallvec 0.6.13", + "spirv_cross", + "winapi 0.3.8", +] + +[[package]] +name = "gfx-backend-empty" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d383e6bc48867cb37d298a20139fd1eec298f8f6d594690cd1c50ef25470cc7" +dependencies = [ + "gfx-hal", + "raw-window-handle", +] + +[[package]] +name = "gfx-backend-metal" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071c004009c55a07bad2559b53a399ec3de30e7a08019bc06d53a40f653ffacd" +dependencies = [ + "arrayvec", + "bitflags", + "block", + "cocoa", + "copyless", + "core-graphics", + "foreign-types", + "gfx-auxil", + "gfx-hal", + "lazy_static", + "log", + "metal", + "objc", + "parking_lot 0.9.0", + "range-alloc", + "raw-window-handle", + "smallvec 0.6.13", + "spirv_cross", + "storage-map", +] + +[[package]] +name = "gfx-backend-vulkan" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9a9de46ec24543193d5dabad3a79e5ede990878bace548758846292466d916" +dependencies = [ + "arrayvec", + "ash", + "byteorder", + "core-graphics", + "gfx-hal", + "lazy_static", + "log", + "objc", + "raw-window-handle", + "smallvec 0.6.13", + "winapi 0.3.8", + "x11", +] + +[[package]] +name = "gfx-hal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c88981665c780447bb08eb099e1ded330754a7246719bab927ee4a949c0ba7f" +dependencies = [ + "bitflags", + "raw-window-handle", + "smallvec 0.6.13", +] + [[package]] name = "ghost" version = "0.1.1" @@ -1023,6 +1338,17 @@ dependencies = [ "syn 1.0.13", ] +[[package]] +name = "glsl-to-spirv" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28caebc98746d507603a2d3df66dcbe04e41d4febad0320f3eec1ef72b6bbef1" +dependencies = [ + "cmake", + "sha2", + "tempfile", +] + [[package]] name = "h2" version = "0.2.1" @@ -1115,6 +1441,15 @@ dependencies = [ "libc", ] +[[package]] +name = "hibitset" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93a1bb8316a44459a7d14253c4d28dd7395cbd23cc04a68c46e851b8e46d64b1" +dependencies = [ + "atom", +] + [[package]] name = "http" version = "0.2.0" @@ -1206,6 +1541,49 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "imgui" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a2d28cee2982d4dab4dd954c23be339ab1f98be4ff5a13ecd8fbfb47cdfa23a" +dependencies = [ + "bitflags", + "imgui-sys", + "lazy_static", + "parking_lot 0.10.0", +] + +[[package]] +name = "imgui-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a8693e0f66ecd2ec10e2f0ed4dc4519071495f350e6d8ddaf3e70351229257" +dependencies = [ + "cc", +] + +[[package]] +name = "imgui-wgpu" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877d4e7adb5523e25bcfd64f9dc47b3f6c2fbf452e99cbd0a21ca2740b0384ba" +dependencies = [ + "glsl-to-spirv", + "imgui", + "log", + "wgpu", +] + +[[package]] +name = "imgui-winit-support" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5685c7d17aee9555377f9c4f7b6fac96899a7015f6b41950c613a3df034aff08" +dependencies = [ + "imgui", + "winit", +] + [[package]] name = "indexmap" version = "1.3.0" @@ -1216,6 +1594,12 @@ dependencies = [ "serde", ] +[[package]] +name = "instant" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c346c299e3fe8ef94dc10c2c0253d858a69aac1245157a3bf4125915d528caf" + [[package]] name = "inventory" version = "0.1.5" @@ -1320,6 +1704,12 @@ dependencies = [ "spin", ] +[[package]] +name = "lazycell" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" + [[package]] name = "legion" version = "0.2.1" @@ -1339,9 +1729,9 @@ dependencies = [ "downcast-rs", "fxhash", "itertools 0.8.2", - "parking_lot", + "parking_lot 0.10.0", "rayon", - "smallvec", + "smallvec 1.2.0", "thiserror", "tracing", ] @@ -1370,6 +1760,16 @@ version = "0.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +[[package]] +name = "libloading" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" +dependencies = [ + "cc", + "winapi 0.3.8", +] + [[package]] name = "libm" version = "0.1.4" @@ -1382,6 +1782,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" +[[package]] +name = "line_drawing" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" +dependencies = [ + "num-traits 0.2.11", +] + [[package]] name = "lock_api" version = "0.3.3" @@ -1400,6 +1809,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + [[package]] name = "matches" version = "0.1.8" @@ -1416,14 +1834,30 @@ dependencies = [ ] [[package]] -name = "memchr" -version = "2.3.0" +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memchr" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" dependencies = [ "libc", ] +[[package]] +name = "memmap" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +dependencies = [ + "libc", + "winapi 0.3.8", +] + [[package]] name = "memoffset" version = "0.5.3" @@ -1433,6 +1867,21 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "metal" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83c7dcc2038e12f68493fa3de44235df27b2497178e257185b4b5b5d028a1e4" +dependencies = [ + "bitflags", + "block", + "cocoa", + "core-graphics", + "foreign-types", + "log", + "objc", +] + [[package]] name = "mime" version = "0.3.16" @@ -1449,6 +1898,24 @@ dependencies = [ "unicase", ] +[[package]] +name = "minifb" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128502f9d895b6d84db78114f87918a598894e9c4616ef2c1792bdbbdf8ee0cf" +dependencies = [ + "cast", + "cc", + "orbclient", + "raw-window-handle", + "tempfile", + "time", + "wayland-client 0.24.1", + "wayland-protocols 0.24.1", + "winapi 0.3.8", + "x11-dl", +] + [[package]] name = "miniz-sys" version = "0.1.12" @@ -1487,6 +1954,18 @@ dependencies = [ "winapi 0.2.8", ] +[[package]] +name = "mio-extras" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" +dependencies = [ + "lazycell", + "log", + "mio", + "slab", +] + [[package]] name = "mio-named-pipes" version = "0.1.6" @@ -1570,7 +2049,7 @@ dependencies = [ "num-complex", "num-rational", "num-traits 0.2.11", - "rand", + "rand 0.7.3", "rand_distr", "typenum", ] @@ -1621,7 +2100,7 @@ dependencies = [ "petgraph 0.5.0", "slab", "slotmap", - "smallvec", + "smallvec 1.2.0", ] [[package]] @@ -1648,6 +2127,19 @@ dependencies = [ "void", ] +[[package]] +name = "nix" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "void", +] + [[package]] name = "nom" version = "4.2.3" @@ -1658,6 +2150,17 @@ dependencies = [ "version_check 0.1.5", ] +[[package]] +name = "num" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +dependencies = [ + "num-integer", + "num-iter", + "num-traits 0.2.11", +] + [[package]] name = "num-bigint" version = "0.2.5" @@ -1682,9 +2185,9 @@ dependencies = [ "num-integer", "num-iter", "num-traits 0.2.11", - "rand", + "rand 0.7.3", "serde", - "smallvec", + "smallvec 1.2.0", "zeroize", ] @@ -1769,6 +2272,25 @@ dependencies = [ "libc", ] +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + [[package]] name = "opaque-debug" version = "0.2.3" @@ -1808,12 +2330,42 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "orbclient" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8b18f57ab94fbd058e30aa57f712ec423c0bb7403f8493a6c58eef0c36d9402" +dependencies = [ + "redox_syscall", + "sdl2", +] + +[[package]] +name = "ordered-float" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" +dependencies = [ + "num-traits 0.2.11", +] + [[package]] name = "ordermap" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" +[[package]] +name = "parking_lot" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" +dependencies = [ + "lock_api", + "parking_lot_core 0.6.2", + "rustc_version", +] + [[package]] name = "parking_lot" version = "0.10.0" @@ -1821,7 +2373,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.7.0", +] + +[[package]] +name = "parking_lot_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "rustc_version", + "smallvec 0.6.13", + "winapi 0.3.8", ] [[package]] @@ -1836,7 +2403,7 @@ dependencies = [ "libc", "petgraph 0.4.13", "redox_syscall", - "smallvec", + "smallvec 1.2.0", "thread-id", "winapi 0.3.8", ] @@ -1933,6 +2500,32 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +[[package]] +name = "proc-macro-error" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2 1.0.7", + "quote 1.0.2", + "syn 1.0.13", + "version_check 0.9.1", +] + +[[package]] +name = "proc-macro-error-attr" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" +dependencies = [ + "proc-macro2 1.0.7", + "quote 1.0.2", + "syn 1.0.13", + "syn-mid", + "version_check 0.9.1", +] + [[package]] name = "proc-macro-hack" version = "0.5.11" @@ -2010,6 +2603,25 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc 0.1.0", + "rand_isaac", + "rand_jitter", + "rand_os 0.1.3", + "rand_pcg", + "rand_xorshift 0.1.1", + "winapi 0.3.8", +] + [[package]] name = "rand" version = "0.7.3" @@ -2018,9 +2630,19 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ "getrandom", "libc", - "rand_chacha", - "rand_core", - "rand_hc", + "rand_chacha 0.2.1", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", ] [[package]] @@ -2030,9 +2652,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" dependencies = [ "c2-chacha", - "rand_core", + "rand_core 0.5.1", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.5.1" @@ -2048,7 +2685,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2" dependencies = [ - "rand", + "rand 0.7.3", +] + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", ] [[package]] @@ -2057,7 +2703,41 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi 0.3.8", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi 0.3.8", ] [[package]] @@ -2067,7 +2747,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" dependencies = [ "getrandom", - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", ] [[package]] @@ -2076,7 +2775,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" dependencies = [ - "rand_core", + "rand_core 0.5.1", ] [[package]] @@ -2085,7 +2784,22 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff" dependencies = [ - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "range-alloc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5927936723a9e8b715d37d7e4b390455087c4bdf25b9f702309460577b14f9" + +[[package]] +name = "raw-window-handle" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211" +dependencies = [ + "libc", ] [[package]] @@ -2118,6 +2832,15 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "redox_syscall" version = "0.1.56" @@ -2133,6 +2856,16 @@ dependencies = [ "byteorder", ] +[[package]] +name = "relevant" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc232e13d37f4547f5b9b42a5efc380cabe5dbc1807f8b893580640b2ab0308" +dependencies = [ + "cfg-if", + "log", +] + [[package]] name = "remove_dir_all" version = "0.5.2" @@ -2142,6 +2875,33 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "rendy-descriptor" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f475bcc0505946e998590f1f0545c52ef4b559174a1b353a7ce6638def8b621e" +dependencies = [ + "gfx-hal", + "log", + "relevant", + "smallvec 0.6.13", +] + +[[package]] +name = "rendy-memory" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed492161a819feae7f27f418bb16035276ac20649c60d756699152cb5c1960ec" +dependencies = [ + "colorful", + "gfx-hal", + "hibitset", + "log", + "relevant", + "slab", + "smallvec 0.6.13", +] + [[package]] name = "reqwest" version = "0.10.3" @@ -2190,7 +2950,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits 0.2.11", - "rand", + "rand 0.7.3", "subtle", "zeroize", ] @@ -2219,6 +2979,27 @@ dependencies = [ "semver", ] +[[package]] +name = "rusttype" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310942406a39981bed7e12b09182a221a29e0990f3e7e0c971f131922ed135d5" +dependencies = [ + "rusttype 0.8.2", +] + +[[package]] +name = "rusttype" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14a911032fb5791ccbeec9f28fdcb9bf0983b81f227bafdfd227c658d0731c8a" +dependencies = [ + "approx 0.3.2", + "arrayvec", + "ordered-float", + "stb_truetype", +] + [[package]] name = "ryu" version = "1.0.2" @@ -2250,6 +3031,30 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +[[package]] +name = "sdl2" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d051a07231e303f5f719da78cb6f7394f6d5b54f733aef5b0b447804a83edd7b" +dependencies = [ + "bitflags", + "lazy_static", + "libc", + "num", + "rand 0.6.5", + "sdl2-sys", +] + +[[package]] +name = "sdl2-sys" +version = "0.32.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86" +dependencies = [ + "cfg-if", + "libc", +] + [[package]] name = "security-framework" version = "0.3.4" @@ -2356,6 +3161,28 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" +[[package]] +name = "sha2" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" +dependencies = [ + "block-buffer", + "byte-tools", + "digest", + "fake-simd", +] + +[[package]] +name = "shared_library" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" +dependencies = [ + "lazy_static", + "libc", +] + [[package]] name = "signal-hook-registry" version = "1.2.0" @@ -2421,12 +3248,37 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c46a3482db8f247956e464d783693ece164ca056e6e67563ee5505bdb86452cd" +[[package]] +name = "smallvec" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" +dependencies = [ + "maybe-uninit", +] + [[package]] name = "smallvec" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" +[[package]] +name = "smithay-client-toolkit" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421c8dc7acf5cb205b88160f8b4cc2c5cfabe210e43b2f80f009f4c1ef910f1d" +dependencies = [ + "andrew", + "bitflags", + "dlib", + "lazy_static", + "memmap", + "nix 0.14.1", + "wayland-client 0.23.6", + "wayland-protocols 0.23.6", +] + [[package]] name = "socket2" version = "0.3.11" @@ -2451,6 +3303,17 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spirv_cross" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbbe441b3ac8ec0ae6a4f05234239bd372a241ce15793eef694e8b24afc267bb" +dependencies = [ + "cc", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "stable_deref_trait" version = "1.1.1" @@ -2463,6 +3326,24 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" +[[package]] +name = "stb_truetype" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" +dependencies = [ + "byteorder", +] + +[[package]] +name = "storage-map" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd0a4829a5c591dc24a944a736d6b1e4053e51339a79fd5d4702c4c999a9c45e" +dependencies = [ + "lock_api", +] + [[package]] name = "stream-cipher" version = "0.3.2" @@ -2478,6 +3359,30 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +[[package]] +name = "structopt" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8faa2719539bbe9d77869bfb15d4ee769f99525e707931452c97b693b3f159d" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f88b8e18c69496aad6f9ddf4630dd7d585bcaf765786cb415b9aec2fe5a0430" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2 1.0.7", + "quote 1.0.2", + "syn 1.0.13", +] + [[package]] name = "strum" version = "0.16.0" @@ -2553,6 +3458,29 @@ dependencies = [ "unicode-xid 0.2.0", ] +[[package]] +name = "syn-mid" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" +dependencies = [ + "proc-macro2 1.0.7", + "quote 1.0.2", + "syn 1.0.13", +] + +[[package]] +name = "synstructure" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", + "unicode-xid 0.1.0", +] + [[package]] name = "synstructure" version = "0.12.3" @@ -2573,7 +3501,7 @@ checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ "cfg-if", "libc", - "rand", + "rand 0.7.3", "redox_syscall", "remove_dir_all", "winapi 0.3.8", @@ -2789,7 +3717,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf" dependencies = [ - "smallvec", + "smallvec 1.2.0", ] [[package]] @@ -2833,7 +3761,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" dependencies = [ - "rand", + "rand 0.7.3", "serde", ] @@ -2991,6 +3919,122 @@ dependencies = [ "weedle", ] +[[package]] +name = "wayland-client" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda" +dependencies = [ + "bitflags", + "calloop", + "downcast-rs", + "libc", + "mio", + "nix 0.14.1", + "wayland-commons 0.23.6", + "wayland-scanner 0.23.6", + "wayland-sys 0.23.6", +] + +[[package]] +name = "wayland-client" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bcc929c26d59a655b0d2cd337299326acc1f6e3d4434c3ae2d6c78d32290ca4" +dependencies = [ + "bitflags", + "downcast-rs", + "libc", + "nix 0.15.0", + "wayland-commons 0.24.1", + "wayland-scanner 0.24.1", + "wayland-sys 0.24.1", +] + +[[package]] +name = "wayland-commons" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb" +dependencies = [ + "nix 0.14.1", + "wayland-sys 0.23.6", +] + +[[package]] +name = "wayland-commons" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "539cdd0c296802332d763ff663739a7f83bdf67b3df58e99fe0215e96a495142" +dependencies = [ + "nix 0.15.0", + "smallvec 0.6.13", + "spin", + "wayland-sys 0.24.1", +] + +[[package]] +name = "wayland-protocols" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9" +dependencies = [ + "bitflags", + "wayland-client 0.23.6", + "wayland-commons 0.23.6", + "wayland-scanner 0.23.6", +] + +[[package]] +name = "wayland-protocols" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79df44471a2e01b61c089472443858062fa64ea60dfd24267848efd7a8f161b6" +dependencies = [ + "bitflags", + "wayland-client 0.24.1", + "wayland-commons 0.24.1", + "wayland-scanner 0.24.1", +] + +[[package]] +name = "wayland-scanner" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93b02247366f395b9258054f964fe293ddd019c3237afba9be2ccbe9e1651c3d" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "xml-rs", +] + +[[package]] +name = "wayland-scanner" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ea5ea1a117137d72c0c197431d198d69783b5e8ca996b0583c98e10b44d426" +dependencies = [ + "proc-macro2 1.0.7", + "quote 1.0.2", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4" +dependencies = [ + "dlib", + "lazy_static", +] + +[[package]] +name = "wayland-sys" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537500923d50be11d95a63c4cb538145e4c82edf61296b7debc1f94a1a6514ed" + [[package]] name = "web-sys" version = "0.3.35" @@ -3013,6 +4057,44 @@ dependencies = [ "nom", ] +[[package]] +name = "wgpu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e9c1ff587eddd68cdf2a78889c7a2128683161c72c67b94457cf498accaf7b" +dependencies = [ + "arrayvec", + "raw-window-handle", + "wgpu-native", + "zerocopy", +] + +[[package]] +name = "wgpu-native" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26642308af1cc9a28a24c7fc5e5408d9689c8a0c01d7117aa83d5a1ed6e83438" +dependencies = [ + "arrayvec", + "bitflags", + "copyless", + "fxhash", + "gfx-backend-dx11", + "gfx-backend-dx12", + "gfx-backend-empty", + "gfx-backend-metal", + "gfx-backend-vulkan", + "gfx-hal", + "lazy_static", + "log", + "parking_lot 0.9.0", + "raw-window-handle", + "rendy-descriptor", + "rendy-memory", + "smallvec 0.6.13", + "vec_map", +] + [[package]] name = "winapi" version = "0.2.8" @@ -3056,6 +4138,35 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65a5c1a5ef76ac31cc97ad29489acdbed2178f3fc12ca00ee6cb11d60adb5a3a" +dependencies = [ + "android_glue", + "bitflags", + "cocoa", + "core-foundation", + "core-graphics", + "core-video-sys", + "dispatch", + "instant", + "lazy_static", + "libc", + "log", + "mio", + "mio-extras", + "objc", + "parking_lot 0.10.0", + "percent-encoding", + "raw-window-handle", + "smithay-client-toolkit", + "wayland-client 0.23.6", + "winapi 0.3.8", + "x11-dl", +] + [[package]] name = "winreg" version = "0.6.2" @@ -3065,6 +4176,15 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi 0.3.8", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -3075,12 +4195,67 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "x11" +version = "2.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ecd092546cb16f25783a5451538e73afc8d32e242648d54f4ae5459ba1e773" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf981e3a5b3301209754218f962052d4d9ee97e478f4d26d4a6eced34c1fef8" +dependencies = [ + "lazy_static", + "libc", + "maybe-uninit", + "pkg-config", +] + +[[package]] +name = "xdg" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" + +[[package]] +name = "xml-rs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5" + [[package]] name = "yaml-rust" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" +[[package]] +name = "zerocopy" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "992b9b31f80fd4a167f903f879b8ca43d6716cc368ea01df90538baa2dd34056" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b090467ecd0624026e8a6405d343ac7382592530d54881330b3fc8e400280fa5" +dependencies = [ + "proc-macro2 0.4.30", + "syn 0.15.44", + "synstructure 0.10.2", +] + [[package]] name = "zeroize" version = "1.1.0" @@ -3099,5 +4274,5 @@ dependencies = [ "proc-macro2 1.0.7", "quote 1.0.2", "syn 1.0.13", - "synstructure", + "synstructure 0.12.3", ] diff --git a/imgui.ini b/imgui.ini new file mode 100644 index 000000000..303933b40 --- /dev/null +++ b/imgui.ini @@ -0,0 +1,5 @@ +[Window][Debug##Default] +Pos=123,45 +Size=399,400 +Collapsed=0 + diff --git a/server/Cargo.toml b/server/Cargo.toml index c0f4574ab..85744f540 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -91,6 +91,7 @@ ctrlc = "3.1" inventory = "0.1" derivative = "2.0" itertools = "0.9" +structopt = "0.3" # Allocators bumpalo = { version = "3.2", features = ["collections"] } @@ -100,6 +101,23 @@ jemallocator = "0.3" thiserror = "1.0" anyhow = "1.0" +# Dependencies for dev tools GUI +imgui = { version = "0.3", optional = true } +winit = { version = "0.21", optional = true } # use old version for imgui-winit-support +imgui-wgpu = { version = "0.5", optional = true } +imgui-winit-support = { version = "0.3", optional = true } +wgpu = { version = "0.4", optional = true } +minifb = { version = "0.15", optional = true } + +[features] +# Enables the dev tools GUI used for +# testing world generation. +# Pass --dev-tools on the CLI +# to run Feather in this mode. +dev-tools = ["imgui", "winit", "imgui-wgpu", "imgui-winit-support", "wgpu", "minifb"] +nightly = ["hashbrown/nightly", "parking_lot/nightly"] +default = ["dev-tools"] + [dev-dependencies] criterion = "0.3" approx = "0.3" @@ -107,6 +125,3 @@ approx = "0.3" [[bench]] name = "worldgen" harness = false - -[features] -nightly = ["hashbrown/nightly", "parking_lot/nightly"] diff --git a/server/src/devtools.rs b/server/src/devtools.rs new file mode 100644 index 000000000..0ffc48974 --- /dev/null +++ b/server/src/devtools.rs @@ -0,0 +1,217 @@ +//! Implements a GUI for performing assorted debugging tasks. +//! Currently only used for world generation. + +use crate::worldgen; +use imgui_winit_support::{HiDpiMode, WinitPlatform}; +use std::time::Instant; +use winit::dpi::LogicalSize; +use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}; +use winit::event_loop::{ControlFlow, EventLoop}; +use winit::window::Window; + +pub const UI_WIDTH: usize = 1920 / 2; +pub const UI_HEIGHT: usize = 1080 / 2; +pub const VIEWER_WIDTH: usize = 512; +pub const VIEWER_HEIGHT: usize = 512; + +struct Context { + window: Window, + surface: wgpu::Surface, + device: wgpu::Device, + queue: wgpu::Queue, + sc_desc: wgpu::SwapChainDescriptor, + sc: wgpu::SwapChain, + platform: WinitPlatform, + renderer: imgui_wgpu::Renderer, + hidpi_factor: f64, +} + +enum State { + Worldgen(worldgen::devtools::State), +} + +pub fn run() -> anyhow::Result<()> { + let (mut context, event_loop, mut imgui) = init_context()?; + let mut state = State::Worldgen(worldgen::devtools::State::default()); + + let mut last_frame = Instant::now(); + + let mut buffer = vec![0; VIEWER_HEIGHT * VIEWER_WIDTH]; + let mut display_window = minifb::Window::new( + "Feather Dev Tools: Display", + VIEWER_WIDTH, + VIEWER_HEIGHT, + minifb::WindowOptions::default(), + )?; + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Poll; + let mut buffer_changed = false; + match event { + Event::WindowEvent { + event: WindowEvent::ScaleFactorChanged { scale_factor, .. }, + .. + } => { + context.hidpi_factor = scale_factor; + } + Event::WindowEvent { + event: WindowEvent::Resized(_), + .. + } => { + let size = context.window.inner_size(); + + context.sc_desc = wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: wgpu::TextureFormat::Bgra8Unorm, + width: size.width as u32, + height: size.height as u32, + present_mode: wgpu::PresentMode::Vsync, + }; + + context.sc = context + .device + .create_swap_chain(&context.surface, &context.sc_desc); + } + Event::WindowEvent { + event: + WindowEvent::KeyboardInput { + input: + KeyboardInput { + virtual_keycode: Some(VirtualKeyCode::Escape), + state: ElementState::Pressed, + .. + }, + .. + }, + .. + } + | Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => { + *control_flow = ControlFlow::Exit; + } + Event::MainEventsCleared => { + context.window.request_redraw(); + } + Event::RedrawEventsCleared => { + last_frame = imgui.io_mut().update_delta_time(last_frame); + + let frame = context.sc.get_next_texture(); + context + .platform + .prepare_frame(imgui.io_mut(), &context.window) + .expect("failed to prepare frame"); + let ui = imgui.frame(); + + { + match &mut state { + State::Worldgen(state) => { + buffer_changed = state.render(&ui, &mut buffer); + } + } + } + + let mut encoder: wgpu::CommandEncoder = context + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); + + context.platform.prepare_render(&ui, &context.window); + context + .renderer + .render(ui.render(), &context.device, &mut encoder, &frame.view) + .expect("Rendering failed"); + + context.queue.submit(&[encoder.finish()]); + } + _ => (), + } + + context + .platform + .handle_event(imgui.io_mut(), &context.window, &event); + + if buffer_changed { + display_window + .update_with_buffer(&buffer, VIEWER_WIDTH, VIEWER_HEIGHT) + .unwrap(); + } + }); +} + +fn init_context() -> anyhow::Result<(Context, EventLoop<()>, imgui::Context)> { + let event_loop = EventLoop::new(); + let hidpi_factor = 1.0; + + let window = Window::new(&event_loop)?; + window.set_inner_size(LogicalSize { + width: UI_WIDTH as f64, + height: UI_HEIGHT as f64, + }); + + window.set_title(&format!( + "Feather Developer Tools v{}", + env!("CARGO_PKG_VERSION") + )); + + let size = window.inner_size(); + + let surface = wgpu::Surface::create(&window); + + let adapter = wgpu::Adapter::request(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::Default, + backends: wgpu::BackendBit::PRIMARY, + }) + .ok_or_else(|| anyhow::anyhow!("failed to select a suitable adapter"))?; + + let (device, mut queue) = adapter.request_device(&wgpu::DeviceDescriptor { + extensions: wgpu::Extensions { + anisotropic_filtering: false, + }, + limits: Default::default(), + }); + + let sc_desc = wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: wgpu::TextureFormat::Bgra8Unorm, + width: size.width as u32, + height: size.height as u32, + present_mode: wgpu::PresentMode::Vsync, + }; + + let sc = device.create_swap_chain(&surface, &sc_desc); + + let mut imgui = imgui::Context::create(); + + let mut platform = WinitPlatform::init(&mut imgui); + platform.attach_window(imgui.io_mut(), &window, HiDpiMode::Default); + + let renderer = imgui_wgpu::Renderer::new( + &mut imgui, + &device, + &mut queue, + sc_desc.format, + Some(wgpu::Color { + r: 0.2, + g: 0.2, + b: 0.2, + a: 1.0, + }), + ); + + Ok(( + Context { + window, + surface, + device, + queue, + sc_desc, + sc, + platform, + renderer, + hidpi_factor, + }, + event_loop, + imgui, + )) +} diff --git a/server/src/lib.rs b/server/src/lib.rs index 87722d7b4..ea64c8f94 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -145,6 +145,8 @@ mod chunk_entities; pub mod chunk_logic; pub mod chunk_worker; pub mod config; +#[cfg(feature = "dev-tools")] +mod devtools; pub mod entity; pub mod game; pub mod io; @@ -173,7 +175,31 @@ pub const PROTOCOL_VERSION: u32 = 404; pub const SERVER_VERSION: &str = "Feather 1.13.2"; pub const TICK_TIME: u64 = 1000 / TPS; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +#[structopt(name = "feather", about = "A Minecraft server implementation in Rust.")] +struct Options { + /// Launches Feather in the dev tools GUI mode instead + /// of running a server. Currently used for developing + /// the world generator. + #[structopt(long = "dev-tools")] + dev_tools: bool, +} + pub fn main() { + let options = Options::from_args(); + + if options.dev_tools { + simple_logger::init_with_level(log::Level::Info).expect("failed to init logging"); + info!("Launching the dev tools GUI"); + run_dev_tools(); + } else { + run_game(); + } +} + +fn run_game() { let config = Arc::new(load_config()); init_log(&config); @@ -275,6 +301,18 @@ pub fn main() { exit(0); } +fn run_dev_tools() { + if cfg!(feature = "dev-tools") { + if let Err(e) = devtools::run() { + error!("An error occurred: {}", e); + exit(-1); + } + } else { + error!("To run the dev tools GUI, please enable the `dev-tools` Cargo feature"); + exit(-1); + } +} + /// Runs the main game loop. fn run_loop( world: &mut World, diff --git a/server/src/worldgen/biomes/grid/mod.rs b/server/src/worldgen/biomes/grid/mod.rs new file mode 100644 index 000000000..e923d9778 --- /dev/null +++ b/server/src/worldgen/biomes/grid/mod.rs @@ -0,0 +1,132 @@ +//! Biome generation based on a growing 2D array of integers. +//! Each step in the pipeline interprets the integers in a different +//! way. At the core of this design is the "zoom" operation, which +//! randomly increases detail in such an array and expands its size. +//! +//! See http://cuberite.xoft.cz/docs/Generator.html#biomegen (section "Grown biomes") +//! for an expanded explanation. + +use crate::worldgen::{BiomeGenerator, ChunkBiomes}; +use feather_core::ChunkPosition; +use simdnoise::NoiseBuilder; + +mod zoom; + +/// Wrapper over `Vec`. +#[derive(Debug, Clone)] +struct Grid { + vec: Vec, + size_x: usize, + /// Global offsets of the origin of this grid in blocks + pub offset_x: i32, + pub offset_z: i32, + /// Scale along each axis of this grid. For example, + /// if set to 4, then moving 1 to the right in this + /// grid corresponds to moving 4 blocks. + pub scale: usize, + // size_z can be inferred using vec.len() and size_x +} + +impl Grid { + /// Creates a new `Grid` with the provided dimensions. + /// Values are initialized with 0. + pub fn new(size_x: usize, size_z: usize, offset_x: i32, offset_z: i32, scale: usize) -> Self { + Self { + vec: vec![0; size_x * size_z], + size_x, + offset_x, + offset_z, + scale, + } + } + + /// Creates a new `Grid` with the same offset + /// as another `Grid` but with new dimensions. + /// The scale is adjusted to account for the new dimensions. + pub fn from_input(other: &Grid, new_size_x: usize, new_size_z: usize) -> Self { + let scale = (other.size_x as f64 / new_size_x as f64 * other.scale as f64).round() as usize; + + Self::new( + new_size_x, + new_size_z, + other.offset_x, + other.offset_z, + scale, + ) + } + + /// Retrieves the value at (x, z). + pub fn at(&self, x: usize, z: usize) -> u16 { + self.vec[x + (z * self.size_x)] + } + + /// Sets the value at (x, z). + pub fn set_at(&mut self, x: usize, z: usize, val: u16) { + self.vec[x + (z * self.size_x)] = val; + } + + /// Returns the size of this grid along the X axis. + pub fn size_x(&self) -> usize { + self.size_x + } + + /// Returns the size of this grid along the Z axis. + pub fn size_z(&self) -> usize { + self.vec.len() / self.size_x + } + + /// Samples the value at the given position, in absolute blocks + /// from the world origin. Nearest interpolation is used. + pub fn sample(&self, abs_x: i32, abs_z: i32) -> u16 { + let mut x = (abs_x - self.offset_x) as usize; + let mut z = (abs_z - self.offset_z) as usize; + + x /= self.scale; + z /= self.scale; + + self.at(x, z) + } +} + +/// Operates an a biome grid, outputting a new grid. +trait GridOperator: Send + Sync + 'static { + /// Performs an operation on the input grid, returning + /// new grid. The returned grid may have a greater size + /// than the input, though it must have the same relative + /// dimensions. + fn operate(&self, input: Grid, seed: u64) -> Grid; +} + +pub struct GridBiomeGenerator; + +// starting grid is 3x3 with scale 512: i.e. each +// tile in the grid represents 512x512 blocks +const STARTING_GRID_SIZE: usize = 3; +const STARTING_GRID_SCALE: usize = 512; +const STARTING_GRID_OFFSET_RELATIVE_TO_CHUNK: i32 = -(STARTING_GRID_SCALE as i32) - 8; + +impl BiomeGenerator for GridBiomeGenerator { + fn generate_for_chunk(&self, chunk: ChunkPosition, seed: u64) -> ChunkBiomes { + let mut starting_grid = Grid::new( + STARTING_GRID_SIZE, + STARTING_GRID_SIZE, + STARTING_GRID_OFFSET_RELATIVE_TO_CHUNK + chunk.x * 16, + STARTING_GRID_OFFSET_RELATIVE_TO_CHUNK + chunk.z * 16, + STARTING_GRID_SCALE, + ); + fill_with_ocean_land(&mut starting_grid, seed); + + todo!() + } +} + +/// Fills in a grid with ocean-land values. 0=ocean; >0=land. +fn fill_with_ocean_land(grid: &mut Grid, seed: u64) { + let _noise = NoiseBuilder::gradient_2d_offset( + grid.offset_x as f32, + grid.size_x(), + grid.offset_z as f32, + grid.size_z(), + ) + .with_seed(seed as i32); +} diff --git a/server/src/worldgen/biomes/grid/zoom.rs b/server/src/worldgen/biomes/grid/zoom.rs new file mode 100644 index 000000000..02ced4f67 --- /dev/null +++ b/server/src/worldgen/biomes/grid/zoom.rs @@ -0,0 +1,70 @@ +use crate::worldgen::biomes::grid::{Grid, GridOperator}; +use crate::worldgen::util::shuffle_seed_for_block; +use rand::{Rng, SeedableRng}; +use rand_xorshift::XorShiftRng; + +/// Grid operator which increases detail in the input. +/// +/// This is implemented as follows: for each 2x2 grid +/// of values in the input array, a 3x3 grid is outputted. +/// The corner values of the output grid are inherited +/// from the original grid, while values in between are +/// selected at random from adjacent corner values. +pub struct ZoomOperator; + +impl GridOperator for ZoomOperator { + fn operate(&self, input: Grid, seed: u64) -> Grid { + let mut output = Grid::from_input(&input, input.size_x() * 2 - 1, input.size_z() * 2 - 1); + + for x in 0..input.size_x() - 1 { + for z in 0..input.size_z() - 1 { + let a = input.at(x, z); + let b = input.at(x + 1, z); + let c = input.at(x, z + 1); + let d = input.at(x + 1, z + 1); + + let output_x = x * 2 + 1; + let output_z = x * 2 + 1; + + // Inherit corner values + output.set_at(output_x, output_z, a); + output.set_at(output_x + 2, output_z, b); + output.set_at(output_x, output_z + 2, c); + output.set_at(output_x + 2, output_z + 2, c); + + // Randomly select a corner value for each in-between spot + let ax = input.offset_x + x as i32; + let az = input.offset_z + z as i32; + output.set_at(output_x + 1, output_z, select(ax, az, seed, &[a, b])); + output.set_at(output_x, output_z + 1, select(ax, az, seed + 1, &[a, c])); + output.set_at( + output_x + 1, + output_z + 1, + select(ax, az, seed + 2, &[a, b, c, d]), + ); + output.set_at( + output_x + 2, + output_z + 1, + select(ax, az, seed + 3, &[b, d]), + ); + output.set_at( + output_x + 1, + output_z + 3, + select(ax, az, seed + 4, &[c, d]), + ); + } + } + + output + } +} + +fn select(abs_x: i32, abs_z: i32, seed: u64, values: &[T]) -> T +where + T: Copy, +{ + let index = XorShiftRng::seed_from_u64(shuffle_seed_for_block(seed, abs_x, abs_z)) + .gen_range(0, values.len()); + + values[index] +} diff --git a/server/src/worldgen/biomes/mod.rs b/server/src/worldgen/biomes/mod.rs index 666e9fd5e..ffdce3eb7 100644 --- a/server/src/worldgen/biomes/mod.rs +++ b/server/src/worldgen/biomes/mod.rs @@ -1,7 +1,9 @@ //! Biome grid creation. mod distorted_voronoi; +mod grid; mod two_level; pub use distorted_voronoi::DistortedVoronoiBiomeGenerator; +pub use grid::GridBiomeGenerator; pub use two_level::TwoLevelBiomeGenerator; diff --git a/server/src/worldgen/devtools/mod.rs b/server/src/worldgen/devtools/mod.rs new file mode 100644 index 000000000..e7ec2de27 --- /dev/null +++ b/server/src/worldgen/devtools/mod.rs @@ -0,0 +1,349 @@ +use crate::devtools::VIEWER_WIDTH; +use imgui::{im_str, ComboBox, Slider}; +use simdnoise::NoiseBuilder; + +pub struct State { + mode: Mode, +} + +impl Default for State { + fn default() -> Self { + Self { + mode: Mode { + kind: ModeKind::DisplayNoise(NoiseSettings::Fbm(FbmSettings::default())), + dimensions: VIEWER_WIDTH as i32, + multiplier: 1.0, + }, + } + } +} + +impl State { + pub fn render(&mut self, ui: &imgui::Ui, buffer: &mut [u32]) -> bool { + let mut current_mode = self.mode.ordinal(); + ComboBox::new(im_str!("Mode")).build_simple_string( + ui, + &mut current_mode, + &[im_str!("Display noise")], + ); + + if current_mode != self.mode.ordinal() { + self.mode = Mode::default_from_ordinal(current_mode); + } + + self.mode.render(ui, buffer) + } + + pub fn dimensions(&self) -> u32 { + self.mode.dimensions as u32 + } +} + +#[derive(Copy, Clone)] +struct Mode { + kind: ModeKind, + dimensions: i32, + multiplier: f32, +} + +#[derive(Copy, Clone)] +enum ModeKind { + DisplayNoise(NoiseSettings), +} + +impl Mode { + fn ordinal(self) -> usize { + match self.kind { + ModeKind::DisplayNoise(_) => 0, + } + } + + fn default_from_ordinal(ordinal: usize) -> Self { + Self { + kind: match ordinal { + 0 => ModeKind::DisplayNoise(NoiseSettings::Fbm(FbmSettings::default())), + x => panic!("invalid mode ordinal {}", x), + }, + dimensions: VIEWER_WIDTH as i32, + multiplier: 1.0, + } + } + + fn render(&mut self, ui: &imgui::Ui, buffer: &mut [u32]) -> bool { + match &mut self.kind { + ModeKind::DisplayNoise(settings) => { + let prev_settings = *settings; + let mut current_item = settings.ordinal(); + ComboBox::new(im_str!("Noise type")).build_simple_string( + ui, + &mut current_item, + &[ + im_str!("Fbm"), + im_str!("Cellular"), + im_str!("Gradient"), + im_str!("Ridge"), + im_str!("Turbulence"), + ], + ); + if current_item != settings.ordinal() { + *settings = NoiseSettings::default_from_ordinal(current_item); + } + + let multiplier_changed = Slider::new(im_str!("Multiplier"), 1.0f32..=100.0) + .build(ui, &mut self.multiplier); + let dim_changed = ui + .input_int(im_str!("Dimensions"), &mut self.dimensions) + .build(); + + settings.render(ui); + + if prev_settings != *settings || dim_changed || multiplier_changed { + // Re-render noise + let data = SampledGrid::new( + settings.generate(self.dimensions as usize, self.dimensions as usize), + self.dimensions as u32, + ); + + buffer.iter_mut().enumerate().for_each(|(i, x)| { + let val = ((data.sample(i % VIEWER_WIDTH, i / VIEWER_WIDTH) + + 0.5f32.sqrt()) + * 255.0 + * self.multiplier) + .round() as u32; + + *x = (val << 16) | (val << 8) | val; + }); + true + } else { + false + } + } + } + } +} + +struct SampledGrid { + dimensions: u32, + data: Vec, + scale: f64, +} + +impl SampledGrid { + pub fn new(data: Vec, dimensions: u32) -> Self { + let scale = VIEWER_WIDTH as f64 / dimensions as f64; + + Self { + dimensions, + data, + scale, + } + } + + pub fn sample(&self, x: usize, y: usize) -> f32 { + let x = (x as f64 / self.scale).floor() as usize; + let y = (y as f64 / self.scale).floor() as usize; + + let index = x + y * self.dimensions as usize; + + if index >= self.data.len() { + 0.0 + } else { + self.data[index] + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +enum NoiseSettings { + Fbm(FbmSettings), + Cellular(CellularSettings), + Gradient(GradientSettings), + Ridge(RidgeSettings), + Turbulence(TurbulenceSettings), +} + +impl NoiseSettings { + fn ordinal(self) -> usize { + match self { + NoiseSettings::Fbm(_) => 0, + NoiseSettings::Cellular(_) => 1, + NoiseSettings::Gradient(_) => 2, + NoiseSettings::Ridge(_) => 3, + NoiseSettings::Turbulence(_) => 4, + } + } + + fn default_from_ordinal(ordinal: usize) -> Self { + match ordinal { + 0 => NoiseSettings::Fbm(FbmSettings::default()), + 1 => NoiseSettings::Cellular(CellularSettings::default()), + 2 => NoiseSettings::Gradient(GradientSettings::default()), + 3 => NoiseSettings::Ridge(RidgeSettings::default()), + 4 => NoiseSettings::Turbulence(TurbulenceSettings::default()), + x => panic!("invalid noise setting ordinal {}", x), + } + } + + fn generate(self, width: usize, height: usize) -> Vec { + match self { + NoiseSettings::Fbm(settings) => NoiseBuilder::fbm_2d(width, height) + .with_freq(settings.freq) + .with_gain(settings.gain) + .with_lacunarity(settings.lacunarity) + .with_octaves(settings.octaves) + .with_seed(settings.seed) + .generate(), + NoiseSettings::Cellular(settings) => NoiseBuilder::cellular_2d(width, height) + .with_freq(settings.freq) + .with_seed(settings.seed) + .generate(), + NoiseSettings::Gradient(settings) => NoiseBuilder::gradient_2d(width, height) + .with_freq(settings.freq) + .with_seed(settings.seed) + .generate(), + NoiseSettings::Ridge(settings) => NoiseBuilder::ridge_2d(width, height) + .with_freq(settings.freq) + .with_gain(settings.gain) + .with_lacunarity(settings.lacunarity) + .with_octaves(settings.octaves) + .with_seed(settings.seed) + .generate(), + NoiseSettings::Turbulence(settings) => NoiseBuilder::turbulence_2d(width, height) + .with_freq(settings.freq) + .with_gain(settings.gain) + .with_lacunarity(settings.lacunarity) + .with_octaves(settings.octaves) + .with_seed(settings.seed) + .generate(), + } + .0 + } + + fn render(&mut self, ui: &imgui::Ui) { + match self { + NoiseSettings::Fbm(settings) => { + Slider::new(im_str!("Seed"), 0..=1_000_000).build(ui, &mut settings.seed); + Slider::new(im_str!("Frequency"), 0.0f32..=1.0).build(ui, &mut settings.freq); + Slider::new(im_str!("Lacunarity"), 0.0..=5.0).build(ui, &mut settings.lacunarity); + Slider::new(im_str!("Gain"), 0.0..=20.0).build(ui, &mut settings.gain); + Slider::new(im_str!("Octaves"), 1u8..=16).build(ui, &mut settings.octaves); + } + NoiseSettings::Cellular(settings) => { + Slider::new(im_str!("Seed"), 0..=1_000_000).build(ui, &mut settings.seed); + Slider::new(im_str!("Frequency"), 0.0f32..=1.0).build(ui, &mut settings.freq); + } + NoiseSettings::Gradient(settings) => { + Slider::new(im_str!("Seed"), 0..=1_000_000).build(ui, &mut settings.seed); + Slider::new(im_str!("Frequency"), 0.0f32..=1.0).build(ui, &mut settings.freq); + } + NoiseSettings::Ridge(settings) => { + Slider::new(im_str!("Seed"), 0..=1_000_000).build(ui, &mut settings.seed); + Slider::new(im_str!("Frequency"), 0.0f32..=1.0).build(ui, &mut settings.freq); + Slider::new(im_str!("Lacunarity"), 0.0..=5.0).build(ui, &mut settings.lacunarity); + Slider::new(im_str!("Gain"), 0.0..=20.0).build(ui, &mut settings.gain); + Slider::new(im_str!("Octaves"), 1u8..=16).build(ui, &mut settings.octaves); + } + NoiseSettings::Turbulence(settings) => { + Slider::new(im_str!("Seed"), 0..=1_000_000).build(ui, &mut settings.seed); + Slider::new(im_str!("Frequency"), 0.0f32..=1.0).build(ui, &mut settings.freq); + Slider::new(im_str!("Lacunarity"), 0.0..=5.0).build(ui, &mut settings.lacunarity); + Slider::new(im_str!("Gain"), 0.0..=20.0).build(ui, &mut settings.gain); + Slider::new(im_str!("Octaves"), 1u8..=16).build(ui, &mut settings.octaves); + } + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +struct FbmSettings { + seed: i32, + freq: f32, + lacunarity: f32, + gain: f32, + octaves: u8, +} + +impl Default for FbmSettings { + fn default() -> Self { + Self { + seed: 0, + freq: 0.02, + lacunarity: 0.5, + gain: 2.0, + octaves: 3, + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +struct CellularSettings { + seed: i32, + freq: f32, + // todo: distance function +} + +impl Default for CellularSettings { + fn default() -> Self { + Self { + seed: 0, + freq: 0.02, + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +struct GradientSettings { + seed: i32, + freq: f32, +} + +impl Default for GradientSettings { + fn default() -> Self { + Self { + seed: 0, + freq: 0.02, + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +struct RidgeSettings { + seed: i32, + freq: f32, + lacunarity: f32, + gain: f32, + octaves: u8, +} + +impl Default for RidgeSettings { + fn default() -> Self { + Self { + seed: 0, + freq: 0.02, + lacunarity: 0.5, + gain: 2.0, + octaves: 3, + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +struct TurbulenceSettings { + seed: i32, + freq: f32, + lacunarity: f32, + gain: f32, + octaves: u8, +} + +impl Default for TurbulenceSettings { + fn default() -> Self { + Self { + seed: 0, + freq: 0.02, + lacunarity: 0.5, + gain: 2.0, + octaves: 3, + } + } +} diff --git a/server/src/worldgen/mod.rs b/server/src/worldgen/mod.rs index da7f05e6b..186e548d9 100644 --- a/server/src/worldgen/mod.rs +++ b/server/src/worldgen/mod.rs @@ -8,6 +8,8 @@ use feather_core::{Biome, Block, Chunk, ChunkPosition}; mod biomes; mod composition; mod density_map; +#[cfg(feature = "dev-tools")] +pub mod devtools; mod finishers; pub mod noise; mod superflat; @@ -15,7 +17,7 @@ mod util; pub mod voronoi; use crate::worldgen::finishers::{ClumpedFoliageFinisher, SingleFoliageFinisher, SnowFinisher}; -pub use biomes::{DistortedVoronoiBiomeGenerator, TwoLevelBiomeGenerator}; +pub use biomes::{DistortedVoronoiBiomeGenerator, GridBiomeGenerator, TwoLevelBiomeGenerator}; use bitvec::order::Local; use bitvec::slice::BitSlice; use bitvec::vec::BitVec; diff --git a/server/src/worldgen/util.rs b/server/src/worldgen/util.rs index ff4072a4d..1fbd7225a 100644 --- a/server/src/worldgen/util.rs +++ b/server/src/worldgen/util.rs @@ -16,3 +16,7 @@ pub fn shuffle_seed_for_column(seed: u64, chunk: ChunkPosition, col_x: usize, co .wrapping_mul(((col_x as u64) << 4) + 4) .wrapping_mul(col_z as u64 + 4) } + +pub fn shuffle_seed_for_block(seed: u64, x: i32, z: i32) -> u64 { + seed.wrapping_mul((x as u64).wrapping_mul(9324) ^ (z as u64).wrapping_shl(10)) +} From 4fa26c9cebb18c3064e04a816527187bdc4d54ee Mon Sep 17 00:00:00 2001 From: caelunshun Date: Wed, 25 Mar 2020 08:40:55 -0600 Subject: [PATCH 2/5] Additional work on worldgen --- server/Cargo.toml | 1 - server/imgui.ini | 5 ++ server/src/devtools.rs | 11 +++- server/src/lib.rs | 7 ++- server/src/worldgen/biomes/grid/mod.rs | 59 +++++++++++------- server/src/worldgen/biomes/grid/zoom.rs | 80 ++++++++++++------------- server/src/worldgen/devtools/mod.rs | 8 +-- server/src/worldgen/mod.rs | 8 ++- server/src/worldgen/noise.rs | 42 +++++++++++++ server/src/worldgen/util.rs | 4 ++ 10 files changed, 149 insertions(+), 76 deletions(-) create mode 100644 server/imgui.ini diff --git a/server/Cargo.toml b/server/Cargo.toml index 85744f540..d05d1a5b6 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -116,7 +116,6 @@ minifb = { version = "0.15", optional = true } # to run Feather in this mode. dev-tools = ["imgui", "winit", "imgui-wgpu", "imgui-winit-support", "wgpu", "minifb"] nightly = ["hashbrown/nightly", "parking_lot/nightly"] -default = ["dev-tools"] [dev-dependencies] criterion = "0.3" diff --git a/server/imgui.ini b/server/imgui.ini new file mode 100644 index 000000000..4a5c20148 --- /dev/null +++ b/server/imgui.ini @@ -0,0 +1,5 @@ +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + diff --git a/server/src/devtools.rs b/server/src/devtools.rs index 0ffc48974..2a442df85 100644 --- a/server/src/devtools.rs +++ b/server/src/devtools.rs @@ -44,9 +44,10 @@ pub fn run() -> anyhow::Result<()> { minifb::WindowOptions::default(), )?; + let mut is_first_run = true; event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Poll; let mut buffer_changed = false; + *control_flow = ControlFlow::Poll; match event { Event::WindowEvent { event: WindowEvent::ScaleFactorChanged { scale_factor, .. }, @@ -107,7 +108,9 @@ pub fn run() -> anyhow::Result<()> { { match &mut state { State::Worldgen(state) => { - buffer_changed = state.render(&ui, &mut buffer); + if state.render(&ui, &mut buffer, is_first_run) { + buffer_changed = true; + } } } } @@ -131,11 +134,13 @@ pub fn run() -> anyhow::Result<()> { .platform .handle_event(imgui.io_mut(), &context.window, &event); - if buffer_changed { + if buffer_changed || is_first_run { display_window .update_with_buffer(&buffer, VIEWER_WIDTH, VIEWER_HEIGHT) .unwrap(); } + + is_first_run = false; }); } diff --git a/server/src/lib.rs b/server/src/lib.rs index ea64c8f94..5d77c623c 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -302,12 +302,15 @@ fn run_game() { } fn run_dev_tools() { - if cfg!(feature = "dev-tools") { + #[cfg(feature = "dev-tools")] + { if let Err(e) = devtools::run() { error!("An error occurred: {}", e); exit(-1); } - } else { + } + #[cfg(not(feature = "dev-tools"))] + { error!("To run the dev tools GUI, please enable the `dev-tools` Cargo feature"); exit(-1); } diff --git a/server/src/worldgen/biomes/grid/mod.rs b/server/src/worldgen/biomes/grid/mod.rs index e923d9778..8c80d3740 100644 --- a/server/src/worldgen/biomes/grid/mod.rs +++ b/server/src/worldgen/biomes/grid/mod.rs @@ -6,15 +6,17 @@ //! See http://cuberite.xoft.cz/docs/Generator.html#biomegen (section "Grown biomes") //! for an expanded explanation. +use crate::worldgen::noise::normalized_fbm; +use crate::worldgen::util::map; use crate::worldgen::{BiomeGenerator, ChunkBiomes}; -use feather_core::ChunkPosition; -use simdnoise::NoiseBuilder; +use feather_core::{Biome, ChunkPosition}; +use zoom::zoom; mod zoom; /// Wrapper over `Vec`. #[derive(Debug, Clone)] -struct Grid { +pub struct Grid { vec: Vec, size_x: usize, /// Global offsets of the origin of this grid in blocks @@ -88,15 +90,7 @@ impl Grid { } } -/// Operates an a biome grid, outputting a new grid. -trait GridOperator: Send + Sync + 'static { - /// Performs an operation on the input grid, returning - /// new grid. The returned grid may have a greater size - /// than the input, though it must have the same relative - /// dimensions. - fn operate(&self, input: Grid, seed: u64) -> Grid; -} - +#[derive(Debug, Default)] pub struct GridBiomeGenerator; // starting grid is 3x3 with scale 512: i.e. each @@ -107,26 +101,45 @@ const STARTING_GRID_OFFSET_RELATIVE_TO_CHUNK: i32 = -(STARTING_GRID_SCALE as i32 impl BiomeGenerator for GridBiomeGenerator { fn generate_for_chunk(&self, chunk: ChunkPosition, seed: u64) -> ChunkBiomes { - let mut starting_grid = Grid::new( + let mut grid = Grid::new( STARTING_GRID_SIZE, STARTING_GRID_SIZE, STARTING_GRID_OFFSET_RELATIVE_TO_CHUNK + chunk.x * 16, STARTING_GRID_OFFSET_RELATIVE_TO_CHUNK + chunk.z * 16, STARTING_GRID_SCALE, ); - fill_with_ocean_land(&mut starting_grid, seed); + fill_with_ocean_land(&mut grid, seed); + for _ in 0..8 { + grid = zoom(grid, seed + 1); + } + + let mut biomes = ChunkBiomes::default(); + + for x in 0..16 { + for z in 0..16 { + let biome = if grid.sample(x + chunk.x * 16, z + chunk.z * 16) > 0 { + Biome::Ocean + } else { + Biome::Plains + }; + biomes.set_biome_at(x as usize, z as usize, biome); + } + } - todo!() + biomes } } -/// Fills in a grid with ocean-land values. 0=ocean; >0=land. +/// Fills in a grid with ocean-land values. 0=land; >0=ocean. fn fill_with_ocean_land(grid: &mut Grid, seed: u64) { - let _noise = NoiseBuilder::gradient_2d_offset( - grid.offset_x as f32, - grid.size_x(), - grid.offset_z as f32, - grid.size_z(), - ) - .with_seed(seed as i32); + for x in 0..grid.size_x() { + for z in 0..grid.size_z() { + let abs_x = x as i32 * grid.scale as i32 + grid.offset_x; + let abs_z = z as i32 * grid.scale as i32 + grid.offset_z; + + let noise = normalized_fbm(abs_x as f32, abs_z as f32, 0.02, 0.5, 2.0, 3, seed); + + grid.set_at(x, z, map(noise, 0.0, 1.0, 0.0, 2.0).floor() as u16); + } + } } diff --git a/server/src/worldgen/biomes/grid/zoom.rs b/server/src/worldgen/biomes/grid/zoom.rs index 02ced4f67..392850a69 100644 --- a/server/src/worldgen/biomes/grid/zoom.rs +++ b/server/src/worldgen/biomes/grid/zoom.rs @@ -1,4 +1,4 @@ -use crate::worldgen::biomes::grid::{Grid, GridOperator}; +use crate::worldgen::biomes::grid::Grid; use crate::worldgen::util::shuffle_seed_for_block; use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; @@ -10,53 +10,49 @@ use rand_xorshift::XorShiftRng; /// The corner values of the output grid are inherited /// from the original grid, while values in between are /// selected at random from adjacent corner values. -pub struct ZoomOperator; +pub fn zoom(input: Grid, seed: u64) -> Grid { + let mut output = Grid::from_input(&input, input.size_x() * 2 - 1, input.size_z() * 2 - 1); -impl GridOperator for ZoomOperator { - fn operate(&self, input: Grid, seed: u64) -> Grid { - let mut output = Grid::from_input(&input, input.size_x() * 2 - 1, input.size_z() * 2 - 1); + for x in 0..input.size_x() - 1 { + for z in 0..input.size_z() - 1 { + let a = input.at(x, z); + let b = input.at(x + 1, z); + let c = input.at(x, z + 1); + let d = input.at(x + 1, z + 1); - for x in 0..input.size_x() - 1 { - for z in 0..input.size_z() - 1 { - let a = input.at(x, z); - let b = input.at(x + 1, z); - let c = input.at(x, z + 1); - let d = input.at(x + 1, z + 1); + let output_x = x * 2; + let output_z = z * 2; - let output_x = x * 2 + 1; - let output_z = x * 2 + 1; + // Inherit corner values + output.set_at(output_x, output_z, a); + output.set_at(output_x + 2, output_z, b); + output.set_at(output_x, output_z + 2, c); + output.set_at(output_x + 2, output_z + 2, c); - // Inherit corner values - output.set_at(output_x, output_z, a); - output.set_at(output_x + 2, output_z, b); - output.set_at(output_x, output_z + 2, c); - output.set_at(output_x + 2, output_z + 2, c); - - // Randomly select a corner value for each in-between spot - let ax = input.offset_x + x as i32; - let az = input.offset_z + z as i32; - output.set_at(output_x + 1, output_z, select(ax, az, seed, &[a, b])); - output.set_at(output_x, output_z + 1, select(ax, az, seed + 1, &[a, c])); - output.set_at( - output_x + 1, - output_z + 1, - select(ax, az, seed + 2, &[a, b, c, d]), - ); - output.set_at( - output_x + 2, - output_z + 1, - select(ax, az, seed + 3, &[b, d]), - ); - output.set_at( - output_x + 1, - output_z + 3, - select(ax, az, seed + 4, &[c, d]), - ); - } + // Randomly select a corner value for each in-between spot + let ax = input.offset_x + x as i32; + let az = input.offset_z + z as i32; + output.set_at(output_x + 1, output_z, select(ax, az, seed, &[a, b])); + output.set_at(output_x, output_z + 1, select(ax, az, seed + 1, &[a, c])); + output.set_at( + output_x + 1, + output_z + 1, + select(ax, az, seed + 2, &[a, b, c, d]), + ); + output.set_at( + output_x + 2, + output_z + 1, + select(ax, az, seed + 3, &[b, d]), + ); + output.set_at( + output_x + 1, + output_z + 2, + select(ax, az, seed + 4, &[c, d]), + ); } - - output } + + output } fn select(abs_x: i32, abs_z: i32, seed: u64, values: &[T]) -> T diff --git a/server/src/worldgen/devtools/mod.rs b/server/src/worldgen/devtools/mod.rs index e7ec2de27..f252d4d89 100644 --- a/server/src/worldgen/devtools/mod.rs +++ b/server/src/worldgen/devtools/mod.rs @@ -19,7 +19,7 @@ impl Default for State { } impl State { - pub fn render(&mut self, ui: &imgui::Ui, buffer: &mut [u32]) -> bool { + pub fn render(&mut self, ui: &imgui::Ui, buffer: &mut [u32], is_first_run: bool) -> bool { let mut current_mode = self.mode.ordinal(); ComboBox::new(im_str!("Mode")).build_simple_string( ui, @@ -31,7 +31,7 @@ impl State { self.mode = Mode::default_from_ordinal(current_mode); } - self.mode.render(ui, buffer) + self.mode.render(ui, buffer, is_first_run) } pub fn dimensions(&self) -> u32 { @@ -69,7 +69,7 @@ impl Mode { } } - fn render(&mut self, ui: &imgui::Ui, buffer: &mut [u32]) -> bool { + fn render(&mut self, ui: &imgui::Ui, buffer: &mut [u32], is_first_run: bool) -> bool { match &mut self.kind { ModeKind::DisplayNoise(settings) => { let prev_settings = *settings; @@ -97,7 +97,7 @@ impl Mode { settings.render(ui); - if prev_settings != *settings || dim_changed || multiplier_changed { + if prev_settings != *settings || dim_changed || multiplier_changed || is_first_run { // Re-render noise let data = SampledGrid::new( settings.generate(self.dimensions as usize, self.dimensions as usize), diff --git a/server/src/worldgen/mod.rs b/server/src/worldgen/mod.rs index 186e548d9..80984a3b4 100644 --- a/server/src/worldgen/mod.rs +++ b/server/src/worldgen/mod.rs @@ -111,7 +111,7 @@ impl ComposableGenerator { Box::new(ClumpedFoliageFinisher::default()), ]; Self::new( - TwoLevelBiomeGenerator::default(), + GridBiomeGenerator::default(), DensityMapGeneratorImpl::default(), BasicCompositionGenerator::default(), finishers, @@ -346,6 +346,12 @@ pub struct ChunkBiomes { biomes: [Biome; 16 * 16], } +impl Default for ChunkBiomes { + fn default() -> Self { + Self::from_array([Biome::Plains; 16 * 16]) + } +} + impl ChunkBiomes { /// Creates a `ChunkBiomes` wrapping the given array of biomes. #[inline] diff --git a/server/src/worldgen/noise.rs b/server/src/worldgen/noise.rs index 372cd6d7a..b433474b3 100644 --- a/server/src/worldgen/noise.rs +++ b/server/src/worldgen/noise.rs @@ -1,4 +1,46 @@ use num_traits::ToPrimitive; +use simdnoise::FbmSettings; + +/// Extension trait for noise settings. +pub trait NoiseExt { + /// Generates noise normalized to `[0, 1]`. + /// + /// http://digitalfreepen.com/2017/06/20/range-perlin-noise.html + fn generate_normalized(self) -> Vec; +} + +impl NoiseExt for FbmSettings { + fn generate_normalized(self) -> Vec { + let mut res = self.generate().0; + + res.iter_mut().for_each(|x| { + *x = normalize(*x); + }); + + res + } +} + +pub fn normalized_fbm( + x: f32, + y: f32, + freq: f32, + lacunarity: f32, + gain: f32, + octaves: u8, + seed: u64, +) -> f32 { + normalize(unsafe { + simdnoise::scalar::fbm_2d(x * freq, y * freq, lacunarity, gain, octaves, seed as i32) + }) +} + +/// Normalizes a noise value to [0, 1]. +pub fn normalize(mut x: f32) -> f32 { + x += 0.5f32.sqrt(); + x /= 0.5f32.sqrt() * 2.0; + x +} /// Struct for applying linear interpolation to a 3D /// density array. diff --git a/server/src/worldgen/util.rs b/server/src/worldgen/util.rs index 1fbd7225a..6f393d3a3 100644 --- a/server/src/worldgen/util.rs +++ b/server/src/worldgen/util.rs @@ -20,3 +20,7 @@ pub fn shuffle_seed_for_column(seed: u64, chunk: ChunkPosition, col_x: usize, co pub fn shuffle_seed_for_block(seed: u64, x: i32, z: i32) -> u64 { seed.wrapping_mul((x as u64).wrapping_mul(9324) ^ (z as u64).wrapping_shl(10)) } + +pub fn map(x: f32, bmin: f32, bmax: f32, amin: f32, amax: f32) -> f32 { + (x - bmin) * ((amax - amin) / (bmax - bmin)) + bmin +} From 3a2d05682176140c0b18d78fc66b300a0743f92c Mon Sep 17 00:00:00 2001 From: caelunshun Date: Wed, 25 Mar 2020 23:56:48 -0600 Subject: [PATCH 3/5] Start moving worldgen into separate crate --- Cargo.lock | 29 +++++- Cargo.toml | 2 + core/Cargo.toml | 2 +- server/Cargo.toml | 14 +-- server/src/lib.rs | 2 - worldgen/Cargo.toml | 15 +++ worldgen/devtools/Cargo.toml | 16 ++++ worldgen/devtools/imgui.ini | 5 + worldgen/devtools/src/biomes.rs | 94 +++++++++++++++++++ .../devtools/src/main.rs | 27 ++++-- worldgen/src/biome.rs | 35 +++++++ worldgen/src/biome/grow.rs | 74 +++++++++++++++ worldgen/src/biome/grow/continents.rs | 27 ++++++ worldgen/src/biome/grow/grid.rs | 37 ++++++++ worldgen/src/biome/grow/zoom.rs | 78 +++++++++++++++ worldgen/src/lib.rs | 29 ++++++ .../src/worldgen => worldgen/src}/noise.rs | 42 --------- worldgen/src/util.rs | 25 +++++ 18 files changed, 481 insertions(+), 72 deletions(-) create mode 100644 worldgen/Cargo.toml create mode 100644 worldgen/devtools/Cargo.toml create mode 100644 worldgen/devtools/imgui.ini create mode 100644 worldgen/devtools/src/biomes.rs rename server/src/devtools.rs => worldgen/devtools/src/main.rs (94%) create mode 100644 worldgen/src/biome.rs create mode 100644 worldgen/src/biome/grow.rs create mode 100644 worldgen/src/biome/grow/continents.rs create mode 100644 worldgen/src/biome/grow/grid.rs create mode 100644 worldgen/src/biome/grow/zoom.rs create mode 100644 worldgen/src/lib.rs rename {server/src/worldgen => worldgen/src}/noise.rs (90%) create mode 100644 worldgen/src/util.rs diff --git a/Cargo.lock b/Cargo.lock index 63c21ba0e..6ece15143 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -914,15 +914,13 @@ dependencies = [ "feather-codegen", "feather-core", "feather-item-block", + "feather-worldgen", "fecs", "futures", "hashbrown", "heapless", "hematite-nbt", "humantime-serde", - "imgui", - "imgui-wgpu", - "imgui-winit-support", "indexmap", "inventory", "itertools 0.9.0", @@ -930,7 +928,6 @@ dependencies = [ "lazy_static", "lock_api", "log", - "minifb", "mojang-api", "multimap", "nalgebra", @@ -960,6 +957,30 @@ dependencies = [ "tokio-util", "toml", "uuid", +] + +[[package]] +name = "feather-worldgen" +version = "0.1.0" +dependencies = [ + "feather-core", + "num-traits 0.2.11", + "rand 0.7.3", + "rand_xorshift 0.2.0", + "simdnoise", +] + +[[package]] +name = "feather-worldgen-devtools" +version = "0.1.0" +dependencies = [ + "anyhow", + "feather-core", + "feather-worldgen", + "imgui", + "imgui-wgpu", + "imgui-winit-support", + "minifb", "wgpu", "winit", ] diff --git a/Cargo.toml b/Cargo.toml index 1e5dad450..f3301e8bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,6 @@ members = [ "item_block", "codegen", "generator", + "worldgen", + "worldgen/devtools" ] diff --git a/core/Cargo.toml b/core/Cargo.toml index 0f9b13ddc..6618a80b2 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -24,7 +24,7 @@ byteorder = "1.3" vek = "0.9" nalgebra-glm = "0.6" lazy_static = "1.4" -uuid = "0.8" +uuid = { version = "0.8", features = ["serde"] } log = "0.4" num-traits = "0.2" num-derive = "0.3" diff --git a/server/Cargo.toml b/server/Cargo.toml index d05d1a5b6..3341a6ac6 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -18,6 +18,7 @@ feather-blocks = { path = "../blocks" } feather-core = { path = "../core" } feather-item-block = { path = "../item_block" } feather-codegen = { path = "../codegen" } +feather-worldgen = { path = "../worldgen" } # Core ECS + systems fecs = { git = "https://github.com/feather-rs/fecs", rev = "20d54b0ff8b11fbb76f55fec012e4feb66e20c42" } @@ -101,20 +102,7 @@ jemallocator = "0.3" thiserror = "1.0" anyhow = "1.0" -# Dependencies for dev tools GUI -imgui = { version = "0.3", optional = true } -winit = { version = "0.21", optional = true } # use old version for imgui-winit-support -imgui-wgpu = { version = "0.5", optional = true } -imgui-winit-support = { version = "0.3", optional = true } -wgpu = { version = "0.4", optional = true } -minifb = { version = "0.15", optional = true } - [features] -# Enables the dev tools GUI used for -# testing world generation. -# Pass --dev-tools on the CLI -# to run Feather in this mode. -dev-tools = ["imgui", "winit", "imgui-wgpu", "imgui-winit-support", "wgpu", "minifb"] nightly = ["hashbrown/nightly", "parking_lot/nightly"] [dev-dependencies] diff --git a/server/src/lib.rs b/server/src/lib.rs index 5d77c623c..82b8b768b 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -145,8 +145,6 @@ mod chunk_entities; pub mod chunk_logic; pub mod chunk_worker; pub mod config; -#[cfg(feature = "dev-tools")] -mod devtools; pub mod entity; pub mod game; pub mod io; diff --git a/worldgen/Cargo.toml b/worldgen/Cargo.toml new file mode 100644 index 000000000..57ae7af80 --- /dev/null +++ b/worldgen/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "feather-worldgen" +version = "0.1.0" +authors = ["caelunshun "] +edition = "2018" + +[dependencies] +feather-core = { path = "../core" } + +rand = "0.7" +rand_xorshift = "0.2" + +simdnoise = "3.1" + +num-traits = "0.2" diff --git a/worldgen/devtools/Cargo.toml b/worldgen/devtools/Cargo.toml new file mode 100644 index 000000000..7309ecce4 --- /dev/null +++ b/worldgen/devtools/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "feather-worldgen-devtools" +version = "0.1.0" +authors = ["caelunshun "] +edition = "2018" + +[dependencies] +feather-worldgen = { path = ".." } +feather-core = { path = "../../core" } +wgpu = "0.4" +winit = "0.21" +imgui = "0.3" +imgui-wgpu = "0.5" +imgui-winit-support = "0.3" +minifb = "0.15" +anyhow = "1.0" diff --git a/worldgen/devtools/imgui.ini b/worldgen/devtools/imgui.ini new file mode 100644 index 000000000..80e127503 --- /dev/null +++ b/worldgen/devtools/imgui.ini @@ -0,0 +1,5 @@ +[Window][Debug##Default] +Pos=77,64 +Size=400,400 +Collapsed=0 + diff --git a/worldgen/devtools/src/biomes.rs b/worldgen/devtools/src/biomes.rs new file mode 100644 index 000000000..e929d92b0 --- /dev/null +++ b/worldgen/devtools/src/biomes.rs @@ -0,0 +1,94 @@ +//! Debugging of the biomes grid. + +use crate::{VIEWER_HEIGHT, VIEWER_WIDTH}; +use feather_core::chunk::CHUNK_WIDTH; +use feather_core::{Biome, ChunkPosition}; +use feather_worldgen::biome::grow::GrowBiomeGenerator; +use feather_worldgen::biome::BiomeGenerator; +use imgui::{im_str, Ui}; + +pub struct State { + /// Requested length and width (in blocks) to view of the biome grid. + pub dimensions: i32, + pub seed: i32, +} + +impl Default for State { + fn default() -> Self { + Self { + dimensions: 4096, + seed: 0, + } + } +} + +impl State { + pub fn render(&mut self, ui: &Ui, buffer: &mut [u32], is_first_run: bool) -> bool { + ui.text(im_str!("Biome grid")); + + let dimensions_changed = ui + .input_int(im_str!("Dimensions (blocks)"), &mut self.dimensions) + .build(); + let seed_changed = ui.input_int(im_str!("Seed"), &mut self.seed).build(); + + if dimensions_changed || seed_changed || is_first_run { + let mut grid = vec![Biome::Plains; self.dimensions as usize * self.dimensions as usize]; + + let generator = GrowBiomeGenerator::new(); + + for x in 0..self.dimensions / CHUNK_WIDTH as i32 { + for z in 0..self.dimensions / CHUNK_WIDTH as i32 { + let chunk = ChunkPosition::new(x, z); + let biomes = generator.generate(self.seed as u64, chunk); + + if x + (CHUNK_WIDTH as i32) < self.dimensions + && z + (CHUNK_WIDTH as i32) < self.dimensions + { + for local_x in 0..CHUNK_WIDTH { + for local_z in 0..CHUNK_WIDTH { + let index = (x * CHUNK_WIDTH as i32 + local_x as i32) + * self.dimensions + + (z * CHUNK_WIDTH as i32 + local_z as i32); + + let index = index as usize; + + if grid.len() > index { + grid[index] = biomes[local_x][local_z]; + } + } + } + } + } + } + + let scale = self.dimensions as f64 / VIEWER_WIDTH as f64; + + for screen_x in 0..VIEWER_WIDTH { + for screen_z in 0..VIEWER_HEIGHT { + let x = (screen_x as f64 * scale).round() as usize; + let z = (screen_z as f64 * scale).round() as usize; + + let index = x * self.dimensions as usize + z; + + let color = if index >= grid.len() { + 0x00 // black + } else { + let biome = grid[index]; + + if biome == Biome::Ocean { + 0xFF // blue + } else { + 0xFF << 8 // green + } + }; + + buffer[screen_x * VIEWER_WIDTH + screen_z] = color; + } + } + + true + } else { + false + } + } +} diff --git a/server/src/devtools.rs b/worldgen/devtools/src/main.rs similarity index 94% rename from server/src/devtools.rs rename to worldgen/devtools/src/main.rs index 2a442df85..cfbf5eece 100644 --- a/server/src/devtools.rs +++ b/worldgen/devtools/src/main.rs @@ -1,7 +1,5 @@ -//! Implements a GUI for performing assorted debugging tasks. -//! Currently only used for world generation. +//! Implements a GUI for debugging world generation. -use crate::worldgen; use imgui_winit_support::{HiDpiMode, WinitPlatform}; use std::time::Instant; use winit::dpi::LogicalSize; @@ -14,6 +12,8 @@ pub const UI_HEIGHT: usize = 1080 / 2; pub const VIEWER_WIDTH: usize = 512; pub const VIEWER_HEIGHT: usize = 512; +mod biomes; + struct Context { window: Window, surface: wgpu::Surface, @@ -27,12 +27,19 @@ struct Context { } enum State { - Worldgen(worldgen::devtools::State), + Biomes(biomes::State), +} + +fn main() { + match run() { + Err(e) => println!("ERROR: {}", e), + Ok(_) => (), + } } pub fn run() -> anyhow::Result<()> { let (mut context, event_loop, mut imgui) = init_context()?; - let mut state = State::Worldgen(worldgen::devtools::State::default()); + let mut state = State::Biomes(biomes::State::default()); let mut last_frame = Instant::now(); @@ -107,10 +114,12 @@ pub fn run() -> anyhow::Result<()> { { match &mut state { - State::Worldgen(state) => { + State::Biomes(state) => { if state.render(&ui, &mut buffer, is_first_run) { buffer_changed = true; } + + is_first_run = false; } } } @@ -134,14 +143,12 @@ pub fn run() -> anyhow::Result<()> { .platform .handle_event(imgui.io_mut(), &context.window, &event); - if buffer_changed || is_first_run { + if buffer_changed { display_window .update_with_buffer(&buffer, VIEWER_WIDTH, VIEWER_HEIGHT) .unwrap(); } - - is_first_run = false; - }); + }) } fn init_context() -> anyhow::Result<(Context, EventLoop<()>, imgui::Context)> { diff --git a/worldgen/src/biome.rs b/worldgen/src/biome.rs new file mode 100644 index 000000000..d2ea37cf5 --- /dev/null +++ b/worldgen/src/biome.rs @@ -0,0 +1,35 @@ +use feather_core::chunk::CHUNK_WIDTH; +use feather_core::{Biome, ChunkPosition}; +use std::ops::{Deref, DerefMut}; + +pub mod grow; + +/// Stores the chunks of a biome. +#[derive(Debug, Clone)] +pub struct Biomes([[Biome; CHUNK_WIDTH]; CHUNK_WIDTH]); + +impl Deref for Biomes { + type Target = [[Biome; CHUNK_WIDTH]]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Biomes { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Default for Biomes { + fn default() -> Self { + Self([[Biome::Plains; CHUNK_WIDTH]; CHUNK_WIDTH]) + } +} + +/// Implemented by biome generators. +pub trait BiomeGenerator: Send + Sync + 'static { + /// Generates a biome grid for the given chunk. + fn generate(&self, seed: u64, position: ChunkPosition) -> Biomes; +} diff --git a/worldgen/src/biome/grow.rs b/worldgen/src/biome/grow.rs new file mode 100644 index 000000000..eec6ee6cd --- /dev/null +++ b/worldgen/src/biome/grow.rs @@ -0,0 +1,74 @@ +pub mod continents; +pub mod grid; +pub mod zoom; + +use crate::biome::grow::continents::ContinentsLayer; +use crate::biome::grow::zoom::ZoomLayer; +use crate::biome::{BiomeGenerator, Biomes}; +use feather_core::{Biome, ChunkPosition}; +pub use grid::Grid; + +const CHUNK_WIDTH: i32 = feather_core::chunk::CHUNK_WIDTH as i32; + +/// Applies some operation to the integer grid. +pub trait GridLayer: Send + Sync + 'static { + fn generate(&self, seed: u64, x: i32, z: i32, size_x: i32, size_z: i32) -> Grid; +} + +pub struct GrowBiomeGenerator { + /// Recursive chain of biome operators. + root: Box, +} + +macro_rules! layer_chain { + ($first:ident, $($generator:ident),+) => { + { + Box::new($first { + below: layer_chain!($($generator ),*), + }) + } + }; + ($first:ident) => { + { + Box::new($first) + } + } +} + +impl GrowBiomeGenerator { + pub fn new() -> Self { + let root = layer_chain! { + ZoomLayer, + ZoomLayer, + ZoomLayer, + ZoomLayer, + ContinentsLayer + }; + + Self { root } + } +} + +impl BiomeGenerator for GrowBiomeGenerator { + fn generate(&self, seed: u64, position: ChunkPosition) -> Biomes { + let mut biomes = Biomes::default(); + + let grid = self.root.generate( + seed, + position.x * CHUNK_WIDTH, + position.z * CHUNK_WIDTH, + CHUNK_WIDTH, + CHUNK_WIDTH, + ); + + // Interpret final grid results as biome IDs. + for x in 0..CHUNK_WIDTH { + for z in 0..CHUNK_WIDTH { + biomes[x as usize][z as usize] = Biome::from_protocol_id(i32::from(grid.at(x, z))) + .expect("biome generator returned invalid biome ID"); + } + } + + biomes + } +} diff --git a/worldgen/src/biome/grow/continents.rs b/worldgen/src/biome/grow/continents.rs new file mode 100644 index 000000000..c3041b8fe --- /dev/null +++ b/worldgen/src/biome/grow/continents.rs @@ -0,0 +1,27 @@ +use crate::biome::grow::{Grid, GridLayer}; +use simdnoise::NoiseBuilder; + +pub struct ContinentsLayer; + +impl GridLayer for ContinentsLayer { + fn generate(&self, seed: u64, x: i32, z: i32, size_x: i32, size_z: i32) -> Grid { + let mut grid = Grid::new(size_x, size_z); + + let (noise, _min, _max) = + NoiseBuilder::fbm_2d_offset(x as f32, size_x as usize, z as f32, size_x as usize) + .with_seed(seed as i32) + .with_freq(0.02) + .generate(); + + for i in 0..size_x { + for j in 0..size_z { + let noise_val = noise[(i + j * size_x) as usize] * 2.0; + + let val = if noise_val > 0.05 { 1 } else { 0 }; + grid.set_at(i, j, val); + } + } + + grid + } +} diff --git a/worldgen/src/biome/grow/grid.rs b/worldgen/src/biome/grow/grid.rs new file mode 100644 index 000000000..7bdf84288 --- /dev/null +++ b/worldgen/src/biome/grow/grid.rs @@ -0,0 +1,37 @@ +use crate::util::IntoUsize; + +/// Wrapper over `Vec`. +#[derive(Debug, Clone)] +pub struct Grid { + pub(crate) vec: Vec, + pub size_x: usize, + pub size_z: usize, +} + +impl Grid { + /// Creates a new `Grid` with the provided dimensions. + /// Values are initialized with 0. + pub fn new(size_x: impl IntoUsize, size_z: impl IntoUsize) -> Self { + let size_x = size_x.into_usize(); + let size_z = size_z.into_usize(); + Self { + vec: vec![0; size_x * size_z], + size_x, + size_z, + } + } + + /// Retrieves the value at (x, z). + pub fn at(&self, x: impl IntoUsize, z: impl IntoUsize) -> u16 { + let x = x.into_usize(); + let z = z.into_usize(); + self.vec[x + (z * self.size_x)] + } + + /// Sets the value at (x, z). + pub fn set_at(&mut self, x: impl IntoUsize, z: impl IntoUsize, val: u16) { + let x = x.into_usize(); + let z = z.into_usize(); + self.vec[x + (z * self.size_x)] = val; + } +} diff --git a/worldgen/src/biome/grow/zoom.rs b/worldgen/src/biome/grow/zoom.rs new file mode 100644 index 000000000..713488181 --- /dev/null +++ b/worldgen/src/biome/grow/zoom.rs @@ -0,0 +1,78 @@ +use crate::biome::grow::{Grid, GridLayer}; +use crate::util::scramble2; +use rand::{Rng, SeedableRng}; +use rand_xorshift::XorShiftRng; + +pub struct ZoomLayer { + pub below: Box, +} + +impl GridLayer for ZoomLayer { + fn generate(&self, seed: u64, x: i32, z: i32, size_x: i32, size_z: i32) -> Grid { + let below_x = x / 2; + let below_z = z / 2; + let below_size_x = (size_x / 2) + 2; + let below_size_z = (size_z / 2) + 2; + let input = self + .below + .generate(seed + 1, below_x, below_z, below_size_x, below_size_z); + + let zoom_size_x = (below_size_x - 1) * 2; + let zoom_size_z = (below_size_z - 1) * 2; + + let mut temp = Grid::new(zoom_size_x, zoom_size_z); + + for i in 0..below_size_z - 1 { + let mut upper_left = input.at(0, i); + let mut lower_left = input.at(0, i + 1); + for j in 0..below_size_z - 1 { + let mut rng = XorShiftRng::seed_from_u64(scramble2(seed, i, j)); + + temp.set_at(j * 2, i * 2, upper_left); + temp.set_at( + j * 2, + i * 2 + 1, + select(&mut rng, &[upper_left, lower_left]), + ); + + let upper_right = input.at(j + 1, i); + let lower_right = input.at(j + 1, i + 1); + + temp.set_at( + j * 2 + 1, + i * 2, + select(&mut rng, &[upper_left, upper_right]), + ); + temp.set_at( + j * 2 + 1, + i * 2 + 1, + select( + &mut rng, + &[upper_left, upper_right, lower_left, lower_right], + ), + ); + + upper_left = upper_right; + lower_left = lower_right; + } + } + + let mut result = Grid::new(size_x, size_z); + + for i in 0..size_z { + for j in 0..size_x { + result.set_at(j, i, temp.at((x % 2) + j, (z % 2) + i)); + } + } + + result + } +} + +fn select(rng: &mut impl Rng, values: &[T]) -> T +where + T: Copy, +{ + let index = rng.gen_range(0, values.len()); + values[index] +} diff --git a/worldgen/src/lib.rs b/worldgen/src/lib.rs new file mode 100644 index 000000000..24cd937e3 --- /dev/null +++ b/worldgen/src/lib.rs @@ -0,0 +1,29 @@ +//! World generation for Feather. + +use crate::biome::BiomeGenerator; + +pub mod biome; +pub mod noise; +pub mod util; + +/// Defines a world generation pipeline. +/// +/// World generation is based on a number of steps: +/// * Biome generation, which generates a biome grid +/// defining the biome at each column of blocks in the chunk. +/// +/// * Shape generation, which generates the shape of chunks. +/// This step usually uses Perlin noise to generate density values, +/// using those values to decide whether a block is solid or not. +/// The output of this step is a bit array with bits set for +/// blocks which should be solid. +/// +/// * Composition, which takes in the generated shape and biome +/// and turns the binary solid/air grid into actual blocks based +/// on the local conditions. +/// +/// * Finishers, which add additional structures on top of the +/// generated chunk: e.g. grass, trees, buildings, caves. +pub struct WorldGenerator { + biome_generator: Box, +} diff --git a/server/src/worldgen/noise.rs b/worldgen/src/noise.rs similarity index 90% rename from server/src/worldgen/noise.rs rename to worldgen/src/noise.rs index b433474b3..372cd6d7a 100644 --- a/server/src/worldgen/noise.rs +++ b/worldgen/src/noise.rs @@ -1,46 +1,4 @@ use num_traits::ToPrimitive; -use simdnoise::FbmSettings; - -/// Extension trait for noise settings. -pub trait NoiseExt { - /// Generates noise normalized to `[0, 1]`. - /// - /// http://digitalfreepen.com/2017/06/20/range-perlin-noise.html - fn generate_normalized(self) -> Vec; -} - -impl NoiseExt for FbmSettings { - fn generate_normalized(self) -> Vec { - let mut res = self.generate().0; - - res.iter_mut().for_each(|x| { - *x = normalize(*x); - }); - - res - } -} - -pub fn normalized_fbm( - x: f32, - y: f32, - freq: f32, - lacunarity: f32, - gain: f32, - octaves: u8, - seed: u64, -) -> f32 { - normalize(unsafe { - simdnoise::scalar::fbm_2d(x * freq, y * freq, lacunarity, gain, octaves, seed as i32) - }) -} - -/// Normalizes a noise value to [0, 1]. -pub fn normalize(mut x: f32) -> f32 { - x += 0.5f32.sqrt(); - x /= 0.5f32.sqrt() * 2.0; - x -} /// Struct for applying linear interpolation to a 3D /// density array. diff --git a/worldgen/src/util.rs b/worldgen/src/util.rs new file mode 100644 index 000000000..414185680 --- /dev/null +++ b/worldgen/src/util.rs @@ -0,0 +1,25 @@ +use num_traits::ToPrimitive; + +pub fn scramble(seed: u64, with: u64) -> u64 { + // TODO: better algorithm. I just wrote random arithmetic. + seed.wrapping_mul(with) + .wrapping_add(with ^ seed) + .wrapping_mul(with.wrapping_shl(32).wrapping_add(0x86cf)) +} + +pub fn scramble2(seed: u64, a: i32, b: i32) -> u64 { + scramble(seed, ((a as u64) << 32) | b as u64) +} + +pub trait IntoUsize { + fn into_usize(self) -> usize; +} + +impl IntoUsize for T +where + T: ToPrimitive, +{ + fn into_usize(self) -> usize { + self.to_usize().expect("failed to convert to `usize`") + } +} From a13a9b13f76c607e4c7a88df4a1b50e8edd74adf Mon Sep 17 00:00:00 2001 From: caelunshun Date: Fri, 27 Mar 2020 18:27:51 -0600 Subject: [PATCH 4/5] Initial continents generator for biomes --- server/src/worldgen/mod.rs | 3 -- worldgen/devtools/imgui.ini | 4 +-- worldgen/devtools/src/biomes.rs | 43 +++++++++++++++++++++--- worldgen/src/biome/grow.rs | 39 ++++++++++++++++------ worldgen/src/biome/grow/continents.rs | 34 ++++++++++++++++--- worldgen/src/biome/grow/smooth.rs | 47 +++++++++++++++++++++++++++ worldgen/src/biome/grow/zoom.rs | 16 +++------ worldgen/src/lib.rs | 2 +- 8 files changed, 151 insertions(+), 37 deletions(-) create mode 100644 worldgen/src/biome/grow/smooth.rs diff --git a/server/src/worldgen/mod.rs b/server/src/worldgen/mod.rs index 80984a3b4..da777d89a 100644 --- a/server/src/worldgen/mod.rs +++ b/server/src/worldgen/mod.rs @@ -8,10 +8,7 @@ use feather_core::{Biome, Block, Chunk, ChunkPosition}; mod biomes; mod composition; mod density_map; -#[cfg(feature = "dev-tools")] -pub mod devtools; mod finishers; -pub mod noise; mod superflat; mod util; pub mod voronoi; diff --git a/worldgen/devtools/imgui.ini b/worldgen/devtools/imgui.ini index 80e127503..6ae86949a 100644 --- a/worldgen/devtools/imgui.ini +++ b/worldgen/devtools/imgui.ini @@ -1,5 +1,5 @@ [Window][Debug##Default] -Pos=77,64 -Size=400,400 +Pos=45,105 +Size=727,419 Collapsed=0 diff --git a/worldgen/devtools/src/biomes.rs b/worldgen/devtools/src/biomes.rs index e929d92b0..68fd710be 100644 --- a/worldgen/devtools/src/biomes.rs +++ b/worldgen/devtools/src/biomes.rs @@ -1,10 +1,9 @@ //! Debugging of the biomes grid. use crate::{VIEWER_HEIGHT, VIEWER_WIDTH}; -use feather_core::chunk::CHUNK_WIDTH; -use feather_core::{Biome, ChunkPosition}; +use feather_core::Biome; +use feather_worldgen::biome::grow::continents::{DRY, ICE, MOUNTAIN, OCEAN, TEMPERATE}; use feather_worldgen::biome::grow::GrowBiomeGenerator; -use feather_worldgen::biome::BiomeGenerator; use imgui::{im_str, Ui}; pub struct State { @@ -33,7 +32,7 @@ impl State { if dimensions_changed || seed_changed || is_first_run { let mut grid = vec![Biome::Plains; self.dimensions as usize * self.dimensions as usize]; - + /* let generator = GrowBiomeGenerator::new(); for x in 0..self.dimensions / CHUNK_WIDTH as i32 { @@ -59,6 +58,32 @@ impl State { } } } + }*/ + + let generator = GrowBiomeGenerator::new(); + + let generated = + generator + .root + .generate(self.seed as u64, 0, 0, self.dimensions, self.dimensions); + + for x in 0..self.dimensions { + for z in 0..self.dimensions { + let val = generated.at(x, z); + grid[(x * self.dimensions + z) as usize] = if val == OCEAN { + Biome::Ocean + } else if val == DRY { + Biome::Desert + } else if val == TEMPERATE { + Biome::Plains + } else if val == MOUNTAIN { + Biome::Mountains + } else if val == ICE { + Biome::SnowyTaiga + } else { + panic!("invalid biome value {}", val); + } + } } let scale = self.dimensions as f64 / VIEWER_WIDTH as f64; @@ -77,8 +102,16 @@ impl State { if biome == Biome::Ocean { 0xFF // blue - } else { + } else if biome == Biome::Plains { 0xFF << 8 // green + } else if biome == Biome::SnowyTaiga { + (0xFF << 16) | (0xFF << 8) | 0xFF // white + } else if biome == Biome::Desert { + (0xFF << 16) | (0xFF << 8) // yellow + } else if biome == Biome::Mountains { + (0xFF / 2) << 8 // dark green + } else { + panic!(); } }; diff --git a/worldgen/src/biome/grow.rs b/worldgen/src/biome/grow.rs index eec6ee6cd..7f471f7a9 100644 --- a/worldgen/src/biome/grow.rs +++ b/worldgen/src/biome/grow.rs @@ -1,12 +1,15 @@ pub mod continents; pub mod grid; +pub mod smooth; pub mod zoom; use crate::biome::grow::continents::ContinentsLayer; use crate::biome::grow::zoom::ZoomLayer; use crate::biome::{BiomeGenerator, Biomes}; -use feather_core::{Biome, ChunkPosition}; +use feather_core::ChunkPosition; pub use grid::Grid; +use rand::Rng; +use smooth::SmoothLayer; const CHUNK_WIDTH: i32 = feather_core::chunk::CHUNK_WIDTH as i32; @@ -17,7 +20,7 @@ pub trait GridLayer: Send + Sync + 'static { pub struct GrowBiomeGenerator { /// Recursive chain of biome operators. - root: Box, + pub root: Box, } macro_rules! layer_chain { @@ -35,11 +38,25 @@ macro_rules! layer_chain { } } +impl Default for GrowBiomeGenerator { + fn default() -> Self { + Self::new() + } +} + impl GrowBiomeGenerator { pub fn new() -> Self { let root = layer_chain! { + SmoothLayer, + ZoomLayer, + ZoomLayer, + SmoothLayer, ZoomLayer, ZoomLayer, + SmoothLayer, + ZoomLayer, + ZoomLayer, + SmoothLayer, ZoomLayer, ZoomLayer, ContinentsLayer @@ -51,9 +68,9 @@ impl GrowBiomeGenerator { impl BiomeGenerator for GrowBiomeGenerator { fn generate(&self, seed: u64, position: ChunkPosition) -> Biomes { - let mut biomes = Biomes::default(); + let biomes = Biomes::default(); - let grid = self.root.generate( + let _grid = self.root.generate( seed, position.x * CHUNK_WIDTH, position.z * CHUNK_WIDTH, @@ -62,13 +79,15 @@ impl BiomeGenerator for GrowBiomeGenerator { ); // Interpret final grid results as biome IDs. - for x in 0..CHUNK_WIDTH { - for z in 0..CHUNK_WIDTH { - biomes[x as usize][z as usize] = Biome::from_protocol_id(i32::from(grid.at(x, z))) - .expect("biome generator returned invalid biome ID"); - } - } biomes } } + +pub fn select(rng: &mut impl Rng, values: &[T]) -> T +where + T: Copy, +{ + let index = rng.gen_range(0, values.len()); + values[index] +} diff --git a/worldgen/src/biome/grow/continents.rs b/worldgen/src/biome/grow/continents.rs index c3041b8fe..73441bd70 100644 --- a/worldgen/src/biome/grow/continents.rs +++ b/worldgen/src/biome/grow/continents.rs @@ -3,21 +3,47 @@ use simdnoise::NoiseBuilder; pub struct ContinentsLayer; +pub const OCEAN: u16 = 0; +pub const DRY: u16 = 1; +pub const TEMPERATE: u16 = 2; +pub const MOUNTAIN: u16 = 3; +pub const ICE: u16 = 4; + impl GridLayer for ContinentsLayer { fn generate(&self, seed: u64, x: i32, z: i32, size_x: i32, size_z: i32) -> Grid { let mut grid = Grid::new(size_x, size_z); - let (noise, _min, _max) = + let (continents_noise, _min, _max) = NoiseBuilder::fbm_2d_offset(x as f32, size_x as usize, z as f32, size_x as usize) .with_seed(seed as i32) - .with_freq(0.02) + .with_freq(0.5) .generate(); + let biome_group_noise = + NoiseBuilder::fbm_2d_offset(x as f32, size_x as usize, z as f32, size_z as usize) + .with_seed(seed as i32 + 1000) + .with_freq(1.5) + .generate() + .0; + for i in 0..size_x { for j in 0..size_z { - let noise_val = noise[(i + j * size_x) as usize] * 2.0; + let noise_val = continents_noise[(i + j * size_x) as usize] * 2.0; - let val = if noise_val > 0.05 { 1 } else { 0 }; + let val = if noise_val > 0.045 { + let biome_group = biome_group_noise[(i + j * size_x) as usize] * 2.0; + if biome_group > 0.15 { + ICE + } else if biome_group > 0.0 { + TEMPERATE + } else if biome_group > -0.05 { + MOUNTAIN + } else { + DRY + } + } else { + OCEAN + }; grid.set_at(i, j, val); } } diff --git a/worldgen/src/biome/grow/smooth.rs b/worldgen/src/biome/grow/smooth.rs new file mode 100644 index 000000000..48bae82e1 --- /dev/null +++ b/worldgen/src/biome/grow/smooth.rs @@ -0,0 +1,47 @@ +use crate::biome::grow::{select, Grid, GridLayer}; +use crate::util::scramble2; +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; + +pub struct SmoothLayer { + pub below: Box, +} + +impl GridLayer for SmoothLayer { + fn generate(&self, seed: u64, x: i32, z: i32, size_x: i32, size_z: i32) -> Grid { + let lower_x = x - 1; + let lower_z = z - 1; + let lower_size_x = size_x + 2; + let lower_size_z = size_z + 2; + let input = self + .below + .generate(seed + 1, lower_x, lower_z, lower_size_x, lower_size_z); + + let mut result = Grid::new(size_x, size_z); + + for i in 0..size_z { + for j in 0..size_x { + let mut rng = XorShiftRng::seed_from_u64(scramble2(seed, z + i, x + j)); + + let val = input.at(j + 1, i + 1); + let above = input.at(j + 1, i); + let below = input.at(j + 1, i + 2); + let left = input.at(j, i + 1); + let right = input.at(j + 2, i + 1); + + let val = if left == right && above == below { + select(&mut rng, &[left, above]) + } else if left == right { + left + } else if above == below { + above + } else { + val + }; + result.set_at(j, i, val); + } + } + + result + } +} diff --git a/worldgen/src/biome/grow/zoom.rs b/worldgen/src/biome/grow/zoom.rs index 713488181..762e25fd1 100644 --- a/worldgen/src/biome/grow/zoom.rs +++ b/worldgen/src/biome/grow/zoom.rs @@ -1,6 +1,6 @@ -use crate::biome::grow::{Grid, GridLayer}; +use crate::biome::grow::{select, Grid, GridLayer}; use crate::util::scramble2; -use rand::{Rng, SeedableRng}; +use rand::SeedableRng; use rand_xorshift::XorShiftRng; pub struct ZoomLayer { @@ -26,7 +26,7 @@ impl GridLayer for ZoomLayer { let mut upper_left = input.at(0, i); let mut lower_left = input.at(0, i + 1); for j in 0..below_size_z - 1 { - let mut rng = XorShiftRng::seed_from_u64(scramble2(seed, i, j)); + let mut rng = XorShiftRng::seed_from_u64(scramble2(seed, z + i, x + j)); temp.set_at(j * 2, i * 2, upper_left); temp.set_at( @@ -61,18 +61,10 @@ impl GridLayer for ZoomLayer { for i in 0..size_z { for j in 0..size_x { - result.set_at(j, i, temp.at((x % 2) + j, (z % 2) + i)); + result.set_at(j, i, temp.at((x.abs() % 2) + j, (z.abs() % 2) + i)); } } result } } - -fn select(rng: &mut impl Rng, values: &[T]) -> T -where - T: Copy, -{ - let index = rng.gen_range(0, values.len()); - values[index] -} diff --git a/worldgen/src/lib.rs b/worldgen/src/lib.rs index 24cd937e3..bf451a2a3 100644 --- a/worldgen/src/lib.rs +++ b/worldgen/src/lib.rs @@ -25,5 +25,5 @@ pub mod util; /// * Finishers, which add additional structures on top of the /// generated chunk: e.g. grass, trees, buildings, caves. pub struct WorldGenerator { - biome_generator: Box, + _biome_generator: Box, } From 331da9206ca5707eeb0d49d79b3c63746ca44461 Mon Sep 17 00:00:00 2001 From: caelunshun Date: Mon, 6 Apr 2020 10:22:20 -0600 Subject: [PATCH 5/5] More work --- worldgen/devtools/imgui.ini | 2 +- worldgen/src/biome/grow/continents.rs | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/worldgen/devtools/imgui.ini b/worldgen/devtools/imgui.ini index 6ae86949a..9169465b8 100644 --- a/worldgen/devtools/imgui.ini +++ b/worldgen/devtools/imgui.ini @@ -1,5 +1,5 @@ [Window][Debug##Default] -Pos=45,105 +Pos=44,106 Size=727,419 Collapsed=0 diff --git a/worldgen/src/biome/grow/continents.rs b/worldgen/src/biome/grow/continents.rs index 73441bd70..8c31f8964 100644 --- a/worldgen/src/biome/grow/continents.rs +++ b/worldgen/src/biome/grow/continents.rs @@ -1,4 +1,6 @@ use crate::biome::grow::{Grid, GridLayer}; +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; use simdnoise::NoiseBuilder; pub struct ContinentsLayer; @@ -16,19 +18,27 @@ impl GridLayer for ContinentsLayer { let (continents_noise, _min, _max) = NoiseBuilder::fbm_2d_offset(x as f32, size_x as usize, z as f32, size_x as usize) .with_seed(seed as i32) - .with_freq(0.5) + .with_freq(0.3) .generate(); let biome_group_noise = NoiseBuilder::fbm_2d_offset(x as f32, size_x as usize, z as f32, size_z as usize) .with_seed(seed as i32 + 1000) - .with_freq(1.5) + .with_freq(1.2) .generate() .0; for i in 0..size_x { for j in 0..size_z { - let noise_val = continents_noise[(i + j * size_x) as usize] * 2.0; + let mut noise_val = continents_noise[(i + j * size_x) as usize] as f64 * 2.0; + + // Ensure area around origin will be land. + // This is done by giving a boost to noise_val + // f(x)=1/x where x is the distance to the origin + // times a coefficient. + let abs_x = i + x; + let abs_z = j + z; + noise_val += 1.0 / (f64::from(abs_x * abs_x + abs_z * abs_z).sqrt() * 3.0); let val = if noise_val > 0.045 { let biome_group = biome_group_noise[(i + j * size_x) as usize] * 2.0;