diff --git a/Cargo.lock b/Cargo.lock index a584ec8..3e6d5bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,14 +88,15 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ "cfg-if", "getrandom", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -326,9 +327,9 @@ checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "bevy" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329e344f835f5a9a4c46a6d1d57371f726aa2c482d1bd669b2b9c4eb1ee91fd7" +checksum = "e4bc7e09282a82a48d70ade0c4c1154b0fd7882a735a39c66766a5d0f4718ea9" dependencies = [ "bevy_internal", ] @@ -339,13 +340,13 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d65b98d6fca1209c36c4d403c377f303aad22d940281fe1a9e431217516f0622" dependencies = [ - "bevy-inspector-egui-derive", + "bevy-inspector-egui-derive 0.21.0", "bevy_app", "bevy_asset", "bevy_core", "bevy_core_pipeline", "bevy_ecs", - "bevy_egui", + "bevy_egui 0.23.0", "bevy_hierarchy", "bevy_log", "bevy_math", @@ -354,7 +355,36 @@ dependencies = [ "bevy_render", "bevy_utils", "bevy_window", - "egui", + "egui 0.23.0", + "image", + "once_cell", + "pretty-type-name", + "smallvec", +] + +[[package]] +name = "bevy-inspector-egui" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c3efee9165f9be9c6a180c6a9bbb4bd39ee0a98a594f4cb7127704e15415cdd" +dependencies = [ + "bevy-inspector-egui-derive 0.22.0", + "bevy_app", + "bevy_asset", + "bevy_core", + "bevy_core_pipeline", + "bevy_ecs", + "bevy_egui 0.24.0", + "bevy_hierarchy", + "bevy_log", + "bevy_math", + "bevy_pbr", + "bevy_reflect", + "bevy_render", + "bevy_time", + "bevy_utils", + "bevy_window", + "egui 0.24.1", "image", "once_cell", "pretty-type-name", @@ -373,10 +403,30 @@ dependencies = [ ] [[package]] -name = "bevy_a11y" -version = "0.12.0" +name = "bevy-inspector-egui-derive" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271b812e5734f5056a400f7d64592dd82d6c0e6179389c2f066f433ab8bc7692" +checksum = "5ec77479f56958ed1b2802c3129ebc704d12245627b2d4dae61f11e6ed5c21b1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "bevy-scene-hook" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e433958378686e72e82184650a54a64055f7e498e446edc32b5a157f926d7d" +dependencies = [ + "bevy", +] + +[[package]] +name = "bevy_a11y" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68080288c932634f6563d3a8299efe0ddc9ea6787539c4c771ba250d089a94f0" dependencies = [ "accesskit", "bevy_app", @@ -386,9 +436,9 @@ dependencies = [ [[package]] name = "bevy_animation" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab94187a1253433e14f175293d8a86ec1c2822fda2a17807908f11ec21f45f00" +checksum = "7aa37683b1281e1ba8cf285644e6e3f0704f14b3901c5ee282067ff7ff6f4a56" dependencies = [ "bevy_app", "bevy_asset", @@ -405,9 +455,9 @@ dependencies = [ [[package]] name = "bevy_app" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "172d532ea812e5954fa814dae003c207f2a0b20c6e50431787c94a7159677ece" +checksum = "d41731817993f92e4363dd3335558e779e290bc71eefc0b5547052b85810907e" dependencies = [ "bevy_derive", "bevy_ecs", @@ -421,9 +471,9 @@ dependencies = [ [[package]] name = "bevy_asset" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccb2b67984088b23e223cfe9ec1befd89a110665a679acb06839bc4334ed37d6" +checksum = "935984568f75867dd7357133b06f4b1502cd2be55e4642d483ce597e46e63bff" dependencies = [ "async-broadcast", "async-fs", @@ -453,9 +503,9 @@ dependencies = [ [[package]] name = "bevy_asset_macros" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b3245193e90fc8abcf1059a467cb224501dcda083d114c67c10ac66b7171e3a" +checksum = "3f48b9bbe4ec605e4910b5cd1e1a0acbfbe0b80af5f3bcc4489a9fdd1e80058c" dependencies = [ "bevy_macro_utils", "proc-macro2", @@ -465,9 +515,9 @@ dependencies = [ [[package]] name = "bevy_audio" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478de80ff25cb7decbcb22797774d1597e8c32914e81431c67d64faadc08f84a" +checksum = "18a69889e1bfa4dbac4e641536b94f91c441da55796ad9832e77836b8264688b" dependencies = [ "bevy_app", "bevy_asset", @@ -483,9 +533,9 @@ dependencies = [ [[package]] name = "bevy_core" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "025e6800b73048092a55c3611e9327ad4c4c17b60517ec1c0086bb40b4b19ea8" +checksum = "3daa24502a14839509f02407bc7e48299fe84d260877de23b60662de0f4f4b6c" dependencies = [ "bevy_app", "bevy_ecs", @@ -498,9 +548,9 @@ dependencies = [ [[package]] name = "bevy_core_pipeline" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e4b08a2d53ba62d9ec1fca3f7f4e0f556e9f59e1c8e63a4b7c2a18c0701152c" +checksum = "b4b77c4fca6e90edbe2e72da7bc9aa7aed7dfdfded0920ae0a0c845f5e11084a" dependencies = [ "bevy_app", "bevy_asset", @@ -519,10 +569,19 @@ dependencies = [ ] [[package]] -name = "bevy_derive" -version = "0.12.0" +name = "bevy_debug_grid" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24bf40259be12a1a24d9fd536f5ff18d31eeb5665b77e2732899783be6edc5d6" +checksum = "4838c193ed4dcf35a550f14cfdd5e7d105de0a58d67841d6e5f55bc5b1c8491c" +dependencies = [ + "bevy", +] + +[[package]] +name = "bevy_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f484318350462c58ba3942a45a656c1fd6b6e484a6b6b7abc3a787ad1a51e500" dependencies = [ "bevy_macro_utils", "quote", @@ -531,9 +590,9 @@ dependencies = [ [[package]] name = "bevy_diagnostic" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b5a99a9fb6cd7d1eb1714fad193944a0317f0887a15cccb8309c8d37951132" +checksum = "fa38ca5967d335cc1006a0e0f1a86c350e2f15fd1878449f61d04cd57a7c4060" dependencies = [ "bevy_app", "bevy_core", @@ -545,10 +604,20 @@ dependencies = [ ] [[package]] -name = "bevy_ecs" -version = "0.12.0" +name = "bevy_easings" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae11a1f467c372b50e9d4b55e78370f5420c9db7416200cc441cc84f08174dd3" +checksum = "d13de5afeee849a6f5a9f35eace1a41efe01fc005ad85671c54876909216f2e6" +dependencies = [ + "bevy", + "interpolation 0.3.0", +] + +[[package]] +name = "bevy_ecs" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709fbd22f81fb681534cd913c41e1cd18b17143368743281195d7f024b61aea" dependencies = [ "async-channel", "bevy_ecs_macros", @@ -567,9 +636,9 @@ dependencies = [ [[package]] name = "bevy_ecs_macros" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f642c2b67c4d0daf8edf15074f6351457eb487a34b3de1290c760d8f3ac9ec16" +checksum = "a8843aa489f159f25cdcd9fee75cd7d221a7098a71eaa72cb2d6b40ac4e3f1ba" dependencies = [ "bevy_macro_utils", "proc-macro2", @@ -585,16 +654,29 @@ checksum = "85450af551b7e1cb766f710763b60a12a82ffd6323945a8f776c6334c59ccdc1" dependencies = [ "arboard", "bevy", - "egui", + "egui 0.23.0", + "thread_local", + "webbrowser", +] + +[[package]] +name = "bevy_egui" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c90c01202dbcebc03315a01ea71553b35e1f20b0da6b1cc8c2605344032a3d96" +dependencies = [ + "arboard", + "bevy", + "egui 0.24.1", "thread_local", "webbrowser", ] [[package]] name = "bevy_encase_derive" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65b9fb5a62c4e3ab70caaa839470d35fa932001b1b34b08bc7f7f1909bd2b3a7" +checksum = "5328a3715e933ebbff07d0e99528dc423c4f7a53590ed1ac19a120348b028990" dependencies = [ "bevy_macro_utils", "encase_derive_impl", @@ -635,9 +717,9 @@ dependencies = [ [[package]] name = "bevy_gilrs" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad31cc2c84315e0759d793d6c5bcb7d8789bbc16359c98d1b766e708c1bbae49" +checksum = "9b81ca2ebf66cbc7f998f1f142b15038ffe3c4ae1d51f70adda26dcf51b0c4ca" dependencies = [ "bevy_app", "bevy_ecs", @@ -651,9 +733,9 @@ dependencies = [ [[package]] name = "bevy_gizmos" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87d1cc978b91f416b23eb16f00e69f95c3a04582021827d8082e92d4725cc510" +checksum = "db232274ddca2ae452eb2731b98267b795d133ddd14013121bc7daddde1c7491" dependencies = [ "bevy_app", "bevy_asset", @@ -671,9 +753,9 @@ dependencies = [ [[package]] name = "bevy_gltf" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f933745c0c86e2c07948def581259b466f99708328657054e956275430ccfd7" +checksum = "85adc6b1fc86687bf67149e0bafaa4d6da432232fa956472d1b37f19121d3ace" dependencies = [ "base64 0.13.1", "bevy_animation", @@ -701,9 +783,9 @@ dependencies = [ [[package]] name = "bevy_hierarchy" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64fa240011fce8ee23f9b46e5a26a628a31d7860d6d2e4e0e361bb3ea6d5a703" +checksum = "06bd477152ce2ae1430f5e0a4f19216e5785c22fee1ab23788b5982dc59d1a55" dependencies = [ "bevy_app", "bevy_core", @@ -716,9 +798,9 @@ dependencies = [ [[package]] name = "bevy_input" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e86e241b3a10b79f65a69205552546723b855d3d4c1bd8261637c076144d32f" +checksum = "cab9a599189b2a694c182d60cd52219dd9364f9892ff542d87799b8e45d9e6dc" dependencies = [ "bevy_app", "bevy_ecs", @@ -730,9 +812,9 @@ dependencies = [ [[package]] name = "bevy_internal" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55124e486814c4d3632d5cfad9c4f4e46d052c028593ec46fef5bfbfb0f840b1" +checksum = "f124bece9831afd80897815231072d51bfe3ac58c6bb58eca8880963b6d0487c" dependencies = [ "bevy_a11y", "bevy_animation", @@ -769,9 +851,9 @@ dependencies = [ [[package]] name = "bevy_log" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "011417debf7868b45932bb97fc0d5bfdeaf9304e324aa94840e2f1e6deeed69d" +checksum = "0dc10ba1d225a8477b9e80a1bf797d8a8b8274e83c9b24fb4d9351aec9229755" dependencies = [ "android_log-sys", "bevy_app", @@ -785,9 +867,9 @@ dependencies = [ [[package]] name = "bevy_macro_utils" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf6fba87c6d069fcbcd8a48625ca8ab4392ad40d2b260863ce7d641a0f42986d" +checksum = "e566640c6b6dced73d2006c764c2cffebe1a82be4809486c4a5d7b4b50efed4d" dependencies = [ "proc-macro2", "quote", @@ -798,9 +880,9 @@ dependencies = [ [[package]] name = "bevy_math" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "752764558a1f429c20704c3b836a019fa308961c43fdfef4f08e339d456c96be" +checksum = "58ddc2b76783939c530178f88e5711a1b01044d7b02db4033e2eb8b43b6cf4ec" dependencies = [ "glam", "serde", @@ -808,9 +890,9 @@ dependencies = [ [[package]] name = "bevy_mikktspace" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b596c41a56f2268ec7cde560edc588bc7b5886e4b49c8b27c4dcc9f7c743424c" +checksum = "8ec4962977a746d870170532fc92759e04d3dbcae8b7b82e7ca3bb83b1d75277" dependencies = [ "glam", ] @@ -823,7 +905,7 @@ checksum = "0241b06b1e994d678c1e7550d923fc756c9f0f928d9339d53506742f11cce2df" dependencies = [ "bevy", "bitfield", - "interpolation", + "interpolation 0.2.0", "thiserror", "wgpu-types", ] @@ -878,10 +960,20 @@ dependencies = [ ] [[package]] -name = "bevy_pbr" -version = "0.12.0" +name = "bevy_panorbit_camera" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb6a35a78d355cc21c10f277dcd171eca65e30a90e76eb89f4dacf606621fe1" +checksum = "c2bfb88d07954e06001f4d38a1acdbdaed802320801d545bf4575db8ee5f0a06" +dependencies = [ + "bevy", + "bevy_easings", +] + +[[package]] +name = "bevy_pbr" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520bfd2a898c74f84ea52cfb8eb061f37373ad15e623489d5f75d27ebd6138fe" dependencies = [ "bevy_app", "bevy_asset", @@ -1039,9 +1131,9 @@ dependencies = [ [[package]] name = "bevy_ptr" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308a02679f6ce21ef71de20fae6d6a2016c07baa21d8e8d0558e6b7851e8adf2" +checksum = "c77ec20c8fafcdc196508ef5ccb4f0400a8d193cb61f7b14a36ed9a25ad423cf" [[package]] name = "bevy_rapier3d" @@ -1058,9 +1150,9 @@ dependencies = [ [[package]] name = "bevy_reflect" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd56914a8ad57621d7a1a099f7e6b1f7482c9c76cedc9c3d4c175a203939c5d" +checksum = "d7921f15fc944c9c8ad01d7dbcea6505b8909c6655cd9382bab1407181556038" dependencies = [ "bevy_math", "bevy_ptr", @@ -1077,9 +1169,9 @@ dependencies = [ [[package]] name = "bevy_reflect_derive" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f627907c40ac552f798423447fc331fc1ddacd94c5f7a2a70942eb06bc8447" +checksum = "b4a8c5475f216e751ef4452a1306b00711f33d2d04d9f149e4c845dfeb6753a0" dependencies = [ "bevy_macro_utils", "proc-macro2", @@ -1090,9 +1182,9 @@ dependencies = [ [[package]] name = "bevy_render" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90d777f4c51bd58e9e40777c6cb8dde0778df7e2c5298b3f9e3455bd12a9856c" +checksum = "bdefdd3737125b0d94a6ff20bb70fa8cfe9d7d5dcd72ba4dfe6c5f1d30d9f6e4" dependencies = [ "async-channel", "bevy_app", @@ -1136,9 +1228,9 @@ dependencies = [ [[package]] name = "bevy_render_macros" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35b00c3d0abff94a729460fc9aa95c2ceac71b49b3041166bb5ba3098e9657e7" +checksum = "64d86bfc5a1e7fbeeaec0c4ceab18155530f5506624670965db3415f75826bea" dependencies = [ "bevy_macro_utils", "proc-macro2", @@ -1148,9 +1240,9 @@ dependencies = [ [[package]] name = "bevy_scene" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6294396a6375f0b14341d8003408c10aa040e3f833ac8bd49677170ec55d73" +checksum = "e7df078b5e406e37c8a1c6ba0d652bf105fde713ce3c3efda7263fe27467eee5" dependencies = [ "bevy_app", "bevy_asset", @@ -1169,9 +1261,9 @@ dependencies = [ [[package]] name = "bevy_sprite" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f7d1f88a6e5497fdafd95c20984a1d1b5517bc39d51600b4988cd60c51837a" +checksum = "c7cc0c9d946e17e3e0aaa202f182837bc796c4f862b2e5a805134f873f21cf7f" dependencies = [ "bevy_app", "bevy_asset", @@ -1195,9 +1287,9 @@ dependencies = [ [[package]] name = "bevy_tasks" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a45be906618192515bc613e46546150089adbb4a82178dc462045acd1e89e92" +checksum = "f4fefa7fe0da8923525f7500e274f1bd60dbd79918a25cf7d0dfa0a6ba15c1cf" dependencies = [ "async-channel", "async-executor", @@ -1209,9 +1301,9 @@ dependencies = [ [[package]] name = "bevy_text" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c136af700af4f87c94f68d6e019528c371bf09ebf4a8ff7468bb3c73806b34f5" +checksum = "3a9a79d49ca06170d69149949b134c14e8b99ace1444c1ca2cd4743b19d5b055" dependencies = [ "ab_glyph", "bevy_app", @@ -1231,9 +1323,9 @@ dependencies = [ [[package]] name = "bevy_time" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b29709cadf22d318a0b7c79f763e9c5ac414292bd0e850066fa935959021b276" +checksum = "e6250d76eed3077128b6a3d004f9f198b01107800b9824051e32bb658054e837" dependencies = [ "bevy_app", "bevy_ecs", @@ -1245,9 +1337,9 @@ dependencies = [ [[package]] name = "bevy_transform" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70262c51e915b6224129206d23823364e650cf5eb5f4b6ce3ee379f608c180d2" +checksum = "d541e0c292edbd96afae816ee680e02247422423ccd5dc635c1e211a20ed64be" dependencies = [ "bevy_app", "bevy_ecs", @@ -1259,9 +1351,9 @@ dependencies = [ [[package]] name = "bevy_ui" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd5ecbf2dceaab118769dd870e34d780bfde556af561fd10d8d613b0f237297e" +checksum = "d785e3b75dabcb2a8ad0d50933f8f3446d59e512cabc2d2a145e28c2bb8792ba" dependencies = [ "bevy_a11y", "bevy_app", @@ -1289,9 +1381,9 @@ dependencies = [ [[package]] name = "bevy_utils" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e75d4a34ef0b15dffd1ee9079ef1f0f5139527e192b9d5708b3e158777c753" +checksum = "7915222f4a08ccc782e08d10b751b42e5f9d786e697d0cb3fd09333cb7e8b6ea" dependencies = [ "ahash", "bevy_utils_proc_macros", @@ -1307,9 +1399,9 @@ dependencies = [ [[package]] name = "bevy_utils_proc_macros" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7dfd3735a61a1b681ed1e176afe4eae731bbb03e51ad871e9eb39e76a2d170e" +checksum = "7aafecc952b6b8eb1a93c12590bd867d25df2f4ae1033a01dfdfc3c35ebccfff" dependencies = [ "proc-macro2", "quote", @@ -1318,9 +1410,9 @@ dependencies = [ [[package]] name = "bevy_window" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e60d1830b3fbd7db5bfea7ac9fcd0f5e1d1af88c91ab469e697ab176d8b3140b" +checksum = "41ee72bf7f974000e9b31bb971a89387f1432ba9413f35c4fef59fef49767260" dependencies = [ "bevy_a11y", "bevy_app", @@ -1334,9 +1426,9 @@ dependencies = [ [[package]] name = "bevy_winit" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f8294e78c6a1f9c34d36501a377c5d20bf0fa23a0958187bb270187741448ba" +checksum = "1eb71f287eca9006dda998784c7b931e400ae2cc4c505da315882a8b082f21ad" dependencies = [ "accesskit_winit", "approx", @@ -1357,6 +1449,33 @@ dependencies = [ "winit", ] +[[package]] +name = "bevy_xpbd_3d" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35590e6cb2860b6a548a37e776dd36ae1aee5c669169caa130f0038a0453ade2" +dependencies = [ + "bevy", + "bevy_xpbd_derive", + "derive_more", + "fxhash", + "glam", + "indexmap 2.0.0", + "itertools", + "nalgebra", + "parry3d", +] + +[[package]] +name = "bevy_xpbd_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1ef1d5e328abe1b76df974245f78e17fd17867583883d5e77444c6a8223a64" +dependencies = [ + "quote", + "syn 2.0.37", +] + [[package]] name = "bindgen" version = "0.68.1" @@ -1642,6 +1761,21 @@ dependencies = [ "const_soft_float", ] +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -1832,6 +1966,19 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -1844,6 +1991,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "duplicate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de78e66ac9061e030587b2a2e75cc88f22304913c907b11307bca737141230cb" +dependencies = [ + "heck", + "proc-macro-error", +] + [[package]] name = "ecolor" version = "0.23.0" @@ -1853,6 +2010,15 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "ecolor" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b7637fc2e74d17e52931bac90ff4fc061ac776ada9c7fa272f24cdca5991972" +dependencies = [ + "bytemuck", +] + [[package]] name = "egui" version = "0.23.0" @@ -1860,10 +2026,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bd69fed5fcf4fbb8225b24e80ea6193b61e17a625db105ef0c4d71dde6eb8b7" dependencies = [ "ahash", - "epaint", + "epaint 0.23.0", "nohash-hasher", ] +[[package]] +name = "egui" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c55bcb864b764eb889515a38b8924757657a250738ad15126637ee2df291ee6b" +dependencies = [ + "ahash", + "epaint 0.24.1", + "nohash-hasher", +] + +[[package]] +name = "egui-gizmo" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2880830f1b9a0ea618472c989e7ee758f9abc54352846e4feab1be278e69316b" +dependencies = [ + "egui 0.24.1", + "glam", + "mint", +] + +[[package]] +name = "egui_dock" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a6cbf38560cdcf75f955b1f2f39be6339a3f2958d06997ce70b7b4aa3f57d" +dependencies = [ + "duplicate", + "egui 0.24.1", + "paste", +] + +[[package]] +name = "egui_file" +version = "0.13.0" +source = "git+https://github.com/Barugon/egui_file.git?rev=de5f8f41df160d67be328ab50974966ceb74e70f#de5f8f41df160d67be328ab50974966ceb74e70f" +dependencies = [ + "egui 0.24.1", +] + [[package]] name = "either" version = "1.9.0" @@ -1879,6 +2086,15 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "emath" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a045c6c0b44b35e98513fc1e9d183ab42881ac27caccb9fa345465601f56cce4" +dependencies = [ + "bytemuck", +] + [[package]] name = "encase" version = "0.6.1" @@ -1920,8 +2136,23 @@ dependencies = [ "ab_glyph", "ahash", "bytemuck", - "ecolor", - "emath", + "ecolor 0.23.0", + "emath 0.23.0", + "nohash-hasher", + "parking_lot", +] + +[[package]] +name = "epaint" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d1b9e000d21bab9b535ce78f9f7745be28b3f777f6c7223936561c5c7fefab8" +dependencies = [ + "ab_glyph", + "ahash", + "bytemuck", + "ecolor 0.24.1", + "emath 0.24.1", "nohash-hasher", "parking_lot", ] @@ -2090,6 +2321,15 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "gethostname" version = "0.2.3" @@ -2158,7 +2398,9 @@ version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" dependencies = [ + "approx", "bytemuck", + "mint", "serde", ] @@ -2326,6 +2568,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hexasphere" version = "9.1.0" @@ -2420,6 +2668,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3b7357d2bbc5ee92f8e899ab645233e43d21407573cceb37fed8bc3dede2c02" +[[package]] +name = "interpolation" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c13ae9d91148fcb4aab6654c4c2a7d02a15395ea9e23f65170f175f8b269ce" + [[package]] name = "io-kit-sys" version = "0.3.0" @@ -2430,6 +2684,15 @@ dependencies = [ "mach2", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -2703,6 +2966,12 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mint" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" + [[package]] name = "mio" version = "0.8.8" @@ -3245,6 +3514,30 @@ dependencies = [ "toml_edit 0.19.15", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.67" @@ -3419,6 +3712,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "ruzstd" version = "0.4.0" @@ -3460,6 +3762,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" + [[package]] name = "serde" version = "1.0.192" @@ -3572,6 +3880,104 @@ dependencies = [ "serde", ] +[[package]] +name = "space_bevy_xpbd_plugin" +version = "0.3.1" +source = "git+https://github.com/rewin123/space_editor?rev=e150ecaf0647de6532d2967928982abf2558bfbc#e150ecaf0647de6532d2967928982abf2558bfbc" +dependencies = [ + "bevy", + "bevy_xpbd_3d", + "space_editor_ui", +] + +[[package]] +name = "space_editor" +version = "0.3.1" +source = "git+https://github.com/rewin123/space_editor?rev=e150ecaf0647de6532d2967928982abf2558bfbc#e150ecaf0647de6532d2967928982abf2558bfbc" +dependencies = [ + "bevy", + "space_bevy_xpbd_plugin", + "space_editor_ui", + "space_prefab", +] + +[[package]] +name = "space_editor_core" +version = "0.3.1" +source = "git+https://github.com/rewin123/space_editor?rev=e150ecaf0647de6532d2967928982abf2558bfbc#e150ecaf0647de6532d2967928982abf2558bfbc" +dependencies = [ + "bevy", + "space_persistence", + "space_prefab", + "space_shared", + "space_undo", +] + +[[package]] +name = "space_editor_ui" +version = "0.3.1" +source = "git+https://github.com/rewin123/space_editor?rev=e150ecaf0647de6532d2967928982abf2558bfbc#e150ecaf0647de6532d2967928982abf2558bfbc" +dependencies = [ + "bevy", + "bevy_debug_grid", + "bevy_egui 0.24.0", + "bevy_mod_picking", + "bevy_panorbit_camera", + "convert_case 0.6.0", + "egui-gizmo", + "egui_dock", + "pretty-type-name", + "space_editor_core", + "space_persistence", + "space_prefab", + "space_shared", + "space_undo", +] + +[[package]] +name = "space_persistence" +version = "0.3.1" +source = "git+https://github.com/rewin123/space_editor?rev=e150ecaf0647de6532d2967928982abf2558bfbc#e150ecaf0647de6532d2967928982abf2558bfbc" +dependencies = [ + "bevy", + "ron", + "serde", +] + +[[package]] +name = "space_prefab" +version = "0.3.1" +source = "git+https://github.com/rewin123/space_editor?rev=e150ecaf0647de6532d2967928982abf2558bfbc#e150ecaf0647de6532d2967928982abf2558bfbc" +dependencies = [ + "bevy", + "bevy-inspector-egui 0.22.1", + "bevy-scene-hook", + "ron", + "serde", + "space_shared", + "space_undo", +] + +[[package]] +name = "space_shared" +version = "0.3.1" +source = "git+https://github.com/rewin123/space_editor?rev=e150ecaf0647de6532d2967928982abf2558bfbc#e150ecaf0647de6532d2967928982abf2558bfbc" +dependencies = [ + "bevy", + "bevy-inspector-egui 0.22.1", + "egui_file", +] + +[[package]] +name = "space_undo" +version = "0.3.1" +source = "git+https://github.com/rewin123/space_editor?rev=e150ecaf0647de6532d2967928982abf2558bfbc#e150ecaf0647de6532d2967928982abf2558bfbc" +dependencies = [ + "bevy", + "pretty-type-name", + "space_shared", +] + [[package]] name = "spade" version = "2.2.1" @@ -3610,7 +4016,7 @@ name = "studio" version = "0.1.0" dependencies = [ "bevy", - "bevy-inspector-egui", + "bevy-inspector-egui 0.21.0", "bevy_mod_outline", "bevy_mod_picking", "bevy_mod_raycast", @@ -3622,6 +4028,7 @@ dependencies = [ "serde", "serde-wasm-bindgen", "serde_json", + "space_editor", "wasm-bindgen", "web-sys", ] @@ -3909,6 +4316,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + [[package]] name = "unicode-width" version = "0.1.11" @@ -4532,3 +4945,23 @@ name = "xml-rs" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] diff --git a/Cargo.toml b/Cargo.toml index 0251c2b..48ecfd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "2" members = ["./studio"] [workspace.dependencies.bevy] -version = "0.12.0" +version = "0.12.1" features = ["tonemapping_luts"] [profile.dev-custom] diff --git a/studio/Cargo.toml b/studio/Cargo.toml index 1b8bc33..ffaa47c 100644 --- a/studio/Cargo.toml +++ b/studio/Cargo.toml @@ -32,6 +32,7 @@ web-sys = { version = "0.3.65", optional = true, features = [ "HtmlElement", "Window", ] } +space_editor = {git = "https://github.com/rewin123/space_editor", rev = "e150ecaf0647de6532d2967928982abf2558bfbc"} [features] wasm = [ diff --git a/studio/src/input.rs b/studio/src/input.rs index 962c5bc..65f4370 100644 --- a/studio/src/input.rs +++ b/studio/src/input.rs @@ -3,6 +3,7 @@ use bevy::{ prelude::*, utils::HashSet, }; +use space_editor::prelude::space_undo::UndoRedo; #[derive(SystemSet, Hash, Debug, PartialEq, Eq, Clone)] pub struct StudioInputSystem; @@ -11,6 +12,18 @@ pub struct StudioInputPlugin; impl Plugin for StudioInputPlugin { fn build(&self, app: &mut App) { app.add_event::(); + + // Reading each frame of the mouse delta allows + // to get rid of the bug that delta is counted from the last reading, + // which leads to camera jumps if you move the mouse between clicks + app.add_systems( + PreUpdate, + read_mouse_delta + .in_set(StudioInputSystem) + .after(bevy::input::InputSystem), + ); + app.init_resource::(); + app.add_systems( PreUpdate, ( @@ -18,9 +31,11 @@ impl Plugin for StudioInputPlugin { translate_debug_toggle, translate_dcc_camera_events, translate_fps_camera_events, + send_undo_event, ) .in_set(StudioInputSystem) - .after(bevy::input::InputSystem), + .after(bevy::input::InputSystem) + .after(read_mouse_delta), ); } } @@ -96,14 +111,14 @@ fn translate_debug_toggle(keyboard: Res>, mut input: EventWriter< } fn translate_dcc_camera_events( - mouse_motion: EventReader, + mouse_motion: Res, mouse_buttons: Res>, keyboard: Res>, mut input: EventWriter, ) { + let delta = mouse_motion.get(); // Camera Pan if mouse_buttons.pressed(MouseButton::Middle) { - let delta = read_mouse_delta(mouse_motion); let lifecycle = if mouse_buttons.just_pressed(MouseButton::Middle) { Lifecycle::Start } else { @@ -121,7 +136,6 @@ fn translate_dcc_camera_events( // Camera Orbit/Zoom else if keyboard.any_pressed([KeyCode::AltLeft, KeyCode::AltRight]) { if mouse_buttons.any_pressed([MouseButton::Left, MouseButton::Right]) { - let delta = read_mouse_delta(mouse_motion); let lifecycle = if mouse_buttons.any_just_pressed([MouseButton::Left, MouseButton::Right]) { Lifecycle::Start @@ -167,7 +181,6 @@ fn translate_dcc_camera_events( Lifecycle::Ongoing }; - let delta = read_mouse_delta(mouse_motion); input.send(InputAction(lifecycle, CameraMotion::Rotate(delta).into())); } // Stop Camera Rotation @@ -185,7 +198,6 @@ fn translate_dcc_camera_events( Lifecycle::Ongoing }; - let delta = read_mouse_delta(mouse_motion); input.send(InputAction(lifecycle, CameraMotion::Rotate(delta).into())); } // Stop Camera Rotation @@ -285,9 +297,29 @@ fn translate_fps_camera_events( } } -#[inline] -fn read_mouse_delta(mut mouse_motion: EventReader) -> Vec2 { - mouse_motion - .read() - .fold(Vec2::ZERO, |accum, current| accum + current.delta) +#[derive(Resource, Default)] +pub struct LastFrameMouseDelta(pub Vec2); + +impl LastFrameMouseDelta { + fn get(&self) -> Vec2 { + self.0 + } +} + +fn read_mouse_delta( + mut mouse_motion: EventReader, + mut last_delta: ResMut, +) { + let delta = mouse_motion + .read() + .fold(Vec2::ZERO, |accum, current| accum + current.delta); + last_delta.0 = delta; +} + +// TODO: Make it configurable +fn send_undo_event(mut events: EventWriter, keyboard: Res>) { + if keyboard.pressed(KeyCode::ControlLeft) && keyboard.just_pressed(KeyCode::Z) { + events.send(UndoRedo::Undo); + info!("Undo event sent"); + } } diff --git a/studio/src/interaction/gizmos/combo.rs b/studio/src/interaction/gizmos/combo.rs index 80ab758..ecdb808 100644 --- a/studio/src/interaction/gizmos/combo.rs +++ b/studio/src/interaction/gizmos/combo.rs @@ -7,160 +7,161 @@ use super::{ on_gizmo_element_hover, on_gizmo_element_unhover, rotation::{on_rotate, on_rotation_end, on_rotation_start, RotationWidget}, translation::{on_translate, on_translation_end, on_translation_start, TranslationWidget}, - GizmoMats, GizmoMeshes, TransformGizmoBundle, TransformGizmoRoot, GIZMO_RENDER_LAYER, + GizmoMats, GizmoMeshes, TransformGizmoBundle, GIZMO_RENDER_LAYER, }; #[inline] pub(super) fn spawn_combo_translation_rotation_gizmo( cmd: &mut Commands, - ent: Entity, - xform: &GlobalTransform, + target: Entity, + target_global_transform: &GlobalTransform, space: TransformSpace, normalizing_scale: f32, meshes: &GizmoMeshes, mats: &GizmoMats, ) { - cmd.entity(ent) - .insert(TransformGizmoRoot) - .with_children(|cmd| { - cmd.spawn(TransformGizmoBundle::new(xform, space, normalizing_scale)) - .with_children(|cmd| { - use super::{ROT_X, ROT_Y, ROT_Z}; + cmd.spawn(TransformGizmoBundle::new( + target, + target_global_transform, + space, + normalizing_scale, + )) + .with_children(|cmd| { + use super::{ROT_X, ROT_Y, ROT_Z}; - // Center sphere - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::ScreenSpace, - MaterialMeshBundle { - mesh: meshes.translate_ss.clone(), - material: mats.translate_ss.clone(), - transform: Transform::IDENTITY, - ..default() - }, - On::>::run(on_gizmo_element_hover), - On::>::run(on_gizmo_element_unhover), - On::>::run(on_translation_start), - On::>::run(on_translate), - On::>::target_commands_mut(on_translation_end), - )); + // Center sphere + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::ScreenSpace, + MaterialMeshBundle { + mesh: meshes.translate_ss.clone(), + material: mats.translate_ss.clone(), + transform: Transform::IDENTITY, + ..default() + }, + On::>::run(on_gizmo_element_hover), + On::>::run(on_gizmo_element_unhover), + On::>::run(on_translation_start), + On::>::run(on_translate), + On::>::run(on_translation_end), + )); - // Rotate X - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - RotationWidget::Axis(Vec3::X), - MaterialMeshBundle { - mesh: meshes.rotate_ring.clone(), - material: mats.rotate_x.clone(), - transform: Transform::from_rotation(ROT_X), - ..default() - }, - On::>::run(on_gizmo_element_hover), - On::>::run(on_gizmo_element_unhover), - On::>::run(on_rotation_start), - On::>::run(on_rotate), - On::>::run(on_rotation_end), - )); - // Translate X - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::Axis(Vec3::X), - MaterialMeshBundle { - mesh: meshes.translate_arrow.clone(), - material: mats.translate_x.clone(), - transform: Transform { - rotation: ROT_X, - translation: vec3(1.2, 0., 0.), - ..default() - }, - ..default() - }, - On::>::run(on_gizmo_element_hover), - On::>::run(on_gizmo_element_unhover), - On::>::run(on_translation_start), - On::>::run(on_translate), - On::>::target_commands_mut(on_translation_end), - )); + // Rotate X + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + RotationWidget::Axis(Vec3::X), + MaterialMeshBundle { + mesh: meshes.rotate_ring.clone(), + material: mats.rotate_x.clone(), + transform: Transform::from_rotation(ROT_X), + ..default() + }, + On::>::run(on_gizmo_element_hover), + On::>::run(on_gizmo_element_unhover), + On::>::run(on_rotation_start), + On::>::run(on_rotate), + On::>::run(on_rotation_end), + )); + // Translate X + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::Axis(Vec3::X), + MaterialMeshBundle { + mesh: meshes.translate_arrow.clone(), + material: mats.translate_x.clone(), + transform: Transform { + rotation: ROT_X, + translation: vec3(1.2, 0., 0.), + ..default() + }, + ..default() + }, + On::>::run(on_gizmo_element_hover), + On::>::run(on_gizmo_element_unhover), + On::>::run(on_translation_start), + On::>::run(on_translate), + On::>::run(on_translation_end), + )); - // Rotate Y - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - RotationWidget::Axis(Vec3::Y), - MaterialMeshBundle { - mesh: meshes.rotate_ring.clone(), - material: mats.rotate_y.clone(), - transform: Transform::from_rotation(ROT_Y), - ..default() - }, - On::>::run(on_gizmo_element_hover), - On::>::run(on_gizmo_element_unhover), - On::>::run(on_rotation_start), - On::>::run(on_rotate), - On::>::run(on_rotation_end), - )); - // Translate Y - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::Axis(Vec3::Y), - MaterialMeshBundle { - mesh: meshes.translate_arrow.clone(), - material: mats.translate_y.clone(), - transform: Transform { - rotation: ROT_Y, - translation: vec3(0., 1.2, 0.), - ..default() - }, - ..default() - }, - On::>::run(on_gizmo_element_hover), - On::>::run(on_gizmo_element_unhover), - On::>::run(on_translation_start), - On::>::run(on_translate), - On::>::target_commands_mut(on_translation_end), - )); + // Rotate Y + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + RotationWidget::Axis(Vec3::Y), + MaterialMeshBundle { + mesh: meshes.rotate_ring.clone(), + material: mats.rotate_y.clone(), + transform: Transform::from_rotation(ROT_Y), + ..default() + }, + On::>::run(on_gizmo_element_hover), + On::>::run(on_gizmo_element_unhover), + On::>::run(on_rotation_start), + On::>::run(on_rotate), + On::>::run(on_rotation_end), + )); + // Translate Y + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::Axis(Vec3::Y), + MaterialMeshBundle { + mesh: meshes.translate_arrow.clone(), + material: mats.translate_y.clone(), + transform: Transform { + rotation: ROT_Y, + translation: vec3(0., 1.2, 0.), + ..default() + }, + ..default() + }, + On::>::run(on_gizmo_element_hover), + On::>::run(on_gizmo_element_unhover), + On::>::run(on_translation_start), + On::>::run(on_translate), + On::>::run(on_translation_end), + )); - // Rotate Z - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - RotationWidget::Axis(Vec3::Z), - MaterialMeshBundle { - mesh: meshes.rotate_ring.clone(), - material: mats.rotate_z.clone(), - transform: Transform::from_rotation(ROT_Z), - ..default() - }, - On::>::run(on_gizmo_element_hover), - On::>::run(on_gizmo_element_unhover), - On::>::run(on_rotation_start), - On::>::run(on_rotate), - On::>::run(on_rotation_end), - )); - // Translate Z - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::Axis(Vec3::Z), - MaterialMeshBundle { - mesh: meshes.translate_arrow.clone(), - material: mats.translate_z.clone(), - transform: Transform { - rotation: ROT_Z, - translation: vec3(0., 0., 1.2), - ..default() - }, - ..default() - }, - On::>::run(on_gizmo_element_hover), - On::>::run(on_gizmo_element_unhover), - On::>::run(on_translation_start), - On::>::run(on_translate), - On::>::target_commands_mut(on_translation_end), - )); - }); - }); + // Rotate Z + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + RotationWidget::Axis(Vec3::Z), + MaterialMeshBundle { + mesh: meshes.rotate_ring.clone(), + material: mats.rotate_z.clone(), + transform: Transform::from_rotation(ROT_Z), + ..default() + }, + On::>::run(on_gizmo_element_hover), + On::>::run(on_gizmo_element_unhover), + On::>::run(on_rotation_start), + On::>::run(on_rotate), + On::>::run(on_rotation_end), + )); + // Translate Z + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::Axis(Vec3::Z), + MaterialMeshBundle { + mesh: meshes.translate_arrow.clone(), + material: mats.translate_z.clone(), + transform: Transform { + rotation: ROT_Z, + translation: vec3(0., 0., 1.2), + ..default() + }, + ..default() + }, + On::>::run(on_gizmo_element_hover), + On::>::run(on_gizmo_element_unhover), + On::>::run(on_translation_start), + On::>::run(on_translate), + On::>::run(on_translation_end), + )); + }); } diff --git a/studio/src/interaction/gizmos/common.rs b/studio/src/interaction/gizmos/common.rs index ed2da5a..c10a1e1 100644 --- a/studio/src/interaction/gizmos/common.rs +++ b/studio/src/interaction/gizmos/common.rs @@ -1,105 +1,64 @@ -use bevy::{math::Affine3A, prelude::*}; +use bevy::prelude::*; use bevy_mod_picking::prelude::*; -use crate::{ - interaction::TransformSpace, - math::{IsNonUniform, MatrixExtras, VecExtras}, -}; +use crate::interaction::TransformSpace; -#[derive(Component)] -pub(super) struct TransformGizmoRoot; - -#[derive(Component)] -pub(super) struct TransformGizmo; - -#[derive(Event)] -pub(super) struct RebuildGizmo; +#[derive(Component, Reflect)] +pub(super) struct TransformGizmo { + pub(super) target: Entity, + pub(super) transform_space: TransformSpace, +} #[derive(Bundle)] pub(super) struct TransformGizmoBundle { name: Name, marker: TransformGizmo, spatial: SpatialBundle, - scale: NaturalScale, } -#[derive(Component, Deref, Reflect)] -pub(super) struct NaturalScale(pub Vec3); - #[derive(Component, Deref)] pub(super) struct InitialTransform(pub GlobalTransform); impl TransformGizmoBundle { pub fn new( - parent_xform: &GlobalTransform, + target: Entity, + target_global_transform: &GlobalTransform, space: TransformSpace, normalizing_scale: f32, ) -> Self { let name = Name::new("TransformGizmo"); - let marker = TransformGizmo; - - let Affine3A { - matrix3, - translation, - } = parent_xform.affine(); - - let (scale, rotation) = matrix3.decompose_scale_rotation(); - let inv_scale = scale.inverse(); - let nat_scale = NaturalScale(Vec3::from_scale_mat(inv_scale)); + let marker = TransformGizmo { + target, + transform_space: space, + }; match space { TransformSpace::Local => { - let global_transform = GlobalTransform::from(Affine3A { - matrix3: rotation, - translation, - }); - - let transform = Transform::from_scale(*nat_scale * normalizing_scale); + let mut transform = target_global_transform.compute_transform(); + transform.scale = Vec3::splat(normalizing_scale); Self { name, marker, spatial: SpatialBundle { - global_transform, + global_transform: GlobalTransform::from(transform), transform, ..default() }, - scale: nat_scale, } } TransformSpace::World => { - // FIXME: I'm struggling to figure out how to eliminate the - // "shear" from a fully inverted local transform when the - // object is non-uniformly scaled. As a workaround, we'll - // force these objects to operate in local-space mode. - // TODO: If this turns into a long-term solution, update the UI - // to reflect that world-space transformation is not - // possible for this object (e.g., by disabling the - // world-space toggle button, maybe with an explanatory - // tooltip). - let local_matrix = if nat_scale.is_non_uniform() { - inv_scale - } else { - matrix3.inverse() - }; - - let global_transform = GlobalTransform::from(Affine3A { - matrix3, - translation, - }); - - let mat4 = Mat4::from_mat3a(local_matrix * normalizing_scale); - let transform = Transform::from_matrix(mat4); + let transform = Transform::from_translation(target_global_transform.translation()) + .with_scale(Vec3::splat(normalizing_scale)); Self { name, marker, spatial: SpatialBundle { - global_transform, + global_transform: GlobalTransform::from(transform), transform, ..default() }, - scale: nat_scale, } } } diff --git a/studio/src/interaction/gizmos/mod.rs b/studio/src/interaction/gizmos/mod.rs index 939c595..b4009d5 100644 --- a/studio/src/interaction/gizmos/mod.rs +++ b/studio/src/interaction/gizmos/mod.rs @@ -35,8 +35,8 @@ pub struct GizmoPlugin; impl Plugin for GizmoPlugin { fn build(&self, app: &mut App) { - app.register_type::(); - app.add_event::(); + app.register_type::(); + app.add_systems(Startup, init_resources); app.add_systems( PreUpdate, @@ -50,13 +50,15 @@ impl Plugin for GizmoPlugin { ( despawn_existing_gizmo.run_if( resource_changed_or_removed::() - .or_else(resource_changed::()) - .or_else(on_event::()), + .or_else(resource_changed::()), ), spawn_gizmo.after(despawn_existing_gizmo).run_if( resource_exists::() - .and_then(not(any_with_component::())), + .and_then(not(any_with_component::())), ), + (update_target_global_trasform, sync_gizmo_transform) + .chain() + .after(CameraMotionSystem), normalize_gizmo_scale.after(CameraMotionSystem), ), ); @@ -67,17 +69,9 @@ impl Plugin for GizmoPlugin { } } -fn despawn_existing_gizmo( - mut cmd: Commands, - q_gizmo_root: Query<(Entity, &Children), With>, - q_gizmos: Query>, -) { - if let Ok((ent, children)) = q_gizmo_root.get_single() { - if let Some(child) = children.iter().find_map(|ent| q_gizmos.get(*ent).ok()) { - cmd.entity(child).despawn_recursive(); - } - - cmd.entity(ent).remove::(); +fn despawn_existing_gizmo(mut cmd: Commands, q_gizmos: Query>) { + for ent in q_gizmos.iter() { + cmd.entity(ent).despawn_recursive(); } } @@ -90,8 +84,8 @@ fn spawn_gizmo( r_meshes: Res, r_mats: Res, ) { - let ent = **r_selection; - let Ok(xform) = q_xform.get(ent) else { + let target = **r_selection; + let Ok(xform) = q_xform.get(target) else { return; }; @@ -107,7 +101,7 @@ fn spawn_gizmo( TransformType::TRANSLATE => { spawn_translation_gizmo( &mut cmd, - ent, + target, xform, r_xform_mode.space, normalizing_scale, @@ -118,7 +112,7 @@ fn spawn_gizmo( TransformType::ROTATE => { spawn_rotation_gizmo( &mut cmd, - ent, + target, xform, r_xform_mode.space, normalizing_scale, @@ -129,7 +123,7 @@ fn spawn_gizmo( ttype if ttype.contains(TransformType::TRANSLATE | TransformType::ROTATE) => { spawn_combo_translation_rotation_gizmo( &mut cmd, - ent, + target, xform, r_xform_mode.space, normalizing_scale, @@ -143,20 +137,57 @@ fn spawn_gizmo( } } +fn sync_gizmo_transform( + mut cmd: Commands, + mut q_gizmo: Query<(&mut Transform, &TransformGizmo)>, + q_targets: Query<&GlobalTransform>, +) { + for (mut transform, gizmo) in q_gizmo.iter_mut() { + if let Ok(target) = q_targets.get(gizmo.target) { + match gizmo.transform_space { + super::TransformSpace::Local => { + let target_transform = target.compute_transform(); + transform.translation = target_transform.translation; + transform.rotation = target_transform.rotation; + } + super::TransformSpace::World => { + transform.translation = target.translation(); + } + } + } else { + cmd.entity(gizmo.target).despawn_recursive(); + } + } +} + +fn update_target_global_trasform( + mut q_gizmo: Query<&TransformGizmo>, + mut q_targets: ParamSet<(TransformHelper,)>, + mut q_targets_global: Query<&mut GlobalTransform>, +) { + for gizmo in q_gizmo.iter_mut() { + if let Ok(global_transform) = q_targets.p0().compute_global_transform(gizmo.target) { + if let Ok(mut global) = q_targets_global.get_mut(gizmo.target) { + *global = global_transform; + } + } + } +} + fn normalize_gizmo_scale( q_cam_xform: Query<&Transform, With>, mut q_gizmo: Query< - (&mut Transform, &GlobalTransform, &NaturalScale), + (&mut Transform, &GlobalTransform), (With, Without), >, ) { let Ok(cam_xform) = q_cam_xform.get_single() else { return; }; - let Ok((mut xform, world_xform, nat_scale)) = q_gizmo.get_single_mut() else { + let Ok((mut xform, _)) = q_gizmo.get_single_mut() else { return; }; - let dist = Vec3::distance(cam_xform.translation, world_xform.translation()); - xform.scale = **nat_scale * (dist / 15.); + let dist = Vec3::distance(cam_xform.translation, xform.translation); + xform.scale = Vec3::splat(dist / 15.); } diff --git a/studio/src/interaction/gizmos/rotation.rs b/studio/src/interaction/gizmos/rotation.rs index d9a3b24..10508d9 100644 --- a/studio/src/interaction/gizmos/rotation.rs +++ b/studio/src/interaction/gizmos/rotation.rs @@ -8,14 +8,14 @@ use bevy_mod_picking::prelude::*; use bevy_mod_raycast::prelude::{Raycast, RaycastSettings}; use crate::{ - interaction::{TransformMode, TransformSpace}, + interaction::TransformSpace, math::{MatrixExtras, NearlyZero}, MainCamera, }; use super::{ on_gizmo_element_hover, on_gizmo_element_unhover, GizmoMats, GizmoMeshes, InitialTransform, - RebuildGizmo, TransformGizmo, TransformGizmoBundle, TransformGizmoRoot, GIZMO_RENDER_LAYER, + TransformGizmo, TransformGizmoBundle, GIZMO_RENDER_LAYER, }; #[derive(Component)] @@ -40,97 +40,93 @@ pub(super) struct LastRotation { #[inline] pub(super) fn spawn_rotation_gizmo( cmd: &mut Commands, - ent: Entity, - xform: &GlobalTransform, + target: Entity, + target_global_transform: &GlobalTransform, space: TransformSpace, normalizing_scale: f32, meshes: &GizmoMeshes, mats: &GizmoMats, ) { - cmd.entity(ent) - .insert(TransformGizmoRoot) - .with_children(|cmd| { - cmd.spawn(( - TransformGizmoBundle::new(xform, space, normalizing_scale), - On::>::run(on_rotation_start), - On::>::run(on_rotate), - On::>::run(on_rotation_end), - )) - .with_children(|cmd| { - use super::{ROT_X, ROT_Y, ROT_Z}; + cmd.spawn(( + TransformGizmoBundle::new(target, target_global_transform, space, normalizing_scale), + On::>::run(on_rotation_start), + On::>::run(on_rotate), + On::>::run(on_rotation_end), + )) + .with_children(|cmd| { + use super::{ROT_X, ROT_Y, ROT_Z}; - // Trackball - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - RotationWidget::Trackball, - MaterialMeshBundle { - mesh: meshes.rotate_ball.clone(), - material: mats.rotate_trackball.clone(), - ..default() - }, - On::>::run(on_trackball_hover), - On::>::run(on_trackball_unhover), - )); + // Trackball + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + RotationWidget::Trackball, + MaterialMeshBundle { + mesh: meshes.rotate_ball.clone(), + material: mats.rotate_trackball.clone(), + ..default() + }, + On::>::run(on_trackball_hover), + On::>::run(on_trackball_unhover), + )); - // Screen-space - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - RotationWidget::ScreenSpace, - MaterialMeshBundle { - mesh: meshes.rotate_ss.clone(), - material: mats.rotate_ss.clone(), - ..default() - }, - On::>::run(on_gizmo_element_hover), - On::>::run(on_gizmo_element_unhover), - )); + // Screen-space + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + RotationWidget::ScreenSpace, + MaterialMeshBundle { + mesh: meshes.rotate_ss.clone(), + material: mats.rotate_ss.clone(), + ..default() + }, + On::>::run(on_gizmo_element_hover), + On::>::run(on_gizmo_element_unhover), + )); - // X - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - RotationWidget::Axis(Vec3::X), - MaterialMeshBundle { - mesh: meshes.rotate_ring.clone(), - material: mats.rotate_x.clone(), - transform: Transform::from_rotation(ROT_X), - ..default() - }, - On::>::run(on_gizmo_element_hover), - On::>::run(on_gizmo_element_unhover), - )); - // Y - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - RotationWidget::Axis(Vec3::Y), - MaterialMeshBundle { - mesh: meshes.rotate_ring.clone(), - material: mats.rotate_y.clone(), - transform: Transform::from_rotation(ROT_Y), - ..default() - }, - On::>::run(on_gizmo_element_hover), - On::>::run(on_gizmo_element_unhover), - )); - // Z - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - RotationWidget::Axis(Vec3::Z), - MaterialMeshBundle { - mesh: meshes.rotate_ring.clone(), - material: mats.rotate_z.clone(), - transform: Transform::from_rotation(ROT_Z), - ..default() - }, - On::>::run(on_gizmo_element_hover), - On::>::run(on_gizmo_element_unhover), - )); - }); - }); + // X + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + RotationWidget::Axis(Vec3::X), + MaterialMeshBundle { + mesh: meshes.rotate_ring.clone(), + material: mats.rotate_x.clone(), + transform: Transform::from_rotation(ROT_X), + ..default() + }, + On::>::run(on_gizmo_element_hover), + On::>::run(on_gizmo_element_unhover), + )); + // Y + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + RotationWidget::Axis(Vec3::Y), + MaterialMeshBundle { + mesh: meshes.rotate_ring.clone(), + material: mats.rotate_y.clone(), + transform: Transform::from_rotation(ROT_Y), + ..default() + }, + On::>::run(on_gizmo_element_hover), + On::>::run(on_gizmo_element_unhover), + )); + // Z + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + RotationWidget::Axis(Vec3::Z), + MaterialMeshBundle { + mesh: meshes.rotate_ring.clone(), + material: mats.rotate_z.clone(), + transform: Transform::from_rotation(ROT_Z), + ..default() + }, + On::>::run(on_gizmo_element_hover), + On::>::run(on_gizmo_element_unhover), + )); + }); } pub(super) fn update_ss_ring_rotation( @@ -182,58 +178,61 @@ fn on_trackball_unhover( pub(super) fn on_rotation_start( event: Listener>, mut cmd: Commands, - q_xform: Query<(Entity, &GlobalTransform), With>, + q_xform: Query<(Entity, &GlobalTransform)>, + q_gizmos: Query<&TransformGizmo>, ) { info!("Rotation start"); - if let Ok((ent, &world_xform)) = q_xform.get_single() { - let hit_point = event.hit.position.unwrap(); + let Ok(gizmo) = q_gizmos.get_single() else { + error!("Rotation gizmo not found"); + return; + }; - cmd.entity(ent).insert(( - InitialTransform(world_xform), - InitialHitPoint(hit_point), - LastHitPoint(hit_point), - LastRotation { - axis: Vec3::ZERO, - theta: 0., - }, - )); - } + let Ok((ent, world_xform)) = q_xform.get(gizmo.target) else { + error!("Rotation gizmo target not found"); + return; + }; + + let hit_point = event.hit.position.unwrap(); + + cmd.entity(ent).insert(( + InitialTransform(*world_xform), + InitialHitPoint(hit_point), + LastHitPoint(hit_point), + LastRotation { + axis: Vec3::ZERO, + theta: 0., + }, + )); } pub(super) fn on_rotation_end( - event: Listener>, + _: Listener>, mut cmd: Commands, - r_xform_mode: Res, - mut ev_rebuild_gizmo: EventWriter, + q_inited_components: Query>, ) { info!("Rotation end"); - cmd.entity(event.target) - .remove::() - .remove::() - .remove::() - .remove::(); - - if matches!(r_xform_mode.space, TransformSpace::World) { - ev_rebuild_gizmo.send(RebuildGizmo); + for ent in q_inited_components.iter() { + cmd.entity(ent) + .remove::() + .remove::() + .remove::() + .remove::(); } } pub(super) fn on_rotate( event: Listener>, mut raycast: Raycast, - mut q_root: Query< - ( - &mut Transform, - Option<&Parent>, - &InitialTransform, - &InitialHitPoint, - &mut LastHitPoint, - &mut LastRotation, - ), - With, - >, + mut q_root: Query<( + &mut Transform, + Option<&Parent>, + &InitialTransform, + &InitialHitPoint, + &mut LastHitPoint, + &mut LastRotation, + )>, q_camera: Query<(&Camera, &GlobalTransform), With>, q_gizmo: Query<&GlobalTransform, (With, Without)>, q_world_xforms: Query<&GlobalTransform, (With, Without)>, diff --git a/studio/src/interaction/gizmos/translation.rs b/studio/src/interaction/gizmos/translation.rs index b4f3645..14d4f75 100644 --- a/studio/src/interaction/gizmos/translation.rs +++ b/studio/src/interaction/gizmos/translation.rs @@ -1,16 +1,11 @@ -use bevy::{ - ecs::system::EntityCommands, math::vec3, pbr::NotShadowCaster, prelude::*, - render::view::RenderLayers, -}; -use bevy_mod_picking::prelude::{ - Drag, DragEnd, DragStart, Listener, ListenerInput, On, Out, Over, Pointer, -}; +use bevy::{math::vec3, pbr::NotShadowCaster, prelude::*, render::view::RenderLayers}; +use bevy_mod_picking::prelude::{Drag, DragEnd, DragStart, Listener, On, Out, Over, Pointer}; use crate::{interaction::TransformSpace, MainCamera}; use super::{ on_gizmo_element_hover, on_gizmo_element_unhover, GizmoMats, GizmoMeshes, InitialTransform, - TransformGizmo, TransformGizmoBundle, TransformGizmoRoot, GIZMO_RENDER_LAYER, + TransformGizmo, TransformGizmoBundle, GIZMO_RENDER_LAYER, }; #[derive(Component)] @@ -23,218 +18,226 @@ pub(super) enum TranslationWidget { #[inline] pub(super) fn spawn_translation_gizmo( cmd: &mut Commands, - ent: Entity, - xform: &GlobalTransform, + target: Entity, + target_global_transform: &GlobalTransform, space: TransformSpace, normalizing_scale: f32, meshes: &GizmoMeshes, mats: &GizmoMats, ) { - cmd.entity(ent) - .insert(TransformGizmoRoot) - .with_children(|cmd| { - cmd.spawn(( - TransformGizmoBundle::new(xform, space, normalizing_scale), - On::>::run(on_gizmo_element_hover), - On::>::run(on_gizmo_element_unhover), - On::>::run(on_translation_start), - On::>::run(on_translate), - On::>::target_commands_mut(on_translation_end), - )) - .with_children(|cmd| { - use super::{CIRC_45, ROT_X, ROT_Y, ROT_Z}; + cmd.spawn(( + TransformGizmoBundle::new(target, target_global_transform, space, normalizing_scale), + On::>::run(on_gizmo_element_hover), + On::>::run(on_gizmo_element_unhover), + On::>::run(on_translation_start), + On::>::run(on_translate), + On::>::run(on_translation_end), + )) + .with_children(|cmd| { + use super::{CIRC_45, ROT_X, ROT_Y, ROT_Z}; - // Center sphere - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::ScreenSpace, - MaterialMeshBundle { - mesh: meshes.translate_ss.clone(), - material: mats.translate_ss.clone(), - transform: Transform::IDENTITY, - ..default() - }, - )); + // Center sphere + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::ScreenSpace, + MaterialMeshBundle { + mesh: meshes.translate_ss.clone(), + material: mats.translate_ss.clone(), + transform: Transform::IDENTITY, + ..default() + }, + )); - // X - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::Axis(Vec3::X), - MaterialMeshBundle { - mesh: meshes.translate_line.clone(), - material: mats.translate_x.clone(), - transform: Transform { - rotation: ROT_X, - translation: vec3(0.6, 0., 0.), - ..default() - }, - ..default() - }, - )); - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::Axis(Vec3::X), - MaterialMeshBundle { - mesh: meshes.translate_arrow.clone(), - material: mats.translate_x.clone(), - transform: Transform { - rotation: ROT_X, - translation: vec3(1., 0., 0.), - ..default() - }, - ..default() - }, - )); + // X + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::Axis(Vec3::X), + MaterialMeshBundle { + mesh: meshes.translate_line.clone(), + material: mats.translate_x.clone(), + transform: Transform { + rotation: ROT_X, + translation: vec3(0.6, 0., 0.), + ..default() + }, + ..default() + }, + )); + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::Axis(Vec3::X), + MaterialMeshBundle { + mesh: meshes.translate_arrow.clone(), + material: mats.translate_x.clone(), + transform: Transform { + rotation: ROT_X, + translation: vec3(1., 0., 0.), + ..default() + }, + ..default() + }, + )); - // Y - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::Axis(Vec3::Y), - MaterialMeshBundle { - mesh: meshes.translate_line.clone(), - material: mats.translate_y.clone(), - transform: Transform { - rotation: ROT_Y, - translation: vec3(0., 0.6, 0.), - ..default() - }, - ..default() - }, - )); - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::Axis(Vec3::Y), - MaterialMeshBundle { - mesh: meshes.translate_arrow.clone(), - material: mats.translate_y.clone(), - transform: Transform { - rotation: ROT_Y, - translation: vec3(0., 1., 0.), - ..default() - }, - ..default() - }, - )); + // Y + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::Axis(Vec3::Y), + MaterialMeshBundle { + mesh: meshes.translate_line.clone(), + material: mats.translate_y.clone(), + transform: Transform { + rotation: ROT_Y, + translation: vec3(0., 0.6, 0.), + ..default() + }, + ..default() + }, + )); + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::Axis(Vec3::Y), + MaterialMeshBundle { + mesh: meshes.translate_arrow.clone(), + material: mats.translate_y.clone(), + transform: Transform { + rotation: ROT_Y, + translation: vec3(0., 1., 0.), + ..default() + }, + ..default() + }, + )); - // Z - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::Axis(Vec3::Z), - MaterialMeshBundle { - mesh: meshes.translate_line.clone(), - material: mats.translate_z.clone(), - transform: Transform { - rotation: ROT_Z, - translation: vec3(0., 0., 0.6), - ..default() - }, - ..default() - }, - )); - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::Axis(Vec3::Z), - MaterialMeshBundle { - mesh: meshes.translate_arrow.clone(), - material: mats.translate_z.clone(), - transform: Transform { - rotation: ROT_Z, - translation: vec3(0., 0., 1.), - ..default() - }, - ..default() - }, - )); + // Z + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::Axis(Vec3::Z), + MaterialMeshBundle { + mesh: meshes.translate_line.clone(), + material: mats.translate_z.clone(), + transform: Transform { + rotation: ROT_Z, + translation: vec3(0., 0., 0.6), + ..default() + }, + ..default() + }, + )); + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::Axis(Vec3::Z), + MaterialMeshBundle { + mesh: meshes.translate_arrow.clone(), + material: mats.translate_z.clone(), + transform: Transform { + rotation: ROT_Z, + translation: vec3(0., 0., 1.), + ..default() + }, + ..default() + }, + )); - // YZ Plane - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::Plane(Vec3::X), - MaterialMeshBundle { - mesh: meshes.translate_plane.clone(), - material: mats.translate_yz.clone(), - transform: Transform { - rotation: ROT_X, - translation: vec3(0., CIRC_45, CIRC_45), - ..default() - }, - ..default() - }, - )); - // XZ Plane - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::Plane(Vec3::Y), - MaterialMeshBundle { - mesh: meshes.translate_plane.clone(), - material: mats.translate_xz.clone(), - transform: Transform { - rotation: ROT_Y, - translation: vec3(CIRC_45, 0., CIRC_45), - ..default() - }, - ..default() - }, - )); - // XY Plane - cmd.spawn(( - NotShadowCaster, - RenderLayers::layer(GIZMO_RENDER_LAYER), - TranslationWidget::Plane(Vec3::Z), - MaterialMeshBundle { - mesh: meshes.translate_plane.clone(), - material: mats.translate_xy.clone(), - transform: Transform { - rotation: ROT_Z, - translation: vec3(CIRC_45, CIRC_45, 0.), - ..default() - }, - ..default() - }, - )); - }); - }); + // YZ Plane + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::Plane(Vec3::X), + MaterialMeshBundle { + mesh: meshes.translate_plane.clone(), + material: mats.translate_yz.clone(), + transform: Transform { + rotation: ROT_X, + translation: vec3(0., CIRC_45, CIRC_45), + ..default() + }, + ..default() + }, + )); + // XZ Plane + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::Plane(Vec3::Y), + MaterialMeshBundle { + mesh: meshes.translate_plane.clone(), + material: mats.translate_xz.clone(), + transform: Transform { + rotation: ROT_Y, + translation: vec3(CIRC_45, 0., CIRC_45), + ..default() + }, + ..default() + }, + )); + // XY Plane + cmd.spawn(( + NotShadowCaster, + RenderLayers::layer(GIZMO_RENDER_LAYER), + TranslationWidget::Plane(Vec3::Z), + MaterialMeshBundle { + mesh: meshes.translate_plane.clone(), + material: mats.translate_xy.clone(), + transform: Transform { + rotation: ROT_Z, + translation: vec3(CIRC_45, CIRC_45, 0.), + ..default() + }, + ..default() + }, + )); + }); } pub(super) fn on_translation_start( _: Listener>, mut cmd: Commands, - q_xform: Query<(Entity, &GlobalTransform), With>, + q_xform: Query<(Entity, &GlobalTransform)>, + q_gizmos: Query<&TransformGizmo>, ) { - if let Ok((ent, &world_xform)) = q_xform.get_single() { - cmd.entity(ent).insert(InitialTransform(world_xform)); - }; + for gizmo_data in q_gizmos.iter() { + if let Ok((ent, &world_xform)) = q_xform.get(gizmo_data.target) { + cmd.entity(ent).insert(InitialTransform(world_xform)); + } + } } pub(super) fn on_translation_end( - _: &ListenerInput>, - cmd: &mut EntityCommands<'_, '_, '_>, + _: Listener>, + mut cmd: Commands, + q_initial_transforms: Query>, ) { - cmd.remove::(); + for ent in q_initial_transforms.iter() { + cmd.entity(ent).remove::(); + } } pub(super) fn on_translate( event: Listener>, - mut q_root: Query<(&mut Transform, &InitialTransform), With>, + mut q_root: Query<(&mut Transform, &InitialTransform, Option<&Parent>)>, q_camera: Query<(&Camera, &GlobalTransform), With>, - q_gizmo: Query<&GlobalTransform, (With, Without)>, + q_gizmo: Query<(&GlobalTransform, &TransformGizmo), Without>, q_widget: Query<&TranslationWidget>, + q_all_global_transforms: Query<&GlobalTransform>, ) { - let (mut xform, init_xform) = q_root.single_mut(); - let gizmo_xform = q_gizmo.single(); + let (gizmo_xform, gizmo_data) = q_gizmo.single(); + let Ok((mut target_transform, target_global_transform, target_parent)) = + q_root.get_mut(gizmo_data.target) + else { + error!("Translation gizmo target not found"); + return; + }; let (cam, cam_xform) = q_camera.single(); // Find the initial origin point in screen-space and add the total screen-space drag distance - let origin_ws = init_xform.translation(); + let origin_ws = target_global_transform.translation(); let origin_ss = cam.world_to_viewport(cam_xform, origin_ws).unwrap(); let target_ss = origin_ss + event.distance; @@ -265,7 +268,18 @@ pub(super) fn on_translate( let projection_length = drag_vector.dot(axis_ws); let target_ws = origin_ws + axis_ws * projection_length; - xform.translation = target_ws; + if let Some(target_parent) = target_parent { + if let Ok(parent_global_transform) = + q_all_global_transforms.get(target_parent.get()) + { + let real_local_transform = + GlobalTransform::from(Transform::from_translation(target_ws)) + .reparented_to(parent_global_transform); + target_transform.translation = real_local_transform.translation; + } + } else { + target_transform.translation = target_ws; + } } Ok(plane) => { // Find the world-space normal of the plane we're translating on @@ -281,7 +295,18 @@ pub(super) fn on_translate( }; let target_ws = ray.origin + ray.direction * hit_dist; - xform.translation = target_ws; + if let Some(target_parent) = target_parent { + if let Ok(parent_global_transform) = + q_all_global_transforms.get(target_parent.get()) + { + let real_local_transform = + GlobalTransform::from(Transform::from_translation(target_ws)) + .reparented_to(parent_global_transform); + target_transform.translation = real_local_transform.translation; + } + } else { + target_transform.translation = target_ws; + } } _ => {} } diff --git a/studio/src/interaction/transformation.rs b/studio/src/interaction/transformation.rs index c1a5305..e067fb0 100644 --- a/studio/src/interaction/transformation.rs +++ b/studio/src/interaction/transformation.rs @@ -32,7 +32,7 @@ impl Default for TransformMode { } } -#[derive(Clone, Copy, Debug, Default)] +#[derive(Clone, Copy, Debug, Default, Reflect)] #[wasm_bindgen] pub enum TransformSpace { #[default] diff --git a/studio/src/lib.rs b/studio/src/lib.rs index 0fad6f8..3d7a8b7 100644 --- a/studio/src/lib.rs +++ b/studio/src/lib.rs @@ -3,6 +3,7 @@ use bevy::prelude::*; use bevy_mod_picking::DefaultPickingPlugins; +use space_editor::prelude::space_undo::UndoPlugin; #[cfg(feature = "wasm")] use wasm_bindgen::prelude::*; @@ -79,7 +80,19 @@ pub fn init(viewport_size: ViewportSize) { SkyboxPlugin, UiLayerPlugin, WorldGridPlugin, - )); + UndoPlugin, + )) + .add_systems( + Startup, + move |mut cmd: Commands, mut ew: EventWriter| { + cmd.insert_resource(SkyboxId("gum_trees_4k".to_string())); + ew.send(LoadSceneEvent("bookcase".to_string())); + }, + ); + + // Only for registering components for undo + use space_editor::prelude::space_undo::AppAutoUndo; + app.auto_reflected_undo::(); #[cfg(feature = "wasm")] wasm::initialize(); @@ -134,6 +147,7 @@ pub fn start_viewer( SkyboxPlugin, UiLayerPlugin, WorldGridPlugin, + UndoPlugin, )) .add_systems( Startup, @@ -143,6 +157,10 @@ pub fn start_viewer( }, ); + // Only for registering components for undo + use space_editor::prelude::space_undo::AppAutoUndo; + app.auto_reflected_undo::(); + #[cfg(feature = "wasm")] wasm::initialize(); diff --git a/studio/src/scene.rs b/studio/src/scene.rs index b4cc5c0..ab64c3e 100644 --- a/studio/src/scene.rs +++ b/studio/src/scene.rs @@ -13,6 +13,7 @@ use bevy::{ scene::InstanceId, }; +use space_editor::prelude::{space_undo::OneFrameUndoIgnore, PrefabMarker}; #[cfg(feature = "wasm")] use wasm_bindgen::prelude::wasm_bindgen; @@ -207,6 +208,8 @@ fn spawn_next_scene( SceneRoot, SceneElement, SpatialBundle::default(), + PrefabMarker, + OneFrameUndoIgnore::default(), //To prevert undo try to register add event )) .id(); @@ -254,7 +257,7 @@ fn tag_scene_elements( }; if gltf.named_nodes.contains_key(&**name) { - cmd.entity(ent).insert(SceneElement); + cmd.entity(ent).insert(SceneElement).insert(PrefabMarker); } } }