initial commit

This commit is contained in:
missing 2022-07-24 21:45:27 -07:00
parent c279996a07
commit 9b630556ae
9 changed files with 2871 additions and 0 deletions

993
Cargo.lock generated Normal file
View file

@ -0,0 +1,993 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "bumpalo"
version = "3.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
[[package]]
name = "calloop"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf2eec61efe56aa1e813f5126959296933cf0700030e4314786c48779a66ab82"
dependencies = [
"log",
"nix",
]
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cocoa"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832"
dependencies = [
"bitflags",
"block",
"cocoa-foundation",
"core-foundation 0.9.3",
"core-graphics 0.22.3",
"foreign-types",
"libc",
"objc",
]
[[package]]
name = "cocoa-foundation"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318"
dependencies = [
"bitflags",
"block",
"core-foundation 0.9.3",
"core-graphics-types",
"foreign-types",
"libc",
"objc",
]
[[package]]
name = "core-foundation"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
dependencies = [
"core-foundation-sys 0.7.0",
"libc",
]
[[package]]
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
"core-foundation-sys 0.8.3",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
[[package]]
name = "core-foundation-sys"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "core-graphics"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923"
dependencies = [
"bitflags",
"core-foundation 0.7.0",
"foreign-types",
"libc",
]
[[package]]
name = "core-graphics"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
dependencies = [
"bitflags",
"core-foundation 0.9.3",
"core-graphics-types",
"foreign-types",
"libc",
]
[[package]]
name = "core-graphics-types"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
dependencies = [
"bitflags",
"core-foundation 0.9.3",
"foreign-types",
"libc",
]
[[package]]
name = "core-video-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828"
dependencies = [
"cfg-if 0.1.10",
"core-foundation-sys 0.7.0",
"core-graphics 0.19.2",
"libc",
"objc",
]
[[package]]
name = "cty"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
[[package]]
name = "d3"
version = "0.1.0"
dependencies = [
"softbuffer",
"winit",
]
[[package]]
name = "darling"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "dispatch"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
name = "dlib"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794"
dependencies = [
"libloading",
]
[[package]]
name = "downcast-rs"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "fastrand"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
dependencies = [
"instant",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "jni-sys"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "js-sys"
version = "0.3.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "libloading"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
dependencies = [
"cfg-if 1.0.0",
"winapi",
]
[[package]]
name = "lock_api"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
dependencies = [
"libc",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memmap2"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357"
dependencies = [
"libc",
]
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "mio"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys",
]
[[package]]
name = "ndk"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d868f654c72e75f8687572699cdabe755f03effbb62542768e995d5b8d699d"
dependencies = [
"bitflags",
"jni-sys",
"ndk-sys",
"num_enum",
"thiserror",
]
[[package]]
name = "ndk-context"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
[[package]]
name = "ndk-glue"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c71bee8ea72d685477e28bd004cfe1bf99c754d688cd78cad139eae4089484d4"
dependencies = [
"lazy_static",
"libc",
"log",
"ndk",
"ndk-context",
"ndk-macro",
"ndk-sys",
]
[[package]]
name = "ndk-macro"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c"
dependencies = [
"darling",
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "ndk-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121"
[[package]]
name = "nix"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf"
dependencies = [
"bitflags",
"cc",
"cfg-if 1.0.0",
"libc",
"memoffset",
]
[[package]]
name = "nom"
version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num_enum"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
dependencies = [
"num_enum_derive",
]
[[package]]
name = "num_enum_derive"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "objc"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [
"malloc_buf",
]
[[package]]
name = "once_cell"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
[[package]]
name = "parking_lot"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
dependencies = [
"cfg-if 1.0.0",
"instant",
"libc",
"redox_syscall",
"smallvec",
"winapi",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pkg-config"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]]
name = "proc-macro-crate"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a"
dependencies = [
"thiserror",
"toml",
]
[[package]]
name = "proc-macro2"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
dependencies = [
"proc-macro2",
]
[[package]]
name = "raw-window-handle"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41"
dependencies = [
"cty",
]
[[package]]
name = "redox_syscall"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534cfe58d6a18cc17120fbf4635d53d14691c1fe4d951064df9bd326178d7d5a"
dependencies = [
"bitflags",
]
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]]
name = "scoped-tls"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03"
[[package]]
name = "smallvec"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
[[package]]
name = "smithay-client-toolkit"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a28f16a97fa0e8ce563b2774d1e732dd5d4025d2772c5dba0a41a0f90a29da3"
dependencies = [
"bitflags",
"calloop",
"dlib",
"lazy_static",
"log",
"memmap2",
"nix",
"pkg-config",
"wayland-client",
"wayland-cursor",
"wayland-protocols",
]
[[package]]
name = "softbuffer"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d1cda310762a78016e0bcb9f21b9f6c288858941eab798443c19d8f77cde68a"
dependencies = [
"cocoa",
"core-graphics 0.22.3",
"foreign-types",
"objc",
"raw-window-handle",
"tempfile",
"thiserror",
"wasm-bindgen",
"wayland-client",
"web-sys",
"winapi",
"x11-dl",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
"cfg-if 1.0.0",
"fastrand",
"libc",
"redox_syscall",
"remove_dir_all",
"winapi",
]
[[package]]
name = "thiserror"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "toml"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
dependencies = [
"serde",
]
[[package]]
name = "unicode-ident"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
[[package]]
name = "wayland-client"
version = "0.29.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91223460e73257f697d9e23d401279123d36039a3f7a449e983f123292d4458f"
dependencies = [
"bitflags",
"downcast-rs",
"libc",
"nix",
"scoped-tls",
"wayland-commons",
"wayland-scanner",
"wayland-sys",
]
[[package]]
name = "wayland-commons"
version = "0.29.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94f6e5e340d7c13490eca867898c4cec5af56c27a5ffe5c80c6fc4708e22d33e"
dependencies = [
"nix",
"once_cell",
"smallvec",
"wayland-sys",
]
[[package]]
name = "wayland-cursor"
version = "0.29.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd"
dependencies = [
"nix",
"wayland-client",
"xcursor",
]
[[package]]
name = "wayland-protocols"
version = "0.29.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741"
dependencies = [
"bitflags",
"wayland-client",
"wayland-commons",
"wayland-scanner",
]
[[package]]
name = "wayland-scanner"
version = "0.29.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39a1ed3143f7a143187156a2ab52742e89dac33245ba505c17224df48939f9e0"
dependencies = [
"proc-macro2",
"quote",
"xml-rs",
]
[[package]]
name = "wayland-sys"
version = "0.29.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4"
dependencies = [
"dlib",
"lazy_static",
"pkg-config",
]
[[package]]
name = "web-sys"
version = "0.3.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
dependencies = [
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
[[package]]
name = "winit"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b43cc931d58b99461188607efd7acb2a093e65fc621f54cad78517a6063e73a"
dependencies = [
"bitflags",
"cocoa",
"core-foundation 0.9.3",
"core-graphics 0.22.3",
"core-video-sys",
"dispatch",
"instant",
"lazy_static",
"libc",
"log",
"mio",
"ndk",
"ndk-glue",
"ndk-sys",
"objc",
"parking_lot",
"percent-encoding",
"raw-window-handle",
"smithay-client-toolkit",
"wasm-bindgen",
"wayland-client",
"wayland-protocols",
"web-sys",
"winapi",
"x11-dl",
]
[[package]]
name = "x11-dl"
version = "2.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59"
dependencies = [
"lazy_static",
"libc",
"pkg-config",
]
[[package]]
name = "xcursor"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7"
dependencies = [
"nom",
]
[[package]]
name = "xml-rs"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"

12
Cargo.toml Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "d3"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
softbuffer = "0.1.1"
winit = "0.26.1"
[features]

156
src/buffer.rs Normal file
View file

@ -0,0 +1,156 @@
use d3::rgb::Rgb;
use d3::vector2::Vec2Int;
pub use d3::vector3::{Direction3, Vec3};
use std::ops::Deref;
#[allow(clippy::module_name_repetitions)]
pub struct GraphicsBuffer {
buf: Vec<Rgb>,
/// Depth™ buffer
depth: Vec<u32>,
width: usize,
height: usize,
}
impl GraphicsBuffer {
pub fn new() -> Self {
Self {
buf: Vec::new(),
depth: Vec::new(),
width: 0,
height: 0,
}
}
pub fn set(&mut self, pos: Vec2Int, v: Rgb, depth: u32) {
if pos.x < 0 || pos.y < 0 || pos.x >= self.width as i32 || pos.y >= self.height as i32 {
return;
}
let index = pos.x as usize + pos.y as usize * self.width;
if depth > self.depth[index] {
return;
}
self.buf[index] = v;
// let channel = (depth / (u32::MAX / u8::MAX as u32)) as u8;
// self.buf[index] = Rgb::new(channel, channel, channel);
self.depth[index] = depth;
}
fn plot_line_low(&mut self, a: Vec2Int, b: Vec2Int, az: f32, bz: f32, v: Rgb) {
#![allow(clippy::many_single_char_names)]
let dx = b.x - a.x;
let dy = (b.y - a.y).abs();
let yi = if b.y >= a.y { 1 } else { -1 };
let mut d = (2 * dy) - dx;
let mut y = a.y;
let mut z = az;
let dz = (bz - az) / dx as f32;
for x in a.x..b.x {
if 0.0 < z && z < 1.0 {
self.set((x, y).into(), v, (z * u32::MAX as f32) as u32);
}
if d > 0 {
y += yi;
d += 2 * (dy - dx);
} else {
d += 2 * dy;
}
z += dz;
}
}
fn plot_line_high(&mut self, a: Vec2Int, b: Vec2Int, az: f32, bz: f32, v: Rgb) {
#![allow(clippy::many_single_char_names)]
let dx = (b.x - a.x).abs();
let dy = b.y - a.y;
let xi = if b.x >= a.x { 1 } else { -1 };
let mut d = (2 * dx) - dy;
let mut x = a.x;
let mut z = az;
let dz = (bz - az) / dy as f32;
for y in a.y..b.y {
if 0.0 < z && z < 1.0 {
self.set((x, y).into(), v, (z * u32::MAX as f32) as u32);
}
if d > 0 {
x += xi;
d += 2 * (dx - dy);
} else {
d += 2 * dx;
}
z += dz;
}
}
pub fn draw_line(&mut self, mut a: Vec3, mut b: Vec3, v: Rgb) {
let quarter_width = (self.width / 4) as f32;
let quarter_height = (self.height / 4) as f32;
let scale = self.height as f32;
a.x *= scale;
b.x *= scale;
a.y *= -scale;
b.y *= -scale;
a.x += quarter_width;
b.x += quarter_width;
a.y += quarter_height;
b.y += quarter_height;
// kinda hacky, need to do this to avoid the `i32` restriction in `Vec3Int`
let az = a.z;
let bz = b.z;
let a = a.rounded().into_vec2();
let b = b.rounded().into_vec2();
// TODO: optimize for vertical and horizontal cases
#[allow(clippy::collapsible_else_if)]
if (b.y - a.y).abs() < (b.x - a.x).abs() {
if a.x > b.x {
self.plot_line_low(b, a, bz, az, v);
} else {
self.plot_line_low(a, b, az, bz, v);
}
} else {
if a.y > b.y {
self.plot_line_high(b, a, bz, az, v);
} else {
self.plot_line_high(a, b, az, bz, v);
}
}
}
pub fn resize(&mut self, dim: Vec2Int, v: Option<Rgb>) {
let (width, height) = (dim.x as usize, dim.y as usize);
self.buf.resize(width * height, v.unwrap_or(Rgb::BLACK));
self.depth.resize(width * height, u32::MAX);
self.width = width;
self.height = height;
}
pub fn resize_and_clear(&mut self, dim: Vec2Int, v: Rgb) {
if dim.x as usize != self.width || dim.y as usize != self.height {
self.resize(dim, Some(v));
} else {
self.buf.fill(v);
self.depth.fill(u32::MAX);
}
}
}
impl Deref for GraphicsBuffer {
type Target = [u32];
fn deref(&self) -> &Self::Target {
Rgb::as_u32_slice(&self.buf)
}
}

15
src/lib.rs Normal file
View file

@ -0,0 +1,15 @@
//! Some docs idk
#![warn(clippy::pedantic)]
#![allow(clippy::must_use_candidate)]
#![allow(clippy::return_self_not_must_use)]
#![warn(missing_docs)]
/// Quaternions, or rotations in 3d space.
pub mod quaternion;
/// Rgb (red green blue) colors.
pub mod rgb;
/// Vec2, or a location in 2d space.
pub mod vector2;
/// Vec3, or a location in 3d space
pub mod vector3;

278
src/main.rs Normal file
View file

@ -0,0 +1,278 @@
#![warn(clippy::pedantic)]
#![allow(clippy::too_many_lines)]
// we use lots of casts, so explicitly allowing
#![allow(clippy::cast_possible_truncation)]
#![allow(clippy::cast_sign_loss)]
#![allow(clippy::cast_precision_loss)]
use d3::quaternion::Quaternion;
use d3::rgb::Rgb;
use d3::vector2::Vec2;
use d3::vector3::{Direction3, Vec3};
use softbuffer::GraphicsContext;
use std::collections::HashMap;
use std::f32::consts::PI;
use std::thread;
use std::time::{Duration, Instant};
use winit::dpi::PhysicalPosition;
use winit::event::{
ElementState, Event, KeyboardInput, ModifiersState, MouseButton, VirtualKeyCode, WindowEvent,
};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
use crate::buffer::GraphicsBuffer;
mod buffer;
#[derive(Clone, Copy, Debug)]
struct Transform {
pos: Vec3,
rot: Quaternion,
}
#[derive(Clone, Copy)]
struct Camera {
transform: Transform,
near_clip: f32,
far_clip: f32,
vertical_fov: f32,
}
#[derive(Clone, Copy)]
struct Triangle {
points: [Vec3; 3],
color: Rgb,
}
struct InputManager {
keys: HashMap<VirtualKeyCode, bool>,
buttons: HashMap<MouseButton, bool>,
modifier_keys: ModifiersState,
mouse_pos: Vec2,
mouse_delta: Vec2,
}
impl InputManager {
fn new() -> Self {
Self {
keys: HashMap::new(),
buttons: HashMap::new(),
modifier_keys: ModifiersState::empty(),
mouse_pos: (0, 0).into(),
mouse_delta: (0, 0).into(),
}
}
fn handle_keyboard_input(&mut self, ev: KeyboardInput) {
if let Some(keycode) = ev.virtual_keycode {
self.keys.insert(
keycode,
match ev.state {
ElementState::Pressed => true,
ElementState::Released => false,
},
);
}
}
fn handle_mouse_movement(&mut self, ev: PhysicalPosition<f64>) {
let ev = ev.cast::<f32>();
let new_pos = Vec2::from((ev.x, ev.y));
self.mouse_delta += new_pos - self.mouse_pos;
self.mouse_pos = new_pos;
}
fn handle_modifiers_changed(&mut self, ev: ModifiersState) {
self.modifier_keys = ev;
}
fn handle_mouse_button(&mut self, ev: (MouseButton, ElementState)) {
self.buttons.insert(
ev.0,
match ev.1 {
ElementState::Pressed => true,
ElementState::Released => false,
},
);
}
fn key_pressed(&self, key: VirtualKeyCode) -> bool {
self.keys.get(&key).copied().unwrap_or_default()
}
fn button_pressed(&self, button: MouseButton) -> bool {
self.buttons.get(&button).copied().unwrap_or_default()
}
fn end_of_frame(&mut self) {
self.mouse_delta = (0, 0).into();
}
}
fn main() {
let mut camera = Camera {
transform: Transform {
pos: Vec3::default(),
rot: Quaternion::one(),
},
near_clip: 0.1,
far_clip: 10.0,
vertical_fov: 70.0,
};
macro_rules! tri {
($a:expr, $b:expr, $c:expr; $col:expr) => {
Triangle {
points: [$a.into(), $b.into(), $c.into()],
color: $col.into(),
}
};
}
let tris = vec![
tri!((1, 1, 5), (1, -1, 5), (-1, -1, 5); Rgb::RED),
tri!((1, 1, 5), (-1, -1, 5), (-1, 1, 5); Rgb::GREEN),
tri!((-1, 1, 7), (-1, -1, 7), (1, -1, 7); Rgb::BLUE),
tri!((-1, 1, 7), (1, -1, 7), (1, 1, 7); Rgb::YELLOW),
];
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
let mut graphics_context = unsafe { GraphicsContext::new(window) }.unwrap();
let mut graphics_buffer = GraphicsBuffer::new();
let mut input_manager = InputManager::new();
let mut last_frame_start_time = Instant::now();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Poll;
match event {
Event::MainEventsCleared => {
thread::sleep(
Duration::from_secs_f32(1.0 / 30.0)
.saturating_sub(Instant::now() - last_frame_start_time),
);
let start_time = Instant::now();
let delta_time = (start_time - last_frame_start_time).as_secs_f32();
last_frame_start_time = start_time;
let (width, height) = {
let size = graphics_context.window().inner_size();
(size.width as u16, size.height as u16)
};
graphics_buffer
.resize_and_clear((width.into(), height.into()).into(), 0xbb_bb_bb.into());
if input_manager.key_pressed(VirtualKeyCode::A) {
camera.transform.pos +=
(Direction3::Left * 2.0 * delta_time).rotate_by(camera.transform.rot);
}
if input_manager.key_pressed(VirtualKeyCode::D) {
camera.transform.pos +=
(Direction3::Right * 2.0 * delta_time).rotate_by(camera.transform.rot);
}
if input_manager.key_pressed(VirtualKeyCode::W) {
camera.transform.pos +=
(Direction3::Forward * 2.0 * delta_time).rotate_by(camera.transform.rot);
}
if input_manager.key_pressed(VirtualKeyCode::S) {
camera.transform.pos +=
(Direction3::Backward * 2.0 * delta_time).rotate_by(camera.transform.rot);
}
if input_manager.modifier_keys.shift() {
camera.transform.pos +=
(Direction3::Down * 2.0 * delta_time).rotate_by(camera.transform.rot);
}
if input_manager.key_pressed(VirtualKeyCode::Space) {
camera.transform.pos +=
(Direction3::Up * 2.0 * delta_time).rotate_by(camera.transform.rot);
}
if input_manager.key_pressed(VirtualKeyCode::Q) {
*control_flow = ControlFlow::Exit;
}
if input_manager.button_pressed(MouseButton::Right) {
camera
.transform
.rot
.compose_in_place(Quaternion::rotation_around(
Direction3::Up.into(),
input_manager.mouse_delta.x / 1000.0,
));
camera
.transform
.rot
.compose_in_place(Quaternion::rotation_around(
Vec3::from(Direction3::Right).rotate_by(camera.transform.rot),
input_manager.mouse_delta.y / 1000.0,
));
}
for tri in &tris {
let points = tri.points.map(|v| transform_point(camera, v));
graphics_buffer.draw_line(points[0], points[1], tri.color);
graphics_buffer.draw_line(points[1], points[2], tri.color);
graphics_buffer.draw_line(points[2], points[0], tri.color);
}
graphics_context.set_buffer(&graphics_buffer, width, height);
// graphics_context
// .window()
// .set_cursor_position(LogicalPosition::new(400, 300))
// .unwrap();
// graphics_context.window().set_cursor_visible(false);
input_manager.end_of_frame();
}
Event::WindowEvent { window_id, event }
if window_id == graphics_context.window().id() =>
{
match event {
WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
}
WindowEvent::KeyboardInput { input, .. } => {
input_manager.handle_keyboard_input(input);
}
WindowEvent::CursorMoved { position, .. } => {
input_manager.handle_mouse_movement(position);
}
WindowEvent::ModifiersChanged(state) => {
input_manager.handle_modifiers_changed(state);
}
WindowEvent::MouseInput { state, button, .. } => {
input_manager.handle_mouse_button((button, state));
}
_ => {}
}
}
_ => {}
}
});
}
fn transform_point(camera: Camera, mut point: Vec3) -> Vec3 {
point -= camera.transform.pos;
let mut point = point.rotate_by(camera.transform.rot.inv());
let z_scale = point.z.abs();
if z_scale < (1.0 / 10000.0) {
point.x = 0.0;
point.y = 0.0;
} else {
let fov_scale = camera.vertical_fov.to_radians().tan();
let scale = fov_scale * z_scale;
point.x /= scale;
point.y /= scale;
}
point.z -= camera.near_clip;
point.z /= camera.far_clip - camera.near_clip;
point
}

