├── .gitignore ├── .travis.yml ├── Cargo.dot ├── Cargo.lock ├── Cargo.png ├── Cargo.toml ├── LICENSE ├── README.md ├── clippy.toml ├── rustfmt.toml ├── screenshot.png └── src ├── chunk.rs ├── main.rs ├── minecraft ├── biome.rs ├── block_state.rs ├── data_1_8_pre2.rs ├── mod.rs ├── model.rs ├── nbt.rs └── region.rs ├── shader.rs └── tools └── DumpData.java /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *~ 3 | *# 4 | *.o 5 | *.so 6 | *.swp 7 | *.dylib 8 | *.dSYM 9 | *.dll 10 | *.rlib 11 | *.dummy 12 | *.exe 13 | *-test 14 | /assets/minecraft/ 15 | /doc/ 16 | /target/ 17 | /build/ 18 | /.rust/ 19 | rusti.sh 20 | watch.sh 21 | /examples/** 22 | !/examples/*.rs 23 | !/examples/assets/ 24 | *.kdev4 25 | *.trace 26 | /home/ 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - nightly 4 | - stable 5 | notifications: 6 | irc: "irc.mozilla.org#piston-internals" 7 | os: 8 | - linux 9 | - osx 10 | env: 11 | global: 12 | - secure: b65AZCt2SSC/EaI+3T2GS70/Tkym40yf83Ro32Qj5gztKNEVjo/oOJWw6X+HY29V70S4BojhSpnKxv6Z59Uhk/d9ng4lPcjthv5FL1asfhYgIgQa1id3JI1xfkBFAPloLGk/DeSB7G9BZPyVFbfNKimjBf7ViO+odZulq/AGsGI= 13 | script: 14 | - cargo build -v 15 | - cargo test -v 16 | - cargo doc -v 17 | after_success: 18 | - cp -R target/doc doc 19 | - curl http://www.rust-ci.org/artifacts/put?t=$RUSTCI_TOKEN | sh 20 | - rm -r doc 21 | -------------------------------------------------------------------------------- /Cargo.dot: -------------------------------------------------------------------------------- 1 | digraph dependencies { 2 | N0[label="hematite"]; 3 | N2[label="camera_controllers"]; 4 | N3[label="docopt"]; 5 | N4[label="flate2"]; 6 | N5[label="fps_counter"]; 7 | N6[label="gfx"]; 8 | N7[label="gfx_device_gl"]; 9 | N10[label="piston"]; 10 | N11[label="piston3d-gfx_voxel"]; 11 | N12[label="pistoncore-glutin_window"]; 12 | N15[label="time"]; 13 | N16[label="vecmath"]; 14 | N26[label="piston3d-cam"]; 15 | N27[label="pistoncore-input"]; 16 | N89[label="pistoncore-event_loop"]; 17 | N90[label="pistoncore-window"]; 18 | N91[label="piston-float"]; 19 | N92[label="piston-gfx_texture"]; 20 | N93[label="piston-texture"]; 21 | N94[label="piston-viewport"]; 22 | N0 -> N2[label=""]; 23 | N0 -> N3[label=""]; 24 | N0 -> N4[label=""]; 25 | N0 -> N5[label=""]; 26 | N0 -> N6[label=""]; 27 | N0 -> N7[label=""]; 28 | N0 -> N10[label=""]; 29 | N0 -> N11[label=""]; 30 | N0 -> N12[label=""]; 31 | N0 -> N15[label=""]; 32 | N0 -> N16[label=""]; 33 | N2 -> N16[label=""]; 34 | N2 -> N26[label=""]; 35 | N2 -> N27[label=""]; 36 | N5 -> N15[label=""]; 37 | N10 -> N27[label=""]; 38 | N10 -> N89[label=""]; 39 | N10 -> N90[label=""]; 40 | N11 -> N6[label=""]; 41 | N11 -> N92[label=""]; 42 | N12 -> N27[label=""]; 43 | N12 -> N90[label=""]; 44 | N16 -> N91[label=""]; 45 | N26 -> N16[label=""]; 46 | N27 -> N94[label=""]; 47 | N89 -> N15[label=""]; 48 | N89 -> N27[label=""]; 49 | N89 -> N90[label=""]; 50 | N89 -> N94[label=""]; 51 | N90 -> N27[label=""]; 52 | N92 -> N6[label=""]; 53 | N92 -> N93[label=""]; 54 | N94 -> N91[label=""]; 55 | } 56 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ab_glyph_rasterizer" 7 | version = "0.1.7" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "330223a1aecc308757b9926e9391c9b47f8ef2dbd8aea9df88312aea18c5e8d6" 10 | 11 | [[package]] 12 | name = "adler" 13 | version = "1.0.2" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 16 | 17 | [[package]] 18 | name = "adler32" 19 | version = "1.2.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" 22 | 23 | [[package]] 24 | name = "aho-corasick" 25 | version = "0.6.10" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" 28 | dependencies = [ 29 | "memchr", 30 | ] 31 | 32 | [[package]] 33 | name = "andrew" 34 | version = "0.3.1" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "8c4afb09dd642feec8408e33f92f3ffc4052946f6b20f32fb99c1f58cd4fa7cf" 37 | dependencies = [ 38 | "bitflags", 39 | "rusttype", 40 | "walkdir", 41 | "xdg", 42 | "xml-rs 0.8.3", 43 | ] 44 | 45 | [[package]] 46 | name = "android_glue" 47 | version = "0.2.3" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" 50 | 51 | [[package]] 52 | name = "array" 53 | version = "0.0.1" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "bf27051ee75000297d5afad639a434ad6d3d7d3136ccaab75a1b7c439b9afa11" 56 | 57 | [[package]] 58 | name = "autocfg" 59 | version = "1.0.1" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 62 | 63 | [[package]] 64 | name = "bitflags" 65 | version = "1.2.1" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 68 | 69 | [[package]] 70 | name = "block" 71 | version = "0.1.6" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" 74 | 75 | [[package]] 76 | name = "byteorder" 77 | version = "1.4.3" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 80 | 81 | [[package]] 82 | name = "bzip2" 83 | version = "0.4.4" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" 86 | dependencies = [ 87 | "bzip2-sys", 88 | "libc", 89 | ] 90 | 91 | [[package]] 92 | name = "bzip2-sys" 93 | version = "0.1.11+1.0.8" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" 96 | dependencies = [ 97 | "cc", 98 | "libc", 99 | "pkg-config", 100 | ] 101 | 102 | [[package]] 103 | name = "calloop" 104 | version = "0.6.5" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "0b036167e76041694579972c28cf4877b4f92da222560ddb49008937b6a6727c" 107 | dependencies = [ 108 | "log", 109 | "nix 0.18.0", 110 | ] 111 | 112 | [[package]] 113 | name = "camera_controllers" 114 | version = "0.32.0" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "832c5e36b91a2cd7d29f4fe76b1464b1288326f450bc829cf75b62fc4a1fed26" 117 | dependencies = [ 118 | "bitflags", 119 | "piston3d-cam", 120 | "pistoncore-input", 121 | "quaternion", 122 | "vecmath", 123 | ] 124 | 125 | [[package]] 126 | name = "cc" 127 | version = "1.0.69" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" 130 | 131 | [[package]] 132 | name = "cfg-if" 133 | version = "0.1.10" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 136 | 137 | [[package]] 138 | name = "cfg-if" 139 | version = "1.0.0" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 142 | 143 | [[package]] 144 | name = "cgl" 145 | version = "0.3.2" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" 148 | dependencies = [ 149 | "libc", 150 | ] 151 | 152 | [[package]] 153 | name = "cocoa" 154 | version = "0.23.0" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "c54201c07dcf3a5ca33fececb8042aed767ee4bfd5a0235a8ceabcda956044b2" 157 | dependencies = [ 158 | "bitflags", 159 | "block", 160 | "cocoa-foundation", 161 | "core-foundation 0.9.3", 162 | "core-graphics 0.22.3", 163 | "foreign-types", 164 | "libc", 165 | "objc", 166 | ] 167 | 168 | [[package]] 169 | name = "cocoa" 170 | version = "0.24.1" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" 173 | dependencies = [ 174 | "bitflags", 175 | "block", 176 | "cocoa-foundation", 177 | "core-foundation 0.9.3", 178 | "core-graphics 0.22.3", 179 | "foreign-types", 180 | "libc", 181 | "objc", 182 | ] 183 | 184 | [[package]] 185 | name = "cocoa-foundation" 186 | version = "0.1.0" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" 189 | dependencies = [ 190 | "bitflags", 191 | "block", 192 | "core-foundation 0.9.3", 193 | "core-graphics-types", 194 | "foreign-types", 195 | "libc", 196 | "objc", 197 | ] 198 | 199 | [[package]] 200 | name = "color_quant" 201 | version = "1.1.0" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" 204 | 205 | [[package]] 206 | name = "core-foundation" 207 | version = "0.7.0" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" 210 | dependencies = [ 211 | "core-foundation-sys 0.7.0", 212 | "libc", 213 | ] 214 | 215 | [[package]] 216 | name = "core-foundation" 217 | version = "0.9.3" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" 220 | dependencies = [ 221 | "core-foundation-sys 0.8.3", 222 | "libc", 223 | ] 224 | 225 | [[package]] 226 | name = "core-foundation-sys" 227 | version = "0.7.0" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" 230 | 231 | [[package]] 232 | name = "core-foundation-sys" 233 | version = "0.8.3" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 236 | 237 | [[package]] 238 | name = "core-graphics" 239 | version = "0.19.2" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" 242 | dependencies = [ 243 | "bitflags", 244 | "core-foundation 0.7.0", 245 | "foreign-types", 246 | "libc", 247 | ] 248 | 249 | [[package]] 250 | name = "core-graphics" 251 | version = "0.22.3" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" 254 | dependencies = [ 255 | "bitflags", 256 | "core-foundation 0.9.3", 257 | "core-graphics-types", 258 | "foreign-types", 259 | "libc", 260 | ] 261 | 262 | [[package]] 263 | name = "core-graphics-types" 264 | version = "0.1.1" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" 267 | dependencies = [ 268 | "bitflags", 269 | "core-foundation 0.9.3", 270 | "foreign-types", 271 | "libc", 272 | ] 273 | 274 | [[package]] 275 | name = "core-video-sys" 276 | version = "0.1.4" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" 279 | dependencies = [ 280 | "cfg-if 0.1.10", 281 | "core-foundation-sys 0.7.0", 282 | "core-graphics 0.19.2", 283 | "libc", 284 | "objc", 285 | ] 286 | 287 | [[package]] 288 | name = "crc32fast" 289 | version = "1.2.1" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" 292 | dependencies = [ 293 | "cfg-if 1.0.0", 294 | ] 295 | 296 | [[package]] 297 | name = "crossbeam-channel" 298 | version = "0.5.1" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" 301 | dependencies = [ 302 | "cfg-if 1.0.0", 303 | "crossbeam-utils", 304 | ] 305 | 306 | [[package]] 307 | name = "crossbeam-deque" 308 | version = "0.8.1" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" 311 | dependencies = [ 312 | "cfg-if 1.0.0", 313 | "crossbeam-epoch", 314 | "crossbeam-utils", 315 | ] 316 | 317 | [[package]] 318 | name = "crossbeam-epoch" 319 | version = "0.9.5" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" 322 | dependencies = [ 323 | "cfg-if 1.0.0", 324 | "crossbeam-utils", 325 | "lazy_static 1.4.0", 326 | "memoffset", 327 | "scopeguard", 328 | ] 329 | 330 | [[package]] 331 | name = "crossbeam-utils" 332 | version = "0.8.8" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" 335 | dependencies = [ 336 | "cfg-if 1.0.0", 337 | "lazy_static 1.4.0", 338 | ] 339 | 340 | [[package]] 341 | name = "cty" 342 | version = "0.2.2" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" 345 | 346 | [[package]] 347 | name = "darling" 348 | version = "0.10.2" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" 351 | dependencies = [ 352 | "darling_core", 353 | "darling_macro", 354 | ] 355 | 356 | [[package]] 357 | name = "darling_core" 358 | version = "0.10.2" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" 361 | dependencies = [ 362 | "fnv", 363 | "ident_case", 364 | "proc-macro2 1.0.27", 365 | "quote 1.0.9", 366 | "strsim 0.9.3", 367 | "syn 1.0.73", 368 | ] 369 | 370 | [[package]] 371 | name = "darling_macro" 372 | version = "0.10.2" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" 375 | dependencies = [ 376 | "darling_core", 377 | "quote 1.0.9", 378 | "syn 1.0.73", 379 | ] 380 | 381 | [[package]] 382 | name = "deflate" 383 | version = "0.7.20" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4" 386 | dependencies = [ 387 | "adler32", 388 | "byteorder", 389 | ] 390 | 391 | [[package]] 392 | name = "derivative" 393 | version = "1.0.4" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "3c6d883546668a3e2011b6a716a7330b82eabb0151b138217f632c8243e17135" 396 | dependencies = [ 397 | "proc-macro2 0.4.30", 398 | "quote 0.6.13", 399 | "syn 0.15.44", 400 | ] 401 | 402 | [[package]] 403 | name = "derivative" 404 | version = "2.2.0" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" 407 | dependencies = [ 408 | "proc-macro2 1.0.27", 409 | "quote 1.0.9", 410 | "syn 1.0.73", 411 | ] 412 | 413 | [[package]] 414 | name = "dispatch" 415 | version = "0.2.0" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" 418 | 419 | [[package]] 420 | name = "dlib" 421 | version = "0.4.2" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "b11f15d1e3268f140f68d390637d5e76d849782d971ae7063e0da69fe9709a76" 424 | dependencies = [ 425 | "libloading 0.6.7", 426 | ] 427 | 428 | [[package]] 429 | name = "dlib" 430 | version = "0.5.0" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" 433 | dependencies = [ 434 | "libloading 0.7.4", 435 | ] 436 | 437 | [[package]] 438 | name = "docopt" 439 | version = "0.7.0" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8" 442 | dependencies = [ 443 | "lazy_static 0.2.11", 444 | "regex", 445 | "rustc-serialize", 446 | "strsim 0.6.0", 447 | ] 448 | 449 | [[package]] 450 | name = "downcast-rs" 451 | version = "1.2.0" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" 454 | 455 | [[package]] 456 | name = "draw_state" 457 | version = "0.8.0" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "33cf9537e2d06891448799b96d5a8c8083e0e90522a7fdabe6ebf4f41d79d651" 460 | dependencies = [ 461 | "bitflags", 462 | ] 463 | 464 | [[package]] 465 | name = "either" 466 | version = "1.6.1" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 469 | 470 | [[package]] 471 | name = "flate2" 472 | version = "1.0.20" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" 475 | dependencies = [ 476 | "cfg-if 1.0.0", 477 | "crc32fast", 478 | "libc", 479 | "miniz_oxide", 480 | ] 481 | 482 | [[package]] 483 | name = "fnv" 484 | version = "1.0.7" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 487 | 488 | [[package]] 489 | name = "foreign-types" 490 | version = "0.3.2" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 493 | dependencies = [ 494 | "foreign-types-shared", 495 | ] 496 | 497 | [[package]] 498 | name = "foreign-types-shared" 499 | version = "0.1.1" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 502 | 503 | [[package]] 504 | name = "fps_counter" 505 | version = "2.0.0" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "3aaba7ff514ee9d802b562927f80b1e94e93d8e74c31b134c9c3762dabf1a36b" 508 | 509 | [[package]] 510 | name = "fs2" 511 | version = "0.4.3" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" 514 | dependencies = [ 515 | "libc", 516 | "winapi 0.3.9", 517 | ] 518 | 519 | [[package]] 520 | name = "fuchsia-zircon" 521 | version = "0.3.3" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 524 | dependencies = [ 525 | "bitflags", 526 | "fuchsia-zircon-sys", 527 | ] 528 | 529 | [[package]] 530 | name = "fuchsia-zircon-sys" 531 | version = "0.3.3" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 534 | 535 | [[package]] 536 | name = "gfx" 537 | version = "0.17.1" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "7d7ce0c1f747245342a73453fdb098ea0764c430421fbc4d98cdc8ef8ede4834" 540 | dependencies = [ 541 | "derivative 1.0.4", 542 | "draw_state", 543 | "gfx_core", 544 | "log", 545 | ] 546 | 547 | [[package]] 548 | name = "gfx_core" 549 | version = "0.8.3" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "c74932837e61f20956c3da1a47471513707dde300274812bba94373ab51830ae" 552 | dependencies = [ 553 | "bitflags", 554 | "derivative 1.0.4", 555 | "draw_state", 556 | "log", 557 | ] 558 | 559 | [[package]] 560 | name = "gfx_device_gl" 561 | version = "0.15.5" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "def9cc76ab9ae3187a1ef5edb16c263fa7d713319ffa1d46e00c9d348081a982" 564 | dependencies = [ 565 | "gfx_core", 566 | "gfx_gl", 567 | "log", 568 | ] 569 | 570 | [[package]] 571 | name = "gfx_gl" 572 | version = "0.5.0" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "3e8a920f8f6c1025a7ddf9dd25502bf059506fd3cd765dfbe8dba0b56b7eeecb" 575 | dependencies = [ 576 | "gl_generator 0.9.0", 577 | ] 578 | 579 | [[package]] 580 | name = "gif" 581 | version = "0.10.3" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "471d90201b3b223f3451cd4ad53e34295f16a1df17b1edf3736d47761c3981af" 584 | dependencies = [ 585 | "color_quant", 586 | "lzw", 587 | ] 588 | 589 | [[package]] 590 | name = "gl" 591 | version = "0.13.0" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "4b411c7e0bfc599e3606412c190e786b5bb48cf00073e1635f9bb6f88fe7d84a" 594 | dependencies = [ 595 | "gl_generator 0.13.1", 596 | ] 597 | 598 | [[package]] 599 | name = "gl_generator" 600 | version = "0.9.0" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "7a795170cbd85b5a7baa58d6d7525cae6a03e486859860c220f7ebbbdd379d0a" 603 | dependencies = [ 604 | "khronos_api 2.2.0", 605 | "log", 606 | "xml-rs 0.7.0", 607 | ] 608 | 609 | [[package]] 610 | name = "gl_generator" 611 | version = "0.13.1" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "ca98bbde17256e02d17336a6bdb5a50f7d0ccacee502e191d3e3d0ec2f96f84a" 614 | dependencies = [ 615 | "khronos_api 3.1.0", 616 | "log", 617 | "xml-rs 0.8.3", 618 | ] 619 | 620 | [[package]] 621 | name = "gl_generator" 622 | version = "0.14.0" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" 625 | dependencies = [ 626 | "khronos_api 3.1.0", 627 | "log", 628 | "xml-rs 0.8.3", 629 | ] 630 | 631 | [[package]] 632 | name = "glutin" 633 | version = "0.26.0" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "1ae1cbb9176b9151c4ce03f012e3cd1c6c18c4be79edeaeb3d99f5d8085c5fa3" 636 | dependencies = [ 637 | "android_glue", 638 | "cgl", 639 | "cocoa 0.23.0", 640 | "core-foundation 0.9.3", 641 | "glutin_egl_sys", 642 | "glutin_emscripten_sys", 643 | "glutin_gles2_sys", 644 | "glutin_glx_sys", 645 | "glutin_wgl_sys", 646 | "lazy_static 1.4.0", 647 | "libloading 0.6.7", 648 | "log", 649 | "objc", 650 | "osmesa-sys", 651 | "parking_lot", 652 | "wayland-client", 653 | "wayland-egl", 654 | "winapi 0.3.9", 655 | "winit", 656 | ] 657 | 658 | [[package]] 659 | name = "glutin_egl_sys" 660 | version = "0.1.6" 661 | source = "registry+https://github.com/rust-lang/crates.io-index" 662 | checksum = "68900f84b471f31ea1d1355567eb865a2cf446294f06cef8d653ed7bcf5f013d" 663 | dependencies = [ 664 | "gl_generator 0.14.0", 665 | "winapi 0.3.9", 666 | ] 667 | 668 | [[package]] 669 | name = "glutin_emscripten_sys" 670 | version = "0.1.1" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "80de4146df76e8a6c32b03007bc764ff3249dcaeb4f675d68a06caf1bac363f1" 673 | 674 | [[package]] 675 | name = "glutin_gles2_sys" 676 | version = "0.1.5" 677 | source = "registry+https://github.com/rust-lang/crates.io-index" 678 | checksum = "e8094e708b730a7c8a1954f4f8a31880af00eb8a1c5b5bf85d28a0a3c6d69103" 679 | dependencies = [ 680 | "gl_generator 0.14.0", 681 | "objc", 682 | ] 683 | 684 | [[package]] 685 | name = "glutin_glx_sys" 686 | version = "0.1.8" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "d93d0575865098580c5b3a423188cd959419912ea60b1e48e8b3b526f6d02468" 689 | dependencies = [ 690 | "gl_generator 0.14.0", 691 | "x11-dl", 692 | ] 693 | 694 | [[package]] 695 | name = "glutin_wgl_sys" 696 | version = "0.1.5" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "3da5951a1569dbab865c6f2a863efafff193a93caf05538d193e9e3816d21696" 699 | dependencies = [ 700 | "gl_generator 0.14.0", 701 | ] 702 | 703 | [[package]] 704 | name = "hematite" 705 | version = "0.0.34" 706 | dependencies = [ 707 | "byteorder", 708 | "camera_controllers", 709 | "docopt", 710 | "flate2", 711 | "fps_counter", 712 | "gfx", 713 | "gfx_core", 714 | "gfx_device_gl", 715 | "libc", 716 | "memmap", 717 | "piston", 718 | "piston3d-gfx_voxel", 719 | "pistoncore-glutin_window", 720 | "rustc-serialize", 721 | "shader_version", 722 | "vecmath", 723 | "zip", 724 | ] 725 | 726 | [[package]] 727 | name = "hermit-abi" 728 | version = "0.1.19" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 731 | dependencies = [ 732 | "libc", 733 | ] 734 | 735 | [[package]] 736 | name = "ident_case" 737 | version = "1.0.1" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 740 | 741 | [[package]] 742 | name = "image" 743 | version = "0.21.3" 744 | source = "registry+https://github.com/rust-lang/crates.io-index" 745 | checksum = "35371e467cd7b0b3d1d6013d619203658467df12d61b0ca43cd67b743b1965eb" 746 | dependencies = [ 747 | "byteorder", 748 | "gif", 749 | "jpeg-decoder", 750 | "lzw", 751 | "num-iter", 752 | "num-rational", 753 | "num-traits", 754 | "png", 755 | "scoped_threadpool", 756 | "tiff", 757 | ] 758 | 759 | [[package]] 760 | name = "inflate" 761 | version = "0.4.5" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" 764 | dependencies = [ 765 | "adler32", 766 | ] 767 | 768 | [[package]] 769 | name = "instant" 770 | version = "0.1.12" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 773 | dependencies = [ 774 | "cfg-if 1.0.0", 775 | ] 776 | 777 | [[package]] 778 | name = "iovec" 779 | version = "0.1.4" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 782 | dependencies = [ 783 | "libc", 784 | ] 785 | 786 | [[package]] 787 | name = "jni-sys" 788 | version = "0.3.0" 789 | source = "registry+https://github.com/rust-lang/crates.io-index" 790 | checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" 791 | 792 | [[package]] 793 | name = "jpeg-decoder" 794 | version = "0.1.22" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" 797 | dependencies = [ 798 | "rayon", 799 | ] 800 | 801 | [[package]] 802 | name = "kernel32-sys" 803 | version = "0.2.2" 804 | source = "registry+https://github.com/rust-lang/crates.io-index" 805 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 806 | dependencies = [ 807 | "winapi 0.2.8", 808 | "winapi-build", 809 | ] 810 | 811 | [[package]] 812 | name = "khronos_api" 813 | version = "2.2.0" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "037ab472c33f67b5fbd3e9163a2645319e5356fcd355efa6d4eb7fff4bbcb554" 816 | 817 | [[package]] 818 | name = "khronos_api" 819 | version = "3.1.0" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" 822 | 823 | [[package]] 824 | name = "lazy_static" 825 | version = "0.2.11" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" 828 | 829 | [[package]] 830 | name = "lazy_static" 831 | version = "1.4.0" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 834 | 835 | [[package]] 836 | name = "lazycell" 837 | version = "1.3.0" 838 | source = "registry+https://github.com/rust-lang/crates.io-index" 839 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 840 | 841 | [[package]] 842 | name = "libc" 843 | version = "0.2.137" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" 846 | 847 | [[package]] 848 | name = "libloading" 849 | version = "0.6.7" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" 852 | dependencies = [ 853 | "cfg-if 1.0.0", 854 | "winapi 0.3.9", 855 | ] 856 | 857 | [[package]] 858 | name = "libloading" 859 | version = "0.7.4" 860 | source = "registry+https://github.com/rust-lang/crates.io-index" 861 | checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" 862 | dependencies = [ 863 | "cfg-if 1.0.0", 864 | "winapi 0.3.9", 865 | ] 866 | 867 | [[package]] 868 | name = "lock_api" 869 | version = "0.4.6" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" 872 | dependencies = [ 873 | "scopeguard", 874 | ] 875 | 876 | [[package]] 877 | name = "log" 878 | version = "0.4.14" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 881 | dependencies = [ 882 | "cfg-if 1.0.0", 883 | ] 884 | 885 | [[package]] 886 | name = "lzw" 887 | version = "0.10.0" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" 890 | 891 | [[package]] 892 | name = "malloc_buf" 893 | version = "0.0.6" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" 896 | dependencies = [ 897 | "libc", 898 | ] 899 | 900 | [[package]] 901 | name = "maybe-uninit" 902 | version = "2.0.0" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" 905 | 906 | [[package]] 907 | name = "memchr" 908 | version = "2.4.0" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" 911 | 912 | [[package]] 913 | name = "memmap" 914 | version = "0.5.2" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "46f3c7359028b31999287dae4e5047ddfe90a23b7dca2282ce759b491080c99b" 917 | dependencies = [ 918 | "fs2", 919 | "kernel32-sys", 920 | "libc", 921 | "winapi 0.2.8", 922 | ] 923 | 924 | [[package]] 925 | name = "memmap2" 926 | version = "0.1.0" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "d9b70ca2a6103ac8b665dc150b142ef0e4e89df640c9e6cf295d189c3caebe5a" 929 | dependencies = [ 930 | "libc", 931 | ] 932 | 933 | [[package]] 934 | name = "memoffset" 935 | version = "0.6.4" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" 938 | dependencies = [ 939 | "autocfg", 940 | ] 941 | 942 | [[package]] 943 | name = "minimal-lexical" 944 | version = "0.2.1" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 947 | 948 | [[package]] 949 | name = "miniz_oxide" 950 | version = "0.4.4" 951 | source = "registry+https://github.com/rust-lang/crates.io-index" 952 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" 953 | dependencies = [ 954 | "adler", 955 | "autocfg", 956 | ] 957 | 958 | [[package]] 959 | name = "mio" 960 | version = "0.6.23" 961 | source = "registry+https://github.com/rust-lang/crates.io-index" 962 | checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" 963 | dependencies = [ 964 | "cfg-if 0.1.10", 965 | "fuchsia-zircon", 966 | "fuchsia-zircon-sys", 967 | "iovec", 968 | "kernel32-sys", 969 | "libc", 970 | "log", 971 | "miow", 972 | "net2", 973 | "slab", 974 | "winapi 0.2.8", 975 | ] 976 | 977 | [[package]] 978 | name = "mio-extras" 979 | version = "2.0.6" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" 982 | dependencies = [ 983 | "lazycell", 984 | "log", 985 | "mio", 986 | "slab", 987 | ] 988 | 989 | [[package]] 990 | name = "miow" 991 | version = "0.2.2" 992 | source = "registry+https://github.com/rust-lang/crates.io-index" 993 | checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" 994 | dependencies = [ 995 | "kernel32-sys", 996 | "net2", 997 | "winapi 0.2.8", 998 | "ws2_32-sys", 999 | ] 1000 | 1001 | [[package]] 1002 | name = "ndk" 1003 | version = "0.2.1" 1004 | source = "registry+https://github.com/rust-lang/crates.io-index" 1005 | checksum = "5eb167c1febed0a496639034d0c76b3b74263636045db5489eee52143c246e73" 1006 | dependencies = [ 1007 | "jni-sys", 1008 | "ndk-sys", 1009 | "num_enum", 1010 | "thiserror", 1011 | ] 1012 | 1013 | [[package]] 1014 | name = "ndk-glue" 1015 | version = "0.2.1" 1016 | source = "registry+https://github.com/rust-lang/crates.io-index" 1017 | checksum = "bdf399b8b7a39c6fb153c4ec32c72fd5fe789df24a647f229c239aa7adb15241" 1018 | dependencies = [ 1019 | "lazy_static 1.4.0", 1020 | "libc", 1021 | "log", 1022 | "ndk", 1023 | "ndk-macro", 1024 | "ndk-sys", 1025 | ] 1026 | 1027 | [[package]] 1028 | name = "ndk-macro" 1029 | version = "0.2.0" 1030 | source = "registry+https://github.com/rust-lang/crates.io-index" 1031 | checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" 1032 | dependencies = [ 1033 | "darling", 1034 | "proc-macro-crate", 1035 | "proc-macro2 1.0.27", 1036 | "quote 1.0.9", 1037 | "syn 1.0.73", 1038 | ] 1039 | 1040 | [[package]] 1041 | name = "ndk-sys" 1042 | version = "0.2.2" 1043 | source = "registry+https://github.com/rust-lang/crates.io-index" 1044 | checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" 1045 | 1046 | [[package]] 1047 | name = "net2" 1048 | version = "0.2.38" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "74d0df99cfcd2530b2e694f6e17e7f37b8e26bb23983ac530c0c97408837c631" 1051 | dependencies = [ 1052 | "cfg-if 0.1.10", 1053 | "libc", 1054 | "winapi 0.3.9", 1055 | ] 1056 | 1057 | [[package]] 1058 | name = "nix" 1059 | version = "0.18.0" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" 1062 | dependencies = [ 1063 | "bitflags", 1064 | "cc", 1065 | "cfg-if 0.1.10", 1066 | "libc", 1067 | ] 1068 | 1069 | [[package]] 1070 | name = "nix" 1071 | version = "0.20.2" 1072 | source = "registry+https://github.com/rust-lang/crates.io-index" 1073 | checksum = "f5e06129fb611568ef4e868c14b326274959aa70ff7776e9d55323531c374945" 1074 | dependencies = [ 1075 | "bitflags", 1076 | "cc", 1077 | "cfg-if 1.0.0", 1078 | "libc", 1079 | "memoffset", 1080 | ] 1081 | 1082 | [[package]] 1083 | name = "nom" 1084 | version = "7.1.1" 1085 | source = "registry+https://github.com/rust-lang/crates.io-index" 1086 | checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" 1087 | dependencies = [ 1088 | "memchr", 1089 | "minimal-lexical", 1090 | ] 1091 | 1092 | [[package]] 1093 | name = "num-derive" 1094 | version = "0.2.5" 1095 | source = "registry+https://github.com/rust-lang/crates.io-index" 1096 | checksum = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" 1097 | dependencies = [ 1098 | "proc-macro2 0.4.30", 1099 | "quote 0.6.13", 1100 | "syn 0.15.44", 1101 | ] 1102 | 1103 | [[package]] 1104 | name = "num-integer" 1105 | version = "0.1.44" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 1108 | dependencies = [ 1109 | "autocfg", 1110 | "num-traits", 1111 | ] 1112 | 1113 | [[package]] 1114 | name = "num-iter" 1115 | version = "0.1.42" 1116 | source = "registry+https://github.com/rust-lang/crates.io-index" 1117 | checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" 1118 | dependencies = [ 1119 | "autocfg", 1120 | "num-integer", 1121 | "num-traits", 1122 | ] 1123 | 1124 | [[package]] 1125 | name = "num-rational" 1126 | version = "0.2.4" 1127 | source = "registry+https://github.com/rust-lang/crates.io-index" 1128 | checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" 1129 | dependencies = [ 1130 | "autocfg", 1131 | "num-integer", 1132 | "num-traits", 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "num-traits" 1137 | version = "0.2.14" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 1140 | dependencies = [ 1141 | "autocfg", 1142 | ] 1143 | 1144 | [[package]] 1145 | name = "num_cpus" 1146 | version = "1.13.0" 1147 | source = "registry+https://github.com/rust-lang/crates.io-index" 1148 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 1149 | dependencies = [ 1150 | "hermit-abi", 1151 | "libc", 1152 | ] 1153 | 1154 | [[package]] 1155 | name = "num_enum" 1156 | version = "0.4.3" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | checksum = "ca565a7df06f3d4b485494f25ba05da1435950f4dc263440eda7a6fa9b8e36e4" 1159 | dependencies = [ 1160 | "derivative 2.2.0", 1161 | "num_enum_derive", 1162 | ] 1163 | 1164 | [[package]] 1165 | name = "num_enum_derive" 1166 | version = "0.4.3" 1167 | source = "registry+https://github.com/rust-lang/crates.io-index" 1168 | checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d" 1169 | dependencies = [ 1170 | "proc-macro-crate", 1171 | "proc-macro2 1.0.27", 1172 | "quote 1.0.9", 1173 | "syn 1.0.73", 1174 | ] 1175 | 1176 | [[package]] 1177 | name = "objc" 1178 | version = "0.2.7" 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" 1180 | checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" 1181 | dependencies = [ 1182 | "malloc_buf", 1183 | ] 1184 | 1185 | [[package]] 1186 | name = "once_cell" 1187 | version = "1.16.0" 1188 | source = "registry+https://github.com/rust-lang/crates.io-index" 1189 | checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" 1190 | 1191 | [[package]] 1192 | name = "osmesa-sys" 1193 | version = "0.1.2" 1194 | source = "registry+https://github.com/rust-lang/crates.io-index" 1195 | checksum = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b" 1196 | dependencies = [ 1197 | "shared_library", 1198 | ] 1199 | 1200 | [[package]] 1201 | name = "owned_ttf_parser" 1202 | version = "0.15.2" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "05e6affeb1632d6ff6a23d2cd40ffed138e82f1532571a26f527c8a284bb2fbb" 1205 | dependencies = [ 1206 | "ttf-parser", 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "parking_lot" 1211 | version = "0.11.2" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 1214 | dependencies = [ 1215 | "instant", 1216 | "lock_api", 1217 | "parking_lot_core", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "parking_lot_core" 1222 | version = "0.8.5" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 1225 | dependencies = [ 1226 | "cfg-if 1.0.0", 1227 | "instant", 1228 | "libc", 1229 | "redox_syscall", 1230 | "smallvec", 1231 | "winapi 0.3.9", 1232 | ] 1233 | 1234 | [[package]] 1235 | name = "percent-encoding" 1236 | version = "2.2.0" 1237 | source = "registry+https://github.com/rust-lang/crates.io-index" 1238 | checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" 1239 | 1240 | [[package]] 1241 | name = "piston" 1242 | version = "0.53.1" 1243 | source = "registry+https://github.com/rust-lang/crates.io-index" 1244 | checksum = "7f483bc0f9316e80f27c9f083fb20e8ae881a9799ad792cf683a059f3f58d6e6" 1245 | dependencies = [ 1246 | "pistoncore-event_loop", 1247 | "pistoncore-input", 1248 | "pistoncore-window", 1249 | ] 1250 | 1251 | [[package]] 1252 | name = "piston-float" 1253 | version = "1.0.0" 1254 | source = "registry+https://github.com/rust-lang/crates.io-index" 1255 | checksum = "f900be47e312e126cc71d35548e8e31edd3901b92ab82d1c4c4757e6b5526564" 1256 | 1257 | [[package]] 1258 | name = "piston-gfx_texture" 1259 | version = "0.35.0" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "c6307afabc7fd1bdaa02c4989d0934d32187f99a0ceb28321dcb869d5c232066" 1262 | dependencies = [ 1263 | "gfx", 1264 | "gfx_core", 1265 | "image", 1266 | "piston-texture", 1267 | ] 1268 | 1269 | [[package]] 1270 | name = "piston-graphics_api_version" 1271 | version = "1.0.1" 1272 | source = "registry+https://github.com/rust-lang/crates.io-index" 1273 | checksum = "3b06401e3ea38467d8d85b394557408107e3e56d827f0d00c9b47e902cbd1bed" 1274 | 1275 | [[package]] 1276 | name = "piston-texture" 1277 | version = "0.6.0" 1278 | source = "registry+https://github.com/rust-lang/crates.io-index" 1279 | checksum = "3649b5f9d1ba48d95207976118e9e2ed473c1de36f6f79cc1b7ed5b75b655b61" 1280 | 1281 | [[package]] 1282 | name = "piston-viewport" 1283 | version = "1.0.2" 1284 | source = "registry+https://github.com/rust-lang/crates.io-index" 1285 | checksum = "61ecaf8ae0d71dd9cdbbd8662b47659621c09430ff3cb880d154858d3b8ac001" 1286 | dependencies = [ 1287 | "piston-float", 1288 | ] 1289 | 1290 | [[package]] 1291 | name = "piston3d-cam" 1292 | version = "0.4.0" 1293 | source = "registry+https://github.com/rust-lang/crates.io-index" 1294 | checksum = "c29bb5a44b7cf1b86c133c3dfa734e81f1cfb1347e4ad7d48b611f28d7b75120" 1295 | dependencies = [ 1296 | "quaternion", 1297 | "vecmath", 1298 | ] 1299 | 1300 | [[package]] 1301 | name = "piston3d-gfx_voxel" 1302 | version = "0.27.0" 1303 | source = "registry+https://github.com/rust-lang/crates.io-index" 1304 | checksum = "dd9a00eba4f9679bf317e102c4ecbd7712c3e21a036d7a7e57bf145754a9a615" 1305 | dependencies = [ 1306 | "array", 1307 | "gfx", 1308 | "image", 1309 | "piston-gfx_texture", 1310 | ] 1311 | 1312 | [[package]] 1313 | name = "pistoncore-event_loop" 1314 | version = "0.53.1" 1315 | source = "registry+https://github.com/rust-lang/crates.io-index" 1316 | checksum = "41d86b3bf012430bb23694348615e37769aca0e9910539ce93674006aeeb77e6" 1317 | dependencies = [ 1318 | "pistoncore-input", 1319 | "pistoncore-window", 1320 | "spin_sleep", 1321 | ] 1322 | 1323 | [[package]] 1324 | name = "pistoncore-glutin_window" 1325 | version = "0.70.1" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | checksum = "a2625037feaa575206054a7a10b397739c6c10e81be0ae65858182d6dd906d30" 1328 | dependencies = [ 1329 | "gl", 1330 | "glutin", 1331 | "pistoncore-input", 1332 | "pistoncore-window", 1333 | "shader_version", 1334 | ] 1335 | 1336 | [[package]] 1337 | name = "pistoncore-input" 1338 | version = "1.0.1" 1339 | source = "registry+https://github.com/rust-lang/crates.io-index" 1340 | checksum = "2977fed6eb16c554fd445a09a50c8a0c250f4c50f752be46a7bd9dcc5ba471f0" 1341 | dependencies = [ 1342 | "bitflags", 1343 | "piston-viewport", 1344 | "serde", 1345 | "serde_derive", 1346 | ] 1347 | 1348 | [[package]] 1349 | name = "pistoncore-window" 1350 | version = "0.47.1" 1351 | source = "registry+https://github.com/rust-lang/crates.io-index" 1352 | checksum = "d62962b4e9cfc13143c77e032302fedc58a8f0f570d30006cdb38ba00a5e50bf" 1353 | dependencies = [ 1354 | "piston-graphics_api_version", 1355 | "pistoncore-input", 1356 | ] 1357 | 1358 | [[package]] 1359 | name = "pkg-config" 1360 | version = "0.3.19" 1361 | source = "registry+https://github.com/rust-lang/crates.io-index" 1362 | checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" 1363 | 1364 | [[package]] 1365 | name = "png" 1366 | version = "0.14.1" 1367 | source = "registry+https://github.com/rust-lang/crates.io-index" 1368 | checksum = "63daf481fdd0defa2d1d2be15c674fbfa1b0fd71882c303a91f9a79b3252c359" 1369 | dependencies = [ 1370 | "bitflags", 1371 | "deflate", 1372 | "inflate", 1373 | "num-iter", 1374 | ] 1375 | 1376 | [[package]] 1377 | name = "proc-macro-crate" 1378 | version = "0.1.5" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" 1381 | dependencies = [ 1382 | "toml", 1383 | ] 1384 | 1385 | [[package]] 1386 | name = "proc-macro2" 1387 | version = "0.4.30" 1388 | source = "registry+https://github.com/rust-lang/crates.io-index" 1389 | checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 1390 | dependencies = [ 1391 | "unicode-xid 0.1.0", 1392 | ] 1393 | 1394 | [[package]] 1395 | name = "proc-macro2" 1396 | version = "1.0.27" 1397 | source = "registry+https://github.com/rust-lang/crates.io-index" 1398 | checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" 1399 | dependencies = [ 1400 | "unicode-xid 0.2.2", 1401 | ] 1402 | 1403 | [[package]] 1404 | name = "quaternion" 1405 | version = "0.4.1" 1406 | source = "registry+https://github.com/rust-lang/crates.io-index" 1407 | checksum = "098443236d1445368525aa1874295cb9d9fc7699b52907c78692f0b18bd8c216" 1408 | dependencies = [ 1409 | "vecmath", 1410 | ] 1411 | 1412 | [[package]] 1413 | name = "quote" 1414 | version = "0.6.13" 1415 | source = "registry+https://github.com/rust-lang/crates.io-index" 1416 | checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 1417 | dependencies = [ 1418 | "proc-macro2 0.4.30", 1419 | ] 1420 | 1421 | [[package]] 1422 | name = "quote" 1423 | version = "1.0.9" 1424 | source = "registry+https://github.com/rust-lang/crates.io-index" 1425 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 1426 | dependencies = [ 1427 | "proc-macro2 1.0.27", 1428 | ] 1429 | 1430 | [[package]] 1431 | name = "raw-window-handle" 1432 | version = "0.3.4" 1433 | source = "registry+https://github.com/rust-lang/crates.io-index" 1434 | checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76" 1435 | dependencies = [ 1436 | "libc", 1437 | "raw-window-handle 0.4.3", 1438 | ] 1439 | 1440 | [[package]] 1441 | name = "raw-window-handle" 1442 | version = "0.4.3" 1443 | source = "registry+https://github.com/rust-lang/crates.io-index" 1444 | checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" 1445 | dependencies = [ 1446 | "cty", 1447 | ] 1448 | 1449 | [[package]] 1450 | name = "rayon" 1451 | version = "1.5.1" 1452 | source = "registry+https://github.com/rust-lang/crates.io-index" 1453 | checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" 1454 | dependencies = [ 1455 | "autocfg", 1456 | "crossbeam-deque", 1457 | "either", 1458 | "rayon-core", 1459 | ] 1460 | 1461 | [[package]] 1462 | name = "rayon-core" 1463 | version = "1.9.1" 1464 | source = "registry+https://github.com/rust-lang/crates.io-index" 1465 | checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" 1466 | dependencies = [ 1467 | "crossbeam-channel", 1468 | "crossbeam-deque", 1469 | "crossbeam-utils", 1470 | "lazy_static 1.4.0", 1471 | "num_cpus", 1472 | ] 1473 | 1474 | [[package]] 1475 | name = "redox_syscall" 1476 | version = "0.2.16" 1477 | source = "registry+https://github.com/rust-lang/crates.io-index" 1478 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" 1479 | dependencies = [ 1480 | "bitflags", 1481 | ] 1482 | 1483 | [[package]] 1484 | name = "regex" 1485 | version = "0.2.11" 1486 | source = "registry+https://github.com/rust-lang/crates.io-index" 1487 | checksum = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" 1488 | dependencies = [ 1489 | "aho-corasick", 1490 | "memchr", 1491 | "regex-syntax", 1492 | "thread_local", 1493 | "utf8-ranges", 1494 | ] 1495 | 1496 | [[package]] 1497 | name = "regex-syntax" 1498 | version = "0.5.6" 1499 | source = "registry+https://github.com/rust-lang/crates.io-index" 1500 | checksum = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" 1501 | dependencies = [ 1502 | "ucd-util", 1503 | ] 1504 | 1505 | [[package]] 1506 | name = "rustc-serialize" 1507 | version = "0.3.24" 1508 | source = "registry+https://github.com/rust-lang/crates.io-index" 1509 | checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" 1510 | 1511 | [[package]] 1512 | name = "rusttype" 1513 | version = "0.9.3" 1514 | source = "registry+https://github.com/rust-lang/crates.io-index" 1515 | checksum = "3ff8374aa04134254b7995b63ad3dc41c7f7236f69528b28553da7d72efaa967" 1516 | dependencies = [ 1517 | "ab_glyph_rasterizer", 1518 | "owned_ttf_parser", 1519 | ] 1520 | 1521 | [[package]] 1522 | name = "same-file" 1523 | version = "1.0.6" 1524 | source = "registry+https://github.com/rust-lang/crates.io-index" 1525 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1526 | dependencies = [ 1527 | "winapi-util", 1528 | ] 1529 | 1530 | [[package]] 1531 | name = "scoped-tls" 1532 | version = "1.0.1" 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" 1534 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 1535 | 1536 | [[package]] 1537 | name = "scoped_threadpool" 1538 | version = "0.1.9" 1539 | source = "registry+https://github.com/rust-lang/crates.io-index" 1540 | checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" 1541 | 1542 | [[package]] 1543 | name = "scopeguard" 1544 | version = "1.1.0" 1545 | source = "registry+https://github.com/rust-lang/crates.io-index" 1546 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1547 | 1548 | [[package]] 1549 | name = "serde" 1550 | version = "1.0.126" 1551 | source = "registry+https://github.com/rust-lang/crates.io-index" 1552 | checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" 1553 | 1554 | [[package]] 1555 | name = "serde_derive" 1556 | version = "1.0.126" 1557 | source = "registry+https://github.com/rust-lang/crates.io-index" 1558 | checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" 1559 | dependencies = [ 1560 | "proc-macro2 1.0.27", 1561 | "quote 1.0.9", 1562 | "syn 1.0.73", 1563 | ] 1564 | 1565 | [[package]] 1566 | name = "shader_version" 1567 | version = "0.7.0" 1568 | source = "registry+https://github.com/rust-lang/crates.io-index" 1569 | checksum = "dfadbf7574784ee97f062ace17e1008fb5e7f46dd714b7dd46baf6efebd30e26" 1570 | dependencies = [ 1571 | "piston-graphics_api_version", 1572 | ] 1573 | 1574 | [[package]] 1575 | name = "shared_library" 1576 | version = "0.1.9" 1577 | source = "registry+https://github.com/rust-lang/crates.io-index" 1578 | checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" 1579 | dependencies = [ 1580 | "lazy_static 1.4.0", 1581 | "libc", 1582 | ] 1583 | 1584 | [[package]] 1585 | name = "slab" 1586 | version = "0.4.7" 1587 | source = "registry+https://github.com/rust-lang/crates.io-index" 1588 | checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" 1589 | dependencies = [ 1590 | "autocfg", 1591 | ] 1592 | 1593 | [[package]] 1594 | name = "smallvec" 1595 | version = "1.10.0" 1596 | source = "registry+https://github.com/rust-lang/crates.io-index" 1597 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" 1598 | 1599 | [[package]] 1600 | name = "smithay-client-toolkit" 1601 | version = "0.12.3" 1602 | source = "registry+https://github.com/rust-lang/crates.io-index" 1603 | checksum = "4750c76fd5d3ac95fa3ed80fe667d6a3d8590a960e5b575b98eea93339a80b80" 1604 | dependencies = [ 1605 | "andrew", 1606 | "bitflags", 1607 | "calloop", 1608 | "dlib 0.4.2", 1609 | "lazy_static 1.4.0", 1610 | "log", 1611 | "memmap2", 1612 | "nix 0.18.0", 1613 | "wayland-client", 1614 | "wayland-cursor", 1615 | "wayland-protocols", 1616 | ] 1617 | 1618 | [[package]] 1619 | name = "spin_sleep" 1620 | version = "1.1.1" 1621 | source = "registry+https://github.com/rust-lang/crates.io-index" 1622 | checksum = "cafa7900db085f4354dbc7025e25d7a839a14360ea13b5fc4fd717f2d3b23134" 1623 | dependencies = [ 1624 | "once_cell", 1625 | "winapi 0.3.9", 1626 | ] 1627 | 1628 | [[package]] 1629 | name = "strsim" 1630 | version = "0.6.0" 1631 | source = "registry+https://github.com/rust-lang/crates.io-index" 1632 | checksum = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" 1633 | 1634 | [[package]] 1635 | name = "strsim" 1636 | version = "0.9.3" 1637 | source = "registry+https://github.com/rust-lang/crates.io-index" 1638 | checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" 1639 | 1640 | [[package]] 1641 | name = "syn" 1642 | version = "0.15.44" 1643 | source = "registry+https://github.com/rust-lang/crates.io-index" 1644 | checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" 1645 | dependencies = [ 1646 | "proc-macro2 0.4.30", 1647 | "quote 0.6.13", 1648 | "unicode-xid 0.1.0", 1649 | ] 1650 | 1651 | [[package]] 1652 | name = "syn" 1653 | version = "1.0.73" 1654 | source = "registry+https://github.com/rust-lang/crates.io-index" 1655 | checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" 1656 | dependencies = [ 1657 | "proc-macro2 1.0.27", 1658 | "quote 1.0.9", 1659 | "unicode-xid 0.2.2", 1660 | ] 1661 | 1662 | [[package]] 1663 | name = "thiserror" 1664 | version = "1.0.26" 1665 | source = "registry+https://github.com/rust-lang/crates.io-index" 1666 | checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" 1667 | dependencies = [ 1668 | "thiserror-impl", 1669 | ] 1670 | 1671 | [[package]] 1672 | name = "thiserror-impl" 1673 | version = "1.0.26" 1674 | source = "registry+https://github.com/rust-lang/crates.io-index" 1675 | checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" 1676 | dependencies = [ 1677 | "proc-macro2 1.0.27", 1678 | "quote 1.0.9", 1679 | "syn 1.0.73", 1680 | ] 1681 | 1682 | [[package]] 1683 | name = "thread_local" 1684 | version = "0.3.6" 1685 | source = "registry+https://github.com/rust-lang/crates.io-index" 1686 | checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" 1687 | dependencies = [ 1688 | "lazy_static 1.4.0", 1689 | ] 1690 | 1691 | [[package]] 1692 | name = "tiff" 1693 | version = "0.2.2" 1694 | source = "registry+https://github.com/rust-lang/crates.io-index" 1695 | checksum = "1e4834f28a0330cb9f3f2c87d2649dca723cb33802e2bdcf18da32759fbec7ce" 1696 | dependencies = [ 1697 | "byteorder", 1698 | "lzw", 1699 | "num-derive", 1700 | "num-traits", 1701 | ] 1702 | 1703 | [[package]] 1704 | name = "time" 1705 | version = "0.1.44" 1706 | source = "registry+https://github.com/rust-lang/crates.io-index" 1707 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 1708 | dependencies = [ 1709 | "libc", 1710 | "wasi", 1711 | "winapi 0.3.9", 1712 | ] 1713 | 1714 | [[package]] 1715 | name = "toml" 1716 | version = "0.5.9" 1717 | source = "registry+https://github.com/rust-lang/crates.io-index" 1718 | checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" 1719 | dependencies = [ 1720 | "serde", 1721 | ] 1722 | 1723 | [[package]] 1724 | name = "ttf-parser" 1725 | version = "0.15.2" 1726 | source = "registry+https://github.com/rust-lang/crates.io-index" 1727 | checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" 1728 | 1729 | [[package]] 1730 | name = "ucd-util" 1731 | version = "0.1.8" 1732 | source = "registry+https://github.com/rust-lang/crates.io-index" 1733 | checksum = "c85f514e095d348c279b1e5cd76795082cf15bd59b93207832abe0b1d8fed236" 1734 | 1735 | [[package]] 1736 | name = "unicode-xid" 1737 | version = "0.1.0" 1738 | source = "registry+https://github.com/rust-lang/crates.io-index" 1739 | checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 1740 | 1741 | [[package]] 1742 | name = "unicode-xid" 1743 | version = "0.2.2" 1744 | source = "registry+https://github.com/rust-lang/crates.io-index" 1745 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 1746 | 1747 | [[package]] 1748 | name = "utf8-ranges" 1749 | version = "1.0.4" 1750 | source = "registry+https://github.com/rust-lang/crates.io-index" 1751 | checksum = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba" 1752 | 1753 | [[package]] 1754 | name = "vecmath" 1755 | version = "1.0.0" 1756 | source = "registry+https://github.com/rust-lang/crates.io-index" 1757 | checksum = "956ae1e0d85bca567dee1dcf87fb1ca2e792792f66f87dced8381f99cd91156a" 1758 | dependencies = [ 1759 | "piston-float", 1760 | ] 1761 | 1762 | [[package]] 1763 | name = "walkdir" 1764 | version = "2.3.2" 1765 | source = "registry+https://github.com/rust-lang/crates.io-index" 1766 | checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" 1767 | dependencies = [ 1768 | "same-file", 1769 | "winapi 0.3.9", 1770 | "winapi-util", 1771 | ] 1772 | 1773 | [[package]] 1774 | name = "wasi" 1775 | version = "0.10.0+wasi-snapshot-preview1" 1776 | source = "registry+https://github.com/rust-lang/crates.io-index" 1777 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 1778 | 1779 | [[package]] 1780 | name = "wayland-client" 1781 | version = "0.28.6" 1782 | source = "registry+https://github.com/rust-lang/crates.io-index" 1783 | checksum = "e3ab332350e502f159382201394a78e3cc12d0f04db863429260164ea40e0355" 1784 | dependencies = [ 1785 | "bitflags", 1786 | "downcast-rs", 1787 | "libc", 1788 | "nix 0.20.2", 1789 | "scoped-tls", 1790 | "wayland-commons", 1791 | "wayland-scanner", 1792 | "wayland-sys", 1793 | ] 1794 | 1795 | [[package]] 1796 | name = "wayland-commons" 1797 | version = "0.28.6" 1798 | source = "registry+https://github.com/rust-lang/crates.io-index" 1799 | checksum = "a21817947c7011bbd0a27e11b17b337bfd022e8544b071a2641232047966fbda" 1800 | dependencies = [ 1801 | "nix 0.20.2", 1802 | "once_cell", 1803 | "smallvec", 1804 | "wayland-sys", 1805 | ] 1806 | 1807 | [[package]] 1808 | name = "wayland-cursor" 1809 | version = "0.28.6" 1810 | source = "registry+https://github.com/rust-lang/crates.io-index" 1811 | checksum = "be610084edd1586d45e7bdd275fe345c7c1873598caa464c4fb835dee70fa65a" 1812 | dependencies = [ 1813 | "nix 0.20.2", 1814 | "wayland-client", 1815 | "xcursor", 1816 | ] 1817 | 1818 | [[package]] 1819 | name = "wayland-egl" 1820 | version = "0.28.6" 1821 | source = "registry+https://github.com/rust-lang/crates.io-index" 1822 | checksum = "99ba1ab1e18756b23982d36f08856d521d7df45015f404a2d7c4f0b2d2f66956" 1823 | dependencies = [ 1824 | "wayland-client", 1825 | "wayland-sys", 1826 | ] 1827 | 1828 | [[package]] 1829 | name = "wayland-protocols" 1830 | version = "0.28.6" 1831 | source = "registry+https://github.com/rust-lang/crates.io-index" 1832 | checksum = "286620ea4d803bacf61fa087a4242ee316693099ee5a140796aaba02b29f861f" 1833 | dependencies = [ 1834 | "bitflags", 1835 | "wayland-client", 1836 | "wayland-commons", 1837 | "wayland-scanner", 1838 | ] 1839 | 1840 | [[package]] 1841 | name = "wayland-scanner" 1842 | version = "0.28.6" 1843 | source = "registry+https://github.com/rust-lang/crates.io-index" 1844 | checksum = "ce923eb2deb61de332d1f356ec7b6bf37094dc5573952e1c8936db03b54c03f1" 1845 | dependencies = [ 1846 | "proc-macro2 1.0.27", 1847 | "quote 1.0.9", 1848 | "xml-rs 0.8.3", 1849 | ] 1850 | 1851 | [[package]] 1852 | name = "wayland-sys" 1853 | version = "0.28.6" 1854 | source = "registry+https://github.com/rust-lang/crates.io-index" 1855 | checksum = "d841fca9aed7febf9bed2e9796c49bf58d4152ceda8ac949ebe00868d8f0feb8" 1856 | dependencies = [ 1857 | "dlib 0.5.0", 1858 | "lazy_static 1.4.0", 1859 | "pkg-config", 1860 | ] 1861 | 1862 | [[package]] 1863 | name = "winapi" 1864 | version = "0.2.8" 1865 | source = "registry+https://github.com/rust-lang/crates.io-index" 1866 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 1867 | 1868 | [[package]] 1869 | name = "winapi" 1870 | version = "0.3.9" 1871 | source = "registry+https://github.com/rust-lang/crates.io-index" 1872 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1873 | dependencies = [ 1874 | "winapi-i686-pc-windows-gnu", 1875 | "winapi-x86_64-pc-windows-gnu", 1876 | ] 1877 | 1878 | [[package]] 1879 | name = "winapi-build" 1880 | version = "0.1.1" 1881 | source = "registry+https://github.com/rust-lang/crates.io-index" 1882 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 1883 | 1884 | [[package]] 1885 | name = "winapi-i686-pc-windows-gnu" 1886 | version = "0.4.0" 1887 | source = "registry+https://github.com/rust-lang/crates.io-index" 1888 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1889 | 1890 | [[package]] 1891 | name = "winapi-util" 1892 | version = "0.1.5" 1893 | source = "registry+https://github.com/rust-lang/crates.io-index" 1894 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1895 | dependencies = [ 1896 | "winapi 0.3.9", 1897 | ] 1898 | 1899 | [[package]] 1900 | name = "winapi-x86_64-pc-windows-gnu" 1901 | version = "0.4.0" 1902 | source = "registry+https://github.com/rust-lang/crates.io-index" 1903 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1904 | 1905 | [[package]] 1906 | name = "winit" 1907 | version = "0.24.0" 1908 | source = "registry+https://github.com/rust-lang/crates.io-index" 1909 | checksum = "da4eda6fce0eb84bd0a33e3c8794eb902e1033d0a1d5a31bc4f19b1b4bbff597" 1910 | dependencies = [ 1911 | "bitflags", 1912 | "cocoa 0.24.1", 1913 | "core-foundation 0.9.3", 1914 | "core-graphics 0.22.3", 1915 | "core-video-sys", 1916 | "dispatch", 1917 | "instant", 1918 | "lazy_static 1.4.0", 1919 | "libc", 1920 | "log", 1921 | "mio", 1922 | "mio-extras", 1923 | "ndk", 1924 | "ndk-glue", 1925 | "ndk-sys", 1926 | "objc", 1927 | "parking_lot", 1928 | "percent-encoding", 1929 | "raw-window-handle 0.3.4", 1930 | "smithay-client-toolkit", 1931 | "wayland-client", 1932 | "winapi 0.3.9", 1933 | "x11-dl", 1934 | ] 1935 | 1936 | [[package]] 1937 | name = "ws2_32-sys" 1938 | version = "0.2.1" 1939 | source = "registry+https://github.com/rust-lang/crates.io-index" 1940 | checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 1941 | dependencies = [ 1942 | "winapi 0.2.8", 1943 | "winapi-build", 1944 | ] 1945 | 1946 | [[package]] 1947 | name = "x11-dl" 1948 | version = "2.18.5" 1949 | source = "registry+https://github.com/rust-lang/crates.io-index" 1950 | checksum = "2bf981e3a5b3301209754218f962052d4d9ee97e478f4d26d4a6eced34c1fef8" 1951 | dependencies = [ 1952 | "lazy_static 1.4.0", 1953 | "libc", 1954 | "maybe-uninit", 1955 | "pkg-config", 1956 | ] 1957 | 1958 | [[package]] 1959 | name = "xcursor" 1960 | version = "0.3.4" 1961 | source = "registry+https://github.com/rust-lang/crates.io-index" 1962 | checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" 1963 | dependencies = [ 1964 | "nom", 1965 | ] 1966 | 1967 | [[package]] 1968 | name = "xdg" 1969 | version = "2.2.0" 1970 | source = "registry+https://github.com/rust-lang/crates.io-index" 1971 | checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" 1972 | 1973 | [[package]] 1974 | name = "xml-rs" 1975 | version = "0.7.0" 1976 | source = "registry+https://github.com/rust-lang/crates.io-index" 1977 | checksum = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" 1978 | dependencies = [ 1979 | "bitflags", 1980 | ] 1981 | 1982 | [[package]] 1983 | name = "xml-rs" 1984 | version = "0.8.3" 1985 | source = "registry+https://github.com/rust-lang/crates.io-index" 1986 | checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" 1987 | 1988 | [[package]] 1989 | name = "zip" 1990 | version = "0.5.13" 1991 | source = "registry+https://github.com/rust-lang/crates.io-index" 1992 | checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" 1993 | dependencies = [ 1994 | "byteorder", 1995 | "bzip2", 1996 | "crc32fast", 1997 | "flate2", 1998 | "thiserror", 1999 | "time", 2000 | ] 2001 | -------------------------------------------------------------------------------- /Cargo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PistonDevelopers/hematite/1fc08c93ad10f948a9b74cdfca0915ce009addb7/Cargo.png -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "hematite" 4 | version = "0.0.34" 5 | edition = "2018" 6 | license = "MIT" 7 | authors = ["bvssvni "] 8 | keywords = ["minecraft", "piston", "client"] 9 | description = "A simple Minecraft client" 10 | repository = "https://github.com/PistonDevelopers/hematite.git" 11 | homepage = "http://hematite.piston.rs" 12 | exclude = ["home/*"] 13 | 14 | [profile.release] 15 | opt-level = 2 16 | debug = false 17 | 18 | [[bin]] 19 | 20 | name = "hematite" 21 | path = "src/main.rs" 22 | 23 | [dependencies] 24 | byteorder = "1.4.3" 25 | camera_controllers = "0.32" 26 | docopt = "0.7.0" 27 | flate2 = "1.0.20" 28 | fps_counter = "2.0.0" 29 | gfx = "0.17.1" 30 | gfx_core = "0.8.3" 31 | gfx_device_gl = "0.15.5" 32 | libc = "0.2.97" 33 | memmap = "0.5.2" 34 | piston = "0.53" 35 | piston3d-gfx_voxel = "0.27" 36 | pistoncore-glutin_window = "0.70" 37 | rustc-serialize = "0.3.24" 38 | shader_version = "0.7" 39 | vecmath = "1.0.0" 40 | zip = "0.5.13" 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 PistonDevelopers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hematite [![Build Status](https://travis-ci.org/PistonDevelopers/hematite.svg?branch=master)](https://travis-ci.org/PistonDevelopers/hematite) 2 | 3 | A simple Minecraft written in Rust with the Piston game engine 4 | 5 | ![screenshot](./screenshot.png) 6 | 7 | ## How To Open a World 8 | 9 | *This method is only for personal use. Never distribute copyrighted content from Minecraft.* 10 | 11 | * In the Minecraft Launcher, click the button “New Profile” 12 | * In the drop down "use version", select `1.8.8` 13 | * Click “Save Profile” 14 | * Click “Play” (this will download the snapshot) 15 | * Quit Minecraft 16 | 17 | * **Copy** your world save to to the hematite directory (It may corrupt your world) 18 | * Save Locations: 19 | * **Windows:** `%appdata%\.minecraft\saves\` 20 | * **OSX:** `~/Library/Application Support/minecraft/saves/` 21 | * **Linux/Other:** `~/.minecraft/saves/` 22 | * Run hematite with: `cargo run --release -- -p "./"` 23 | 24 | ## Dependencies 25 | 26 | ![dependencies](./Cargo.png) 27 | 28 | [How to contribute](https://github.com/PistonDevelopers/piston/blob/master/CONTRIBUTING.md) 29 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | single-char-binding-names-threshold = 7 2 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2018" 2 | use_try_shorthand = true 3 | use_field_init_shorthand = true 4 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PistonDevelopers/hematite/1fc08c93ad10f948a9b74cdfca0915ce009addb7/screenshot.png -------------------------------------------------------------------------------- /src/chunk.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::collections::HashMap; 3 | 4 | use crate::array::*; 5 | use crate::shader::Vertex; 6 | use gfx; 7 | 8 | #[derive(Copy, Clone)] 9 | pub struct BlockState { 10 | pub value: u16, 11 | } 12 | 13 | pub const EMPTY_BLOCK: BlockState = BlockState { value: 0 }; 14 | 15 | #[derive(Copy, Clone)] 16 | pub struct BiomeId { 17 | pub value: u8, 18 | } 19 | 20 | #[derive(Copy, Clone)] 21 | pub struct LightLevel { 22 | pub value: u8, 23 | } 24 | 25 | impl LightLevel { 26 | pub fn block_light(self) -> u8 { 27 | self.value & 0xf 28 | } 29 | pub fn sky_light(self) -> u8 { 30 | self.value >> 4 31 | } 32 | } 33 | 34 | pub const SIZE: usize = 16; 35 | 36 | /// A chunk of SIZE x SIZE x SIZE blocks, in YZX order. 37 | #[derive(Copy, Clone)] 38 | pub struct Chunk { 39 | pub blocks: [[[BlockState; SIZE]; SIZE]; SIZE], 40 | pub light_levels: [[[LightLevel; SIZE]; SIZE]; SIZE], 41 | } 42 | 43 | // TODO: Change to const pointer. 44 | pub const EMPTY_CHUNK: &Chunk = &Chunk { 45 | blocks: [[[EMPTY_BLOCK; SIZE]; SIZE]; SIZE], 46 | light_levels: [[[LightLevel { value: 0xf0 }; SIZE]; SIZE]; SIZE], 47 | }; 48 | 49 | pub struct ChunkColumn { 50 | pub chunks: Vec, 51 | pub buffers: [RefCell>>; SIZE], 52 | pub biomes: [[BiomeId; SIZE]; SIZE], 53 | } 54 | 55 | pub struct ChunkManager { 56 | chunk_columns: HashMap<(i32, i32), ChunkColumn>, 57 | } 58 | 59 | impl ChunkManager { 60 | pub fn new() -> ChunkManager { 61 | ChunkManager { 62 | chunk_columns: HashMap::new(), 63 | } 64 | } 65 | 66 | pub fn add_chunk_column(&mut self, x: i32, z: i32, c: ChunkColumn) { 67 | self.chunk_columns.insert((x, z), c); 68 | } 69 | 70 | pub fn each_chunk_and_neighbors<'a, F>(&'a self, mut f: F) 71 | where 72 | F: FnMut( 73 | /*coords:*/ [i32; 3], 74 | /*buffer:*/ &'a RefCell>>, 75 | /*chunks:*/ [[[&'a Chunk; 3]; 3]; 3], 76 | /*biomes:*/ [[Option<&'a [[BiomeId; SIZE]; SIZE]>; 3]; 3], 77 | ), 78 | { 79 | for &(x, z) in self.chunk_columns.keys() { 80 | let columns = 81 | [-1, 0, 1].map(|dz| [-1, 0, 1].map(|dx| self.chunk_columns.get(&(x + dx, z + dz)))); 82 | let central = columns[1][1].unwrap(); 83 | for y in 0..central.chunks.len() { 84 | let chunks = [-1, 0, 1].map(|dy| { 85 | let y = y as i32 + dy; 86 | columns.map(|cz| { 87 | cz.map(|cx| { 88 | cx.and_then(|c| c.chunks[..].get(y as usize)) 89 | .unwrap_or(EMPTY_CHUNK) 90 | }) 91 | }) 92 | }); 93 | f( 94 | [x, y as i32, z], 95 | ¢ral.buffers[y], 96 | chunks, 97 | columns.map(|cz| cz.map(|cx| cx.map(|c| &c.biomes))), 98 | ) 99 | } 100 | } 101 | } 102 | 103 | pub fn each_chunk(&self, mut f: F) 104 | where 105 | F: FnMut( 106 | /*x:*/ i32, 107 | /*y:*/ i32, 108 | /*z:*/ i32, 109 | /*c:*/ &Chunk, 110 | /*b:*/ &RefCell>>, 111 | ), 112 | { 113 | for (&(x, z), c) in self.chunk_columns.iter() { 114 | for (y, (c, b)) in c.chunks.iter().zip(c.buffers.iter()).enumerate() { 115 | f(x, y as i32, z, c, b) 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_compatibility, rust_2018_idioms)] 2 | 3 | #[macro_use] 4 | extern crate gfx; 5 | 6 | // Reexport modules from gfx_voxel while stuff is moving 7 | // from Hematite to the library. 8 | pub use gfx_voxel::{array, cube}; 9 | 10 | use std::cmp::max; 11 | use std::f32::consts::PI; 12 | use std::fs::File; 13 | use std::path::{Path, PathBuf}; 14 | use std::time::Instant; 15 | 16 | use crate::array::*; 17 | use crate::shader::Renderer; 18 | use docopt::Docopt; 19 | use flate2::read::GzDecoder; 20 | use gfx::traits::Device; 21 | use glutin_window::*; 22 | use piston::event_loop::{EventLoop, EventSettings, Events}; 23 | use piston::input::{AfterRenderEvent, MouseRelativeEvent, PressEvent, RenderEvent, UpdateEvent}; 24 | use piston::window::{AdvancedWindow, OpenGLWindow, Size, Window, WindowSettings}; 25 | use vecmath::{vec3_add, vec3_normalized, vec3_scale}; 26 | 27 | pub mod chunk; 28 | pub mod minecraft; 29 | pub mod shader; 30 | 31 | use crate::minecraft::biome::Biomes; 32 | use crate::minecraft::block_state::BlockStates; 33 | 34 | static USAGE: &str = " 35 | hematite, Minecraft made in Rust! 36 | 37 | Usage: 38 | hematite [options] 39 | 40 | Options: 41 | -p, --path Fully qualified path for world folder. 42 | --mcversion= Minecraft version [default: 1.8.8]. 43 | "; 44 | 45 | #[derive(RustcDecodable)] 46 | struct Args { 47 | arg_world: String, 48 | flag_path: bool, 49 | flag_mcversion: String, 50 | } 51 | 52 | fn create_main_targets( 53 | dim: gfx::texture::Dimensions, 54 | ) -> ( 55 | gfx::handle::RenderTargetView, 56 | gfx::handle::DepthStencilView, 57 | ) { 58 | use gfx::format::{DepthStencil, Format, Formatted, Srgba8}; 59 | use gfx_core::memory::Typed; 60 | 61 | let color_format: Format = ::get_format(); 62 | let depth_format: Format = ::get_format(); 63 | let (output_color, output_stencil) = 64 | gfx_device_gl::create_main_targets_raw(dim, color_format.0, depth_format.0); 65 | let output_color = Typed::new(output_color); 66 | let output_stencil = Typed::new(output_stencil); 67 | (output_color, output_stencil) 68 | } 69 | 70 | fn main() { 71 | let args: Args = Docopt::new(USAGE) 72 | .and_then(|dopt| dopt.decode()) 73 | .unwrap_or_else(|e| e.exit()); 74 | 75 | // Automagically pull MC assets 76 | minecraft::fetch_assets(&args.flag_mcversion); 77 | 78 | // Automagically expand path if world is located at 79 | // $MINECRAFT_ROOT/saves/ 80 | let world = if args.flag_path { 81 | PathBuf::from(&args.arg_world) 82 | } else { 83 | let mut mc_path = minecraft::vanilla_root_path(); 84 | mc_path.push("saves"); 85 | mc_path.push(args.arg_world); 86 | mc_path 87 | }; 88 | 89 | let file_name = world.join("level.dat"); 90 | let level_reader = GzDecoder::new(File::open(file_name).unwrap()); 91 | let level = minecraft::nbt::Nbt::from_reader(level_reader).unwrap(); 92 | println!("{:?}", level); 93 | let player_pos: [f32; 3] = Array::from_iter( 94 | level["Data"]["Player"]["Pos"] 95 | .as_double_list() 96 | .unwrap() 97 | .iter() 98 | .map(|&x| x as f32), 99 | ); 100 | let player_chunk = [player_pos.x(), player_pos.z()].map(|x| (x / 16.0).floor() as i32); 101 | let player_rot = level["Data"]["Player"]["Rotation"].as_float_list().unwrap(); 102 | let player_yaw = player_rot[0]; 103 | let player_pitch = player_rot[1]; 104 | 105 | let regions = player_chunk.map(|x| x >> 5); 106 | let region_file = world.join(format!("region/r.{}.{}.mca", regions[0], regions[1])); 107 | let region = minecraft::region::Region::open(®ion_file).unwrap(); 108 | 109 | let loading_title = format!( 110 | "Hematite loading... - {}", 111 | world.file_name().unwrap().to_str().unwrap() 112 | ); 113 | 114 | let mut window: GlutinWindow = WindowSettings::new(loading_title, [854, 480]) 115 | .fullscreen(false) 116 | .exit_on_esc(true) 117 | .samples(0) 118 | .vsync(false) 119 | .graphics_api(shader_version::opengl::OpenGL::V3_2) 120 | .build() 121 | .unwrap(); 122 | 123 | let (mut device, mut factory) = 124 | gfx_device_gl::create(|s| window.get_proc_address(s) as *const _); 125 | 126 | let Size { 127 | width: w, 128 | height: h, 129 | } = window.size(); 130 | 131 | let (target_view, depth_view) = create_main_targets((w as u16, h as u16, 1, (0_u8).into())); 132 | 133 | let assets = Path::new("./assets"); 134 | 135 | // Load biomes. 136 | let biomes = Biomes::load(assets); 137 | 138 | // Load block state definitions and models. 139 | let block_states = BlockStates::load(assets, &mut factory); 140 | 141 | let encoder = factory.create_command_buffer().into(); 142 | let mut renderer = Renderer::new( 143 | factory, 144 | encoder, 145 | target_view, 146 | depth_view, 147 | block_states.texture.surface.clone(), 148 | ); 149 | 150 | let mut chunk_manager = chunk::ChunkManager::new(); 151 | 152 | println!("Started loading chunks..."); 153 | let c_bases = player_chunk.map(|x| max(0, (x & 0x1f) - 8) as u8); 154 | for cz in c_bases[1]..c_bases[1] + 16 { 155 | for cx in c_bases[0]..c_bases[0] + 16 { 156 | if let Some(column) = region.get_chunk_column(cx, cz) { 157 | let (cx, cz) = (cx as i32 + regions[0] * 32, cz as i32 + regions[1] * 32); 158 | chunk_manager.add_chunk_column(cx, cz, column) 159 | } 160 | } 161 | } 162 | println!("Finished loading chunks."); 163 | 164 | let projection_mat = camera_controllers::CameraPerspective { 165 | fov: 70.0, 166 | near_clip: 0.1, 167 | far_clip: 1000.0, 168 | aspect_ratio: { 169 | let Size { 170 | width: w, 171 | height: h, 172 | } = window.size(); 173 | (w as f32) / (h as f32) 174 | }, 175 | } 176 | .projection(); 177 | renderer.set_projection(projection_mat); 178 | 179 | let mut first_person_settings = camera_controllers::FirstPersonSettings::keyboard_wasd(); 180 | first_person_settings.mouse_sensitivity_horizontal = 0.5; 181 | first_person_settings.mouse_sensitivity_vertical = 0.5; 182 | first_person_settings.speed_horizontal = 8.0; 183 | first_person_settings.speed_vertical = 4.0; 184 | let mut first_person = camera_controllers::FirstPerson::new(player_pos, first_person_settings); 185 | first_person.yaw = PI - player_yaw / 180.0 * PI; 186 | first_person.pitch = player_pitch / 180.0 * PI; 187 | 188 | let mut fps_counter = fps_counter::FPSCounter::new(); 189 | 190 | let mut pending_chunks = vec![]; 191 | chunk_manager.each_chunk_and_neighbors(|coords, buffer, chunks, column_biomes| { 192 | pending_chunks.push((coords, buffer, chunks, column_biomes)); 193 | }); 194 | 195 | let mut capture_cursor = false; 196 | println!("Press C to capture mouse"); 197 | 198 | let mut staging_buffer = vec![]; 199 | let mut events = Events::new(EventSettings::new().ups(120).max_fps(10_000)); 200 | while let Some(e) = events.next(&mut window) { 201 | use piston::input::Button::Keyboard; 202 | use piston::input::Key; 203 | 204 | if e.render_args().is_some() { 205 | // Apply the same y/z camera offset vanilla minecraft has. 206 | let mut camera = first_person.camera(0.0); 207 | camera.position[1] += 1.62; 208 | let mut xz_forward = camera.forward; 209 | xz_forward[1] = 0.0; 210 | xz_forward = vec3_normalized(xz_forward); 211 | camera.position = vec3_add(camera.position, vec3_scale(xz_forward, 0.1)); 212 | 213 | let view_mat = camera.orthogonal(); 214 | renderer.set_view(view_mat); 215 | renderer.clear(); 216 | let mut num_chunks: usize = 0; 217 | let mut num_sorted_chunks: usize = 0; 218 | let mut num_total_chunks: usize = 0; 219 | let start_time = Instant::now(); 220 | chunk_manager.each_chunk(|cx, cy, cz, _, buffer| { 221 | if let Some(buffer) = buffer.borrow_mut().as_mut() { 222 | num_total_chunks += 1; 223 | 224 | let inf = f32::INFINITY; 225 | let mut bb_min = [inf, inf, inf]; 226 | let mut bb_max = [-inf, -inf, -inf]; 227 | let xyz = [cx, cy, cz].map(|x| x as f32 * 16.0); 228 | for &dx in [0.0, 16.0].iter() { 229 | for &dy in [0.0, 16.0].iter() { 230 | for &dz in [0.0, 16.0].iter() { 231 | use vecmath::col_mat4_transform; 232 | 233 | let v = vec3_add(xyz, [dx, dy, dz]); 234 | let xyzw = col_mat4_transform(view_mat, [v[0], v[1], v[2], 1.0]); 235 | let v = col_mat4_transform(projection_mat, xyzw); 236 | let xyz = vec3_scale([v[0], v[1], v[2]], 1.0 / v[3]); 237 | bb_min = Array::from_fn(|i| bb_min[i].min(xyz[i])); 238 | bb_max = Array::from_fn(|i| bb_max[i].max(xyz[i])); 239 | } 240 | } 241 | } 242 | 243 | let cull_bits: [bool; 3] = Array::from_fn(|i| { 244 | let (min, max) = (bb_min[i], bb_max[i]); 245 | min.signum() == max.signum() && min.abs().min(max.abs()) >= 1.0 246 | }); 247 | 248 | if !cull_bits.iter().any(|&cull| cull) { 249 | renderer.render(buffer); 250 | num_chunks += 1; 251 | 252 | if bb_min[0] < 0.0 && bb_max[0] > 0.0 || bb_min[1] < 0.0 && bb_max[1] > 0.0 253 | { 254 | num_sorted_chunks += 1; 255 | } 256 | } 257 | } 258 | }); 259 | let end_duration = start_time.elapsed(); 260 | renderer.flush(&mut device); 261 | let frame_end_duration = start_time.elapsed(); 262 | 263 | let fps = fps_counter.tick(); 264 | let title = format!( 265 | "Hematite sort={} render={} total={} in {:.2}ms+{:.2}ms @ {}FPS - {}", 266 | num_sorted_chunks, 267 | num_chunks, 268 | num_total_chunks, 269 | end_duration.as_secs() as f64 270 | + end_duration.subsec_nanos() as f64 / 1_000_000_000.0, 271 | frame_end_duration.as_secs() as f64 272 | + frame_end_duration.subsec_nanos() as f64 / 1_000_000_000.0, 273 | fps, 274 | world.file_name().unwrap().to_str().unwrap() 275 | ); 276 | window.set_title(title); 277 | } 278 | 279 | if e.after_render_args().is_some() { 280 | device.cleanup(); 281 | } 282 | 283 | if e.update_args().is_some() { 284 | use std::i32; 285 | // HACK(eddyb) find the closest chunk to the player. 286 | // The pending vector should be sorted instead. 287 | let pp = first_person.position.map(|x| (x / 16.0).floor() as i32); 288 | let closest = pending_chunks 289 | .iter() 290 | .enumerate() 291 | .fold( 292 | (None, i32::max_value()), 293 | |(best_i, best_dist), (i, &(cc, _, _, _))| { 294 | let xyz = [cc[0] - pp[0], cc[1] - pp[1], cc[2] - pp[2]].map(|x| x * x); 295 | let dist = xyz[0] + xyz[1] + xyz[2]; 296 | if dist < best_dist { 297 | (Some(i), dist) 298 | } else { 299 | (best_i, best_dist) 300 | } 301 | }, 302 | ) 303 | .0; 304 | let pending = closest.and_then(|i| { 305 | // Vec swap_remove doesn't return Option anymore 306 | match pending_chunks.len() { 307 | 0 => None, 308 | _ => Some(pending_chunks.swap_remove(i)), 309 | } 310 | }); 311 | if let Some((coords, buffer, chunks, column_biomes)) = pending { 312 | minecraft::block_state::fill_buffer( 313 | &block_states, 314 | &biomes, 315 | &mut staging_buffer, 316 | coords, 317 | chunks, 318 | column_biomes, 319 | ); 320 | *buffer.borrow_mut() = Some(renderer.create_buffer(&staging_buffer[..])); 321 | staging_buffer.clear(); 322 | 323 | if pending_chunks.is_empty() { 324 | println!("Finished filling chunk vertex buffers."); 325 | } 326 | } 327 | } 328 | 329 | if let Some(Keyboard(Key::C)) = e.press_args() { 330 | println!( 331 | "Turned cursor capture {}", 332 | if capture_cursor { "off" } else { "on" } 333 | ); 334 | capture_cursor = !capture_cursor; 335 | 336 | window.set_capture_cursor(capture_cursor); 337 | } 338 | 339 | if e.mouse_relative_args().is_some() && !capture_cursor { 340 | // Don't send the mouse event to the FPS controller. 341 | continue; 342 | } 343 | 344 | first_person.event(&e); 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /src/minecraft/biome.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Index; 2 | use std::path::Path; 3 | 4 | use crate::chunk::BiomeId; 5 | use crate::minecraft::data; 6 | use gfx_voxel::texture::ColorMap; 7 | 8 | #[derive(Copy, Clone)] 9 | pub struct Biome { 10 | pub name: &'static str, 11 | pub temperature: f32, 12 | pub humidity: f32, 13 | pub grass_color: [u8; 3], 14 | pub foliage_color: [u8; 3], 15 | } 16 | 17 | pub struct Biomes { 18 | biomes: Box<[Option; 256]>, 19 | } 20 | 21 | impl Biomes { 22 | pub fn load(assets: &Path) -> Biomes { 23 | let mut biomes = Box::new([None; 256]); 24 | 25 | let grass_colors = Path::new("minecraft/textures/colormap/grass.png"); 26 | let grass_colors = ColorMap::from_path(&assets.join(&grass_colors)).unwrap(); 27 | let foliage_colors = Path::new("minecraft/textures/colormap/foliage.png"); 28 | let foliage_colors = ColorMap::from_path(&assets.join(foliage_colors)).unwrap(); 29 | 30 | for (i, &biome) in data::BIOMES.iter().enumerate() { 31 | biomes[i] = biome.map(|(name, t, h)| Biome { 32 | name, 33 | temperature: t, 34 | humidity: h, 35 | grass_color: grass_colors.get(t, h), 36 | foliage_color: foliage_colors.get(t, h), 37 | }); 38 | } 39 | 40 | Biomes { biomes } 41 | } 42 | } 43 | 44 | impl Index for Biomes { 45 | type Output = Biome; 46 | 47 | fn index(&self, id: BiomeId) -> &Biome { 48 | self.biomes[id.value as usize].as_ref().unwrap() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/minecraft/block_state.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::cmp::max; 3 | use std::collections::hash_map::Entry::{Occupied, Vacant}; 4 | use std::collections::HashMap; 5 | use std::fs::File; 6 | use std::num::Wrapping; 7 | use std::path::Path; 8 | 9 | use crate::array::*; 10 | use crate::chunk::{BiomeId, BlockState, Chunk}; 11 | use crate::cube; 12 | use crate::minecraft::biome::Biomes; 13 | use crate::minecraft::data::BLOCK_STATES; 14 | use crate::minecraft::model::OrthoRotation::*; 15 | use crate::minecraft::model::{self, Model, OrthoRotation}; 16 | use crate::shader::Vertex; 17 | use gfx; 18 | use gfx_voxel::texture::{AtlasBuilder, ImageSize, Texture}; 19 | use rustc_serialize::json; 20 | use vecmath::vec3_add; 21 | 22 | use self::PolymorphDecision::*; 23 | 24 | pub struct BlockStates { 25 | pub models: Vec, 26 | pub texture: Texture, 27 | } 28 | 29 | #[derive(PartialEq, Eq, Clone, Copy)] 30 | pub enum RandomOffset { 31 | None, 32 | XZ, 33 | XYZ, 34 | } 35 | 36 | #[derive(PartialEq, Eq, Clone, Copy)] 37 | pub enum Dir { 38 | Down, 39 | Up, 40 | North, 41 | South, 42 | West, 43 | East, 44 | 45 | // Some diagonal directions (used by redstone). 46 | UpNorth, 47 | UpSouth, 48 | UpWest, 49 | UpEast, 50 | } 51 | 52 | impl Dir { 53 | pub fn xyz(self) -> [i32; 3] { 54 | match self { 55 | Dir::Down => [0, -1, 0], 56 | Dir::Up => [0, 1, 0], 57 | Dir::North => [0, 0, -1], 58 | Dir::South => [0, 0, 1], 59 | Dir::West => [-1, 0, 0], 60 | Dir::East => [1, 0, 0], 61 | 62 | Dir::UpNorth => [0, 1, -1], 63 | Dir::UpSouth => [0, 1, 1], 64 | Dir::UpWest => [-1, 1, 0], 65 | Dir::UpEast => [1, 1, 0], 66 | } 67 | } 68 | } 69 | 70 | #[derive(Clone, Copy)] 71 | pub enum PolymorphDecision { 72 | // Stop and use this block state ID for the model. 73 | PickBlockState(u16), 74 | 75 | // Each of these checks a condition and continues if true, 76 | // or jumps to the provided u8 'else' index otherwise. 77 | // Blocks are specified with a signed offset from the block itself. 78 | // The 'OrSolid' variants also check for any solid blocks. 79 | IfBlock(Dir, i8, u8), 80 | IfBlockOrSolid(Dir, i8, u8), 81 | //IfGroup(Dir, Group, u8), 82 | //IfGroupOrSolid(Dir, Group, u8) 83 | } 84 | 85 | struct Description { 86 | id: u16, 87 | name: &'static str, 88 | variant: Cow<'static, str>, 89 | random_offset: RandomOffset, 90 | polymorph_oracle: Vec, 91 | } 92 | 93 | #[derive(Clone)] 94 | pub struct ModelAndBehavior { 95 | pub model: Model, 96 | pub random_offset: RandomOffset, 97 | pub polymorph_oracle: Vec, 98 | } 99 | 100 | impl ModelAndBehavior { 101 | pub fn empty() -> ModelAndBehavior { 102 | ModelAndBehavior { 103 | model: Model::empty(), 104 | random_offset: RandomOffset::None, 105 | polymorph_oracle: vec![], 106 | } 107 | } 108 | 109 | pub fn is_empty(&self) -> bool { 110 | self.model.is_empty() 111 | } 112 | } 113 | 114 | impl BlockStates { 115 | pub fn load>(assets: &Path, f: &mut F) -> BlockStates { 116 | let mut last_id = BLOCK_STATES.last().map_or(0, |state| state.0); 117 | let mut states = Vec::::with_capacity(BLOCK_STATES.len().next_power_of_two()); 118 | let mut extras = vec![]; 119 | let mut flower1 = None::; 120 | let mut flower2 = None::; 121 | for (i, &(id, name, variant)) in BLOCK_STATES.iter().enumerate() { 122 | let mut polymorph_oracle = vec![]; 123 | let mut random_offset = RandomOffset::None; 124 | 125 | // Find double_plant. 126 | if variant == "half=upper" { 127 | if name != "paeonia" { 128 | println!("Warning: unknown upper double_plant {}", name); 129 | } 130 | let (_, lower_name, lower_variant) = BLOCK_STATES[i - 1]; 131 | assert!(lower_name == name && lower_variant == "half=lower"); 132 | let lower = BLOCK_STATES[..i - 1].iter().enumerate().rev(); 133 | let lower = lower.take_while(|&(i, &(id, _, variant))| { 134 | id + 1 == BLOCK_STATES[i + 1].0 && variant == "half=lower" 135 | }); 136 | // Note: excluding paeonia itself, which works as-is. 137 | let num_plants = lower.count(); 138 | 139 | for j in i - 1 - num_plants..i - 1 { 140 | last_id += 1; 141 | let (_, lower_name, _) = BLOCK_STATES[j]; 142 | extras.push(Description { 143 | id: last_id, 144 | name: lower_name, 145 | variant: Cow::Borrowed("half=upper"), 146 | random_offset: RandomOffset::XZ, 147 | polymorph_oracle: vec![], 148 | }); 149 | states[j].random_offset = RandomOffset::XZ; 150 | 151 | let next_index = polymorph_oracle.len() as u8; 152 | polymorph_oracle.push(IfBlock( 153 | Dir::Down, 154 | (BLOCK_STATES[j].0.wrapping_sub(id)) as i8, 155 | next_index.wrapping_add(2), 156 | )); 157 | polymorph_oracle.push(PickBlockState(last_id)); 158 | } 159 | random_offset = RandomOffset::XZ; 160 | polymorph_oracle.push(PickBlockState(id)); 161 | } 162 | 163 | if name == "dandelion" { 164 | flower1 = Some(id); 165 | } else if name == "poppy" { 166 | flower2 = Some(id); 167 | } else if ["dead_bush", "tall_grass", "fern"].contains(&name) { 168 | random_offset = RandomOffset::XYZ; 169 | } 170 | 171 | if flower1 == Some(id & !0xf) || flower2 == Some(id & !0xf) { 172 | random_offset = RandomOffset::XZ; 173 | } 174 | 175 | let variant = if variant.ends_with(",shape=outer_right") { 176 | Cow::Owned(format!("{}=straight", &variant[..variant.len() - 12])) 177 | } else { 178 | Cow::Borrowed(variant) 179 | }; 180 | 181 | states.push(Description { 182 | id, 183 | name, 184 | variant, 185 | random_offset, 186 | polymorph_oracle, 187 | }); 188 | } 189 | states.extend(extras.into_iter()); 190 | 191 | BlockStates::load_with_states(assets, f, states) 192 | } 193 | 194 | fn load_with_states>( 195 | assets: &Path, 196 | f: &mut F, 197 | states: Vec, 198 | ) -> BlockStates { 199 | struct Variant { 200 | model: String, 201 | rotate_x: OrthoRotation, 202 | rotate_y: OrthoRotation, 203 | uvlock: bool, 204 | } 205 | 206 | let last_id = states.last().map_or(0, |state| state.id); 207 | let mut models = Vec::with_capacity(last_id as usize + 1); 208 | let mut atlas = AtlasBuilder::new(assets.join(Path::new("minecraft/textures")), 16, 16); 209 | let mut partial_model_cache = HashMap::new(); 210 | let mut block_state_cache: HashMap> = HashMap::new(); 211 | 212 | for state in states.into_iter() { 213 | let variants = match block_state_cache.entry(state.name.to_string()) { 214 | Occupied(entry) => entry.into_mut(), 215 | Vacant(entry) => entry.insert({ 216 | let name = state.name; 217 | let path = 218 | assets.join(Path::new(&format!("minecraft/blockstates/{}.json", name))); 219 | match json::Json::from_reader(&mut File::open(&path).unwrap()).unwrap() { 220 | json::Json::Object(mut json) => match json.remove("variants").unwrap() { 221 | json::Json::Object(variants) => variants 222 | .into_iter() 223 | .map(|(k, v)| { 224 | let mut variant = match v { 225 | json::Json::Object(o) => o, 226 | json::Json::Array(l) => { 227 | println!( 228 | "ignoring {} extra variants for {}#{}", 229 | l.len() - 1, 230 | name, 231 | k 232 | ); 233 | match l.into_iter().next() { 234 | Some(json::Json::Object(o)) => Some(o), 235 | _ => None, 236 | } 237 | .unwrap() 238 | } 239 | json => panic!("{}#{} has invalid value {}", name, k, json), 240 | }; 241 | let model = match variant.remove("model").unwrap() { 242 | json::Json::String(s) => s, 243 | json => panic!("'model' has invalid value {}", json), 244 | }; 245 | let rotate_x = variant.remove("x").map_or(Rotate0, |r| { 246 | match OrthoRotation::from_json(&r) { 247 | Some(r) => r, 248 | None => panic!("invalid rotation for x {}", r), 249 | } 250 | }); 251 | let rotate_y = variant.remove("y").map_or(Rotate0, |r| { 252 | match OrthoRotation::from_json(&r) { 253 | Some(r) => r, 254 | None => panic!("invalid rotation for y {}", r), 255 | } 256 | }); 257 | if let Some(r) = variant.remove("z") { 258 | println!("ignoring z rotation {} in {}", r, name) 259 | } 260 | let uvlock = variant 261 | .remove("uvlock") 262 | .map_or(false, |x| x.as_boolean().unwrap()); 263 | ( 264 | k, 265 | Variant { 266 | model, 267 | rotate_x, 268 | rotate_y, 269 | uvlock, 270 | }, 271 | ) 272 | }) 273 | .collect(), 274 | json => panic!("'variants' has invalid value {}", json), 275 | }, 276 | json => panic!("root object has invalid value {}", json), 277 | } 278 | }), 279 | }; 280 | 281 | let variant = match state.variant { 282 | Cow::Owned(ref variant) => variants.get(variant), 283 | Cow::Borrowed(variant) => variants.get(variant), 284 | } 285 | .unwrap(); 286 | let mut model = 287 | Model::load(&variant.model, assets, &mut atlas, &mut partial_model_cache); 288 | 289 | let rotate_faces = |m: &mut Model, ix: usize, iy: usize, rot_mat: [i32; 4]| { 290 | let (a, b, c, d) = ( 291 | rot_mat[0] as f32, 292 | rot_mat[1] as f32, 293 | rot_mat[2] as f32, 294 | rot_mat[3] as f32, 295 | ); 296 | for face in m.faces.iter_mut() { 297 | for vertex in face.vertices.iter_mut() { 298 | let xyz = &mut vertex.xyz; 299 | let (x, y) = (xyz[ix] - 0.5, xyz[iy] - 0.5); 300 | xyz[ix] = a * x + b * y + 0.5; 301 | xyz[iy] = c * x + d * y + 0.5; 302 | } 303 | let fixup_cube_face = |f: cube::Face| { 304 | let (a, b, c, d) = (rot_mat[0], rot_mat[1], rot_mat[2], rot_mat[3]); 305 | let mut dir = f.direction(); 306 | let (x, y) = (dir[ix], dir[iy]); 307 | dir[ix] = a * x + b * y; 308 | dir[iy] = c * x + d * y; 309 | cube::Face::from_direction(dir).unwrap() 310 | }; 311 | face.cull_face = face.cull_face.map(fixup_cube_face); 312 | face.ao_face = face.ao_face.map(fixup_cube_face); 313 | if variant.uvlock { 314 | // Skip over faces that are constant in the ix or iy axis. 315 | let xs = face.vertices.map(|v| v.xyz[ix]); 316 | if xs.map(|x| (x - xs[0]).abs() < f32::EPSILON) == [true, true, true, true] 317 | { 318 | continue; 319 | } 320 | let ys = face.vertices.map(|v| v.xyz[iy]); 321 | if ys.map(|y| (y - ys[0]).abs() < f32::EPSILON) == [true, true, true, true] 322 | { 323 | continue; 324 | } 325 | 326 | let uvs = face.vertices.map(|x| x.uv); 327 | let uv_min = [0, 1] 328 | .map(|i| (uvs[0][i]).min(uvs[1][i]).min(uvs[2][i]).min(uvs[3][i])); 329 | let temp = uv_min.map(|x| (x / 16.0).floor() * 16.0); 330 | let (u_base, v_base) = (temp[0], temp[1]); 331 | for vertex in face.vertices.iter_mut() { 332 | let uv = &mut vertex.uv; 333 | let (u, v) = (uv[0] - u_base - 8.0, uv[1] - v_base - 8.0); 334 | uv[0] = a * u - b * v + 8.0 + u_base; 335 | uv[1] = -c * u + d * v + 8.0 + v_base; 336 | } 337 | } 338 | } 339 | }; 340 | 341 | let rotate_faces = |m: &mut Model, ix: usize, iy: usize, r: OrthoRotation| match r { 342 | Rotate0 => {} 343 | Rotate90 => rotate_faces(m, ix, iy, [0, -1, 1, 0]), 344 | Rotate180 => rotate_faces(m, ix, iy, [-1, 0, 0, -1]), 345 | Rotate270 => rotate_faces(m, ix, iy, [0, 1, -1, 0]), 346 | }; 347 | 348 | rotate_faces(&mut model, 2, 1, variant.rotate_x); 349 | rotate_faces(&mut model, 0, 2, variant.rotate_y); 350 | 351 | while models.len() <= state.id as usize { 352 | models.push(ModelAndBehavior::empty()); 353 | } 354 | 355 | models[state.id as usize] = ModelAndBehavior { 356 | model, 357 | random_offset: state.random_offset, 358 | polymorph_oracle: state.polymorph_oracle, 359 | }; 360 | } 361 | 362 | drop(partial_model_cache); 363 | drop(block_state_cache); 364 | 365 | let texture = atlas.complete(f); 366 | let (width, height) = texture.get_size(); 367 | let u_unit = 1.0 / (width as f32); 368 | let v_unit = 1.0 / (height as f32); 369 | 370 | for model in models.iter_mut() { 371 | for face in model.model.faces.iter_mut() { 372 | for vertex in face.vertices.iter_mut() { 373 | vertex.uv[0] *= u_unit; 374 | vertex.uv[1] *= v_unit; 375 | } 376 | } 377 | } 378 | 379 | BlockStates { models, texture } 380 | } 381 | 382 | pub fn get_model(&self, i: BlockState) -> Option<&ModelAndBehavior> { 383 | let i = i.value as usize; 384 | if i >= self.models.len() || self.models[i].is_empty() { 385 | None 386 | } else { 387 | Some(&self.models[i]) 388 | } 389 | } 390 | 391 | pub fn texture(&self) -> &Texture { 392 | &self.texture 393 | } 394 | 395 | pub fn get_opacity(&self, i: BlockState) -> model::Opacity { 396 | let i = i.value as usize; 397 | if i >= self.models.len() { 398 | model::Opacity::Transparent 399 | } else { 400 | self.models[i].model.opacity 401 | } 402 | } 403 | } 404 | 405 | pub fn fill_buffer( 406 | block_states: &BlockStates, 407 | biomes: &Biomes, 408 | buffer: &mut Vec, 409 | coords: [i32; 3], 410 | chunks: [[[&Chunk; 3]; 3]; 3], 411 | column_biomes: [[Option<&[[BiomeId; 16]; 16]>; 3]; 3], 412 | ) { 413 | let chunk_xyz = coords.map(|x| x as f32 * 16.0); 414 | for y in 0..16_usize { 415 | for z in 0..16_usize { 416 | for x in 0..16_usize { 417 | let at = |dir: [i32; 3]| { 418 | let (dx, dy, dz) = (dir[0] as usize, dir[1] as usize, dir[2] as usize); 419 | let (x, y, z) = ( 420 | x.wrapping_add(dx).wrapping_add(16), 421 | y.wrapping_add(dy).wrapping_add(16), 422 | z.wrapping_add(dz).wrapping_add(16), 423 | ); 424 | let chunk = chunks[y / 16][z / 16][x / 16]; 425 | let (x, y, z) = (x % 16, y % 16, z % 16); 426 | (chunk.blocks[y][z][x], chunk.light_levels[y][z][x]) 427 | }; 428 | let this_block = at([0, 0, 0]).0; 429 | let model = match block_states.get_model(this_block) { 430 | Some(model) if !model.polymorph_oracle.is_empty() => { 431 | let mut i = 0; 432 | let result; 433 | loop { 434 | let (cond, idx) = match model.polymorph_oracle[i] { 435 | PickBlockState(id) => { 436 | result = &block_states.models[id as usize]; 437 | break; 438 | } 439 | IfBlock(dir, offset, idx) => { 440 | let id = this_block.value.wrapping_add(offset as u16); 441 | (at(dir.xyz()).0.value == id, idx) 442 | } 443 | IfBlockOrSolid(dir, offset, idx) => { 444 | let id = this_block.value.wrapping_add(offset as u16); 445 | let other = at(dir.xyz()).0; 446 | ( 447 | other.value == id 448 | || block_states.get_opacity(other).is_opaque(), 449 | idx, 450 | ) 451 | } /*IfGroup(dir, group, idx) => { 452 | let other = at(dir.xyz()).0; 453 | (block_states.models[other.value].group == group, idx) 454 | } 455 | IfGroupOrSolid(dir, group, idx) => { 456 | let other = at(dir.xyz()).0; 457 | (block_states.models[other.value].group == group || 458 | block_states.get_opacity(other).is_opaque(), idx) 459 | }*/ 460 | }; 461 | if cond { 462 | i += 1; 463 | } else { 464 | i = idx as usize; 465 | } 466 | } 467 | result 468 | } 469 | Some(model) => model, 470 | None => continue, 471 | }; 472 | let block_xyz = vec3_add([x, y, z].map(|x| x as f32), chunk_xyz); 473 | let block_xyz = match model.random_offset { 474 | RandomOffset::None => block_xyz, 475 | random_offset => { 476 | let (x, z) = (block_xyz[0], block_xyz[2]); 477 | let seed = Wrapping((Wrapping(x as i32) * Wrapping(3129871)).0 as i64) 478 | ^ (Wrapping(z as i64) * Wrapping(116129781)); 479 | let value = seed * seed * Wrapping(42317861) + seed * Wrapping(11); 480 | let ox = (((value.0 >> 16) & 15) as f32 / 15.0 - 0.5) * 0.5; 481 | let oz = (((value.0 >> 24) & 15) as f32 / 15.0 - 0.5) * 0.5; 482 | let oy = if random_offset == RandomOffset::XYZ { 483 | (((value.0 >> 20) & 15) as f32 / 15.0 - 1.0) * 0.2 484 | } else { 485 | 0.0 486 | }; 487 | vec3_add(block_xyz, [ox, oy, oz]) 488 | } 489 | }; 490 | let model = &model.model; 491 | for face in model.faces.iter() { 492 | if let Some(cull_face) = face.cull_face { 493 | let (neighbor, _) = at(cull_face.direction()); 494 | if block_states.get_opacity(neighbor).is_opaque() { 495 | continue; 496 | } 497 | } 498 | 499 | let tint_source = if face.tint { 500 | model.tint_source 501 | } else { 502 | model::Tint::None 503 | }; 504 | 505 | let v = face.vertices.map(|vertex| { 506 | // Average tint and light around the vertex. 507 | let (rgb, mut num_colors) = match tint_source { 508 | model::Tint::None => ([0xff, 0xff, 0xff], 1.0), 509 | model::Tint::Grass | model::Tint::Foliage => ([0x00, 0x00, 0x00], 0.0), 510 | model::Tint::Redstone => ([0xff, 0x00, 0x00], 1.0), 511 | }; 512 | let mut rgb = rgb.map(|x: u8| x as f32 / 255.0); 513 | let (mut sum_light_level, mut num_light_level) = (0.0, 0.0); 514 | 515 | let rounded_xyz = vertex.xyz.map(|x| x.round() as i32); 516 | let (dx, dy, dz) = (rounded_xyz[0], rounded_xyz[1], rounded_xyz[2]); 517 | for &dx in [dx - 1, dx].iter() { 518 | for &dz in [dz - 1, dz].iter() { 519 | for &dy in [dy - 1, dy].iter() { 520 | let (neighbor, light_level) = at([dx, dy, dz]); 521 | let light_level = 522 | max(light_level.block_light(), light_level.sky_light()); 523 | let mut light_level = light_level as f32; 524 | 525 | let use_block = match face.ao_face { 526 | Some(ao_face) => { 527 | let mut above = true; 528 | for (i, &a) in ao_face.direction().iter().enumerate() { 529 | let da = [dx, dy, dz][i]; 530 | let va = rounded_xyz[i]; 531 | let above_da = match a { 532 | -1 => va - 1, 533 | 1 => va, 534 | _ => da, 535 | }; 536 | if da != above_da { 537 | above = false; 538 | break; 539 | } 540 | } 541 | 542 | if above 543 | && block_states.get_opacity(neighbor).is_solid() 544 | { 545 | light_level = 0.0; 546 | } 547 | 548 | above 549 | } 550 | None => !block_states.get_opacity(neighbor).is_opaque(), 551 | }; 552 | 553 | if use_block { 554 | sum_light_level += light_level; 555 | num_light_level += 1.0; 556 | } 557 | } 558 | match tint_source { 559 | model::Tint::None | model::Tint::Redstone => continue, 560 | model::Tint::Grass | model::Tint::Foliage => {} 561 | } 562 | let (x, z) = ( 563 | x.wrapping_add(dx as usize).wrapping_add(16), 564 | z.wrapping_add(dz as usize).wrapping_add(16), 565 | ); 566 | let biome = match column_biomes[z / 16][x / 16] { 567 | Some(biome) => biomes[biome[z % 16][x % 16]], 568 | None => continue, 569 | }; 570 | rgb = vec3_add( 571 | rgb, 572 | match tint_source { 573 | model::Tint::None | model::Tint::Redstone => continue, 574 | model::Tint::Grass => biome.grass_color, 575 | model::Tint::Foliage => biome.foliage_color, 576 | } 577 | .map(|x| x as f32 / 255.0), 578 | ); 579 | num_colors += 1.0; 580 | } 581 | } 582 | 583 | let light_factor = 0.2 584 | + if num_light_level != 0.0 { 585 | sum_light_level / num_light_level / 15.0 * 0.8 586 | } else { 587 | 0.0 588 | }; 589 | 590 | // Up, North and South, East and West, Down have different lighting. 591 | let light_factor = light_factor 592 | * match face.ao_face { 593 | Some(ao_face) => match ao_face { 594 | cube::Up => 1.0, 595 | cube::North | cube::South => 0.8, 596 | cube::East | cube::West => 0.6, 597 | cube::Down => 0.5, 598 | }, 599 | None => 1.0, 600 | }; 601 | 602 | Vertex { 603 | xyz: vec3_add(block_xyz, vertex.xyz), 604 | uv: vertex.uv, 605 | // No clue why the difference of 2 exists. 606 | rgb: rgb.map(|x| x * light_factor / num_colors - 2.0 / 255.0), 607 | } 608 | }); 609 | 610 | // Split the clockwise quad into two clockwise triangles. 611 | buffer.extend([0, 1, 2, 2, 3, 0].iter().map(|&i| v[i])); 612 | } 613 | } 614 | } 615 | } 616 | } 617 | -------------------------------------------------------------------------------- /src/minecraft/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod biome; 2 | pub mod block_state; 3 | pub mod data_1_8_pre2; 4 | pub mod model; 5 | pub mod nbt; 6 | pub mod region; 7 | 8 | pub use crate::minecraft::data_1_8_pre2 as data; 9 | use std::env; 10 | use std::fs::{self, File}; 11 | use std::io; 12 | use std::path::PathBuf; 13 | use zip::ZipArchive; 14 | 15 | fn var(key: &str) -> String { 16 | match env::var(key) { 17 | Ok(val) => val, 18 | Err(err) => panic!("couldn't find env var {}; err: {:?}", key, err), 19 | } 20 | } 21 | 22 | #[cfg(windows)] 23 | pub fn vanilla_root_path() -> PathBuf { 24 | let appdata = var("appdata"); 25 | let mut buf = PathBuf::from(&appdata); 26 | buf.push(".minecraft"); 27 | buf 28 | } 29 | #[cfg(target_os = "linux")] 30 | pub fn vanilla_root_path() -> PathBuf { 31 | let home = var("HOME"); 32 | let mut buf = PathBuf::from(home); 33 | buf.push(".minecraft"); 34 | buf 35 | } 36 | #[cfg(target_os = "macos")] 37 | pub fn vanilla_root_path() -> PathBuf { 38 | let home = var("HOME"); 39 | let mut buf = PathBuf::from(home); 40 | buf.push("Library"); 41 | buf.push("Application Support"); 42 | buf.push("minecraft"); 43 | buf 44 | } 45 | 46 | pub fn fetch_assets(version: &str) { 47 | let mut buf = vanilla_root_path(); 48 | buf.push("versions"); 49 | buf.push(version); 50 | buf.push(format!("{}.jar", version)); 51 | 52 | println!("Opening {:?}...", &buf); 53 | let file = File::open(&buf).unwrap(); 54 | let mut archive = ZipArchive::new(file).unwrap(); 55 | println!("File {:?} contains {} files.", &buf, archive.len()); 56 | 57 | let mut count = 0; 58 | for i in 0..archive.len() { 59 | let mut file = archive.by_index(i).unwrap(); 60 | // Won't work because file.name() borrows file 'a lifetime. 61 | // let path = &PathBuf::from(file.name().trim_right_matches('\0')); 62 | let path = sanitize_filename(file.name()); 63 | if file.name().starts_with("assets/minecraft") { 64 | fs::create_dir_all(path.parent().unwrap()).unwrap(); 65 | 66 | let mut outfile = File::create(&path).unwrap(); 67 | io::copy(&mut file, &mut outfile).unwrap(); 68 | count += 1 69 | } 70 | } 71 | 72 | println!("Extracted {} files.", count); 73 | } 74 | 75 | fn sanitize_filename(filename: &str) -> PathBuf { 76 | // PathBuf::from(filename.trim_right_matches('\0')) 77 | let no_null_filename = match filename.find('\0') { 78 | Some(index) => &filename[0..index], 79 | None => filename, 80 | }; 81 | PathBuf::from(no_null_filename) 82 | } 83 | -------------------------------------------------------------------------------- /src/minecraft/model.rs: -------------------------------------------------------------------------------- 1 | use std::collections::hash_map::Entry::{Occupied, Vacant}; 2 | use std::collections::HashMap; 3 | use std::f32::consts::{PI, SQRT_2}; 4 | use std::fs::File; 5 | use std::path::Path; 6 | use std::str::FromStr; 7 | 8 | use self::OrthoRotation::*; 9 | 10 | use crate::array::*; 11 | use crate::cube; 12 | use gfx_voxel::texture::AtlasBuilder; 13 | use rustc_serialize::json; 14 | 15 | #[derive(Copy, Clone)] 16 | pub struct Vertex { 17 | pub xyz: [f32; 3], 18 | pub uv: [f32; 2], 19 | } 20 | 21 | #[derive(Copy, Clone)] 22 | pub enum Tint { 23 | None, 24 | Grass, 25 | Foliage, 26 | Redstone, 27 | } 28 | 29 | #[derive(Copy, Clone)] 30 | pub enum OrthoRotation { 31 | Rotate0, 32 | Rotate90, 33 | Rotate180, 34 | Rotate270, 35 | } 36 | 37 | impl OrthoRotation { 38 | pub fn from_json(json: &json::Json) -> Option { 39 | json.as_i64().and_then(|r| { 40 | Some(match r { 41 | 0 => Rotate0, 42 | 90 => Rotate90, 43 | 180 => Rotate180, 44 | 270 => Rotate270, 45 | _ => return None, 46 | }) 47 | }) 48 | } 49 | } 50 | 51 | #[derive(Copy, Clone)] 52 | pub struct Face { 53 | pub vertices: [Vertex; 4], 54 | pub tint: bool, 55 | pub cull_face: Option, 56 | pub ao_face: Option, 57 | } 58 | 59 | #[derive(Clone)] 60 | enum PartialTexture { 61 | Variable(String), 62 | Coords(f32, f32), 63 | } 64 | 65 | #[derive(Clone)] 66 | pub struct PartialModel { 67 | textures: HashMap, 68 | faces: Vec<(Face, String)>, 69 | full_faces: Vec, 70 | no_ambient_occlusion: bool, 71 | } 72 | 73 | #[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone)] 74 | pub enum Opacity { 75 | Transparent, 76 | TranslucentSolid, 77 | TransparentSolid, 78 | Opaque, 79 | } 80 | 81 | impl Opacity { 82 | pub fn is_opaque(self) -> bool { 83 | self == Opacity::Opaque 84 | } 85 | 86 | pub fn is_solid(self) -> bool { 87 | self != Opacity::Transparent 88 | } 89 | } 90 | 91 | #[derive(Clone)] 92 | pub struct Model { 93 | pub faces: Vec, 94 | pub opacity: Opacity, 95 | pub tint_source: Tint, 96 | } 97 | 98 | fn array3_num(json: &json::Json, mut f: F) -> [T; 3] 99 | where 100 | F: FnMut(f64) -> T, 101 | { 102 | Array::from_iter( 103 | json.as_array() 104 | .unwrap() 105 | .iter() 106 | .map(|x| f(x.as_f64().unwrap())), 107 | ) 108 | } 109 | 110 | fn clone_parent(m: &PartialModel, _a: &mut AtlasBuilder) -> PartialModel { 111 | m.clone() 112 | } 113 | 114 | impl PartialModel { 115 | fn load( 116 | name: &str, 117 | assets: &Path, 118 | atlas: &mut AtlasBuilder, 119 | cache: &mut HashMap, 120 | mut f: F, 121 | ) -> T 122 | where 123 | F: FnMut(&PartialModel, &mut AtlasBuilder) -> T, 124 | { 125 | if let Some(model) = cache.get(name) { 126 | return f(model, atlas); 127 | } 128 | let path = assets.join(Path::new(&format!("minecraft/models/{}.json", name))); 129 | let obj = json::Json::from_reader(&mut File::open(&path).unwrap()).unwrap(); 130 | 131 | let mut model = match obj.find("parent").and_then(|x| x.as_string()) { 132 | // FIXME(toqueteos): Cthulu himself came here and inspired me, if we use a closure here instead of 133 | // "clone_parent" this would trigger an error: "reached the recursion limit during monomorphization" 134 | Some(parent) => PartialModel::load(parent, assets, atlas, cache, clone_parent), 135 | None => PartialModel { 136 | textures: HashMap::new(), 137 | faces: vec![], 138 | full_faces: vec![], 139 | no_ambient_occlusion: false, 140 | }, 141 | }; 142 | 143 | if let Some(ambient_occlusion) = obj.find("ambientocclusion").and_then(|x| x.as_boolean()) { 144 | model.no_ambient_occlusion = !ambient_occlusion 145 | } 146 | 147 | if let Some(textures) = obj.find("textures").and_then(|x| x.as_object()) { 148 | for (name, tex) in textures.iter() { 149 | let tex = tex.as_string().unwrap(); 150 | let tex = if tex.starts_with('#') { 151 | PartialTexture::Variable(tex[1..].to_string()) 152 | } else { 153 | let (u, v) = atlas.load(tex); 154 | PartialTexture::Coords(u as f32, v as f32) 155 | }; 156 | model.textures.insert(name.clone(), tex); 157 | } 158 | } 159 | 160 | if let Some(elements) = obj 161 | .find("elements") 162 | .and_then(|x: &json::Json| x.as_array().cloned()) 163 | { 164 | for element in elements.iter().map(|x| x) { 165 | let from = array3_num(element.find("from").unwrap(), |x| x as f32 / 16.0); 166 | let to = array3_num(element.find("to").unwrap(), |x| x as f32 / 16.0); 167 | let scale = [to[0] - from[0], to[1] - from[1], to[2] - from[2]]; 168 | 169 | let is_full_cube = from == [0.0, 0.0, 0.0] && to == [1.0, 1.0, 1.0]; 170 | let element_start = model.faces.len(); 171 | 172 | for (k, v) in element.find("faces").unwrap().as_object().unwrap().iter() { 173 | let face: cube::Face = k.parse().unwrap(); 174 | let temp = match v.find("uv") { 175 | Some(uv) => Array::from_iter( 176 | uv.as_array() 177 | .unwrap() 178 | .iter() 179 | .map(|x| x.as_f64().unwrap() as f32), 180 | ), 181 | None => match face { 182 | cube::West | cube::East => [from[2], from[1], to[2], to[1]], 183 | cube::Down | cube::Up => [from[0], from[2], to[0], to[2]], 184 | cube::North | cube::South => [from[0], from[1], to[0], to[1]], 185 | } 186 | .map(|x| x * 16.0), 187 | }; 188 | let (u0, v0, u1, v1) = (temp[0], temp[1], temp[2], temp[3]); 189 | 190 | let tex = v.find("texture").unwrap().as_string().unwrap(); 191 | assert!(tex.starts_with('#')); 192 | let tex = tex[1..].to_string(); 193 | 194 | let cull_face = v 195 | .find("cullface") 196 | .map(|s| FromStr::from_str(s.as_string().unwrap()).unwrap()); 197 | 198 | if cull_face.is_some() && cull_face != Some(face) { 199 | println!( 200 | "odd case: cull_face = {:?} for face = {:?}", 201 | cull_face.unwrap(), 202 | face 203 | ); 204 | } 205 | 206 | let tint = v 207 | .find("tintindex") 208 | .map(|x| { 209 | let x = x.as_i64().unwrap(); 210 | if x != 0 { 211 | println!("odd case: tint_index = {}", x); 212 | } 213 | }) 214 | .is_some(); 215 | 216 | if cull_face == Some(face) && is_full_cube { 217 | model.full_faces.push(model.faces.len()); 218 | } 219 | 220 | let rotation = 221 | v.find("rotation") 222 | .map_or(Rotate0, |r| match OrthoRotation::from_json(r) { 223 | Some(r) => r, 224 | None => panic!("invalid rotation for face {}", r), 225 | }); 226 | 227 | let xyz = face.vertices(from, scale); 228 | // Swap vertical texture coordinates. 229 | let (v0, v1) = (v1, v0); 230 | // Bring texture coordinates closer to avoid seams. 231 | let u_center = (u0 + u1) / 2.0; 232 | let us = [u0, u1].map(|u| u - (u - u_center).signum() / 128.0); 233 | let (u0, u1) = (us[0], us[1]); 234 | let v_center = (v0 + v1) / 2.0; 235 | let vs = [v0, v1].map(|v| v - (v - v_center).signum() / 128.0); 236 | let (v0, v1) = (vs[0], vs[1]); 237 | // Clockwise quad (from bottom-right to top-right). 238 | let uvs = 239 | [(u1, v0), (u0, v0), (u0, v1), (u1, v1)].map(|(u, v)| match rotation { 240 | Rotate0 => [u, v], 241 | Rotate90 => [v, 16.0 - u], 242 | Rotate180 => [16.0 - u, 16.0 - v], 243 | Rotate270 => [16.0 - v, u], 244 | }); 245 | 246 | model.faces.push(( 247 | Face { 248 | vertices: Array::from_fn(|i| Vertex { 249 | xyz: xyz[i], 250 | uv: uvs[i], 251 | }), 252 | tint, 253 | cull_face, 254 | ao_face: Some(face), 255 | }, 256 | tex, 257 | )); 258 | } 259 | 260 | if let Some(r) = element.find("rotation") { 261 | let angle = r.find("angle").unwrap().as_f64().unwrap(); 262 | let angle = angle as f32 / 180.0 * PI; 263 | let rescale = r.find("rescale").map_or(false, |x| x.as_boolean().unwrap()); 264 | let origin = array3_num(r.find("origin").unwrap(), |x| x as f32 / 16.0); 265 | 266 | let (s, c) = (angle.sin(), angle.cos()); 267 | let mut rot = |ix: usize, iy: usize| { 268 | for &mut (ref mut face, _) in model.faces[element_start..].iter_mut() { 269 | face.ao_face = None; 270 | 271 | let (ox, oy) = (origin[ix], origin[iy]); 272 | for v in face.vertices.iter_mut() { 273 | let (x, y) = (v.xyz[ix] - ox, v.xyz[iy] - oy); 274 | v.xyz[ix] = x * c + y * s; 275 | v.xyz[iy] = -x * s + y * c; 276 | } 277 | 278 | if rescale { 279 | for v in face.vertices.iter_mut() { 280 | v.xyz[ix] *= SQRT_2; 281 | v.xyz[iy] *= SQRT_2; 282 | } 283 | } 284 | 285 | for v in face.vertices.iter_mut() { 286 | v.xyz[ix] += ox; 287 | v.xyz[iy] += oy; 288 | } 289 | } 290 | }; 291 | match r.find("axis").unwrap().as_string().unwrap() { 292 | "x" => rot(2, 1), 293 | "y" => rot(0, 2), 294 | "z" => rot(1, 0), 295 | axis => panic!("invalid rotation axis {}", axis), 296 | } 297 | } 298 | } 299 | } 300 | 301 | match cache.entry(name.to_string()) { 302 | Occupied(entry) => f(entry.get(), atlas), 303 | Vacant(entry) => f(entry.insert(model), atlas), 304 | } 305 | } 306 | } 307 | 308 | impl Model { 309 | pub fn load( 310 | name: &str, 311 | assets: &Path, 312 | atlas: &mut AtlasBuilder, 313 | cache: &mut HashMap, 314 | ) -> Model { 315 | PartialModel::load( 316 | &format!("block/{}", name), 317 | assets, 318 | atlas, 319 | cache, 320 | |partial, atlas| { 321 | let mut faces: Vec = partial 322 | .faces 323 | .iter() 324 | .map(|&(mut face, ref tex)| { 325 | fn texture_coords( 326 | textures: &HashMap, 327 | tex: &str, 328 | ) -> Option<(f32, f32)> { 329 | match textures.get(tex) { 330 | Some(&PartialTexture::Variable(ref tex)) => { 331 | texture_coords(textures, tex) 332 | } 333 | Some(&PartialTexture::Coords(u, v)) => Some((u, v)), 334 | None => None, 335 | } 336 | } 337 | let (u, v) = texture_coords(&partial.textures, tex).unwrap(); 338 | for vertex in face.vertices.iter_mut() { 339 | vertex.uv[0] += u; 340 | vertex.uv[1] += v; 341 | } 342 | face 343 | }) 344 | .collect(); 345 | 346 | let mut full_faces = [Opacity::Transparent; 6]; 347 | if partial.full_faces.len() >= 6 { 348 | for &i in partial.full_faces.iter() { 349 | let face = faces[i].cull_face.unwrap() as usize; 350 | if full_faces[face] == Opacity::Opaque { 351 | continue; 352 | } 353 | let (mut min_u, mut min_v) = (f32::INFINITY, f32::INFINITY); 354 | let (mut max_u, mut max_v) = (0.0, 0.0); 355 | for vertex in faces[i].vertices.iter() { 356 | let (u, v) = (vertex.uv[0], vertex.uv[1]); 357 | min_u = u.min(min_u); 358 | min_v = v.min(min_v); 359 | max_u = u.max(max_u); 360 | max_v = v.max(max_v); 361 | } 362 | let (u0, v0) = (min_u.floor() as u32, min_v.floor() as u32); 363 | let (u1, v1) = (max_u.ceil() as u32, max_v.ceil() as u32); 364 | let rect = [u0, v0, u1 - u0, v1 - v0]; 365 | let opacity = match atlas.min_alpha(rect) { 366 | 0 => Opacity::TransparentSolid, 367 | 255 => Opacity::Opaque, 368 | _ => Opacity::TranslucentSolid, 369 | }; 370 | if full_faces[face] < opacity { 371 | full_faces[face] = opacity; 372 | } 373 | } 374 | } 375 | 376 | if partial.no_ambient_occlusion { 377 | for face in faces.iter_mut() { 378 | face.ao_face = None; 379 | } 380 | } else if faces.iter().any(|f| f.ao_face.is_none()) { 381 | println!( 382 | "Warning: model {} uses AO but has faces which are unsuitable", 383 | name 384 | ); 385 | } 386 | 387 | let tint_source = if faces.iter().any(|f| f.tint) { 388 | match name { 389 | name if name.starts_with("grass_") 390 | || name.starts_with("double_grass_") 391 | || name.starts_with("double_fern_") => 392 | { 393 | Tint::Grass 394 | } 395 | "reeds" | "fern" | "tall_grass" => Tint::Grass, 396 | name if name.ends_with("_leaves") 397 | || name.ends_with("_stem_fruit") 398 | || name.starts_with("vine_") 399 | || name.starts_with("stem_") => 400 | { 401 | Tint::Foliage 402 | } 403 | "waterlily" => Tint::Foliage, 404 | name if name.starts_with("redstone_") => Tint::Redstone, 405 | _ => { 406 | println!("tint source not known for '{}'", name); 407 | Tint::None 408 | } 409 | } 410 | } else { 411 | Tint::None 412 | }; 413 | 414 | Model { 415 | faces, 416 | opacity: *full_faces.iter().min().unwrap(), 417 | tint_source, 418 | } 419 | }, 420 | ) 421 | } 422 | 423 | pub fn empty() -> Model { 424 | Model { 425 | faces: Vec::new(), 426 | opacity: Opacity::Transparent, 427 | tint_source: Tint::None, 428 | } 429 | } 430 | 431 | pub fn is_empty(&self) -> bool { 432 | self.faces.is_empty() 433 | } 434 | } 435 | -------------------------------------------------------------------------------- /src/minecraft/nbt.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::fmt; 3 | use std::io; 4 | use std::io::Read; 5 | use std::ops::Index; 6 | use std::string::{self, ToString}; 7 | 8 | use byteorder::{BigEndian, ReadBytesExt}; 9 | use flate2::read::{GzDecoder, ZlibDecoder}; 10 | use rustc_serialize; 11 | use rustc_serialize::hex::ToHex; 12 | 13 | use self::DecoderError::*; 14 | 15 | /// Represents a NBT value 16 | #[derive(Clone, PartialEq)] 17 | pub enum Nbt { 18 | Byte(i8), 19 | Short(i16), 20 | Int(i32), 21 | Long(i64), 22 | Float(f32), 23 | Double(f64), 24 | ByteArray(Vec), 25 | IntArray(Vec), 26 | String(String), 27 | List(List), 28 | Compound(Compound), 29 | } 30 | 31 | impl fmt::Debug for Nbt { 32 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 33 | match *self { 34 | Nbt::Byte(x) => write!(f, "{}b", x), 35 | Nbt::Short(x) => write!(f, "{}s", x), 36 | Nbt::Int(x) => write!(f, "{}i", x), 37 | Nbt::Long(x) => write!(f, "{}L", x), 38 | Nbt::Float(x) => write!(f, "{:.1}f", x), 39 | Nbt::Double(x) => write!(f, "{:.1}", x), 40 | Nbt::ByteArray(ref x) => write!(f, "b<{}>", x[..].to_hex()), 41 | Nbt::IntArray(ref x) => write!(f, "{:?}", *x), 42 | Nbt::String(ref x) => write!(f, "\"{}\"", *x), 43 | Nbt::List(ref x) => write!(f, "{:?}", *x), 44 | Nbt::Compound(ref x) => write!(f, "{:?}", *x), 45 | } 46 | } 47 | } 48 | 49 | impl fmt::Display for Nbt { 50 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 51 | match *self { 52 | Nbt::Byte(x) => write!(f, "{}", x), 53 | Nbt::Short(x) => write!(f, "{}", x), 54 | Nbt::Int(x) => write!(f, "{}", x), 55 | Nbt::Long(x) => write!(f, "{}", x), 56 | Nbt::Float(x) => write!(f, "{:.1}", x), 57 | Nbt::Double(x) => write!(f, "{:.1}", x), 58 | Nbt::ByteArray(ref x) => write!(f, "<{}>", x[..].to_hex()), 59 | Nbt::IntArray(ref x) => write!(f, "{:?}", *x), 60 | Nbt::String(ref x) => write!(f, "\"{}\"", *x), 61 | Nbt::List(ref x) => write!(f, "{:?}", *x), 62 | Nbt::Compound(ref x) => write!(f, "{:?}", *x), 63 | } 64 | } 65 | } 66 | 67 | /// An ordered list of NBT values. 68 | #[derive(Clone, PartialEq, Debug)] 69 | pub enum List { 70 | Byte(Vec), 71 | Short(Vec), 72 | Int(Vec), 73 | Long(Vec), 74 | Float(Vec), 75 | Double(Vec), 76 | ByteArray(Vec>), 77 | IntArray(Vec>), 78 | String(Vec), 79 | List(Vec), 80 | Compound(Vec), 81 | } 82 | 83 | /// An unordered list of named NBT values. 84 | pub type Compound = HashMap; 85 | 86 | impl Nbt { 87 | pub fn from_reader(r: R) -> NbtReaderResult { 88 | Ok(NbtReader::new(r).tag()?.unwrap().0) 89 | } 90 | 91 | pub fn from_gzip(data: &[u8]) -> NbtReaderResult { 92 | let reader = GzDecoder::new(data); 93 | Nbt::from_reader(reader) 94 | } 95 | 96 | pub fn from_zlib(data: &[u8]) -> NbtReaderResult { 97 | let reader = ZlibDecoder::new(data); 98 | Nbt::from_reader(reader) 99 | } 100 | 101 | pub fn as_byte(&self) -> Option { 102 | match *self { 103 | Nbt::Byte(b) => Some(b), 104 | _ => None, 105 | } 106 | } 107 | 108 | pub fn into_compound(self) -> Result { 109 | match self { 110 | Nbt::Compound(c) => Ok(c), 111 | x => Err(x), 112 | } 113 | } 114 | 115 | pub fn into_compound_list(self) -> Result, Nbt> { 116 | match self { 117 | Nbt::List(List::Compound(c)) => Ok(c), 118 | x => Err(x), 119 | } 120 | } 121 | 122 | pub fn as_bytearray(&self) -> Option<&[u8]> { 123 | match *self { 124 | Nbt::ByteArray(ref b) => Some(&b[..]), 125 | _ => None, 126 | } 127 | } 128 | 129 | pub fn into_bytearray(self) -> Result, Nbt> { 130 | match self { 131 | Nbt::ByteArray(b) => Ok(b), 132 | x => Err(x), 133 | } 134 | } 135 | 136 | pub fn as_float_list(&self) -> Option<&[f32]> { 137 | match *self { 138 | Nbt::List(List::Float(ref f)) => Some(&f[..]), 139 | _ => None, 140 | } 141 | } 142 | 143 | pub fn as_double_list(&self) -> Option<&[f64]> { 144 | match *self { 145 | Nbt::List(List::Double(ref d)) => Some(&d[..]), 146 | _ => None, 147 | } 148 | } 149 | } 150 | 151 | impl<'a> Index<&'a str> for Nbt { 152 | type Output = Nbt; 153 | 154 | fn index<'b>(&'b self, s: &'a str) -> &'b Nbt { 155 | match *self { 156 | Nbt::Compound(ref c) => c.get(s).unwrap(), 157 | _ => panic!("cannot index non-compound Nbt ({:?}) with '{}'", self, s), 158 | } 159 | } 160 | } 161 | 162 | const TAG_END: i8 = 0; 163 | const TAG_BYTE: i8 = 1; 164 | const TAG_SHORT: i8 = 2; 165 | const TAG_INT: i8 = 3; 166 | const TAG_LONG: i8 = 4; 167 | const TAG_FLOAT: i8 = 5; 168 | const TAG_DOUBLE: i8 = 6; 169 | const TAG_BYTE_ARRAY: i8 = 7; 170 | const TAG_STRING: i8 = 8; 171 | const TAG_LIST: i8 = 9; 172 | const TAG_COMPOUND: i8 = 10; 173 | const TAG_INT_ARRAY: i8 = 11; 174 | 175 | pub type NbtReaderResult = Result; 176 | 177 | #[derive(Debug)] 178 | pub enum NbtReaderError { 179 | Io(io::Error), 180 | Utf8(string::FromUtf8Error), 181 | } 182 | 183 | impl From for NbtReaderError { 184 | fn from(err: io::Error) -> NbtReaderError { 185 | NbtReaderError::Io(err) 186 | } 187 | } 188 | 189 | impl From for NbtReaderError { 190 | fn from(err: string::FromUtf8Error) -> NbtReaderError { 191 | NbtReaderError::Utf8(err) 192 | } 193 | } 194 | 195 | pub struct NbtReader { 196 | reader: R, 197 | } 198 | 199 | impl NbtReader { 200 | pub fn new(reader: R) -> NbtReader { 201 | NbtReader { reader } 202 | } 203 | 204 | fn i8(&mut self) -> NbtReaderResult { 205 | self.reader.read_i8().map_err(NbtReaderError::from) 206 | } 207 | fn i16(&mut self) -> NbtReaderResult { 208 | self.reader 209 | .read_i16::() 210 | .map_err(NbtReaderError::from) 211 | } 212 | fn i32(&mut self) -> NbtReaderResult { 213 | self.reader 214 | .read_i32::() 215 | .map_err(NbtReaderError::from) 216 | } 217 | fn i64(&mut self) -> NbtReaderResult { 218 | self.reader 219 | .read_i64::() 220 | .map_err(NbtReaderError::from) 221 | } 222 | fn f32(&mut self) -> NbtReaderResult { 223 | self.reader 224 | .read_f32::() 225 | .map_err(NbtReaderError::from) 226 | } 227 | fn f64(&mut self) -> NbtReaderResult { 228 | self.reader 229 | .read_f64::() 230 | .map_err(NbtReaderError::from) 231 | } 232 | 233 | fn string(&mut self) -> NbtReaderResult { 234 | let len = self.reader.read_u16::()? as usize; 235 | let mut v = Vec::with_capacity(len); 236 | for _ in 0..len { 237 | let mut c = [0]; 238 | self.reader.read_exact(&mut c)?; 239 | v.push(c[0]) 240 | } 241 | String::from_utf8(v).map_err(NbtReaderError::from) 242 | } 243 | 244 | fn array_u8(&mut self) -> NbtReaderResult> { 245 | let len = self.i32()? as usize; 246 | let mut v = Vec::with_capacity(len); 247 | for _ in 0..len { 248 | let mut c = [0]; 249 | self.reader.read_exact(&mut c)?; 250 | v.push(c[0]) 251 | } 252 | Ok(v) 253 | } 254 | 255 | fn array(&mut self, mut read: F) -> NbtReaderResult> 256 | where 257 | F: FnMut(&mut NbtReader) -> NbtReaderResult, 258 | { 259 | let len = self.i32()? as usize; 260 | let mut v = Vec::with_capacity(len); 261 | for _ in 0..len { 262 | v.push(read(self)?) 263 | } 264 | Ok(v) 265 | } 266 | 267 | fn compound(&mut self) -> NbtReaderResult { 268 | let mut map = HashMap::new(); 269 | while let Some((v, name)) = self.tag()? { 270 | map.insert(name, v); 271 | } 272 | Ok(map) 273 | } 274 | 275 | fn list(&mut self) -> NbtReaderResult { 276 | match self.i8()? { 277 | TAG_END => { 278 | assert_eq!(self.i32()?, 0); 279 | Ok(List::Compound(Vec::new())) 280 | } 281 | TAG_BYTE => self.array(|r| r.i8()).map(List::Byte), 282 | TAG_SHORT => self.array(|r| r.i16()).map(List::Short), 283 | TAG_INT => self.array(|r| r.i32()).map(List::Int), 284 | TAG_LONG => self.array(|r| r.i64()).map(List::Long), 285 | TAG_FLOAT => self.array(|r| r.f32()).map(List::Float), 286 | TAG_DOUBLE => self.array(|r| r.f64()).map(List::Double), 287 | TAG_BYTE_ARRAY => self.array(|r| r.array_u8()).map(List::ByteArray), 288 | TAG_INT_ARRAY => self.array(|r| r.array(|r| r.i32())).map(List::IntArray), 289 | TAG_STRING => self.array(|r| r.string()).map(List::String), 290 | TAG_LIST => self.array(|r| r.list()).map(List::List), 291 | TAG_COMPOUND => self.array(|r| r.compound()).map(List::Compound), 292 | tag_type => panic!("Unexpected tag type {}", tag_type), 293 | } 294 | } 295 | 296 | pub fn tag(&mut self) -> NbtReaderResult> { 297 | Ok(match self.i8()? { 298 | TAG_END => None, 299 | tag_type => { 300 | let name = self.string()?; 301 | Some(( 302 | match tag_type { 303 | TAG_BYTE => self.i8().map(Nbt::Byte), 304 | TAG_SHORT => self.i16().map(Nbt::Short), 305 | TAG_INT => self.i32().map(Nbt::Int), 306 | TAG_LONG => self.i64().map(Nbt::Long), 307 | TAG_FLOAT => self.f32().map(Nbt::Float), 308 | TAG_DOUBLE => self.f64().map(Nbt::Double), 309 | TAG_BYTE_ARRAY => self.array_u8().map(Nbt::ByteArray), 310 | TAG_INT_ARRAY => self.array(|r| r.i32()).map(Nbt::IntArray), 311 | TAG_STRING => self.string().map(Nbt::String), 312 | TAG_LIST => self.list().map(Nbt::List), 313 | TAG_COMPOUND => self.compound().map(Nbt::Compound), 314 | tag_type => panic!("Unexpected tag type {}", tag_type), 315 | }?, 316 | name, 317 | )) 318 | } 319 | }) 320 | } 321 | } 322 | 323 | /// A structure to decode NBT to values in rust. 324 | pub struct Decoder { 325 | stack: Vec>, 326 | } 327 | 328 | #[derive(Clone, PartialEq, Eq, Debug)] 329 | pub enum DecoderError { 330 | ExpectedError(String, String), 331 | MissingFieldError(String), 332 | UnknownVariantError(String), 333 | ApplicationError(String), 334 | } 335 | 336 | pub type DecodeResult = Result; 337 | 338 | impl Decoder { 339 | /// Creates a new decoder instance for decoding the specified NBT value. 340 | pub fn new(nbt: Nbt) -> Decoder { 341 | Decoder { 342 | stack: vec![Ok(nbt)], 343 | } 344 | } 345 | fn pop(&mut self) -> DecodeResult { 346 | self.stack.pop().unwrap() 347 | } 348 | fn push(&mut self, nbt: Nbt) { 349 | self.stack.push(Ok(nbt)) 350 | } 351 | fn push_all(&mut self, list: Vec, f: F) -> usize 352 | where 353 | F: FnMut(T) -> Nbt, 354 | { 355 | let len = list.len(); 356 | self.stack 357 | .extend(list.into_iter().rev().map(f).map(Ok::)); 358 | len 359 | } 360 | } 361 | 362 | // impl Decodable for Nbt { 363 | // fn decode(d: &mut D) -> Result { 364 | // d.pop() 365 | // } 366 | // } 367 | 368 | macro_rules! expect( 369 | ($s:expr, $t:path) => ({ 370 | match $s.pop() { 371 | Ok($t(v)) => Ok(v), 372 | Ok(other) => { 373 | Err(ExpectedError(stringify!($t).to_string(), other.to_string())) 374 | } 375 | Err(e) => Err(e) 376 | } 377 | }); 378 | ($s:expr, $t:ident as $to:ty) => (expect!($s, $t).map(|x| x as $to)) 379 | ); 380 | 381 | impl rustc_serialize::Decoder for Decoder { 382 | type Error = DecoderError; 383 | 384 | fn read_nil(&mut self) -> DecodeResult<()> { 385 | Err(ExpectedError("()".to_string(), self.pop()?.to_string())) 386 | } 387 | 388 | fn read_usize(&mut self) -> DecodeResult { 389 | Ok(self.read_isize()? as usize) 390 | } 391 | fn read_u64(&mut self) -> DecodeResult { 392 | expect!(self, Nbt::Long).map(|x| x as u64) 393 | } 394 | fn read_u32(&mut self) -> DecodeResult { 395 | expect!(self, Nbt::Int).map(|x| x as u32) 396 | } 397 | fn read_u16(&mut self) -> DecodeResult { 398 | expect!(self, Nbt::Short).map(|x| x as u16) 399 | } 400 | 401 | fn read_u8(&mut self) -> DecodeResult { 402 | expect!(self, Nbt::Byte).map(|x| x as u8) 403 | } 404 | fn read_isize(&mut self) -> DecodeResult { 405 | match self.pop()? { 406 | Nbt::Byte(x) => Ok(x as isize), 407 | Nbt::Short(x) => Ok(x as isize), 408 | Nbt::Int(x) => Ok(x as isize), 409 | Nbt::Long(x) => Ok(x as isize), 410 | other => Err(ExpectedError("isize".to_string(), other.to_string())), 411 | } 412 | } 413 | fn read_i64(&mut self) -> DecodeResult { 414 | expect!(self, Nbt::Long) 415 | } 416 | fn read_i32(&mut self) -> DecodeResult { 417 | expect!(self, Nbt::Int) 418 | } 419 | 420 | fn read_i16(&mut self) -> DecodeResult { 421 | expect!(self, Nbt::Short) 422 | } 423 | fn read_i8(&mut self) -> DecodeResult { 424 | expect!(self, Nbt::Byte) 425 | } 426 | 427 | fn read_bool(&mut self) -> DecodeResult { 428 | Ok(self.read_u8()? != 0) 429 | } 430 | 431 | fn read_f64(&mut self) -> DecodeResult { 432 | expect!(self, Nbt::Double) 433 | } 434 | fn read_f32(&mut self) -> DecodeResult { 435 | expect!(self, Nbt::Float) 436 | } 437 | 438 | fn read_char(&mut self) -> DecodeResult { 439 | let s = self.read_str()?; 440 | { 441 | let mut it = s.chars(); 442 | if let (Some(c), None) = (it.next(), it.next()) { 443 | return Ok(c); 444 | } 445 | } 446 | Err(ExpectedError("single character string".to_string(), s)) 447 | } 448 | 449 | fn read_str(&mut self) -> DecodeResult { 450 | expect!(self, Nbt::String) 451 | } 452 | 453 | fn read_enum(&mut self, _name: &str, f: F) -> DecodeResult 454 | where 455 | F: FnOnce(&mut Self) -> DecodeResult, 456 | { 457 | f(self) 458 | } 459 | 460 | fn read_enum_variant(&mut self, names: &[&str], mut f: F) -> DecodeResult 461 | where 462 | F: FnMut(&mut Self, usize) -> DecodeResult, 463 | { 464 | let name = match self.pop()? { 465 | Nbt::String(s) => s, 466 | Nbt::Compound(mut o) => { 467 | let name = match o.remove("variant") { 468 | Some(Nbt::String(s)) => s, 469 | Some(val) => return Err(ExpectedError("String".to_string(), val.to_string())), 470 | None => return Err(MissingFieldError("variant".to_string())), 471 | }; 472 | match o.remove("fields") { 473 | Some(v) => { 474 | self.push(v); 475 | self.read_seq(|_, _| Ok(()))?; 476 | } 477 | None => return Err(MissingFieldError("fields".to_string())), 478 | } 479 | name 480 | } 481 | nbt => { 482 | return Err(ExpectedError( 483 | "String or Compound".to_string(), 484 | nbt.to_string(), 485 | )) 486 | } 487 | }; 488 | let idx = match names.iter().position(|n| n == &name) { 489 | Some(idx) => idx, 490 | None => return Err(UnknownVariantError(name)), 491 | }; 492 | f(self, idx) 493 | } 494 | 495 | fn read_enum_variant_arg(&mut self, _idx: usize, f: F) -> DecodeResult 496 | where 497 | F: FnOnce(&mut Self) -> DecodeResult, 498 | { 499 | f(self) 500 | } 501 | 502 | fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> DecodeResult 503 | where 504 | F: FnMut(&mut Self, usize) -> DecodeResult, 505 | { 506 | self.read_enum_variant(names, f) 507 | } 508 | 509 | fn read_enum_struct_variant_field( 510 | &mut self, 511 | _name: &str, 512 | idx: usize, 513 | f: F, 514 | ) -> DecodeResult 515 | where 516 | F: FnOnce(&mut Self) -> DecodeResult, 517 | { 518 | self.read_enum_variant_arg(idx, f) 519 | } 520 | 521 | fn read_struct(&mut self, _name: &str, _len: usize, f: F) -> DecodeResult 522 | where 523 | F: FnOnce(&mut Self) -> DecodeResult, 524 | { 525 | let value = f(self)?; 526 | let _ = self.pop(); 527 | Ok(value) 528 | } 529 | 530 | fn read_struct_field(&mut self, name: &str, _idx: usize, f: F) -> DecodeResult 531 | where 532 | F: FnOnce(&mut Self) -> DecodeResult, 533 | { 534 | let mut obj = expect!(self, Nbt::Compound)?; 535 | 536 | let value = match obj.remove(name) { 537 | None => return Err(MissingFieldError(name.to_string())), 538 | Some(v) => { 539 | self.stack.push(Ok(v)); 540 | f(self)? 541 | } 542 | }; 543 | self.push(Nbt::Compound(obj)); 544 | Ok(value) 545 | } 546 | 547 | fn read_tuple(&mut self, tuple_len: usize, f: F) -> DecodeResult 548 | where 549 | F: FnOnce(&mut Self) -> DecodeResult, 550 | { 551 | self.read_seq(move |d, len| { 552 | if len == tuple_len { 553 | f(d) 554 | } else { 555 | Err(ExpectedError( 556 | format!("Tuple{}", tuple_len), 557 | format!("Tuple{}", len), 558 | )) 559 | } 560 | }) 561 | } 562 | 563 | fn read_tuple_arg(&mut self, idx: usize, f: F) -> DecodeResult 564 | where 565 | F: FnOnce(&mut Self) -> DecodeResult, 566 | { 567 | self.read_seq_elt(idx, f) 568 | } 569 | 570 | fn read_tuple_struct(&mut self, _name: &str, len: usize, f: F) -> DecodeResult 571 | where 572 | F: FnOnce(&mut Self) -> DecodeResult, 573 | { 574 | self.read_tuple(len, f) 575 | } 576 | 577 | fn read_tuple_struct_arg(&mut self, idx: usize, f: F) -> DecodeResult 578 | where 579 | F: FnOnce(&mut Self) -> DecodeResult, 580 | { 581 | self.read_tuple_arg(idx, f) 582 | } 583 | 584 | fn read_option(&mut self, mut f: F) -> DecodeResult 585 | where 586 | F: FnMut(&mut Self, bool) -> DecodeResult, 587 | { 588 | match self.pop() { 589 | Ok(value) => { 590 | self.push(value); 591 | f(self, true) 592 | } 593 | Err(MissingFieldError(_)) => f(self, false), 594 | Err(e) => Err(e), 595 | } 596 | } 597 | 598 | fn read_seq(&mut self, f: F) -> DecodeResult 599 | where 600 | F: FnOnce(&mut Self, usize) -> DecodeResult, 601 | { 602 | let len = match expect!(self, Nbt::List)? { 603 | List::Byte(list) => self.push_all(list, Nbt::Byte), 604 | List::Short(list) => self.push_all(list, Nbt::Short), 605 | List::Int(list) => self.push_all(list, Nbt::Int), 606 | List::Long(list) => self.push_all(list, Nbt::Long), 607 | List::Float(list) => self.push_all(list, Nbt::Float), 608 | List::Double(list) => self.push_all(list, Nbt::Double), 609 | List::ByteArray(list) => self.push_all(list, Nbt::ByteArray), 610 | List::IntArray(list) => self.push_all(list, Nbt::IntArray), 611 | List::String(list) => self.push_all(list, Nbt::String), 612 | List::List(list) => self.push_all(list, Nbt::List), 613 | List::Compound(list) => self.push_all(list, Nbt::Compound), 614 | }; 615 | f(self, len) 616 | } 617 | 618 | fn read_seq_elt(&mut self, _idx: usize, f: F) -> DecodeResult 619 | where 620 | F: FnOnce(&mut Self) -> DecodeResult, 621 | { 622 | f(self) 623 | } 624 | 625 | fn read_map(&mut self, f: F) -> DecodeResult 626 | where 627 | F: FnOnce(&mut Self, usize) -> DecodeResult, 628 | { 629 | let obj = expect!(self, Nbt::Compound)?; 630 | let len = obj.len(); 631 | for (key, value) in obj.into_iter() { 632 | self.push(value); 633 | self.push(Nbt::String(key)); 634 | } 635 | f(self, len) 636 | } 637 | 638 | fn read_map_elt_key(&mut self, _idx: usize, f: F) -> DecodeResult 639 | where 640 | F: FnOnce(&mut Self) -> DecodeResult, 641 | { 642 | f(self) 643 | } 644 | 645 | fn read_map_elt_val(&mut self, _idx: usize, f: F) -> DecodeResult 646 | where 647 | F: FnOnce(&mut Self) -> DecodeResult, 648 | { 649 | f(self) 650 | } 651 | 652 | fn error(&mut self, err: &str) -> DecoderError { 653 | ApplicationError(err.to_string()) 654 | } 655 | } 656 | -------------------------------------------------------------------------------- /src/minecraft/region.rs: -------------------------------------------------------------------------------- 1 | use gfx; 2 | use memmap::{Mmap, Protection}; 3 | use std::cell::RefCell; 4 | use std::io; 5 | use std::path::Path; 6 | 7 | use crate::array::*; 8 | use crate::chunk::{BiomeId, BlockState, Chunk, ChunkColumn, LightLevel, EMPTY_CHUNK, SIZE}; 9 | use crate::minecraft::nbt::Nbt; 10 | 11 | pub struct Region { 12 | mmap: Mmap, 13 | } 14 | 15 | fn array_16x16x16(mut f: F) -> [[[T; SIZE]; SIZE]; SIZE] 16 | where 17 | F: FnMut(usize, usize, usize) -> T, 18 | { 19 | Array::from_fn(|y| -> [[T; SIZE]; SIZE] { 20 | Array::from_fn(|z| -> [T; 16] { Array::from_fn(|x| f(x, y, z)) }) 21 | }) 22 | } 23 | 24 | impl Region { 25 | pub fn open(filename: &Path) -> io::Result { 26 | let mmap = Mmap::open_path(filename, Protection::Read)?; 27 | Ok(Region { mmap }) 28 | } 29 | 30 | fn as_slice(&self) -> &[u8] { 31 | unsafe { self.mmap.as_slice() } 32 | } 33 | 34 | pub fn get_chunk_column(&self, x: u8, z: u8) -> Option> { 35 | let locations = &self.as_slice()[..4096]; 36 | let i = 4 * ((x % 32) as usize + (z % 32) as usize * 32); 37 | let start = ((locations[i] as usize) << 16) 38 | | ((locations[i + 1] as usize) << 8) 39 | | (locations[i + 2] as usize); 40 | let num = locations[i + 3] as usize; 41 | if start == 0 || num == 0 { 42 | return None; 43 | } 44 | let sectors = &self.as_slice()[start * 4096..(start + num) * 4096]; 45 | let len = ((sectors[0] as usize) << 24) 46 | | ((sectors[1] as usize) << 16) 47 | | ((sectors[2] as usize) << 8) 48 | | (sectors[3] as usize); 49 | let nbt = match sectors[4] { 50 | 1 => Nbt::from_gzip(§ors[5..4 + len]), 51 | 2 => Nbt::from_zlib(§ors[5..4 + len]), 52 | c => panic!("unknown region chunk compression method {}", c), 53 | }; 54 | 55 | let mut c = nbt.unwrap().into_compound().unwrap(); 56 | let mut level = c.remove("Level").unwrap().into_compound().unwrap(); 57 | let mut chunks = Vec::new(); 58 | for chunk in level 59 | .remove("Sections") 60 | .unwrap() 61 | .into_compound_list() 62 | .unwrap() 63 | .into_iter() 64 | { 65 | let y = chunk.get("Y").unwrap().as_byte().unwrap(); 66 | let blocks = chunk.get("Blocks").unwrap().as_bytearray().unwrap(); 67 | let blocks_top = chunk.get("Add").and_then(|x| x.as_bytearray()); 68 | let blocks_data = chunk.get("Data").unwrap().as_bytearray().unwrap(); 69 | let block_light = chunk.get("BlockLight").unwrap().as_bytearray().unwrap(); 70 | let sky_light = chunk.get("SkyLight").unwrap().as_bytearray().unwrap(); 71 | 72 | let chunk = Chunk { 73 | blocks: array_16x16x16(|x, y, z| { 74 | let i = (y * SIZE + z) * SIZE + x; 75 | let top = match blocks_top { 76 | Some(blocks_top) => (blocks_top[i >> 1] >> ((i & 1) * 4)) & 0x0f, 77 | None => 0, 78 | }; 79 | let data = (blocks_data[i >> 1] >> ((i & 1) * 4)) & 0x0f; 80 | BlockState { 81 | value: ((blocks[i] as u16) << 4) | ((top as u16) << 12) | (data as u16), 82 | } 83 | }), 84 | light_levels: array_16x16x16(|x, y, z| { 85 | let i = (y * 16 + z) * 16 + x; 86 | let block = (block_light[i >> 1] >> ((i & 1) * 4)) & 0x0f; 87 | let sky = (sky_light[i >> 1] >> ((i & 1) * 4)) & 0x0f; 88 | LightLevel { 89 | value: block | (sky << 4), 90 | } 91 | }), 92 | }; 93 | while chunks.len() <= y as usize { 94 | chunks.push(*EMPTY_CHUNK); 95 | } 96 | chunks[y as usize] = chunk; 97 | } 98 | let biomes = level.get("Biomes").unwrap().as_bytearray().unwrap(); 99 | Some(ChunkColumn { 100 | chunks, 101 | buffers: Array::from_fn(|_| RefCell::new(None)), 102 | biomes: Array::from_fn(|z| -> [BiomeId; SIZE] { 103 | Array::from_fn(|x| BiomeId { 104 | value: biomes[z * SIZE + x], 105 | }) 106 | }), 107 | }) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/shader.rs: -------------------------------------------------------------------------------- 1 | use gfx; 2 | use gfx::traits::FactoryExt; 3 | use vecmath::{self, Matrix4}; 4 | 5 | static VERTEX: &[u8] = b" 6 | #version 150 core 7 | uniform mat4 u_projection, u_view; 8 | 9 | in vec2 at_tex_coord; 10 | in vec3 at_color, at_position; 11 | 12 | out vec2 v_tex_coord; 13 | out vec3 v_color; 14 | 15 | void main() { 16 | v_tex_coord = at_tex_coord; 17 | v_color = at_color; 18 | gl_Position = u_projection * u_view * vec4(at_position, 1.0); 19 | } 20 | "; 21 | 22 | static FRAGMENT: &[u8] = b" 23 | #version 150 core 24 | out vec4 out_color; 25 | 26 | uniform sampler2D s_texture; 27 | 28 | in vec2 v_tex_coord; 29 | in vec3 v_color; 30 | 31 | void main() { 32 | vec4 tex_color = texture(s_texture, v_tex_coord); 33 | if(tex_color.a == 0.0) // Discard transparent pixels. 34 | discard; 35 | out_color = tex_color * vec4(v_color, 1.0); 36 | } 37 | "; 38 | 39 | gfx_pipeline!( pipe { 40 | vbuf: gfx::VertexBuffer = (), 41 | transform: gfx::Global<[[f32; 4]; 4]> = "u_projection", 42 | view: gfx::Global<[[f32; 4]; 4]> = "u_view", 43 | color: gfx::TextureSampler<[f32; 4]> = "s_texture", 44 | out_color: gfx::RenderTarget = "out_color", 45 | out_depth: gfx::DepthTarget = 46 | gfx::preset::depth::LESS_EQUAL_WRITE, 47 | }); 48 | 49 | gfx_vertex_struct!(Vertex { 50 | xyz: [f32; 3] = "at_position", 51 | uv: [f32; 2] = "at_tex_coord", 52 | rgb: [f32; 3] = "at_color", 53 | }); 54 | 55 | pub struct Renderer, C: gfx::CommandBuffer> { 56 | factory: F, 57 | pub pipe: gfx::PipelineState, 58 | data: pipe::Data, 59 | encoder: gfx::Encoder, 60 | clear_color: [f32; 4], 61 | clear_depth: f32, 62 | clear_stencil: u8, 63 | slice: gfx::Slice, 64 | } 65 | 66 | impl, C: gfx::CommandBuffer> Renderer { 67 | pub fn new( 68 | mut factory: F, 69 | encoder: gfx::Encoder, 70 | target: gfx::handle::RenderTargetView, 71 | depth: gfx::handle::DepthStencilView, 72 | tex: gfx::handle::Texture, 73 | ) -> Renderer { 74 | let sampler = factory.create_sampler(gfx::texture::SamplerInfo::new( 75 | gfx::texture::FilterMethod::Scale, 76 | gfx::texture::WrapMode::Tile, 77 | )); 78 | 79 | let texture_view = factory 80 | .view_texture_as_shader_resource::( 81 | &tex, 82 | (0, 0), 83 | gfx::format::Swizzle::new(), 84 | ) 85 | .unwrap(); 86 | 87 | let prog = factory.link_program(VERTEX, FRAGMENT).unwrap(); 88 | 89 | let mut rasterizer = gfx::state::Rasterizer::new_fill(); 90 | rasterizer.front_face = gfx::state::FrontFace::Clockwise; 91 | let pipe = factory 92 | .create_pipeline_from_program( 93 | &prog, 94 | gfx::Primitive::TriangleList, 95 | rasterizer, 96 | pipe::new(), 97 | ) 98 | .unwrap(); 99 | 100 | let vbuf = factory.create_vertex_buffer(&[]); 101 | let slice = gfx::Slice::new_match_vertex_buffer(&vbuf); 102 | 103 | let data = pipe::Data { 104 | vbuf, 105 | transform: vecmath::mat4_id(), 106 | view: vecmath::mat4_id(), 107 | color: (texture_view, sampler), 108 | out_color: target, 109 | out_depth: depth, 110 | }; 111 | 112 | Renderer { 113 | factory, 114 | pipe, 115 | data, 116 | encoder, 117 | clear_color: [0.81, 0.8, 1.0, 1.0], 118 | clear_depth: 1.0, 119 | clear_stencil: 0, 120 | slice, 121 | } 122 | } 123 | 124 | pub fn set_projection(&mut self, proj_mat: Matrix4) { 125 | self.data.transform = proj_mat; 126 | } 127 | 128 | pub fn set_view(&mut self, view_mat: Matrix4) { 129 | self.data.view = view_mat; 130 | } 131 | 132 | pub fn clear(&mut self) { 133 | self.encoder.clear(&self.data.out_color, self.clear_color); 134 | self.encoder 135 | .clear_depth(&self.data.out_depth, self.clear_depth); 136 | self.encoder 137 | .clear_stencil(&self.data.out_depth, self.clear_stencil); 138 | } 139 | 140 | pub fn flush + Sized>( 141 | &mut self, 142 | device: &mut D, 143 | ) { 144 | self.encoder.flush(device); 145 | } 146 | 147 | pub fn create_buffer(&mut self, data: &[Vertex]) -> gfx::handle::Buffer { 148 | let vbuf = self.factory.create_vertex_buffer(data); 149 | self.slice = gfx::Slice::new_match_vertex_buffer(&vbuf); 150 | 151 | vbuf 152 | } 153 | 154 | pub fn render(&mut self, buffer: &mut gfx::handle::Buffer) { 155 | self.data.vbuf = buffer.clone(); 156 | self.slice.end = buffer.len() as u32; 157 | self.encoder.draw(&self.slice, &self.pipe, &self.data); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/tools/DumpData.java: -------------------------------------------------------------------------------- 1 | import java.util.Map; 2 | 3 | // Updated for 1.8-pre2. 4 | // Follow the grep commands to update obfuscated class names. 5 | 6 | public class DumpData { 7 | public static void main(String[] args) { 8 | // grep -C1 'static boolean . = false;' * | grep 'static final Logger . = LogManager\.getLogger();' # od 9 | od.c(); 10 | // grep '"textures/atlas/blocks.png"' * # cty 11 | // grep 'private final cty b;' * # cxi 12 | cxi manager = new cxi(new cty("textures")); 13 | Map block_to_blockstate = manager.c().a().a(); 14 | 15 | System.out.print("// (name, temperature, humidity)\n"); 16 | System.out.print("pub static BIOMES: [Option<(&'static str, f32, f32)>, ..256] = ["); 17 | int none_trail_len = 0; 18 | // grep Swampland * # ark 19 | for(ark biome : ark.n()) { 20 | if(biome == null) { 21 | if((none_trail_len % 16) == 0) 22 | System.out.print("\n None,"); 23 | else 24 | System.out.print(" None,"); 25 | none_trail_len++; 26 | } else { 27 | System.out.printf("\n Some((\"%s\", %.1f, %.1f)),", biome.ah, biome.ap, biome.aq); 28 | none_trail_len = 0; 29 | } 30 | } 31 | System.out.print("\n];\n\n"); 32 | 33 | System.out.print("// (id, name, variant)\n"); 34 | System.out.print("pub static BLOCK_STATES: &'static [(u16, &'static str, &'static str)] = &[\n"); 35 | // grep 'new \w*("air");' * # atp 36 | for(Object o : atp.d) { 37 | int id = atp.d.b(o); 38 | // grep '?"normal":' * # cxj 39 | cxj path = (cxj)block_to_blockstate.get(o); 40 | if(path == null || !path.b().equals("minecraft")) 41 | System.out.printf(" // %04x: \"%s\" (%s)\n", id, o, path); 42 | else 43 | System.out.printf(" (0x%04x, \"%s\", \"%s\"),\n", id, path.a(), path.c()); 44 | } 45 | System.out.print("];\n"); 46 | } 47 | } 48 | --------------------------------------------------------------------------------