initial commit
This commit is contained in:
363
Cargo.lock
generated
363
Cargo.lock
generated
@@ -207,16 +207,29 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-executor"
|
name = "async-channel"
|
||||||
version = "1.6.0"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4b0c4a4f319e45986f347ee47fef8bf5e81c9abc3f6f58dc2391439f30df65f0"
|
checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-lock 2.8.0",
|
"concurrent-queue",
|
||||||
|
"event-listener 4.0.0",
|
||||||
|
"event-listener-strategy",
|
||||||
|
"futures-core",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-executor"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c"
|
||||||
|
dependencies = [
|
||||||
|
"async-lock 3.2.0",
|
||||||
"async-task",
|
"async-task",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"fastrand 2.0.1",
|
"fastrand 2.0.1",
|
||||||
"futures-lite 1.13.0",
|
"futures-lite 2.1.0",
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -234,16 +247,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-global-executor"
|
name = "async-global-executor"
|
||||||
version = "2.3.1"
|
version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776"
|
checksum = "9b4353121d5644cdf2beb5726ab752e79a8db1ebb52031770ec47db31d245526"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel 2.1.1",
|
||||||
"async-executor",
|
"async-executor",
|
||||||
"async-io 1.13.0",
|
"async-io 2.2.1",
|
||||||
"async-lock 2.8.0",
|
"async-lock 3.2.0",
|
||||||
"blocking",
|
"blocking",
|
||||||
"futures-lite 1.13.0",
|
"futures-lite 2.1.0",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -269,22 +282,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-io"
|
name = "async-io"
|
||||||
version = "2.2.0"
|
version = "2.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41ed9d5715c2d329bf1b4da8d60455b99b187f27ba726df2883799af9af60997"
|
checksum = "d6d3b15875ba253d1110c740755e246537483f152fa334f91abd7fe84c88b3ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-lock 3.0.0",
|
"async-lock 3.2.0",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite 2.0.1",
|
"futures-lite 2.1.0",
|
||||||
"parking",
|
"parking",
|
||||||
"polling 3.3.0",
|
"polling 3.3.1",
|
||||||
"rustix 0.38.21",
|
"rustix 0.38.26",
|
||||||
"slab",
|
"slab",
|
||||||
"tracing",
|
"tracing",
|
||||||
"waker-fn",
|
"windows-sys 0.52.0",
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -298,11 +310,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-lock"
|
name = "async-lock"
|
||||||
version = "3.0.0"
|
version = "3.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "45e900cdcd39bb94a14487d3f7ef92ca222162e6c7c3fe7cb3550ea75fb486ed"
|
checksum = "7125e42787d53db9dd54261812ef17e937c95a51e4d291373b670342fa44310c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"event-listener 3.0.1",
|
"event-listener 4.0.0",
|
||||||
"event-listener-strategy",
|
"event-listener-strategy",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
@@ -318,9 +330,9 @@ dependencies = [
|
|||||||
"async-signal",
|
"async-signal",
|
||||||
"blocking",
|
"blocking",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"event-listener 3.0.1",
|
"event-listener 3.1.0",
|
||||||
"futures-lite 1.13.0",
|
"futures-lite 1.13.0",
|
||||||
"rustix 0.38.21",
|
"rustix 0.38.26",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -341,13 +353,13 @@ version = "0.2.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5"
|
checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-io 2.2.0",
|
"async-io 2.2.1",
|
||||||
"async-lock 2.8.0",
|
"async-lock 2.8.0",
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"rustix 0.38.21",
|
"rustix 0.38.26",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"slab",
|
"slab",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
@@ -359,7 +371,7 @@ version = "1.12.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
|
checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel 1.9.0",
|
||||||
"async-global-executor",
|
"async-global-executor",
|
||||||
"async-io 1.13.0",
|
"async-io 1.13.0",
|
||||||
"async-lock 2.8.0",
|
"async-lock 2.8.0",
|
||||||
@@ -550,9 +562,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bindgen"
|
name = "bindgen"
|
||||||
version = "0.68.1"
|
version = "0.69.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078"
|
checksum = "9ffcebc3849946a7170a05992aac39da343a90676ab392c51a4280981d6379c2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
"cexpr",
|
"cexpr",
|
||||||
@@ -616,16 +628,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blocking"
|
name = "blocking"
|
||||||
version = "1.4.1"
|
version = "1.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8c36a4d0d48574b3dd360b4b7d95cc651d2b6557b6402848a27d4b228a473e2a"
|
checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel 2.1.1",
|
||||||
"async-lock 2.8.0",
|
"async-lock 3.2.0",
|
||||||
"async-task",
|
"async-task",
|
||||||
"fastrand 2.0.1",
|
"fastrand 2.0.1",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite 1.13.0",
|
"futures-lite 2.1.0",
|
||||||
"piper",
|
"piper",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@@ -815,9 +827,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "concurrent-queue"
|
||||||
version = "2.3.0"
|
version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400"
|
checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
@@ -851,9 +863,9 @@ checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.3"
|
version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -861,9 +873,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.4"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-graphics"
|
name = "core-graphics"
|
||||||
@@ -893,9 +905,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-graphics-types"
|
name = "core-graphics-types"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33"
|
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
@@ -915,11 +927,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "coreaudio-sys"
|
name = "coreaudio-sys"
|
||||||
version = "0.2.13"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d8478e5bdad14dce236b9898ea002eabfa87cbe14f0aa538dbe3b6a4bec4332d"
|
checksum = "f3120ebb80a9de008e638ad833d4127d50ea3d3a960ea23ea69bc66d9358a028"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bindgen 0.68.1",
|
"bindgen 0.69.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1215,9 +1227,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.10.0"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
|
checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"humantime",
|
"humantime",
|
||||||
"is-terminal",
|
"is-terminal",
|
||||||
@@ -1234,12 +1246,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.6"
|
version = "0.3.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e"
|
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1250,9 +1262,20 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
version = "3.0.1"
|
version = "3.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "01cec0252c2afff729ee6f00e903d479fba81784c8e2bd77447673471fdfaea1"
|
checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2"
|
||||||
|
dependencies = [
|
||||||
|
"concurrent-queue",
|
||||||
|
"parking",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "event-listener"
|
||||||
|
version = "4.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"parking",
|
"parking",
|
||||||
@@ -1261,11 +1284,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener-strategy"
|
name = "event-listener-strategy"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160"
|
checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"event-listener 3.0.1",
|
"event-listener 4.0.0",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1371,9 +1394,9 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.0"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
|
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
@@ -1399,6 +1422,21 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.3.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-io",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.29"
|
version = "0.3.29"
|
||||||
@@ -1406,6 +1444,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
|
checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1414,6 +1453,17 @@ version = "0.3.29"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
|
checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-executor"
|
||||||
|
version = "0.3.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-io"
|
name = "futures-io"
|
||||||
version = "0.3.29"
|
version = "0.3.29"
|
||||||
@@ -1437,11 +1487,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-lite"
|
name = "futures-lite"
|
||||||
version = "2.0.1"
|
version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb"
|
checksum = "aeee267a1883f7ebef3700f262d2d54de95dfaf38189015a74fdc4e0c7ad8143"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"fastrand 2.0.1",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"parking",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1474,6 +1527,7 @@ version = "0.3.29"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
|
checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-macro",
|
"futures-macro",
|
||||||
@@ -1552,9 +1606,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.2"
|
version = "0.14.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
@@ -1655,9 +1709,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
|
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-bidi",
|
"unicode-bidi",
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
@@ -1681,7 +1735,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.14.2",
|
"hashbrown 0.14.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1740,7 +1794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.3.3",
|
"hermit-abi 0.3.3",
|
||||||
"rustix 0.38.21",
|
"rustix 0.38.26",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1813,9 +1867,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.65"
|
version = "0.3.66"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
|
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
@@ -1923,9 +1977,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.4.11"
|
version = "0.4.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
|
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
@@ -2367,9 +2421,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.0"
|
version = "2.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
@@ -2459,16 +2513,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polling"
|
name = "polling"
|
||||||
version = "3.3.0"
|
version = "3.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e53b6af1f60f36f8c2ac2aad5459d75a5a9b4be1e8cdd40264f315d78193e531"
|
checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"rustix 0.38.21",
|
"rustix 0.38.26",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2523,9 +2577,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.69"
|
version = "1.0.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -2693,15 +2747,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.21"
|
version = "0.38.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
|
checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys 0.4.11",
|
"linux-raw-sys 0.4.12",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2766,18 +2820,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.192"
|
version = "1.0.193"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
|
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.192"
|
version = "1.0.193"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
|
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2841,9 +2895,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shaderc"
|
name = "shaderc"
|
||||||
version = "0.8.2"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "31cef52787a0db5108788ea20bed13d6bf4b96287c5c5201e55725f7070f3443"
|
checksum = "27e07913ada18607bb60d12431cbe3358d3bbebbe95948e1618851dc01e63b7b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"shaderc-sys",
|
"shaderc-sys",
|
||||||
@@ -2851,9 +2905,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shaderc-sys"
|
name = "shaderc-sys"
|
||||||
version = "0.8.2"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e8f8439fffcffd6efcd74197204addf935dbab5752696bd990a6cd36d54cf64"
|
checksum = "73120d240fe22196300f39ca8547ca2d014960f27b19b47b21288b396272f7f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cmake",
|
"cmake",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -2898,18 +2952,18 @@ checksum = "a4f120bb98cb4cb0dab21c882968c3cbff79dd23b46f07b1cf5c25044945ce84"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slotmap"
|
name = "slotmap"
|
||||||
version = "1.0.6"
|
version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
|
checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.11.1"
|
version = "1.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay-client-toolkit"
|
name = "smithay-client-toolkit"
|
||||||
@@ -3061,15 +3115,15 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand 2.0.1",
|
"fastrand 2.0.1",
|
||||||
"redox_syscall 0.4.1",
|
"redox_syscall 0.4.1",
|
||||||
"rustix 0.38.21",
|
"rustix 0.38.26",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.3.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
|
checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
@@ -3283,9 +3337,9 @@ checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.4.1"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
|
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"idna",
|
"idna",
|
||||||
@@ -3431,9 +3485,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.88"
|
version = "0.2.89"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
|
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
@@ -3441,9 +3495,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.88"
|
version = "0.2.89"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
|
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"log",
|
"log",
|
||||||
@@ -3456,9 +3510,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-futures"
|
name = "wasm-bindgen-futures"
|
||||||
version = "0.4.38"
|
version = "0.4.39"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02"
|
checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@@ -3468,9 +3522,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.88"
|
version = "0.2.89"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
|
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -3478,9 +3532,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.88"
|
version = "0.2.89"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
|
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -3491,9 +3545,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.88"
|
version = "0.2.89"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
|
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-backend"
|
name = "wayland-backend"
|
||||||
@@ -3656,9 +3710,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.65"
|
version = "0.3.66"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85"
|
checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -3673,7 +3727,7 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
"home",
|
"home",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix 0.38.21",
|
"rustix 0.38.26",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3743,6 +3797,15 @@ dependencies = [
|
|||||||
"windows-targets 0.48.5",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -3773,6 +3836,21 @@ dependencies = [
|
|||||||
"windows_x86_64_msvc 0.48.5",
|
"windows_x86_64_msvc 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.52.0",
|
||||||
|
"windows_aarch64_msvc 0.52.0",
|
||||||
|
"windows_i686_gnu 0.52.0",
|
||||||
|
"windows_i686_msvc 0.52.0",
|
||||||
|
"windows_x86_64_gnu 0.52.0",
|
||||||
|
"windows_x86_64_gnullvm 0.52.0",
|
||||||
|
"windows_x86_64_msvc 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -3785,6 +3863,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -3797,6 +3881,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -3809,6 +3899,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -3821,6 +3917,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -3833,6 +3935,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -3845,6 +3953,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -3857,6 +3971,12 @@ version = "0.48.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit"
|
name = "winit"
|
||||||
version = "0.28.7"
|
version = "0.28.7"
|
||||||
@@ -3894,9 +4014,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.5.19"
|
version = "0.5.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b"
|
checksum = "40460c13b1e9b107cfc9ede71232f204c36250bbf6f9c78515e2e27ead3122a7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@@ -3904,6 +4024,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "wlx-capture"
|
name = "wlx-capture"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/galister/wlx-capture.git#56eba19fac9834e2dfb77dd3a0a93b088a93dee9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ashpd",
|
"ashpd",
|
||||||
"drm-fourcc",
|
"drm-fourcc",
|
||||||
@@ -3923,12 +4044,14 @@ dependencies = [
|
|||||||
name = "wlx-overlay-s"
|
name = "wlx-overlay-s"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ash",
|
||||||
"ash-window",
|
"ash-window",
|
||||||
"chrono",
|
"chrono",
|
||||||
"cstr",
|
"cstr",
|
||||||
"env_logger 0.10.0",
|
"env_logger 0.10.1",
|
||||||
"fontconfig-rs",
|
"fontconfig-rs",
|
||||||
"freetype-rs",
|
"freetype-rs",
|
||||||
|
"futures",
|
||||||
"glam",
|
"glam",
|
||||||
"idmap",
|
"idmap",
|
||||||
"idmap-derive",
|
"idmap-derive",
|
||||||
@@ -4097,18 +4220,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.25"
|
version = "0.7.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557"
|
checksum = "7d6f15f7ade05d2a4935e34a457b936c23dc70a05cc1d97133dc99e7a3fe0f0e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.7.25"
|
version = "0.7.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b"
|
checksum = "dbbad221e3f78500350ecbd7dfa4e63ef945c05f4c61cb7f4d3f84cd0bba649b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
ash = "^0.37.2"
|
||||||
ash-window = "0.12.0"
|
ash-window = "0.12.0"
|
||||||
chrono = "0.4.29"
|
chrono = "0.4.29"
|
||||||
cstr = "0.2.11"
|
cstr = "0.2.11"
|
||||||
env_logger = "0.10.0"
|
env_logger = "0.10.0"
|
||||||
fontconfig-rs = { version = "0.1.1", features = ["dlopen"] }
|
fontconfig-rs = { version = "0.1.1", features = ["dlopen"] }
|
||||||
freetype-rs = "0.32.0"
|
freetype-rs = "0.32.0"
|
||||||
|
futures = "0.3.29"
|
||||||
glam = { version = "0.24.1", features = ["approx"] }
|
glam = { version = "0.24.1", features = ["approx"] }
|
||||||
idmap = "0.2.21"
|
idmap = "0.2.21"
|
||||||
idmap-derive = "0.1.2"
|
idmap-derive = "0.1.2"
|
||||||
@@ -34,5 +36,5 @@ vulkano-shaders = "0.33.0"
|
|||||||
vulkano-util = "0.33.0"
|
vulkano-util = "0.33.0"
|
||||||
vulkano-win = "0.33.0"
|
vulkano-win = "0.33.0"
|
||||||
winit = "0.28.6"
|
winit = "0.28.6"
|
||||||
wlx-capture = { version = "0.1.0", path = "../wlx-capture" }
|
wlx-capture = { git = "https://github.com/galister/wlx-capture.git" }
|
||||||
|
|
||||||
|
|||||||
674
LICENSE
Normal file
674
LICENSE
Normal file
@@ -0,0 +1,674 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||||
4
README.md
Normal file
4
README.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# WlxOverlay-S
|
||||||
|
[WIP] X11 & Wayland desktop overlay for SteamVR and OpenXR, Vulkan edition
|
||||||
|
|
||||||
|
Nothing works yet.
|
||||||
@@ -1,152 +1,158 @@
|
|||||||
use std::{collections::VecDeque, time::Instant};
|
use std::{
|
||||||
|
collections::{BinaryHeap, VecDeque},
|
||||||
|
sync::Arc,
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
|
|
||||||
use glam::{Affine3A, Vec2, Vec3, Vec3A};
|
use idmap::IdMap;
|
||||||
use ovr_overlay::TrackedDeviceIndex;
|
|
||||||
|
|
||||||
pub struct InputState<TState, THand> {
|
use crate::{
|
||||||
pub hmd: Affine3A,
|
overlays::{
|
||||||
pub pointers: [Pointer<THand>; 2],
|
keyboard::create_keyboard,
|
||||||
pub devices: Vec<TrackedDevice>,
|
screen::{get_screens_wayland, get_screens_x11},
|
||||||
pub(super) data: TState,
|
watch::create_watch,
|
||||||
|
},
|
||||||
|
state::AppState,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::overlay::{OverlayData, OverlayState};
|
||||||
|
|
||||||
|
pub struct OverlayContainer<T>
|
||||||
|
where
|
||||||
|
T: Default,
|
||||||
|
{
|
||||||
|
overlays: IdMap<usize, OverlayData<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TState, THand> InputState<TState, THand> {
|
impl<T> OverlayContainer<T>
|
||||||
pub fn pre_update(&mut self) {
|
where
|
||||||
self.pointers[0].before = self.pointers[0].now;
|
T: Default,
|
||||||
self.pointers[1].before = self.pointers[1].now;
|
{
|
||||||
|
pub fn new(app: &mut AppState) -> Self {
|
||||||
|
let mut overlays = IdMap::new();
|
||||||
|
|
||||||
|
let screens = if std::env::var("WAYLAND_DISPLAY").is_ok() {
|
||||||
|
get_screens_wayland(&app.session)
|
||||||
|
} else {
|
||||||
|
get_screens_x11()
|
||||||
|
};
|
||||||
|
|
||||||
|
let watch = create_watch::<T>(&app, &screens);
|
||||||
|
overlays.insert(watch.state.id, watch);
|
||||||
|
|
||||||
|
let keyboard = create_keyboard(&app);
|
||||||
|
overlays.insert(keyboard.state.id, keyboard);
|
||||||
|
|
||||||
|
let mut first = true;
|
||||||
|
for mut screen in screens {
|
||||||
|
if first {
|
||||||
|
screen.state.want_visible = true;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
overlays.insert(screen.state.id, screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { overlays }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn post_update(&mut self) {
|
pub fn mut_by_selector(&mut self, selector: &OverlaySelector) -> Option<&mut OverlayData<T>> {
|
||||||
for hand in &mut self.pointers {
|
match selector {
|
||||||
if hand.now.click_modifier_right {
|
OverlaySelector::Id(id) => self.mut_by_id(*id),
|
||||||
hand.interaction.mode = PointerMode::Right;
|
OverlaySelector::Name(name) => self.mut_by_name(name),
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if hand.now.click_modifier_middle {
|
|
||||||
hand.interaction.mode = PointerMode::Middle;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let hmd_up = self.hmd.transform_vector3a(Vec3A::Y);
|
|
||||||
let dot =
|
|
||||||
hmd_up.dot(hand.pose.transform_vector3a(Vec3A::X)) * (1.0 - 2.0 * hand.hand as f32);
|
|
||||||
|
|
||||||
hand.interaction.mode = if dot < -0.85 {
|
|
||||||
PointerMode::Right
|
|
||||||
} else if dot > 0.7 {
|
|
||||||
PointerMode::Middle
|
|
||||||
} else {
|
|
||||||
PointerMode::Left
|
|
||||||
};
|
|
||||||
|
|
||||||
let middle_click_orientation = false;
|
|
||||||
let right_click_orientation = false;
|
|
||||||
match hand.interaction.mode {
|
|
||||||
PointerMode::Middle => {
|
|
||||||
if !middle_click_orientation {
|
|
||||||
hand.interaction.mode = PointerMode::Left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PointerMode::Right => {
|
|
||||||
if !right_click_orientation {
|
|
||||||
hand.interaction.mode = PointerMode::Left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_by_id<'a>(&'a mut self, id: usize) -> Option<&'a OverlayData<T>> {
|
||||||
|
self.overlays.get(&id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mut_by_id<'a>(&'a mut self, id: usize) -> Option<&'a mut OverlayData<T>> {
|
||||||
|
self.overlays.get_mut(&id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_by_name<'a>(&'a mut self, name: &str) -> Option<&'a OverlayData<T>> {
|
||||||
|
self.overlays.values().find(|o| *o.state.name == *name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mut_by_name<'a>(&'a mut self, name: &str) -> Option<&'a mut OverlayData<T>> {
|
||||||
|
self.overlays.values_mut().find(|o| *o.state.name == *name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a OverlayData<T>> {
|
||||||
|
self.overlays.values()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut OverlayData<T>> {
|
||||||
|
self.overlays.values_mut()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Pointer<THand> {
|
pub enum OverlaySelector {
|
||||||
pub hand: usize,
|
Id(usize),
|
||||||
pub pose: Affine3A,
|
Name(Arc<str>),
|
||||||
pub now: PointerState,
|
|
||||||
pub before: PointerState,
|
|
||||||
pub(super) interaction: InteractionState,
|
|
||||||
pub(super) data: THand,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
struct AppTask {
|
||||||
pub struct PointerState {
|
pub not_before: Instant,
|
||||||
pub scroll: f32,
|
pub task: TaskType,
|
||||||
pub click: bool,
|
|
||||||
pub grab: bool,
|
|
||||||
pub alt_click: bool,
|
|
||||||
pub show_hide: bool,
|
|
||||||
pub space_drag: bool,
|
|
||||||
pub click_modifier_right: bool,
|
|
||||||
pub click_modifier_middle: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InteractionState {
|
impl PartialEq<AppTask> for AppTask {
|
||||||
pub mode: PointerMode,
|
fn eq(&self, other: &Self) -> bool {
|
||||||
pub grabbed: Option<GrabData>,
|
self.not_before == other.not_before
|
||||||
pub clicked_id: Option<usize>,
|
}
|
||||||
pub hovered_id: Option<usize>,
|
}
|
||||||
pub release_actions: VecDeque<Box<dyn Fn()>>,
|
impl PartialOrd<AppTask> for AppTask {
|
||||||
pub next_push: Instant,
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.not_before.cmp(&other.not_before).reverse())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Eq for AppTask {}
|
||||||
|
impl Ord for AppTask {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.not_before.cmp(&other.not_before).reverse()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for InteractionState {
|
pub enum TaskType {
|
||||||
fn default() -> Self {
|
Global(Box<dyn FnOnce(&mut AppState) + Send>),
|
||||||
|
Overlay(
|
||||||
|
OverlaySelector,
|
||||||
|
Box<dyn FnOnce(&mut AppState, &mut OverlayState) + Send>,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TaskContainer {
|
||||||
|
tasks: BinaryHeap<AppTask>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TaskContainer {
|
||||||
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
mode: PointerMode::Left,
|
tasks: BinaryHeap::new(),
|
||||||
grabbed: None,
|
}
|
||||||
clicked_id: None,
|
}
|
||||||
hovered_id: None,
|
|
||||||
release_actions: VecDeque::new(),
|
pub fn enqueue(&mut self, task: TaskType) {
|
||||||
next_push: Instant::now(),
|
self.tasks.push(AppTask {
|
||||||
|
not_before: Instant::now(),
|
||||||
|
task,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueue_at(&mut self, task: TaskType, not_before: Instant) {
|
||||||
|
self.tasks.push(AppTask { not_before, task });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn retrieve_due(&mut self, dest_buf: &mut VecDeque<TaskType>) {
|
||||||
|
let now = Instant::now();
|
||||||
|
|
||||||
|
while let Some(task) = self.tasks.peek() {
|
||||||
|
if task.not_before > now {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest_buf.push_back(self.tasks.pop().unwrap().task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PointerHit {
|
|
||||||
pub hand: usize,
|
|
||||||
pub mode: PointerMode,
|
|
||||||
pub primary: bool,
|
|
||||||
pub uv: Vec2,
|
|
||||||
pub dist: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RayHit {
|
|
||||||
idx: usize,
|
|
||||||
ray_pos: Vec3,
|
|
||||||
hit_pos: Vec3,
|
|
||||||
uv: Vec2,
|
|
||||||
dist: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
|
||||||
pub struct GrabData {
|
|
||||||
pub offset: Vec3,
|
|
||||||
pub grabbed_id: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
|
||||||
pub enum PointerMode {
|
|
||||||
#[default]
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Middle,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TrackedDevice {
|
|
||||||
pub index: TrackedDeviceIndex,
|
|
||||||
pub valid: bool,
|
|
||||||
pub soc: Option<f32>,
|
|
||||||
pub charging: bool,
|
|
||||||
pub role: TrackedDeviceRole,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum TrackedDeviceRole {
|
|
||||||
None,
|
|
||||||
Hmd,
|
|
||||||
LeftHand,
|
|
||||||
RightHand,
|
|
||||||
Tracker,
|
|
||||||
}
|
|
||||||
|
|||||||
362
src/backend/input.rs
Normal file
362
src/backend/input.rs
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
use std::{collections::VecDeque, time::Instant};
|
||||||
|
|
||||||
|
use glam::{Affine3A, Vec2, Vec3A};
|
||||||
|
use log::warn;
|
||||||
|
use ovr_overlay::TrackedDeviceIndex;
|
||||||
|
use tinyvec::array_vec;
|
||||||
|
|
||||||
|
use crate::state::AppState;
|
||||||
|
|
||||||
|
use super::{common::OverlayContainer, overlay::OverlayData};
|
||||||
|
|
||||||
|
pub struct TrackedDevice {
|
||||||
|
pub index: TrackedDeviceIndex,
|
||||||
|
pub valid: bool,
|
||||||
|
pub soc: Option<f32>,
|
||||||
|
pub charging: bool,
|
||||||
|
pub role: TrackedDeviceRole,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum TrackedDeviceRole {
|
||||||
|
None,
|
||||||
|
Hmd,
|
||||||
|
LeftHand,
|
||||||
|
RightHand,
|
||||||
|
Tracker,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InputState<TState, THand> {
|
||||||
|
pub hmd: Affine3A,
|
||||||
|
pub pointers: [Pointer<THand>; 2],
|
||||||
|
pub devices: Vec<TrackedDevice>,
|
||||||
|
pub(super) data: TState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TState, THand> InputState<TState, THand> {
|
||||||
|
pub fn pre_update(&mut self) {
|
||||||
|
self.pointers[0].before = self.pointers[0].now;
|
||||||
|
self.pointers[1].before = self.pointers[1].now;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn post_update(&mut self) {
|
||||||
|
for hand in &mut self.pointers {
|
||||||
|
if hand.now.click_modifier_right {
|
||||||
|
hand.interaction.mode = PointerMode::Right;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if hand.now.click_modifier_middle {
|
||||||
|
hand.interaction.mode = PointerMode::Middle;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hmd_up = self.hmd.transform_vector3a(Vec3A::Y);
|
||||||
|
let dot =
|
||||||
|
hmd_up.dot(hand.pose.transform_vector3a(Vec3A::X)) * (1.0 - 2.0 * hand.hand as f32);
|
||||||
|
|
||||||
|
hand.interaction.mode = if dot < -0.85 {
|
||||||
|
PointerMode::Right
|
||||||
|
} else if dot > 0.7 {
|
||||||
|
PointerMode::Middle
|
||||||
|
} else {
|
||||||
|
PointerMode::Left
|
||||||
|
};
|
||||||
|
|
||||||
|
let middle_click_orientation = false;
|
||||||
|
let right_click_orientation = false;
|
||||||
|
match hand.interaction.mode {
|
||||||
|
PointerMode::Middle => {
|
||||||
|
if !middle_click_orientation {
|
||||||
|
hand.interaction.mode = PointerMode::Left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PointerMode::Right => {
|
||||||
|
if !right_click_orientation {
|
||||||
|
hand.interaction.mode = PointerMode::Left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InteractionState {
|
||||||
|
pub mode: PointerMode,
|
||||||
|
pub grabbed: Option<GrabData>,
|
||||||
|
pub clicked_id: Option<usize>,
|
||||||
|
pub hovered_id: Option<usize>,
|
||||||
|
pub release_actions: VecDeque<Box<dyn Fn()>>,
|
||||||
|
pub next_push: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for InteractionState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
mode: PointerMode::Left,
|
||||||
|
grabbed: None,
|
||||||
|
clicked_id: None,
|
||||||
|
hovered_id: None,
|
||||||
|
release_actions: VecDeque::new(),
|
||||||
|
next_push: Instant::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Pointer<THand> {
|
||||||
|
pub idx: usize,
|
||||||
|
pub hand: u8,
|
||||||
|
pub pose: Affine3A,
|
||||||
|
pub now: PointerState,
|
||||||
|
pub before: PointerState,
|
||||||
|
pub(super) interaction: InteractionState,
|
||||||
|
pub(super) data: THand,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
pub struct PointerState {
|
||||||
|
pub scroll: f32,
|
||||||
|
pub click: bool,
|
||||||
|
pub grab: bool,
|
||||||
|
pub alt_click: bool,
|
||||||
|
pub show_hide: bool,
|
||||||
|
pub space_drag: bool,
|
||||||
|
pub click_modifier_right: bool,
|
||||||
|
pub click_modifier_middle: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
pub struct PointerHit {
|
||||||
|
pub pointer: usize,
|
||||||
|
pub overlay: usize,
|
||||||
|
pub mode: PointerMode,
|
||||||
|
pub primary: bool,
|
||||||
|
pub uv: Vec2,
|
||||||
|
pub dist: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait InteractionHandler {
|
||||||
|
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit);
|
||||||
|
fn on_left(&mut self, app: &mut AppState, pointer: usize);
|
||||||
|
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool);
|
||||||
|
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DummyInteractionHandler;
|
||||||
|
|
||||||
|
impl InteractionHandler for DummyInteractionHandler {
|
||||||
|
fn on_left(&mut self, _app: &mut AppState, _pointer: usize) {}
|
||||||
|
fn on_hover(&mut self, _app: &mut AppState, _hit: &PointerHit) {}
|
||||||
|
fn on_pointer(&mut self, _app: &mut AppState, _hit: &PointerHit, _pressed: bool) {}
|
||||||
|
fn on_scroll(&mut self, _app: &mut AppState, _hit: &PointerHit, _delta: f32) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
struct RayHit {
|
||||||
|
overlay: usize,
|
||||||
|
hit_pos: Vec3A,
|
||||||
|
dist: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
pub struct GrabData {
|
||||||
|
pub offset: Vec3A,
|
||||||
|
pub grabbed_id: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
pub enum PointerMode {
|
||||||
|
#[default]
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Middle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<THand> Pointer<THand> {
|
||||||
|
pub fn interact<O>(&mut self, overlays: &mut OverlayContainer<O>, app: &mut AppState)
|
||||||
|
where
|
||||||
|
O: Default,
|
||||||
|
{
|
||||||
|
if let Some(grab_data) = self.interaction.grabbed {
|
||||||
|
if let Some(grabbed) = overlays.mut_by_id(grab_data.grabbed_id) {
|
||||||
|
self.handle_grabbed(grabbed, grab_data.offset);
|
||||||
|
} else {
|
||||||
|
warn!("Grabbed overlay {} does not exist", grab_data.grabbed_id);
|
||||||
|
self.interaction.grabbed = None;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(mut hit) = self.get_nearest_hit(overlays) else {
|
||||||
|
if let Some(hovered_id) = self.interaction.hovered_id.take() {
|
||||||
|
if let Some(hovered) = overlays.mut_by_id(hovered_id) {
|
||||||
|
hovered.backend.on_left(app, self.idx);
|
||||||
|
}
|
||||||
|
self.interaction.hovered_id = None;
|
||||||
|
}
|
||||||
|
if let Some(clicked_id) = self.interaction.clicked_id.take() {
|
||||||
|
if let Some(clicked) = overlays.mut_by_id(clicked_id) {
|
||||||
|
let hit = PointerHit {
|
||||||
|
pointer: self.idx,
|
||||||
|
overlay: clicked_id,
|
||||||
|
mode: self.interaction.mode,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
clicked.backend.on_pointer(app, &hit, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(hovered_id) = self.interaction.hovered_id {
|
||||||
|
if hovered_id != hit.overlay {
|
||||||
|
if let Some(old_hovered) = overlays.mut_by_id(hovered_id) {
|
||||||
|
if Some(self.idx) == old_hovered.primary_pointer {
|
||||||
|
old_hovered.primary_pointer = None;
|
||||||
|
}
|
||||||
|
old_hovered.backend.on_left(app, self.idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let Some(hovered) = overlays.mut_by_id(hit.overlay) else {
|
||||||
|
warn!("Hit overlay {} does not exist", hit.overlay);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.interaction.hovered_id = Some(hit.overlay);
|
||||||
|
|
||||||
|
if let Some(primary_pointer) = hovered.primary_pointer {
|
||||||
|
if hit.pointer < primary_pointer {
|
||||||
|
hovered.primary_pointer = Some(hit.pointer);
|
||||||
|
hit.primary = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hovered.primary_pointer = Some(hit.pointer);
|
||||||
|
hit.primary = true;
|
||||||
|
}
|
||||||
|
hovered.backend.on_hover(app, &hit);
|
||||||
|
|
||||||
|
if self.now.scroll.abs() > 0.1 {
|
||||||
|
hovered.backend.on_scroll(app, &hit, self.now.scroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.now.click && !self.before.click {
|
||||||
|
self.interaction.clicked_id = Some(hit.overlay);
|
||||||
|
hovered.backend.on_pointer(app, &hit, true);
|
||||||
|
} else if !self.now.click && self.before.click {
|
||||||
|
if let Some(clicked_id) = self.interaction.clicked_id.take() {
|
||||||
|
if let Some(clicked) = overlays.mut_by_id(clicked_id) {
|
||||||
|
clicked.backend.on_pointer(app, &hit, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hovered.backend.on_pointer(app, &hit, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_nearest_hit<O>(&mut self, overlays: &mut OverlayContainer<O>) -> Option<PointerHit>
|
||||||
|
where
|
||||||
|
O: Default,
|
||||||
|
{
|
||||||
|
let mut hits = array_vec!([RayHit; 8]);
|
||||||
|
|
||||||
|
for overlay in overlays.iter() {
|
||||||
|
if !overlay.state.want_visible {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(hit) = self.ray_test(overlay.state.id, &overlay.state.transform) {
|
||||||
|
hits.try_push(hit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hits.sort_by(|a, b| a.dist.partial_cmp(&b.dist).unwrap());
|
||||||
|
|
||||||
|
for hit in hits.iter() {
|
||||||
|
let uv = overlays
|
||||||
|
.get_by_id(hit.overlay)
|
||||||
|
.unwrap() // this is safe
|
||||||
|
.state
|
||||||
|
.transform
|
||||||
|
.inverse()
|
||||||
|
.transform_point3a(hit.hit_pos)
|
||||||
|
.truncate();
|
||||||
|
|
||||||
|
if uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(PointerHit {
|
||||||
|
pointer: self.idx,
|
||||||
|
overlay: hit.overlay,
|
||||||
|
mode: self.interaction.mode,
|
||||||
|
primary: false,
|
||||||
|
uv,
|
||||||
|
dist: hit.dist,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_grab<O>(&mut self, overlay: &mut OverlayData<O>)
|
||||||
|
where
|
||||||
|
O: Default,
|
||||||
|
{
|
||||||
|
let offset = self
|
||||||
|
.pose
|
||||||
|
.inverse()
|
||||||
|
.transform_point3a(overlay.state.transform.translation);
|
||||||
|
|
||||||
|
self.interaction.grabbed = Some(GrabData {
|
||||||
|
offset,
|
||||||
|
grabbed_id: overlay.state.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn handle_grabbed<O>(&mut self, overlay: &mut OverlayData<O>, offset: Vec3A)
|
||||||
|
where
|
||||||
|
O: Default,
|
||||||
|
{
|
||||||
|
if self.now.grab {
|
||||||
|
overlay.state.transform.translation = self.pose.transform_point3a(offset);
|
||||||
|
|
||||||
|
if self.now.click && !self.before.click {
|
||||||
|
warn!("todo: click-while-grabbed");
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.interaction.mode {
|
||||||
|
PointerMode::Left => {
|
||||||
|
overlay.state.transform.translation.y += self.now.scroll * 0.01;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
overlay.state.transform.matrix3 = overlay
|
||||||
|
.state
|
||||||
|
.transform
|
||||||
|
.matrix3
|
||||||
|
.mul_scalar(1.0 + 0.01 * self.now.scroll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
overlay.state.spawn_point = overlay.state.transform.translation;
|
||||||
|
self.interaction.grabbed = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn ray_test(&self, overlay: usize, plane: &Affine3A) -> Option<RayHit> {
|
||||||
|
let plane_normal = plane.transform_vector3a(Vec3A::NEG_Z);
|
||||||
|
let ray_dir = self.pose.transform_vector3a(Vec3A::NEG_Z);
|
||||||
|
|
||||||
|
let d = plane.translation.dot(-plane_normal);
|
||||||
|
let dist = -(d + self.pose.translation.dot(plane_normal)) / ray_dir.dot(plane_normal);
|
||||||
|
|
||||||
|
let hit_pos = self.pose.translation + ray_dir * dist;
|
||||||
|
|
||||||
|
Some(RayHit {
|
||||||
|
overlay,
|
||||||
|
hit_pos,
|
||||||
|
dist,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
pub mod common;
|
pub mod common;
|
||||||
|
pub mod input;
|
||||||
pub mod openvr;
|
pub mod openvr;
|
||||||
pub mod openxr;
|
pub mod openxr;
|
||||||
|
pub mod overlay;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::array;
|
use std::{array, io::Write, path::Path};
|
||||||
|
|
||||||
use glam::Affine3A;
|
use glam::Affine3A;
|
||||||
use ovr_overlay::{
|
use ovr_overlay::{
|
||||||
@@ -11,7 +11,7 @@ use ovr_overlay::{
|
|||||||
TrackedDeviceIndex,
|
TrackedDeviceIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::backend::common::{
|
use crate::backend::input::{
|
||||||
InputState, InteractionState, Pointer, PointerState, TrackedDevice, TrackedDeviceRole,
|
InputState, InteractionState, Pointer, PointerState, TrackedDevice, TrackedDeviceRole,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -96,7 +96,8 @@ impl InputState<OpenVrInputState, OpenVrHandState> {
|
|||||||
.collect::<Result<_, &'static str>>()?;
|
.collect::<Result<_, &'static str>>()?;
|
||||||
|
|
||||||
let hands: [Pointer<OpenVrHandState>; 2] = array::from_fn(|i| Pointer::<OpenVrHandState> {
|
let hands: [Pointer<OpenVrHandState>; 2] = array::from_fn(|i| Pointer::<OpenVrHandState> {
|
||||||
hand: i,
|
idx: i,
|
||||||
|
hand: i as u8,
|
||||||
now: PointerState::default(),
|
now: PointerState::default(),
|
||||||
before: PointerState::default(),
|
before: PointerState::default(),
|
||||||
pose: Affine3A::IDENTITY,
|
pose: Affine3A::IDENTITY,
|
||||||
@@ -286,3 +287,30 @@ fn copy_from_hmd(in_mat: &HmdMatrix34_t, out_mat: &mut Affine3A) {
|
|||||||
out_mat.w_axis[1] = in_mat.m[1][3];
|
out_mat.w_axis[1] = in_mat.m[1][3];
|
||||||
out_mat.w_axis[2] = in_mat.m[2][3];
|
out_mat.w_axis[2] = in_mat.m[2][3];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn action_manifest_path() -> &'static Path {
|
||||||
|
let action_path = "/tmp/wlxoverlay-s/actions.json";
|
||||||
|
std::fs::create_dir_all("/tmp/wlxoverlay-s").unwrap();
|
||||||
|
|
||||||
|
std::fs::File::create(action_path)
|
||||||
|
.unwrap()
|
||||||
|
.write_all(include_bytes!("../../res/actions.json"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
std::fs::File::create("/tmp/wlxoverlay-s/actions_binding_knuckles.json")
|
||||||
|
.unwrap()
|
||||||
|
.write_all(include_bytes!("../../res/actions_binding_knuckles.json"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
std::fs::File::create("/tmp/wlxoverlay-s/actions_binding_vive.json")
|
||||||
|
.unwrap()
|
||||||
|
.write_all(include_bytes!("../../res/actions_binding_vive.json"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
std::fs::File::create("/tmp/wlxoverlay-s/actions_binding_oculus.json")
|
||||||
|
.unwrap()
|
||||||
|
.write_all(include_bytes!("../../res/actions_binding_oculus.json"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Path::new(action_path)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
collections::VecDeque,
|
||||||
path::Path,
|
path::Path,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
@@ -8,45 +9,73 @@ use ovr_overlay::{
|
|||||||
sys::{ETrackedDeviceProperty, EVRApplicationType, EVREventType},
|
sys::{ETrackedDeviceProperty, EVRApplicationType, EVREventType},
|
||||||
TrackedDeviceIndex,
|
TrackedDeviceIndex,
|
||||||
};
|
};
|
||||||
|
use vulkano::{
|
||||||
|
device::{physical::PhysicalDevice, DeviceExtensions},
|
||||||
|
instance::InstanceExtensions,
|
||||||
|
Handle, VulkanObject,
|
||||||
|
};
|
||||||
|
|
||||||
use super::common::InputState;
|
use crate::state::AppState;
|
||||||
|
|
||||||
|
use self::{input::action_manifest_path, overlay::OpenVrOverlayData};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
common::{OverlayContainer, TaskType},
|
||||||
|
input::InputState,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod overlay;
|
pub mod overlay;
|
||||||
|
|
||||||
fn openvr_run() {
|
pub fn openvr_run() {
|
||||||
let app_type = EVRApplicationType::VRApplication_Overlay;
|
let app_type = EVRApplicationType::VRApplication_Overlay;
|
||||||
let Ok(context) = ovr_overlay::Context::init(app_type) else {
|
let Ok(context) = ovr_overlay::Context::init(app_type) else {
|
||||||
error!("Failed to initialize OpenVR");
|
error!("Failed to initialize OpenVR");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut overlay = context.overlay_mngr();
|
let mut overlay_mngr = context.overlay_mngr();
|
||||||
let mut settings = context.settings_mngr();
|
//let mut settings_mngr = context.settings_mngr();
|
||||||
let mut input = context.input_mngr();
|
let mut input_mngr = context.input_mngr();
|
||||||
let mut system = context.system_mngr();
|
let mut system_mngr = context.system_mngr();
|
||||||
let mut compositor = context.compositor_mngr();
|
let mut compositor_mngr = context.compositor_mngr();
|
||||||
|
|
||||||
let Ok(_) = input.set_action_manifest(Path::new("resources/actions.json")) else {
|
let device_extensions_fn = |device: &PhysicalDevice| {
|
||||||
error!("Failed to set action manifest");
|
let names = compositor_mngr.get_vulkan_device_extensions_required(device.handle().as_raw());
|
||||||
|
let ext = DeviceExtensions::from_iter(names.iter().map(|s| s.as_str()));
|
||||||
|
ext
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut compositor_mngr = context.compositor_mngr();
|
||||||
|
let instance_extensions = {
|
||||||
|
let names = compositor_mngr.get_vulkan_instance_extensions_required();
|
||||||
|
InstanceExtensions::from_iter(names.iter().map(|s| s.as_str()))
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut state = AppState::new(instance_extensions, device_extensions_fn);
|
||||||
|
let mut overlays = OverlayContainer::<OpenVrOverlayData>::new(&mut state);
|
||||||
|
|
||||||
|
if let Err(e) = input_mngr.set_action_manifest(action_manifest_path()) {
|
||||||
|
error!("Failed to set action manifest: {}", e.description());
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(mut input_state) = InputState::new(&mut input) else {
|
let Ok(mut input) = InputState::new(&mut input_mngr) else {
|
||||||
error!("Failed to initialize input");
|
error!("Failed to initialize input");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(refresh_rate) = system.get_tracked_device_property::<f32>(TrackedDeviceIndex::HMD, ETrackedDeviceProperty::Prop_DisplayFrequency_Float) else {
|
let Ok(refresh_rate) = system_mngr.get_tracked_device_property::<f32>(TrackedDeviceIndex::HMD, ETrackedDeviceProperty::Prop_DisplayFrequency_Float) else {
|
||||||
error!("Failed to get display refresh rate");
|
error!("Failed to get display refresh rate");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let frame_time = (1000.0 / refresh_rate).floor() * 0.001;
|
let frame_time = (1000.0 / refresh_rate).floor() * 0.001;
|
||||||
let mut next_device_update = Instant::now();
|
let mut next_device_update = Instant::now();
|
||||||
|
let mut due_tasks = VecDeque::with_capacity(4);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
while let Some(event) = system.poll_next_event() {
|
while let Some(event) = system_mngr.poll_next_event() {
|
||||||
match event.event_type {
|
match event.event_type {
|
||||||
EVREventType::VREvent_Quit => {
|
EVREventType::VREvent_Quit => {
|
||||||
info!("Received quit event, shutting down.");
|
info!("Received quit event, shutting down.");
|
||||||
@@ -61,35 +90,57 @@ fn openvr_run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if next_device_update <= Instant::now() {
|
if next_device_update <= Instant::now() {
|
||||||
input_state.update_devices(&mut system);
|
input.update_devices(&mut system_mngr);
|
||||||
next_device_update = Instant::now() + Duration::from_secs(30);
|
next_device_update = Instant::now() + Duration::from_secs(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
input_state.pre_update();
|
state.tasks.retrieve_due(&mut due_tasks);
|
||||||
input_state.update(&mut input, &mut system);
|
while let Some(task) = due_tasks.pop_front() {
|
||||||
input_state.post_update();
|
match task {
|
||||||
|
TaskType::Global(f) => f(&mut state),
|
||||||
|
TaskType::Overlay(sel, f) => {
|
||||||
|
if let Some(o) = overlays.mut_by_selector(&sel) {
|
||||||
|
f(&mut state, &mut o.state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// task scheduler
|
input.pre_update();
|
||||||
|
input.update(&mut input_mngr, &mut system_mngr);
|
||||||
|
input.post_update();
|
||||||
|
|
||||||
// after input
|
input
|
||||||
|
.pointers
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|p| p.interact(&mut overlays, &mut state));
|
||||||
|
|
||||||
// interactions
|
overlays
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|o| o.after_input(&mut overlay_mngr, &mut state));
|
||||||
|
|
||||||
// show overlays
|
log::debug!("Rendering frame");
|
||||||
|
|
||||||
|
overlays
|
||||||
|
.iter_mut()
|
||||||
|
.filter(|o| o.state.want_visible)
|
||||||
|
.for_each(|o| o.render(&mut state));
|
||||||
|
|
||||||
|
log::debug!("Rendering overlays");
|
||||||
|
|
||||||
|
overlays
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|o| o.after_render(&mut overlay_mngr, &state.graphics));
|
||||||
|
|
||||||
// chaperone
|
// chaperone
|
||||||
|
|
||||||
// render overlays
|
// close font handles?
|
||||||
|
|
||||||
// hide overlays
|
|
||||||
|
|
||||||
// close font handles
|
|
||||||
|
|
||||||
// playspace moved end frame
|
// playspace moved end frame
|
||||||
|
|
||||||
let mut seconds_since_vsync = 0f32;
|
let mut seconds_since_vsync = 0f32;
|
||||||
std::thread::sleep(Duration::from_secs_f32(
|
std::thread::sleep(Duration::from_secs_f32(
|
||||||
if system.get_time_since_last_vsync(&mut seconds_since_vsync, &mut 0u64) {
|
if system_mngr.get_time_since_last_vsync(&mut seconds_since_vsync, &mut 0u64) {
|
||||||
frame_time - seconds_since_vsync
|
frame_time - seconds_since_vsync
|
||||||
} else {
|
} else {
|
||||||
0.011
|
0.011
|
||||||
|
|||||||
@@ -1,15 +1,207 @@
|
|||||||
use ovr_overlay::sys::VRVulkanTextureData_t;
|
use glam::Vec4;
|
||||||
|
use ovr_overlay::{
|
||||||
|
overlay::{OverlayHandle, OverlayManager},
|
||||||
|
sys::VRVulkanTextureData_t,
|
||||||
|
};
|
||||||
|
use vulkano::{
|
||||||
|
command_buffer::{
|
||||||
|
synced::{
|
||||||
|
SyncCommandBuffer, SyncCommandBufferBuilder, SyncCommandBufferBuilderExecuteCommands,
|
||||||
|
},
|
||||||
|
AutoCommandBufferBuilder, CommandBufferExecFuture,
|
||||||
|
},
|
||||||
|
image::{ImageAccess, ImageLayout},
|
||||||
|
sync::{future::NowFuture, ImageMemoryBarrier},
|
||||||
|
Handle, VulkanObject,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::overlays::OverlayData;
|
use crate::{backend::overlay::OverlayData, graphics::WlxGraphics, state::AppState};
|
||||||
|
|
||||||
pub(super) struct OpenVrOverlayManager {
|
#[derive(Default)]
|
||||||
pub(super) overlays: Vec<OpenVrOverlay>,
|
pub(super) struct OpenVrOverlayData {
|
||||||
}
|
handle: Option<OverlayHandle>,
|
||||||
|
last_image: Option<u64>,
|
||||||
pub(super) struct OpenVrOverlay {
|
|
||||||
pub(super) visible: bool,
|
pub(super) visible: bool,
|
||||||
pub(super) color: [f32; 4],
|
pub(super) color: Vec4,
|
||||||
overlay: OverlayData,
|
pub(super) curvature: f32,
|
||||||
handle: u32,
|
pub(super) sort_order: u32,
|
||||||
ovr_texture: VRVulkanTextureData_t,
|
}
|
||||||
|
|
||||||
|
impl OverlayData<OpenVrOverlayData> {
|
||||||
|
pub fn initialize(
|
||||||
|
&mut self,
|
||||||
|
overlay: &mut OverlayManager,
|
||||||
|
app: &mut AppState,
|
||||||
|
) -> OverlayHandle {
|
||||||
|
let key = format!("wlx-{}", self.state.name);
|
||||||
|
let handle = match overlay.create_overlay(&key, &key) {
|
||||||
|
Ok(handle) => handle,
|
||||||
|
Err(e) => {
|
||||||
|
panic!("Failed to create overlay: {}", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
log::debug!("{}: initialize", self.state.name);
|
||||||
|
|
||||||
|
self.data.handle = Some(handle);
|
||||||
|
|
||||||
|
self.init(app);
|
||||||
|
|
||||||
|
self.upload_width(overlay);
|
||||||
|
self.upload_color(overlay);
|
||||||
|
self.upload_curvature(overlay);
|
||||||
|
|
||||||
|
handle
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn after_input(&mut self, overlay: &mut OverlayManager, app: &mut AppState) {
|
||||||
|
if self.state.want_visible && !self.data.visible {
|
||||||
|
self.show(overlay, app);
|
||||||
|
} else if !self.state.want_visible && self.data.visible {
|
||||||
|
self.hide(overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn after_render(&mut self, overlay: &mut OverlayManager, graphics: &WlxGraphics) {
|
||||||
|
if self.data.visible {
|
||||||
|
self.upload_texture(overlay, graphics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show(&mut self, overlay: &mut OverlayManager, app: &mut AppState) {
|
||||||
|
let handle = match self.data.handle {
|
||||||
|
Some(handle) => handle,
|
||||||
|
None => self.initialize(overlay, app),
|
||||||
|
};
|
||||||
|
log::debug!("{}: show", self.state.name);
|
||||||
|
if let Err(e) = overlay.set_visibility(handle, true) {
|
||||||
|
panic!("Failed to show overlay: {}", e);
|
||||||
|
}
|
||||||
|
self.data.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hide(&mut self, overlay: &mut OverlayManager) {
|
||||||
|
let Some(handle) = self.data.handle else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
log::debug!("{}: hide", self.state.name);
|
||||||
|
if let Err(e) = overlay.set_visibility(handle, false) {
|
||||||
|
panic!("Failed to hide overlay: {}", e);
|
||||||
|
}
|
||||||
|
self.data.visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_color(&self, overlay: &mut OverlayManager) {
|
||||||
|
let Some(handle) = self.data.handle else {
|
||||||
|
log::debug!("{}: No overlay handle", self.state.name);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if let Err(e) = overlay.set_opacity(handle, self.data.color.w) {
|
||||||
|
panic!("Failed to set overlay opacity: {}", e);
|
||||||
|
}
|
||||||
|
if let Err(e) = overlay.set_tint(
|
||||||
|
handle,
|
||||||
|
ovr_overlay::ColorTint {
|
||||||
|
r: self.data.color.x,
|
||||||
|
g: self.data.color.y,
|
||||||
|
b: self.data.color.z,
|
||||||
|
a: 1.0,
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
panic!("Failed to set overlay tint: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_width(&self, overlay: &mut OverlayManager) {
|
||||||
|
let Some(handle) = self.data.handle else {
|
||||||
|
log::debug!("{}: No overlay handle", self.state.name);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if let Err(e) = overlay.set_width(handle, self.state.width) {
|
||||||
|
panic!("Failed to set overlay width: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_curvature(&self, overlay: &mut OverlayManager) {
|
||||||
|
let Some(handle) = self.data.handle else {
|
||||||
|
log::debug!("{}: No overlay handle", self.state.name);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if let Err(e) = overlay.set_curvature(handle, self.data.curvature) {
|
||||||
|
panic!("Failed to set overlay curvature: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_sort_order(&self, overlay: &mut OverlayManager) {
|
||||||
|
let Some(handle) = self.data.handle else {
|
||||||
|
log::debug!("{}: No overlay handle", self.state.name);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if let Err(e) = overlay.set_sort_order(handle, self.data.sort_order) {
|
||||||
|
panic!("Failed to set overlay z order: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_texture(&mut self, overlay: &mut OverlayManager, graphics: &WlxGraphics) {
|
||||||
|
let Some(handle) = self.data.handle else {
|
||||||
|
log::debug!("{}: No overlay handle", self.state.name);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(view) = self.backend.view() else {
|
||||||
|
log::debug!("{}: Not rendered", self.state.name);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let image = view.image().inner().image.clone();
|
||||||
|
|
||||||
|
let raw_image = image.handle().as_raw();
|
||||||
|
|
||||||
|
if let Some(last_image) = self.data.last_image {
|
||||||
|
if last_image == raw_image {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(format) = image.format() else {
|
||||||
|
panic!("{}: Image format is None", self.state.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
let dimensions = image.dimensions();
|
||||||
|
|
||||||
|
let mut texture = VRVulkanTextureData_t {
|
||||||
|
m_nImage: raw_image,
|
||||||
|
m_nFormat: format as _,
|
||||||
|
m_nWidth: dimensions.width(),
|
||||||
|
m_nHeight: dimensions.height(),
|
||||||
|
m_nSampleCount: image.samples() as u32,
|
||||||
|
m_pDevice: graphics.device.handle().as_raw() as *mut _,
|
||||||
|
m_pPhysicalDevice: graphics.device.physical_device().handle().as_raw() as *mut _,
|
||||||
|
m_pInstance: graphics.instance.handle().as_raw() as *mut _,
|
||||||
|
m_pQueue: graphics.queue.handle().as_raw() as *mut _,
|
||||||
|
m_nQueueFamilyIndex: graphics.queue.queue_family_index(),
|
||||||
|
};
|
||||||
|
|
||||||
|
graphics
|
||||||
|
.transition_layout(
|
||||||
|
image.clone(),
|
||||||
|
ImageLayout::ColorAttachmentOptimal,
|
||||||
|
ImageLayout::TransferSrcOptimal,
|
||||||
|
)
|
||||||
|
.wait(None)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
log::info!("nImage: {}, nFormat: {:?}, nWidth: {}, nHeight: {}, nSampleCount: {}, nQueueFamilyIndex: {}", texture.m_nImage, format, texture.m_nWidth, texture.m_nHeight, texture.m_nSampleCount, texture.m_nQueueFamilyIndex);
|
||||||
|
if let Err(e) = overlay.set_image_vulkan(handle, &mut texture) {
|
||||||
|
panic!("Failed to set overlay texture: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
graphics
|
||||||
|
.transition_layout(
|
||||||
|
image,
|
||||||
|
ImageLayout::TransferSrcOptimal,
|
||||||
|
ImageLayout::ColorAttachmentOptimal,
|
||||||
|
)
|
||||||
|
.wait(None)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
170
src/backend/overlay.rs
Normal file
170
src/backend/overlay.rs
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
use std::sync::{
|
||||||
|
atomic::{AtomicUsize, Ordering},
|
||||||
|
Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use glam::{Affine3A, Quat, Vec3A};
|
||||||
|
use vulkano::image::ImageViewAbstract;
|
||||||
|
|
||||||
|
use crate::state::AppState;
|
||||||
|
|
||||||
|
use super::input::{DummyInteractionHandler, InteractionHandler, PointerHit};
|
||||||
|
|
||||||
|
static AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
pub trait OverlayBackend: OverlayRenderer + InteractionHandler {}
|
||||||
|
|
||||||
|
pub struct OverlayState {
|
||||||
|
pub id: usize,
|
||||||
|
pub name: Arc<str>,
|
||||||
|
pub width: f32,
|
||||||
|
pub size: (i32, i32),
|
||||||
|
pub want_visible: bool,
|
||||||
|
pub show_hide: bool,
|
||||||
|
pub grabbable: bool,
|
||||||
|
pub transform: Affine3A,
|
||||||
|
pub spawn_point: Vec3A,
|
||||||
|
pub spawn_rotation: Quat,
|
||||||
|
pub relative_to: RelativeTo,
|
||||||
|
pub primary_pointer: Option<usize>,
|
||||||
|
pub interaction_transform: Affine3A,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for OverlayState {
|
||||||
|
fn default() -> Self {
|
||||||
|
OverlayState {
|
||||||
|
id: AUTO_INCREMENT.fetch_add(1, Ordering::Relaxed),
|
||||||
|
name: Arc::from(""),
|
||||||
|
width: 1.,
|
||||||
|
size: (0, 0),
|
||||||
|
want_visible: false,
|
||||||
|
show_hide: false,
|
||||||
|
grabbable: false,
|
||||||
|
relative_to: RelativeTo::None,
|
||||||
|
spawn_point: Vec3A::NEG_Z,
|
||||||
|
spawn_rotation: Quat::IDENTITY,
|
||||||
|
transform: Affine3A::IDENTITY,
|
||||||
|
primary_pointer: None,
|
||||||
|
interaction_transform: Affine3A::IDENTITY,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OverlayData<T>
|
||||||
|
where
|
||||||
|
T: Default,
|
||||||
|
{
|
||||||
|
pub state: OverlayState,
|
||||||
|
pub backend: Box<dyn OverlayBackend>,
|
||||||
|
pub primary_pointer: Option<usize>,
|
||||||
|
pub data: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for OverlayData<T>
|
||||||
|
where
|
||||||
|
T: Default,
|
||||||
|
{
|
||||||
|
fn default() -> Self {
|
||||||
|
OverlayData {
|
||||||
|
state: Default::default(),
|
||||||
|
backend: Box::new(SplitOverlayBackend::default()),
|
||||||
|
primary_pointer: None,
|
||||||
|
data: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OverlayState {
|
||||||
|
pub fn reset(&mut self, _app: &mut AppState) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> OverlayData<T>
|
||||||
|
where
|
||||||
|
T: Default,
|
||||||
|
{
|
||||||
|
pub fn init(&mut self, app: &mut AppState) {
|
||||||
|
self.backend.init(app);
|
||||||
|
}
|
||||||
|
pub fn render(&mut self, app: &mut AppState) {
|
||||||
|
self.backend.render(app);
|
||||||
|
}
|
||||||
|
pub fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> {
|
||||||
|
self.backend.view()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait OverlayRenderer {
|
||||||
|
fn init(&mut self, app: &mut AppState);
|
||||||
|
fn pause(&mut self, app: &mut AppState);
|
||||||
|
fn resume(&mut self, app: &mut AppState);
|
||||||
|
fn render(&mut self, app: &mut AppState);
|
||||||
|
fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FallbackRenderer;
|
||||||
|
|
||||||
|
impl OverlayRenderer for FallbackRenderer {
|
||||||
|
fn init(&mut self, _app: &mut AppState) {}
|
||||||
|
fn pause(&mut self, _app: &mut AppState) {}
|
||||||
|
fn resume(&mut self, _app: &mut AppState) {}
|
||||||
|
fn render(&mut self, _app: &mut AppState) {}
|
||||||
|
fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Boilerplate and dummies
|
||||||
|
|
||||||
|
pub enum RelativeTo {
|
||||||
|
None,
|
||||||
|
Head,
|
||||||
|
Hand(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SplitOverlayBackend {
|
||||||
|
pub renderer: Box<dyn OverlayRenderer>,
|
||||||
|
pub interaction: Box<dyn InteractionHandler>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SplitOverlayBackend {
|
||||||
|
fn default() -> SplitOverlayBackend {
|
||||||
|
SplitOverlayBackend {
|
||||||
|
renderer: Box::new(FallbackRenderer),
|
||||||
|
interaction: Box::new(DummyInteractionHandler),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OverlayBackend for SplitOverlayBackend {}
|
||||||
|
impl OverlayRenderer for SplitOverlayBackend {
|
||||||
|
fn init(&mut self, app: &mut AppState) {
|
||||||
|
self.renderer.init(app);
|
||||||
|
}
|
||||||
|
fn pause(&mut self, app: &mut AppState) {
|
||||||
|
self.renderer.pause(app);
|
||||||
|
}
|
||||||
|
fn resume(&mut self, app: &mut AppState) {
|
||||||
|
self.renderer.resume(app);
|
||||||
|
}
|
||||||
|
fn render(&mut self, app: &mut AppState) {
|
||||||
|
self.renderer.render(app);
|
||||||
|
}
|
||||||
|
fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> {
|
||||||
|
self.renderer.view()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl InteractionHandler for SplitOverlayBackend {
|
||||||
|
fn on_left(&mut self, app: &mut AppState, pointer: usize) {
|
||||||
|
self.interaction.on_left(app, pointer);
|
||||||
|
}
|
||||||
|
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) {
|
||||||
|
self.interaction.on_hover(app, hit);
|
||||||
|
}
|
||||||
|
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32) {
|
||||||
|
self.interaction.on_scroll(app, hit, delta);
|
||||||
|
}
|
||||||
|
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
||||||
|
self.interaction.on_pointer(app, hit, pressed);
|
||||||
|
}
|
||||||
|
}
|
||||||
519
src/graphics.rs
519
src/graphics.rs
@@ -1,10 +1,67 @@
|
|||||||
use std::{sync::Arc, slice::Iter, io::Cursor, error::Error};
|
use std::{error::Error, io::Cursor, slice::Iter, sync::Arc};
|
||||||
|
|
||||||
use log::{info,error};
|
use ash::vk::SubmitInfo;
|
||||||
use vulkano::{format::Format, device::{physical::PhysicalDeviceType, QueueFlags, DeviceExtensions, Device, DeviceCreateInfo, Features, QueueCreateInfo, Queue}, Version, VulkanLibrary, instance::{Instance, InstanceCreateInfo}, memory::allocator::{StandardMemoryAllocator, AllocationCreateInfo, MemoryUsage}, command_buffer::{allocator::StandardCommandBufferAllocator, CommandBufferUsage, AutoCommandBufferBuilder, PrimaryAutoCommandBuffer, RenderingAttachmentInfo, RenderingInfo, PrimaryCommandBufferAbstract, CommandBufferExecFuture, SubpassContents, SecondaryAutoCommandBuffer, CommandBufferInheritanceInfo, CommandBufferInheritanceRenderPassType, CommandBufferInheritanceRenderingInfo}, descriptor_set::{allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet}, buffer::{Buffer, BufferCreateInfo, BufferUsage, BufferContents, Subbuffer, allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}}, sampler::{Filter, SamplerCreateInfo, SamplerAddressMode, Sampler}, pipeline::{GraphicsPipeline, Pipeline, graphics::{render_pass::PipelineRenderingCreateInfo, vertex_input::Vertex, input_assembly::InputAssemblyState, viewport::{ViewportState, Viewport}, color_blend::{ColorBlendState, AttachmentBlend}}, PipelineBindPoint}, image::{ImageViewAbstract, ImageUsage, SwapchainImage, ImageDimensions, ImmutableImage, MipmapsCount, StorageImage, ImageError, SubresourceData, ImageCreateFlags, AttachmentImage}, swapchain::{Surface, Swapchain, SwapchainCreateInfo, CompositeAlpha}, shader::ShaderModule, render_pass::{StoreOp, LoadOp}, sync::future::NowFuture};
|
use log::{debug, error, info};
|
||||||
use winit::{event_loop::EventLoop, window::{WindowBuilder, Window}};
|
use smallvec::smallvec;
|
||||||
|
use vulkano::{
|
||||||
|
buffer::{
|
||||||
|
allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo},
|
||||||
|
Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer,
|
||||||
|
},
|
||||||
|
command_buffer::{
|
||||||
|
allocator::{
|
||||||
|
CommandBufferAllocator, CommandBufferBuilderAlloc, StandardCommandBufferAllocator,
|
||||||
|
},
|
||||||
|
sys::{CommandBufferBeginInfo, UnsafeCommandBufferBuilder},
|
||||||
|
AutoCommandBufferBuilder, CommandBufferExecFuture, CommandBufferInheritanceInfo,
|
||||||
|
CommandBufferInheritanceRenderPassType, CommandBufferInheritanceRenderingInfo,
|
||||||
|
CommandBufferLevel, CommandBufferUsage, PrimaryAutoCommandBuffer,
|
||||||
|
PrimaryCommandBufferAbstract, RenderingAttachmentInfo, RenderingInfo,
|
||||||
|
SecondaryAutoCommandBuffer, SubpassContents,
|
||||||
|
},
|
||||||
|
descriptor_set::{
|
||||||
|
allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet,
|
||||||
|
},
|
||||||
|
device::{
|
||||||
|
physical::{PhysicalDevice, PhysicalDeviceType},
|
||||||
|
Device, DeviceCreateInfo, DeviceExtensions, Features, Queue, QueueCreateInfo, QueueFlags,
|
||||||
|
},
|
||||||
|
format::Format,
|
||||||
|
image::{
|
||||||
|
sys::Image, AttachmentImage, ImageAccess, ImageCreateFlags, ImageDimensions, ImageError,
|
||||||
|
ImageLayout, ImageUsage, ImageViewAbstract, ImmutableImage, MipmapsCount, StorageImage,
|
||||||
|
SubresourceData, SwapchainImage,
|
||||||
|
},
|
||||||
|
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
|
||||||
|
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||||
|
pipeline::{
|
||||||
|
graphics::{
|
||||||
|
color_blend::{AttachmentBlend, ColorBlendState},
|
||||||
|
input_assembly::InputAssemblyState,
|
||||||
|
render_pass::PipelineRenderingCreateInfo,
|
||||||
|
vertex_input::Vertex,
|
||||||
|
viewport::{Viewport, ViewportState},
|
||||||
|
},
|
||||||
|
GraphicsPipeline, Pipeline, PipelineBindPoint,
|
||||||
|
},
|
||||||
|
render_pass::{LoadOp, StoreOp},
|
||||||
|
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
|
||||||
|
shader::ShaderModule,
|
||||||
|
swapchain::{CompositeAlpha, Surface, Swapchain, SwapchainCreateInfo},
|
||||||
|
sync::{
|
||||||
|
fence::Fence, future::NowFuture, AccessFlags, DependencyInfo, ImageMemoryBarrier,
|
||||||
|
PipelineStages,
|
||||||
|
},
|
||||||
|
Version, VulkanLibrary, VulkanObject,
|
||||||
|
};
|
||||||
use vulkano_win::VkSurfaceBuild;
|
use vulkano_win::VkSurfaceBuild;
|
||||||
use wlx_capture::frame::{DmabufFrame, DRM_FORMAT_ABGR8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888};
|
use winit::{
|
||||||
|
event_loop::EventLoop,
|
||||||
|
window::{Window, WindowBuilder},
|
||||||
|
};
|
||||||
|
use wlx_capture::frame::{
|
||||||
|
DmabufFrame, DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888,
|
||||||
|
};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(BufferContents, Vertex, Copy, Clone, Debug)]
|
#[derive(BufferContents, Vertex, Copy, Clone, Debug)]
|
||||||
@@ -15,10 +72,10 @@ pub struct Vert2Uv {
|
|||||||
pub in_uv: [f32; 2],
|
pub in_uv: [f32; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const INDICES : [u16; 6] = [2, 1, 0, 1, 2, 3];
|
pub const INDICES: [u16; 6] = [2, 1, 0, 1, 2, 3];
|
||||||
|
|
||||||
pub struct WlxGraphics {
|
pub struct WlxGraphics {
|
||||||
pub instance: Arc<Instance>,
|
pub instance: Arc<Instance>,
|
||||||
pub device: Arc<Device>,
|
pub device: Arc<Device>,
|
||||||
pub queue: Arc<Queue>,
|
pub queue: Arc<Queue>,
|
||||||
|
|
||||||
@@ -28,18 +85,26 @@ pub struct WlxGraphics {
|
|||||||
pub command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
|
pub command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
|
||||||
pub descriptor_set_allocator: Arc<StandardDescriptorSetAllocator>,
|
pub descriptor_set_allocator: Arc<StandardDescriptorSetAllocator>,
|
||||||
|
|
||||||
|
pub quad_verts: Subbuffer<[Vert2Uv]>,
|
||||||
pub quad_indices: Subbuffer<[u16]>,
|
pub quad_indices: Subbuffer<[u16]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlxGraphics {
|
impl WlxGraphics {
|
||||||
pub fn new() -> (Arc<Self>, EventLoop<()>) {
|
pub fn new(
|
||||||
|
vk_instance_extensions: InstanceExtensions,
|
||||||
|
mut vk_device_extensions_fn: impl FnMut(&PhysicalDevice) -> DeviceExtensions,
|
||||||
|
) -> (Arc<Self>, EventLoop<()>) {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
let layers = vec!["VK_LAYER_KHRONOS_validation".to_owned()];
|
let layers = vec!["VK_LAYER_KHRONOS_validation".to_owned()];
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
let layers = vec![];
|
let layers = vec![];
|
||||||
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
let required_extensions = vulkano_win::required_extensions(&library);
|
let library_extensions = vulkano_win::required_extensions(&library);
|
||||||
|
let required_extensions = library_extensions.union(&vk_instance_extensions);
|
||||||
|
|
||||||
|
debug!("Instance exts for app: {:?}", &required_extensions);
|
||||||
|
debug!("Instance exts for runtime: {:?}", &vk_instance_extensions);
|
||||||
|
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
library,
|
library,
|
||||||
@@ -61,13 +126,14 @@ impl WlxGraphics {
|
|||||||
..DeviceExtensions::empty()
|
..DeviceExtensions::empty()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("Device exts for app: {:?}", &device_extensions);
|
||||||
|
|
||||||
// TODO headless
|
// TODO headless
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
let surface = WindowBuilder::new()
|
let surface = WindowBuilder::new()
|
||||||
.build_vk_surface(&event_loop, instance.clone())
|
.build_vk_surface(&event_loop, instance.clone())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
||||||
let (physical_device, queue_family_index) = instance
|
let (physical_device, queue_family_index) = instance
|
||||||
.enumerate_physical_devices()
|
.enumerate_physical_devices()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -75,7 +141,14 @@ impl WlxGraphics {
|
|||||||
p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering
|
p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering
|
||||||
})
|
})
|
||||||
.filter(|p| {
|
.filter(|p| {
|
||||||
p.supported_extensions().contains(&device_extensions)
|
let runtime_extensions = vk_device_extensions_fn(p);
|
||||||
|
debug!(
|
||||||
|
"Device exts for {}: {:?}",
|
||||||
|
p.properties().device_name,
|
||||||
|
&runtime_extensions
|
||||||
|
);
|
||||||
|
let my_extensions = runtime_extensions.union(&device_extensions);
|
||||||
|
p.supported_extensions().contains(&my_extensions)
|
||||||
})
|
})
|
||||||
.filter_map(|p| {
|
.filter_map(|p| {
|
||||||
p.queue_family_properties()
|
p.queue_family_properties()
|
||||||
@@ -87,20 +160,18 @@ impl WlxGraphics {
|
|||||||
})
|
})
|
||||||
.map(|i| (p, i as u32))
|
.map(|i| (p, i as u32))
|
||||||
})
|
})
|
||||||
.min_by_key(|(p, _)| {
|
.min_by_key(|(p, _)| match p.properties().device_type {
|
||||||
match p.properties().device_type {
|
PhysicalDeviceType::DiscreteGpu => 0,
|
||||||
PhysicalDeviceType::DiscreteGpu => 0,
|
PhysicalDeviceType::IntegratedGpu => 1,
|
||||||
PhysicalDeviceType::IntegratedGpu => 1,
|
PhysicalDeviceType::VirtualGpu => 2,
|
||||||
PhysicalDeviceType::VirtualGpu => 2,
|
PhysicalDeviceType::Cpu => 3,
|
||||||
PhysicalDeviceType::Cpu => 3,
|
PhysicalDeviceType::Other => 4,
|
||||||
PhysicalDeviceType::Other => 4,
|
_ => 5,
|
||||||
_ => 5,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.expect("no suitable physical device found");
|
.expect("no suitable physical device found");
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Nice {} you have there.",
|
"Using vkPhysicalDevice: {}",
|
||||||
physical_device.properties().device_name,
|
physical_device.properties().device_name,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -128,8 +199,44 @@ impl WlxGraphics {
|
|||||||
let queue = queues.next().unwrap();
|
let queue = queues.next().unwrap();
|
||||||
|
|
||||||
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
|
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
|
||||||
let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(device.clone(), Default::default()));
|
let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(
|
||||||
let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(device.clone()));
|
device.clone(),
|
||||||
|
Default::default(),
|
||||||
|
));
|
||||||
|
let descriptor_set_allocator =
|
||||||
|
Arc::new(StandardDescriptorSetAllocator::new(device.clone()));
|
||||||
|
|
||||||
|
let vertices = [
|
||||||
|
Vert2Uv {
|
||||||
|
in_pos: [0., 0.],
|
||||||
|
in_uv: [0., 0.],
|
||||||
|
},
|
||||||
|
Vert2Uv {
|
||||||
|
in_pos: [0., 1.],
|
||||||
|
in_uv: [0., 1.],
|
||||||
|
},
|
||||||
|
Vert2Uv {
|
||||||
|
in_pos: [1., 0.],
|
||||||
|
in_uv: [1., 0.],
|
||||||
|
},
|
||||||
|
Vert2Uv {
|
||||||
|
in_pos: [1., 1.],
|
||||||
|
in_uv: [1., 1.],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let quad_verts = Buffer::from_iter(
|
||||||
|
&memory_allocator,
|
||||||
|
BufferCreateInfo {
|
||||||
|
usage: BufferUsage::VERTEX_BUFFER,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
AllocationCreateInfo {
|
||||||
|
usage: MemoryUsage::Upload,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
vertices.into_iter(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let quad_indices = Buffer::from_iter(
|
let quad_indices = Buffer::from_iter(
|
||||||
&memory_allocator,
|
&memory_allocator,
|
||||||
@@ -142,7 +249,8 @@ impl WlxGraphics {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
INDICES.iter().cloned(),
|
INDICES.iter().cloned(),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let me = Self {
|
let me = Self {
|
||||||
instance,
|
instance,
|
||||||
@@ -153,21 +261,30 @@ impl WlxGraphics {
|
|||||||
command_buffer_allocator,
|
command_buffer_allocator,
|
||||||
descriptor_set_allocator,
|
descriptor_set_allocator,
|
||||||
quad_indices,
|
quad_indices,
|
||||||
|
quad_verts,
|
||||||
};
|
};
|
||||||
|
|
||||||
(Arc::new(me), event_loop)
|
(Arc::new(me), event_loop)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_swapchain(&self, format: Option<Format>) -> (Arc<Swapchain>, Vec<Arc<SwapchainImage>>) {
|
pub fn create_swapchain(
|
||||||
|
&self,
|
||||||
|
format: Option<Format>,
|
||||||
|
) -> (Arc<Swapchain>, Vec<Arc<SwapchainImage>>) {
|
||||||
let (min_image_count, composite_alpha, image_format) = if let Some(format) = format {
|
let (min_image_count, composite_alpha, image_format) = if let Some(format) = format {
|
||||||
(1, CompositeAlpha::Opaque, format)
|
(1, CompositeAlpha::Opaque, format)
|
||||||
} else {
|
} else {
|
||||||
let surface_capabilities = self.device
|
let surface_capabilities = self
|
||||||
|
.device
|
||||||
.physical_device()
|
.physical_device()
|
||||||
.surface_capabilities(&self.surface, Default::default())
|
.surface_capabilities(&self.surface, Default::default())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let composite_alpha = surface_capabilities.supported_composite_alpha.into_iter().next().unwrap();
|
let composite_alpha = surface_capabilities
|
||||||
|
.supported_composite_alpha
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let image_format = Some(
|
let image_format = Some(
|
||||||
self.device
|
self.device
|
||||||
@@ -176,9 +293,18 @@ impl WlxGraphics {
|
|||||||
.unwrap()[0]
|
.unwrap()[0]
|
||||||
.0,
|
.0,
|
||||||
);
|
);
|
||||||
(surface_capabilities.min_image_count, composite_alpha, image_format.unwrap())
|
(
|
||||||
|
surface_capabilities.min_image_count,
|
||||||
|
composite_alpha,
|
||||||
|
image_format.unwrap(),
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let window = self.surface.object().unwrap().downcast_ref::<Window>().unwrap();
|
let window = self
|
||||||
|
.surface
|
||||||
|
.object()
|
||||||
|
.unwrap()
|
||||||
|
.downcast_ref::<Window>()
|
||||||
|
.unwrap();
|
||||||
let swapchain = Swapchain::new(
|
let swapchain = Swapchain::new(
|
||||||
self.device.clone(),
|
self.device.clone(),
|
||||||
self.surface.clone(),
|
self.surface.clone(),
|
||||||
@@ -196,7 +322,15 @@ impl WlxGraphics {
|
|||||||
swapchain
|
swapchain
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upload_verts(&self, width: f32, height: f32, x: f32, y: f32, w: f32, h: f32) -> Subbuffer<[Vert2Uv]> {
|
pub fn upload_verts(
|
||||||
|
&self,
|
||||||
|
width: f32,
|
||||||
|
height: f32,
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
w: f32,
|
||||||
|
h: f32,
|
||||||
|
) -> Subbuffer<[Vert2Uv]> {
|
||||||
let rw = width;
|
let rw = width;
|
||||||
let rh = height;
|
let rh = height;
|
||||||
|
|
||||||
@@ -207,16 +341,30 @@ impl WlxGraphics {
|
|||||||
let y1 = h / rh + y0;
|
let y1 = h / rh + y0;
|
||||||
|
|
||||||
let vertices = [
|
let vertices = [
|
||||||
Vert2Uv { in_pos: [x0, y0], in_uv: [0.0, 0.0] },
|
Vert2Uv {
|
||||||
Vert2Uv { in_pos: [x0, y1], in_uv: [0.0, 1.0] },
|
in_pos: [x0, y0],
|
||||||
Vert2Uv { in_pos: [x1, y0], in_uv: [1.0, 0.0] },
|
in_uv: [0.0, 0.0],
|
||||||
Vert2Uv { in_pos: [x1, y1], in_uv: [1.0, 1.0] },
|
},
|
||||||
|
Vert2Uv {
|
||||||
|
in_pos: [x0, y1],
|
||||||
|
in_uv: [0.0, 1.0],
|
||||||
|
},
|
||||||
|
Vert2Uv {
|
||||||
|
in_pos: [x1, y0],
|
||||||
|
in_uv: [1.0, 0.0],
|
||||||
|
},
|
||||||
|
Vert2Uv {
|
||||||
|
in_pos: [x1, y1],
|
||||||
|
in_uv: [1.0, 1.0],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
self.upload_buffer(BufferUsage::VERTEX_BUFFER, vertices.iter())
|
self.upload_buffer(BufferUsage::VERTEX_BUFFER, vertices.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upload_buffer<T>(&self, usage: BufferUsage, contents: Iter<'_, T>) -> Subbuffer<[T]>
|
pub fn upload_buffer<T>(&self, usage: BufferUsage, contents: Iter<'_, T>) -> Subbuffer<[T]>
|
||||||
where T: BufferContents + Clone {
|
where
|
||||||
|
T: BufferContents + Clone,
|
||||||
|
{
|
||||||
Buffer::from_iter(
|
Buffer::from_iter(
|
||||||
&self.memory_allocator,
|
&self.memory_allocator,
|
||||||
BufferCreateInfo {
|
BufferCreateInfo {
|
||||||
@@ -228,8 +376,9 @@ impl WlxGraphics {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
contents.cloned(),
|
contents.cloned(),
|
||||||
).unwrap()
|
)
|
||||||
}
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn dmabuf_texture(&self, frame: DmabufFrame) -> Result<Arc<StorageImage>, ImageError> {
|
pub fn dmabuf_texture(&self, frame: DmabufFrame) -> Result<Arc<StorageImage>, ImageError> {
|
||||||
let dimensions = ImageDimensions::Dim2d {
|
let dimensions = ImageDimensions::Dim2d {
|
||||||
@@ -246,7 +395,8 @@ impl WlxGraphics {
|
|||||||
_ => panic!("Unsupported dmabuf format {:x}", frame.format.fourcc),
|
_ => panic!("Unsupported dmabuf format {:x}", frame.format.fourcc),
|
||||||
};
|
};
|
||||||
|
|
||||||
let planes = frame.planes
|
let planes = frame
|
||||||
|
.planes
|
||||||
.iter()
|
.iter()
|
||||||
.take(frame.num_planes)
|
.take(frame.num_planes)
|
||||||
.filter_map(|plane| {
|
.filter_map(|plane| {
|
||||||
@@ -258,7 +408,8 @@ impl WlxGraphics {
|
|||||||
offset: plane.offset as _,
|
offset: plane.offset as _,
|
||||||
row_pitch: plane.stride as _,
|
row_pitch: plane.stride as _,
|
||||||
})
|
})
|
||||||
}).collect();
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
StorageImage::new_from_dma_buf_fd(
|
StorageImage::new_from_dma_buf_fd(
|
||||||
&self.memory_allocator,
|
&self.memory_allocator,
|
||||||
@@ -272,28 +423,112 @@ impl WlxGraphics {
|
|||||||
frame.format.modifier,
|
frame.format.modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_texture(&self, width: u32, height: u32, format: Format) -> Arc<AttachmentImage> {
|
pub fn render_texture(&self, width: u32, height: u32, format: Format) -> Arc<AttachmentImage> {
|
||||||
let tex = AttachmentImage::with_usage(
|
let tex = AttachmentImage::with_usage(
|
||||||
&self.memory_allocator,
|
&self.memory_allocator,
|
||||||
[width, height],
|
[width, height],
|
||||||
format,
|
format,
|
||||||
ImageUsage::SAMPLED | ImageUsage::TRANSFER_SRC | ImageUsage::COLOR_ATTACHMENT,
|
ImageUsage::SAMPLED | ImageUsage::TRANSFER_SRC | ImageUsage::COLOR_ATTACHMENT,
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
tex
|
tex
|
||||||
}
|
}
|
||||||
pub fn create_pipeline(self: &Arc<Self>, vert: Arc<ShaderModule>, frag: Arc<ShaderModule>, format: Format) -> Arc<WlxPipeline> {
|
|
||||||
|
pub fn create_pipeline(
|
||||||
|
self: &Arc<Self>,
|
||||||
|
vert: Arc<ShaderModule>,
|
||||||
|
frag: Arc<ShaderModule>,
|
||||||
|
format: Format,
|
||||||
|
) -> Arc<WlxPipeline> {
|
||||||
Arc::new(WlxPipeline::new(self.clone(), vert, frag, format))
|
Arc::new(WlxPipeline::new(self.clone(), vert, frag, format))
|
||||||
}
|
}
|
||||||
pub fn create_command_buffer(self: &Arc<Self>, usage: CommandBufferUsage) -> WlxCommandBuffer<PrimaryAutoCommandBuffer> {
|
|
||||||
|
pub fn create_command_buffer(
|
||||||
|
self: &Arc<Self>,
|
||||||
|
usage: CommandBufferUsage,
|
||||||
|
) -> WlxCommandBuffer<PrimaryAutoCommandBuffer> {
|
||||||
let command_buffer = AutoCommandBufferBuilder::primary(
|
let command_buffer = AutoCommandBufferBuilder::primary(
|
||||||
&self.command_buffer_allocator,
|
&self.command_buffer_allocator,
|
||||||
self.queue.queue_family_index(),
|
self.queue.queue_family_index(),
|
||||||
usage,
|
usage,
|
||||||
).unwrap();
|
)
|
||||||
WlxCommandBuffer { graphics: self.clone(), command_buffer }
|
.unwrap();
|
||||||
|
WlxCommandBuffer {
|
||||||
|
graphics: self.clone(),
|
||||||
|
command_buffer,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn transition_layout(
|
||||||
|
&self,
|
||||||
|
image: Arc<Image>,
|
||||||
|
old_layout: ImageLayout,
|
||||||
|
new_layout: ImageLayout,
|
||||||
|
) -> Fence {
|
||||||
|
let barrier = ImageMemoryBarrier {
|
||||||
|
src_stages: PipelineStages::ALL_TRANSFER,
|
||||||
|
src_access: AccessFlags::TRANSFER_WRITE,
|
||||||
|
dst_stages: PipelineStages::ALL_TRANSFER,
|
||||||
|
dst_access: AccessFlags::TRANSFER_READ,
|
||||||
|
old_layout,
|
||||||
|
new_layout,
|
||||||
|
subresource_range: image.subresource_range(),
|
||||||
|
..ImageMemoryBarrier::image(image)
|
||||||
|
};
|
||||||
|
|
||||||
|
let builder_alloc = self
|
||||||
|
.command_buffer_allocator
|
||||||
|
.allocate(
|
||||||
|
self.queue.queue_family_index(),
|
||||||
|
CommandBufferLevel::Primary,
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.next()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let command_buffer = unsafe {
|
||||||
|
let mut builder = UnsafeCommandBufferBuilder::new(
|
||||||
|
&builder_alloc.inner(),
|
||||||
|
CommandBufferBeginInfo {
|
||||||
|
usage: CommandBufferUsage::OneTimeSubmit,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
builder.pipeline_barrier(&DependencyInfo {
|
||||||
|
image_memory_barriers: smallvec![barrier],
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
builder.build().unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let fence = vulkano::sync::fence::Fence::new(
|
||||||
|
self.device.clone(),
|
||||||
|
vulkano::sync::fence::FenceCreateInfo::default(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let fns = self.device.fns();
|
||||||
|
unsafe {
|
||||||
|
(fns.v1_0.queue_submit)(
|
||||||
|
self.queue.handle(),
|
||||||
|
1,
|
||||||
|
[SubmitInfo::builder()
|
||||||
|
.command_buffers(&[command_buffer.handle()])
|
||||||
|
.build()]
|
||||||
|
.as_ptr(),
|
||||||
|
fence.handle(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.result()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
fence
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WlxCommandBuffer<T> {
|
pub struct WlxCommandBuffer<T> {
|
||||||
@@ -306,7 +541,9 @@ impl<T> WlxCommandBuffer<T> {
|
|||||||
&self.command_buffer
|
&self.command_buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner_mut(&mut self) -> &mut AutoCommandBufferBuilder<T, Arc<StandardCommandBufferAllocator>> {
|
pub fn inner_mut(
|
||||||
|
&mut self,
|
||||||
|
) -> &mut AutoCommandBufferBuilder<T, Arc<StandardCommandBufferAllocator>> {
|
||||||
&mut self.command_buffer
|
&mut self.command_buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,37 +551,55 @@ impl<T> WlxCommandBuffer<T> {
|
|||||||
self.command_buffer
|
self.command_buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn begin(mut self, render_target: Arc<dyn ImageViewAbstract>) -> Self
|
pub fn begin(
|
||||||
{
|
mut self,
|
||||||
|
render_target: Arc<dyn ImageViewAbstract>,
|
||||||
|
want_layout: Option<ImageLayout>,
|
||||||
|
) -> Self {
|
||||||
|
if let Some(want_layout) = want_layout {
|
||||||
|
let mut barrier =
|
||||||
|
ImageMemoryBarrier::image(render_target.image().inner().image.clone());
|
||||||
|
barrier.old_layout = ImageLayout::ColorAttachmentOptimal;
|
||||||
|
barrier.new_layout = want_layout;
|
||||||
|
}
|
||||||
|
|
||||||
self.command_buffer
|
self.command_buffer
|
||||||
.begin_rendering(RenderingInfo {
|
.begin_rendering(RenderingInfo {
|
||||||
contents: SubpassContents::SecondaryCommandBuffers,
|
contents: SubpassContents::SecondaryCommandBuffers,
|
||||||
color_attachments: vec![Some(RenderingAttachmentInfo {
|
color_attachments: vec![Some(RenderingAttachmentInfo {
|
||||||
load_op: LoadOp::Clear,
|
load_op: LoadOp::Clear,
|
||||||
store_op: StoreOp::Store,
|
store_op: StoreOp::Store,
|
||||||
clear_value: Some([0.0, 0.0, 0.0, 0.0].into()),
|
clear_value: Some([0.0, 0.0, 0.0, 0.0].into()),
|
||||||
..RenderingAttachmentInfo::image_view(
|
..RenderingAttachmentInfo::image_view(render_target.clone())
|
||||||
render_target.clone(),
|
})],
|
||||||
)
|
..Default::default()
|
||||||
})],
|
})
|
||||||
..Default::default()
|
.unwrap();
|
||||||
}).unwrap();
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_ref(&mut self, pass: &WlxPass) -> &mut Self
|
pub fn run_ref(&mut self, pass: &WlxPass) -> &mut Self {
|
||||||
{
|
let _ = self
|
||||||
let _ = self.command_buffer.execute_commands(pass.command_buffer.clone()).unwrap();
|
.command_buffer
|
||||||
|
.execute_commands(pass.command_buffer.clone())
|
||||||
|
.unwrap();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(mut self, pass: &WlxPass) -> Self
|
pub fn run(mut self, pass: &WlxPass) -> Self {
|
||||||
{
|
let _ = self
|
||||||
let _ = self.command_buffer.execute_commands(pass.command_buffer.clone());
|
.command_buffer
|
||||||
|
.execute_commands(pass.command_buffer.clone());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn texture2d(&mut self, width: u32, height: u32, format: Format, data: Vec<u8>) -> Arc<ImmutableImage> {
|
pub fn texture2d(
|
||||||
|
&mut self,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
format: Format,
|
||||||
|
data: Vec<u8>,
|
||||||
|
) -> Arc<ImmutableImage> {
|
||||||
let dimensions = ImageDimensions::Dim2d {
|
let dimensions = ImageDimensions::Dim2d {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
@@ -374,7 +629,6 @@ impl<T> WlxCommandBuffer<T> {
|
|||||||
reader.next_frame(&mut image_data).unwrap();
|
reader.next_frame(&mut image_data).unwrap();
|
||||||
self.texture2d(width, height, Format::R8G8B8A8_UNORM, image_data)
|
self.texture2d(width, height, Format::R8G8B8A8_UNORM, image_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlxCommandBuffer<PrimaryAutoCommandBuffer> {
|
impl WlxCommandBuffer<PrimaryAutoCommandBuffer> {
|
||||||
@@ -414,26 +668,33 @@ pub struct WlxPipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WlxPipeline {
|
impl WlxPipeline {
|
||||||
fn new(graphics: Arc<WlxGraphics>, vert: Arc<ShaderModule>, frag: Arc<ShaderModule>, format: Format) -> Self {
|
fn new(
|
||||||
|
graphics: Arc<WlxGraphics>,
|
||||||
|
vert: Arc<ShaderModule>,
|
||||||
|
frag: Arc<ShaderModule>,
|
||||||
|
format: Format,
|
||||||
|
) -> Self {
|
||||||
let vep = vert.entry_point("main").unwrap();
|
let vep = vert.entry_point("main").unwrap();
|
||||||
let fep = frag.entry_point("main").unwrap();
|
let fep = frag.entry_point("main").unwrap();
|
||||||
let pipeline = GraphicsPipeline::start()
|
let pipeline = GraphicsPipeline::start()
|
||||||
.render_pass(PipelineRenderingCreateInfo {
|
.render_pass(PipelineRenderingCreateInfo {
|
||||||
color_attachment_formats: vec![Some(format)],
|
color_attachment_formats: vec![Some(format)],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.color_blend_state(ColorBlendState::default().blend(
|
.color_blend_state(ColorBlendState::default().blend(AttachmentBlend::alpha()))
|
||||||
AttachmentBlend::alpha()
|
.vertex_input_state(Vert2Uv::per_vertex())
|
||||||
))
|
.input_assembly_state(InputAssemblyState::new())
|
||||||
.vertex_input_state(Vert2Uv::per_vertex())
|
.vertex_shader(vep, ())
|
||||||
.input_assembly_state(InputAssemblyState::new())
|
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||||
.vertex_shader(vep, ())
|
.fragment_shader(fep, ())
|
||||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
.build(graphics.device.clone())
|
||||||
.fragment_shader(fep, ())
|
.unwrap();
|
||||||
.build(graphics.device.clone())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Self { graphics, pipeline, format}
|
Self {
|
||||||
|
graphics,
|
||||||
|
pipeline,
|
||||||
|
format,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner(&self) -> Arc<GraphicsPipeline> {
|
pub fn inner(&self) -> Arc<GraphicsPipeline> {
|
||||||
@@ -444,7 +705,12 @@ impl WlxPipeline {
|
|||||||
self.graphics.clone()
|
self.graphics.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uniform_sampler(&self, set: usize, texture: Arc<dyn ImageViewAbstract>, filter: Filter) -> Arc<PersistentDescriptorSet> {
|
pub fn uniform_sampler(
|
||||||
|
&self,
|
||||||
|
set: usize,
|
||||||
|
texture: Arc<dyn ImageViewAbstract>,
|
||||||
|
filter: Filter,
|
||||||
|
) -> Arc<PersistentDescriptorSet> {
|
||||||
let sampler = Sampler::new(
|
let sampler = Sampler::new(
|
||||||
self.graphics.device.clone(),
|
self.graphics.device.clone(),
|
||||||
SamplerCreateInfo {
|
SamplerCreateInfo {
|
||||||
@@ -455,7 +721,7 @@ impl WlxPipeline {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let layout = self.pipeline.layout().set_layouts().get(set).unwrap();
|
let layout = self.pipeline.layout().set_layouts().get(set).unwrap();
|
||||||
|
|
||||||
PersistentDescriptorSet::new(
|
PersistentDescriptorSet::new(
|
||||||
@@ -467,7 +733,9 @@ impl WlxPipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn uniform_buffer<T>(&self, set: usize, data: Vec<T>) -> Arc<PersistentDescriptorSet>
|
pub fn uniform_buffer<T>(&self, set: usize, data: Vec<T>) -> Arc<PersistentDescriptorSet>
|
||||||
where T: BufferContents + Copy {
|
where
|
||||||
|
T: BufferContents + Copy,
|
||||||
|
{
|
||||||
let uniform_buffer = SubbufferAllocator::new(
|
let uniform_buffer = SubbufferAllocator::new(
|
||||||
self.graphics.memory_allocator.clone(),
|
self.graphics.memory_allocator.clone(),
|
||||||
SubbufferAllocatorCreateInfo {
|
SubbufferAllocatorCreateInfo {
|
||||||
@@ -486,27 +754,44 @@ impl WlxPipeline {
|
|||||||
PersistentDescriptorSet::new(
|
PersistentDescriptorSet::new(
|
||||||
&self.graphics.descriptor_set_allocator,
|
&self.graphics.descriptor_set_allocator,
|
||||||
layout.clone(),
|
layout.clone(),
|
||||||
[WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)]
|
[WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)],
|
||||||
).unwrap()
|
)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_pass(self: &Arc<Self>, dimensions: [f32; 2], vertex_buffer: Subbuffer<[Vert2Uv]>, index_buffer: Subbuffer<[u16]>, descriptor_sets: Vec<Arc<PersistentDescriptorSet>>) -> WlxPass {
|
pub fn create_pass(
|
||||||
WlxPass::new(self.clone(), dimensions, vertex_buffer, index_buffer, descriptor_sets)
|
self: &Arc<Self>,
|
||||||
|
dimensions: [f32; 2],
|
||||||
|
vertex_buffer: Subbuffer<[Vert2Uv]>,
|
||||||
|
index_buffer: Subbuffer<[u16]>,
|
||||||
|
descriptor_sets: Vec<Arc<PersistentDescriptorSet>>,
|
||||||
|
) -> WlxPass {
|
||||||
|
WlxPass::new(
|
||||||
|
self.clone(),
|
||||||
|
dimensions,
|
||||||
|
vertex_buffer,
|
||||||
|
index_buffer,
|
||||||
|
descriptor_sets,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WlxPass
|
pub struct WlxPass {
|
||||||
{
|
|
||||||
pipeline: Arc<WlxPipeline>,
|
pipeline: Arc<WlxPipeline>,
|
||||||
vertex_buffer: Subbuffer<[Vert2Uv]>,
|
vertex_buffer: Subbuffer<[Vert2Uv]>,
|
||||||
index_buffer: Subbuffer<[u16]>,
|
index_buffer: Subbuffer<[u16]>,
|
||||||
descriptor_sets: Vec<Arc<PersistentDescriptorSet>>,
|
descriptor_sets: Vec<Arc<PersistentDescriptorSet>>,
|
||||||
pub command_buffer: Arc<SecondaryAutoCommandBuffer>,
|
pub command_buffer: Arc<SecondaryAutoCommandBuffer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlxPass
|
impl WlxPass {
|
||||||
{
|
fn new(
|
||||||
fn new(pipeline: Arc<WlxPipeline>, dimensions: [f32; 2], vertex_buffer: Subbuffer<[Vert2Uv]>, index_buffer: Subbuffer<[u16]>, descriptor_sets: Vec<Arc<PersistentDescriptorSet>>) -> Self {
|
pipeline: Arc<WlxPipeline>,
|
||||||
|
dimensions: [f32; 2],
|
||||||
|
vertex_buffer: Subbuffer<[Vert2Uv]>,
|
||||||
|
index_buffer: Subbuffer<[u16]>,
|
||||||
|
descriptor_sets: Vec<Arc<PersistentDescriptorSet>>,
|
||||||
|
) -> Self {
|
||||||
let viewport = Viewport {
|
let viewport = Viewport {
|
||||||
origin: [0.0, 0.0],
|
origin: [0.0, 0.0],
|
||||||
dimensions,
|
dimensions,
|
||||||
@@ -515,21 +800,23 @@ impl WlxPass
|
|||||||
|
|
||||||
let pipeline_inner = pipeline.inner().clone();
|
let pipeline_inner = pipeline.inner().clone();
|
||||||
let mut command_buffer = AutoCommandBufferBuilder::secondary(
|
let mut command_buffer = AutoCommandBufferBuilder::secondary(
|
||||||
&pipeline.graphics.command_buffer_allocator,
|
&pipeline.graphics.command_buffer_allocator,
|
||||||
pipeline.graphics.queue.queue_family_index(),
|
pipeline.graphics.queue.queue_family_index(),
|
||||||
CommandBufferUsage::MultipleSubmit,
|
CommandBufferUsage::MultipleSubmit,
|
||||||
CommandBufferInheritanceInfo {
|
CommandBufferInheritanceInfo {
|
||||||
render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRendering(
|
render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRendering(
|
||||||
CommandBufferInheritanceRenderingInfo {
|
CommandBufferInheritanceRenderingInfo {
|
||||||
color_attachment_formats: vec![Some(pipeline.format)],
|
color_attachment_formats: vec![Some(pipeline.format)],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})),
|
},
|
||||||
..Default::default()
|
)),
|
||||||
}
|
..Default::default()
|
||||||
)
|
},
|
||||||
.unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
command_buffer.set_viewport(0, [viewport])
|
command_buffer
|
||||||
|
.set_viewport(0, [viewport])
|
||||||
.bind_pipeline_graphics(pipeline_inner)
|
.bind_pipeline_graphics(pipeline_inner)
|
||||||
.bind_descriptor_sets(
|
.bind_descriptor_sets(
|
||||||
PipelineBindPoint::Graphics,
|
PipelineBindPoint::Graphics,
|
||||||
@@ -545,9 +832,10 @@ impl WlxPass
|
|||||||
error!("Failed to draw: {}", source);
|
error!("Failed to draw: {}", source);
|
||||||
}
|
}
|
||||||
Err(err)
|
Err(err)
|
||||||
}).unwrap();
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
pipeline,
|
pipeline,
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
index_buffer,
|
index_buffer,
|
||||||
@@ -556,4 +844,3 @@ impl WlxPass
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use fontconfig::{FontConfig, OwnedPattern};
|
|||||||
use freetype::{bitmap::PixelMode, face::LoadFlag, Face, Library};
|
use freetype::{bitmap::PixelMode, face::LoadFlag, Face, Library};
|
||||||
use idmap::IdMap;
|
use idmap::IdMap;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use vulkano::{format::Format, command_buffer::CommandBufferUsage, image::ImmutableImage};
|
use vulkano::{command_buffer::CommandBufferUsage, format::Format, image::ImmutableImage};
|
||||||
|
|
||||||
use crate::graphics::WlxGraphics;
|
use crate::graphics::WlxGraphics;
|
||||||
|
|
||||||
@@ -23,9 +23,6 @@ struct FontCollection {
|
|||||||
|
|
||||||
struct Font {
|
struct Font {
|
||||||
face: Face,
|
face: Face,
|
||||||
path: String,
|
|
||||||
index: isize,
|
|
||||||
size: isize,
|
|
||||||
glyphs: IdMap<usize, Rc<Glyph>>,
|
glyphs: IdMap<usize, Rc<Glyph>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +47,12 @@ impl FontCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_text_size(&mut self, text: &str, size: isize, graphics: Arc<WlxGraphics>) -> (f32, f32) {
|
pub fn get_text_size(
|
||||||
|
&mut self,
|
||||||
|
text: &str,
|
||||||
|
size: isize,
|
||||||
|
graphics: Arc<WlxGraphics>,
|
||||||
|
) -> (f32, f32) {
|
||||||
let sizef = size as f32;
|
let sizef = size as f32;
|
||||||
|
|
||||||
let height = sizef + ((text.lines().count() as f32) - 1f32) * (sizef * 1.5);
|
let height = sizef + ((text.lines().count() as f32) - 1f32) * (sizef * 1.5);
|
||||||
@@ -59,7 +61,10 @@ impl FontCache {
|
|||||||
for line in text.lines() {
|
for line in text.lines() {
|
||||||
let w: f32 = line
|
let w: f32 = line
|
||||||
.chars()
|
.chars()
|
||||||
.map(|c| self.get_glyph_for_cp(c as usize, size, graphics.clone()).advance)
|
.map(|c| {
|
||||||
|
self.get_glyph_for_cp(c as usize, size, graphics.clone())
|
||||||
|
.advance
|
||||||
|
})
|
||||||
.sum();
|
.sum();
|
||||||
|
|
||||||
if w > max_w {
|
if w > max_w {
|
||||||
@@ -69,7 +74,12 @@ impl FontCache {
|
|||||||
(max_w, height)
|
(max_w, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_glyphs(&mut self, text: &str, size: isize, graphics: Arc<WlxGraphics>) -> Vec<Rc<Glyph>> {
|
pub fn get_glyphs(
|
||||||
|
&mut self,
|
||||||
|
text: &str,
|
||||||
|
size: isize,
|
||||||
|
graphics: Arc<WlxGraphics>,
|
||||||
|
) -> Vec<Rc<Glyph>> {
|
||||||
let mut glyphs = Vec::new();
|
let mut glyphs = Vec::new();
|
||||||
for line in text.lines() {
|
for line in text.lines() {
|
||||||
for c in line.chars() {
|
for c in line.chars() {
|
||||||
@@ -143,13 +153,7 @@ impl FontCache {
|
|||||||
let mut glyphs = IdMap::new();
|
let mut glyphs = IdMap::new();
|
||||||
glyphs.insert(0, zero_glyph);
|
glyphs.insert(0, zero_glyph);
|
||||||
|
|
||||||
let font = Font {
|
let font = Font { face, glyphs };
|
||||||
face,
|
|
||||||
path: path.to_string(),
|
|
||||||
size,
|
|
||||||
index: font_idx as _,
|
|
||||||
glyphs,
|
|
||||||
};
|
|
||||||
coll.fonts.push(font);
|
coll.fonts.push(font);
|
||||||
|
|
||||||
idx
|
idx
|
||||||
@@ -159,7 +163,12 @@ impl FontCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_glyph_for_cp(&mut self, cp: usize, size: isize, graphics: Arc<WlxGraphics>) -> Rc<Glyph> {
|
fn get_glyph_for_cp(
|
||||||
|
&mut self,
|
||||||
|
cp: usize,
|
||||||
|
size: isize,
|
||||||
|
graphics: Arc<WlxGraphics>,
|
||||||
|
) -> Rc<Glyph> {
|
||||||
let key = self.get_font_for_cp(cp, size);
|
let key = self.get_font_for_cp(cp, size);
|
||||||
|
|
||||||
let font = &mut self.collections[size].fonts[key];
|
let font = &mut self.collections[size].fonts[key];
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ use glam::{Vec2, Vec3};
|
|||||||
use vulkano::{
|
use vulkano::{
|
||||||
command_buffer::{CommandBufferUsage, PrimaryAutoCommandBuffer},
|
command_buffer::{CommandBufferUsage, PrimaryAutoCommandBuffer},
|
||||||
format::Format,
|
format::Format,
|
||||||
image::{view::ImageView, AttachmentImage},
|
image::{view::ImageView, AttachmentImage, ImageLayout, ImageViewAbstract},
|
||||||
sampler::Filter,
|
sampler::Filter,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
graphics::{WlxCommandBuffer, WlxGraphics, WlxPass, WlxPipeline},
|
backend::{
|
||||||
overlays::{
|
input::{InteractionHandler, PointerHit},
|
||||||
interactions::{InteractionHandler, PointerHit},
|
overlay::{OverlayBackend, OverlayRenderer},
|
||||||
OverlayBackend, OverlayRenderer,
|
|
||||||
},
|
},
|
||||||
|
graphics::{WlxCommandBuffer, WlxGraphics, WlxPass, WlxPipeline},
|
||||||
shaders::{frag_color, frag_glyph, frag_sprite, vert_common},
|
shaders::{frag_color, frag_glyph, frag_sprite, vert_common},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
};
|
};
|
||||||
@@ -203,11 +203,8 @@ pub struct Canvas<D, S> {
|
|||||||
interact_stride: usize,
|
interact_stride: usize,
|
||||||
interact_rows: usize,
|
interact_rows: usize,
|
||||||
|
|
||||||
tex_fg: Arc<AttachmentImage>,
|
|
||||||
view_fg: Arc<ImageView<AttachmentImage>>,
|
view_fg: Arc<ImageView<AttachmentImage>>,
|
||||||
tex_bg: Arc<AttachmentImage>,
|
|
||||||
view_bg: Arc<ImageView<AttachmentImage>>,
|
view_bg: Arc<ImageView<AttachmentImage>>,
|
||||||
tex_final: Arc<AttachmentImage>,
|
|
||||||
view_final: Arc<ImageView<AttachmentImage>>,
|
view_final: Arc<ImageView<AttachmentImage>>,
|
||||||
|
|
||||||
pass_fg: WlxPass,
|
pass_fg: WlxPass,
|
||||||
@@ -284,11 +281,8 @@ impl<D, S> Canvas<D, S> {
|
|||||||
interact_map: vec![None; stride * rows],
|
interact_map: vec![None; stride * rows],
|
||||||
interact_stride: stride,
|
interact_stride: stride,
|
||||||
interact_rows: rows,
|
interact_rows: rows,
|
||||||
tex_fg,
|
|
||||||
view_fg,
|
view_fg,
|
||||||
tex_bg,
|
|
||||||
view_bg,
|
view_bg,
|
||||||
tex_final,
|
|
||||||
view_final,
|
view_final,
|
||||||
pass_fg,
|
pass_fg,
|
||||||
pass_bg,
|
pass_bg,
|
||||||
@@ -323,7 +317,7 @@ impl<D, S> Canvas<D, S> {
|
|||||||
.canvas
|
.canvas
|
||||||
.graphics
|
.graphics
|
||||||
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)
|
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)
|
||||||
.begin(self.view_bg.clone());
|
.begin(self.view_bg.clone(), None);
|
||||||
for c in self.controls.iter_mut() {
|
for c in self.controls.iter_mut() {
|
||||||
if let Some(fun) = c.on_render_bg {
|
if let Some(fun) = c.on_render_bg {
|
||||||
fun(c, &self.canvas, app, &mut cmd_buffer);
|
fun(c, &self.canvas, app, &mut cmd_buffer);
|
||||||
@@ -337,7 +331,7 @@ impl<D, S> Canvas<D, S> {
|
|||||||
.canvas
|
.canvas
|
||||||
.graphics
|
.graphics
|
||||||
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)
|
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)
|
||||||
.begin(self.view_fg.clone());
|
.begin(self.view_fg.clone(), None);
|
||||||
for c in self.controls.iter_mut() {
|
for c in self.controls.iter_mut() {
|
||||||
if let Some(fun) = c.on_render_fg {
|
if let Some(fun) = c.on_render_fg {
|
||||||
fun(c, &self.canvas, app, &mut cmd_buffer);
|
fun(c, &self.canvas, app, &mut cmd_buffer);
|
||||||
@@ -352,32 +346,32 @@ impl<D, S> Canvas<D, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<D, S> InteractionHandler for Canvas<D, S> {
|
impl<D, S> InteractionHandler for Canvas<D, S> {
|
||||||
fn on_left(&mut self, _app: &mut AppState, hand: usize) {
|
fn on_left(&mut self, _app: &mut AppState, pointer: usize) {
|
||||||
self.hover_controls[hand] = None;
|
self.hover_controls[pointer] = None;
|
||||||
}
|
}
|
||||||
fn on_hover(&mut self, _app: &mut AppState, hit: &PointerHit) {
|
fn on_hover(&mut self, _app: &mut AppState, hit: &PointerHit) {
|
||||||
if let Some(i) = self.interactive_get_idx(hit.uv) {
|
if let Some(i) = self.interactive_get_idx(hit.uv) {
|
||||||
self.hover_controls[hit.hand] = Some(i);
|
self.hover_controls[hit.pointer] = Some(i);
|
||||||
} else {
|
} else {
|
||||||
self.hover_controls[hit.hand] = None;
|
self.hover_controls[hit.pointer] = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
||||||
let idx = if pressed {
|
let idx = if pressed {
|
||||||
self.interactive_get_idx(hit.uv)
|
self.interactive_get_idx(hit.uv)
|
||||||
} else {
|
} else {
|
||||||
self.pressed_controls[hit.hand]
|
self.pressed_controls[hit.pointer]
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(idx) = idx {
|
if let Some(idx) = idx {
|
||||||
let c = &mut self.controls[idx];
|
let c = &mut self.controls[idx];
|
||||||
if pressed {
|
if pressed {
|
||||||
if let Some(ref mut f) = c.on_press {
|
if let Some(ref mut f) = c.on_press {
|
||||||
self.pressed_controls[hit.hand] = Some(idx);
|
self.pressed_controls[hit.pointer] = Some(idx);
|
||||||
f(c, &mut self.canvas.data, app);
|
f(c, &mut self.canvas.data, app);
|
||||||
}
|
}
|
||||||
} else if let Some(ref mut f) = c.on_release {
|
} else if let Some(ref mut f) = c.on_release {
|
||||||
self.pressed_controls[hit.hand] = None;
|
self.pressed_controls[hit.pointer] = None;
|
||||||
f(c, &mut self.canvas.data, app);
|
f(c, &mut self.canvas.data, app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -410,7 +404,10 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
|
|||||||
.canvas
|
.canvas
|
||||||
.graphics
|
.graphics
|
||||||
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)
|
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)
|
||||||
.begin(self.view_final.clone());
|
.begin(
|
||||||
|
self.view_final.clone(),
|
||||||
|
Some(ImageLayout::TransferSrcOptimal),
|
||||||
|
);
|
||||||
|
|
||||||
if dirty {
|
if dirty {
|
||||||
self.render_fg(app);
|
self.render_fg(app);
|
||||||
@@ -437,8 +434,8 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
|
|||||||
|
|
||||||
let _ = cmd_buffer.end_render_and_execute();
|
let _ = cmd_buffer.end_render_and_execute();
|
||||||
}
|
}
|
||||||
fn view(&mut self) -> Arc<dyn vulkano::image::ImageViewAbstract> {
|
fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> {
|
||||||
self.view_final.clone()
|
Some(self.view_final.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
254
src/main.rs
254
src/main.rs
@@ -4,43 +4,12 @@ mod graphics;
|
|||||||
mod gui;
|
mod gui;
|
||||||
mod input;
|
mod input;
|
||||||
mod overlays;
|
mod overlays;
|
||||||
mod ovr;
|
|
||||||
mod shaders;
|
mod shaders;
|
||||||
mod state;
|
mod state;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use crate::backend::openvr::openvr_run;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crate::graphics::{Vert2Uv, WlxGraphics, INDICES};
|
|
||||||
use crate::input::initialize_input;
|
|
||||||
use crate::overlays::watch::create_watch;
|
|
||||||
use crate::{
|
|
||||||
shaders::{frag_sprite, vert_common},
|
|
||||||
state::AppState,
|
|
||||||
};
|
|
||||||
use env_logger::Env;
|
use env_logger::Env;
|
||||||
use log::{info, warn};
|
use log::info;
|
||||||
use vulkano::{
|
|
||||||
buffer::BufferUsage,
|
|
||||||
command_buffer::CommandBufferUsage,
|
|
||||||
image::{
|
|
||||||
view::{ImageView, ImageViewCreateInfo},
|
|
||||||
ImageAccess, ImageSubresourceRange, ImageViewType, SwapchainImage,
|
|
||||||
},
|
|
||||||
pipeline::graphics::viewport::Viewport,
|
|
||||||
sampler::Filter,
|
|
||||||
swapchain::{
|
|
||||||
acquire_next_image, AcquireError, SwapchainCreateInfo, SwapchainCreationError,
|
|
||||||
SwapchainPresentInfo,
|
|
||||||
},
|
|
||||||
sync::{self, FlushError, GpuFuture},
|
|
||||||
};
|
|
||||||
use winit::{
|
|
||||||
event::{Event, WindowEvent},
|
|
||||||
event_loop::ControlFlow,
|
|
||||||
window::Window,
|
|
||||||
};
|
|
||||||
use wlx_capture::{frame::WlxFrame, wayland::WlxClient, wlr::WlrDmabufCapture, WlxCapture};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
|
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
|
||||||
@@ -50,222 +19,5 @@ fn main() {
|
|||||||
env!("CARGO_PKG_VERSION")
|
env!("CARGO_PKG_VERSION")
|
||||||
);
|
);
|
||||||
|
|
||||||
let (graphics, event_loop) = WlxGraphics::new();
|
openvr_run();
|
||||||
let (mut swapchain, images) = graphics.create_swapchain(None);
|
|
||||||
|
|
||||||
let mut app = AppState {
|
|
||||||
fc: crate::gui::font::FontCache::new(),
|
|
||||||
session: crate::state::AppSession::load(),
|
|
||||||
tasks: VecDeque::with_capacity(16),
|
|
||||||
graphics: graphics.clone(),
|
|
||||||
format: swapchain.image_format(),
|
|
||||||
input: initialize_input(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let wl = WlxClient::new().unwrap();
|
|
||||||
let output_id = wl.outputs[0].id;
|
|
||||||
let mut capture = WlrDmabufCapture::new(wl, output_id).unwrap();
|
|
||||||
let rx = capture.init();
|
|
||||||
|
|
||||||
let vertices = [
|
|
||||||
Vert2Uv {
|
|
||||||
in_pos: [0., 0.],
|
|
||||||
in_uv: [0., 0.],
|
|
||||||
},
|
|
||||||
Vert2Uv {
|
|
||||||
in_pos: [0., 1.],
|
|
||||||
in_uv: [0., 1.],
|
|
||||||
},
|
|
||||||
Vert2Uv {
|
|
||||||
in_pos: [1., 0.],
|
|
||||||
in_uv: [1., 0.],
|
|
||||||
},
|
|
||||||
Vert2Uv {
|
|
||||||
in_pos: [1., 1.],
|
|
||||||
in_uv: [1., 1.],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
let vertex_buffer = graphics.upload_buffer(BufferUsage::VERTEX_BUFFER, vertices.iter());
|
|
||||||
let index_buffer = graphics.upload_buffer(BufferUsage::INDEX_BUFFER, INDICES.iter());
|
|
||||||
|
|
||||||
let vs = vert_common::load(graphics.device.clone()).unwrap();
|
|
||||||
let fs = frag_sprite::load(graphics.device.clone()).unwrap();
|
|
||||||
|
|
||||||
let uploads = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit);
|
|
||||||
|
|
||||||
let mut watch = create_watch(&app, vec![]);
|
|
||||||
watch.init(&mut app);
|
|
||||||
watch.render(&mut app);
|
|
||||||
|
|
||||||
let pipeline1 = graphics.create_pipeline(vs.clone(), fs.clone(), swapchain.image_format());
|
|
||||||
let set1 = pipeline1.uniform_sampler(0, watch.view(), Filter::Nearest);
|
|
||||||
|
|
||||||
capture.request_new_frame();
|
|
||||||
|
|
||||||
let pipeline = graphics.create_pipeline(vs, fs, swapchain.image_format());
|
|
||||||
let set0;
|
|
||||||
loop {
|
|
||||||
if let Ok(frame) = rx.try_recv() {
|
|
||||||
match frame {
|
|
||||||
WlxFrame::Dmabuf(dmabuf_frame) => match graphics.dmabuf_texture(dmabuf_frame) {
|
|
||||||
Ok(tex) => {
|
|
||||||
let format = tex.format();
|
|
||||||
let view = ImageView::new(
|
|
||||||
tex,
|
|
||||||
ImageViewCreateInfo {
|
|
||||||
format: Some(format),
|
|
||||||
view_type: ImageViewType::Dim2d,
|
|
||||||
subresource_range: ImageSubresourceRange::from_parameters(
|
|
||||||
format, 1, 1,
|
|
||||||
),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
set0 = pipeline.uniform_sampler(0, view, Filter::Nearest);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
warn!("Failed to create texture from dmabuf: {}", e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
warn!("Received non-dmabuf frame");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//let set1 = graphics.uniform_buffer(1, vec![1.0, 1.0, 1.0, 1.0]);
|
|
||||||
let image_extent_f32 = [
|
|
||||||
swapchain.image_extent()[0] as f32,
|
|
||||||
swapchain.image_extent()[1] as f32,
|
|
||||||
];
|
|
||||||
let image_extent2_f32 = [
|
|
||||||
swapchain.image_extent()[0] as f32 / 2.,
|
|
||||||
swapchain.image_extent()[1] as f32 / 2.,
|
|
||||||
];
|
|
||||||
let pass = pipeline.create_pass(
|
|
||||||
image_extent_f32,
|
|
||||||
vertex_buffer.clone(),
|
|
||||||
index_buffer.clone(),
|
|
||||||
vec![set0],
|
|
||||||
);
|
|
||||||
let pass2 = pipeline1.create_pass(image_extent2_f32, vertex_buffer, index_buffer, vec![set1]);
|
|
||||||
|
|
||||||
let mut viewport = Viewport {
|
|
||||||
origin: [0.0, 0.0],
|
|
||||||
dimensions: [1024.0, 1024.0],
|
|
||||||
depth_range: 0.0..1.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut attachment_image_views = window_size_dependent_setup(&images, &mut viewport);
|
|
||||||
|
|
||||||
//let set1 = pipeline.uniform_buffer(1, vec![1.0, 0.0, 1.0, 1.0]);
|
|
||||||
|
|
||||||
let mut recreate_swapchain = false;
|
|
||||||
let mut previous_frame_end = //Some(sync::now(graphics.device.clone()).boxed());
|
|
||||||
Some(uploads.end_and_execute().boxed());
|
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(_),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
|
||||||
|
|
||||||
if recreate_swapchain {
|
|
||||||
let window = graphics
|
|
||||||
.surface
|
|
||||||
.object()
|
|
||||||
.unwrap()
|
|
||||||
.downcast_ref::<Window>()
|
|
||||||
.unwrap();
|
|
||||||
let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo {
|
|
||||||
image_extent: window.inner_size().into(),
|
|
||||||
..swapchain.create_info()
|
|
||||||
}) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
|
|
||||||
Err(e) => panic!("failed to recreate swapchain: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
|
||||||
attachment_image_views = window_size_dependent_setup(&new_images, &mut viewport);
|
|
||||||
recreate_swapchain = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(swapchain.clone(), None) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(AcquireError::OutOfDate) => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if suboptimal {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cmd = graphics
|
|
||||||
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)
|
|
||||||
.begin(attachment_image_views[image_index as usize].clone())
|
|
||||||
.run(&pass)
|
|
||||||
.run(&pass2)
|
|
||||||
.end_render();
|
|
||||||
|
|
||||||
let future = previous_frame_end
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.join(acquire_future)
|
|
||||||
.then_execute(graphics.queue.clone(), cmd)
|
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
graphics.queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future {
|
|
||||||
Ok(future) => {
|
|
||||||
previous_frame_end = Some(future.boxed());
|
|
||||||
}
|
|
||||||
Err(FlushError::OutOfDate) => {
|
|
||||||
recreate_swapchain = true;
|
|
||||||
previous_frame_end = Some(sync::now(graphics.device.clone()).boxed());
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
|
||||||
previous_frame_end = Some(sync::now(graphics.device.clone()).boxed());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function is called once during initialization, then again whenever the window is resized.
|
|
||||||
fn window_size_dependent_setup(
|
|
||||||
images: &[Arc<SwapchainImage>],
|
|
||||||
viewport: &mut Viewport,
|
|
||||||
) -> Vec<Arc<ImageView<SwapchainImage>>> {
|
|
||||||
let dimensions = images[0].dimensions().width_height();
|
|
||||||
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
|
|
||||||
|
|
||||||
images
|
|
||||||
.iter()
|
|
||||||
.map(|image| ImageView::new_default(image.clone()).unwrap())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
use std::{collections::VecDeque, time::Instant};
|
|
||||||
|
|
||||||
use glam::{Affine3A, Vec2, Vec3};
|
|
||||||
|
|
||||||
use crate::state::AppState;
|
|
||||||
|
|
||||||
pub const HAND_LEFT: usize = 0;
|
|
||||||
pub const HAND_RIGHT: usize = 1;
|
|
||||||
|
|
||||||
pub const POINTER_NORM: u16 = 0;
|
|
||||||
pub const POINTER_SHIFT: u16 = 1;
|
|
||||||
pub const POINTER_ALT: u16 = 2;
|
|
||||||
|
|
||||||
pub trait InteractionHandler {
|
|
||||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit);
|
|
||||||
fn on_left(&mut self, app: &mut AppState, hand: usize);
|
|
||||||
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool);
|
|
||||||
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Dummies & plumbing below ---
|
|
||||||
|
|
||||||
impl Default for PointerState {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
click: false,
|
|
||||||
grab: false,
|
|
||||||
show_hide: false,
|
|
||||||
scroll: 0.,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DummyInteractionHandler;
|
|
||||||
|
|
||||||
impl InteractionHandler for DummyInteractionHandler {
|
|
||||||
fn on_left(&mut self, _app: &mut AppState, _hand: usize) {}
|
|
||||||
fn on_hover(&mut self, _app: &mut AppState, _hit: &PointerHit) {}
|
|
||||||
fn on_pointer(&mut self, _app: &mut AppState, _hit: &PointerHit, _pressed: bool) {}
|
|
||||||
fn on_scroll(&mut self, _app: &mut AppState, _hit: &PointerHit, _delta: f32) {}
|
|
||||||
}
|
|
||||||
@@ -10,23 +10,25 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
backend::overlay::{OverlayData, OverlayState},
|
||||||
gui::{color_parse, CanvasBuilder, Control},
|
gui::{color_parse, CanvasBuilder, Control},
|
||||||
input::{KeyModifier, VirtualKey, KEYS_TO_MODS},
|
input::{KeyModifier, VirtualKey, KEYS_TO_MODS},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
};
|
};
|
||||||
use glam::{vec2, vec3};
|
use glam::{vec2, vec3a};
|
||||||
use log::error;
|
use log::error;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rodio::{Decoder, OutputStream, Source};
|
use rodio::{Decoder, OutputStream, Source};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::OverlayData;
|
|
||||||
|
|
||||||
const PIXELS_PER_UNIT: f32 = 80.;
|
const PIXELS_PER_UNIT: f32 = 80.;
|
||||||
const BUTTON_PADDING: f32 = 4.;
|
const BUTTON_PADDING: f32 = 4.;
|
||||||
|
|
||||||
pub fn create_keyboard(app: &AppState) -> OverlayData {
|
pub fn create_keyboard<O>(app: &AppState) -> OverlayData<O>
|
||||||
|
where
|
||||||
|
O: Default,
|
||||||
|
{
|
||||||
let size = vec2(
|
let size = vec2(
|
||||||
LAYOUT.row_size * PIXELS_PER_UNIT,
|
LAYOUT.row_size * PIXELS_PER_UNIT,
|
||||||
(LAYOUT.main_layout.len() as f32) * PIXELS_PER_UNIT,
|
(LAYOUT.main_layout.len() as f32) * PIXELS_PER_UNIT,
|
||||||
@@ -106,12 +108,15 @@ pub fn create_keyboard(app: &AppState) -> OverlayData {
|
|||||||
let canvas = canvas.build();
|
let canvas = canvas.build();
|
||||||
|
|
||||||
OverlayData {
|
OverlayData {
|
||||||
name: Arc::from("Kbd"),
|
state: OverlayState {
|
||||||
show_hide: true,
|
name: Arc::from("Kbd"),
|
||||||
width: LAYOUT.row_size * 0.05,
|
show_hide: true,
|
||||||
size: (size.x as _, size.y as _),
|
width: LAYOUT.row_size * 0.05,
|
||||||
grabbable: true,
|
size: (size.x as _, size.y as _),
|
||||||
spawn_point: vec3(0., -0.5, -1.),
|
grabbable: true,
|
||||||
|
spawn_point: vec3a(0., -0.5, -1.),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
backend: Box::new(canvas),
|
backend: Box::new(canvas),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,145 +1,3 @@
|
|||||||
use std::sync::{
|
|
||||||
atomic::{AtomicUsize, Ordering},
|
|
||||||
Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use glam::{Affine3A, Quat, Vec3};
|
|
||||||
use vulkano::image::ImageViewAbstract;
|
|
||||||
|
|
||||||
use crate::state::AppState;
|
|
||||||
|
|
||||||
use self::interactions::{DummyInteractionHandler, InteractionHandler, PointerHit};
|
|
||||||
|
|
||||||
pub mod interactions;
|
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
|
pub mod screen;
|
||||||
pub mod watch;
|
pub mod watch;
|
||||||
|
|
||||||
static AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
pub enum RelativeTo {
|
|
||||||
None,
|
|
||||||
Head,
|
|
||||||
Hand(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait OverlayBackend: OverlayRenderer + InteractionHandler {}
|
|
||||||
|
|
||||||
pub struct OverlayData {
|
|
||||||
pub id: usize,
|
|
||||||
pub name: Arc<str>,
|
|
||||||
pub width: f32,
|
|
||||||
pub size: (i32, i32),
|
|
||||||
pub want_visible: bool,
|
|
||||||
pub show_hide: bool,
|
|
||||||
pub grabbable: bool,
|
|
||||||
pub transform: Affine3A,
|
|
||||||
pub spawn_point: Vec3,
|
|
||||||
pub spawn_rotation: Quat,
|
|
||||||
pub relative_to: RelativeTo,
|
|
||||||
pub interaction_transform: Affine3A,
|
|
||||||
pub backend: Box<dyn OverlayBackend>,
|
|
||||||
pub primary_pointer: Option<usize>,
|
|
||||||
}
|
|
||||||
impl Default for OverlayData {
|
|
||||||
fn default() -> OverlayData {
|
|
||||||
OverlayData {
|
|
||||||
id: AUTO_INCREMENT.fetch_add(1, Ordering::Relaxed),
|
|
||||||
name: Arc::from(""),
|
|
||||||
width: 1.,
|
|
||||||
size: (0, 0),
|
|
||||||
want_visible: false,
|
|
||||||
show_hide: false,
|
|
||||||
grabbable: false,
|
|
||||||
relative_to: RelativeTo::None,
|
|
||||||
spawn_point: Vec3::NEG_Z,
|
|
||||||
spawn_rotation: Quat::IDENTITY,
|
|
||||||
transform: Affine3A::IDENTITY,
|
|
||||||
interaction_transform: Affine3A::IDENTITY,
|
|
||||||
backend: Box::new(SplitOverlayBackend::default()),
|
|
||||||
primary_pointer: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OverlayData {
|
|
||||||
pub fn reset(&mut self, app: &mut AppState) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
pub fn init(&mut self, app: &mut AppState) {
|
|
||||||
self.backend.init(app);
|
|
||||||
}
|
|
||||||
pub fn render(&mut self, app: &mut AppState) {
|
|
||||||
self.backend.render(app);
|
|
||||||
}
|
|
||||||
pub fn view(&mut self) -> Arc<dyn ImageViewAbstract> {
|
|
||||||
self.backend.view()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait OverlayRenderer {
|
|
||||||
fn init(&mut self, app: &mut AppState);
|
|
||||||
fn pause(&mut self, app: &mut AppState);
|
|
||||||
fn resume(&mut self, app: &mut AppState);
|
|
||||||
fn render(&mut self, app: &mut AppState);
|
|
||||||
fn view(&mut self) -> Arc<dyn ImageViewAbstract>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FallbackRenderer;
|
|
||||||
|
|
||||||
impl OverlayRenderer for FallbackRenderer {
|
|
||||||
fn init(&mut self, _app: &mut AppState) {}
|
|
||||||
fn pause(&mut self, _app: &mut AppState) {}
|
|
||||||
fn resume(&mut self, _app: &mut AppState) {}
|
|
||||||
fn render(&mut self, _app: &mut AppState) {}
|
|
||||||
fn view(&mut self) -> Arc<dyn ImageViewAbstract> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Boilerplate and dummies
|
|
||||||
|
|
||||||
pub struct SplitOverlayBackend {
|
|
||||||
pub renderer: Box<dyn OverlayRenderer>,
|
|
||||||
pub interaction: Box<dyn InteractionHandler>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for SplitOverlayBackend {
|
|
||||||
fn default() -> SplitOverlayBackend {
|
|
||||||
SplitOverlayBackend {
|
|
||||||
renderer: Box::new(FallbackRenderer),
|
|
||||||
interaction: Box::new(DummyInteractionHandler),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OverlayBackend for SplitOverlayBackend {}
|
|
||||||
impl OverlayRenderer for SplitOverlayBackend {
|
|
||||||
fn init(&mut self, app: &mut AppState) {
|
|
||||||
self.renderer.init(app);
|
|
||||||
}
|
|
||||||
fn pause(&mut self, app: &mut AppState) {
|
|
||||||
self.renderer.pause(app);
|
|
||||||
}
|
|
||||||
fn resume(&mut self, app: &mut AppState) {
|
|
||||||
self.renderer.resume(app);
|
|
||||||
}
|
|
||||||
fn render(&mut self, app: &mut AppState) {
|
|
||||||
self.renderer.render(app);
|
|
||||||
}
|
|
||||||
fn view(&mut self) -> Arc<dyn ImageViewAbstract> {
|
|
||||||
self.renderer.view()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl InteractionHandler for SplitOverlayBackend {
|
|
||||||
fn on_left(&mut self, app: &mut AppState, hand: usize) {
|
|
||||||
self.interaction.on_left(app, hand);
|
|
||||||
}
|
|
||||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) {
|
|
||||||
self.interaction.on_hover(app, hit);
|
|
||||||
}
|
|
||||||
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32) {
|
|
||||||
self.interaction.on_scroll(app, hit, delta);
|
|
||||||
}
|
|
||||||
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
|
||||||
self.interaction.on_pointer(app, hit, pressed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,20 +1,59 @@
|
|||||||
|
use log::{info, warn};
|
||||||
|
use std::{
|
||||||
|
f32::consts::PI,
|
||||||
|
path::Path,
|
||||||
|
sync::{mpsc::Receiver, Arc},
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
use vulkano::{
|
||||||
|
command_buffer::CommandBufferUsage,
|
||||||
|
format::Format,
|
||||||
|
image::{view::ImageView, ImageAccess, ImageViewAbstract, ImmutableImage},
|
||||||
|
Handle, VulkanObject,
|
||||||
|
};
|
||||||
|
use wlx_capture::{
|
||||||
|
frame::WlxFrame,
|
||||||
|
pipewire::{pipewire_select_screen, PipewireCapture},
|
||||||
|
wayland::{Transform, WlxClient, WlxOutput},
|
||||||
|
wlr::WlrDmabufCapture,
|
||||||
|
WlxCapture,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct ScreenInteractionData {
|
use glam::{vec2, Affine2, Quat, Vec2, Vec3};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
backend::{
|
||||||
|
input::{InteractionHandler, PointerHit, PointerMode},
|
||||||
|
overlay::{OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend},
|
||||||
|
},
|
||||||
|
input::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT},
|
||||||
|
state::{AppSession, AppState},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct ScreenInteractionHandler {
|
||||||
next_scroll: Instant,
|
next_scroll: Instant,
|
||||||
next_move: Instant,
|
next_move: Instant,
|
||||||
mouse_transform: Affine2,
|
mouse_transform: Affine2,
|
||||||
}
|
}
|
||||||
impl ScreenInteractionData {
|
impl ScreenInteractionHandler {
|
||||||
fn new(pos: Vec2, size: Vec2, transform: Transform) -> ScreenInteractionHandler {
|
fn new(pos: Vec2, size: Vec2, transform: Transform) -> ScreenInteractionHandler {
|
||||||
let transform = match transform {
|
let transform = match transform {
|
||||||
Transform::_90 | Transform::Flipped90 =>
|
Transform::_90 | Transform::Flipped90 => Affine2::from_cols(
|
||||||
Affine2::from_cols(vec2(0., size.y), vec2(-size.x, 0.), vec2(pos.x + size.x, pos.y)),
|
vec2(0., size.y),
|
||||||
Transform::_180 | Transform::Flipped180 =>
|
vec2(-size.x, 0.),
|
||||||
Affine2::from_cols(vec2(-size.x, 0.), vec2(0., -size.y), vec2(pos.x + size.x, pos.y + size.y)),
|
vec2(pos.x + size.x, pos.y),
|
||||||
Transform::_270 | Transform::Flipped270 =>
|
),
|
||||||
Affine2::from_cols(vec2(0., -size.y), vec2(size.x, 0.), vec2(pos.x, pos.y + size.y)),
|
Transform::_180 | Transform::Flipped180 => Affine2::from_cols(
|
||||||
_ =>
|
vec2(-size.x, 0.),
|
||||||
Affine2::from_cols(vec2(size.x, 0.), vec2(0., size.y), pos),
|
vec2(0., -size.y),
|
||||||
|
vec2(pos.x + size.x, pos.y + size.y),
|
||||||
|
),
|
||||||
|
Transform::_270 | Transform::Flipped270 => Affine2::from_cols(
|
||||||
|
vec2(0., -size.y),
|
||||||
|
vec2(size.x, 0.),
|
||||||
|
vec2(pos.x, pos.y + size.y),
|
||||||
|
),
|
||||||
|
_ => Affine2::from_cols(vec2(size.x, 0.), vec2(0., size.y), pos),
|
||||||
};
|
};
|
||||||
|
|
||||||
ScreenInteractionHandler {
|
ScreenInteractionHandler {
|
||||||
@@ -25,7 +64,222 @@ impl ScreenInteractionData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ScreenInteractionHandler {
|
impl InteractionHandler for ScreenInteractionHandler {
|
||||||
|
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) {
|
||||||
|
if self.next_move < Instant::now() {
|
||||||
|
let pos = self.mouse_transform.transform_point2(hit.uv);
|
||||||
|
app.input.mouse_move(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
||||||
|
let pos = self.mouse_transform.transform_point2(hit.uv);
|
||||||
|
app.input.mouse_move(pos);
|
||||||
|
|
||||||
|
let btn = match hit.mode {
|
||||||
|
PointerMode::Right => MOUSE_RIGHT,
|
||||||
|
PointerMode::Middle => MOUSE_MIDDLE,
|
||||||
|
_ => MOUSE_LEFT,
|
||||||
|
};
|
||||||
|
|
||||||
|
if pressed {
|
||||||
|
self.next_move = Instant::now() + Duration::from_millis(300);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.input.send_button(btn, pressed);
|
||||||
|
}
|
||||||
|
fn on_scroll(&mut self, app: &mut AppState, _hit: &PointerHit, delta: f32) {
|
||||||
|
let millis = (1. - delta.abs()) * delta;
|
||||||
|
if let Some(next_scroll) = Instant::now().checked_add(Duration::from_millis(millis as _)) {
|
||||||
|
self.next_scroll = next_scroll;
|
||||||
|
}
|
||||||
|
app.input.wheel(if delta < 0. { -1 } else { 1 })
|
||||||
|
}
|
||||||
|
fn on_left(&mut self, _app: &mut AppState, _hand: usize) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ScreenRenderer {
|
||||||
|
capture: Box<dyn WlxCapture>,
|
||||||
|
resolution: (i32, i32),
|
||||||
|
receiver: Option<Receiver<WlxFrame>>,
|
||||||
|
view: Option<Arc<dyn ImageViewAbstract>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScreenRenderer {
|
||||||
|
pub fn new_wlr(output: &WlxOutput) -> Option<ScreenRenderer> {
|
||||||
|
let Some(client) = WlxClient::new() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let Some(capture) = WlrDmabufCapture::new(client, output.id) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(ScreenRenderer {
|
||||||
|
capture: Box::new(capture),
|
||||||
|
resolution: output.size,
|
||||||
|
receiver: None,
|
||||||
|
view: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_pw(
|
||||||
|
output: &WlxOutput,
|
||||||
|
token: Option<&str>,
|
||||||
|
_fallback: bool,
|
||||||
|
) -> Option<ScreenRenderer> {
|
||||||
|
let name = output.name.clone();
|
||||||
|
let node_id = futures::executor::block_on(pipewire_select_screen(token)).ok()?;
|
||||||
|
|
||||||
|
let capture = PipewireCapture::new(name, node_id, 60);
|
||||||
|
|
||||||
|
Some(ScreenRenderer {
|
||||||
|
capture: Box::new(capture),
|
||||||
|
resolution: output.size,
|
||||||
|
receiver: None,
|
||||||
|
view: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_xshm() -> ScreenRenderer {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OverlayRenderer for ScreenRenderer {
|
||||||
|
fn init(&mut self, app: &mut AppState) {
|
||||||
|
self.receiver = Some(self.capture.init());
|
||||||
|
let mut cmd = app
|
||||||
|
.graphics
|
||||||
|
.create_command_buffer(CommandBufferUsage::OneTimeSubmit);
|
||||||
|
let default_image = cmd.texture2d(1, 1, Format::R8G8B8A8_UNORM, vec![255, 0, 255, 255]);
|
||||||
|
let _ = cmd.end_and_execute();
|
||||||
|
}
|
||||||
|
fn render(&mut self, app: &mut AppState) {
|
||||||
|
let Some(receiver) = self.receiver.as_mut() else {
|
||||||
|
log::error!("No receiver");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
for frame in receiver.try_iter() {
|
||||||
|
match frame {
|
||||||
|
WlxFrame::Dmabuf(frame) => {
|
||||||
|
if let Ok(new) = app.graphics.dmabuf_texture(frame) {
|
||||||
|
if let Some(current) = self.view.as_ref() {
|
||||||
|
if current.image().inner().image.handle().as_raw()
|
||||||
|
== new.inner().image.handle().as_raw()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.view = Some(ImageView::new_default(new).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WlxFrame::MemFd(frame) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
WlxFrame::MemPtr(frame) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
self.capture.request_new_frame();
|
||||||
|
}
|
||||||
|
fn pause(&mut self, _app: &mut AppState) {
|
||||||
|
self.capture.pause();
|
||||||
|
}
|
||||||
|
fn resume(&mut self, _app: &mut AppState) {
|
||||||
|
self.capture.resume();
|
||||||
|
}
|
||||||
|
fn view(&mut self) -> Option<Arc<dyn ImageViewAbstract>> {
|
||||||
|
self.view.as_ref().and_then(|v| Some(v.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_create_screen<O>(wl: &WlxClient, idx: usize, session: &AppSession) -> Option<OverlayData<O>>
|
||||||
|
where
|
||||||
|
O: Default,
|
||||||
|
{
|
||||||
|
let output = &wl.outputs[idx];
|
||||||
|
info!(
|
||||||
|
"{}: Res {}x{} Size {:?} Pos {:?}",
|
||||||
|
output.name, output.size.0, output.size.1, output.logical_size, output.logical_pos,
|
||||||
|
);
|
||||||
|
|
||||||
|
let size = (output.size.0, output.size.1);
|
||||||
|
let mut capture: Option<ScreenRenderer> = None;
|
||||||
|
|
||||||
|
if session.capture_method == "auto" && wl.maybe_wlr_dmabuf_mgr.is_some() {
|
||||||
|
info!("{}: Using Wlr DMA-Buf", &output.name);
|
||||||
|
capture = ScreenRenderer::new_wlr(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
if capture.is_none() {
|
||||||
|
info!("{}: Using Pipewire capture", &output.name);
|
||||||
|
let file_name = format!("{}.token", &output.name);
|
||||||
|
let full_path = Path::new(&session.config_path).join(file_name);
|
||||||
|
let token = std::fs::read_to_string(full_path).ok();
|
||||||
|
|
||||||
|
capture = ScreenRenderer::new_pw(
|
||||||
|
output,
|
||||||
|
token.as_deref(),
|
||||||
|
session.capture_method == "pw_fallback",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if let Some(capture) = capture {
|
||||||
|
let backend = Box::new(SplitOverlayBackend {
|
||||||
|
renderer: Box::new(capture),
|
||||||
|
interaction: Box::new(ScreenInteractionHandler::new(
|
||||||
|
vec2(output.logical_pos.0 as f32, output.logical_pos.1 as f32),
|
||||||
|
vec2(output.logical_size.0 as f32, output.logical_size.1 as f32),
|
||||||
|
output.transform,
|
||||||
|
)),
|
||||||
|
});
|
||||||
|
|
||||||
|
let axis = Vec3::new(0., 0., 1.);
|
||||||
|
|
||||||
|
let angle = match output.transform {
|
||||||
|
Transform::_90 | Transform::Flipped90 => PI / 2.,
|
||||||
|
Transform::_180 | Transform::Flipped180 => PI,
|
||||||
|
Transform::_270 | Transform::Flipped270 => -PI / 2.,
|
||||||
|
_ => 0.,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(OverlayData {
|
||||||
|
state: OverlayState {
|
||||||
|
name: output.name.clone(),
|
||||||
|
size,
|
||||||
|
want_visible: idx == 0,
|
||||||
|
show_hide: true,
|
||||||
|
grabbable: true,
|
||||||
|
spawn_rotation: Quat::from_axis_angle(axis, angle),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
backend,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
warn!("{}: Will not be used", &output.name);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_screens_wayland<O>(session: &AppSession) -> Vec<OverlayData<O>>
|
||||||
|
where
|
||||||
|
O: Default,
|
||||||
|
{
|
||||||
|
let mut overlays = vec![];
|
||||||
|
let wl = WlxClient::new().unwrap();
|
||||||
|
|
||||||
|
for idx in 0..wl.outputs.len() {
|
||||||
|
if let Some(overlay) = try_create_screen(&wl, idx, &session) {
|
||||||
|
overlays.push(overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
overlays
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_screens_x11<O>() -> Vec<OverlayData<O>>
|
||||||
|
where
|
||||||
|
O: Default,
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
use std::{sync::Arc, time::Instant};
|
use std::{sync::Arc, time::Instant};
|
||||||
|
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use glam::{Quat, Vec3};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
backend::{
|
||||||
|
common::{OverlaySelector, TaskType},
|
||||||
|
overlay::{OverlayData, OverlayState, RelativeTo},
|
||||||
|
},
|
||||||
gui::{color_parse, CanvasBuilder},
|
gui::{color_parse, CanvasBuilder},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{OverlayData, RelativeTo};
|
pub fn create_watch<O>(state: &AppState, screens: &[OverlayData<O>]) -> OverlayData<O>
|
||||||
|
where
|
||||||
pub const WATCH_DEFAULT_POS: Vec3 = Vec3::new(0., 0., 0.15);
|
O: Default,
|
||||||
pub const WATCH_DEFAULT_ROT: Quat = Quat::from_xyzw(0.7071066, 0., 0.7071066, 0.0007963);
|
{
|
||||||
|
|
||||||
pub fn create_watch(state: &AppState, screens: Vec<(usize, Arc<str>)>) -> OverlayData {
|
|
||||||
let mut canvas = CanvasBuilder::new(400, 200, state.graphics.clone(), state.format, ());
|
let mut canvas = CanvasBuilder::new(400, 200, state.graphics.clone(), state.format, ());
|
||||||
let empty_str: Arc<str> = Arc::from("");
|
let empty_str: Arc<str> = Arc::from("");
|
||||||
|
|
||||||
@@ -93,22 +94,19 @@ pub fn create_watch(state: &AppState, screens: Vec<(usize, Arc<str>)>) -> Overla
|
|||||||
.as_millis()
|
.as_millis()
|
||||||
< 2000
|
< 2000
|
||||||
{
|
{
|
||||||
app.tasks.push_back(Box::new(|_app, o| {
|
app.tasks.enqueue(TaskType::Overlay(
|
||||||
for overlay in o {
|
OverlaySelector::Name("Kbd".into()),
|
||||||
if &*overlay.name == "Kbd" {
|
Box::new(|_app, o| {
|
||||||
overlay.want_visible = !overlay.want_visible;
|
o.want_visible = !o.want_visible;
|
||||||
return;
|
}),
|
||||||
}
|
));
|
||||||
}
|
|
||||||
}));
|
|
||||||
} else {
|
} else {
|
||||||
app.tasks.push_back(Box::new(|app, o| {
|
app.tasks.enqueue(TaskType::Overlay(
|
||||||
for overlay in o {
|
OverlaySelector::Name("Kbd".into()),
|
||||||
if &*overlay.name == "Kbd" {
|
Box::new(|app, o| {
|
||||||
overlay.reset(app);
|
o.reset(app);
|
||||||
}
|
}),
|
||||||
}
|
));
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -116,11 +114,17 @@ pub fn create_watch(state: &AppState, screens: Vec<(usize, Arc<str>)>) -> Overla
|
|||||||
|
|
||||||
canvas.bg_color = color_parse("#405060");
|
canvas.bg_color = color_parse("#405060");
|
||||||
|
|
||||||
for (scr_idx, scr_name) in screens.into_iter() {
|
for screen in screens.into_iter() {
|
||||||
let button = canvas.button(button_x + 2., 162., button_width - 4., 36., scr_name);
|
let button = canvas.button(
|
||||||
|
button_x + 2.,
|
||||||
|
162.,
|
||||||
|
button_width - 4.,
|
||||||
|
36.,
|
||||||
|
screen.state.name.clone(),
|
||||||
|
);
|
||||||
button.state = Some(WatchButtonState {
|
button.state = Some(WatchButtonState {
|
||||||
pressed_at: Instant::now(),
|
pressed_at: Instant::now(),
|
||||||
scr_idx,
|
scr_idx: screen.state.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
button.on_press = Some(|control, _data, _app| {
|
button.on_press = Some(|control, _data, _app| {
|
||||||
@@ -136,13 +140,19 @@ pub fn create_watch(state: &AppState, screens: Vec<(usize, Arc<str>)>) -> Overla
|
|||||||
.as_millis()
|
.as_millis()
|
||||||
< 2000
|
< 2000
|
||||||
{
|
{
|
||||||
app.tasks.push_back(Box::new(move |_app, o| {
|
app.tasks.enqueue(TaskType::Overlay(
|
||||||
o[scr_idx].want_visible = !o[scr_idx].want_visible;
|
OverlaySelector::Id(scr_idx),
|
||||||
}));
|
Box::new(|_app, o| {
|
||||||
|
o.want_visible = !o.want_visible;
|
||||||
|
}),
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
app.tasks.push_back(Box::new(move |app, o| {
|
app.tasks.enqueue(TaskType::Overlay(
|
||||||
o[scr_idx].reset(app);
|
OverlaySelector::Id(scr_idx),
|
||||||
}));
|
Box::new(|app, o| {
|
||||||
|
o.reset(app);
|
||||||
|
}),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -152,14 +162,17 @@ pub fn create_watch(state: &AppState, screens: Vec<(usize, Arc<str>)>) -> Overla
|
|||||||
let relative_to = RelativeTo::Hand(state.session.watch_hand);
|
let relative_to = RelativeTo::Hand(state.session.watch_hand);
|
||||||
|
|
||||||
OverlayData {
|
OverlayData {
|
||||||
name: "Watch".into(),
|
state: OverlayState {
|
||||||
size: (400, 200),
|
name: "Watch".into(),
|
||||||
width: 0.065,
|
size: (400, 200),
|
||||||
|
width: 0.065,
|
||||||
|
want_visible: true,
|
||||||
|
spawn_point: state.session.watch_pos.into(),
|
||||||
|
spawn_rotation: state.session.watch_rot,
|
||||||
|
relative_to,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
backend: Box::new(canvas.build()),
|
backend: Box::new(canvas.build()),
|
||||||
want_visible: true,
|
|
||||||
relative_to,
|
|
||||||
spawn_point: state.session.watch_pos,
|
|
||||||
spawn_rotation: state.session.watch_rot,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
64
src/ovr.rs
64
src/ovr.rs
@@ -1,64 +0,0 @@
|
|||||||
use std::{path::Path, sync::Arc};
|
|
||||||
|
|
||||||
use vulkano::{
|
|
||||||
image::{
|
|
||||||
sys::{Image, RawImage},
|
|
||||||
ImageViewAbstract,
|
|
||||||
},
|
|
||||||
Handle, VulkanObject,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::graphics::WlxGraphics;
|
|
||||||
|
|
||||||
pub struct OpenVrState {
|
|
||||||
pub context: ovr_overlay::Context,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct OvrTextureData {
|
|
||||||
image_handle: u64,
|
|
||||||
device: u64,
|
|
||||||
physical: u64,
|
|
||||||
instance: u64,
|
|
||||||
queue: u64,
|
|
||||||
queue_family_index: u32,
|
|
||||||
width: u32,
|
|
||||||
height: u32,
|
|
||||||
format: u32,
|
|
||||||
sample_count: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OvrTextureData {
|
|
||||||
pub fn new(graphics: Arc<WlxGraphics>, view: Arc<dyn ImageViewAbstract>) -> OvrTextureData {
|
|
||||||
let image = view.image();
|
|
||||||
|
|
||||||
let device = graphics.device.handle().as_raw();
|
|
||||||
let physical = graphics.device.physical_device().handle().as_raw();
|
|
||||||
let instance = graphics.instance.handle().as_raw();
|
|
||||||
let queue = graphics.queue.handle().as_raw();
|
|
||||||
let queue_family_index = graphics.queue.queue_family_index();
|
|
||||||
|
|
||||||
let (width, height) = {
|
|
||||||
let dim = image.dimensions();
|
|
||||||
(dim.width() as u32, dim.height() as u32)
|
|
||||||
};
|
|
||||||
|
|
||||||
let sample_count = image.samples() as u32;
|
|
||||||
let format = image.format() as u32;
|
|
||||||
|
|
||||||
let image_handle = image.inner().image.handle().as_raw();
|
|
||||||
|
|
||||||
OvrTextureData {
|
|
||||||
image_handle,
|
|
||||||
device,
|
|
||||||
physical,
|
|
||||||
instance,
|
|
||||||
queue,
|
|
||||||
queue_family_index,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
format,
|
|
||||||
sample_count,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"action_manifest_version" : 0,
|
"action_manifest_version" : 0,
|
||||||
"app_key" : "galister.wlxoverlay",
|
"app_key" : "galister.wlxoverlay-s",
|
||||||
"bindings" : {
|
"bindings" : {
|
||||||
"/actions/default" : {
|
"/actions/default" : {
|
||||||
"haptics" : [
|
"haptics" : [
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"action_manifest_version" : 0,
|
"action_manifest_version" : 0,
|
||||||
"app_key" : "galister.wlxoverlay",
|
"app_key" : "galister.wlxoverlay-s",
|
||||||
"bindings" : {
|
"bindings" : {
|
||||||
"/actions/default" : {
|
"/actions/default" : {
|
||||||
"haptics" : [
|
"haptics" : [
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"action_manifest_version" : 0,
|
"action_manifest_version" : 0,
|
||||||
"app_key" : "galister.wlxoverlay",
|
"app_key" : "galister.wlxoverlay-s",
|
||||||
"bindings" : {
|
"bindings" : {
|
||||||
"/actions/default": {
|
"/actions/default": {
|
||||||
"haptics" : [
|
"haptics" : [
|
||||||
|
|||||||
35
src/state.rs
35
src/state.rs
@@ -1,27 +1,50 @@
|
|||||||
use std::{collections::VecDeque, env::VarError, path::Path, sync::Arc};
|
use std::{env::VarError, path::Path, sync::Arc};
|
||||||
|
|
||||||
use glam::{Quat, Vec3};
|
use glam::{Quat, Vec3};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
use vulkano::{
|
||||||
|
device::{physical::PhysicalDevice, DeviceExtensions},
|
||||||
|
format::Format,
|
||||||
|
instance::InstanceExtensions,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
graphics::WlxGraphics, gui::font::FontCache, input::InputProvider, overlays::OverlayData,
|
backend::common::TaskContainer, graphics::WlxGraphics, gui::font::FontCache,
|
||||||
|
input::InputProvider,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const WATCH_DEFAULT_POS: Vec3 = Vec3::new(0., 0., 0.15);
|
pub const WATCH_DEFAULT_POS: Vec3 = Vec3::new(0., 0., 0.15);
|
||||||
pub const WATCH_DEFAULT_ROT: Quat = Quat::from_xyzw(0.7071066, 0., 0.7071066, 0.0007963);
|
pub const WATCH_DEFAULT_ROT: Quat = Quat::from_xyzw(0.7071066, 0., 0.7071066, 0.0007963);
|
||||||
|
|
||||||
pub type Task = Box<dyn FnOnce(&mut AppState, &mut [OverlayData]) + Send>;
|
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub fc: FontCache,
|
pub fc: FontCache,
|
||||||
//pub input: InputState,
|
//pub input: InputState,
|
||||||
pub session: AppSession,
|
pub session: AppSession,
|
||||||
pub tasks: VecDeque<Task>,
|
pub tasks: TaskContainer,
|
||||||
pub graphics: Arc<WlxGraphics>,
|
pub graphics: Arc<WlxGraphics>,
|
||||||
pub format: vulkano::format::Format,
|
pub format: vulkano::format::Format,
|
||||||
pub input: Box<dyn InputProvider>,
|
pub input: Box<dyn InputProvider>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AppState {
|
||||||
|
pub fn new(
|
||||||
|
vk_instance_extensions: InstanceExtensions,
|
||||||
|
vk_device_extensions_fn: impl FnMut(&PhysicalDevice) -> DeviceExtensions,
|
||||||
|
) -> Self {
|
||||||
|
let (graphics, _event_loop) =
|
||||||
|
WlxGraphics::new(vk_instance_extensions, vk_device_extensions_fn);
|
||||||
|
|
||||||
|
AppState {
|
||||||
|
fc: FontCache::new(),
|
||||||
|
session: AppSession::load(),
|
||||||
|
tasks: TaskContainer::new(),
|
||||||
|
graphics: graphics.clone(),
|
||||||
|
format: Format::R8G8B8A8_UNORM,
|
||||||
|
input: crate::input::initialize_input(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct AppSession {
|
pub struct AppSession {
|
||||||
pub config_path: String,
|
pub config_path: String,
|
||||||
|
|
||||||
@@ -50,7 +73,7 @@ pub struct AppSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AppSession {
|
impl AppSession {
|
||||||
pub fn load() -> AppSession {
|
pub fn load() -> Self {
|
||||||
let config_path = std::env::var("XDG_CONFIG_HOME")
|
let config_path = std::env::var("XDG_CONFIG_HOME")
|
||||||
.or_else(|_| std::env::var("HOME").map(|home| format!("{}/.config", home)))
|
.or_else(|_| std::env::var("HOME").map(|home| format!("{}/.config", home)))
|
||||||
.or_else(|_| {
|
.or_else(|_| {
|
||||||
|
|||||||
Reference in New Issue
Block a user