316
src/quaternion.rs Normal file
View file

@ -0,0 +1,316 @@
use std::{
fmt::{Debug, Display},
ops::{Add, Div, Mul, Neg, Sub},
};
use crate::vector3::Vec3;
/// A rotation, orientation, or location in 3d space.
///
/// Recomended reading: [Quaternion on Wikipedia](https://en.wikipedia.org/wiki/Quaternion), [Quaternions and spatial rotation on Wikipedia](https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation)
///
/// Most functions and operations on `Quaternion` will require the mathematical knowledge to understand, except for [`compose`], [`apply`], [`inv`], [`rotation_around`], and [`one`].
///
/// [`compose`]: Quaternion::compose
/// [`apply`]: Quaternion::apply
/// [`inv`]: Quaternion::inv
/// [`rotation_around`]: Quaternion::rotation_around
/// [`one`]: Quaternion::one
#[derive(Copy, Clone, PartialEq, Default)]
pub struct Quaternion {
/// The real part of the quaternion.
pub a: f32,
/// The coefficient of the `i` part of the quaternion.
pub b: f32,
/// The coefficient of the `j` part of the quaternion.
pub c: f32,
/// The coefficient of the `k` part of the quaternion.
pub d: f32,
}
impl Debug for Quaternion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} + {}i + {}j + {}k", self.a, self.b, self.c, self.d)
}
}
impl Display for Quaternion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(self, f)
}
}
///////////////////////////
// Creating a Quaternion //
///////////////////////////
impl Quaternion {
/// Creates a scalar/real quaternion from the given value.
pub fn scalar(a: f32) -> Self {
Self {
a,
..Default::default()
}
}
/// Creates a vector quaternion from the given [`Vec3`].
pub fn vector(v: Vec3) -> Self {
Self {
b: v.x,
c: v.y,
d: v.z,
..Default::default()
}
}
/// Creates the zero quaternion.
pub fn zero() -> Self {
Quaternion::default()
}
/// Create a quaternion equal to 1, which is also the "no rotation" quaternion.
pub fn one() -> Self {
Self::scalar(1.0)
}
/// Creates a quaternion from the given real and vector parts.
pub fn new(a: f32, v: Vec3) -> Self {
Self {
a,
b: v.x,
c: v.y,
d: v.z,
}
}
/// Creates a quaternion from the given components
pub fn from_components(a: f32, b: f32, c: f32, d: f32) -> Self {
Self { a, b, c, d }
}
/// Creates a quaternion representing a `theta` radians rotation around `axis`.
pub fn rotation_around(axis: Vec3, theta: f32) -> Self {
(theta / 2.0).cos() - Self::vector(axis.normalized()) * (theta / 2.0).sin()
}
}
impl From<f32> for Quaternion {
fn from(a: f32) -> Self {
Self::scalar(a)
}
}
impl From<Vec3> for Quaternion {
fn from(v: Vec3) -> Self {
Self::vector(v)
}
}
impl From<(f32, Vec3)> for Quaternion {
fn from((a, v): (f32, Vec3)) -> Self {
Self::new(a, v)
}
}
impl From<(f32, f32, f32, f32)> for Quaternion {
fn from((a, b, c, d): (f32, f32, f32, f32)) -> Self {
Self::from_components(a, b, c, d)
}
}
////////////////////////////
// Operations with itself //
////////////////////////////
impl Quaternion {
/// Gets the squared norm of the quaternion.
pub fn sq_norm(self) -> f32 {
self.a.powi(2) + self.b.powi(2) + self.c.powi(2) + self.d.powi(2)
}
/// Gets the norm of the quaternion.
pub fn norm(self) -> f32 {
self.sq_norm().sqrt()
}
/// Takes the conjugate of the quaternion.
pub fn conjugate(self) -> Self {
Self {
a: self.a,
b: -self.b,
c: -self.c,
d: -self.d,
}
}
/// Takes the reciprocal of the quaternion.
pub fn inv(self) -> Self {
self.conjugate() / self.sq_norm()
}
/// Gets the versor/unit quaternion of the quaternion.
pub fn versor(self) -> Self {
self / self.norm()
}
/// Determines if the quaternion is a versor/unit quaternion.
pub fn is_versor(self) -> bool {
(self.sq_norm() - 1.0).abs() < f32::EPSILON
}
/// Conjugates `self` by `rhs`, the operation `rhs * self * rhs.inv()`.
pub fn conjugate_by(self, rhs: Self) -> Self {
rhs * self * rhs.inv()
}
/// Gets the scalar part of this quaternion.
pub fn scalar_part(self) -> f32 {
self.a
}
/// Gets the vector part of this quaternion.
pub fn vector_part(self) -> Vec3 {
(self.b, self.c, self.d).into()
}
/// Creates a rotation which is `self` followed by `rhs`.
///
/// Same as `rhs * self`, in that order.
pub fn compose(self, rhs: Self) -> Self {
rhs * self
}
/// Composes `rhs` with `self`, in place.
///
/// See also: [`Quaternion::compose`]
pub fn compose_in_place(&mut self, rhs: Self) {
*self = self.compose(rhs);
}
/// Applies this rotation to a point in space.
///
/// Same as `Quaternion::vector(v).conjugate_by(self).vector_part()`
pub fn apply(self, v: Vec3) -> Vec3 {
Self::vector(v).conjugate_by(self).vector_part()
}
}
impl Neg for Quaternion {
type Output = Self;
fn neg(self) -> Self::Output {
Self {
a: -self.a,
b: -self.b,
c: -self.c,
d: -self.d,
}
}
}
impl Add for Quaternion {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
a: self.a + rhs.a,
b: self.b + rhs.b,
c: self.c + rhs.c,
d: self.d + rhs.d,
}
}
}
impl Sub for Quaternion {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
self + -rhs
}
}
impl Mul for Quaternion {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
// https://en.wikipedia.org/wiki/Quaternion#Hamilton_product
Self {
a: (self.a * rhs.a) - (self.b * rhs.b) - (self.c * rhs.c) - (self.d * rhs.d),
b: (self.a * rhs.b) + (self.b * rhs.a) + (self.c * rhs.d) - (self.d * rhs.c),
c: (self.a * rhs.c) - (self.b * rhs.d) + (self.c * rhs.a) + (self.d * rhs.b),
d: (self.a * rhs.d) + (self.b * rhs.c) - (self.c * rhs.b) + (self.d * rhs.a),
}
}
}
// `impl Div for Quaternion` is explicitly left out, since it is ambiguous.
//////////////////////////////////
// Operations with real numbers //
//////////////////////////////////
impl Add<f32> for Quaternion {
type Output = Self;
fn add(self, rhs: f32) -> Self::Output {
Self {
a: self.a + rhs,
..self
}
}
}
impl Add<Quaternion> for f32 {
type Output = Quaternion;
fn add(self, rhs: Quaternion) -> Self::Output {
rhs + self
}
}
impl Sub<f32> for Quaternion {
type Output = Self;
fn sub(self, rhs: f32) -> Self::Output {
self + -rhs
}
}
impl Sub<Quaternion> for f32 {
type Output = Quaternion;
fn sub(self, rhs: Quaternion) -> Self::Output {
-rhs + self
}
}
impl Mul<f32> for Quaternion {
type Output = Quaternion;
fn mul(self, rhs: f32) -> Self::Output {
Self {
a: self.a * rhs,
b: self.b * rhs,
c: self.c * rhs,
d: self.d * rhs,
}
}
}
impl Mul<Quaternion> for f32 {
type Output = Quaternion;
fn mul(self, rhs: Quaternion) -> Self::Output {
rhs * self
}
}
impl Div<f32> for Quaternion {
type Output = Quaternion;
fn div(self, rhs: f32) -> Self::Output {
self * (1.0 / rhs)
}
}
// `impl Div<Quaternion> for f32` is explicitly left out, since it makes no sense

