Merge branch 'haslersn/block-groups' into 'master'

common: Rework `Chunk` and `Chonk` implementation

See merge request veloren/veloren!475
This commit is contained in:
Joshua Barretto 2019-09-07 09:14:54 +00:00
commit a9f06b1c65
34 changed files with 1218 additions and 484 deletions

120
Cargo.lock generated
View File

@ -244,6 +244,17 @@ name = "block"
version = "0.1.6" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bstr"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "0.5.3" version = "0.5.3"
@ -555,6 +566,39 @@ dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "criterion"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
"cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "criterion-plot"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "crossbeam" name = "crossbeam"
version = "0.4.1" version = "0.4.1"
@ -687,6 +731,26 @@ dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "csv"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "csv-core"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "daggy" name = "daggy"
version = "0.5.0" version = "0.5.0"
@ -1444,6 +1508,14 @@ dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "itertools"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.4" version = "0.4.4"
@ -1635,6 +1707,9 @@ dependencies = [
name = "memchr" name = "memchr"
version = "2.2.1" version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "memmap" name = "memmap"
@ -2460,6 +2535,15 @@ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "rand_os"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "rand_pcg" name = "rand_pcg"
version = "0.1.2" version = "0.1.2"
@ -2477,6 +2561,14 @@ dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "rand_xoshiro"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "rawpointer" name = "rawpointer"
version = "0.1.0" version = "0.1.0"
@ -2552,6 +2644,14 @@ dependencies = [
"utf8-ranges 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "regex-automata"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.5.6" version = "0.5.6"
@ -3038,6 +3138,15 @@ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "tinytemplate"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "tuple_utils" name = "tuple_utils"
version = "0.2.0" version = "0.2.0"
@ -3143,6 +3252,7 @@ name = "veloren-common"
version = "0.3.0" version = "0.3.0"
dependencies = [ dependencies = [
"bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"dot_vox 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "dot_vox 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"find_folder 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "find_folder 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3493,6 +3603,7 @@ dependencies = [
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
"checksum blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bf775a81bb2d464e20ff170ac20316c7b08a43d11dbc72f0f82e8e8d3d6d0499" "checksum blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bf775a81bb2d464e20ff170ac20316c7b08a43d11dbc72f0f82e8e8d3d6d0499"
"checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245"
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
@ -3529,6 +3640,8 @@ dependencies = [
"checksum coreaudio-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "78fdbabf58d5b1f461e31b94a571c109284f384cec619a3d96e66ec55b4de82b" "checksum coreaudio-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "78fdbabf58d5b1f461e31b94a571c109284f384cec619a3d96e66ec55b4de82b"
"checksum cpal 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58ae1ed6536b1b233f5e3aeb6997a046ddb4d05e3f61701b58a92eb254a829e" "checksum cpal 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58ae1ed6536b1b233f5e3aeb6997a046ddb4d05e3f61701b58a92eb254a829e"
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
"checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6"
"checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2"
"checksum crossbeam 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7408247b1b87f480890f28b670c5f8d9a8a4274833433fe74dc0dfd46d33650" "checksum crossbeam 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7408247b1b87f480890f28b670c5f8d9a8a4274833433fe74dc0dfd46d33650"
"checksum crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c" "checksum crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c"
"checksum crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b85741761b7f160bc5e7e0c14986ef685b7f8bf9b7ad081c60c604bb4649827" "checksum crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b85741761b7f160bc5e7e0c14986ef685b7f8bf9b7ad081c60c604bb4649827"
@ -3542,6 +3655,8 @@ dependencies = [
"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" "checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015"
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d"
"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c"
"checksum daggy 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9293a0da7d1bc1f30090ece4d9f9de79a07be7302ddb00e5eb1fefb6ee6409e2" "checksum daggy 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9293a0da7d1bc1f30090ece4d9f9de79a07be7302ddb00e5eb1fefb6ee6409e2"
"checksum deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4" "checksum deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4"
"checksum derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6073e9676dbebdddeabaeb63e3b7cefd23c86f5c41d381ee1237cc77b1079898" "checksum derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6073e9676dbebdddeabaeb63e3b7cefd23c86f5c41d381ee1237cc77b1079898"
@ -3621,6 +3736,7 @@ dependencies = [
"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" "checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
"checksum instant 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d6706e8fb9de9be6143801a75747fa2209855b13d74ee994e30d86b38afdf77f" "checksum instant 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d6706e8fb9de9be6143801a75747fa2209855b13d74ee994e30d86b38afdf77f"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum jpeg-decoder 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c1aae18ffeeae409c6622c3b6a7ee49792a7e5a062eea1b135fbb74e301792ba" "checksum jpeg-decoder 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c1aae18ffeeae409c6622c3b6a7ee49792a7e5a062eea1b135fbb74e301792ba"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
@ -3735,8 +3851,10 @@ dependencies = [
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" "checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff"
"checksum rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebac11a9d2e11f2af219b8b8d833b76b1ea0e054aa0e8d8e9e4cbde353bdf019" "checksum rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebac11a9d2e11f2af219b8b8d833b76b1ea0e054aa0e8d8e9e4cbde353bdf019"
"checksum rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b0186e22767d5b9738a05eab7c6ac90b15db17e5b5f9bd87976dd7d89a10a4" "checksum rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b0186e22767d5b9738a05eab7c6ac90b15db17e5b5f9bd87976dd7d89a10a4"
"checksum rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe0df8435ac0c397d467b6cad6d25543d06e8a019ef3f6af3c384597515bd2" "checksum rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe0df8435ac0c397d467b6cad6d25543d06e8a019ef3f6af3c384597515bd2"
@ -3745,6 +3863,7 @@ dependencies = [
"checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" "checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d"
"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" "checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
"checksum regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d8297cc20bbb6184f8b45ff61c8ee6a9ac56c156cec8e38c3e5084773c44ad" "checksum regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d8297cc20bbb6184f8b45ff61c8ee6a9ac56c156cec8e38c3e5084773c44ad"
"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9"
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" "checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" "checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f"
"checksum rodio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d0f961b254e66d147a7b550c78b01308934c97d807a34b417fd0f5a0a0f3a2d" "checksum rodio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d0f961b254e66d147a7b550c78b01308934c97d807a34b417fd0f5a0a0f3a2d"
@ -3801,6 +3920,7 @@ dependencies = [
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum tiff 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b7c2cfc4742bd8a32f2e614339dd8ce30dbcf676bb262bd63a2327bc5df57d" "checksum tiff 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b7c2cfc4742bd8a32f2e614339dd8ce30dbcf676bb262bd63a2327bc5df57d"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20"
"checksum tuple_utils 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbfecd7bb8f0a3e96b3b31c46af2677a55a588767c0091f484601424fcb20e7e" "checksum tuple_utils 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbfecd7bb8f0a3e96b3b31c46af2677a55a588767c0091f484601424fcb20e7e"
"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
"checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874" "checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874"

View File

@ -12,12 +12,12 @@ use common::{
msg::{ClientMsg, ClientState, RequestStateError, ServerError, ServerInfo, ServerMsg}, msg::{ClientMsg, ClientState, RequestStateError, ServerError, ServerInfo, ServerMsg},
net::PostBox, net::PostBox,
state::{State, Uid}, state::{State, Uid},
terrain::{block::Block, chonk::ChonkMetrics, TerrainChunk, TerrainChunkSize}, terrain::{block::Block, TerrainChunk, TerrainChunkSize},
vol::VolSize, vol::RectVolSize,
ChatType, ChatType,
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use log::{info, log_enabled, warn}; use log::warn;
use std::{ use std::{
net::SocketAddr, net::SocketAddr,
sync::Arc, sync::Arc,
@ -210,7 +210,7 @@ impl Client {
.cloned()? .cloned()?
.0, .0,
) )
.map2(Vec2::from(TerrainChunkSize::SIZE), |e: f32, sz| { .map2(TerrainChunkSize::RECT_SIZE, |e: f32, sz| {
(e as u32).div_euclid(sz) as i32 (e as u32).div_euclid(sz) as i32
}); });
@ -398,6 +398,7 @@ impl Client {
} }
} }
/*
// Output debug metrics // Output debug metrics
if log_enabled!(log::Level::Info) && self.tick % 600 == 0 { if log_enabled!(log::Level::Info) && self.tick % 600 == 0 {
let metrics = self let metrics = self
@ -407,6 +408,7 @@ impl Client {
.fold(ChonkMetrics::default(), |a, (_, c)| a + c.get_metrics()); .fold(ChonkMetrics::default(), |a, (_, c)| a + c.get_metrics());
info!("{:?}", metrics); info!("{:?}", metrics);
} }
*/
// 7) Finish the tick, pass control back to the frontend. // 7) Finish the tick, pass control back to the frontend.
self.tick += 1; self.tick += 1;

View File

@ -28,3 +28,10 @@ find_folder = "0.3.0"
parking_lot = "0.9.0" parking_lot = "0.9.0"
crossbeam = "0.7.2" crossbeam = "0.7.2"
notify = "5.0.0-pre.1" notify = "5.0.0-pre.1"
[dev-dependencies]
criterion = "0.3"
[[bench]]
name = "chonk_benchmark"
harness = false

View File

@ -0,0 +1,133 @@
#[macro_use]
extern crate criterion;
use criterion::black_box;
use criterion::Criterion;
use vek::*;
use veloren_common::{
terrain::{
block::{Block, BlockKind},
TerrainChunk, TerrainChunkMeta,
},
vol::*,
};
const MIN_Z: i32 = 140;
const MAX_Z: i32 = 220;
fn criterion_benchmark(c: &mut Criterion) {
// Setup: Create chunk and fill it (dense) for z in [140, 220).
let mut chunk = TerrainChunk::new(
MIN_Z,
Block::new(BlockKind::Dense, Default::default()),
Block::empty(),
TerrainChunkMeta::void(),
);
for pos in chunk.pos_iter(
Vec3::new(0, 0, MIN_Z),
Vec3::new(
TerrainChunk::RECT_SIZE.x as i32,
TerrainChunk::RECT_SIZE.y as i32,
MAX_Z,
),
) {
chunk
.set(pos, Block::new(BlockKind::Dense, Default::default()))
.unwrap();
}
c.bench_function("chunk: full read", |b| {
b.iter(|| {
for (_, vox) in chunk.vol_iter(
Vec3::new(0, 0, MIN_Z),
Vec3::new(
TerrainChunk::RECT_SIZE.x as i32,
TerrainChunk::RECT_SIZE.x as i32,
MAX_Z,
),
) {
black_box(vox);
}
})
});
c.bench_function("chunk: constrained read", |b| {
b.iter(|| {
for (_, vox) in
chunk.vol_iter(Vec3::new(9, 13, 2 + MIN_Z), Vec3::new(26, 30, -13 + MAX_Z))
{
black_box(vox);
}
})
});
c.bench_function("chunk: local read", |b| {
b.iter(|| {
for (_, vox) in
chunk.vol_iter(Vec3::new(9, 13, 2 + MIN_Z), Vec3::new(14, 18, 7 + MIN_Z))
{
black_box(vox);
}
})
});
c.bench_function("chunk: X-direction read", |b| {
b.iter(|| {
for (_, vox) in
chunk.vol_iter(Vec3::new(9, 13, 2 + MIN_Z), Vec3::new(26, 14, 3 + MIN_Z))
{
black_box(vox);
}
})
});
c.bench_function("chunk: Y-direction read", |b| {
b.iter(|| {
for (_, vox) in
chunk.vol_iter(Vec3::new(9, 13, 2 + MIN_Z), Vec3::new(10, 30, 3 + MIN_Z))
{
black_box(vox);
}
})
});
c.bench_function("chunk: Z-direction read", |b| {
b.iter(|| {
for (_, vox) in
chunk.vol_iter(Vec3::new(9, 13, 2 + MIN_Z), Vec3::new(10, 14, 19 + MIN_Z))
{
black_box(vox);
}
})
});
c.bench_function("chunk: long Z-direction read", |b| {
b.iter(|| {
for (_, vox) in
chunk.vol_iter(Vec3::new(9, 13, 2 + MIN_Z), Vec3::new(10, 14, -13 + MAX_Z))
{
black_box(vox);
}
})
});
c.bench_function("chunk: full write (dense)", |b| {
b.iter(|| {
for pos in chunk.pos_iter(
Vec3::new(0, 0, MIN_Z),
Vec3::new(
TerrainChunk::RECT_SIZE.x as i32,
TerrainChunk::RECT_SIZE.x as i32,
MAX_Z,
),
) {
let _ = chunk.set(pos, Block::new(BlockKind::Dense, Default::default()));
}
})
});
black_box(chunk);
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

View File

@ -5,7 +5,7 @@ pub use mat_cell::Material;
use self::cell::Cell; use self::cell::Cell;
use self::mat_cell::MatCell; use self::mat_cell::MatCell;
use crate::{ use crate::{
vol::{ReadVol, SizedVol, Vox, WriteVol}, vol::{IntoFullPosIterator, IntoFullVolIterator, ReadVol, SizedVol, Vox, WriteVol},
volumes::dyna::Dyna, volumes::dyna::Dyna,
}; };
use dot_vox::DotVoxData; use dot_vox::DotVoxData;
@ -52,7 +52,7 @@ impl From<&DotVoxData> for Segment {
impl Segment { impl Segment {
/// Transform cells /// Transform cells
pub fn map(mut self, transform: impl Fn(Cell) -> Option<Cell>) -> Self { pub fn map(mut self, transform: impl Fn(Cell) -> Option<Cell>) -> Self {
for pos in self.iter_positions() { for pos in self.full_pos_iter() {
if let Some(new) = transform(*self.get(pos).unwrap()) { if let Some(new) = transform(*self.get(pos).unwrap()) {
self.set(pos, new).unwrap(); self.set(pos, new).unwrap();
} }
@ -91,9 +91,9 @@ impl<V: Vox + Copy> DynaUnionizer<V> {
// Determine size of the new Dyna // Determine size of the new Dyna
let mut min_point = self.0[0].1; let mut min_point = self.0[0].1;
let mut max_point = self.0[0].1 + self.0[0].0.get_size().map(|e| e as i32); let mut max_point = self.0[0].1 + self.0[0].0.size().map(|e| e as i32);
for (dyna, offset) in self.0.iter().skip(1) { for (dyna, offset) in self.0.iter().skip(1) {
let size = dyna.get_size().map(|e| e as i32); let size = dyna.size().map(|e| e as i32);
min_point = min_point.map2(*offset, std::cmp::min); min_point = min_point.map2(*offset, std::cmp::min);
max_point = max_point.map2(offset + size, std::cmp::max); max_point = max_point.map2(offset + size, std::cmp::max);
} }
@ -103,8 +103,7 @@ impl<V: Vox + Copy> DynaUnionizer<V> {
// Copy segments into combined // Copy segments into combined
let origin = min_point.map(|e| e * -1); let origin = min_point.map(|e| e * -1);
for (dyna, offset) in self.0 { for (dyna, offset) in self.0 {
for pos in dyna.iter_positions() { for (pos, vox) in dyna.full_vol_iter() {
let vox = dyna.get(pos).unwrap();
if !vox.is_empty() { if !vox.is_empty() {
combined.set(origin + offset + pos, *vox).unwrap(); combined.set(origin + offset + pos, *vox).unwrap();
} }
@ -119,9 +118,9 @@ pub type MatSegment = Dyna<MatCell, ()>;
impl MatSegment { impl MatSegment {
pub fn to_segment(&self, map: impl Fn(Material) -> Rgb<u8>) -> Segment { pub fn to_segment(&self, map: impl Fn(Material) -> Rgb<u8>) -> Segment {
let mut vol = Dyna::filled(self.get_size(), Cell::empty(), ()); let mut vol = Dyna::filled(self.size(), Cell::empty(), ());
for pos in self.iter_positions() { for (pos, vox) in self.full_vol_iter() {
let rgb = match self.get(pos).unwrap() { let rgb = match vox {
MatCell::None => continue, MatCell::None => continue,
MatCell::Mat(mat) => map(*mat), MatCell::Mat(mat) => map(*mat),
MatCell::Normal(rgb) => *rgb, MatCell::Normal(rgb) => *rgb,

View File

@ -53,7 +53,7 @@ impl<'a, V: ReadVol, F: RayUntil<V::Vox>, G: RayForEach> Ray<'a, V, F, G> {
self self
} }
pub fn cast(mut self) -> (f32, Result<Option<&'a V::Vox>, V::Err>) { pub fn cast(mut self) -> (f32, Result<Option<&'a V::Vox>, V::Error>) {
// TODO: Fully test this! // TODO: Fully test this!
const PLANCK: f32 = 0.001; const PLANCK: f32 = 0.001;

View File

@ -6,7 +6,7 @@ use crate::{
event::{EventBus, LocalEvent, ServerEvent}, event::{EventBus, LocalEvent, ServerEvent},
msg::{EcsCompPacket, EcsResPacket}, msg::{EcsCompPacket, EcsResPacket},
sys, sys,
terrain::{Block, TerrainChunk, TerrainMap}, terrain::{Block, TerrainChunk, TerrainGrid},
vol::WriteVol, vol::WriteVol,
}; };
use hashbrown::{HashMap, HashSet}; use hashbrown::{HashMap, HashSet};
@ -150,7 +150,7 @@ impl State {
// Register unsynced resources used by the ECS. // Register unsynced resources used by the ECS.
ecs.add_resource(Time(0.0)); ecs.add_resource(Time(0.0));
ecs.add_resource(DeltaTime(0.0)); ecs.add_resource(DeltaTime(0.0));
ecs.add_resource(TerrainMap::new().unwrap()); ecs.add_resource(TerrainGrid::new().unwrap());
ecs.add_resource(BlockChange::default()); ecs.add_resource(BlockChange::default());
ecs.add_resource(TerrainChanges::default()); ecs.add_resource(TerrainChanges::default());
ecs.add_resource(EventBus::<ServerEvent>::default()); ecs.add_resource(EventBus::<ServerEvent>::default());
@ -217,12 +217,12 @@ impl State {
} }
/// Get a reference to this state's terrain. /// Get a reference to this state's terrain.
pub fn terrain(&self) -> Fetch<TerrainMap> { pub fn terrain(&self) -> Fetch<TerrainGrid> {
self.ecs.read_resource() self.ecs.read_resource()
} }
/// Get a writable reference to this state's terrain. /// Get a writable reference to this state's terrain.
pub fn terrain_mut(&self) -> FetchMut<TerrainMap> { pub fn terrain_mut(&self) -> FetchMut<TerrainGrid> {
self.ecs.write_resource() self.ecs.write_resource()
} }
@ -248,7 +248,7 @@ impl State {
pub fn insert_chunk(&mut self, key: Vec2<i32>, chunk: TerrainChunk) { pub fn insert_chunk(&mut self, key: Vec2<i32>, chunk: TerrainChunk) {
if self if self
.ecs .ecs
.write_resource::<TerrainMap>() .write_resource::<TerrainGrid>()
.insert(key, Arc::new(chunk)) .insert(key, Arc::new(chunk))
.is_some() .is_some()
{ {
@ -268,7 +268,7 @@ impl State {
pub fn remove_chunk(&mut self, key: Vec2<i32>) { pub fn remove_chunk(&mut self, key: Vec2<i32>) {
if self if self
.ecs .ecs
.write_resource::<TerrainMap>() .write_resource::<TerrainGrid>()
.remove(key) .remove(key)
.is_some() .is_some()
{ {
@ -299,7 +299,7 @@ impl State {
self.ecs.maintain(); self.ecs.maintain();
// Apply terrain changes // Apply terrain changes
let mut terrain = self.ecs.write_resource::<TerrainMap>(); let mut terrain = self.ecs.write_resource::<TerrainGrid>();
self.ecs self.ecs
.read_resource::<BlockChange>() .read_resource::<BlockChange>()
.blocks .blocks

View File

@ -4,7 +4,7 @@ use crate::{
Stats, Vel, Stats, Vel,
}, },
state::DeltaTime, state::DeltaTime,
terrain::TerrainMap, terrain::TerrainGrid,
}; };
use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteStorage}; use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
use std::time::Duration; use std::time::Duration;
@ -30,7 +30,7 @@ pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> System<'a> for Sys {
type SystemData = ( type SystemData = (
ReadExpect<'a, TerrainMap>, ReadExpect<'a, TerrainGrid>,
Read<'a, DeltaTime>, Read<'a, DeltaTime>,
ReadStorage<'a, Stats>, ReadStorage<'a, Stats>,
ReadStorage<'a, Controller>, ReadStorage<'a, Controller>,

View File

@ -3,7 +3,7 @@ use {
comp::{Body, Ori, PhysicsState, Pos, Scale, Vel}, comp::{Body, Ori, PhysicsState, Pos, Scale, Vel},
event::{EventBus, LocalEvent}, event::{EventBus, LocalEvent},
state::DeltaTime, state::DeltaTime,
terrain::TerrainMap, terrain::TerrainGrid,
vol::ReadVol, vol::ReadVol,
}, },
specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage}, specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage},
@ -32,7 +32,7 @@ pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> System<'a> for Sys {
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
ReadExpect<'a, TerrainMap>, ReadExpect<'a, TerrainGrid>,
Read<'a, DeltaTime>, Read<'a, DeltaTime>,
Read<'a, EventBus<LocalEvent>>, Read<'a, EventBus<LocalEvent>>,
ReadStorage<'a, Scale>, ReadStorage<'a, Scale>,

View File

@ -1,42 +1,60 @@
use super::{block::Block, TerrainChunkMeta, TerrainChunkSize};
use crate::{ use crate::{
vol::{BaseVol, ReadVol, VolSize, WriteVol}, vol::{
volumes::chunk::{Chunk, ChunkErr}, BaseVol, IntoPosIterator, IntoVolIterator, ReadVol, RectRasterableVol, RectVolSize,
VolSize, Vox, WriteVol,
},
volumes::chunk::{Chunk, ChunkError, ChunkPosIter, ChunkVolIter},
}; };
use hashbrown::HashMap;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::ops::Add; use std::marker::PhantomData;
use vek::*; use vek::*;
#[derive(Debug)] #[derive(Debug)]
pub enum ChonkError { pub enum ChonkError {
ChunkError(ChunkErr), SubChunkError(ChunkError),
OutOfBounds, OutOfBounds,
} }
const SUB_CHUNK_HEIGHT: u32 = 16;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Chonk { pub struct SubChunkSize<ChonkSize: RectVolSize> {
z_offset: i32, phantom: PhantomData<ChonkSize>,
sub_chunks: Vec<SubChunk>,
below: Block,
above: Block,
meta: TerrainChunkMeta,
} }
impl Chonk { // TODO (haslersn): Assert ChonkSize::RECT_SIZE.x == ChonkSize::RECT_SIZE.y
pub fn new(z_offset: i32, below: Block, above: Block, meta: TerrainChunkMeta) -> Self {
impl<ChonkSize: RectVolSize> VolSize for SubChunkSize<ChonkSize> {
const SIZE: Vec3<u32> = Vec3 {
x: ChonkSize::RECT_SIZE.x,
y: ChonkSize::RECT_SIZE.x,
z: ChonkSize::RECT_SIZE.x / 2,
};
}
type SubChunk<V, S, M> = Chunk<V, SubChunkSize<S>, M>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Chonk<V: Vox, S: RectVolSize, M: Clone> {
z_offset: i32,
sub_chunks: Vec<SubChunk<V, S, M>>,
below: V,
above: V,
meta: M,
phantom: PhantomData<S>,
}
impl<V: Vox, S: RectVolSize, M: Clone> Chonk<V, S, M> {
pub fn new(z_offset: i32, below: V, above: V, meta: M) -> Self {
Self { Self {
z_offset, z_offset,
sub_chunks: Vec::new(), sub_chunks: Vec::new(),
below, below,
above, above,
meta, meta,
phantom: PhantomData,
} }
} }
pub fn meta(&self) -> &TerrainChunkMeta { pub fn meta(&self) -> &M {
&self.meta &self.meta
} }
@ -45,203 +63,223 @@ impl Chonk {
} }
pub fn get_max_z(&self) -> i32 { pub fn get_max_z(&self) -> i32 {
self.z_offset + (self.sub_chunks.len() as u32 * SUB_CHUNK_HEIGHT) as i32 self.z_offset + (self.sub_chunks.len() as u32 * SubChunkSize::<S>::SIZE.z) as i32
} }
pub fn get_metrics(&self) -> ChonkMetrics { // Returns the index (in self.sub_chunks) of the SubChunk that contains
ChonkMetrics { // layer z; note that this index changes when more SubChunks are prepended
chonks: 1, fn sub_chunk_idx(&self, z: i32) -> i32 {
homogeneous: self let diff = z - self.z_offset;
.sub_chunks diff >> (SubChunkSize::<S>::SIZE.z - 1).count_ones()
.iter() }
.filter(|s| match s {
SubChunk::Homogeneous(_) => true, // Converts a z coordinate into a local z coordinate within a sub chunk
_ => false, fn sub_chunk_z(&self, z: i32) -> i32 {
}) let diff = z - self.z_offset;
.count(), diff & (SubChunkSize::<S>::SIZE.z - 1) as i32
hash: self }
.sub_chunks
.iter() // Returns the z offset of the sub_chunk that contains layer z
.filter(|s| match s { fn sub_chunk_min_z(&self, z: i32) -> i32 {
SubChunk::Hash(_, _) => true, z - self.sub_chunk_z(z)
_ => false,
})
.count(),
heterogeneous: self
.sub_chunks
.iter()
.filter(|s| match s {
SubChunk::Heterogeneous(_) => true,
_ => false,
})
.count(),
} }
} }
fn sub_chunk_idx(&self, z: i32) -> usize { impl<V: Vox, S: RectVolSize, M: Clone> BaseVol for Chonk<V, S, M> {
((z - self.z_offset) as u32 / SUB_CHUNK_HEIGHT as u32) as usize type Vox = V;
} type Error = ChonkError;
} }
impl BaseVol for Chonk { impl<V: Vox, S: RectVolSize, M: Clone> RectRasterableVol for Chonk<V, S, M> {
type Vox = Block; const RECT_SIZE: Vec2<u32> = S::RECT_SIZE;
type Err = ChonkError;
} }
impl ReadVol for Chonk { impl<V: Vox, S: RectVolSize, M: Clone> ReadVol for Chonk<V, S, M> {
#[inline(always)] #[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&Block, ChonkError> { fn get(&self, pos: Vec3<i32>) -> Result<&V, Self::Error> {
if pos.z < self.z_offset { if pos.z < self.get_min_z() {
// Below the terrain // Below the terrain
Ok(&self.below) Ok(&self.below)
} else if pos.z >= self.z_offset + SUB_CHUNK_HEIGHT as i32 * self.sub_chunks.len() as i32 { } else if pos.z >= self.get_max_z() {
// Above the terrain // Above the terrain
Ok(&self.above) Ok(&self.above)
} else { } else {
// Within the terrain // Within the terrain
let sub_chunk_idx = self.sub_chunk_idx(pos.z); let sub_chunk_idx = self.sub_chunk_idx(pos.z);
match &self.sub_chunks[sub_chunk_idx] {
// Can't fail
SubChunk::Homogeneous(block) => Ok(block),
SubChunk::Hash(cblock, map) => {
let rpos = pos let rpos = pos
- Vec3::unit_z() - Vec3::unit_z()
* (self.z_offset + sub_chunk_idx as i32 * SUB_CHUNK_HEIGHT as i32); * (self.z_offset + sub_chunk_idx * SubChunkSize::<S>::SIZE.z as i32);
self.sub_chunks[sub_chunk_idx as usize]
Ok(map.get(&rpos.map(|e| e as u8)).unwrap_or(cblock)) .get(rpos)
} .map_err(Self::Error::SubChunkError)
SubChunk::Heterogeneous(chunk) => {
let rpos = pos
- Vec3::unit_z()
* (self.z_offset + sub_chunk_idx as i32 * SUB_CHUNK_HEIGHT as i32);
chunk.get(rpos).map_err(ChonkError::ChunkError)
}
}
} }
} }
} }
impl WriteVol for Chonk { impl<V: Vox, S: RectVolSize, M: Clone> WriteVol for Chonk<V, S, M> {
#[inline(always)] #[inline(always)]
fn set(&mut self, pos: Vec3<i32>, block: Block) -> Result<(), ChonkError> { fn set(&mut self, pos: Vec3<i32>, block: Self::Vox) -> Result<(), Self::Error> {
while pos.z < self.z_offset { let mut sub_chunk_idx = self.sub_chunk_idx(pos.z);
self.sub_chunks.insert(0, SubChunk::Homogeneous(self.below));
self.z_offset -= SUB_CHUNK_HEIGHT as i32; if pos.z < self.get_min_z() {
// Prepend exactly sufficiently many SubChunks via Vec::splice
let c = Chunk::<V, SubChunkSize<S>, M>::filled(self.below.clone(), self.meta.clone());
let n = (-sub_chunk_idx) as usize;
self.sub_chunks.splice(0..0, std::iter::repeat(c).take(n));
self.z_offset += sub_chunk_idx * SubChunkSize::<S>::SIZE.z as i32;
sub_chunk_idx = 0;
} else if pos.z >= self.get_max_z() {
// Append exactly sufficiently many SubChunks via Vec::extend
let c = Chunk::<V, SubChunkSize<S>, M>::filled(self.above.clone(), self.meta.clone());
let n = 1 + sub_chunk_idx as usize - self.sub_chunks.len();
self.sub_chunks.extend(std::iter::repeat(c).take(n));
} }
let sub_chunk_idx = self.sub_chunk_idx(pos.z); let rpos = pos
- Vec3::unit_z() * (self.z_offset + sub_chunk_idx * SubChunkSize::<S>::SIZE.z as i32);
while self.sub_chunks.get(sub_chunk_idx).is_none() { self.sub_chunks[sub_chunk_idx as usize] // TODO (haslersn): self.sub_chunks.get(...).and_then(...)
self.sub_chunks.push(SubChunk::Homogeneous(self.above)); .set(rpos, block)
.map_err(Self::Error::SubChunkError)
}
} }
let rpos = struct ChonkIterHelper<V: Vox, S: RectVolSize, M: Clone> {
pos - Vec3::unit_z() * (self.z_offset + sub_chunk_idx as i32 * SUB_CHUNK_HEIGHT as i32); sub_chunk_min_z: i32,
lower_bound: Vec3<i32>,
match &mut self.sub_chunks[sub_chunk_idx] { upper_bound: Vec3<i32>,
// Can't fail phantom: PhantomData<Chonk<V, S, M>>,
SubChunk::Homogeneous(cblock) if block == *cblock => Ok(()),
SubChunk::Homogeneous(cblock) => {
let mut map = HashMap::default();
map.insert(rpos.map(|e| e as u8), block);
self.sub_chunks[sub_chunk_idx] = SubChunk::Hash(*cblock, map);
Ok(())
}
SubChunk::Hash(cblock, map) if block == *cblock => {
map.remove(&rpos.map(|e| e as u8));
Ok(())
}
SubChunk::Hash(_cblock, map) if map.len() <= 4096 => {
map.insert(rpos.map(|e| e as u8), block);
Ok(())
}
SubChunk::Hash(cblock, map) => {
let mut new_chunk = Chunk::filled(*cblock, ());
for (map_pos, map_block) in map {
new_chunk
.set(map_pos.map(|e| i32::from(e)), *map_block)
.unwrap(); // Can't fail (I hope!)
} }
new_chunk.set(rpos, block).unwrap(); // Can't fail (I hope) impl<V: Vox, S: RectVolSize, M: Clone> Iterator for ChonkIterHelper<V, S, M> {
type Item = (i32, Vec3<i32>, Vec3<i32>);
self.sub_chunks[sub_chunk_idx] = SubChunk::Heterogeneous(new_chunk); #[inline(always)]
Ok(()) fn next(&mut self) -> Option<Self::Item> {
if self.lower_bound.z >= self.upper_bound.z {
return None;
}
let mut lb = self.lower_bound;
let mut ub = self.upper_bound;
let current_min_z = self.sub_chunk_min_z;
lb.z -= current_min_z;
ub.z -= current_min_z;
ub.z = std::cmp::min(ub.z, SubChunkSize::<S>::SIZE.z as i32);
self.sub_chunk_min_z += SubChunkSize::<S>::SIZE.z as i32;
self.lower_bound.z = self.sub_chunk_min_z;
Some((current_min_z, lb, ub))
}
} }
/* pub struct ChonkPosIter<V: Vox, S: RectVolSize, M: Clone> {
SubChunk::Homogeneous(cblock) => { outer: ChonkIterHelper<V, S, M>,
let mut new_chunk = Chunk::filled(*cblock, ()); opt_inner: Option<(i32, ChunkPosIter<V, SubChunkSize<S>, M>)>,
}
new_chunk.set(rpos, block).unwrap(); // Can't fail (I hope!)
impl<V: Vox, S: RectVolSize, M: Clone> Iterator for ChonkPosIter<V, S, M> {
self.sub_chunks[sub_chunk_idx] = SubChunk::Heterogeneous(new_chunk); type Item = Vec3<i32>;
Ok(())
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some((sub_chunk_min_z, ref mut inner)) = self.opt_inner {
if let Some(mut pos) = inner.next() {
pos.z += sub_chunk_min_z;
return Some(pos);
}
}
match self.outer.next() {
None => return None,
Some((sub_chunk_min_z, lb, ub)) => {
self.opt_inner = Some((sub_chunk_min_z, SubChunk::<V, S, M>::pos_iter(lb, ub)))
}
} }
*/
SubChunk::Heterogeneous(chunk) => {
chunk.set(rpos, block).map_err(ChonkError::ChunkError)
} //_ => unimplemented!(),
} }
} }
} }
#[derive(Debug, Clone, Serialize, Deserialize)] enum InnerChonkVolIter<'a, V: Vox, S: RectVolSize, M: Clone> {
pub struct SubChunkSize; Vol(ChunkVolIter<'a, V, SubChunkSize<S>, M>),
Pos(ChunkPosIter<V, SubChunkSize<S>, M>),
}
impl VolSize for SubChunkSize { pub struct ChonkVolIter<'a, V: Vox, S: RectVolSize, M: Clone> {
const SIZE: Vec3<u32> = Vec3 { chonk: &'a Chonk<V, S, M>,
x: TerrainChunkSize::SIZE.x, outer: ChonkIterHelper<V, S, M>,
y: TerrainChunkSize::SIZE.y, opt_inner: Option<(i32, InnerChonkVolIter<'a, V, S, M>)>,
z: SUB_CHUNK_HEIGHT, }
impl<'a, V: Vox, S: RectVolSize, M: Clone> Iterator for ChonkVolIter<'a, V, S, M> {
type Item = (Vec3<i32>, &'a V);
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some((sub_chunk_min_z, ref mut inner)) = self.opt_inner {
let got = match inner {
InnerChonkVolIter::<'a, V, S, M>::Vol(iter) => iter.next(),
InnerChonkVolIter::<'a, V, S, M>::Pos(iter) => iter.next().map(|pos| {
if sub_chunk_min_z < self.chonk.get_min_z() {
(pos, &self.chonk.below)
} else {
(pos, &self.chonk.above)
}
}),
}; };
if let Some((mut pos, vox)) = got {
pos.z += sub_chunk_min_z;
return Some((pos, vox));
}
}
match self.outer.next() {
None => return None,
Some((sub_chunk_min_z, lb, ub)) => {
let inner = if sub_chunk_min_z < self.chonk.get_min_z()
|| sub_chunk_min_z >= self.chonk.get_max_z()
{
InnerChonkVolIter::<'a, V, S, M>::Pos(SubChunk::<V, S, M>::pos_iter(lb, ub))
} else {
InnerChonkVolIter::<'a, V, S, M>::Vol(
self.chonk.sub_chunks
[self.chonk.sub_chunk_idx(sub_chunk_min_z) as usize]
.vol_iter(lb, ub),
)
};
self.opt_inner = Some((sub_chunk_min_z, inner));
}
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SubChunk {
Homogeneous(Block),
Hash(Block, HashMap<Vec3<u8>, Block>),
Heterogeneous(Chunk<Block, SubChunkSize, ()>),
} }
impl SubChunk {
pub fn filled(block: Block) -> Self {
SubChunk::Homogeneous(block)
} }
} }
#[derive(Debug)] impl<'a, V: Vox, S: RectVolSize, M: Clone> IntoPosIterator for &'a Chonk<V, S, M> {
pub struct ChonkMetrics { type IntoIter = ChonkPosIter<V, S, M>;
chonks: usize,
homogeneous: usize,
hash: usize,
heterogeneous: usize,
}
impl Default for ChonkMetrics { fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter {
fn default() -> Self { Self::IntoIter {
ChonkMetrics { outer: ChonkIterHelper::<V, S, M> {
chonks: 0, sub_chunk_min_z: self.sub_chunk_min_z(lower_bound.z),
homogeneous: 0, lower_bound,
hash: 0, upper_bound,
heterogeneous: 0, phantom: PhantomData,
},
opt_inner: None,
} }
} }
} }
impl Add for ChonkMetrics { impl<'a, V: Vox, S: RectVolSize, M: Clone> IntoVolIterator<'a> for &'a Chonk<V, S, M> {
type Output = Self; type IntoIter = ChonkVolIter<'a, V, S, M>;
fn add(self, other: Self::Output) -> Self { fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter {
Self::Output { Self::IntoIter {
chonks: self.chonks + other.chonks, chonk: self,
homogeneous: self.homogeneous + other.homogeneous, outer: ChonkIterHelper::<V, S, M> {
hash: self.hash + other.hash, sub_chunk_min_z: self.sub_chunk_min_z(lower_bound.z),
heterogeneous: self.heterogeneous + other.heterogeneous, lower_bound,
upper_bound,
phantom: PhantomData,
},
opt_inner: None,
} }
} }
} }

View File

@ -10,7 +10,7 @@ pub use self::{
structure::Structure, structure::Structure,
}; };
use crate::{vol::VolSize, volumes::vol_map_2d::VolMap2d}; use crate::{vol::RectVolSize, volumes::vol_grid_2d::VolGrid2d};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use vek::*; use vek::*;
@ -19,12 +19,8 @@ use vek::*;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TerrainChunkSize; pub struct TerrainChunkSize;
impl VolSize for TerrainChunkSize { impl RectVolSize for TerrainChunkSize {
const SIZE: Vec3<u32> = Vec3 { const RECT_SIZE: Vec2<u32> = Vec2 { x: 32, y: 32 };
x: 32,
y: 32,
z: 32,
};
} }
// TerrainChunkMeta // TerrainChunkMeta
@ -61,5 +57,5 @@ impl TerrainChunkMeta {
// Terrain type aliases // Terrain type aliases
pub type TerrainChunk = chonk::Chonk; //Chunk<Block, TerrainChunkSize, TerrainChunkMeta>; pub type TerrainChunk = chonk::Chonk<Block, TerrainChunkSize, TerrainChunkMeta>;
pub type TerrainMap = VolMap2d<TerrainChunk, TerrainChunkSize>; pub type TerrainGrid = VolGrid2d<TerrainChunk>;

View File

@ -2,14 +2,14 @@ use super::BlockKind;
use crate::{ use crate::{
assets::{self, Asset}, assets::{self, Asset},
vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol}, vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol},
volumes::dyna::{Dyna, DynaErr}, volumes::dyna::{Dyna, DynaError},
}; };
use dot_vox::DotVoxData; use dot_vox::DotVoxData;
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
use vek::*; use vek::*;
#[derive(Copy, Clone)] #[derive(Copy, Clone, PartialEq)]
pub enum StructureBlock { pub enum StructureBlock {
None, None,
TemperateLeaves, TemperateLeaves,
@ -63,7 +63,7 @@ impl Structure {
pub fn get_bounds(&self) -> Aabb<i32> { pub fn get_bounds(&self) -> Aabb<i32> {
Aabb { Aabb {
min: -self.center, min: -self.center,
max: self.vol.get_size().map(|e| e as i32) - self.center, max: self.vol.size().map(|e| e as i32) - self.center,
} }
} }
@ -74,7 +74,7 @@ impl Structure {
impl BaseVol for Structure { impl BaseVol for Structure {
type Vox = StructureBlock; type Vox = StructureBlock;
type Err = StructureError; type Error = StructureError;
} }
impl ReadVol for Structure { impl ReadVol for Structure {
@ -82,7 +82,7 @@ impl ReadVol for Structure {
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, StructureError> { fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, StructureError> {
match self.vol.get(pos + self.center) { match self.vol.get(pos + self.center) {
Ok(block) => Ok(block), Ok(block) => Ok(block),
Err(DynaErr::OutOfBounds) => Ok(&self.empty), Err(DynaError::OutOfBounds) => Ok(&self.empty),
} }
} }
} }

View File

@ -2,8 +2,18 @@ use crate::ray::Ray;
use std::fmt::Debug; use std::fmt::Debug;
use vek::*; use vek::*;
/// Used to specify a volume's compile-time size. This exists as a substitute until const generics
/// are implemented.
pub trait VolSize: Clone {
const SIZE: Vec3<u32>;
}
pub trait RectVolSize: Clone {
const RECT_SIZE: Vec2<u32>;
}
/// A voxel. /// A voxel.
pub trait Vox: Sized { pub trait Vox: Sized + Clone + PartialEq {
fn empty() -> Self; fn empty() -> Self;
fn is_empty(&self) -> bool; fn is_empty(&self) -> bool;
@ -19,64 +29,88 @@ pub trait Vox: Sized {
/// A volume that contains voxel data. /// A volume that contains voxel data.
pub trait BaseVol { pub trait BaseVol {
type Vox: Vox; type Vox: Vox;
type Err: Debug; type Error: Debug;
}
/// Implementing `BaseVol` for any `&'a BaseVol` makes it possible to implement
/// `IntoVolIterator` for references.
impl<'a, T: BaseVol> BaseVol for &'a T {
type Vox = T::Vox;
type Error = T::Error;
} }
// Utility types // Utility types
pub struct VoxPosIter { /// A volume that is a cuboid.
pos: Vec3<u32>,
sz: Vec3<u32>,
}
impl Iterator for VoxPosIter {
type Item = Vec3<i32>;
fn next(&mut self) -> Option<Self::Item> {
let mut old_pos = self.pos;
if old_pos.z == self.sz.z {
old_pos.z = 0;
old_pos.y += 1;
if old_pos.y == self.sz.y {
old_pos.y = 0;
old_pos.x += 1;
if old_pos.x == self.sz.x {
return None;
}
}
}
self.pos = old_pos + Vec3::unit_z();
Some(old_pos.map(|e| e as i32))
}
}
/// A volume that has a finite size.
pub trait SizedVol: BaseVol { pub trait SizedVol: BaseVol {
/// Get the size of the volume. /// Returns the (inclusive) lower bound of the volume.
fn get_size(&self) -> Vec3<u32>; fn lower_bound(&self) -> Vec3<i32>;
/// Iterate through all potential voxel positions in this volume. /// Returns the (exclusive) upper bound of the volume.
fn iter_positions(&self) -> VoxPosIter { fn upper_bound(&self) -> Vec3<i32>;
VoxPosIter {
pos: Vec3::zero(), /// Returns the size of the volume.
sz: self.get_size(), fn size(&self) -> Vec3<u32> {
(self.upper_bound() - self.lower_bound()).map(|e| e as u32)
} }
} }
/// A volume that is compile-time sized and has its lower bound at `(0, 0, 0)`.
/// The name `RasterableVol` was chosen because such a volume can be used with
/// `VolGrid3d`.
pub trait RasterableVol: BaseVol {
const SIZE: Vec3<u32>;
}
impl<V: RasterableVol> SizedVol for V {
fn lower_bound(&self) -> Vec3<i32> {
Vec3::zero()
}
fn upper_bound(&self) -> Vec3<i32> {
V::SIZE.map(|e| e as i32)
}
}
/// A volume whose cross section with the XY-plane is a rectangle.
pub trait RectSizedVol: BaseVol {
fn lower_bound_xy(&self) -> Vec2<i32>;
fn upper_bound_xy(&self) -> Vec2<i32>;
fn size_xy(&self) -> Vec2<u32> {
(self.upper_bound_xy() - self.lower_bound_xy()).map(|e| e as u32)
}
}
/// A volume that is compile-time sized in x and y direction and has its lower
/// bound at `(0, 0, z)`. In z direction there's no restriction on the lower
/// or upper bound. The name `RectRasterableVol` was chosen because such a
/// volume can be used with `VolGrid2d`.
pub trait RectRasterableVol: BaseVol {
const RECT_SIZE: Vec2<u32>;
}
impl<V: RectRasterableVol> RectSizedVol for V {
fn lower_bound_xy(&self) -> Vec2<i32> {
Vec2::zero()
}
fn upper_bound_xy(&self) -> Vec2<i32> {
V::RECT_SIZE.map(|e| e as i32)
}
} }
/// A volume that provides read access to its voxel data. /// A volume that provides read access to its voxel data.
pub trait ReadVol: BaseVol { pub trait ReadVol: BaseVol {
/// Get a reference to the voxel at the provided position in the volume. /// Get a reference to the voxel at the provided position in the volume.
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Err>; fn get<'a>(&'a self, pos: Vec3<i32>) -> Result<&'a Self::Vox, Self::Error>;
fn ray( fn ray<'a>(
&self, &'a self,
from: Vec3<f32>, from: Vec3<f32>,
to: Vec3<f32>, to: Vec3<f32>,
) -> Ray<Self, fn(&Self::Vox) -> bool, fn(Vec3<i32>)> ) -> Ray<'a, Self, fn(&Self::Vox) -> bool, fn(Vec3<i32>)>
where where
Self: Sized, Self: Sized,
{ {
@ -85,6 +119,8 @@ pub trait ReadVol: BaseVol {
} }
/// A volume that provides the ability to sample (i.e., clone a section of) its voxel data. /// A volume that provides the ability to sample (i.e., clone a section of) its voxel data.
///
/// TODO (haslersn): Do we still need this now that we have `IntoVolIterator`?
pub trait SampleVol<I>: BaseVol { pub trait SampleVol<I>: BaseVol {
type Sample: BaseVol + ReadVol; type Sample: BaseVol + ReadVol;
/// Take a sample of the volume by cloning voxels within the provided range. /// Take a sample of the volume by cloning voxels within the provided range.
@ -94,19 +130,142 @@ pub trait SampleVol<I>: BaseVol {
/// ///
/// Note that the resultant volume has a coordinate space relative to the sample, not the /// Note that the resultant volume has a coordinate space relative to the sample, not the
/// original volume. /// original volume.
fn sample(&self, range: I) -> Result<Self::Sample, Self::Err>; fn sample(&self, range: I) -> Result<Self::Sample, Self::Error>;
} }
/// A volume that provides write access to its voxel data. /// A volume that provides write access to its voxel data.
pub trait WriteVol: BaseVol { pub trait WriteVol: BaseVol {
/// Set the voxel at the provided position in the volume to the provided value. /// Set the voxel at the provided position in the volume to the provided value.
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), Self::Err>; fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), Self::Error>;
} }
// Utility traits /// A volume (usually rather a reference to a volume) that is convertible into
/// an iterator to a cuboid subsection of the volume.
pub trait IntoVolIterator<'a>: BaseVol
where
Self::Vox: 'a,
{
type IntoIter: Iterator<Item = (Vec3<i32>, &'a Self::Vox)>;
/// Used to specify a volume's compile-time size. This exists as a substitute until const generics fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter;
/// are implemented. }
pub trait VolSize {
const SIZE: Vec3<u32>; pub trait IntoPosIterator: BaseVol {
type IntoIter: Iterator<Item = Vec3<i32>>;
fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter;
}
// Helpers
/// A volume (usually rather a reference to a volume) that is convertible into
/// an iterator.
pub trait IntoFullVolIterator<'a>: BaseVol
where
Self::Vox: 'a,
{
type IntoIter: Iterator<Item = (Vec3<i32>, &'a Self::Vox)>;
fn full_vol_iter(self) -> Self::IntoIter;
}
/// For any `&'a SizedVol: IntoVolIterator` we implement `IntoFullVolIterator`.
/// Unfortunately we can't just implement `IntoIterator` in this generic way
/// because it's defined in another crate. That's actually the only reason why
/// the trait `IntoFullVolIterator` exists.
impl<'a, T: 'a + SizedVol> IntoFullVolIterator<'a> for &'a T
where
Self: IntoVolIterator<'a>,
{
type IntoIter = <Self as IntoVolIterator<'a>>::IntoIter;
fn full_vol_iter(self) -> Self::IntoIter {
self.vol_iter(self.lower_bound(), self.upper_bound())
}
}
pub trait IntoFullPosIterator: BaseVol {
type IntoIter: Iterator<Item = Vec3<i32>>;
fn full_pos_iter(self) -> Self::IntoIter;
}
impl<'a, T: 'a + SizedVol> IntoFullPosIterator for &'a T
where
Self: IntoPosIterator,
{
type IntoIter = <Self as IntoPosIterator>::IntoIter;
fn full_pos_iter(self) -> Self::IntoIter {
self.pos_iter(self.lower_bound(), self.upper_bound())
}
}
// Defaults
/// Convenience iterator type that can be used to quickly implement
/// `IntoPosIterator`.
pub struct DefaultPosIterator {
current: Vec3<i32>,
begin: Vec2<i32>,
end: Vec3<i32>,
}
impl DefaultPosIterator {
pub fn new(lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self {
Self {
current: lower_bound,
begin: From::from(lower_bound),
end: upper_bound,
}
}
}
impl Iterator for DefaultPosIterator {
type Item = Vec3<i32>;
fn next(&mut self) -> Option<Vec3<i32>> {
self.current.x += (self.current.x < self.end.x) as i32;
if self.current.x == self.end.x {
self.current.x = self.begin.x;
self.current.y += (self.current.y < self.end.y) as i32;
if self.current.y == self.end.y {
self.current.y = self.begin.y;
self.current.z += (self.current.z < self.end.z) as i32;
if self.current.z == self.end.z {
return None;
}
}
}
Some(self.current)
}
}
/// Convenience iterator type that can be used to quickly implement
/// `IntoVolIterator`.
pub struct DefaultVolIterator<'a, T: ReadVol> {
vol: &'a T,
pos_iter: DefaultPosIterator,
}
impl<'a, T: ReadVol> DefaultVolIterator<'a, T> {
pub fn new(vol: &'a T, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self {
Self {
vol,
pos_iter: DefaultPosIterator::new(lower_bound, upper_bound),
}
}
}
impl<'a, T: ReadVol> Iterator for DefaultVolIterator<'a, T> {
type Item = (Vec3<i32>, &'a T::Vox);
fn next(&mut self) -> Option<(Vec3<i32>, &'a T::Vox)> {
while let Some(pos) = self.pos_iter.next() {
if let Ok(vox) = self.vol.get(pos) {
return Some((pos, vox));
}
}
return None;
}
} }

View File

@ -1,83 +1,115 @@
use crate::vol::{BaseVol, ReadVol, SizedVol, VolSize, Vox, WriteVol}; use crate::vol::{
BaseVol, IntoPosIterator, IntoVolIterator, RasterableVol, ReadVol, VolSize, Vox, WriteVol,
};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::iter::Iterator;
use std::marker::PhantomData; use std::marker::PhantomData;
use vek::*; use vek::*;
#[derive(Debug)] #[derive(Debug)]
pub enum ChunkErr { pub enum ChunkError {
OutOfBounds, OutOfBounds,
} }
/// A volume with dimensions known at compile-time. /// The volume is spatially subdivided into groups of `4*4*4` blocks. Since a
// V = Voxel /// `Chunk` is of total size `32*32*16`, this implies that there are `8*8*4`
// S = Size (replace when const generics are a thing) /// groups. (These numbers are generic in the actual code such that there are
// M = Metadata /// always `256` groups. I.e. the group size is chosen depending on the desired
/// total size of the `Chunk`.)
///
/// There's a single vector `self.vox` which consecutively stores these groups.
/// Each group might or might not be contained in `self.vox`. A group that is
/// not contained represents that the full group consists only of `self.default`
/// voxels. This saves a lot of memory because oftentimes a `Chunk` consists of
/// either a lot of air or a lot of stone.
///
/// To track whether a group is contained in `self.vox`, there's an index buffer
/// `self.indices : [u8; 256]`. It contains for each group
///
/// * (a) the order in which it has been inserted into `self.vox`, if the group
/// is contained in `self.vox` or
/// * (b) 255, otherwise. That case represents that the whole group consists
/// only of `self.default` voxels.
///
/// (Note that 255 is a valid insertion order for case (a) only if `self.vox` is
/// full and then no other group has the index 255. Therefore there's no
/// ambiguity.)
///
/// ## Rationale:
///
/// The index buffer should be small because:
///
/// * Small size increases the probability that it will always be in cache.
/// * The index buffer is allocated for every `Chunk` and an almost empty `Chunk`
/// shall not consume too much memory.
///
/// The number of 256 groups is particularly nice because it means that the index
/// buffer can consist of `u8`s. This keeps the space requirement for the index
/// buffer as low as 4 cache lines.
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Chunk<V: Vox, S: VolSize, M> { pub struct Chunk<V: Vox, S: VolSize, M> {
indices: Vec<u8>, // TODO (haslersn): Box<[u8; S::SIZE.x * S::SIZE.y * S::SIZE.z]>, this is however not possible in Rust yet
vox: Vec<V>, vox: Vec<V>,
default: V,
meta: M, meta: M,
phantom: PhantomData<S>, phantom: PhantomData<S>,
} }
impl<V: Vox, S: VolSize, M> Chunk<V, S, M> { impl<V: Vox, S: VolSize, M> Chunk<V, S, M> {
/// Used to transform a voxel position in the volume into its corresponding index const VOLUME: u32 = (S::SIZE.x * S::SIZE.y * S::SIZE.z) as u32;
/// in the voxel array. const GROUP_VOLUME: u32 = [Self::VOLUME / 256, 1][(Self::VOLUME < 256) as usize];
#[inline(always)] /// `GROUP_COUNT_TOTAL` is always `256`, except if `VOLUME < 256`
fn idx_for(pos: Vec3<i32>) -> Option<usize> { const GROUP_COUNT_TOTAL: u32 = Self::VOLUME / Self::GROUP_VOLUME;
if pos.map(|e| e >= 0).reduce_and() const GROUP_LONG_SIDE_LEN: u32 = 1 << ((Self::GROUP_VOLUME * 4 - 1).count_ones() / 3);
&& pos.map2(S::SIZE, |e, lim| e < lim as i32).reduce_and() const GROUP_SIZE: Vec3<u32> = Vec3::new(
{ Self::GROUP_LONG_SIDE_LEN,
Some(Self::idx_for_unchecked(pos)) Self::GROUP_LONG_SIDE_LEN,
} else { Self::GROUP_VOLUME / (Self::GROUP_LONG_SIDE_LEN * Self::GROUP_LONG_SIDE_LEN),
None );
} const GROUP_COUNT: Vec3<u32> = Vec3::new(
} S::SIZE.x / Self::GROUP_SIZE.x,
S::SIZE.y / Self::GROUP_SIZE.y,
S::SIZE.z / Self::GROUP_SIZE.z,
);
/// Used to transform a voxel position in the volume into its corresponding index /// Creates a new `Chunk` with the provided dimensions and all voxels filled
/// in the voxel array. /// with duplicates of the provided voxel.
#[inline(always)] pub fn filled(default: V, meta: M) -> Self {
fn idx_for_unchecked(pos: Vec3<i32>) -> usize { // TODO (haslersn): Alter into compile time assertions
(pos.x * S::SIZE.y as i32 * S::SIZE.z as i32 + pos.y * S::SIZE.z as i32 + pos.z) as usize //
} // An extent is valid if it fulfils the following conditions.
} //
// 1. In each direction, the extent is a power of two.
// 2. In each direction, the group size is in [1, 256].
// 3. In each direction, the group count is in [1, 256].
//
// Rationales:
//
// 1. We have code in the implementation that assumes it. In particular,
// code using `.count_ones()`.
// 2. The maximum group size is `256x256x256`, because there's code that
// stores group relative indices as `u8`.
// 3. There's code that stores group indices as `u8`.
debug_assert!(S::SIZE.x.is_power_of_two());
debug_assert!(S::SIZE.y.is_power_of_two());
debug_assert!(S::SIZE.z.is_power_of_two());
debug_assert!(0 < Self::GROUP_SIZE.x);
debug_assert!(0 < Self::GROUP_SIZE.y);
debug_assert!(0 < Self::GROUP_SIZE.z);
debug_assert!(Self::GROUP_SIZE.x <= 256);
debug_assert!(Self::GROUP_SIZE.y <= 256);
debug_assert!(Self::GROUP_SIZE.z <= 256);
debug_assert!(0 < Self::GROUP_COUNT.x);
debug_assert!(0 < Self::GROUP_COUNT.y);
debug_assert!(0 < Self::GROUP_COUNT.z);
debug_assert!(Self::GROUP_COUNT.x <= 256);
debug_assert!(Self::GROUP_COUNT.y <= 256);
debug_assert!(Self::GROUP_COUNT.z <= 256);
impl<V: Vox, S: VolSize, M> BaseVol for Chunk<V, S, M> {
type Vox = V;
type Err = ChunkErr;
}
impl<V: Vox, S: VolSize, M> SizedVol for Chunk<V, S, M> {
#[inline(always)]
fn get_size(&self) -> Vec3<u32> {
S::SIZE
}
}
impl<V: Vox, S: VolSize, M> ReadVol for Chunk<V, S, M> {
#[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&V, ChunkErr> {
Self::idx_for(pos)
.and_then(|idx| self.vox.get(idx))
.ok_or(ChunkErr::OutOfBounds)
}
}
impl<V: Vox, S: VolSize, M> WriteVol for Chunk<V, S, M> {
#[inline(always)]
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), ChunkErr> {
Self::idx_for(pos)
.and_then(|idx| self.vox.get_mut(idx))
.map(|old_vox| *old_vox = vox)
.ok_or(ChunkErr::OutOfBounds)
}
}
impl<V: Vox + Clone, S: VolSize, M> Chunk<V, S, M> {
/// Create a new `Chunk` with the provided dimensions and all voxels filled with duplicates of
/// the provided voxel.
pub fn filled(vox: V, meta: M) -> Self {
Self { Self {
vox: vec![vox; S::SIZE.product() as usize], indices: vec![255; Self::GROUP_COUNT_TOTAL as usize],
vox: Vec::new(),
default,
meta, meta,
phantom: PhantomData, phantom: PhantomData,
} }
@ -92,4 +124,225 @@ impl<V: Vox + Clone, S: VolSize, M> Chunk<V, S, M> {
pub fn metadata_mut(&mut self) -> &mut M { pub fn metadata_mut(&mut self) -> &mut M {
&mut self.meta &mut self.meta
} }
#[inline(always)]
fn grp_idx(pos: Vec3<i32>) -> u32 {
let grp_pos = pos.map2(Self::GROUP_SIZE, |e, s| e as u32 / s);
(grp_pos.z * (Self::GROUP_COUNT.y * Self::GROUP_COUNT.x))
+ (grp_pos.y * Self::GROUP_COUNT.x)
+ (grp_pos.x)
}
#[inline(always)]
fn rel_idx(pos: Vec3<i32>) -> u32 {
let rel_pos = pos.map2(Self::GROUP_SIZE, |e, s| e as u32 % s);
(rel_pos.z * (Self::GROUP_SIZE.y * Self::GROUP_SIZE.x))
+ (rel_pos.y * Self::GROUP_SIZE.x)
+ (rel_pos.x)
}
#[inline(always)]
fn idx_unchecked(&self, pos: Vec3<i32>) -> Option<usize> {
let grp_idx = Self::grp_idx(pos);
let rel_idx = Self::rel_idx(pos);
let base = self.indices[grp_idx as usize];
let num_groups = self.vox.len() as u32 / Self::GROUP_VOLUME;
if base as u32 >= num_groups {
None
} else {
Some((base as u32 * Self::GROUP_VOLUME + rel_idx) as usize)
}
}
#[inline(always)]
fn force_idx_unchecked(&mut self, pos: Vec3<i32>) -> usize {
let grp_idx = Self::grp_idx(pos);
let rel_idx = Self::rel_idx(pos);
let base = &mut self.indices[grp_idx as usize];
let num_groups = self.vox.len() as u32 / Self::GROUP_VOLUME;
if *base as u32 >= num_groups {
*base = num_groups as u8;
self.vox
.extend(std::iter::repeat(self.default.clone()).take(Self::GROUP_VOLUME as usize));
}
(*base as u32 * Self::GROUP_VOLUME + rel_idx) as usize
}
#[inline(always)]
fn get_unchecked(&self, pos: Vec3<i32>) -> &V {
match self.idx_unchecked(pos) {
Some(idx) => &self.vox[idx],
None => &self.default,
}
}
#[inline(always)]
fn set_unchecked(&mut self, pos: Vec3<i32>, vox: V) {
if vox != self.default {
let idx = self.force_idx_unchecked(pos);
self.vox[idx] = vox;
} else if let Some(idx) = self.idx_unchecked(pos) {
self.vox[idx] = vox;
}
}
}
impl<V: Vox, S: VolSize, M> BaseVol for Chunk<V, S, M> {
type Vox = V;
type Error = ChunkError;
}
impl<V: Vox, S: VolSize, M> RasterableVol for Chunk<V, S, M> {
const SIZE: Vec3<u32> = S::SIZE;
}
impl<V: Vox, S: VolSize, M> ReadVol for Chunk<V, S, M> {
#[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Error> {
if !pos
.map2(S::SIZE, |e, s| 0 <= e && e < s as i32)
.reduce_and()
{
Err(Self::Error::OutOfBounds)
} else {
Ok(self.get_unchecked(pos))
}
}
}
impl<V: Vox, S: VolSize, M> WriteVol for Chunk<V, S, M> {
#[inline(always)]
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), Self::Error> {
if !pos
.map2(S::SIZE, |e, s| 0 <= e && e < s as i32)
.reduce_and()
{
Err(Self::Error::OutOfBounds)
} else {
Ok(self.set_unchecked(pos, vox))
}
}
}
pub struct ChunkPosIter<V: Vox, S: VolSize, M> {
// Store as `u8`s so as to reduce memory footprint.
lb: Vec3<i32>,
ub: Vec3<i32>,
pos: Vec3<i32>,
phantom: PhantomData<Chunk<V, S, M>>,
}
impl<V: Vox, S: VolSize, M> ChunkPosIter<V, S, M> {
fn new(lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self {
// If the range is empty, then we have the special case `ub = lower_bound`.
let ub = if lower_bound.map2(upper_bound, |l, u| l < u).reduce_and() {
upper_bound
} else {
lower_bound
};
Self {
lb: lower_bound,
ub,
pos: lower_bound,
phantom: PhantomData,
}
}
}
impl<V: Vox, S: VolSize, M> Iterator for ChunkPosIter<V, S, M> {
type Item = Vec3<i32>;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.pos.z >= self.ub.z {
return None;
}
let res = Some(self.pos);
self.pos.x += 1;
if self.pos.x != self.ub.x && self.pos.x % Chunk::<V, S, M>::GROUP_SIZE.x as i32 != 0 {
return res;
}
self.pos.x = std::cmp::max(
self.lb.x,
(self.pos.x - 1) & !(Chunk::<V, S, M>::GROUP_SIZE.x as i32 - 1),
);
self.pos.y += 1;
if self.pos.y != self.ub.y && self.pos.y % Chunk::<V, S, M>::GROUP_SIZE.y as i32 != 0 {
return res;
}
self.pos.y = std::cmp::max(
self.lb.y,
(self.pos.y - 1) & !(Chunk::<V, S, M>::GROUP_SIZE.y as i32 - 1),
);
self.pos.z += 1;
if self.pos.z != self.ub.z && self.pos.z % Chunk::<V, S, M>::GROUP_SIZE.z as i32 != 0 {
return res;
}
self.pos.z = std::cmp::max(
self.lb.z,
(self.pos.z - 1) & !(Chunk::<V, S, M>::GROUP_SIZE.z as i32 - 1),
);
self.pos.x = (self.pos.x | (Chunk::<V, S, M>::GROUP_SIZE.x as i32 - 1)) + 1;
if self.pos.x < self.ub.x {
return res;
}
self.pos.x = self.lb.x;
self.pos.y = (self.pos.y | (Chunk::<V, S, M>::GROUP_SIZE.y as i32 - 1)) + 1;
if self.pos.y < self.ub.y {
return res;
}
self.pos.y = self.lb.y;
self.pos.z = (self.pos.z | (Chunk::<V, S, M>::GROUP_SIZE.z as i32 - 1)) + 1;
res
}
}
pub struct ChunkVolIter<'a, V: Vox, S: VolSize, M> {
chunk: &'a Chunk<V, S, M>,
iter_impl: ChunkPosIter<V, S, M>,
}
impl<'a, V: Vox, S: VolSize, M> Iterator for ChunkVolIter<'a, V, S, M> {
type Item = (Vec3<i32>, &'a V);
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
self.iter_impl
.next()
.map(|pos| (pos, self.chunk.get_unchecked(pos)))
}
}
impl<V: Vox, S: VolSize, M> Chunk<V, S, M> {
/// It's possible to obtain a positional iterator without having a `Chunk`
/// instance.
pub fn pos_iter(lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ChunkPosIter<V, S, M> {
ChunkPosIter::<V, S, M>::new(lower_bound, upper_bound)
}
}
impl<'a, V: Vox, S: VolSize, M> IntoPosIterator for &'a Chunk<V, S, M> {
type IntoIter = ChunkPosIter<V, S, M>;
fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter {
Chunk::<V, S, M>::pos_iter(lower_bound, upper_bound)
}
}
impl<'a, V: Vox, S: VolSize, M> IntoVolIterator<'a> for &'a Chunk<V, S, M> {
type IntoIter = ChunkVolIter<'a, V, S, M>;
fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter {
ChunkVolIter::<'a, V, S, M> {
chunk: self,
iter_impl: ChunkPosIter::<V, S, M>::new(lower_bound, upper_bound),
}
}
} }

View File

@ -1,9 +1,12 @@
use crate::vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol}; use crate::vol::{
BaseVol, DefaultPosIterator, DefaultVolIterator, IntoPosIterator, IntoVolIterator, ReadVol,
SizedVol, Vox, WriteVol,
};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use vek::*; use vek::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum DynaErr { pub enum DynaError {
OutOfBounds, OutOfBounds,
} }
@ -40,32 +43,53 @@ impl<V: Vox, M> Dyna<V, M> {
impl<V: Vox, M> BaseVol for Dyna<V, M> { impl<V: Vox, M> BaseVol for Dyna<V, M> {
type Vox = V; type Vox = V;
type Err = DynaErr; type Error = DynaError;
} }
impl<V: Vox, M> SizedVol for Dyna<V, M> { impl<V: Vox, M> SizedVol for Dyna<V, M> {
#[inline(always)] #[inline(always)]
fn get_size(&self) -> Vec3<u32> { fn lower_bound(&self) -> Vec3<i32> {
self.sz Vec3::zero()
}
#[inline(always)]
fn upper_bound(&self) -> Vec3<i32> {
self.sz.map(|e| e as i32)
} }
} }
impl<V: Vox, M> ReadVol for Dyna<V, M> { impl<V: Vox, M> ReadVol for Dyna<V, M> {
#[inline(always)] #[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&V, DynaErr> { fn get(&self, pos: Vec3<i32>) -> Result<&V, DynaError> {
Self::idx_for(self.sz, pos) Self::idx_for(self.sz, pos)
.and_then(|idx| self.vox.get(idx)) .and_then(|idx| self.vox.get(idx))
.ok_or(DynaErr::OutOfBounds) .ok_or(DynaError::OutOfBounds)
} }
} }
impl<V: Vox, M> WriteVol for Dyna<V, M> { impl<V: Vox, M> WriteVol for Dyna<V, M> {
#[inline(always)] #[inline(always)]
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), DynaErr> { fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), DynaError> {
Self::idx_for(self.sz, pos) Self::idx_for(self.sz, pos)
.and_then(|idx| self.vox.get_mut(idx)) .and_then(|idx| self.vox.get_mut(idx))
.map(|old_vox| *old_vox = vox) .map(|old_vox| *old_vox = vox)
.ok_or(DynaErr::OutOfBounds) .ok_or(DynaError::OutOfBounds)
}
}
impl<'a, V: Vox, M> IntoPosIterator for &'a Dyna<V, M> {
type IntoIter = DefaultPosIterator;
fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter {
Self::IntoIter::new(lower_bound, upper_bound)
}
}
impl<'a, V: Vox, M> IntoVolIterator<'a> for &'a Dyna<V, M> {
type IntoIter = DefaultVolIterator<'a, Dyna<V, M>>;
fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter {
Self::IntoIter::new(self, lower_bound, upper_bound)
} }
} }

View File

@ -1,4 +1,4 @@
pub mod chunk; pub mod chunk;
pub mod dyna; pub mod dyna;
pub mod vol_map_2d; pub mod vol_grid_2d;
pub mod vol_map_3d; pub mod vol_grid_3d;

View File

@ -1,16 +1,16 @@
use crate::{ use crate::{
vol::{BaseVol, ReadVol, SampleVol, VolSize, WriteVol}, vol::{BaseVol, ReadVol, RectRasterableVol, SampleVol, WriteVol},
volumes::dyna::DynaErr, volumes::dyna::DynaError,
}; };
use hashbrown::{hash_map, HashMap}; use hashbrown::{hash_map, HashMap};
use std::{fmt::Debug, marker::PhantomData, sync::Arc}; use std::{fmt::Debug, sync::Arc};
use vek::*; use vek::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum VolMap2dErr<V: BaseVol> { pub enum VolGrid2dError<V: RectRasterableVol> {
NoSuchChunk, NoSuchChunk,
ChunkErr(V::Err), ChunkError(V::Error),
DynaErr(DynaErr), DynaError(DynaError),
InvalidChunkSize, InvalidChunkSize,
} }
@ -18,56 +18,55 @@ pub enum VolMap2dErr<V: BaseVol> {
// S = Size (replace with a const when const generics is a thing) // S = Size (replace with a const when const generics is a thing)
// M = Chunk metadata // M = Chunk metadata
#[derive(Clone)] #[derive(Clone)]
pub struct VolMap2d<V: BaseVol, S: VolSize> { pub struct VolGrid2d<V: RectRasterableVol> {
chunks: HashMap<Vec2<i32>, Arc<V>>, chunks: HashMap<Vec2<i32>, Arc<V>>,
phantom: PhantomData<S>,
} }
impl<V: BaseVol, S: VolSize> VolMap2d<V, S> { impl<V: RectRasterableVol> VolGrid2d<V> {
#[inline(always)] #[inline(always)]
pub fn chunk_key<P: Into<Vec2<i32>>>(pos: P) -> Vec2<i32> { pub fn chunk_key<P: Into<Vec2<i32>>>(pos: P) -> Vec2<i32> {
pos.into() pos.into()
.map2(S::SIZE.into(), |e, sz: u32| e >> (sz - 1).count_ones()) .map2(V::RECT_SIZE, |e, sz: u32| e >> (sz - 1).count_ones())
} }
#[inline(always)] #[inline(always)]
pub fn chunk_offs(pos: Vec3<i32>) -> Vec3<i32> { pub fn chunk_offs(pos: Vec3<i32>) -> Vec3<i32> {
let offs = pos.map2(S::SIZE, |e, sz| e & (sz - 1) as i32); let offs = Vec2::<i32>::from(pos).map2(V::RECT_SIZE, |e, sz| e & (sz - 1) as i32);
Vec3::new(offs.x, offs.y, pos.z) Vec3::new(offs.x, offs.y, pos.z)
} }
} }
impl<V: BaseVol + Debug, S: VolSize> BaseVol for VolMap2d<V, S> { impl<V: RectRasterableVol + Debug> BaseVol for VolGrid2d<V> {
type Vox = V::Vox; type Vox = V::Vox;
type Err = VolMap2dErr<V>; type Error = VolGrid2dError<V>;
} }
impl<V: BaseVol + ReadVol + Debug, S: VolSize> ReadVol for VolMap2d<V, S> { impl<V: RectRasterableVol + ReadVol + Debug> ReadVol for VolGrid2d<V> {
#[inline(always)] #[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&V::Vox, VolMap2dErr<V>> { fn get(&self, pos: Vec3<i32>) -> Result<&V::Vox, VolGrid2dError<V>> {
let ck = Self::chunk_key(pos); let ck = Self::chunk_key(pos);
self.chunks self.chunks
.get(&ck) .get(&ck)
.ok_or(VolMap2dErr::NoSuchChunk) .ok_or(VolGrid2dError::NoSuchChunk)
.and_then(|chunk| { .and_then(|chunk| {
let co = Self::chunk_offs(pos); let co = Self::chunk_offs(pos);
chunk.get(co).map_err(VolMap2dErr::ChunkErr) chunk.get(co).map_err(VolGrid2dError::ChunkError)
}) })
} }
} }
// TODO: This actually breaks the API: samples are supposed to have an offset of zero! // TODO: This actually breaks the API: samples are supposed to have an offset of zero!
// TODO: Should this be changed, perhaps? // TODO: Should this be changed, perhaps?
impl<I: Into<Aabr<i32>>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol<I> for VolMap2d<V, S> { impl<I: Into<Aabr<i32>>, V: RectRasterableVol + ReadVol + Debug> SampleVol<I> for VolGrid2d<V> {
type Sample = VolMap2d<V, S>; type Sample = VolGrid2d<V>;
/// Take a sample of the terrain by cloning the voxels within the provided range. /// Take a sample of the terrain by cloning the voxels within the provided range.
/// ///
/// Note that the resultant volume does not carry forward metadata from the original chunks. /// Note that the resultant volume does not carry forward metadata from the original chunks.
fn sample(&self, range: I) -> Result<Self::Sample, VolMap2dErr<V>> { fn sample(&self, range: I) -> Result<Self::Sample, VolGrid2dError<V>> {
let range = range.into(); let range = range.into();
let mut sample = VolMap2d::new()?; let mut sample = VolGrid2d::new()?;
let chunk_min = Self::chunk_key(range.min); let chunk_min = Self::chunk_key(range.min);
let chunk_max = Self::chunk_key(range.max); let chunk_max = Self::chunk_key(range.max);
for x in chunk_min.x..=chunk_max.x { for x in chunk_min.x..=chunk_max.x {
@ -86,39 +85,38 @@ impl<I: Into<Aabr<i32>>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol<I>
} }
} }
impl<V: BaseVol + WriteVol + Clone + Debug, S: VolSize + Clone> WriteVol for VolMap2d<V, S> { impl<V: RectRasterableVol + WriteVol + Clone + Debug> WriteVol for VolGrid2d<V> {
#[inline(always)] #[inline(always)]
fn set(&mut self, pos: Vec3<i32>, vox: V::Vox) -> Result<(), VolMap2dErr<V>> { fn set(&mut self, pos: Vec3<i32>, vox: V::Vox) -> Result<(), VolGrid2dError<V>> {
let ck = Self::chunk_key(pos); let ck = Self::chunk_key(pos);
self.chunks self.chunks
.get_mut(&ck) .get_mut(&ck)
.ok_or(VolMap2dErr::NoSuchChunk) .ok_or(VolGrid2dError::NoSuchChunk)
.and_then(|chunk| { .and_then(|chunk| {
let co = Self::chunk_offs(pos); let co = Self::chunk_offs(pos);
Arc::make_mut(chunk) Arc::make_mut(chunk)
.set(co, vox) .set(co, vox)
.map_err(VolMap2dErr::ChunkErr) .map_err(VolGrid2dError::ChunkError)
}) })
} }
} }
impl<V: BaseVol, S: VolSize> VolMap2d<V, S> { impl<V: RectRasterableVol> VolGrid2d<V> {
pub fn new() -> Result<Self, VolMap2dErr<V>> { pub fn new() -> Result<Self, VolGrid2dError<V>> {
if Self::chunk_size() if Self::chunk_size()
.map(|e| e.is_power_of_two() && e > 0) .map(|e| e.is_power_of_two() && e > 0)
.reduce_and() .reduce_and()
{ {
Ok(Self { Ok(Self {
chunks: HashMap::default(), chunks: HashMap::default(),
phantom: PhantomData,
}) })
} else { } else {
Err(VolMap2dErr::InvalidChunkSize) Err(VolGrid2dError::InvalidChunkSize)
} }
} }
pub fn chunk_size() -> Vec2<u32> { pub fn chunk_size() -> Vec2<u32> {
S::SIZE.into() V::RECT_SIZE
} }
pub fn insert(&mut self, key: Vec2<i32>, chunk: Arc<V>) -> Option<Arc<V>> { pub fn insert(&mut self, key: Vec2<i32>, chunk: Arc<V>) -> Option<Arc<V>> {
@ -149,7 +147,7 @@ impl<V: BaseVol, S: VolSize> VolMap2d<V, S> {
} }
pub fn key_pos(&self, key: Vec2<i32>) -> Vec2<i32> { pub fn key_pos(&self, key: Vec2<i32>) -> Vec2<i32> {
key * Vec2::<u32>::from(S::SIZE).map(|e| e as i32) key * V::RECT_SIZE.map(|e| e as i32)
} }
pub fn pos_key(&self, pos: Vec3<i32>) -> Vec2<i32> { pub fn pos_key(&self, pos: Vec3<i32>) -> Vec2<i32> {
@ -163,11 +161,11 @@ impl<V: BaseVol, S: VolSize> VolMap2d<V, S> {
} }
} }
pub struct ChunkIter<'a, V: BaseVol> { pub struct ChunkIter<'a, V: RectRasterableVol> {
iter: hash_map::Iter<'a, Vec2<i32>, Arc<V>>, iter: hash_map::Iter<'a, Vec2<i32>, Arc<V>>,
} }
impl<'a, V: BaseVol> Iterator for ChunkIter<'a, V> { impl<'a, V: RectRasterableVol> Iterator for ChunkIter<'a, V> {
type Item = (Vec2<i32>, &'a Arc<V>); type Item = (Vec2<i32>, &'a Arc<V>);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {

View File

@ -1,16 +1,16 @@
use crate::{ use crate::{
vol::{BaseVol, ReadVol, SampleVol, VolSize, WriteVol}, vol::{BaseVol, RasterableVol, ReadVol, SampleVol, WriteVol},
volumes::dyna::DynaErr, volumes::dyna::DynaError,
}; };
use hashbrown::{hash_map, HashMap}; use hashbrown::{hash_map, HashMap};
use std::{fmt::Debug, marker::PhantomData, sync::Arc}; use std::{fmt::Debug, sync::Arc};
use vek::*; use vek::*;
#[derive(Debug)] #[derive(Debug)]
pub enum VolMap3dErr<V: BaseVol> { pub enum VolGrid3dError<V: RasterableVol> {
NoSuchChunk, NoSuchChunk,
ChunkErr(V::Err), ChunkErr(V::Error),
DynaErr(DynaErr), DynaError(DynaError),
InvalidChunkSize, InvalidChunkSize,
} }
@ -18,15 +18,14 @@ pub enum VolMap3dErr<V: BaseVol> {
// S = Size (replace with a const when const generics is a thing) // S = Size (replace with a const when const generics is a thing)
// M = Chunk metadata // M = Chunk metadata
#[derive(Clone)] #[derive(Clone)]
pub struct VolMap3d<V: BaseVol, S: VolSize> { pub struct VolGrid3d<V: RasterableVol> {
chunks: HashMap<Vec3<i32>, Arc<V>>, chunks: HashMap<Vec3<i32>, Arc<V>>,
phantom: PhantomData<S>,
} }
impl<V: BaseVol, S: VolSize> VolMap3d<V, S> { impl<V: RasterableVol> VolGrid3d<V> {
#[inline(always)] #[inline(always)]
pub fn chunk_key(pos: Vec3<i32>) -> Vec3<i32> { pub fn chunk_key(pos: Vec3<i32>) -> Vec3<i32> {
pos.map2(S::SIZE, |e, sz| { pos.map2(V::SIZE, |e, sz| {
// Horrid, but it's faster than a cheetah with a red bull blood transfusion // Horrid, but it's faster than a cheetah with a red bull blood transfusion
let log2 = (sz - 1).count_ones(); let log2 = (sz - 1).count_ones();
((((i64::from(e) + (1 << 32)) as u64) >> log2) - (1 << (32 - log2))) as i32 ((((i64::from(e) + (1 << 32)) as u64) >> log2) - (1 << (32 - log2))) as i32
@ -35,43 +34,43 @@ impl<V: BaseVol, S: VolSize> VolMap3d<V, S> {
#[inline(always)] #[inline(always)]
pub fn chunk_offs(pos: Vec3<i32>) -> Vec3<i32> { pub fn chunk_offs(pos: Vec3<i32>) -> Vec3<i32> {
pos.map2(S::SIZE, |e, sz| { pos.map2(V::SIZE, |e, sz| {
// Horrid, but it's even faster than the aforementioned cheetah // Horrid, but it's even faster than the aforementioned cheetah
(((i64::from(e) + (1 << 32)) as u64) & u64::from(sz - 1)) as i32 (((i64::from(e) + (1 << 32)) as u64) & u64::from(sz - 1)) as i32
}) })
} }
} }
impl<V: BaseVol + Debug, S: VolSize> BaseVol for VolMap3d<V, S> { impl<V: RasterableVol + Debug> BaseVol for VolGrid3d<V> {
type Vox = V::Vox; type Vox = V::Vox;
type Err = VolMap3dErr<V>; type Error = VolGrid3dError<V>;
} }
impl<V: BaseVol + ReadVol + Debug, S: VolSize> ReadVol for VolMap3d<V, S> { impl<V: RasterableVol + ReadVol + Debug> ReadVol for VolGrid3d<V> {
#[inline(always)] #[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&V::Vox, VolMap3dErr<V>> { fn get(&self, pos: Vec3<i32>) -> Result<&V::Vox, VolGrid3dError<V>> {
let ck = Self::chunk_key(pos); let ck = Self::chunk_key(pos);
self.chunks self.chunks
.get(&ck) .get(&ck)
.ok_or(VolMap3dErr::NoSuchChunk) .ok_or(VolGrid3dError::NoSuchChunk)
.and_then(|chunk| { .and_then(|chunk| {
let co = Self::chunk_offs(pos); let co = Self::chunk_offs(pos);
chunk.get(co).map_err(VolMap3dErr::ChunkErr) chunk.get(co).map_err(VolGrid3dError::ChunkErr)
}) })
} }
} }
// TODO: This actually breaks the API: samples are supposed to have an offset of zero! // TODO: This actually breaks the API: samples are supposed to have an offset of zero!
// TODO: Should this be changed, perhaps? // TODO: Should this be changed, perhaps?
impl<I: Into<Aabb<i32>>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol<I> for VolMap3d<V, S> { impl<I: Into<Aabb<i32>>, V: RasterableVol + ReadVol + Debug> SampleVol<I> for VolGrid3d<V> {
type Sample = VolMap3d<V, S>; type Sample = VolGrid3d<V>;
/// Take a sample of the terrain by cloning the voxels within the provided range. /// Take a sample of the terrain by cloning the voxels within the provided range.
/// ///
/// Note that the resultant volume does not carry forward metadata from the original chunks. /// Note that the resultant volume does not carry forward metadata from the original chunks.
fn sample(&self, range: I) -> Result<Self::Sample, VolMap3dErr<V>> { fn sample(&self, range: I) -> Result<Self::Sample, VolGrid3dError<V>> {
let range = range.into(); let range = range.into();
let mut sample = VolMap3d::new()?; let mut sample = VolGrid3d::new()?;
let chunk_min = Self::chunk_key(range.min); let chunk_min = Self::chunk_key(range.min);
let chunk_max = Self::chunk_key(range.max); let chunk_max = Self::chunk_key(range.max);
for x in chunk_min.x..=chunk_max.x { for x in chunk_min.x..=chunk_max.x {
@ -92,39 +91,38 @@ impl<I: Into<Aabb<i32>>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol<I>
} }
} }
impl<V: BaseVol + WriteVol + Clone + Debug, S: VolSize + Clone> WriteVol for VolMap3d<V, S> { impl<V: RasterableVol + WriteVol + Clone + Debug> WriteVol for VolGrid3d<V> {
#[inline(always)] #[inline(always)]
fn set(&mut self, pos: Vec3<i32>, vox: V::Vox) -> Result<(), VolMap3dErr<V>> { fn set(&mut self, pos: Vec3<i32>, vox: V::Vox) -> Result<(), VolGrid3dError<V>> {
let ck = Self::chunk_key(pos); let ck = Self::chunk_key(pos);
self.chunks self.chunks
.get_mut(&ck) .get_mut(&ck)
.ok_or(VolMap3dErr::NoSuchChunk) .ok_or(VolGrid3dError::NoSuchChunk)
.and_then(|chunk| { .and_then(|chunk| {
let co = Self::chunk_offs(pos); let co = Self::chunk_offs(pos);
Arc::make_mut(chunk) Arc::make_mut(chunk)
.set(co, vox) .set(co, vox)
.map_err(VolMap3dErr::ChunkErr) .map_err(VolGrid3dError::ChunkErr)
}) })
} }
} }
impl<V: BaseVol, S: VolSize> VolMap3d<V, S> { impl<V: RasterableVol> VolGrid3d<V> {
pub fn new() -> Result<Self, VolMap3dErr<V>> { pub fn new() -> Result<Self, VolGrid3dError<V>> {
if Self::chunk_size() if Self::chunk_size()
.map(|e| e.is_power_of_two() && e > 0) .map(|e| e.is_power_of_two() && e > 0)
.reduce_and() .reduce_and()
{ {
Ok(Self { Ok(Self {
chunks: HashMap::new(), chunks: HashMap::new(),
phantom: PhantomData,
}) })
} else { } else {
Err(VolMap3dErr::InvalidChunkSize) Err(VolGrid3dError::InvalidChunkSize)
} }
} }
pub fn chunk_size() -> Vec3<u32> { pub fn chunk_size() -> Vec3<u32> {
S::SIZE V::SIZE
} }
pub fn insert(&mut self, key: Vec3<i32>, chunk: Arc<V>) -> Option<Arc<V>> { pub fn insert(&mut self, key: Vec3<i32>, chunk: Arc<V>) -> Option<Arc<V>> {
@ -147,7 +145,7 @@ impl<V: BaseVol, S: VolSize> VolMap3d<V, S> {
} }
pub fn key_pos(&self, key: Vec3<i32>) -> Vec3<i32> { pub fn key_pos(&self, key: Vec3<i32>) -> Vec3<i32> {
key * S::SIZE.map(|e| e as i32) key * V::SIZE.map(|e| e as i32)
} }
pub fn pos_key(&self, pos: Vec3<i32>) -> Vec3<i32> { pub fn pos_key(&self, pos: Vec3<i32>) -> Vec3<i32> {
@ -161,11 +159,11 @@ impl<V: BaseVol, S: VolSize> VolMap3d<V, S> {
} }
} }
pub struct ChunkIter<'a, V: BaseVol> { pub struct ChunkIter<'a, V: RasterableVol> {
iter: hash_map::Iter<'a, Vec3<i32>, Arc<V>>, iter: hash_map::Iter<'a, Vec3<i32>, Arc<V>>,
} }
impl<'a, V: BaseVol> Iterator for ChunkIter<'a, V> { impl<'a, V: RasterableVol> Iterator for ChunkIter<'a, V> {
type Item = (Vec3<i32>, &'a Arc<V>); type Item = (Vec3<i32>, &'a Arc<V>);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {

View File

@ -0,0 +1 @@

View File

@ -846,7 +846,7 @@ fn handle_debug_column(server: &mut Server, entity: EcsEntity, args: String, act
let sim = server.world.sim(); let sim = server.world.sim();
if let Ok((x, y)) = scan_fmt!(&args, action.arg_fmt, i32, i32) { if let Ok((x, y)) = scan_fmt!(&args, action.arg_fmt, i32, i32) {
let wpos = Vec2::new(x, y); let wpos = Vec2::new(x, y);
/* let chunk_pos = wpos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { /* let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
e / sz as i32 e / sz as i32
}); */ }); */

View File

@ -22,9 +22,8 @@ use common::{
msg::{ClientMsg, ClientState, RequestStateError, ServerError, ServerInfo, ServerMsg}, msg::{ClientMsg, ClientState, RequestStateError, ServerError, ServerInfo, ServerMsg},
net::PostOffice, net::PostOffice,
state::{BlockChange, State, TimeOfDay, Uid}, state::{BlockChange, State, TimeOfDay, Uid},
terrain::{block::Block, TerrainChunk, TerrainChunkSize, TerrainMap}, terrain::{block::Block, TerrainChunk, TerrainChunkSize, TerrainGrid},
vol::Vox, vol::{ReadVol, RectVolSize, Vox},
vol::{ReadVol, VolSize},
}; };
use crossbeam::channel; use crossbeam::channel;
use hashbrown::HashSet; use hashbrown::HashSet;
@ -261,7 +260,7 @@ impl Server {
let mut block_change = ecs.write_resource::<BlockChange>(); let mut block_change = ecs.write_resource::<BlockChange>();
let _ = ecs let _ = ecs
.read_resource::<TerrainMap>() .read_resource::<TerrainGrid>()
.ray(pos, pos + dir * radius) .ray(pos, pos + dir * radius)
.until(|_| rand::random::<f32>() < 0.05) .until(|_| rand::random::<f32>() < 0.05)
.for_each(|pos| block_change.set(pos, Block::empty())) .for_each(|pos| block_change.set(pos, Block::empty()))
@ -479,7 +478,7 @@ impl Server {
fn chunk_in_vd( fn chunk_in_vd(
player_pos: Vec3<f32>, player_pos: Vec3<f32>,
chunk_pos: Vec2<i32>, chunk_pos: Vec2<i32>,
terrain: &TerrainMap, terrain: &TerrainGrid,
vd: u32, vd: u32,
) -> bool { ) -> bool {
let player_chunk_pos = terrain.pos_key(player_pos.map(|e| e as i32)); let player_chunk_pos = terrain.pos_key(player_pos.map(|e| e as i32));
@ -1085,8 +1084,8 @@ impl Server {
) { ) {
{ {
// Check if the entity is in the client's range // Check if the entity is in the client's range
(pos.0 - client_pos.0) Vec2::from(pos.0 - client_pos.0)
.map2(TerrainChunkSize::SIZE, |d, sz| { .map2(TerrainChunkSize::RECT_SIZE, |d: f32, sz| {
(d.abs() as u32 / sz).checked_sub(2).unwrap_or(0) (d.abs() as u32 / sz).checked_sub(2).unwrap_or(0)
}) })
.magnitude_squared() .magnitude_squared()

View File

@ -40,7 +40,6 @@ impl Animation for WieldAnimation {
* 0.1, * 0.1,
); );
match Tool::Hammer { match Tool::Hammer {
//TODO: Inventory //TODO: Inventory
Tool::Sword => { Tool::Sword => {

View File

@ -39,7 +39,7 @@ use crate::{
GlobalState, GlobalState,
}; };
use client::{Client, Event as ClientEvent}; use client::{Client, Event as ClientEvent};
use common::{comp, terrain::TerrainChunkSize, vol::VolSize}; use common::{comp, terrain::TerrainChunk, vol::RectRasterableVol};
use conrod_core::{ use conrod_core::{
text::cursor::Index, text::cursor::Index,
widget::{self, Button, Image, Rectangle, Text}, widget::{self, Button, Image, Rectangle, Text},
@ -482,8 +482,10 @@ impl Hud {
.filter(|(entity, _, stats, _, _)| *entity != me && !stats.is_dead) .filter(|(entity, _, stats, _, _)| *entity != me && !stats.is_dead)
// Don't process nametags outside the vd (visibility further limited by ui backend) // Don't process nametags outside the vd (visibility further limited by ui backend)
.filter(|(_, pos, _, _, _)| { .filter(|(_, pos, _, _, _)| {
(pos.0 - player_pos) Vec2::from(pos.0 - player_pos)
.map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32) .map2(TerrainChunk::RECT_SIZE, |d: f32, sz| {
d.abs() as f32 / sz as f32
})
.magnitude() .magnitude()
< view_distance as f32 < view_distance as f32
}) })
@ -523,8 +525,10 @@ impl Hud {
}) })
// Don't process health bars outside the vd (visibility further limited by ui backend) // Don't process health bars outside the vd (visibility further limited by ui backend)
.filter(|(_, pos, _, _)| { .filter(|(_, pos, _, _)| {
(pos.0 - player_pos) Vec2::from(pos.0 - player_pos)
.map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32) .map2(TerrainChunk::RECT_SIZE, |d: f32, sz| {
d.abs() as f32 / sz as f32
})
.magnitude() .magnitude()
< view_distance as f32 < view_distance as f32
}) })

View File

@ -5,7 +5,7 @@ use crate::{
use common::{ use common::{
figure::Segment, figure::Segment,
util::{linear_to_srgb, srgb_to_linear}, util::{linear_to_srgb, srgb_to_linear},
vol::{ReadVol, SizedVol, Vox}, vol::{IntoFullVolIterator, Vox},
}; };
use vek::*; use vek::*;
@ -23,8 +23,8 @@ impl Meshable<FigurePipeline, FigurePipeline> for Segment {
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) { ) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
let mut mesh = Mesh::new(); let mut mesh = Mesh::new();
for pos in self.iter_positions() { for (pos, vox) in self.full_vol_iter() {
if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) { if let Some(col) = vox.get_color() {
let col = col.map(|e| e as f32 / 255.0); let col = col.map(|e| e as f32 / 255.0);
vol::push_vox_verts( vol::push_vox_verts(
@ -64,8 +64,8 @@ impl Meshable<SpritePipeline, SpritePipeline> for Segment {
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) { ) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
let mut mesh = Mesh::new(); let mut mesh = Mesh::new();
for pos in self.iter_positions() { for (pos, vox) in self.full_vol_iter() {
if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) { if let Some(col) = vox.get_color() {
let col = col.map(|e| e as f32 / 255.0); let col = col.map(|e| e as f32 / 255.0);
vol::push_vox_verts( vol::push_vox_verts(

View File

@ -4,8 +4,8 @@ use crate::{
}; };
use common::{ use common::{
terrain::{Block, BlockKind}, terrain::{Block, BlockKind},
vol::{BaseVol, ReadVol, VolSize}, vol::{ReadVol, RectRasterableVol},
volumes::vol_map_2d::VolMap2d, volumes::vol_grid_2d::VolGrid2d,
}; };
use std::fmt::Debug; use std::fmt::Debug;
use vek::*; use vek::*;
@ -24,8 +24,8 @@ fn block_shadow_density(kind: BlockKind) -> (f32, f32) {
} }
} }
impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone> impl<V: RectRasterableVol<Vox = Block> + ReadVol + Debug> Meshable<TerrainPipeline, FluidPipeline>
Meshable<TerrainPipeline, FluidPipeline> for VolMap2d<V, S> for VolGrid2d<V>
{ {
type Pipeline = TerrainPipeline; type Pipeline = TerrainPipeline;
type TranslucentPipeline = FluidPipeline; type TranslucentPipeline = FluidPipeline;
@ -126,7 +126,7 @@ impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone>
} }
/* /*
impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone> Meshable for VolMap3d<V, S> { impl<V: BaseVol<Vox = Block> + ReadVol + Debug> Meshable for VolGrid3d<V> {
type Pipeline = TerrainPipeline; type Pipeline = TerrainPipeline;
type Supplement = Aabb<i32>; type Supplement = Aabb<i32>;

View File

@ -17,8 +17,8 @@ use common::{
comp::{ comp::{
ActionState::*, Body, CharacterState, Last, MovementState::*, Ori, Pos, Scale, Stats, Vel, ActionState::*, Body, CharacterState, Last, MovementState::*, Ori, Pos, Scale, Stats, Vel,
}, },
terrain::TerrainChunkSize, terrain::TerrainChunk,
vol::VolSize, vol::RectRasterableVol,
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use log::debug; use log::debug;
@ -77,8 +77,10 @@ impl FigureMgr {
.join() .join()
{ {
// Don't process figures outside the vd // Don't process figures outside the vd
let vd_frac = (pos.0 - player_pos) let vd_frac = Vec2::from(pos.0 - player_pos)
.map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32) .map2(TerrainChunk::RECT_SIZE, |d: f32, sz| {
d.abs() as f32 / sz as f32
})
.magnitude() .magnitude()
/ view_distance as f32; / view_distance as f32;
// Keep from re-adding/removing entities on the border of the vd // Keep from re-adding/removing entities on the border of the vd

View File

@ -18,7 +18,11 @@ use crate::{
window::Event, window::Event,
}; };
use client::Client; use client::Client;
use common::{comp, terrain::BlockKind, vol::ReadVol}; use common::{
comp,
terrain::{BlockKind, TerrainChunk},
vol::ReadVol,
};
use specs::Join; use specs::Join;
use vek::*; use vek::*;
@ -45,7 +49,7 @@ pub struct Scene {
skybox: Skybox, skybox: Skybox,
postprocess: PostProcess, postprocess: PostProcess,
terrain: Terrain, terrain: Terrain<TerrainChunk>,
loaded_distance: f32, loaded_distance: f32,
figure_mgr: FigureMgr, figure_mgr: FigureMgr,

View File

@ -10,15 +10,15 @@ use client::Client;
use common::{ use common::{
assets, assets,
figure::Segment, figure::Segment,
terrain::{Block, BlockKind, TerrainChunkSize, TerrainMap}, terrain::{Block, BlockKind},
vol::{ReadVol, SampleVol, VolSize, Vox}, vol::{BaseVol, ReadVol, RectRasterableVol, SampleVol, Vox},
volumes::vol_map_2d::VolMap2dErr, volumes::vol_grid_2d::{VolGrid2d, VolGrid2dError},
}; };
use crossbeam::channel; use crossbeam::channel;
use dot_vox::DotVoxData; use dot_vox::DotVoxData;
use frustum_query::frustum::Frustum; use frustum_query::frustum::Frustum;
use hashbrown::HashMap; use hashbrown::HashMap;
use std::{f32, i32, ops::Mul, time::Duration}; use std::{f32, fmt::Debug, i32, marker::PhantomData, ops::Mul, time::Duration};
use vek::*; use vek::*;
struct TerrainChunk { struct TerrainChunk {
@ -135,11 +135,11 @@ fn sprite_config_for(kind: BlockKind) -> Option<SpriteConfig> {
} }
/// Function executed by worker threads dedicated to chunk meshing. /// Function executed by worker threads dedicated to chunk meshing.
fn mesh_worker( fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug>(
pos: Vec2<i32>, pos: Vec2<i32>,
z_bounds: (f32, f32), z_bounds: (f32, f32),
started_tick: u64, started_tick: u64,
volume: <TerrainMap as SampleVol<Aabr<i32>>>::Sample, volume: <VolGrid2d<V> as SampleVol<Aabr<i32>>>::Sample,
range: Aabb<i32>, range: Aabb<i32>,
) -> MeshWorkerResponse { ) -> MeshWorkerResponse {
let (opaque_mesh, fluid_mesh) = volume.generate_mesh(range); let (opaque_mesh, fluid_mesh) = volume.generate_mesh(range);
@ -152,12 +152,11 @@ fn mesh_worker(
sprite_instances: { sprite_instances: {
let mut instances = HashMap::new(); let mut instances = HashMap::new();
for x in 0..TerrainChunkSize::SIZE.x as i32 { for x in 0..V::RECT_SIZE.x as i32 {
for y in 0..TerrainChunkSize::SIZE.y as i32 { for y in 0..V::RECT_SIZE.y as i32 {
for z in z_bounds.0 as i32..z_bounds.1 as i32 + 1 { for z in z_bounds.0 as i32..z_bounds.1 as i32 + 1 {
let wpos = Vec3::from( let wpos = Vec3::from(pos * V::RECT_SIZE.map(|e: u32| e as i32))
pos * Vec2::from(TerrainChunkSize::SIZE).map(|e: u32| e as i32), + Vec3::new(x, y, z);
) + Vec3::new(x, y, z);
let kind = volume.get(wpos).unwrap_or(&Block::empty()).kind(); let kind = volume.get(wpos).unwrap_or(&Block::empty()).kind();
@ -189,7 +188,7 @@ fn mesh_worker(
} }
} }
pub struct Terrain { pub struct Terrain<V: RectRasterableVol> {
chunks: HashMap<Vec2<i32>, TerrainChunk>, chunks: HashMap<Vec2<i32>, TerrainChunk>,
// The mpsc sender and receiver used for talking to meshing worker threads. // The mpsc sender and receiver used for talking to meshing worker threads.
@ -200,9 +199,11 @@ pub struct Terrain {
// GPU data // GPU data
sprite_models: HashMap<(BlockKind, usize), Model<SpritePipeline>>, sprite_models: HashMap<(BlockKind, usize), Model<SpritePipeline>>,
phantom: PhantomData<V>,
} }
impl Terrain { impl<V: RectRasterableVol> Terrain<V> {
pub fn new(renderer: &mut Renderer) -> Self { pub fn new(renderer: &mut Renderer) -> Self {
// Create a new mpsc (Multiple Produced, Single Consumer) pair for communicating with // Create a new mpsc (Multiple Produced, Single Consumer) pair for communicating with
// worker threads that are meshing chunks. // worker threads that are meshing chunks.
@ -597,6 +598,7 @@ impl Terrain {
] ]
.into_iter() .into_iter()
.collect(), .collect(),
phantom: PhantomData,
} }
} }
@ -728,10 +730,10 @@ impl Terrain {
let aabr = Aabr { let aabr = Aabr {
min: todo min: todo
.pos .pos
.map2(TerrainMap::chunk_size(), |e, sz| e * sz as i32 - 1), .map2(VolGrid2d::<V>::chunk_size(), |e, sz| e * sz as i32 - 1),
max: todo max: todo.pos.map2(VolGrid2d::<V>::chunk_size(), |e, sz| {
.pos (e + 1) * sz as i32 + 1
.map2(TerrainMap::chunk_size(), |e, sz| (e + 1) * sz as i32 + 1), }),
}; };
// Copy out the chunk data we need to perform the meshing. We do this by taking a // Copy out the chunk data we need to perform the meshing. We do this by taking a
@ -740,7 +742,7 @@ impl Terrain {
Ok(sample) => sample, Ok(sample) => sample,
// Either this chunk or its neighbours doesn't yet exist, so we keep it in the // Either this chunk or its neighbours doesn't yet exist, so we keep it in the
// queue to be processed at a later date when we have its neighbours. // queue to be processed at a later date when we have its neighbours.
Err(VolMap2dErr::NoSuchChunk) => return, Err(VolGrid2dError::NoSuchChunk) => return,
_ => panic!("Unhandled edge case"), _ => panic!("Unhandled edge case"),
}; };
@ -807,7 +809,7 @@ impl Terrain {
locals: renderer locals: renderer
.create_consts(&[TerrainLocals { .create_consts(&[TerrainLocals {
model_offs: Vec3::from( model_offs: Vec3::from(
response.pos.map2(TerrainMap::chunk_size(), |e, sz| { response.pos.map2(VolGrid2d::<V>::chunk_size(), |e, sz| {
e as f32 * sz as f32 e as f32 * sz as f32
}), }),
) )
@ -836,7 +838,7 @@ impl Terrain {
); );
// Update chunk visibility // Update chunk visibility
let chunk_sz = TerrainChunkSize::SIZE.x as f32; let chunk_sz = V::RECT_SIZE.x as f32;
for (pos, chunk) in &mut self.chunks { for (pos, chunk) in &mut self.chunks {
let chunk_pos = pos.map(|e| e as f32 * chunk_sz); let chunk_pos = pos.map(|e| e as f32 * chunk_sz);
@ -886,9 +888,8 @@ impl Terrain {
if chunk.visible { if chunk.visible {
const SPRITE_RENDER_DISTANCE: f32 = 128.0; const SPRITE_RENDER_DISTANCE: f32 = 128.0;
let chunk_center = pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { let chunk_center =
(e as f32 + 0.5) * sz as f32 pos.map2(V::RECT_SIZE, |e, sz: u32| (e as f32 + 0.5) * sz as f32);
});
if Vec2::from(focus_pos).distance_squared(chunk_center) if Vec2::from(focus_pos).distance_squared(chunk_center)
< SPRITE_RENDER_DISTANCE * SPRITE_RENDER_DISTANCE < SPRITE_RENDER_DISTANCE * SPRITE_RENDER_DISTANCE
{ {

View File

@ -1,7 +1,7 @@
use common::{ use common::{
figure::Segment, figure::Segment,
util::{linear_to_srgba, srgba_to_linear}, util::{linear_to_srgba, srgba_to_linear},
vol::{ReadVol, SizedVol, Vox}, vol::{IntoFullVolIterator, ReadVol, SizedVol, Vox},
}; };
use euc::{buffer::Buffer2d, rasterizer, Pipeline}; use euc::{buffer::Buffer2d, rasterizer, Pipeline};
use image::{DynamicImage, RgbaImage}; use image::{DynamicImage, RgbaImage};
@ -69,7 +69,7 @@ pub fn draw_vox(
let mut color = Buffer2d::new(dims, [0; 4]); let mut color = Buffer2d::new(dims, [0; 4]);
let mut depth = Buffer2d::new(dims, 1.0); let mut depth = Buffer2d::new(dims, 1.0);
let (w, h, d) = segment.get_size().map(|e| e as f32).into_tuple(); let (w, h, d) = segment.size().map(|e| e as f32).into_tuple();
let mvp = Mat4::<f32>::orthographic_rh_no(FrustumPlanes { let mvp = Mat4::<f32>::orthographic_rh_no(FrustumPlanes {
left: -1.0, left: -1.0,
@ -155,8 +155,8 @@ fn create_quad(
fn generate_mesh(segment: &Segment, offs: Vec3<f32>) -> Vec<Vert> { fn generate_mesh(segment: &Segment, offs: Vec3<f32>) -> Vec<Vert> {
let mut vertices = Vec::new(); let mut vertices = Vec::new();
for pos in segment.iter_positions() { for (pos, vox) in segment.full_vol_iter() {
if let Some(col) = segment.get(pos).ok().and_then(|vox| vox.get_color()) { if let Some(col) = vox.get_color() {
let col = col.map(|e| e as f32 / 255.0); let col = col.map(|e| e as f32 / 255.0);
let is_empty = |pos| segment.get(pos).map(|v| v.is_empty()).unwrap_or(true); let is_empty = |pos| segment.get(pos).map(|v| v.is_empty()).unwrap_or(true);

View File

@ -9,7 +9,7 @@ use crate::{
use common::{ use common::{
assets, assets,
terrain::{BlockKind, Structure, TerrainChunkSize}, terrain::{BlockKind, Structure, TerrainChunkSize},
vol::VolSize, vol::RectVolSize,
}; };
use lazy_static::lazy_static; use lazy_static::lazy_static;
use noise::NoiseFn; use noise::NoiseFn;
@ -71,9 +71,7 @@ impl<'a> ColumnGen<'a> {
.min_by_key(|(pos, _)| pos.distance_squared(wpos)) .min_by_key(|(pos, _)| pos.distance_squared(wpos))
.unwrap(); .unwrap();
let chunk_pos = pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { let chunk_pos = pos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32);
e / sz as i32
});
let chunk = self.sim.get(chunk_pos)?; let chunk = self.sim.get(chunk_pos)?;
if seed % 5 == 2 if seed % 5 == 2
@ -126,9 +124,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
fn get(&self, wpos: Vec2<i32>) -> Option<ColumnSample<'a>> { fn get(&self, wpos: Vec2<i32>) -> Option<ColumnSample<'a>> {
let wposf = wpos.map(|e| e as f64); let wposf = wpos.map(|e| e as f64);
let chunk_pos = wpos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32);
e / sz as i32
});
let sim = &self.sim; let sim = &self.sim;

View File

@ -34,13 +34,13 @@ impl TownColumn {
} }
} }
#[derive(Clone)] #[derive(Clone, PartialEq)]
pub struct Module { pub struct Module {
pub vol_idx: usize, pub vol_idx: usize,
pub dir: usize, pub dir: usize,
} }
#[derive(Clone)] #[derive(Clone, PartialEq)]
pub enum CellKind { pub enum CellKind {
Empty, Empty,
Park, Park,
@ -50,7 +50,7 @@ pub enum CellKind {
House(usize), House(usize),
} }
#[derive(Clone)] #[derive(Clone, PartialEq)]
pub struct TownCell { pub struct TownCell {
pub kind: CellKind, pub kind: CellKind,
pub module: Option<Module>, pub module: Option<Module>,
@ -200,11 +200,11 @@ impl TownVol {
impl BaseVol for TownVol { impl BaseVol for TownVol {
type Vox = TownCell; type Vox = TownCell;
type Err = TownError; type Error = TownError;
} }
impl ReadVol for TownVol { impl ReadVol for TownVol {
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Err> { fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Error> {
match self.grid.get(Vec2::from(pos)) { match self.grid.get(Vec2::from(pos)) {
Some((base, _, cells)) => cells Some((base, _, cells)) => cells
.get((pos.z + UNDERGROUND_DEPTH - *base) as usize) .get((pos.z + UNDERGROUND_DEPTH - *base) as usize)
@ -215,7 +215,7 @@ impl ReadVol for TownVol {
} }
impl WriteVol for TownVol { impl WriteVol for TownVol {
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), Self::Err> { fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), Self::Error> {
match self.grid.get_mut(Vec2::from(pos)) { match self.grid.get_mut(Vec2::from(pos)) {
Some((base, _, cells)) => cells Some((base, _, cells)) => cells
.get_mut((pos.z + UNDERGROUND_DEPTH - *base) as usize) .get_mut((pos.z + UNDERGROUND_DEPTH - *base) as usize)

View File

@ -25,7 +25,7 @@ use crate::{
}; };
use common::{ use common::{
terrain::{Block, BlockKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize}, terrain::{Block, BlockKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
vol::{ReadVol, VolSize, Vox, WriteVol}, vol::{ReadVol, RectVolSize, Vox, WriteVol},
}; };
use rand::Rng; use rand::Rng;
use std::time::Duration; use std::time::Duration;
@ -70,7 +70,7 @@ impl World {
let stone = Block::new(BlockKind::Dense, Rgb::new(200, 220, 255)); let stone = Block::new(BlockKind::Dense, Rgb::new(200, 220, 255));
let water = Block::new(BlockKind::Water, Rgb::new(60, 90, 190)); let water = Block::new(BlockKind::Water, Rgb::new(60, 90, 190));
let chunk_size2d = Vec2::from(TerrainChunkSize::SIZE); let chunk_size2d = TerrainChunkSize::RECT_SIZE;
let (base_z, sim_chunk) = match self let (base_z, sim_chunk) = match self
.sim .sim
.get_interpolated( .get_interpolated(
@ -96,13 +96,13 @@ impl World {
let meta = TerrainChunkMeta::new(sim_chunk.get_name(&self.sim), sim_chunk.get_biome()); let meta = TerrainChunkMeta::new(sim_chunk.get_name(&self.sim), sim_chunk.get_biome());
let mut sampler = self.sample_blocks(); let mut sampler = self.sample_blocks();
let chunk_block_pos = Vec3::from(chunk_pos) * TerrainChunkSize::SIZE.map(|e| e as i32); let chunk_block_pos = Vec3::from(chunk_pos) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32);
let mut chunk = TerrainChunk::new(base_z, stone, air, meta); let mut chunk = TerrainChunk::new(base_z, stone, air, meta);
for x in 0..TerrainChunkSize::SIZE.x as i32 { for x in 0..TerrainChunkSize::RECT_SIZE.x as i32 {
for y in 0..TerrainChunkSize::SIZE.y as i32 { for y in 0..TerrainChunkSize::RECT_SIZE.y as i32 {
let wpos2d = Vec2::new(x, y) let wpos2d = Vec2::new(x, y)
+ Vec3::from(chunk_pos) * TerrainChunkSize::SIZE.map(|e| e as i32); + Vec2::from(chunk_pos) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32);
let z_cache = match sampler.get_z_cache(wpos2d) { let z_cache = match sampler.get_z_cache(wpos2d) {
Some(z_cache) => z_cache, Some(z_cache) => z_cache,
@ -127,7 +127,7 @@ impl World {
} }
let gen_entity_pos = || { let gen_entity_pos = || {
let lpos2d = Vec2::from(TerrainChunkSize::SIZE) let lpos2d = TerrainChunkSize::RECT_SIZE
.map(|sz| rand::thread_rng().gen::<u32>().rem_euclid(sz)); .map(|sz| rand::thread_rng().gen::<u32>().rem_euclid(sz));
let mut lpos = Vec3::new(lpos2d.x as i32, lpos2d.y as i32, 0); let mut lpos = Vec3::new(lpos2d.x as i32, lpos2d.y as i32, 0);

View File

@ -18,7 +18,7 @@ use crate::{
}; };
use common::{ use common::{
terrain::{BiomeKind, TerrainChunkSize}, terrain::{BiomeKind, TerrainChunkSize},
vol::VolSize, vol::RectVolSize,
}; };
use noise::{ use noise::{
BasicMulti, Billow, HybridMulti, MultiFractal, NoiseFn, RidgedMulti, Seedable, SuperSimplex, BasicMulti, Billow, HybridMulti, MultiFractal, NoiseFn, RidgedMulti, Seedable, SuperSimplex,
@ -328,7 +328,7 @@ impl WorldSim {
self.rng.gen::<usize>() % grid_size.y, self.rng.gen::<usize>() % grid_size.y,
); );
let wpos = (cell_pos * cell_size + cell_size / 2) let wpos = (cell_pos * cell_size + cell_size / 2)
.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { .map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
e as i32 * sz as i32 + sz as i32 / 2 e as i32 * sz as i32 + sz as i32 / 2
}); });
@ -378,8 +378,8 @@ impl WorldSim {
for j in 0..WORLD_SIZE.y { for j in 0..WORLD_SIZE.y {
let chunk_pos = Vec2::new(i as i32, j as i32); let chunk_pos = Vec2::new(i as i32, j as i32);
let block_pos = Vec2::new( let block_pos = Vec2::new(
chunk_pos.x * TerrainChunkSize::SIZE.x as i32, chunk_pos.x * TerrainChunkSize::RECT_SIZE.x as i32,
chunk_pos.y * TerrainChunkSize::SIZE.y as i32, chunk_pos.y * TerrainChunkSize::RECT_SIZE.y as i32,
); );
let _cell_pos = Vec2::new(i / cell_size, j / cell_size); let _cell_pos = Vec2::new(i / cell_size, j / cell_size);
@ -389,9 +389,8 @@ impl WorldSim {
.iter() .iter()
.map(|(pos, seed)| RegionInfo { .map(|(pos, seed)| RegionInfo {
chunk_pos: *pos, chunk_pos: *pos,
block_pos: pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { block_pos: pos
e * sz as i32 .map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e * sz as i32),
}),
dist: (pos - chunk_pos).map(|e| e as f32).magnitude(), dist: (pos - chunk_pos).map(|e| e as f32).magnitude(),
seed: *seed, seed: *seed,
}) })
@ -429,7 +428,7 @@ impl WorldSim {
for i in 0..WORLD_SIZE.x { for i in 0..WORLD_SIZE.x {
for j in 0..WORLD_SIZE.y { for j in 0..WORLD_SIZE.y {
let chunk_pos = Vec2::new(i as i32, j as i32); let chunk_pos = Vec2::new(i as i32, j as i32);
let wpos = chunk_pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { let wpos = chunk_pos.map2(Vec2::from(TerrainChunkSize::RECT_SIZE), |e, sz: u32| {
e * sz as i32 + sz as i32 / 2 e * sz as i32 + sz as i32 / 2
}); });
@ -474,9 +473,11 @@ impl WorldSim {
} }
pub fn get_wpos(&self, wpos: Vec2<i32>) -> Option<&SimChunk> { pub fn get_wpos(&self, wpos: Vec2<i32>) -> Option<&SimChunk> {
self.get(wpos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { self.get(
wpos.map2(Vec2::from(TerrainChunkSize::RECT_SIZE), |e, sz: u32| {
e / sz as i32 e / sz as i32
})) }),
)
} }
pub fn get_mut(&mut self, chunk_pos: Vec2<i32>) -> Option<&mut SimChunk> { pub fn get_mut(&mut self, chunk_pos: Vec2<i32>) -> Option<&mut SimChunk> {
@ -509,7 +510,7 @@ impl WorldSim {
T: Copy + Default + Add<Output = T> + Mul<f32, Output = T>, T: Copy + Default + Add<Output = T> + Mul<f32, Output = T>,
F: FnMut(&SimChunk) -> T, F: FnMut(&SimChunk) -> T,
{ {
let pos = pos.map2(TerrainChunkSize::SIZE.into(), |e, sz: u32| { let pos = pos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
e as f64 / sz as f64 e as f64 / sz as f64
}); });
@ -579,7 +580,7 @@ pub struct Structures {
impl SimChunk { impl SimChunk {
fn generate(posi: usize, gen_ctx: &mut GenCtx, gen_cdf: &GenCdf) -> Self { fn generate(posi: usize, gen_ctx: &mut GenCtx, gen_cdf: &GenCdf) -> Self {
let pos = uniform_idx_as_vec2(posi); let pos = uniform_idx_as_vec2(posi);
let wposf = (pos * TerrainChunkSize::SIZE.map(|e| e as i32)).map(|e| e as f64); let wposf = (pos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32)).map(|e| e as f64);
let (_, alt_base) = gen_cdf.alt_base[posi]; let (_, alt_base) = gen_cdf.alt_base[posi];
let map_edge_factor = map_edge_factor(posi); let map_edge_factor = map_edge_factor(posi);

View File

@ -1,5 +1,5 @@
use super::WORLD_SIZE; use super::WORLD_SIZE;
use common::{terrain::TerrainChunkSize, vol::VolSize}; use common::{terrain::TerrainChunkSize, vol::RectVolSize};
use vek::*; use vek::*;
/// Computes the cumulative distribution function of the weighted sum of k independent, /// Computes the cumulative distribution function of the weighted sum of k independent,
@ -141,7 +141,7 @@ pub fn uniform_noise(f: impl Fn(usize, Vec2<f64>) -> Option<f32>) -> InverseCdf
.filter_map(|i| { .filter_map(|i| {
(f( (f(
i, i,
(uniform_idx_as_vec2(i) * TerrainChunkSize::SIZE.map(|e| e as i32)) (uniform_idx_as_vec2(i) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32))
.map(|e| e as f64), .map(|e| e as f64),
) )
.map(|res| (i, res))) .map(|res| (i, res)))