diff options
| author | salmonik <raisersoft@proton.me> | 2026-07-09 23:27:55 +0200 |
|---|---|---|
| committer | salmonik <raisersoft@proton.me> | 2026-07-09 23:27:55 +0200 |
| commit | 3460d889aa2e7af1a60d218a1a8589027b4e4e63 (patch) | |
| tree | 89e66acd05fba086835337bfa95b36710dc8c4da | |
| download | dungeon-3460d889aa2e7af1a60d218a1a8589027b4e4e63.tar.gz dungeon-3460d889aa2e7af1a60d218a1a8589027b4e4e63.zip | |
init
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | .zed/tasks.json | 14 | ||||
| -rw-r--r-- | Cargo.lock | 783 | ||||
| -rw-r--r-- | Cargo.toml | 8 | ||||
| -rw-r--r-- | src/game.rs | 204 | ||||
| -rw-r--r-- | src/main.rs | 90 | ||||
| -rw-r--r-- | src/renderer.rs | 196 | ||||
| -rw-r--r-- | src/texture.rs | 102 |
8 files changed, 1398 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore | |||
| @@ -0,0 +1 @@ | |||
| /target | |||
diff --git a/.zed/tasks.json b/.zed/tasks.json new file mode 100644 index 0000000..090709f --- /dev/null +++ b/.zed/tasks.json | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | [ | ||
| 2 | { | ||
| 3 | "label": "run release", | ||
| 4 | "command": "cargo r -r", | ||
| 5 | "show_command": false, | ||
| 6 | "show_summary": false, | ||
| 7 | }, | ||
| 8 | { | ||
| 9 | "label": "run debug", | ||
| 10 | "command": "cargo r", | ||
| 11 | "show_command": false, | ||
| 12 | "show_summary": false, | ||
| 13 | }, | ||
| 14 | ] | ||
diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..1d07e99 --- /dev/null +++ b/Cargo.lock | |||
| @@ -0,0 +1,783 @@ | |||
| 1 | # This file is automatically @generated by Cargo. | ||
| 2 | # It is not intended for manual editing. | ||
| 3 | version = 4 | ||
| 4 | |||
| 5 | [[package]] | ||
| 6 | name = "autocfg" | ||
| 7 | version = "1.5.1" | ||
| 8 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 9 | checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" | ||
| 10 | |||
| 11 | [[package]] | ||
| 12 | name = "bitflags" | ||
| 13 | version = "1.3.2" | ||
| 14 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 15 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" | ||
| 16 | |||
| 17 | [[package]] | ||
| 18 | name = "bitflags" | ||
| 19 | version = "2.13.0" | ||
| 20 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 21 | checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" | ||
| 22 | |||
| 23 | [[package]] | ||
| 24 | name = "bumpalo" | ||
| 25 | version = "3.20.3" | ||
| 26 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 27 | checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" | ||
| 28 | |||
| 29 | [[package]] | ||
| 30 | name = "cc" | ||
| 31 | version = "1.2.66" | ||
| 32 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 33 | checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" | ||
| 34 | dependencies = [ | ||
| 35 | "find-msvc-tools", | ||
| 36 | "shlex", | ||
| 37 | ] | ||
| 38 | |||
| 39 | [[package]] | ||
| 40 | name = "cfg-if" | ||
| 41 | version = "1.0.4" | ||
| 42 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 43 | checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" | ||
| 44 | |||
| 45 | [[package]] | ||
| 46 | name = "dlib" | ||
| 47 | version = "0.5.3" | ||
| 48 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 49 | checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" | ||
| 50 | dependencies = [ | ||
| 51 | "libloading", | ||
| 52 | ] | ||
| 53 | |||
| 54 | [[package]] | ||
| 55 | name = "doom" | ||
| 56 | version = "0.1.0" | ||
| 57 | dependencies = [ | ||
| 58 | "minifb", | ||
| 59 | "rand", | ||
| 60 | ] | ||
| 61 | |||
| 62 | [[package]] | ||
| 63 | name = "downcast-rs" | ||
| 64 | version = "1.2.1" | ||
| 65 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 66 | checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" | ||
| 67 | |||
| 68 | [[package]] | ||
| 69 | name = "errno" | ||
| 70 | version = "0.3.14" | ||
| 71 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 72 | checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" | ||
| 73 | dependencies = [ | ||
| 74 | "libc", | ||
| 75 | "windows-sys", | ||
| 76 | ] | ||
| 77 | |||
| 78 | [[package]] | ||
| 79 | name = "fastrand" | ||
| 80 | version = "2.4.1" | ||
| 81 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 82 | checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" | ||
| 83 | |||
| 84 | [[package]] | ||
| 85 | name = "find-msvc-tools" | ||
| 86 | version = "0.1.9" | ||
| 87 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 88 | checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" | ||
| 89 | |||
| 90 | [[package]] | ||
| 91 | name = "futures" | ||
| 92 | version = "0.3.32" | ||
| 93 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 94 | checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" | ||
| 95 | dependencies = [ | ||
| 96 | "futures-channel", | ||
| 97 | "futures-core", | ||
| 98 | "futures-executor", | ||
| 99 | "futures-io", | ||
| 100 | "futures-sink", | ||
| 101 | "futures-task", | ||
| 102 | "futures-util", | ||
| 103 | ] | ||
| 104 | |||
| 105 | [[package]] | ||
| 106 | name = "futures-channel" | ||
| 107 | version = "0.3.32" | ||
| 108 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 109 | checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" | ||
| 110 | dependencies = [ | ||
| 111 | "futures-core", | ||
| 112 | "futures-sink", | ||
| 113 | ] | ||
| 114 | |||
| 115 | [[package]] | ||
| 116 | name = "futures-core" | ||
| 117 | version = "0.3.32" | ||
| 118 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 119 | checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" | ||
| 120 | |||
| 121 | [[package]] | ||
| 122 | name = "futures-executor" | ||
| 123 | version = "0.3.32" | ||
| 124 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 125 | checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" | ||
| 126 | dependencies = [ | ||
| 127 | "futures-core", | ||
| 128 | "futures-task", | ||
| 129 | "futures-util", | ||
| 130 | ] | ||
| 131 | |||
| 132 | [[package]] | ||
| 133 | name = "futures-io" | ||
| 134 | version = "0.3.32" | ||
| 135 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 136 | checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" | ||
| 137 | |||
| 138 | [[package]] | ||
| 139 | name = "futures-macro" | ||
| 140 | version = "0.3.32" | ||
| 141 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 142 | checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" | ||
| 143 | dependencies = [ | ||
| 144 | "proc-macro2", | ||
| 145 | "quote", | ||
| 146 | "syn", | ||
| 147 | ] | ||
| 148 | |||
| 149 | [[package]] | ||
| 150 | name = "futures-sink" | ||
| 151 | version = "0.3.32" | ||
| 152 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 153 | checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" | ||
| 154 | |||
| 155 | [[package]] | ||
| 156 | name = "futures-task" | ||
| 157 | version = "0.3.32" | ||
| 158 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 159 | checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" | ||
| 160 | |||
| 161 | [[package]] | ||
| 162 | name = "futures-util" | ||
| 163 | version = "0.3.32" | ||
| 164 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 165 | checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" | ||
| 166 | dependencies = [ | ||
| 167 | "futures-channel", | ||
| 168 | "futures-core", | ||
| 169 | "futures-io", | ||
| 170 | "futures-macro", | ||
| 171 | "futures-sink", | ||
| 172 | "futures-task", | ||
| 173 | "memchr", | ||
| 174 | "pin-project-lite", | ||
| 175 | "slab", | ||
| 176 | ] | ||
| 177 | |||
| 178 | [[package]] | ||
| 179 | name = "getrandom" | ||
| 180 | version = "0.2.17" | ||
| 181 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 182 | checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" | ||
| 183 | dependencies = [ | ||
| 184 | "cfg-if", | ||
| 185 | "libc", | ||
| 186 | "wasi", | ||
| 187 | ] | ||
| 188 | |||
| 189 | [[package]] | ||
| 190 | name = "getrandom" | ||
| 191 | version = "0.4.3" | ||
| 192 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 193 | checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" | ||
| 194 | dependencies = [ | ||
| 195 | "cfg-if", | ||
| 196 | "libc", | ||
| 197 | "r-efi", | ||
| 198 | ] | ||
| 199 | |||
| 200 | [[package]] | ||
| 201 | name = "instant" | ||
| 202 | version = "0.1.13" | ||
| 203 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 204 | checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" | ||
| 205 | dependencies = [ | ||
| 206 | "cfg-if", | ||
| 207 | "js-sys", | ||
| 208 | "wasm-bindgen", | ||
| 209 | "web-sys", | ||
| 210 | ] | ||
| 211 | |||
| 212 | [[package]] | ||
| 213 | name = "js-sys" | ||
| 214 | version = "0.3.103" | ||
| 215 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 216 | checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" | ||
| 217 | dependencies = [ | ||
| 218 | "cfg-if", | ||
| 219 | "futures-util", | ||
| 220 | "wasm-bindgen", | ||
| 221 | ] | ||
| 222 | |||
| 223 | [[package]] | ||
| 224 | name = "lazy_static" | ||
| 225 | version = "1.5.0" | ||
| 226 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 227 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" | ||
| 228 | |||
| 229 | [[package]] | ||
| 230 | name = "libc" | ||
| 231 | version = "0.2.186" | ||
| 232 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 233 | checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" | ||
| 234 | |||
| 235 | [[package]] | ||
| 236 | name = "libloading" | ||
| 237 | version = "0.8.9" | ||
| 238 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 239 | checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" | ||
| 240 | dependencies = [ | ||
| 241 | "cfg-if", | ||
| 242 | "windows-link", | ||
| 243 | ] | ||
| 244 | |||
| 245 | [[package]] | ||
| 246 | name = "libredox" | ||
| 247 | version = "0.1.18" | ||
| 248 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 249 | checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" | ||
| 250 | dependencies = [ | ||
| 251 | "bitflags 2.13.0", | ||
| 252 | "libc", | ||
| 253 | "plain", | ||
| 254 | "redox_syscall", | ||
| 255 | ] | ||
| 256 | |||
| 257 | [[package]] | ||
| 258 | name = "linux-raw-sys" | ||
| 259 | version = "0.12.1" | ||
| 260 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 261 | checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" | ||
| 262 | |||
| 263 | [[package]] | ||
| 264 | name = "memchr" | ||
| 265 | version = "2.8.3" | ||
| 266 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 267 | checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" | ||
| 268 | |||
| 269 | [[package]] | ||
| 270 | name = "memoffset" | ||
| 271 | version = "0.6.5" | ||
| 272 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 273 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" | ||
| 274 | dependencies = [ | ||
| 275 | "autocfg", | ||
| 276 | ] | ||
| 277 | |||
| 278 | [[package]] | ||
| 279 | name = "minifb" | ||
| 280 | version = "0.27.0" | ||
| 281 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 282 | checksum = "b0c470a74618b43cd182c21b3dc1e6123501249f3bad9a0085e95d1304ca2478" | ||
| 283 | dependencies = [ | ||
| 284 | "cc", | ||
| 285 | "dlib", | ||
| 286 | "futures", | ||
| 287 | "instant", | ||
| 288 | "js-sys", | ||
| 289 | "lazy_static", | ||
| 290 | "libc", | ||
| 291 | "orbclient", | ||
| 292 | "raw-window-handle", | ||
| 293 | "serde", | ||
| 294 | "serde_derive", | ||
| 295 | "tempfile", | ||
| 296 | "wasm-bindgen-futures", | ||
| 297 | "wayland-client", | ||
| 298 | "wayland-cursor", | ||
| 299 | "wayland-protocols", | ||
| 300 | "winapi", | ||
| 301 | "x11-dl", | ||
| 302 | ] | ||
| 303 | |||
| 304 | [[package]] | ||
| 305 | name = "nix" | ||
| 306 | version = "0.24.3" | ||
| 307 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 308 | checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" | ||
| 309 | dependencies = [ | ||
| 310 | "bitflags 1.3.2", | ||
| 311 | "cfg-if", | ||
| 312 | "libc", | ||
| 313 | "memoffset", | ||
| 314 | ] | ||
| 315 | |||
| 316 | [[package]] | ||
| 317 | name = "once_cell" | ||
| 318 | version = "1.21.4" | ||
| 319 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 320 | checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" | ||
| 321 | |||
| 322 | [[package]] | ||
| 323 | name = "orbclient" | ||
| 324 | version = "0.3.55" | ||
| 325 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 326 | checksum = "5df339f526ea9a60e371768d50efc2f2508c7203290731565d1f7a6f71d21747" | ||
| 327 | dependencies = [ | ||
| 328 | "libc", | ||
| 329 | "libredox", | ||
| 330 | "sdl2", | ||
| 331 | ] | ||
| 332 | |||
| 333 | [[package]] | ||
| 334 | name = "pin-project-lite" | ||
| 335 | version = "0.2.17" | ||
| 336 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 337 | checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" | ||
| 338 | |||
| 339 | [[package]] | ||
| 340 | name = "pkg-config" | ||
| 341 | version = "0.3.33" | ||
| 342 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 343 | checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" | ||
| 344 | |||
| 345 | [[package]] | ||
| 346 | name = "plain" | ||
| 347 | version = "0.2.3" | ||
| 348 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 349 | checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" | ||
| 350 | |||
| 351 | [[package]] | ||
| 352 | name = "ppv-lite86" | ||
| 353 | version = "0.2.21" | ||
| 354 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 355 | checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" | ||
| 356 | dependencies = [ | ||
| 357 | "zerocopy", | ||
| 358 | ] | ||
| 359 | |||
| 360 | [[package]] | ||
| 361 | name = "proc-macro2" | ||
| 362 | version = "1.0.106" | ||
| 363 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 364 | checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" | ||
| 365 | dependencies = [ | ||
| 366 | "unicode-ident", | ||
| 367 | ] | ||
| 368 | |||
| 369 | [[package]] | ||
| 370 | name = "quote" | ||
| 371 | version = "1.0.46" | ||
| 372 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 373 | checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" | ||
| 374 | dependencies = [ | ||
| 375 | "proc-macro2", | ||
| 376 | ] | ||
| 377 | |||
| 378 | [[package]] | ||
| 379 | name = "r-efi" | ||
| 380 | version = "6.0.0" | ||
| 381 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 382 | checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" | ||
| 383 | |||
| 384 | [[package]] | ||
| 385 | name = "rand" | ||
| 386 | version = "0.8.6" | ||
| 387 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 388 | checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" | ||
| 389 | dependencies = [ | ||
| 390 | "libc", | ||
| 391 | "rand_chacha", | ||
| 392 | "rand_core", | ||
| 393 | ] | ||
| 394 | |||
| 395 | [[package]] | ||
| 396 | name = "rand_chacha" | ||
| 397 | version = "0.3.1" | ||
| 398 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 399 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" | ||
| 400 | dependencies = [ | ||
| 401 | "ppv-lite86", | ||
| 402 | "rand_core", | ||
| 403 | ] | ||
| 404 | |||
| 405 | [[package]] | ||
| 406 | name = "rand_core" | ||
| 407 | version = "0.6.4" | ||
| 408 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 409 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" | ||
| 410 | dependencies = [ | ||
| 411 | "getrandom 0.2.17", | ||
| 412 | ] | ||
| 413 | |||
| 414 | [[package]] | ||
| 415 | name = "raw-window-handle" | ||
| 416 | version = "0.6.2" | ||
| 417 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 418 | checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" | ||
| 419 | |||
| 420 | [[package]] | ||
| 421 | name = "redox_syscall" | ||
| 422 | version = "0.9.0" | ||
| 423 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 424 | checksum = "c5102a6aaa05aa011a238e178e6bca86d2cb56fc9f586d37cb80f5bca6e07759" | ||
| 425 | dependencies = [ | ||
| 426 | "bitflags 2.13.0", | ||
| 427 | ] | ||
| 428 | |||
| 429 | [[package]] | ||
| 430 | name = "rustix" | ||
| 431 | version = "1.1.4" | ||
| 432 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 433 | checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" | ||
| 434 | dependencies = [ | ||
| 435 | "bitflags 2.13.0", | ||
| 436 | "errno", | ||
| 437 | "libc", | ||
| 438 | "linux-raw-sys", | ||
| 439 | "windows-sys", | ||
| 440 | ] | ||
| 441 | |||
| 442 | [[package]] | ||
| 443 | name = "rustversion" | ||
| 444 | version = "1.0.23" | ||
| 445 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 446 | checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" | ||
| 447 | |||
| 448 | [[package]] | ||
| 449 | name = "scoped-tls" | ||
| 450 | version = "1.0.1" | ||
| 451 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 452 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" | ||
| 453 | |||
| 454 | [[package]] | ||
| 455 | name = "sdl2" | ||
| 456 | version = "0.38.0" | ||
| 457 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 458 | checksum = "2d42407afc6a8ab67e36f92e80b8ba34cbdc55aaeed05249efe9a2e8d0e9feef" | ||
| 459 | dependencies = [ | ||
| 460 | "bitflags 1.3.2", | ||
| 461 | "lazy_static", | ||
| 462 | "libc", | ||
| 463 | "sdl2-sys", | ||
| 464 | ] | ||
| 465 | |||
| 466 | [[package]] | ||
| 467 | name = "sdl2-sys" | ||
| 468 | version = "0.38.0" | ||
| 469 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 470 | checksum = "3ff61407fc75d4b0bbc93dc7e4d6c196439965fbef8e4a4f003a36095823eac0" | ||
| 471 | dependencies = [ | ||
| 472 | "cfg-if", | ||
| 473 | "libc", | ||
| 474 | "version-compare", | ||
| 475 | ] | ||
| 476 | |||
| 477 | [[package]] | ||
| 478 | name = "serde" | ||
| 479 | version = "1.0.228" | ||
| 480 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 481 | checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" | ||
| 482 | dependencies = [ | ||
| 483 | "serde_core", | ||
| 484 | "serde_derive", | ||
| 485 | ] | ||
| 486 | |||
| 487 | [[package]] | ||
| 488 | name = "serde_core" | ||
| 489 | version = "1.0.228" | ||
| 490 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 491 | checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" | ||
| 492 | dependencies = [ | ||
| 493 | "serde_derive", | ||
| 494 | ] | ||
| 495 | |||
| 496 | [[package]] | ||
| 497 | name = "serde_derive" | ||
| 498 | version = "1.0.228" | ||
| 499 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 500 | checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" | ||
| 501 | dependencies = [ | ||
| 502 | "proc-macro2", | ||
| 503 | "quote", | ||
| 504 | "syn", | ||
| 505 | ] | ||
| 506 | |||
| 507 | [[package]] | ||
| 508 | name = "shlex" | ||
| 509 | version = "2.0.1" | ||
| 510 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 511 | checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" | ||
| 512 | |||
| 513 | [[package]] | ||
| 514 | name = "slab" | ||
| 515 | version = "0.4.12" | ||
| 516 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 517 | checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" | ||
| 518 | |||
| 519 | [[package]] | ||
| 520 | name = "smallvec" | ||
| 521 | version = "1.15.2" | ||
| 522 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 523 | checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" | ||
| 524 | |||
| 525 | [[package]] | ||
| 526 | name = "syn" | ||
| 527 | version = "2.0.118" | ||
| 528 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 529 | checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" | ||
| 530 | dependencies = [ | ||
| 531 | "proc-macro2", | ||
| 532 | "quote", | ||
| 533 | "unicode-ident", | ||
| 534 | ] | ||
| 535 | |||
| 536 | [[package]] | ||
| 537 | name = "tempfile" | ||
| 538 | version = "3.27.0" | ||
| 539 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 540 | checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" | ||
| 541 | dependencies = [ | ||
| 542 | "fastrand", | ||
| 543 | "getrandom 0.4.3", | ||
| 544 | "once_cell", | ||
| 545 | "rustix", | ||
| 546 | "windows-sys", | ||
| 547 | ] | ||
| 548 | |||
| 549 | [[package]] | ||
| 550 | name = "unicode-ident" | ||
| 551 | version = "1.0.24" | ||
| 552 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 553 | checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" | ||
| 554 | |||
| 555 | [[package]] | ||
| 556 | name = "version-compare" | ||
| 557 | version = "0.1.1" | ||
| 558 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 559 | checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" | ||
| 560 | |||
| 561 | [[package]] | ||
| 562 | name = "wasi" | ||
| 563 | version = "0.11.1+wasi-snapshot-preview1" | ||
| 564 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 565 | checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" | ||
| 566 | |||
| 567 | [[package]] | ||
| 568 | name = "wasm-bindgen" | ||
| 569 | version = "0.2.126" | ||
| 570 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 571 | checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" | ||
| 572 | dependencies = [ | ||
| 573 | "cfg-if", | ||
| 574 | "once_cell", | ||
| 575 | "rustversion", | ||
| 576 | "wasm-bindgen-macro", | ||
| 577 | "wasm-bindgen-shared", | ||
| 578 | ] | ||
| 579 | |||
| 580 | [[package]] | ||
| 581 | name = "wasm-bindgen-futures" | ||
| 582 | version = "0.4.76" | ||
| 583 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 584 | checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" | ||
| 585 | dependencies = [ | ||
| 586 | "js-sys", | ||
| 587 | "wasm-bindgen", | ||
| 588 | ] | ||
| 589 | |||
| 590 | [[package]] | ||
| 591 | name = "wasm-bindgen-macro" | ||
| 592 | version = "0.2.126" | ||
| 593 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 594 | checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" | ||
| 595 | dependencies = [ | ||
| 596 | "quote", | ||
| 597 | "wasm-bindgen-macro-support", | ||
| 598 | ] | ||
| 599 | |||
| 600 | [[package]] | ||
| 601 | name = "wasm-bindgen-macro-support" | ||
| 602 | version = "0.2.126" | ||
| 603 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 604 | checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" | ||
| 605 | dependencies = [ | ||
| 606 | "bumpalo", | ||
| 607 | "proc-macro2", | ||
| 608 | "quote", | ||
| 609 | "syn", | ||
| 610 | "wasm-bindgen-shared", | ||
| 611 | ] | ||
| 612 | |||
| 613 | [[package]] | ||
| 614 | name = "wasm-bindgen-shared" | ||
| 615 | version = "0.2.126" | ||
| 616 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 617 | checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" | ||
| 618 | dependencies = [ | ||
| 619 | "unicode-ident", | ||
| 620 | ] | ||
| 621 | |||
| 622 | [[package]] | ||
| 623 | name = "wayland-client" | ||
| 624 | version = "0.29.5" | ||
| 625 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 626 | checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" | ||
| 627 | dependencies = [ | ||
| 628 | "bitflags 1.3.2", | ||
| 629 | "downcast-rs", | ||
| 630 | "libc", | ||
| 631 | "nix", | ||
| 632 | "scoped-tls", | ||
| 633 | "wayland-commons", | ||
| 634 | "wayland-scanner", | ||
| 635 | "wayland-sys", | ||
| 636 | ] | ||
| 637 | |||
| 638 | [[package]] | ||
| 639 | name = "wayland-commons" | ||
| 640 | version = "0.29.5" | ||
| 641 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 642 | checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" | ||
| 643 | dependencies = [ | ||
| 644 | "nix", | ||
| 645 | "once_cell", | ||
| 646 | "smallvec", | ||
| 647 | "wayland-sys", | ||
| 648 | ] | ||
| 649 | |||
| 650 | [[package]] | ||
| 651 | name = "wayland-cursor" | ||
| 652 | version = "0.29.5" | ||
| 653 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 654 | checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" | ||
| 655 | dependencies = [ | ||
| 656 | "nix", | ||
| 657 | "wayland-client", | ||
| 658 | "xcursor", | ||
| 659 | ] | ||
| 660 | |||
| 661 | [[package]] | ||
| 662 | name = "wayland-protocols" | ||
| 663 | version = "0.29.5" | ||
| 664 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 665 | checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" | ||
| 666 | dependencies = [ | ||
| 667 | "bitflags 1.3.2", | ||
| 668 | "wayland-client", | ||
| 669 | "wayland-commons", | ||
| 670 | "wayland-scanner", | ||
| 671 | ] | ||
| 672 | |||
| 673 | [[package]] | ||
| 674 | name = "wayland-scanner" | ||
| 675 | version = "0.29.5" | ||
| 676 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 677 | checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" | ||
| 678 | dependencies = [ | ||
| 679 | "proc-macro2", | ||
| 680 | "quote", | ||
| 681 | "xml-rs", | ||
| 682 | ] | ||
| 683 | |||
| 684 | [[package]] | ||
| 685 | name = "wayland-sys" | ||
| 686 | version = "0.29.5" | ||
| 687 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 688 | checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" | ||
| 689 | dependencies = [ | ||
| 690 | "dlib", | ||
| 691 | "lazy_static", | ||
| 692 | "pkg-config", | ||
| 693 | ] | ||
| 694 | |||
| 695 | [[package]] | ||
| 696 | name = "web-sys" | ||
| 697 | version = "0.3.103" | ||
| 698 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 699 | checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" | ||
| 700 | dependencies = [ | ||
| 701 | "js-sys", | ||
| 702 | "wasm-bindgen", | ||
| 703 | ] | ||
| 704 | |||
| 705 | [[package]] | ||
| 706 | name = "winapi" | ||
| 707 | version = "0.3.9" | ||
| 708 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 709 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" | ||
| 710 | dependencies = [ | ||
| 711 | "winapi-i686-pc-windows-gnu", | ||
| 712 | "winapi-x86_64-pc-windows-gnu", | ||
| 713 | ] | ||
| 714 | |||
| 715 | [[package]] | ||
| 716 | name = "winapi-i686-pc-windows-gnu" | ||
| 717 | version = "0.4.0" | ||
| 718 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 719 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" | ||
| 720 | |||
| 721 | [[package]] | ||
| 722 | name = "winapi-x86_64-pc-windows-gnu" | ||
| 723 | version = "0.4.0" | ||
| 724 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 725 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" | ||
| 726 | |||
| 727 | [[package]] | ||
| 728 | name = "windows-link" | ||
| 729 | version = "0.2.1" | ||
| 730 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 731 | checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" | ||
| 732 | |||
| 733 | [[package]] | ||
| 734 | name = "windows-sys" | ||
| 735 | version = "0.61.2" | ||
| 736 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 737 | checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" | ||
| 738 | dependencies = [ | ||
| 739 | "windows-link", | ||
| 740 | ] | ||
| 741 | |||
| 742 | [[package]] | ||
| 743 | name = "x11-dl" | ||
| 744 | version = "2.21.0" | ||
| 745 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 746 | checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" | ||
| 747 | dependencies = [ | ||
| 748 | "libc", | ||
| 749 | "once_cell", | ||
| 750 | "pkg-config", | ||
| 751 | ] | ||
| 752 | |||
| 753 | [[package]] | ||
| 754 | name = "xcursor" | ||
| 755 | version = "0.3.10" | ||
| 756 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 757 | checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" | ||
| 758 | |||
| 759 | [[package]] | ||
| 760 | name = "xml-rs" | ||
| 761 | version = "0.8.28" | ||
| 762 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 763 | checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" | ||
| 764 | |||
| 765 | [[package]] | ||
| 766 | name = "zerocopy" | ||
| 767 | version = "0.8.54" | ||
| 768 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 769 | checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" | ||
| 770 | dependencies = [ | ||
| 771 | "zerocopy-derive", | ||
| 772 | ] | ||
| 773 | |||
| 774 | [[package]] | ||
| 775 | name = "zerocopy-derive" | ||
| 776 | version = "0.8.54" | ||
| 777 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 778 | checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" | ||
| 779 | dependencies = [ | ||
| 780 | "proc-macro2", | ||
| 781 | "quote", | ||
| 782 | "syn", | ||
| 783 | ] | ||
diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b2d135e --- /dev/null +++ b/Cargo.toml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | [package] | ||
| 2 | name = "doom" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | |||
| 6 | [dependencies] | ||
| 7 | minifb = "0.27" | ||
| 8 | rand = "0.8" | ||
diff --git a/src/game.rs b/src/game.rs new file mode 100644 index 0000000..4bedecc --- /dev/null +++ b/src/game.rs | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | use rand::Rng; | ||
| 2 | |||
| 3 | // --------------- maze grid --------------- | ||
| 4 | |||
| 5 | #[derive(Clone, Copy, PartialEq, Eq)] | ||
| 6 | pub enum Cell { | ||
| 7 | Wall, | ||
| 8 | Passage, | ||
| 9 | Exit, | ||
| 10 | } | ||
| 11 | |||
| 12 | pub struct Maze { | ||
| 13 | cells: Vec<Cell>, | ||
| 14 | width: usize, | ||
| 15 | height: usize, | ||
| 16 | } | ||
| 17 | |||
| 18 | impl Maze { | ||
| 19 | /// Recursive-backtracker perfect maze. `room_w × room_h` is the logical | ||
| 20 | /// room count; the actual grid will be `(room_w*2+1) × (room_h*2+1)`. | ||
| 21 | pub fn generate(room_w: usize, room_h: usize, rng: &mut impl Rng) -> Self { | ||
| 22 | let w = room_w * 2 + 1; | ||
| 23 | let h = room_h * 2 + 1; | ||
| 24 | |||
| 25 | let mut cells = vec![Cell::Wall; w * h]; | ||
| 26 | cells[1 * w + 1] = Cell::Passage; | ||
| 27 | |||
| 28 | let mut stack = vec![(1usize, 1usize)]; | ||
| 29 | |||
| 30 | while let Some(&(cy, cx)) = stack.last() { | ||
| 31 | let mut unvisited = Vec::new(); | ||
| 32 | |||
| 33 | for (dy, dx) in [(-2isize, 0isize), (2, 0), (0, -2), (0, 2)] { | ||
| 34 | let ny = cy as isize + dy; | ||
| 35 | let nx = cx as isize + dx; | ||
| 36 | if ny >= 1 && ny < (h - 1) as isize && nx >= 1 && nx < (w - 1) as isize { | ||
| 37 | if cells[ny as usize * w + nx as usize] == Cell::Wall { | ||
| 38 | unvisited.push((ny as usize, nx as usize)); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | if unvisited.is_empty() { | ||
| 44 | stack.pop(); | ||
| 45 | } else { | ||
| 46 | let idx = rng.gen_range(0..unvisited.len()); | ||
| 47 | let (ny, nx) = unvisited[idx]; | ||
| 48 | |||
| 49 | // carve the wall between current cell and chosen neighbour | ||
| 50 | let wall_y = (cy + ny) / 2; | ||
| 51 | let wall_x = (cx + nx) / 2; | ||
| 52 | cells[wall_y * w + wall_x] = Cell::Passage; | ||
| 53 | cells[ny * w + nx] = Cell::Passage; | ||
| 54 | |||
| 55 | stack.push((ny, nx)); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | // ---- place exit in a far-away passage ---- | ||
| 60 | let mut passages: Vec<(f64, usize, usize)> = Vec::new(); | ||
| 61 | for y in (1..h).step_by(2) { | ||
| 62 | for x in (1..w).step_by(2) { | ||
| 63 | if cells[y * w + x] == Cell::Passage && !(y == 1 && x == 1) { | ||
| 64 | let dist = ((y as f64 - 1.0).powi(2) + (x as f64 - 1.0).powi(2)).sqrt(); | ||
| 65 | passages.push((dist, y, x)); | ||
| 66 | } | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | if !passages.is_empty() { | ||
| 71 | passages.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap()); | ||
| 72 | let far_count = (passages.len() / 4).max(1); | ||
| 73 | let idx = rng.gen_range(0..far_count); | ||
| 74 | let (_, ey, ex) = passages[idx]; | ||
| 75 | cells[ey * w + ex] = Cell::Exit; | ||
| 76 | } | ||
| 77 | |||
| 78 | Self { | ||
| 79 | cells, | ||
| 80 | width: w, | ||
| 81 | height: h, | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | #[inline] | ||
| 86 | pub fn is_wall(&self, y: usize, x: usize) -> bool { | ||
| 87 | self.cells | ||
| 88 | .get(y * self.width + x) | ||
| 89 | .map_or(true, |&c| c == Cell::Wall) | ||
| 90 | } | ||
| 91 | |||
| 92 | /// Floating-point query — out-of-bounds is treated as wall. | ||
| 93 | #[inline] | ||
| 94 | pub fn is_passage_at_float(&self, x: f64, y: f64) -> bool { | ||
| 95 | let xi = x as usize; | ||
| 96 | let yi = y as usize; | ||
| 97 | if xi >= self.width || yi >= self.height { | ||
| 98 | return false; | ||
| 99 | } | ||
| 100 | self.cells[yi * self.width + xi] != Cell::Wall | ||
| 101 | } | ||
| 102 | |||
| 103 | #[inline] | ||
| 104 | pub fn is_exit(&self, x: f64, y: f64) -> bool { | ||
| 105 | let xi = x as usize; | ||
| 106 | let yi = y as usize; | ||
| 107 | if xi >= self.width || yi >= self.height { | ||
| 108 | return false; | ||
| 109 | } | ||
| 110 | self.cells[yi * self.width + xi] == Cell::Exit | ||
| 111 | } | ||
| 112 | |||
| 113 | pub fn width(&self) -> usize { | ||
| 114 | self.width | ||
| 115 | } | ||
| 116 | pub fn height(&self) -> usize { | ||
| 117 | self.height | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | // --------------- player --------------- | ||
| 122 | |||
| 123 | pub struct Player { | ||
| 124 | pub x: f64, | ||
| 125 | pub y: f64, | ||
| 126 | pub angle: f64, // radians, 0 = +x (east), π/2 = +y (south) | ||
| 127 | } | ||
| 128 | |||
| 129 | impl Player { | ||
| 130 | pub fn new(x: f64, y: f64, angle: f64) -> Self { | ||
| 131 | Self { x, y, angle } | ||
| 132 | } | ||
| 133 | |||
| 134 | pub fn rotate(&mut self, delta: f64) { | ||
| 135 | self.angle = (self.angle + delta).rem_euclid(2.0 * std::f64::consts::PI); | ||
| 136 | } | ||
| 137 | |||
| 138 | /// Apply a raw (dx, dy) displacement with wall-sliding collision. | ||
| 139 | /// Checks are done per-axis so the player slides along walls naturally. | ||
| 140 | pub fn try_move(&mut self, dx: f64, dy: f64, maze: &Maze) { | ||
| 141 | let m = 0.35; // collision margin — keeps the camera out of walls | ||
| 142 | |||
| 143 | let nx = self.x + dx; | ||
| 144 | if maze.is_passage_at_float(nx + m, self.y + m) | ||
| 145 | && maze.is_passage_at_float(nx + m, self.y - m) | ||
| 146 | && maze.is_passage_at_float(nx - m, self.y + m) | ||
| 147 | && maze.is_passage_at_float(nx - m, self.y - m) | ||
| 148 | { | ||
| 149 | self.x = nx; | ||
| 150 | } | ||
| 151 | |||
| 152 | let ny = self.y + dy; | ||
| 153 | if maze.is_passage_at_float(self.x + m, ny + m) | ||
| 154 | && maze.is_passage_at_float(self.x - m, ny + m) | ||
| 155 | && maze.is_passage_at_float(self.x + m, ny - m) | ||
| 156 | && maze.is_passage_at_float(self.x - m, ny - m) | ||
| 157 | { | ||
| 158 | self.y = ny; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | // --------------- top-level game --------------- | ||
| 164 | |||
| 165 | pub struct Game { | ||
| 166 | pub maze: Maze, | ||
| 167 | pub player: Player, | ||
| 168 | pub wall_texture: Vec<u32>, | ||
| 169 | pub floor_texture: Vec<u32>, | ||
| 170 | } | ||
| 171 | |||
| 172 | impl Game { | ||
| 173 | pub fn new() -> Self { | ||
| 174 | let mut rng = rand::thread_rng(); | ||
| 175 | let maze = Maze::generate(16, 16, &mut rng); // 33×33 grid | ||
| 176 | let player = Player::new(1.5, 1.5, 0.0); // start centre of (1,1), facing east | ||
| 177 | let wall_texture = crate::texture::generate_wall_texture(&mut rng); | ||
| 178 | let floor_texture = crate::texture::generate_floor_texture(&mut rng); | ||
| 179 | |||
| 180 | Self { | ||
| 181 | maze, | ||
| 182 | player, | ||
| 183 | wall_texture, | ||
| 184 | floor_texture, | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | pub fn rotate(&mut self, delta: f64) { | ||
| 189 | self.player.rotate(delta); | ||
| 190 | } | ||
| 191 | |||
| 192 | /// Apply forward + strafe as a single combined displacement so that | ||
| 193 | /// diagonal wall-hugging is checked atomically (no two-step clip). | ||
| 194 | pub fn apply_movement(&mut self, forward: f64, strafe: f64) { | ||
| 195 | let a = self.player.angle; | ||
| 196 | let dx = a.cos() * forward + (a + std::f64::consts::FRAC_PI_2).cos() * strafe; | ||
| 197 | let dy = a.sin() * forward + (a + std::f64::consts::FRAC_PI_2).sin() * strafe; | ||
| 198 | self.player.try_move(dx, dy, &self.maze); | ||
| 199 | } | ||
| 200 | |||
| 201 | pub fn check_win(&self) -> bool { | ||
| 202 | self.maze.is_exit(self.player.x, self.player.y) | ||
| 203 | } | ||
| 204 | } | ||
diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..d51fdfd --- /dev/null +++ b/src/main.rs | |||
| @@ -0,0 +1,90 @@ | |||
| 1 | mod game; | ||
| 2 | mod renderer; | ||
| 3 | mod texture; | ||
| 4 | |||
| 5 | use game::Game; | ||
| 6 | use minifb::{Key, Window, WindowOptions}; | ||
| 7 | use renderer::Renderer; | ||
| 8 | use std::time::Instant; | ||
| 9 | |||
| 10 | const SCREEN_W: usize = 640; | ||
| 11 | const SCREEN_H: usize = 480; | ||
| 12 | |||
| 13 | fn main() { | ||
| 14 | println!("=== DOOM-LIKE MAZE ==="); | ||
| 15 | println!("Find the exit!"); | ||
| 16 | println!(" W / Up — forward"); | ||
| 17 | println!(" S / Down — backward"); | ||
| 18 | println!(" A / D — strafe left / right"); | ||
| 19 | println!(" ← / → — turn"); | ||
| 20 | println!(" Esc — quit\n"); | ||
| 21 | |||
| 22 | let mut game = Game::new(); | ||
| 23 | let renderer = Renderer::new(SCREEN_W, SCREEN_H); | ||
| 24 | |||
| 25 | let mut window = Window::new( | ||
| 26 | "Maze — Find the Exit!", | ||
| 27 | SCREEN_W, | ||
| 28 | SCREEN_H, | ||
| 29 | WindowOptions::default(), | ||
| 30 | ) | ||
| 31 | .expect("Failed to create window"); | ||
| 32 | |||
| 33 | let mut framebuffer = vec![0u32; SCREEN_W * SCREEN_H]; | ||
| 34 | let mut last = Instant::now(); | ||
| 35 | let frame_budget = std::time::Duration::from_micros(16600); // ~60 fps | ||
| 36 | |||
| 37 | while window.is_open() && !window.is_key_down(Key::Escape) { | ||
| 38 | let frame_start = Instant::now(); | ||
| 39 | let dt = (frame_start - last).as_secs_f64().min(0.1); | ||
| 40 | last = frame_start; | ||
| 41 | |||
| 42 | // ---- input ---- | ||
| 43 | let move_speed = 2.8; | ||
| 44 | let turn_speed = 2.8; | ||
| 45 | let strafe_speed = 2.2; | ||
| 46 | |||
| 47 | if window.is_key_down(Key::Left) { | ||
| 48 | game.rotate(-turn_speed * dt); | ||
| 49 | } | ||
| 50 | if window.is_key_down(Key::Right) { | ||
| 51 | game.rotate(turn_speed * dt); | ||
| 52 | } | ||
| 53 | // Combine forward + strafe into one displacement (prevents two-step | ||
| 54 | // wall clipping when pressing W+D / W+A near a wall). | ||
| 55 | let fwd = if window.is_key_down(Key::W) || window.is_key_down(Key::Up) { | ||
| 56 | move_speed * dt | ||
| 57 | } else if window.is_key_down(Key::S) || window.is_key_down(Key::Down) { | ||
| 58 | -move_speed * dt | ||
| 59 | } else { | ||
| 60 | 0.0 | ||
| 61 | }; | ||
| 62 | let strf = if window.is_key_down(Key::D) { | ||
| 63 | strafe_speed * dt | ||
| 64 | } else if window.is_key_down(Key::A) { | ||
| 65 | -strafe_speed * dt | ||
| 66 | } else { | ||
| 67 | 0.0 | ||
| 68 | }; | ||
| 69 | game.apply_movement(fwd, strf); | ||
| 70 | |||
| 71 | // ---- win condition ---- | ||
| 72 | if game.check_win() { | ||
| 73 | println!("🎉 You found the exit! Generating a new maze…"); | ||
| 74 | game = Game::new(); | ||
| 75 | last = Instant::now(); // avoid huge dt spike | ||
| 76 | } | ||
| 77 | |||
| 78 | // ---- render ---- | ||
| 79 | renderer.render(&game, &mut framebuffer); | ||
| 80 | window | ||
| 81 | .update_with_buffer(&framebuffer, SCREEN_W, SCREEN_H) | ||
| 82 | .unwrap(); | ||
| 83 | |||
| 84 | // Sleep the remainder of the frame budget (saves CPU). | ||
| 85 | let elapsed = frame_start.elapsed(); | ||
| 86 | if elapsed < frame_budget { | ||
| 87 | std::thread::sleep(frame_budget - elapsed); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | } | ||
diff --git a/src/renderer.rs b/src/renderer.rs new file mode 100644 index 0000000..0792537 --- /dev/null +++ b/src/renderer.rs | |||
| @@ -0,0 +1,196 @@ | |||
| 1 | use crate::game::Game; | ||
| 2 | use crate::texture::TEX_SIZE; | ||
| 3 | |||
| 4 | pub struct Renderer { | ||
| 5 | screen_w: usize, | ||
| 6 | screen_h: usize, | ||
| 7 | /// Precomputed: floor_dist_lut[row] = perpendicular distance to floor at that row. | ||
| 8 | floor_dist_lut: Vec<f64>, | ||
| 9 | /// Precomputed: floor_bright_lut[row] = brightness × 256 for that row (fixed-point). | ||
| 10 | floor_bright_lut: Vec<u32>, | ||
| 11 | } | ||
| 12 | |||
| 13 | impl Renderer { | ||
| 14 | pub fn new(screen_w: usize, screen_h: usize) -> Self { | ||
| 15 | let half_h = screen_h as f64 / 2.0; | ||
| 16 | let mut floor_dist_lut = vec![0.0f64; screen_h]; | ||
| 17 | let mut floor_bright_lut = vec![0u32; screen_h]; | ||
| 18 | |||
| 19 | // Only rows below the horizon have meaningful floor values. | ||
| 20 | for py in (screen_h / 2 + 1)..screen_h { | ||
| 21 | let dy = py as f64 - half_h; | ||
| 22 | let dist = 0.5 * screen_h as f64 / dy; | ||
| 23 | floor_dist_lut[py] = dist; | ||
| 24 | let bright = (1.0 / (1.0 + dist * 0.15)).max(0.05); | ||
| 25 | floor_bright_lut[py] = (bright * 256.0) as u32; | ||
| 26 | } | ||
| 27 | |||
| 28 | Self { | ||
| 29 | screen_w, | ||
| 30 | screen_h, | ||
| 31 | floor_dist_lut, | ||
| 32 | floor_bright_lut, | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | /// Produce one frame into `buffer` (packed `0xAARRGGBB`). | ||
| 37 | pub fn render(&self, game: &Game, buffer: &mut [u32]) { | ||
| 38 | buffer.fill(0xFF00_0000); // pure-black ceiling | ||
| 39 | |||
| 40 | let half_h = self.screen_h as f64 / 2.0; | ||
| 41 | let fov = std::f64::consts::PI / 3.0; // 60° | ||
| 42 | |||
| 43 | for sx in 0..self.screen_w { | ||
| 44 | let cam_x = 2.0 * sx as f64 / self.screen_w as f64 - 1.0; | ||
| 45 | let ray_angle = game.player.angle + (fov / 2.0) * cam_x; | ||
| 46 | let rdx = ray_angle.cos(); | ||
| 47 | let rdy = ray_angle.sin(); | ||
| 48 | |||
| 49 | // ---- DDA setup ------------------------------------------------- | ||
| 50 | let mut map_x = game.player.x as isize; | ||
| 51 | let mut map_y = game.player.y as isize; | ||
| 52 | |||
| 53 | let ddx = if rdx == 0.0 { | ||
| 54 | f64::MAX | ||
| 55 | } else { | ||
| 56 | (1.0 / rdx).abs() | ||
| 57 | }; | ||
| 58 | let ddy = if rdy == 0.0 { | ||
| 59 | f64::MAX | ||
| 60 | } else { | ||
| 61 | (1.0 / rdy).abs() | ||
| 62 | }; | ||
| 63 | |||
| 64 | let (step_x, mut side_x) = if rdx < 0.0 { | ||
| 65 | (-1isize, (game.player.x - map_x as f64) * ddx) | ||
| 66 | } else { | ||
| 67 | (1isize, (map_x as f64 + 1.0 - game.player.x) * ddx) | ||
| 68 | }; | ||
| 69 | |||
| 70 | let (step_y, mut side_y) = if rdy < 0.0 { | ||
| 71 | (-1isize, (game.player.y - map_y as f64) * ddy) | ||
| 72 | } else { | ||
| 73 | (1isize, (map_y as f64 + 1.0 - game.player.y) * ddy) | ||
| 74 | }; | ||
| 75 | |||
| 76 | let mut hit_side: bool; | ||
| 77 | let euclidean: f64; | ||
| 78 | |||
| 79 | // ---- DDA loop -------------------------------------------------- | ||
| 80 | loop { | ||
| 81 | if side_x < side_y { | ||
| 82 | side_x += ddx; | ||
| 83 | map_x += step_x; | ||
| 84 | hit_side = false; | ||
| 85 | } else { | ||
| 86 | side_y += ddy; | ||
| 87 | map_y += step_y; | ||
| 88 | hit_side = true; | ||
| 89 | } | ||
| 90 | |||
| 91 | if map_y < 0 | ||
| 92 | || map_y >= game.maze.height() as isize | ||
| 93 | || map_x < 0 | ||
| 94 | || map_x >= game.maze.width() as isize | ||
| 95 | { | ||
| 96 | euclidean = 1.0; | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | |||
| 100 | if game.maze.is_wall(map_y as usize, map_x as usize) { | ||
| 101 | euclidean = if !hit_side { | ||
| 102 | (map_x as f64 - game.player.x + (1.0 - step_x as f64) / 2.0) / rdx | ||
| 103 | } else { | ||
| 104 | (map_y as f64 - game.player.y + (1.0 - step_y as f64) / 2.0) / rdy | ||
| 105 | }; | ||
| 106 | break; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | // Fisheye correction | ||
| 111 | let perp_dist = (euclidean * (ray_angle - game.player.angle).cos().abs()).max(0.001); | ||
| 112 | |||
| 113 | // ---- wall slice ------------------------------------------------ | ||
| 114 | let wall_h = (self.screen_h as f64 / perp_dist) as isize; | ||
| 115 | let draw_start = ((-wall_h / 2) + self.screen_h as isize / 2).max(0) as usize; | ||
| 116 | let draw_end = ((wall_h / 2) + self.screen_h as isize / 2) | ||
| 117 | .min(self.screen_h as isize - 1) as usize; | ||
| 118 | |||
| 119 | // Texture x-coordinate (uses Euclidean, not perp) | ||
| 120 | let wall_x = if !hit_side { | ||
| 121 | game.player.y + euclidean * rdy | ||
| 122 | } else { | ||
| 123 | game.player.x + euclidean * rdx | ||
| 124 | }; | ||
| 125 | let wall_x = wall_x - wall_x.floor(); | ||
| 126 | let tex_x = ((wall_x * TEX_SIZE as f64) as usize).min(TEX_SIZE - 1); | ||
| 127 | |||
| 128 | // Hoist: brightness is identical for every pixel in this column | ||
| 129 | let wall_bright_fx = { | ||
| 130 | let b = (1.0 / (1.0 + perp_dist * 0.12)).max(0.08); | ||
| 131 | (b * 256.0) as u32 | ||
| 132 | }; | ||
| 133 | |||
| 134 | for py in draw_start..=draw_end { | ||
| 135 | let tex_y = ((py as f64 - half_h + wall_h as f64 / 2.0) * TEX_SIZE as f64 | ||
| 136 | / wall_h as f64) as usize; | ||
| 137 | let tex_y = tex_y.min(TEX_SIZE - 1); | ||
| 138 | |||
| 139 | let color = game.wall_texture[tex_y * TEX_SIZE + tex_x]; | ||
| 140 | buffer[py * self.screen_w + sx] = darken_fx(color, wall_bright_fx); | ||
| 141 | } | ||
| 142 | |||
| 143 | // ---- floor below the wall -------------------------------------- | ||
| 144 | let floor_start = draw_end + 1; | ||
| 145 | if floor_start < self.screen_h { | ||
| 146 | for py in floor_start..self.screen_h { | ||
| 147 | let floor_dist = self.floor_dist_lut[py]; | ||
| 148 | |||
| 149 | if floor_dist > 15.0 { | ||
| 150 | // Far floor → just a dark pixel, skip texture & world calc. | ||
| 151 | let gray = darken_fx(0xFF80_8080, self.floor_bright_lut[py]); | ||
| 152 | buffer[py * self.screen_w + sx] = gray; | ||
| 153 | } else { | ||
| 154 | let fx = game.player.x + floor_dist * rdx; | ||
| 155 | let fy = game.player.y + floor_dist * rdy; | ||
| 156 | |||
| 157 | let ftx = ((fx.fract().abs() * TEX_SIZE as f64) as usize).min(TEX_SIZE - 1); | ||
| 158 | let fty = ((fy.fract().abs() * TEX_SIZE as f64) as usize).min(TEX_SIZE - 1); | ||
| 159 | |||
| 160 | let color = game.floor_texture[fty * TEX_SIZE + ftx]; | ||
| 161 | buffer[py * self.screen_w + sx] = | ||
| 162 | darken_fx(color, self.floor_bright_lut[py]); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | // ---- crosshair ----------------------------------------------------- | ||
| 169 | let cx = self.screen_w / 2; | ||
| 170 | let cy = self.screen_h / 2; | ||
| 171 | let cross_color = 0xFF00_FF00; | ||
| 172 | for i in 0..=4isize { | ||
| 173 | if cy as isize - i >= 0 { | ||
| 174 | buffer[(cy - i as usize) * self.screen_w + cx] = cross_color; | ||
| 175 | } | ||
| 176 | if (cy + i as usize) < self.screen_h { | ||
| 177 | buffer[(cy + i as usize) * self.screen_w + cx] = cross_color; | ||
| 178 | } | ||
| 179 | if cx as isize - i >= 0 { | ||
| 180 | buffer[cy * self.screen_w + (cx - i as usize)] = cross_color; | ||
| 181 | } | ||
| 182 | if (cx + i as usize) < self.screen_w { | ||
| 183 | buffer[cy * self.screen_w + (cx + i as usize)] = cross_color; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | /// Integer darken: `bright_fx` is brightness × 256 in fixed-point. | ||
| 190 | #[inline(always)] | ||
| 191 | fn darken_fx(color: u32, bright_fx: u32) -> u32 { | ||
| 192 | let r = (((color >> 16) & 0xFF) * bright_fx) >> 8; | ||
| 193 | let g = (((color >> 8) & 0xFF) * bright_fx) >> 8; | ||
| 194 | let b = ((color & 0xFF) * bright_fx) >> 8; | ||
| 195 | 0xFF00_0000 | (r << 16) | (g << 8) | b | ||
| 196 | } | ||
diff --git a/src/texture.rs b/src/texture.rs new file mode 100644 index 0000000..bdbb15c --- /dev/null +++ b/src/texture.rs | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | use rand::Rng; | ||
| 2 | |||
| 3 | pub const TEX_SIZE: usize = 64; | ||
| 4 | |||
| 5 | /// Deterministic hash for coherent procedural noise. | ||
| 6 | fn hash(x: u32, y: u32, seed: u64) -> u64 { | ||
| 7 | let mut h = (x as u64).wrapping_mul(0x9e3779b9); | ||
| 8 | h = h.wrapping_add((y as u64).wrapping_mul(0x517cc1b727220a95)); | ||
| 9 | h = h.wrapping_add(seed); | ||
| 10 | h = (h ^ (h >> 33)).wrapping_mul(0xc6a4a7935bd1e995); | ||
| 11 | h = (h ^ (h >> 29)).wrapping_mul(0x5bd1e995); | ||
| 12 | h | ||
| 13 | } | ||
| 14 | |||
| 15 | /// Brown cracked wall texture — 64×64, brick pattern with mortar lines and fissures. | ||
| 16 | pub fn generate_wall_texture(rng: &mut impl Rng) -> Vec<u32> { | ||
| 17 | let seed = rng.gen::<u64>(); | ||
| 18 | let mut tex = vec![0u32; TEX_SIZE * TEX_SIZE]; | ||
| 19 | |||
| 20 | for y in 0..TEX_SIZE { | ||
| 21 | for x in 0..TEX_SIZE { | ||
| 22 | let h = hash(x as u32, y as u32, seed); | ||
| 23 | |||
| 24 | let r = 105u8.wrapping_add((h % 50) as u8); | ||
| 25 | let g = 55u8.wrapping_add(((h >> 8) % 35) as u8); | ||
| 26 | let b = 22u8.wrapping_add(((h >> 16) % 25) as u8); | ||
| 27 | |||
| 28 | // Brick mortar every 16 pixels | ||
| 29 | let mortar = y % 16 == 0 || y % 16 == 15; | ||
| 30 | |||
| 31 | let (r, g, b) = if mortar { | ||
| 32 | (42, 20, 8) | ||
| 33 | } else { | ||
| 34 | let crack_hash = hash(x.wrapping_add(1000) as u32, y as u32, seed); | ||
| 35 | let crack_val = (crack_hash % 100) as u8; | ||
| 36 | if crack_val < 8 { | ||
| 37 | // dark crack | ||
| 38 | let factor = 0.30 + (crack_val as f64 / 8.0) * 0.25; | ||
| 39 | ( | ||
| 40 | (r as f64 * factor) as u8, | ||
| 41 | (g as f64 * factor) as u8, | ||
| 42 | (b as f64 * factor) as u8, | ||
| 43 | ) | ||
| 44 | } else if crack_val < 14 { | ||
| 45 | // light crack highlight | ||
| 46 | ( | ||
| 47 | (r.saturating_add(25)).min(255), | ||
| 48 | (g.saturating_add(18)).min(255), | ||
| 49 | (b.saturating_add(10)).min(255), | ||
| 50 | ) | ||
| 51 | } else { | ||
| 52 | (r, g, b) | ||
| 53 | } | ||
| 54 | }; | ||
| 55 | |||
| 56 | tex[y * TEX_SIZE + x] = | ||
| 57 | 0xFF00_0000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | tex | ||
| 61 | } | ||
| 62 | |||
| 63 | /// Gray stone-tile floor — 64×64, checkerboard with grout and subtle colour tint. | ||
| 64 | pub fn generate_floor_texture(rng: &mut impl Rng) -> Vec<u32> { | ||
| 65 | let seed = rng.gen::<u64>(); | ||
| 66 | let mut tex = vec![0u32; TEX_SIZE * TEX_SIZE]; | ||
| 67 | |||
| 68 | for y in 0..TEX_SIZE { | ||
| 69 | for x in 0..TEX_SIZE { | ||
| 70 | let h = hash(x as u32, y as u32, seed); | ||
| 71 | let h2 = hash(x.wrapping_add(2000) as u32, y.wrapping_add(2000) as u32, seed); | ||
| 72 | |||
| 73 | let tile_x = x / 16; | ||
| 74 | let tile_y = y / 16; | ||
| 75 | let is_light_tile = (tile_x + tile_y) % 2 == 0; | ||
| 76 | |||
| 77 | let local_x = x % 16; | ||
| 78 | let local_y = y % 16; | ||
| 79 | let is_grout = local_x == 0 || local_y == 0; | ||
| 80 | |||
| 81 | let base_gray: u8 = if is_light_tile { 115 } else { 95 }; | ||
| 82 | let noise = (h % 15) as u8; | ||
| 83 | |||
| 84 | let tint_r = (h2 % 8) as i16 - 4i16; | ||
| 85 | let tint_b = ((h2 >> 8) % 8) as i16 - 4i16; | ||
| 86 | |||
| 87 | let gray = if is_grout { | ||
| 88 | base_gray.saturating_sub(30).saturating_add(noise / 3) | ||
| 89 | } else { | ||
| 90 | base_gray.saturating_add(noise / 2) | ||
| 91 | }; | ||
| 92 | |||
| 93 | let r = (gray as i16 + tint_r).clamp(0, 255) as u8; | ||
| 94 | let g = gray; | ||
| 95 | let b = (gray as i16 + tint_b).clamp(0, 255) as u8; | ||
| 96 | |||
| 97 | tex[y * TEX_SIZE + x] = | ||
| 98 | 0xFF00_0000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | tex | ||
| 102 | } | ||