96
src/rgb.rs Normal file
View file

@ -0,0 +1,96 @@
use core::slice;
#[derive(Clone, Copy, Default)]
#[repr(transparent)]
/// An RGB (red green blue) color.
pub struct Rgb(u32);
impl Rgb {
/// Red, or `Rgb::new(255, 0, 0)`.
pub const RED: Self = Self::new_u32(0xff_00_00);
/// Green, or `Rgb::new(0, 255, 0)`.
pub const GREEN: Self = Self::new_u32(0x00_ff_00);
/// Blue, or `Rgb::new(0, 0, 255)`.
pub const BLUE: Self = Self::new_u32(0x00_00_ff);
/// Yellow, or `Rgb::new(255, 255, 0)`.
pub const YELLOW: Self = Self::new_u32(0xff_ff_00);
/// Cyan, or `Rgb::new(0, 255, 255)`.
pub const CYAN: Self = Self::new_u32(0x00_ff_ff);
/// Magenta, or `Rgb::new(255, 0, 255)`.
pub const MAGENTA: Self = Self::new_u32(0xff_00_ff);
/// Black, or `Rgb::new(0, 0, 0)`.
pub const BLACK: Self = Self::new_u32(0x00_00_00);
/// White, or `Rgb::new(255, 255, 255)`.
pub const WHITE: Self = Self::new_u32(0xff_ff_ff);
/// Creates a new color from the given red, green, and blue values.
pub const fn new(r: u8, g: u8, b: u8) -> Self {
Self(((r as u32) << 16) | ((g as u32) << 8) | (b as u32))
}
/// Creates a new color from the given `u32`, in the following format:
///
/// `00000000_RRRRRRRR_GGGGGGGG_BBBBBBBB`
pub const fn new_u32(v: u32) -> Self {
Self(v & 0xff_ff_ff)
}
/// Gets the red value of this color.
pub fn red(self) -> u8 {
#![allow(clippy::cast_possible_truncation)]
(self.0 >> 16) as u8
}
/// Gets the green value of this color.
pub fn green(self) -> u8 {
((self.0 >> 8) & 0xff) as u8
}
/// Gets the blue value of this color.
pub fn blue(self) -> u8 {
(self.0 & 0xff) as u8
}
/// Sets the red value of this color.
pub fn set_red(&mut self, r: u8) {
*self = Self((self.0 & 0x00_ff_ff) | (u32::from(r) << 16));
}
/// Sets the green value of this color.
pub fn set_green(&mut self, r: u8) {
*self = Self((self.0 & 0xff_00_ff) | (u32::from(r) << 8));
}
/// Sets the blue value of this color.
pub fn set_blue(&mut self, r: u8) {
*self = Self((self.0 & 0xff_ff_00) | u32::from(r));
}
/// Reinterprets an `Rgb` slice as a `u32` slice.
pub fn as_u32_slice(slice: &[Rgb]) -> &[u32] {
unsafe { slice::from_raw_parts((slice as *const [Rgb]).cast(), slice.len()) }
}
/// Takes the inner `u32` out of an `Rgb`.
pub fn into_inner(self) -> u32 {
self.0
}
}
impl From<(u8, u8, u8)> for Rgb {
fn from((r, g, b): (u8, u8, u8)) -> Self {
Self::new(r, g, b)
}
}
impl From<u32> for Rgb {
fn from(v: u32) -> Self {
Self::new_u32(v)
}
}
impl From<Rgb> for u32 {
fn from(v: Rgb) -> Self {
v.into_inner()
}
}

