From 8eec38e55c9945641251a0ead7d321a56e3acf56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Bousqui=C3=A9?= Date: Wed, 16 Sep 2026 14:17:11 +0200 Subject: [PATCH] fix(lib): migrate to winit 0.30 ApplicationHandler model winit 0.30.13 removed WindowBuilder and deprecated EventLoop::run. Move window/GPU creation into ApplicationHandler::resumed, expose AppHandler::setup hook, switch App::run to run_app, and migrate both examples. pollster becomes a regular dependency (used by app.rs). --- Cargo.lock | 591 ++++++++++++++++++++++++----------------- lib/Cargo.toml | 6 +- lib/examples/manual.rs | 227 ++++++++++------ lib/examples/simple.rs | 108 ++++---- lib/src/app.rs | 267 ++++++++++++++----- lib/src/handler.rs | 6 + 6 files changed, 748 insertions(+), 457 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 220a8f4..bef01b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,23 +39,21 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android-activity" -version = "0.5.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" dependencies = [ "android-properties", "bitflags 2.13.0", "cc", - "cesu8", "jni", - "jni-sys 0.3.1", "libc", "log", "ndk", "ndk-context", - "ndk-sys 0.5.0+25.2.9519653", + "ndk-sys", "num_enum", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -139,23 +137,13 @@ version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" -[[package]] -name = "block-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" -dependencies = [ - "objc-sys", -] - [[package]] name = "block2" -version = "0.3.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "block-sys", - "objc2 0.4.1", + "objc2 0.5.2", ] [[package]] @@ -201,9 +189,9 @@ checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" [[package]] name = "calloop" -version = "0.12.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ "bitflags 2.13.0", "log", @@ -215,9 +203,9 @@ dependencies = [ [[package]] name = "calloop-wayland-source" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" dependencies = [ "calloop", "rustix 0.38.44", @@ -237,24 +225,12 @@ dependencies = [ "shlex", ] -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - [[package]] name = "cfg_aliases" version = "0.2.1" @@ -389,6 +365,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" + [[package]] name = "equivalent" version = "1.0.2" @@ -580,17 +562,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" -[[package]] -name = "icrate" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" -dependencies = [ - "block2 0.3.0", - "dispatch", - "objc2 0.4.1", -] - [[package]] name = "indexmap" version = "2.14.0" @@ -603,18 +574,32 @@ dependencies = [ [[package]] name = "jni" -version = "0.21.1" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" dependencies = [ - "cesu8", "cfg-if", "combine", - "jni-sys 0.3.1", + "jni-macros", + "jni-sys 0.4.1", "log", - "thiserror 1.0.69", + "simd_cesu8", + "thiserror 2.0.18", "walkdir", - "windows-sys 0.45.0", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn", ] [[package]] @@ -775,7 +760,7 @@ dependencies = [ "bit-set", "bitflags 2.13.0", "cfg-if", - "cfg_aliases 0.2.1", + "cfg_aliases", "codespan-reporting", "half", "hashbrown 0.17.1", @@ -805,14 +790,14 @@ dependencies = [ [[package]] name = "ndk" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ "bitflags 2.13.0", "jni-sys 0.3.1", "log", - "ndk-sys 0.5.0+25.2.9519653", + "ndk-sys", "num_enum", "raw-window-handle", "thiserror 1.0.69", @@ -824,15 +809,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" -[[package]] -name = "ndk-sys" -version = "0.5.0+25.2.9519653" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" -dependencies = [ - "jni-sys 0.3.1", -] - [[package]] name = "ndk-sys" version = "0.6.0+11769913" @@ -882,12 +858,12 @@ checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" [[package]] name = "objc2" -version = "0.4.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" dependencies = [ "objc-sys", - "objc2-encode 3.0.0", + "objc2-encode", ] [[package]] @@ -896,7 +872,59 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" dependencies = [ - "objc2-encode 4.1.0", + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.13.0", + "block2 0.5.1", + "libc", + "objc2 0.5.2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation 0.2.2", + "objc2-quartz-core 0.2.2", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -923,10 +951,28 @@ dependencies = [ ] [[package]] -name = "objc2-encode" -version = "3.0.0" +name = "objc2-core-image" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal 0.2.2", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-contacts", + "objc2-foundation 0.2.2", +] [[package]] name = "objc2-encode" @@ -934,6 +980,19 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.13.0", + "block2 0.5.1", + "dispatch", + "libc", + "objc2 0.5.2", +] + [[package]] name = "objc2-foundation" version = "0.3.2" @@ -956,6 +1015,30 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-app-kit", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + [[package]] name = "objc2-metal" version = "0.3.2" @@ -965,7 +1048,20 @@ dependencies = [ "bitflags 2.13.0", "block2 0.6.2", "objc2 0.6.4", - "objc2-foundation", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal 0.2.2", ] [[package]] @@ -978,8 +1074,63 @@ dependencies = [ "objc2 0.6.4", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation", - "objc2-metal", + "objc2-foundation 0.3.2", + "objc2-metal 0.3.2", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation 0.2.2", + "objc2-link-presentation", + "objc2-quartz-core 0.2.2", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation 0.2.2", ] [[package]] @@ -1045,6 +1196,26 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -1079,18 +1250,18 @@ dependencies = [ [[package]] name = "pollster" -version = "0.4.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" +checksum = "bc6355899e1c9462875b6757c79f3caa011a1fdae12bbb1a2e72dd1f234f8336" dependencies = [ "pollster-macro", ] [[package]] name = "pollster-macro" -version = "0.4.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac5da421106a50887c5b51d20806867db377fbb86bacf478ee0500a912e0c113" +checksum = "79af046f3496a2db85e4c2fb04f2e9ff77e6b82f29bd43012b398290ce2c811c" dependencies = [ "proc-macro2", "quote", @@ -1186,15 +1357,15 @@ checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" dependencies = [ "objc2 0.6.4", "objc2-core-foundation", - "objc2-foundation", - "objc2-quartz-core", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] @@ -1229,6 +1400,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.44" @@ -1284,9 +1464,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sctk-adwaita" -version = "0.8.3" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70b31447ca297092c5a9916fc3b955203157b37c19ca8edde4f52e9843e602c7" +checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" dependencies = [ "ab_glyph", "log", @@ -1295,6 +1475,12 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.228" @@ -1331,6 +1517,22 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "slab" version = "0.4.12" @@ -1354,9 +1556,9 @@ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "smithay-client-toolkit" -version = "0.18.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ "bitflags 2.13.0", "calloop", @@ -1522,6 +1724,22 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" + [[package]] name = "ttf-parser" version = "0.25.1" @@ -1676,9 +1894,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.31.2" +version = "0.32.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" +checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" dependencies = [ "bitflags 2.13.0", "wayland-backend", @@ -1688,9 +1906,9 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.2.0" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" +checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" dependencies = [ "bitflags 2.13.0", "wayland-backend", @@ -1701,9 +1919,9 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.2.0" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" +checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ "bitflags 2.13.0", "wayland-backend", @@ -1747,9 +1965,9 @@ dependencies = [ [[package]] name = "web-time" -version = "0.2.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -1765,7 +1983,7 @@ dependencies = [ "bitflags 2.13.0", "bytemuck", "cfg-if", - "cfg_aliases 0.2.1", + "cfg_aliases", "document-features", "hashbrown 0.17.1", "js-sys", @@ -1796,7 +2014,7 @@ dependencies = [ "bit-vec", "bitflags 2.13.0", "bytemuck", - "cfg_aliases 0.2.1", + "cfg_aliases", "document-features", "hashbrown 0.17.1", "indexmap", @@ -1860,7 +2078,7 @@ dependencies = [ "block2 0.6.2", "bytemuck", "cfg-if", - "cfg_aliases 0.2.1", + "cfg_aliases", "glow", "glutin_wgl_sys", "gpu-allocator", @@ -1872,13 +2090,13 @@ dependencies = [ "log", "naga", "naga-types", - "ndk-sys 0.6.0+11769913", + "ndk-sys", "objc2 0.6.4", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation", - "objc2-metal", - "objc2-quartz-core", + "objc2-foundation 0.3.2", + "objc2-metal 0.3.2", + "objc2-quartz-core 0.3.2", "once_cell", "ordered-float", "parking_lot", @@ -2040,20 +2258,11 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -2062,7 +2271,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2074,50 +2283,20 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -2129,54 +2308,18 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -2189,72 +2332,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -2263,37 +2358,41 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.29.15" +version = "0.30.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" +checksum = "a6755fa58a9f8350bd1e472d4c3fcc25f824ec358933bba33306d0b63df5978d" dependencies = [ "ahash", "android-activity", "atomic-waker", "bitflags 2.13.0", + "block2 0.5.1", "bytemuck", "calloop", - "cfg_aliases 0.1.1", + "cfg_aliases", + "concurrent-queue", "core-foundation", "core-graphics", "cursor-icon", - "icrate", + "dpi", "js-sys", "libc", - "log", "memmap2", "ndk", - "ndk-sys 0.5.0+25.2.9519653", - "objc2 0.4.1", - "once_cell", + "objc2 0.5.2", + "objc2-app-kit", + "objc2-foundation 0.2.2", + "objc2-ui-kit", "orbclient", "percent-encoding", + "pin-project", "raw-window-handle", - "redox_syscall 0.3.5", + "redox_syscall 0.4.1", "rustix 0.38.44", "sctk-adwaita", "smithay-client-toolkit", "smol_str", + "tracing", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", @@ -2303,7 +2402,7 @@ dependencies = [ "wayland-protocols-plasma", "web-sys", "web-time", - "windows-sys 0.48.0", + "windows-sys 0.52.0", "x11-dl", "x11rb", "xkbcommon-dl", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 333d1fe..e66130c 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -8,10 +8,8 @@ path = "src/lib.rs" [dependencies] wgpu = "30.0.0" # Vérifiez la version la plus récente -winit = "0.29" # For window management — pinned to match examples +winit = "0.30.13" # For window management — pinned to match examples thiserror = "2" bytemuck = { version = "1.25.0", features = ["derive"] } glam = "0.33" - -[dev-dependencies] -pollster = { version="0.4.0", features = ["macro"] } +pollster = { version="1.0.1", features = ["macro"] } diff --git a/lib/examples/manual.rs b/lib/examples/manual.rs index 98cb251..461e1cc 100644 --- a/lib/examples/manual.rs +++ b/lib/examples/manual.rs @@ -1,6 +1,13 @@ +//! Workflow bas-niveau : utilisation directe du `Context`, `Renderer`, `PipelineCache`, `Mesh` et +//! `Material`, contournant la façade `App`. Rendu d'un quad plat éclairé via la boucle winit 0.30 +//! (`EventLoop::run_app` + `ApplicationHandler`). La fenêtre et le GPU sont créés dans `resumed()`, +//! comme l'exigent winit 0.30 et la migration faite dans `app.rs`. use std::sync::Arc; -use winit::event_loop::EventLoop; -use winit::window::WindowBuilder; +use winit::application::ApplicationHandler; +use winit::dpi::LogicalSize; +use winit::event::WindowEvent; +use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop}; +use winit::window::{Window, WindowAttributes}; use wsg_lib::core::Context; use wsg_lib::core::Frame; use wsg_lib::core::Renderer; @@ -10,92 +17,144 @@ use wsg_lib::resources::Mesh; use wsg_lib::resources::Vertex; use wsg_lib::utils; +/// Application bas-niveau : détient les objets GPU + window, tous créés dans `resumed`. +struct App { + /// Fenêtre système, partagée via Arc (comme dans app.rs). + window: Option>, + /// Contexte GPU (Instance, Surface, Adapter, Device, Queue). + context: Option, + /// Couche d'exécution qui soumet les draw calls. + renderer: Option, + /// Cache de shaders/pipelines. + cache: Option, + /// Matériau (pipeline) du quad. + material: Option, + /// Mesh du quad (sommets + indices). + mesh: Option, +} + +impl ApplicationHandler for App { + /// Crée la fenêtre puis le GPU, et construit le mesh/matériau. Exécuté une fois au démarrage. + /// Redondant `resumed` pour créer à nouveau ? double protection par `self.context.is_some()`. + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + if self.context.is_some() { + return; + } + event_loop.set_control_flow(ControlFlow::Poll); + + let attrs = WindowAttributes::default() + .with_title("WSG Manual") + .with_inner_size(LogicalSize::new(800.0, 600.0)); + let window = Arc::new(event_loop.create_window(attrs).unwrap()); + + // 1. Initialisation + let context = pollster::block_on(Context::new(window.clone())).expect("Échec init GPU"); + + // Configuration de la surface et récupération du format + let format = context + .configure(&context.adapter, 800, 600) + .expect("Échec configuration"); + + // 2. Initialisation du Renderer (Il récupère tout ce dont il a besoin) + let device = Arc::new(context.device.clone()); + let mut cache = PipelineCache::new(device); + cache + .register_shader("basic", utils::BASIC_SHADER_PATH) + .unwrap(); + + let renderer = Renderer::new(&context, format); + + // 3. Material : On utilise renderer.device() et renderer.format() + let material = Material::new(renderer.format(), "basic", &mut cache); + + // Mesh : On utilise le device du renderer + let vertices = [ + // Position (x,y,z) | Normale (x,y,z) | UV (u,v) | Couleur (r,g,b,a) + Vertex { + position: [-0.5, 0.5, 0.0], + normal: [0.0, 0.0, 1.0], + uv: [0.0, 0.0], + color: [1.0, 0.0, 0.0, 1.0], + }, // Haut-Gauche (Rouge) + Vertex { + position: [0.5, 0.5, 0.0], + normal: [0.0, 0.0, 1.0], + uv: [1.0, 0.0], + color: [0.0, 1.0, 0.0, 1.0], + }, // Haut-Droite (Vert) + Vertex { + position: [0.5, -0.5, 0.0], + normal: [0.0, 0.0, 1.0], + uv: [1.0, 1.0], + color: [0.0, 0.0, 1.0, 1.0], + }, // Bas-Droite (Bleu) + Vertex { + position: [-0.5, -0.5, 0.0], + normal: [0.0, 0.0, 1.0], + uv: [0.0, 1.0], + color: [1.0, 1.0, 0.0, 1.0], + }, // Bas-Gauche (Jaune) + ]; + let indices: [u16; 6] = [0, 1, 2, 0, 2, 3]; + let mesh = Mesh::new(renderer.device(), &vertices, Some(&indices)); + + self.window = Some(window); + self.context = Some(context); + self.renderer = Some(renderer); + self.cache = Some(cache); + self.material = Some(material); + self.mesh = Some(mesh); + } + + /// À chaque frame, demande un redessin pour un rendu continu (animation). + fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { + if let Some(window) = &self.window { + window.request_redraw(); + } + } + + /// Dispatch des événements de fenêtre : RedrawRequested rend puis présente, CloseRequested quitte. + fn window_event( + &mut self, + event_loop: &ActiveEventLoop, + _window_id: winit::window::WindowId, + event: WindowEvent, + ) { + match event { + winit::event::WindowEvent::RedrawRequested => { + if let (Some(context), Some(renderer), Some(mesh), Some(material)) = + (&self.context, &self.renderer, &self.mesh, &self.material) + { + if let Some(frame) = Frame::try_new(&context.surface) { + // 1. Rendu (plus d'arguments device/queue inutiles) + renderer.render(frame.view(), mesh, material); + + // 2. Présentation + renderer.present(frame); + } + } + } + winit::event::WindowEvent::CloseRequested => { + event_loop.exit(); // C'est ici que tu demandes à la boucle de s'arrêter + } + _ => (), + } + } +} + fn main() { println!( "Répertoire courant : {:?}", std::env::current_dir().unwrap() ); let event_loop = EventLoop::new().unwrap(); - let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap()); - - // 1. Initialisation - let context = pollster::block_on(Context::new(window.clone())).expect("Échec init GPU"); - - // Configuration de la surface et récupération du format - let format = context - .configure(&context.adapter, 800, 600) - .expect("Échec configuration"); - - // 2. Initialisation du Renderer (Il récupère tout ce dont il a besoin) - let device = Arc::new(context.device.clone()); - let mut cache = PipelineCache::new(device); - cache - .register_shader("basic", utils::BASIC_SHADER_PATH) - .unwrap(); - - let renderer = Renderer::new(&context, format); - - // 3. Material : On utilise renderer.device() et renderer.format() - let material = Material::new(renderer.format(), "basic", &mut cache); - - // Mesh : On utilise le device du renderer - let vertices = [ - // Position (x,y,z) | Normale (x,y,z) | UV (u,v) | Couleur (r,g,b,a) - Vertex { - position: [-0.5, 0.5, 0.0], - normal: [0.0, 0.0, 1.0], - uv: [0.0, 0.0], - color: [1.0, 0.0, 0.0, 1.0], - }, // Haut-Gauche (Rouge) - Vertex { - position: [0.5, 0.5, 0.0], - normal: [0.0, 0.0, 1.0], - uv: [1.0, 0.0], - color: [0.0, 1.0, 0.0, 1.0], - }, // Haut-Droite (Vert) - Vertex { - position: [0.5, -0.5, 0.0], - normal: [0.0, 0.0, 1.0], - uv: [1.0, 1.0], - color: [0.0, 0.0, 1.0, 1.0], - }, // Bas-Droite (Bleu) - Vertex { - position: [-0.5, -0.5, 0.0], - normal: [0.0, 0.0, 1.0], - uv: [0.0, 1.0], - color: [1.0, 1.0, 0.0, 1.0], - }, // Bas-Gauche (Jaune) - ]; - let indices: [u16; 6] = [0, 1, 2, 0, 2, 3]; - let mesh = Mesh::new(renderer.device(), &vertices, Some(&indices)); - - // Render loop - event_loop - .run(|event, elwt| { - match event { - winit::event::Event::AboutToWait => { - window.request_redraw(); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::RedrawRequested, - .. - } => { - if let Some(frame) = Frame::try_new(&context.surface) { - // 1. Rendu (plus d'arguments device/queue inutiles) - renderer.render(frame.view(), &mesh, &material); - - // 2. Présentation - renderer.present(frame); - } - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::CloseRequested, - .. - } => { - elwt.exit(); // C'est ici que tu demandes à la boucle de s'arrêter - } - _ => (), - } - }) - .unwrap(); + let mut app = App { + window: None, + context: None, + renderer: None, + cache: None, + material: None, + mesh: None, + }; + event_loop.run_app(&mut app).unwrap(); } diff --git a/lib/examples/simple.rs b/lib/examples/simple.rs index 0da983b..55cebfe 100644 --- a/lib/examples/simple.rs +++ b/lib/examples/simple.rs @@ -1,8 +1,9 @@ //! Workflow déclaratif minimal, sans manipulation WGPU explicite dans ce fichier. -//! `AppBuilder` ouvre la fenêtre, construit le `Context`/`Renderer` et fait tourner la boucle -//! update → render → present. La scène se rend automatiquement : la méthode `render()` par défaut -//! du trait `AppHandler` appelle `app.render_scene(frame.view())`, donc l'utilisateur n'implémente -//! même pas `render` ici — il ne fait que remplir `app.scene` avec un mesh, un matériau et une entité. +//! `AppBuilder` crée l'event loop puis `App::run` ouvre la fenêtre, construit le `Context`/`Renderer` +//! et fait tourner la boucle update → render → present. Depuis la migration winit 0.30, le GPU n'existe +//! qu'après `resumed` : c'est pourquoi l'enregistrement shader + la création mesh/matériau/entité vivent +//! dans le hook `AppHandler::setup`, appelé une fois le contexte prêt. La scène se rend automatiquement : +//! la méthode `render()` par défaut appelle `app.render_scene(frame.view())`. use std::sync::Arc; use wsg_lib::AppHandler; use wsg_lib::app::AppBuilder; @@ -11,56 +12,59 @@ use wsg_lib::utils::WsgError; struct MonQuad; -impl AppHandler for MonQuad {} +impl AppHandler for MonQuad { + fn setup(&mut self, app: &mut wsg_lib::App) { + let format = app.renderer().format(); + + // Enregistrement du shader, création du matériau et du mesh du quad (sans importer wgpu). + app.cache() + .register_shader("basic", wsg_lib::utils::BASIC_SHADER_PATH) + .unwrap(); + let vertices = [ + Vertex { + position: [-0.5, 0.5, 0.0], + normal: [0.0, 0.0, 1.0], + uv: [0.0, 0.0], + color: [1.0, 0.0, 0.0, 1.0], + }, // Haut-Gauche (Rouge) + Vertex { + position: [0.5, 0.5, 0.0], + normal: [0.0, 0.0, 1.0], + uv: [1.0, 0.0], + color: [0.0, 1.0, 0.0, 1.0], + }, // Haut-Droite (Vert) + Vertex { + position: [0.5, -0.5, 0.0], + normal: [0.0, 0.0, 1.0], + uv: [1.0, 1.0], + color: [0.0, 0.0, 1.0, 1.0], + }, // Bas-Droite (Bleu) + Vertex { + position: [-0.5, -0.5, 0.0], + normal: [0.0, 0.0, 1.0], + uv: [0.0, 1.0], + color: [1.0, 1.0, 0.0, 1.0], + }, // Bas-Gauche (Jaune) + ]; + let indices: [u16; 6] = [0, 1, 2, 0, 2, 3]; + + let mesh = Arc::new(Mesh::new( + app.renderer().device(), + &vertices, + Some(&indices), + )); + let material = Arc::new(Material::new(format, "basic", app.cache())); + + app.scene.add_mesh("quad_mesh", mesh).unwrap(); + app.scene.add_material("basic_material", material).unwrap(); + app.scene + .add_entity("quad", "quad_mesh", "basic_material") + .unwrap(); + } +} #[pollster::main] async fn main() -> Result<(), WsgError> { - let mut app = AppBuilder::new().title("WSG Simple").build().await?; - - // Enregistrement du shader, création du matériau et du mesh du quad (sans importer wgpu). - app.cache - .register_shader("basic", wsg_lib::utils::BASIC_SHADER_PATH) - .unwrap(); - let vertices = [ - Vertex { - position: [-0.5, 0.5, 0.0], - normal: [0.0, 0.0, 1.0], - uv: [0.0, 0.0], - color: [1.0, 0.0, 0.0, 1.0], - }, // Haut-Gauche (Rouge) - Vertex { - position: [0.5, 0.5, 0.0], - normal: [0.0, 0.0, 1.0], - uv: [1.0, 0.0], - color: [0.0, 1.0, 0.0, 1.0], - }, // Haut-Droite (Vert) - Vertex { - position: [0.5, -0.5, 0.0], - normal: [0.0, 0.0, 1.0], - uv: [1.0, 1.0], - color: [0.0, 0.0, 1.0, 1.0], - }, // Bas-Droite (Bleu) - Vertex { - position: [-0.5, -0.5, 0.0], - normal: [0.0, 0.0, 1.0], - uv: [0.0, 1.0], - color: [1.0, 1.0, 0.0, 1.0], - }, // Bas-Gauche (Jaune) - ]; - let indices: [u16; 6] = [0, 1, 2, 0, 2, 3]; - - let mesh = Arc::new(Mesh::new(app.renderer.device(), &vertices, Some(&indices))); - let material = Arc::new(Material::new( - app.renderer.format(), - "basic", - &mut app.cache, - )); - - app.scene.add_mesh("quad_mesh", mesh).unwrap(); - app.scene.add_material("basic_material", material).unwrap(); - app.scene - .add_entity("quad", "quad_mesh", "basic_material") - .unwrap(); - + let app = AppBuilder::new().title("WSG Simple").build().await?; app.run(MonQuad) } diff --git a/lib/src/app.rs b/lib/src/app.rs index dbd8cc5..34caae2 100644 --- a/lib/src/app.rs +++ b/lib/src/app.rs @@ -12,6 +12,14 @@ //! - **scene::scene**: Exposes Scene as mutable field so users can register resources and entities. //! - **utils::conf**: Provides default window title, dimensions, and embedded WGSL source. //! - **handler**: Defines the AppHandler trait that users implement for custom logic. +//! +//! ## Architecture Note (winit 0.30) +//! winit 0.30 removed the synchronous window-creation API (`WindowBuilder`) and the closure-based +//! `EventLoop::run`, replacing them with the [`ApplicationHandler`] model driven by `EventLoop::run_app`. +//! Windows can only be created inside `ApplicationHandler::resumed()`. Consequently this module builds +//! the window and GPU context lazily inside `AppRunner`'s `resumed()` callback, and exposes the +//! user-facing `AppBuilder::build → App::run` flow over that model. `AppHandler::setup()` is invoked +//! once right after GPU initialization so users can register shaders/meshes/materials/entities. use crate::AppHandler; use crate::core::{Context, Renderer}; @@ -20,68 +28,96 @@ use crate::scene::Scene; use crate::utils::WsgError; use crate::utils::conf::{APP_DEFAULT_HEIGHT, APP_DEFAULT_TITLE, APP_DEFAULT_WIDTH}; use std::sync::Arc; -use winit::event_loop::EventLoop; -use winit::window::Window; +use winit::application::ApplicationHandler; +use winit::dpi::LogicalSize; +use winit::event::WindowEvent; +use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop}; +use winit::window::{Window, WindowAttributes}; /// High-level application facade that orchestrates window lifecycle, event loop, and rendering automation. /// Encapsulates all five WGPU objects (Instance, Surface, Adapter, Device, Queue) plus the render loop. /// Users create an App via AppBuilder, then run it with their implementation of AppHandler. +/// +/// The GPU-facing fields (`context`, `renderer`, `window`, `cache`) are created lazily when the +/// application is resumed (see `AppRunner`); they are only populated after `App::run` has started. +/// Access them through the `context()`, `renderer()`, `window()` and `cache()` accessors, which is +/// guaranteed to work inside `AppHandler::setup`, `update` and `render`. pub struct App { - /// GPU hardware context — owns Instance, Surface, Adapter, Device, Queue lifecycle. - pub context: Context, - /// Executor layer — binds Materials and Meshes into RenderPasses during draw calls. - pub renderer: Renderer, - /// Winit event loop for window management. Set to None after run() consumes it. - pub event_loop: Option>, // On met en Option pour pouvoir faire .take() facilement - /// Shader compilation cache — manages RenderPipelines keyed by shader_id. - pub cache: PipelineCache, - /// Resource depot and entity graph — users register Meshes/Materials here before the render loop begins. + /// Resource depot and entity graph — users register Meshes/Materials here during `AppHandler::setup`. pub scene: Scene, + /// Window title, read by the runner when the window is created in `resumed`. + pub(crate) title: String, + /// Window width, read by the runner when the window is created in `resumed`. + pub(crate) width: u32, + /// Window height, read by the runner when the window is created in `resumed`. + pub(crate) height: u32, + /// Winit event loop for window management. Set to None after run() consumes it. + event_loop: Option>, // On met en Option pour pouvoir faire .take() facilement + /// GPU hardware context — owns Instance, Surface, Adapter, Device, Queue lifecycle. + context: Option, + /// Executor layer — binds Materials and Meshes into RenderPasses during draw calls. + renderer: Option, /// The OS-level window backing this application. Shared via Arc for multi-owner access. - pub window: Arc, + window: Option>, + /// Shader compilation cache — manages RenderPipelines keyed by shader_id. + cache: Option, } impl App { + /// Returns a reference to the GPU renderer. + /// Panics if called before `App::run` has created the renderer (i.e. before `resumed` fires). + pub fn renderer(&self) -> &Renderer { + self.renderer + .as_ref() + .expect("renderer not initialized yet — call app.run(handler) first") + } + + /// Returns a reference to the GPU hardware context. + /// Panics if called before `App::run` has created the context (i.e. before `resumed` fires). + pub fn context(&self) -> &Context { + self.context + .as_ref() + .expect("context not initialized yet — call app.run(handler) first") + } + + /// Returns a mutable reference to the shader compilation cache. + /// Panics if called before `App::run` has created the cache (i.e. before `resumed` fires). + pub fn cache(&mut self) -> &mut PipelineCache { + self.cache + .as_mut() + .expect("cache not initialized yet — call app.run(handler) first") + } + + /// Returns a reference to the window backing this application. + /// Panics if called before `App::run` has created the window (i.e. before `resumed` fires). + pub fn window(&self) -> &Window { + self.window + .as_ref() + .expect("window not initialized yet — call app.run(handler) first") + .as_ref() + } + /// Runs the application's main loop: processes events, updates logic per frame, renders, and presents. /// Inputs: handler — user-provided AppHandler implementation containing game logic. /// Returns Ok(()) on success or Err(WsgError::WindowSystem) if the event loop exits abnormally. /// Called once at application entry point; runs until the window is closed or an error occurs. - /// Internal steps: 1) take EventLoop from Option → 2) enter winit event loop → - /// 3a) on AboutToWait: call handler.update() + request_redraw → - /// 3b) on RedrawRequested: acquire frame → call handler.render() → present frame → - /// 3c) on CloseRequested: exit event loop. - pub fn run(mut self, mut handler: H) -> Result<(), WsgError> { + /// Internal steps: 1) take EventLoop from Option → 2) build an `AppRunner` around the handler → + /// 3) on resumed: create window/context/renderer/cache and call handler.setup() → + /// 4) on about_to_wait: call handler.update() + request_redraw → + /// 5) on RedrawRequested: acquire frame → call handler.render() → present frame → + /// 6) on CloseRequested: exit the event loop. + pub fn run(mut self, handler: H) -> Result<(), WsgError> { // On extrait l'event_loop de manière sûre grâce au Option let event_loop = self.event_loop.take().ok_or(WsgError::WindowSystem)?; // Erreur si déjà pris + let mut runner = AppRunner { + title: self.title.clone(), + width: self.width, + height: self.height, + handler, + app: None, + }; event_loop - .run(move |event, elwt| { - match event { - winit::event::Event::AboutToWait => { - // update logic - handler.update(&mut self); - self.window.request_redraw(); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::RedrawRequested, - .. - } => { - // Rendering logic - let frame = self.context.get_next_frame(); - - // On appelle le render() de l'utilisateur (reçoit la frame courante) - handler.render(&mut self, &frame); - // On présente automatiquement - self.renderer.present(frame); - } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::CloseRequested, - .. - } => { - elwt.exit(); - } - _ => {} - } - }) + .run_app(&mut runner) .map_err(|_| WsgError::WindowSystem) } @@ -90,7 +126,7 @@ impl App { /// who override `render` to control drawing themselves. /// Inputs: view — the frame's texture view acting as the color attachment target. pub fn render_scene(&self, view: &wgpu::TextureView) { - self.renderer.render_scene(view, &self.scene); + self.renderer().render_scene(view, &self.scene); } } @@ -128,34 +164,123 @@ impl AppBuilder { self.height = height; self } - /// Builds the configured `App` instance by creating all required components in order: - /// EventLoop → Window → Context → Renderer → PipelineCache → Scene. - /// Returns Ok(App) on success or Err(WsgError) if any component fails during creation. - /// Called after setting desired properties via the builder pattern; triggers async GPU initialization. + /// Builds the configured `App` instance: creates the event loop and stores the window + /// configuration. The GPU context, window and renderer are created later, when the event loop + /// is resumed (inside `App::run`), because winit 0.30 only allows window creation in that phase. + /// Returns Ok(App) on success or Err(WsgError) if the event loop cannot be created. + /// Called after setting desired properties via the builder pattern before `App::run`. pub async fn build(self) -> Result { - let event_loop = EventLoop::new().unwrap(); - let window = Arc::new( - winit::window::WindowBuilder::new() - .with_title(&self.title) - .build(&event_loop) - .map_err(|_| WsgError::WindowSystem)?, - ); - let context = Context::new(window.clone()).await?; - let device = Arc::new(context.device.clone()); - let format = context - .configure(&context.adapter, self.width, self.height) - .map_err(|_| WsgError::SurfaceIncompatible)?; - let renderer = Renderer::new(&context, format); - let cache = PipelineCache::new(device); - let scene = Scene::new(); - + let event_loop = EventLoop::new().map_err(|_| WsgError::WindowSystem)?; Ok(App { - context, - renderer, - cache, - scene, + scene: Scene::new(), + title: self.title, + width: self.width, + height: self.height, event_loop: Some(event_loop), - window, + context: None, + renderer: None, + window: None, + cache: None, }) } } + +/// Internal runner that adapts a user `AppHandler` to winit's 0.30 `ApplicationHandler` model. +/// It owns the window/GPU lifecycle: everything is created lazily inside `resumed()`, then the +/// user's `setup`, `update` and `render` hooks are driven from the corresponding winit events. +struct AppRunner { + /// Window title, applied when the window is created in `resumed`. + title: String, + /// Window width in pixels, applied when the window is created in `resumed`. + width: u32, + /// Window height in pixels, applied when the window is created in `resumed`. + height: u32, + /// The user-provided game logic. + handler: H, + /// The fully-built App facade, populated on the first `resumed` event. + app: Option, +} + +impl ApplicationHandler for AppRunner { + /// Builds the window, GPU context, renderer and shader cache, then invokes the user's `setup`. + /// Guarded so redundant back-to-back `resumed` events do not re-initialize the GPU. + /// Inputs: event_loop — the active event loop used to create the window and control redrawing. + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + if self.app.is_some() { + return; + } + event_loop.set_control_flow(ControlFlow::Poll); + + let attrs = WindowAttributes::default() + .with_title(&self.title) + .with_inner_size(LogicalSize::new(self.width as f64, self.height as f64)); + let window = Arc::new( + event_loop + .create_window(attrs) + .map_err(|_| WsgError::WindowSystem) + .expect("failed to create window"), + ); + + // Initialization GPU (bloquant, simplifié au max) + let context = pollster::block_on(Context::new(window.clone())).expect("Échec init GPU"); + let format = context + .configure(&context.adapter, self.width, self.height) + .expect("Échec configuration surface"); + let device = Arc::new(context.device.clone()); + let cache = PipelineCache::new(device); + let renderer = Renderer::new(&context, format); + + let mut app = App { + scene: Scene::new(), + title: self.title.clone(), + width: self.width, + height: self.height, + event_loop: None, + context: Some(context), + renderer: Some(renderer), + window: Some(window), + cache: Some(cache), + }; + // On laisse l'utilisateur enregistrer shaders/meshes/matériaux/entités une fois le GPU prêt. + self.handler.setup(&mut app); + self.app = Some(app); + } + + /// Drives the user's per-frame update and requests a redraw so the window renders continuously. + /// Inputs: _event_loop — active event loop (unused here). + fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { + let Some(app) = self.app.as_mut() else { + return; + }; + self.handler.update(app); + app.window().request_redraw(); + } + + /// Dispatches window events: RedrawRequested renders/presents a frame, CloseRequested exits. + /// Inputs: event_loop — active event loop, used to exit on close; event — the window event. + fn window_event( + &mut self, + event_loop: &ActiveEventLoop, + _window_id: winit::window::WindowId, + event: WindowEvent, + ) { + let Some(app) = self.app.as_mut() else { + return; + }; + match event { + WindowEvent::RedrawRequested => { + // Rendering logic + let frame = app.context().get_next_frame(); + + // On appelle le render() de l'utilisateur (reçoit la frame courante) + self.handler.render(app, &frame); + // On présente automatiquement + app.renderer().present(frame); + } + WindowEvent::CloseRequested => { + event_loop.exit(); + } + _ => {} + } + } +} diff --git a/lib/src/handler.rs b/lib/src/handler.rs index 0c92ceb..0776f13 100644 --- a/lib/src/handler.rs +++ b/lib/src/handler.rs @@ -24,6 +24,12 @@ use crate::core::Frame; /// render (draw call execution). Default implementations provide empty update and automatic /// scene rendering for convenience. pub trait AppHandler { + /// Called once by `App::run`, right after the window/GPU context are created (winit `resumed`). + /// Use it to register shaders, build Meshes/Materials, and populate `app.scene` before the loop + /// starts. This replaces the pre-`run` setup that was possible before the winit 0.30 migration. + /// Default implementation does nothing. + /// Inputs: app — mutable reference to the fully-initialized App facade. + fn setup(&mut self, _app: &mut App) {} /// Called once per frame before rendering begins. Used for physics updates, input processing, /// entity management, and any other pre-render logic. Default implementation does nothing. /// Inputs: _app — mutable reference to the App facade providing access to all subsystems.