478
src/vector2.rs Normal file
View file

@ -0,0 +1,478 @@
use std::{
fmt::Debug,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use crate::vector3::{Vec3, Vec3Int};
// Direction
/// A cardinal direction in a 2d plane.
///
/// Conversions to a [`Vec2`] or [`Vec2Int`] assume that East is positive-x and South is positive-y.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Direction2 {
/// The positive y-axis, or Vec2::from((0, 1))
Up,
/// The negative y-axis, or Vec2::from((0, -1))
Down,
/// The negative x-axis, or Vec2::from((-1, 0))
Left,
/// The positive x-axis, or Vec2::from((1, 0))
Right,
}
#[allow(clippy::enum_glob_use)]
impl Direction2 {
/// Flips this `Direction` around both the x- and y-axes.
pub fn flipped(self) -> Self {
self.flipped_x().flipped_y()
}
/// Flips this `Direction` around the x-axis.
pub fn flipped_x(self) -> Self {
use Direction2::*;
match self {
Left => Right,
Right => Left,
v => v,
}
}
/// Flips this `Direction` around the y-axis.
pub fn flipped_y(self) -> Self {
use Direction2::*;
match self {
Up => Down,
Down => Up,
v => v,
}
}
}
// ...and related op impls
impl Neg for Direction2 {
type Output = Self;
fn neg(self) -> Self::Output {
self.flipped()
}
}
#[allow(clippy::enum_glob_use)]
impl From<Direction2> for Vec2 {
fn from(v: Direction2) -> Self {
use Direction2::*;
match v {
Up => (0.0, 1.0).into(),
Down => (0.0, -1.0).into(),
Left => (-1.0, 0.0).into(),
Right => (1.0, 0.0).into(),
}
}
}
#[allow(clippy::enum_glob_use)]
impl From<Direction2> for Vec2Int {
fn from(v: Direction2) -> Self {
use Direction2::*;
match v {
Up => (0, 1).into(),
Down => (0, -1).into(),
Left => (-1, 0).into(),
Right => (1, 0).into(),
}
}
}
impl Mul<f32> for Direction2 {
type Output = Vec2;
fn mul(self, rhs: f32) -> Self::Output {
Vec2::from(self) * rhs
}
}
impl Mul<i32> for Direction2 {
type Output = Vec2Int;
fn mul(self, rhs: i32) -> Self::Output {
Vec2Int::from(self) * rhs
}
}
// Vec2
/// A set of 2 [`f32`]s representing a location or direction in the 2d plane.
#[derive(Clone, Copy, Default, PartialEq)]
pub struct Vec2 {
/// The x component of the vector.
pub x: f32,
/// The y component of the vector.
pub y: f32,
}
impl Debug for Vec2 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Vec2").field(&self.x).field(&self.y).finish()
}
}
impl Vec2 {
/// Creates a new `Vec2` with the given x- and y-values.
///
/// It is often simpler, and preferred, to just write `(x, y).into()`.
pub const fn new(x: f32, y: f32) -> Vec2 {
Self { x, y }
}
/// Gets the squared magnitude of the vector.
///
/// Useful for comparisons as it is faster to calculate than `magnitude`.
pub fn sq_magnitude(self) -> f32 {
self.x * self.x + self.y * self.y
}
/// Gets the magnitude of the vector.
pub fn magnitude(self) -> f32 {
self.sq_magnitude().sqrt()
}
/// Gets the squared distance from this vector to `rhs`.
///
/// Useful for comparisons as it is faster to calculate than `dist`.
pub fn sq_dist(self, rhs: Self) -> f32 {
(self - rhs).sq_magnitude()
}
/// Gets the distance from this vector to `rhs`.
pub fn dist(self, rhs: Self) -> f32 {
(self - rhs).magnitude()
}
/// Normalizes the vector, making its magnitude `1`.
pub fn normalized(self) -> Self {
self / self.magnitude()
}
/// Rounds the vector to a [`Vec2Int`].
///
/// This uses `as i32` under the hood, and as such comes with all the same unfortunate edge cases. Beware.
pub fn rounded(self) -> Vec2Int {
#[allow(clippy::cast_possible_truncation)]
Vec2Int {
x: self.x as i32,
y: self.y as i32,
}
}
/// Transforms this vector into a [`Vec3`] with a z-coordinate of 0.
pub fn into_vec2(self) -> Vec3 {
Vec3 {
x: self.x,
y: self.y,
z: 0.0,
}
}
}
impl From<(i32, i32)> for Vec2 {
fn from(v: (i32, i32)) -> Self {
Vec2Int::from(v).to_float()
}
}
impl From<(f32, f32)> for Vec2 {
fn from(v: (f32, f32)) -> Self {
Self { x: v.0, y: v.1 }
}
}
impl From<Vec2> for (f32, f32) {
fn from(v: Vec2) -> Self {
(v.x, v.y)
}
}
impl PartialEq<(i32, i32)> for Vec2 {
fn eq(&self, other: &(i32, i32)) -> bool {
self == &Self::from(*other)
}
}
impl PartialEq<(f32, f32)> for Vec2 {
fn eq(&self, other: &(f32, f32)) -> bool {
self == &Self::from(*other)
}
}
// ...and related op impls
impl Neg for Vec2 {
type Output = Self;
fn neg(self) -> Self::Output {
self * -1.0
}
}
impl Add for Vec2 {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl Add<Direction2> for Vec2 {
type Output = Self;
fn add(self, rhs: Direction2) -> Self::Output {
self + Self::from(rhs)
}
}
impl<T> AddAssign<T> for Vec2
where
Vec2: Add<T, Output = Self>,
{
fn add_assign(&mut self, rhs: T) {
*self = *self + rhs;
}
}
impl<T> Sub<T> for Vec2
where
Vec2: Add<T, Output = Self>,
{
type Output = Self;
fn sub(self, rhs: T) -> Self::Output {
-(-self + rhs)
}
}
impl<T> SubAssign<T> for Vec2
where
Vec2: Sub<T, Output = Self>,
{
fn sub_assign(&mut self, rhs: T) {
*self = *self - rhs;
}
}
impl Mul<f32> for Vec2 {
type Output = Self;
fn mul(self, rhs: f32) -> Self::Output {
Self {
x: self.x * rhs,
y: self.y * rhs,
}
}
}
impl Div<f32> for Vec2 {
type Output = Self;
fn div(self, rhs: f32) -> Self::Output {
Self {
x: self.x / rhs,
y: self.y / rhs,
}
}
}
impl MulAssign<f32> for Vec2 {
fn mul_assign(&mut self, rhs: f32) {
*self = *self * rhs;
}
}
impl DivAssign<f32> for Vec2 {
fn div_assign(&mut self, rhs: f32) {
*self = *self / rhs;
}
}
// Vec2Int
/// A set of 2 [`i32`]s representing a location or direction in the 2d plane.
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct Vec2Int {
/// The x component of the vector.
pub x: i32,
/// The y component of the vector.
pub y: i32,
}
impl Debug for Vec2Int {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Vec2Int")
.field(&self.x)
.field(&self.y)
.finish()
}
}
impl Vec2Int {
/// Creates a new `Vec2` with the given x- and y-values.
///
/// It is often simpler, and preferred, to just write `(x, y).into()`.
pub const fn new(x: i32, y: i32) -> Vec2Int {
Self { x, y }
}
/// Gets the squared magnitude of the vector.
///
/// Useful for comparisons as it is faster to calculate than `magnitude`.
pub fn sq_magnitude(self) -> i32 {
self.x * self.x + self.y * self.y
}
/// Gets the magnitude of the vector.
pub fn magnitude(self) -> f32 {
#[allow(clippy::cast_precision_loss)]
(self.sq_magnitude() as f32).sqrt()
}
/// Gets the squared distance from this vector to `rhs`.
///
/// Useful for comparisons as it is faster to calculate than `dist`.
pub fn sq_dist(self, rhs: Self) -> i32 {
(self - rhs).sq_magnitude()
}
/// Gets the distance from this vector to `rhs`.
pub fn dist(self, rhs: Self) -> f32 {
(self - rhs).magnitude()
}
/// Casts this vector to a [`Vec2`].
///
/// This uses `as f32` under the hood, and as such comes with all the same unfortunate edge cases. Beware.
pub fn to_float(self) -> Vec2 {
#[allow(clippy::cast_precision_loss)]
Vec2 {
x: self.x as f32,
y: self.y as f32,
}
}
/// Transforms this vector into a [`Vec3Int`] with a z-coordinate of 0.
pub fn into_vec2(self) -> Vec3Int {
Vec3Int {
x: self.x,
y: self.y,
z: 0,
}
}
}
impl From<(i32, i32)> for Vec2Int {
fn from(v: (i32, i32)) -> Self {
Self { x: v.0, y: v.1 }
}
}
impl From<Vec2Int> for (i32, i32) {
fn from(v: Vec2Int) -> Self {
(v.x, v.y)
}
}
impl PartialEq<(i32, i32)> for Vec2Int {
fn eq(&self, other: &(i32, i32)) -> bool {
self == &Self::from(*other)
}
}
// ...and related op impls
impl Neg for Vec2Int {
type Output = Self;
fn neg(self) -> Self::Output {
self * -1
}
}
impl Add for Vec2Int {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl Add<Direction2> for Vec2Int {
type Output = Self;
fn add(self, rhs: Direction2) -> Self::Output {
self + Self::from(rhs)
}
}
impl<T> AddAssign<T> for Vec2Int
where
Vec2Int: Add<T, Output = Self>,
{
fn add_assign(&mut self, rhs: T) {
*self = *self + rhs;
}
}
impl<T> Sub<T> for Vec2Int
where
Vec2Int: Add<T, Output = Self>,
{
type Output = Self;
fn sub(self, rhs: T) -> Self::Output {
-(-self + rhs)
}
}
impl<T> SubAssign<T> for Vec2Int
where
Vec2Int: Sub<T, Output = Self>,
{
fn sub_assign(&mut self, rhs: T) {
*self = *self - rhs;
}
}
impl Mul<i32> for Vec2Int {
type Output = Self;
fn mul(self, rhs: i32) -> Self::Output {
Self {
x: self.x * rhs,
y: self.y * rhs,
}
}
}
impl Div<i32> for Vec2Int {
type Output = Self;
fn div(self, rhs: i32) -> Self::Output {
Self {
x: self.x / rhs,
y: self.y / rhs,
}
}
}
impl MulAssign<i32> for Vec2Int {
fn mul_assign(&mut self, rhs: i32) {
*self = *self * rhs;
}
}
impl DivAssign<i32> for Vec2Int {
fn div_assign(&mut self, rhs: i32) {
*self = *self / rhs;
}
}

527
src/vector3.rs Normal file
View file

@ -0,0 +1,527 @@
use std::{
fmt::Debug,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use crate::{
quaternion::Quaternion,
vector2::{Vec2, Vec2Int},
};
// Direction
/// A cardinal direction in a 3d plane.
///
/// Conversions to a [`Vec3`] or [`Vec3Int`] assume that East is positive-x and South is positive-y.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Direction3 {
/// The positive y-axis, or Vec3::from((0, 1, 0))
Up,
/// The negative y-axis, or Vec3::from((0, -1, 0))
Down,
/// The negative x-axis, or Vec3::from((-1, 0, 0))
Left,
/// The positive x-axis, or Vec3::from((1, 0, 0))
Right,
/// The positive z-axis, or Vec3::from((0, 0, 1))
Forward,
/// The negative z-axis, or Vec3::from((0, 0, -1))
Backward,
}
#[allow(clippy::enum_glob_use)]
impl Direction3 {
/// Flips this `Direction` around the x-, y-, and z-axes.
pub fn flipped(self) -> Self {
self.flipped_x().flipped_y().flipped_z()
}
/// Flips this `Direction` around the x-axis.
pub fn flipped_x(self) -> Self {
use Direction3::*;
match self {
Left => Right,
Right => Left,
v => v,
}
}
/// Flips this `Direction` around the y-axis.
pub fn flipped_y(self) -> Self {
use Direction3::*;
match self {
Up => Down,
Down => Up,
v => v,
}
}
/// Flips this `Direction` around the z-axis.
pub fn flipped_z(self) -> Self {
use Direction3::*;
match self {
Forward => Backward,
Backward => Forward,
v => v,
}
}
}
// ...and related op impls
impl Neg for Direction3 {
type Output = Self;
fn neg(self) -> Self::Output {
self.flipped()
}
}
#[allow(clippy::enum_glob_use)]
impl From<Direction3> for Vec3 {
fn from(v: Direction3) -> Self {
use Direction3::*;
match v {
Up => (0.0, 1.0, 0.0).into(),
Down => (0.0, -1.0, 0.0).into(),
Left => (-1.0, 0.0, 0.0).into(),
Right => (1.0, 0.0, 0.0).into(),
Forward => (0.0, 0.0, 1.0).into(),
Backward => (0.0, 0.0, -1.0).into(),
}
}
}
#[allow(clippy::enum_glob_use)]
impl From<Direction3> for Vec3Int {
fn from(v: Direction3) -> Self {
use Direction3::*;
match v {
Up => (0, 1, 0).into(),
Down => (0, -1, 0).into(),
Left => (-1, 0, 0).into(),
Right => (1, 0, 0).into(),
Forward => (0, 0, 1).into(),
Backward => (0, 0, -1).into(),
}
}
}
impl Mul<f32> for Direction3 {
type Output = Vec3;
fn mul(self, rhs: f32) -> Self::Output {
Vec3::from(self) * rhs
}
}
impl Mul<i32> for Direction3 {
type Output = Vec3Int;
fn mul(self, rhs: i32) -> Self::Output {
Vec3Int::from(self) * rhs
}
}
// Vec3
/// A set of 3 [`f32`]s representing a location or direction in the 3d plane.
#[derive(Clone, Copy, Default, PartialEq)]
pub struct Vec3 {
/// The x component of the vector.
pub x: f32,
/// The y component of the vector.
pub y: f32,
/// The z component of the vector.
pub z: f32,
}
impl Debug for Vec3 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Vec3")
.field(&self.x)
.field(&self.y)
.field(&self.z)
.finish()
}
}
impl Vec3 {
/// Creates a new `Vec3` with the given x-, y-, and z-values.
///
/// It is often simpler, and preferred, to just write `(x, y, z).into()`.
pub const fn new(x: f32, y: f32, z: f32) -> Vec3 {
Self { x, y, z }
}
/// Gets the squared magnitude of the vector.
///
/// Useful for comparisons as it is faster to calculate than `magnitude`.
pub fn sq_magnitude(self) -> f32 {
self.x * self.x + self.y * self.y + self.z * self.z
}
/// Gets the magnitude of the vector.
pub fn magnitude(self) -> f32 {
self.sq_magnitude().sqrt()
}
/// Gets the squared distance from this vector to `rhs`.
///
/// Useful for comparisons as it is faster to calculate than `dist`.
pub fn sq_dist(self, rhs: Self) -> f32 {
(self - rhs).sq_magnitude()
}
/// Gets the distance from this vector to `rhs`.
pub fn dist(self, rhs: Self) -> f32 {
(self - rhs).magnitude()
}
/// Normalizes the vector, making its magnitude `1`.
pub fn normalized(self) -> Self {
self / self.magnitude()
}
/// Rounds the vector to a [`Vec3Int`].
///
/// This uses `as i32` under the hood, and as such comes with all the same unfortunate edge cases. Beware.
pub fn rounded(self) -> Vec3Int {
#[allow(clippy::cast_possible_truncation)]
Vec3Int {
x: self.x as i32,
y: self.y as i32,
z: self.z as i32,
}
}
/// Transforms this vector into a [`Vec2`], dropping the z-coordinate.
pub fn into_vec2(self) -> Vec2 {
Vec2 {
x: self.x,
y: self.y,
}
}
/// Rotates this vector by the given quaternion.
pub fn rotate_by(self, rhs: Quaternion) -> Self {
rhs.apply(self)
}
}
impl From<(i32, i32, i32)> for Vec3 {
fn from(v: (i32, i32, i32)) -> Self {
Vec3Int::from(v).into_float()
}
}
impl From<(f32, f32, f32)> for Vec3 {
fn from(v: (f32, f32, f32)) -> Self {
Self {
x: v.0,
y: v.1,
z: v.2,
}
}
}
impl From<Vec3> for (f32, f32, f32) {
fn from(v: Vec3) -> Self {
(v.x, v.y, v.z)
}
}
impl PartialEq<(i32, i32, i32)> for Vec3 {
fn eq(&self, other: &(i32, i32, i32)) -> bool {
self == &Self::from(*other)
}
}
impl PartialEq<(f32, f32, f32)> for Vec3 {
fn eq(&self, other: &(f32, f32, f32)) -> bool {
self == &Self::from(*other)
}
}
// ...and related op impls
impl Neg for Vec3 {
type Output = Self;
fn neg(self) -> Self::Output {
self * -1.0
}
}
impl Add for Vec3 {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
}
}
}
impl Add<Direction3> for Vec3 {
type Output = Self;
fn add(self, rhs: Direction3) -> Self::Output {
self + Self::from(rhs)
}
}
impl<T> AddAssign<T> for Vec3
where
Vec3: Add<T, Output = Self>,
{
fn add_assign(&mut self, rhs: T) {
*self = *self + rhs;
}
}
impl<T> Sub<T> for Vec3
where
Vec3: Add<T, Output = Self>,
{
type Output = Self;
fn sub(self, rhs: T) -> Self::Output {
-(-self + rhs)
}
}
impl<T> SubAssign<T> for Vec3
where
Vec3: Sub<T, Output = Self>,
{
fn sub_assign(&mut self, rhs: T) {
*self = *self - rhs;
}
}
impl Mul<f32> for Vec3 {
type Output = Self;
fn mul(self, rhs: f32) -> Self::Output {
Self {
x: self.x * rhs,
y: self.y * rhs,
z: self.z * rhs,
}
}
}
impl Div<f32> for Vec3 {
type Output = Self;
fn div(self, rhs: f32) -> Self::Output {
Self {
x: self.x / rhs,
y: self.y / rhs,
z: self.z / rhs,
}
}
}
impl MulAssign<f32> for Vec3 {
fn mul_assign(&mut self, rhs: f32) {
*self = *self * rhs;
}
}
impl DivAssign<f32> for Vec3 {
fn div_assign(&mut self, rhs: f32) {
*self = *self / rhs;
}
}
// Vec3Int
/// A set of 3 [`i32`]s representing a location or direction in the 3d plane.
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct Vec3Int {
/// The x component of the vector.
pub x: i32,
/// The y component of the vector.
pub y: i32,
/// The z component of the vector.
pub z: i32,
}
impl Debug for Vec3Int {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Vec3Int")
.field(&self.x)
.field(&self.y)
.field(&self.z)
.finish()
}
}
impl Vec3Int {
/// Creates a new `Vec3Int` with the given x-, y-, and z-values.
///
/// It is often simpler, and preferred, to just write `(x, y, z).into()`.
pub const fn new(x: i32, y: i32, z: i32) -> Vec3Int {
Self { x, y, z }
}
/// Gets the squared magnitude of the vector.
///
/// Useful for comparisons as it is faster to calculate than `magnitude`.
pub fn sq_magnitude(self) -> i32 {
self.x * self.x + self.y * self.y + self.z * self.z
}
/// Gets the magnitude of the vector.
pub fn magnitude(self) -> f32 {
#[allow(clippy::cast_precision_loss)]
(self.sq_magnitude() as f32).sqrt()
}
/// Gets the squared distance from this vector to `rhs`.
///
/// Useful for comparisons as it is faster to calculate than `dist`.
pub fn sq_dist(self, rhs: Self) -> i32 {
(self - rhs).sq_magnitude()
}
/// Gets the distance from this vector to `rhs`.
pub fn dist(self, rhs: Self) -> f32 {
(self - rhs).magnitude()
}
/// Casts this vector to a [`Vec3`].
///
/// This uses `as f32` under the hood, and as such comes with all the same unfortunate edge cases. Beware.
pub fn into_float(self) -> Vec3 {
#[allow(clippy::cast_precision_loss)]
Vec3 {
x: self.x as f32,
y: self.y as f32,
z: self.z as f32,
}
}
/// Transforms this vector into a [`Vec2Int`], dropping the z-coordinate.
pub fn into_vec2(self) -> Vec2Int {
Vec2Int {
x: self.x,
y: self.y,
}
}
}
impl From<(i32, i32, i32)> for Vec3Int {
fn from(v: (i32, i32, i32)) -> Self {
Self {
x: v.0,
y: v.1,
z: v.2,
}
}
}
impl From<Vec3Int> for (i32, i32, i32) {
fn from(v: Vec3Int) -> Self {
(v.x, v.y, v.z)
}
}
impl PartialEq<(i32, i32, i32)> for Vec3Int {
fn eq(&self, other: &(i32, i32, i32)) -> bool {
self == &Self::from(*other)
}
}
// ...and related op impls
impl Neg for Vec3Int {
type Output = Self;
fn neg(self) -> Self::Output {
self * -1
}
}
impl Add for Vec3Int {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
}
}
}
impl Add<Direction3> for Vec3Int {
type Output = Self;
fn add(self, rhs: Direction3) -> Self::Output {
self + Self::from(rhs)
}
}
impl<T> AddAssign<T> for Vec3Int
where
Vec3Int: Add<T, Output = Self>,
{
fn add_assign(&mut self, rhs: T) {
*self = *self + rhs;
}
}
impl<T> Sub<T> for Vec3Int
where
Vec3Int: Add<T, Output = Self>,
{
type Output = Self;
fn sub(self, rhs: T) -> Self::Output {
-(-self + rhs)
}
}
impl<T> SubAssign<T> for Vec3Int
where
Vec3Int: Sub<T, Output = Self>,
{
fn sub_assign(&mut self, rhs: T) {
*self = *self - rhs;
}
}
impl Mul<i32> for Vec3Int {
type Output = Self;
fn mul(self, rhs: i32) -> Self::Output {
Self {
x: self.x * rhs,
y: self.y * rhs,
z: self.z * rhs,
}
}
}
impl Div<i32> for Vec3Int {
type Output = Self;
fn div(self, rhs: i32) -> Self::Output {
Self {
x: self.x / rhs,
y: self.y / rhs,
z: self.z / rhs,
}
}
}
impl MulAssign<i32> for Vec3Int {
fn mul_assign(&mut self, rhs: i32) {
*self = *self * rhs;
}
}
impl DivAssign<i32> for Vec3Int {
fn div_assign(&mut self, rhs: i32) {
*self = *self / rhs;
}
}