mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-08 08:45:43 +08:00
Merge branch 'efroemling:master' into master
This commit is contained in:
commit
36127a9021
130
.efrocachemap
generated
130
.efrocachemap
generated
@ -421,42 +421,42 @@
|
|||||||
"build/assets/ba_data/audio/zoeOw.ogg": "74befe45a8417e95b6a2233c51992a26",
|
"build/assets/ba_data/audio/zoeOw.ogg": "74befe45a8417e95b6a2233c51992a26",
|
||||||
"build/assets/ba_data/audio/zoePickup01.ogg": "48ab8cddfcde36a750856f3f81dd20c8",
|
"build/assets/ba_data/audio/zoePickup01.ogg": "48ab8cddfcde36a750856f3f81dd20c8",
|
||||||
"build/assets/ba_data/audio/zoeScream01.ogg": "2b468aedfa8741090247f04eb9e6df55",
|
"build/assets/ba_data/audio/zoeScream01.ogg": "2b468aedfa8741090247f04eb9e6df55",
|
||||||
"build/assets/ba_data/data/langdata.json": "992c5c5ce292132c4f011f39e0d13de8",
|
"build/assets/ba_data/data/langdata.json": "2a2c4783fddc4b24d07b4ce0d8a74393",
|
||||||
"build/assets/ba_data/data/languages/arabic.json": "d1f900ab5aa2433d402bd46ed1149cc7",
|
"build/assets/ba_data/data/languages/arabic.json": "295c559911fa251f401f8cdcad91c226",
|
||||||
"build/assets/ba_data/data/languages/belarussian.json": "e151808b6b4f6dc159cf55ee62adad3c",
|
"build/assets/ba_data/data/languages/belarussian.json": "e151808b6b4f6dc159cf55ee62adad3c",
|
||||||
"build/assets/ba_data/data/languages/chinese.json": "8d889accdd49334591209bdaf6eaf02f",
|
"build/assets/ba_data/data/languages/chinese.json": "0a9d9534e7329d1e886adae6fdc007c4",
|
||||||
"build/assets/ba_data/data/languages/chinesetraditional.json": "f858da49be0a5374157c627857751078",
|
"build/assets/ba_data/data/languages/chinesetraditional.json": "f858da49be0a5374157c627857751078",
|
||||||
"build/assets/ba_data/data/languages/croatian.json": "766532c67af5bd0144c2d63cab0516fa",
|
"build/assets/ba_data/data/languages/croatian.json": "766532c67af5bd0144c2d63cab0516fa",
|
||||||
"build/assets/ba_data/data/languages/czech.json": "93c5fe0d884d95435da6c675f64e30e0",
|
"build/assets/ba_data/data/languages/czech.json": "93c5fe0d884d95435da6c675f64e30e0",
|
||||||
"build/assets/ba_data/data/languages/danish.json": "3fd69080783d5c9dcc0af737f02b6f1e",
|
"build/assets/ba_data/data/languages/danish.json": "3fd69080783d5c9dcc0af737f02b6f1e",
|
||||||
"build/assets/ba_data/data/languages/dutch.json": "22b44a33bf81142ba2befad14eb5746e",
|
"build/assets/ba_data/data/languages/dutch.json": "22b44a33bf81142ba2befad14eb5746e",
|
||||||
"build/assets/ba_data/data/languages/english.json": "b38d54aecf3ac47b8d8ca97d8bab3006",
|
"build/assets/ba_data/data/languages/english.json": "6fb6ec37e79064edb4b8864eabdd024d",
|
||||||
"build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880",
|
"build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880",
|
||||||
"build/assets/ba_data/data/languages/filipino.json": "347f38524816691170d266708fe25894",
|
"build/assets/ba_data/data/languages/filipino.json": "2efdfb879135b196a272dd47fc2039a2",
|
||||||
"build/assets/ba_data/data/languages/french.json": "d8527da977a563185de25ef02bacf826",
|
"build/assets/ba_data/data/languages/french.json": "4e218dcd488fa63e7db5b4da2261b9e1",
|
||||||
"build/assets/ba_data/data/languages/german.json": "549754d2a530d825200c6126be56df5c",
|
"build/assets/ba_data/data/languages/german.json": "450fa41ae264f29a5d1af22143d0d0ad",
|
||||||
"build/assets/ba_data/data/languages/gibberish.json": "837423db378b3e7679683805826aa26e",
|
"build/assets/ba_data/data/languages/gibberish.json": "63c6212c774622346f3ad0d87ff31e80",
|
||||||
"build/assets/ba_data/data/languages/greek.json": "a65d78f912e9a89f98de004405167a6a",
|
"build/assets/ba_data/data/languages/greek.json": "287c0ec437b38772284ef9d3e4fb2fc3",
|
||||||
"build/assets/ba_data/data/languages/hindi.json": "88ee0cda537bab9ac827def5e236fe1a",
|
"build/assets/ba_data/data/languages/hindi.json": "8ea0c58a44a24edb131d0e53b074d1f6",
|
||||||
"build/assets/ba_data/data/languages/hungarian.json": "796a290a8c44a1e7635208c2ff5fdc6e",
|
"build/assets/ba_data/data/languages/hungarian.json": "796a290a8c44a1e7635208c2ff5fdc6e",
|
||||||
"build/assets/ba_data/data/languages/indonesian.json": "bff88ce57744a639810b93a1d1dd79f4",
|
"build/assets/ba_data/data/languages/indonesian.json": "53961b1484a1831f32bec2cc2941e672",
|
||||||
"build/assets/ba_data/data/languages/italian.json": "338e7a03dff47f4eefc0ca3a995cd4f4",
|
"build/assets/ba_data/data/languages/italian.json": "58ecf53a963dbeca1bbf3605e5ab6a2f",
|
||||||
"build/assets/ba_data/data/languages/korean.json": "ca1122a9ee551da3f75ae632012bd0e2",
|
"build/assets/ba_data/data/languages/korean.json": "ca1122a9ee551da3f75ae632012bd0e2",
|
||||||
"build/assets/ba_data/data/languages/malay.json": "832562ce997fc70704b9234c95fb2e38",
|
"build/assets/ba_data/data/languages/malay.json": "832562ce997fc70704b9234c95fb2e38",
|
||||||
"build/assets/ba_data/data/languages/persian.json": "71cc5b33abda0f285b970b8cc4a014a8",
|
"build/assets/ba_data/data/languages/persian.json": "a391d80ff58ea22926499e4b19d2c0d0",
|
||||||
"build/assets/ba_data/data/languages/polish.json": "e1a1a801851924748ad38fa68216439a",
|
"build/assets/ba_data/data/languages/polish.json": "7a4a6cb882cf90dad32e6607215525bf",
|
||||||
"build/assets/ba_data/data/languages/portuguese.json": "9fcd6b4da9e5d0dc0e337ab00b5debe2",
|
"build/assets/ba_data/data/languages/portuguese.json": "51e362956f89da3eec980f587c092253",
|
||||||
"build/assets/ba_data/data/languages/romanian.json": "aeebdd54f65939c2facc6ac50c117826",
|
"build/assets/ba_data/data/languages/romanian.json": "aeebdd54f65939c2facc6ac50c117826",
|
||||||
"build/assets/ba_data/data/languages/russian.json": "910cf653497654a16d5c4f067d6def22",
|
"build/assets/ba_data/data/languages/russian.json": "561504cca28eb3204ac194950029e565",
|
||||||
"build/assets/ba_data/data/languages/serbian.json": "d7452dd72ac0e51680cb39b5ebaa1c69",
|
"build/assets/ba_data/data/languages/serbian.json": "d7452dd72ac0e51680cb39b5ebaa1c69",
|
||||||
"build/assets/ba_data/data/languages/slovak.json": "27962d53dc3f7dd4e877cd40faafeeef",
|
"build/assets/ba_data/data/languages/slovak.json": "27962d53dc3f7dd4e877cd40faafeeef",
|
||||||
"build/assets/ba_data/data/languages/spanish.json": "0122b0b24aa111ab259af02bbae9b7b6",
|
"build/assets/ba_data/data/languages/spanish.json": "5a4dbd505060dd02d634bd4de4d5faab",
|
||||||
"build/assets/ba_data/data/languages/swedish.json": "77d671f10613291ebf9c71da66f18a18",
|
"build/assets/ba_data/data/languages/swedish.json": "77d671f10613291ebf9c71da66f18a18",
|
||||||
"build/assets/ba_data/data/languages/tamil.json": "b9d4b4e107456ea6420ee0f9d9d7a03e",
|
"build/assets/ba_data/data/languages/tamil.json": "65ab7798d637fa62a703750179eeb723",
|
||||||
"build/assets/ba_data/data/languages/thai.json": "33f63753c9af9a5b238d229a0bf23fbc",
|
"build/assets/ba_data/data/languages/thai.json": "33f63753c9af9a5b238d229a0bf23fbc",
|
||||||
"build/assets/ba_data/data/languages/turkish.json": "9d7e58c9062dc517c3779c255a9b3142",
|
"build/assets/ba_data/data/languages/turkish.json": "776d1a0c9ef2333a9110d93558ab19e2",
|
||||||
"build/assets/ba_data/data/languages/ukrainian.json": "f72eb51abfbbb56e27866895d7e947d2",
|
"build/assets/ba_data/data/languages/ukrainian.json": "f72eb51abfbbb56e27866895d7e947d2",
|
||||||
"build/assets/ba_data/data/languages/venetian.json": "88595b7ee696b4094d7874c3c4188852",
|
"build/assets/ba_data/data/languages/venetian.json": "9fe1a58d9e5dfb00f31ce3b2eb9993f4",
|
||||||
"build/assets/ba_data/data/languages/vietnamese.json": "921cd1e50f60fe3e101f246e172750ba",
|
"build/assets/ba_data/data/languages/vietnamese.json": "921cd1e50f60fe3e101f246e172750ba",
|
||||||
"build/assets/ba_data/data/maps/big_g.json": "1dd301d490643088a435ce75df971054",
|
"build/assets/ba_data/data/maps/big_g.json": "1dd301d490643088a435ce75df971054",
|
||||||
"build/assets/ba_data/data/maps/bridgit.json": "6aea74805f4880cc11237c5734a24422",
|
"build/assets/ba_data/data/maps/bridgit.json": "6aea74805f4880cc11237c5734a24422",
|
||||||
@ -4056,53 +4056,53 @@
|
|||||||
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
|
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
|
||||||
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
|
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
|
||||||
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
|
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
|
||||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "8ea626f6dd70d998ee77c58fffc51545",
|
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "ad13d636bcb25150044a7644846b8a09",
|
||||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "d7ad10904fe7c4d4555366ccb1feedcb",
|
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "7c5df955611590ef491bf614fbd60179",
|
||||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "a9eea92d521e97b1772b5e44b402ce8a",
|
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "ae38bd212ae64b51482a2ccb9c1cbfd3",
|
||||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "57043f40971d800d27ee6d646aae8d61",
|
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "d0bcee2dd5567719aa35667c5206dffc",
|
||||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "3e4009d7fa4b90abc526f56361ecab05",
|
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "eb3cd4f86175afcf8ffa2749afa32fa3",
|
||||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "334cdc0688e66a1bc75cd05bae1729c7",
|
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "6b86ba36c3719773008feaa6cdc0d0f8",
|
||||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "95278d80378be5b61026253492cbfa70",
|
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "877c9ae4532fef809a3dcbd8ffea343c",
|
||||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "0a3da8e5264a7b733960e83a0e8c4bba",
|
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "7df313c48c87460f56fa837502965088",
|
||||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "a089d4aaa39e18553cf0a70a77b4cfcd",
|
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "bc40bb549d26437fb8679c1e9d088272",
|
||||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "e66c4eceb79710b8fda2bfea781e241a",
|
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "47aa08cb9f5e660023f0f3c0e4ffd65e",
|
||||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "6b3021b9a7584da86bbb95324e81e851",
|
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "bbb0a8383d6ce1ca887190ea49223f4f",
|
||||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "6fe90d50f905a0da9fa52c39a458d1e3",
|
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "7dd91e3407d49981c1c975d4f01ac205",
|
||||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "afc7ed826486aec82613832865177570",
|
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "c87883aa2f832e792e945fd9208d712a",
|
||||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "ae8b6dad770793188aad8e2966189bb3",
|
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "fea8fd84d8c060f2f82f402902b8c54e",
|
||||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "7622dde1a021152cac42e7db3e803392",
|
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "0a454a8be47f37231655761d15e3f7e5",
|
||||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "8a4b1e521bf668cc6ec6a65519defb12",
|
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "4c79db3a882eb0b8b225a8df0339b1cc",
|
||||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "9a69c0d4c9ae319595843b16f14795fc",
|
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "43b9ef321f8e80da29ddb19a760dbd77",
|
||||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "89c02260fb4781f5e293658cecbb363f",
|
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "6f891004f2f07c452dea29bd53f29d30",
|
||||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "3165d4230069c22300abfff8abf1d714",
|
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "bf7a1ce0e7a2015d538406c6f6df761c",
|
||||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "41e46dfdbb542e3e823f6aee87e93ac9",
|
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "cf213dce81901a67c9970b3befdaa320",
|
||||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "20cc128ff9d44f9d74e4301c6d49f48f",
|
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "473e7e6c0cf90b9e6ac653552b18f68d",
|
||||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "f93bc8f98ee31f39b54ab46264eccb22",
|
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "4e11b895cbf2e1339cf34bc06c54a4ea",
|
||||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "20cc128ff9d44f9d74e4301c6d49f48f",
|
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "473e7e6c0cf90b9e6ac653552b18f68d",
|
||||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "f93bc8f98ee31f39b54ab46264eccb22",
|
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "4e11b895cbf2e1339cf34bc06c54a4ea",
|
||||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "1565f3b227843827d692cb3ef65847b6",
|
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "d9af1a429cff9346e0cad6fcea017e5b",
|
||||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "d8d74c6c40db43054ccc7d27920cfbfe",
|
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "ae5f87286947575463c386cfe1c443e4",
|
||||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "1565f3b227843827d692cb3ef65847b6",
|
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "d9af1a429cff9346e0cad6fcea017e5b",
|
||||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "d8d74c6c40db43054ccc7d27920cfbfe",
|
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "ae5f87286947575463c386cfe1c443e4",
|
||||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "43bdfa8acd84e9cf2e443ce8e923c229",
|
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "110eef3dc285a35a1899510e368c73b1",
|
||||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "d935dc21becdfd65bec51c5f5b2fd770",
|
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "2692dc69f7cb2501f0aaa8675f559987",
|
||||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "43bdfa8acd84e9cf2e443ce8e923c229",
|
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "110eef3dc285a35a1899510e368c73b1",
|
||||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "d935dc21becdfd65bec51c5f5b2fd770",
|
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "2692dc69f7cb2501f0aaa8675f559987",
|
||||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "6d49ad39f194480da458b431405f5a2b",
|
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "344954c4f788d7d9b4d7035ebb6131d8",
|
||||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "c8715c85010ea431d7346f40f5421819",
|
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "48c4873dae2344c1d4092a1d85dab424",
|
||||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "49775819d4ba9af15061080d17377a18",
|
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "abcede4e60fa8877f18e66e086fb7387",
|
||||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "c8715c85010ea431d7346f40f5421819",
|
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "48c4873dae2344c1d4092a1d85dab424",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "750c2964308cd3f3e5986fcda9a25706",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "6149911c660a9864b651cc1a8e50eec1",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "772af7da6a115f53b0b3f6a4afd3baec",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "57cef68ab703ba819bd0fbe9e4b1c331",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "178c1a53a7ad50297aed68d0ca3a1476",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "a47bab28b86c7cefce891b8e5c8b687a",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "b011bc2b6437995f2d33f5215b4ffa36",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "d68ebb1139363d711b044de65e17b204",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "a758a4f98336208381b093aacb735878",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "ea1349137f64f3d662b9a95278ca4c02",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "6c86545fab2327105114676a20ca5e68",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "c8731ff226716cee3d1e46027ead1cfe",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "f75525fdc9f7db4a81ca9bae6a79add5",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "4ee6b633a99c5bcbea4f5dee5bda186e",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "2e297069baec404d43ccdb18abeef658",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "2c3bd4952b30d88247229ad309f73092",
|
||||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
||||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "28323912b56ec07701eda3d41a6a4101",
|
"src/assets/ba_data/python/babase/_mgen/enums.py": "28323912b56ec07701eda3d41a6a4101",
|
||||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "ba8ce3ca3858b4c2d20db68f99b788b2",
|
"src/ballistica/base/mgen/pyembed/binding_base.inc": "6df0f34207346d89a72924249ddd4706",
|
||||||
"src/ballistica/base/mgen/pyembed/binding_base_app.inc": "00f81f9bd92386ec12a6e60170678a98",
|
"src/ballistica/base/mgen/pyembed/binding_base_app.inc": "00f81f9bd92386ec12a6e60170678a98",
|
||||||
"src/ballistica/classic/mgen/pyembed/binding_classic.inc": "3ceb412513963f0818ab39c58bf292e3",
|
"src/ballistica/classic/mgen/pyembed/binding_classic.inc": "3ceb412513963f0818ab39c58bf292e3",
|
||||||
"src/ballistica/core/mgen/pyembed/binding_core.inc": "9d0a3c9636138e35284923e0c8311c69",
|
"src/ballistica/core/mgen/pyembed/binding_core.inc": "9d0a3c9636138e35284923e0c8311c69",
|
||||||
|
|||||||
11
CHANGELOG.md
11
CHANGELOG.md
@ -1,4 +1,4 @@
|
|||||||
### 1.7.28 (build 21465, api 8, 2023-10-14)
|
### 1.7.28 (build 21491, api 8, 2023-10-22)
|
||||||
|
|
||||||
- Massively cleaned up code related to rendering and window systems (OpenGL,
|
- Massively cleaned up code related to rendering and window systems (OpenGL,
|
||||||
SDL, etc). This code had been growing into a nasty tangle for 15 years
|
SDL, etc). This code had been growing into a nasty tangle for 15 years
|
||||||
@ -146,7 +146,14 @@
|
|||||||
rates are high.
|
rates are high.
|
||||||
- Added a proper graceful shutdown process for the audio server. This should
|
- Added a proper graceful shutdown process for the audio server. This should
|
||||||
result in fewer ugly pops and warning messages when the app is quit.
|
result in fewer ugly pops and warning messages when the app is quit.
|
||||||
|
- Tidied up some keyboard shortcuts to be more platform-appropriate. For
|
||||||
|
example, toggling fullscreen on Windows is now Alt+Enter or F11.
|
||||||
|
- Fancy rebuilt Mac build should now automatically sync its frame rate to the
|
||||||
|
display its running on (using CVDisplayLinks, not VSync).
|
||||||
|
- Mac build is now relying solely on Apple's Game Controller Framework, which
|
||||||
|
seems pretty awesome these days. It should support most stuff SDL does and
|
||||||
|
with less configuring involved. Please holler if you come across something
|
||||||
|
that doesn't work.
|
||||||
|
|
||||||
### 1.7.27 (build 21282, api 8, 2023-08-30)
|
### 1.7.27 (build 21282, api 8, 2023-08-30)
|
||||||
|
|
||||||
|
|||||||
@ -353,6 +353,10 @@ set(BALLISTICA_SOURCES
|
|||||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/camera.h
|
${BA_SRC_ROOT}/ballistica/base/graphics/support/camera.h
|
||||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/frame_def.cc
|
${BA_SRC_ROOT}/ballistica/base/graphics/support/frame_def.cc
|
||||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/frame_def.h
|
${BA_SRC_ROOT}/ballistica/base/graphics/support/frame_def.h
|
||||||
|
${BA_SRC_ROOT}/ballistica/base/graphics/support/graphics_client_context.cc
|
||||||
|
${BA_SRC_ROOT}/ballistica/base/graphics/support/graphics_client_context.h
|
||||||
|
${BA_SRC_ROOT}/ballistica/base/graphics/support/graphics_settings.cc
|
||||||
|
${BA_SRC_ROOT}/ballistica/base/graphics/support/graphics_settings.h
|
||||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/net_graph.cc
|
${BA_SRC_ROOT}/ballistica/base/graphics/support/net_graph.cc
|
||||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/net_graph.h
|
${BA_SRC_ROOT}/ballistica/base/graphics/support/net_graph.h
|
||||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/render_command_buffer.h
|
${BA_SRC_ROOT}/ballistica/base/graphics/support/render_command_buffer.h
|
||||||
@ -688,6 +692,7 @@ set(BALLISTICA_SOURCES
|
|||||||
${BA_SRC_ROOT}/ballistica/shared/generic/lambda_runnable.h
|
${BA_SRC_ROOT}/ballistica/shared/generic/lambda_runnable.h
|
||||||
${BA_SRC_ROOT}/ballistica/shared/generic/runnable.cc
|
${BA_SRC_ROOT}/ballistica/shared/generic/runnable.cc
|
||||||
${BA_SRC_ROOT}/ballistica/shared/generic/runnable.h
|
${BA_SRC_ROOT}/ballistica/shared/generic/runnable.h
|
||||||
|
${BA_SRC_ROOT}/ballistica/shared/generic/snapshot.h
|
||||||
${BA_SRC_ROOT}/ballistica/shared/generic/timer_list.cc
|
${BA_SRC_ROOT}/ballistica/shared/generic/timer_list.cc
|
||||||
${BA_SRC_ROOT}/ballistica/shared/generic/timer_list.h
|
${BA_SRC_ROOT}/ballistica/shared/generic/timer_list.h
|
||||||
${BA_SRC_ROOT}/ballistica/shared/generic/utf8.cc
|
${BA_SRC_ROOT}/ballistica/shared/generic/utf8.cc
|
||||||
|
|||||||
@ -345,6 +345,10 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\camera.h" />
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\camera.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\frame_def.cc" />
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\frame_def.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\frame_def.h" />
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\frame_def.h" />
|
||||||
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.cc" />
|
||||||
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.h" />
|
||||||
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_settings.cc" />
|
||||||
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_settings.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\net_graph.cc" />
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\net_graph.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\net_graph.h" />
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\net_graph.h" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\render_command_buffer.h" />
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\render_command_buffer.h" />
|
||||||
@ -680,6 +684,7 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\shared\generic\lambda_runnable.h" />
|
<ClInclude Include="..\..\src\ballistica\shared\generic\lambda_runnable.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\shared\generic\runnable.cc" />
|
<ClCompile Include="..\..\src\ballistica\shared\generic\runnable.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\shared\generic\runnable.h" />
|
<ClInclude Include="..\..\src\ballistica\shared\generic\runnable.h" />
|
||||||
|
<ClInclude Include="..\..\src\ballistica\shared\generic\snapshot.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\shared\generic\timer_list.cc" />
|
<ClCompile Include="..\..\src\ballistica\shared\generic\timer_list.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\shared\generic\timer_list.h" />
|
<ClInclude Include="..\..\src\ballistica\shared\generic\timer_list.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\shared\generic\utf8.cc" />
|
<ClCompile Include="..\..\src\ballistica\shared\generic\utf8.cc" />
|
||||||
|
|||||||
@ -469,6 +469,18 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\frame_def.h">
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\frame_def.h">
|
||||||
<Filter>ballistica\base\graphics\support</Filter>
|
<Filter>ballistica\base\graphics\support</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.cc">
|
||||||
|
<Filter>ballistica\base\graphics\support</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.h">
|
||||||
|
<Filter>ballistica\base\graphics\support</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_settings.cc">
|
||||||
|
<Filter>ballistica\base\graphics\support</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_settings.h">
|
||||||
|
<Filter>ballistica\base\graphics\support</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\net_graph.cc">
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\net_graph.cc">
|
||||||
<Filter>ballistica\base\graphics\support</Filter>
|
<Filter>ballistica\base\graphics\support</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -1474,6 +1486,9 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\shared\generic\runnable.h">
|
<ClInclude Include="..\..\src\ballistica\shared\generic\runnable.h">
|
||||||
<Filter>ballistica\shared\generic</Filter>
|
<Filter>ballistica\shared\generic</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ballistica\shared\generic\snapshot.h">
|
||||||
|
<Filter>ballistica\shared\generic</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\ballistica\shared\generic\timer_list.cc">
|
<ClCompile Include="..\..\src\ballistica\shared\generic\timer_list.cc">
|
||||||
<Filter>ballistica\shared\generic</Filter>
|
<Filter>ballistica\shared\generic</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
@ -340,6 +340,10 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\camera.h" />
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\camera.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\frame_def.cc" />
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\frame_def.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\frame_def.h" />
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\frame_def.h" />
|
||||||
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.cc" />
|
||||||
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.h" />
|
||||||
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_settings.cc" />
|
||||||
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_settings.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\net_graph.cc" />
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\net_graph.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\net_graph.h" />
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\net_graph.h" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\render_command_buffer.h" />
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\render_command_buffer.h" />
|
||||||
@ -675,6 +679,7 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\shared\generic\lambda_runnable.h" />
|
<ClInclude Include="..\..\src\ballistica\shared\generic\lambda_runnable.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\shared\generic\runnable.cc" />
|
<ClCompile Include="..\..\src\ballistica\shared\generic\runnable.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\shared\generic\runnable.h" />
|
<ClInclude Include="..\..\src\ballistica\shared\generic\runnable.h" />
|
||||||
|
<ClInclude Include="..\..\src\ballistica\shared\generic\snapshot.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\shared\generic\timer_list.cc" />
|
<ClCompile Include="..\..\src\ballistica\shared\generic\timer_list.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\shared\generic\timer_list.h" />
|
<ClInclude Include="..\..\src\ballistica\shared\generic\timer_list.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\shared\generic\utf8.cc" />
|
<ClCompile Include="..\..\src\ballistica\shared\generic\utf8.cc" />
|
||||||
|
|||||||
@ -469,6 +469,18 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\frame_def.h">
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\frame_def.h">
|
||||||
<Filter>ballistica\base\graphics\support</Filter>
|
<Filter>ballistica\base\graphics\support</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.cc">
|
||||||
|
<Filter>ballistica\base\graphics\support</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.h">
|
||||||
|
<Filter>ballistica\base\graphics\support</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_settings.cc">
|
||||||
|
<Filter>ballistica\base\graphics\support</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_settings.h">
|
||||||
|
<Filter>ballistica\base\graphics\support</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\net_graph.cc">
|
<ClCompile Include="..\..\src\ballistica\base\graphics\support\net_graph.cc">
|
||||||
<Filter>ballistica\base\graphics\support</Filter>
|
<Filter>ballistica\base\graphics\support</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -1474,6 +1486,9 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\shared\generic\runnable.h">
|
<ClInclude Include="..\..\src\ballistica\shared\generic\runnable.h">
|
||||||
<Filter>ballistica\shared\generic</Filter>
|
<Filter>ballistica\shared\generic</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ballistica\shared\generic\snapshot.h">
|
||||||
|
<Filter>ballistica\shared\generic</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\ballistica\shared\generic\timer_list.cc">
|
<ClCompile Include="..\..\src\ballistica\shared\generic\timer_list.cc">
|
||||||
<Filter>ballistica\shared\generic</Filter>
|
<Filter>ballistica\shared\generic</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
@ -27,7 +27,10 @@ from _babase import (
|
|||||||
apptime,
|
apptime,
|
||||||
apptimer,
|
apptimer,
|
||||||
AppTimer,
|
AppTimer,
|
||||||
can_toggle_fullscreen,
|
fullscreen_control_available,
|
||||||
|
fullscreen_control_get,
|
||||||
|
fullscreen_control_key_shortcut,
|
||||||
|
fullscreen_control_set,
|
||||||
charstr,
|
charstr,
|
||||||
clipboard_get_text,
|
clipboard_get_text,
|
||||||
clipboard_has_text,
|
clipboard_has_text,
|
||||||
@ -200,7 +203,10 @@ __all__ = [
|
|||||||
'apptimer',
|
'apptimer',
|
||||||
'AppTimer',
|
'AppTimer',
|
||||||
'Call',
|
'Call',
|
||||||
'can_toggle_fullscreen',
|
'fullscreen_control_available',
|
||||||
|
'fullscreen_control_get',
|
||||||
|
'fullscreen_control_key_shortcut',
|
||||||
|
'fullscreen_control_set',
|
||||||
'charstr',
|
'charstr',
|
||||||
'clipboard_get_text',
|
'clipboard_get_text',
|
||||||
'clipboard_has_text',
|
'clipboard_has_text',
|
||||||
|
|||||||
@ -895,10 +895,18 @@ class App:
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
# Spin and wait for anything blocking shutdown to complete.
|
# Spin and wait for anything blocking shutdown to complete.
|
||||||
|
starttime = _babase.apptime()
|
||||||
_babase.lifecyclelog('shutdown-suppress wait begin')
|
_babase.lifecyclelog('shutdown-suppress wait begin')
|
||||||
while _babase.shutdown_suppress_count() > 0:
|
while _babase.shutdown_suppress_count() > 0:
|
||||||
await asyncio.sleep(0.001)
|
await asyncio.sleep(0.001)
|
||||||
_babase.lifecyclelog('shutdown-suppress wait end')
|
_babase.lifecyclelog('shutdown-suppress wait end')
|
||||||
|
duration = _babase.apptime() - starttime
|
||||||
|
if duration > 1.0:
|
||||||
|
logging.warning(
|
||||||
|
'Shutdown-suppressions lasted longer than ideal '
|
||||||
|
'(%.2f seconds).',
|
||||||
|
duration,
|
||||||
|
)
|
||||||
|
|
||||||
async def _fade_and_shutdown_graphics(self) -> None:
|
async def _fade_and_shutdown_graphics(self) -> None:
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|||||||
@ -185,10 +185,8 @@ def _feed_logs_to_babase(log_handler: LogHandler) -> None:
|
|||||||
def _on_log(entry: LogEntry) -> None:
|
def _on_log(entry: LogEntry) -> None:
|
||||||
# Forward this along to the engine to display in the in-app
|
# Forward this along to the engine to display in the in-app
|
||||||
# console, in the Android log, etc.
|
# console, in the Android log, etc.
|
||||||
_babase.display_log(
|
_babase.emit_log(
|
||||||
name=entry.name,
|
name=entry.name, level=entry.level.name, message=entry.message
|
||||||
level=entry.level.name,
|
|
||||||
message=entry.message,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# We also want to feed some logs to the old v1-cloud-log system.
|
# We also want to feed some logs to the old v1-cloud-log system.
|
||||||
|
|||||||
@ -33,18 +33,30 @@ def reset_to_main_menu() -> None:
|
|||||||
logging.warning('reset_to_main_menu: no-op due to classic not present.')
|
logging.warning('reset_to_main_menu: no-op due to classic not present.')
|
||||||
|
|
||||||
|
|
||||||
def set_config_fullscreen_on() -> None:
|
def store_config_fullscreen_on() -> None:
|
||||||
"""The OS has changed our fullscreen state and we should take note."""
|
"""The OS has changed our fullscreen state and we should take note."""
|
||||||
_babase.app.config['Fullscreen'] = True
|
_babase.app.config['Fullscreen'] = True
|
||||||
_babase.app.config.commit()
|
_babase.app.config.commit()
|
||||||
|
|
||||||
|
|
||||||
def set_config_fullscreen_off() -> None:
|
def store_config_fullscreen_off() -> None:
|
||||||
"""The OS has changed our fullscreen state and we should take note."""
|
"""The OS has changed our fullscreen state and we should take note."""
|
||||||
_babase.app.config['Fullscreen'] = False
|
_babase.app.config['Fullscreen'] = False
|
||||||
_babase.app.config.commit()
|
_babase.app.config.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def set_config_fullscreen_on() -> None:
|
||||||
|
"""Set and store fullscreen state"""
|
||||||
|
_babase.app.config['Fullscreen'] = True
|
||||||
|
_babase.app.config.apply_and_commit()
|
||||||
|
|
||||||
|
|
||||||
|
def set_config_fullscreen_off() -> None:
|
||||||
|
"""The OS has changed our fullscreen state and we should take note."""
|
||||||
|
_babase.app.config['Fullscreen'] = False
|
||||||
|
_babase.app.config.apply_and_commit()
|
||||||
|
|
||||||
|
|
||||||
def not_signed_in_screen_message() -> None:
|
def not_signed_in_screen_message() -> None:
|
||||||
from babase._language import Lstr
|
from babase._language import Lstr
|
||||||
|
|
||||||
@ -377,3 +389,17 @@ def string_edit_adapter_can_be_replaced(adapter: StringEditAdapter) -> bool:
|
|||||||
def get_dev_console_tab_names() -> list[str]:
|
def get_dev_console_tab_names() -> list[str]:
|
||||||
"""Return the current set of dev-console tab names."""
|
"""Return the current set of dev-console tab names."""
|
||||||
return [t.name for t in _babase.app.devconsole.tabs]
|
return [t.name for t in _babase.app.devconsole.tabs]
|
||||||
|
|
||||||
|
|
||||||
|
def unsupported_controller_message(name: str) -> None:
|
||||||
|
"""Print a message when an unsupported controller is connected."""
|
||||||
|
from babase._language import Lstr
|
||||||
|
|
||||||
|
# Ick; this can get called early in the bootstrapping process
|
||||||
|
# before we're allowed to load assets. Guard against that.
|
||||||
|
if _babase.asset_loads_allowed():
|
||||||
|
_babase.getsimplesound('error').play()
|
||||||
|
_babase.screenmessage(
|
||||||
|
Lstr(resource='unsupportedControllerText', subs=[('${NAME}', name)]),
|
||||||
|
color=(1, 0, 0),
|
||||||
|
)
|
||||||
|
|||||||
@ -40,7 +40,7 @@ if TYPE_CHECKING:
|
|||||||
# the last load. Either way, however, multiple execs will happen in some
|
# the last load. Either way, however, multiple execs will happen in some
|
||||||
# form.
|
# form.
|
||||||
#
|
#
|
||||||
# So we need to do a few things to handle that situation gracefully.
|
# To handle that situation gracefully, we need to do a few things:
|
||||||
#
|
#
|
||||||
# - First, we need to store any mutable global state in the __main__
|
# - First, we need to store any mutable global state in the __main__
|
||||||
# module; not in ourself. This way, alternate versions of ourself will
|
# module; not in ourself. This way, alternate versions of ourself will
|
||||||
@ -48,11 +48,11 @@ if TYPE_CHECKING:
|
|||||||
#
|
#
|
||||||
# - Second, we should avoid the use of isinstance and similar calls for
|
# - Second, we should avoid the use of isinstance and similar calls for
|
||||||
# our types. An EnvConfig we create would technically be a different
|
# our types. An EnvConfig we create would technically be a different
|
||||||
# type than that created by an alternate baenv.
|
# type than an EnvConfig created by an alternate baenv.
|
||||||
|
|
||||||
# Build number and version of the ballistica binary we expect to be
|
# Build number and version of the ballistica binary we expect to be
|
||||||
# using.
|
# using.
|
||||||
TARGET_BALLISTICA_BUILD = 21465
|
TARGET_BALLISTICA_BUILD = 21491
|
||||||
TARGET_BALLISTICA_VERSION = '1.7.28'
|
TARGET_BALLISTICA_VERSION = '1.7.28'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,10 @@ from babase import (
|
|||||||
apptimer,
|
apptimer,
|
||||||
AppTimer,
|
AppTimer,
|
||||||
Call,
|
Call,
|
||||||
can_toggle_fullscreen,
|
fullscreen_control_available,
|
||||||
|
fullscreen_control_get,
|
||||||
|
fullscreen_control_key_shortcut,
|
||||||
|
fullscreen_control_set,
|
||||||
charstr,
|
charstr,
|
||||||
clipboard_is_supported,
|
clipboard_is_supported,
|
||||||
clipboard_set_text,
|
clipboard_set_text,
|
||||||
@ -139,7 +142,10 @@ __all__ = [
|
|||||||
'buttonwidget',
|
'buttonwidget',
|
||||||
'Call',
|
'Call',
|
||||||
'can_show_ad',
|
'can_show_ad',
|
||||||
'can_toggle_fullscreen',
|
'fullscreen_control_available',
|
||||||
|
'fullscreen_control_get',
|
||||||
|
'fullscreen_control_key_shortcut',
|
||||||
|
'fullscreen_control_set',
|
||||||
'charstr',
|
'charstr',
|
||||||
'checkboxwidget',
|
'checkboxwidget',
|
||||||
'clipboard_is_supported',
|
'clipboard_is_supported',
|
||||||
|
|||||||
@ -704,7 +704,7 @@ class AccountSettingsWindow(bui.Window):
|
|||||||
position=((self._sub_width - button_width) * 0.5, v + 30),
|
position=((self._sub_width - button_width) * 0.5, v + 30),
|
||||||
autoselect=True,
|
autoselect=True,
|
||||||
size=(button_width, 60),
|
size=(button_width, 60),
|
||||||
label=bui.Lstr(resource=self._r + '.manageAccountText'),
|
label=bui.Lstr(resource=f'{self._r}.manageAccountText'),
|
||||||
color=(0.55, 0.5, 0.6),
|
color=(0.55, 0.5, 0.6),
|
||||||
icon=bui.gettexture('settingsIcon'),
|
icon=bui.gettexture('settingsIcon'),
|
||||||
textcolor=(0.75, 0.7, 0.8),
|
textcolor=(0.75, 0.7, 0.8),
|
||||||
|
|||||||
@ -98,9 +98,11 @@ class ControlsSettingsWindow(bui.Window):
|
|||||||
# made-for-iOS/Mac systems
|
# made-for-iOS/Mac systems
|
||||||
# (we can run into problems where devices register as one of each
|
# (we can run into problems where devices register as one of each
|
||||||
# type otherwise)..
|
# type otherwise)..
|
||||||
|
# UPDATE: We always use the apple system these days (which should
|
||||||
|
# support older controllers). So no need for a switch.
|
||||||
show_mac_controller_subsystem = False
|
show_mac_controller_subsystem = False
|
||||||
if platform == 'mac' and bui.is_xcode_build():
|
# if platform == 'mac' and bui.is_xcode_build():
|
||||||
show_mac_controller_subsystem = True
|
# show_mac_controller_subsystem = True
|
||||||
|
|
||||||
if show_mac_controller_subsystem:
|
if show_mac_controller_subsystem:
|
||||||
height += spacing * 1.5
|
height += spacing * 1.5
|
||||||
@ -311,6 +313,7 @@ class ControlsSettingsWindow(bui.Window):
|
|||||||
maxwidth=width * 0.8,
|
maxwidth=width * 0.8,
|
||||||
)
|
)
|
||||||
v -= spacing
|
v -= spacing
|
||||||
|
|
||||||
if show_mac_controller_subsystem:
|
if show_mac_controller_subsystem:
|
||||||
PopupMenu(
|
PopupMenu(
|
||||||
parent=self._root_widget,
|
parent=self._root_widget,
|
||||||
|
|||||||
@ -29,16 +29,16 @@ def gamepad_configure_callback(event: dict[str, Any]) -> None:
|
|||||||
logging.exception('Error transitioning out main_menu_window.')
|
logging.exception('Error transitioning out main_menu_window.')
|
||||||
bui.getsound('activateBeep').play()
|
bui.getsound('activateBeep').play()
|
||||||
bui.getsound('swish').play()
|
bui.getsound('swish').play()
|
||||||
inputdevice = event['input_device']
|
device = event['input_device']
|
||||||
assert isinstance(inputdevice, bs.InputDevice)
|
assert isinstance(device, bs.InputDevice)
|
||||||
if inputdevice.allows_configuring:
|
if device.allows_configuring:
|
||||||
bui.app.ui_v1.set_main_menu_window(
|
bui.app.ui_v1.set_main_menu_window(
|
||||||
gamepad.GamepadSettingsWindow(inputdevice).get_root_widget()
|
gamepad.GamepadSettingsWindow(device).get_root_widget()
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
width = 700
|
width = 700
|
||||||
height = 200
|
height = 200
|
||||||
button_width = 100
|
button_width = 80
|
||||||
uiscale = bui.app.ui_v1.uiscale
|
uiscale = bui.app.ui_v1.uiscale
|
||||||
dlg = bui.containerwidget(
|
dlg = bui.containerwidget(
|
||||||
scale=(
|
scale=(
|
||||||
@ -52,8 +52,13 @@ def gamepad_configure_callback(event: dict[str, Any]) -> None:
|
|||||||
transition='in_right',
|
transition='in_right',
|
||||||
)
|
)
|
||||||
bui.app.ui_v1.set_main_menu_window(dlg)
|
bui.app.ui_v1.set_main_menu_window(dlg)
|
||||||
device_name = inputdevice.name
|
|
||||||
if device_name == 'iDevice':
|
if device.allows_configuring_in_system_settings:
|
||||||
|
msg = bui.Lstr(
|
||||||
|
resource='configureDeviceInSystemSettingsText',
|
||||||
|
subs=[('${DEVICE}', device.name)],
|
||||||
|
)
|
||||||
|
elif device.is_controller_app:
|
||||||
msg = bui.Lstr(
|
msg = bui.Lstr(
|
||||||
resource='bsRemoteConfigureInAppText',
|
resource='bsRemoteConfigureInAppText',
|
||||||
subs=[('${REMOTE_APP_NAME}', bui.get_remote_app_name())],
|
subs=[('${REMOTE_APP_NAME}', bui.get_remote_app_name())],
|
||||||
@ -61,7 +66,7 @@ def gamepad_configure_callback(event: dict[str, Any]) -> None:
|
|||||||
else:
|
else:
|
||||||
msg = bui.Lstr(
|
msg = bui.Lstr(
|
||||||
resource='cantConfigureDeviceText',
|
resource='cantConfigureDeviceText',
|
||||||
subs=[('${DEVICE}', device_name)],
|
subs=[('${DEVICE}', device.name)],
|
||||||
)
|
)
|
||||||
bui.textwidget(
|
bui.textwidget(
|
||||||
parent=dlg,
|
parent=dlg,
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class GraphicsSettingsWindow(bui.Window):
|
|||||||
self._show_fullscreen = False
|
self._show_fullscreen = False
|
||||||
fullscreen_spacing_top = spacing * 0.2
|
fullscreen_spacing_top = spacing * 0.2
|
||||||
fullscreen_spacing = spacing * 1.2
|
fullscreen_spacing = spacing * 1.2
|
||||||
if bui.can_toggle_fullscreen():
|
if bui.fullscreen_control_available():
|
||||||
self._show_fullscreen = True
|
self._show_fullscreen = True
|
||||||
height += fullscreen_spacing + fullscreen_spacing_top
|
height += fullscreen_spacing + fullscreen_spacing_top
|
||||||
|
|
||||||
@ -122,21 +122,29 @@ class GraphicsSettingsWindow(bui.Window):
|
|||||||
self._fullscreen_checkbox: bui.Widget | None = None
|
self._fullscreen_checkbox: bui.Widget | None = None
|
||||||
if self._show_fullscreen:
|
if self._show_fullscreen:
|
||||||
v -= fullscreen_spacing_top
|
v -= fullscreen_spacing_top
|
||||||
self._fullscreen_checkbox = ConfigCheckBox(
|
# Fullscreen control does not necessarily talk to the
|
||||||
|
# app config so we have to wrangle it manually instead of
|
||||||
|
# using a config-checkbox.
|
||||||
|
label = bui.Lstr(resource=f'{self._r}.fullScreenText')
|
||||||
|
|
||||||
|
# Show keyboard shortcut alongside the control if they
|
||||||
|
# provide one.
|
||||||
|
shortcut = bui.fullscreen_control_key_shortcut()
|
||||||
|
if shortcut is not None:
|
||||||
|
label = bui.Lstr(
|
||||||
|
value='$(NAME) [$(SHORTCUT)]',
|
||||||
|
subs=[('$(NAME)', label), ('$(SHORTCUT)', shortcut)],
|
||||||
|
)
|
||||||
|
self._fullscreen_checkbox = bui.checkboxwidget(
|
||||||
parent=self._root_widget,
|
parent=self._root_widget,
|
||||||
position=(100, v),
|
position=(100, v),
|
||||||
maxwidth=200,
|
value=bui.fullscreen_control_get(),
|
||||||
|
on_value_change_call=bui.fullscreen_control_set,
|
||||||
|
maxwidth=250,
|
||||||
size=(300, 30),
|
size=(300, 30),
|
||||||
configkey='Fullscreen',
|
text=label,
|
||||||
displayname=bui.Lstr(
|
)
|
||||||
resource=self._r
|
|
||||||
+ (
|
|
||||||
'.fullScreenCmdText'
|
|
||||||
if app.classic.platform == 'mac'
|
|
||||||
else '.fullScreenCtrlText'
|
|
||||||
)
|
|
||||||
),
|
|
||||||
).widget
|
|
||||||
if not self._have_selected_child:
|
if not self._have_selected_child:
|
||||||
bui.containerwidget(
|
bui.containerwidget(
|
||||||
edit=self._root_widget,
|
edit=self._root_widget,
|
||||||
@ -528,8 +536,10 @@ class GraphicsSettingsWindow(bui.Window):
|
|||||||
and bui.apptime() - self._last_max_fps_set_time > 1.0
|
and bui.apptime() - self._last_max_fps_set_time > 1.0
|
||||||
):
|
):
|
||||||
self._apply_max_fps()
|
self._apply_max_fps()
|
||||||
|
|
||||||
if self._show_fullscreen:
|
if self._show_fullscreen:
|
||||||
|
# Keep the fullscreen checkbox up to date with the current value.
|
||||||
bui.checkboxwidget(
|
bui.checkboxwidget(
|
||||||
edit=self._fullscreen_checkbox,
|
edit=self._fullscreen_checkbox,
|
||||||
value=bui.app.config.resolve('Fullscreen'),
|
value=bui.fullscreen_control_get(),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "ballistica/base/app_adapter/app_adapter.h"
|
#include "ballistica/base/app_adapter/app_adapter.h"
|
||||||
|
|
||||||
#if BA_OSTYPE_ANDROID
|
#if BA_OSTYPE_ANDROID // Remove conditional once android sources are public.
|
||||||
#include "ballistica/base/app_adapter/app_adapter_android.h"
|
#include "ballistica/base/app_adapter/app_adapter_android.h"
|
||||||
#endif
|
#endif
|
||||||
#include "ballistica/base/app_adapter/app_adapter_apple.h"
|
#include "ballistica/base/app_adapter/app_adapter_apple.h"
|
||||||
@ -15,6 +15,8 @@
|
|||||||
#include "ballistica/base/networking/network_reader.h"
|
#include "ballistica/base/networking/network_reader.h"
|
||||||
#include "ballistica/base/networking/networking.h"
|
#include "ballistica/base/networking/networking.h"
|
||||||
#include "ballistica/base/platform/base_platform.h"
|
#include "ballistica/base/platform/base_platform.h"
|
||||||
|
#include "ballistica/base/python/base_python.h"
|
||||||
|
#include "ballistica/base/support/app_config.h"
|
||||||
#include "ballistica/base/support/stress_test.h"
|
#include "ballistica/base/support/stress_test.h"
|
||||||
#include "ballistica/base/ui/ui.h"
|
#include "ballistica/base/ui/ui.h"
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
@ -239,7 +241,7 @@ void AppAdapter::DoExitMainThreadEventLoop() {
|
|||||||
FatalError("DoExitMainThreadEventLoop is not implemented here.");
|
FatalError("DoExitMainThreadEventLoop is not implemented here.");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto AppAdapter::CanToggleFullscreen() -> bool const { return false; }
|
auto AppAdapter::FullscreenControlAvailable() const -> bool { return false; }
|
||||||
|
|
||||||
auto AppAdapter::SupportsVSync() -> bool const { return false; }
|
auto AppAdapter::SupportsVSync() -> bool const { return false; }
|
||||||
|
|
||||||
@ -253,6 +255,29 @@ void AppAdapter::DoPushGraphicsContextRunnable(Runnable* runnable) {
|
|||||||
DoPushMainThreadRunnable(runnable);
|
DoPushMainThreadRunnable(runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto AppAdapter::FullscreenControlGet() const -> bool {
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
|
// By default, just go through config (assume we have full control over
|
||||||
|
// the fullscreen state ourself).
|
||||||
|
return g_base->app_config->Resolve(AppConfig::BoolID::kFullscreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppAdapter::FullscreenControlSet(bool fullscreen) {
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
|
// By default, just set these in the config and apply it (assumes config
|
||||||
|
// changes get plugged into actual fullscreen state).
|
||||||
|
g_base->python->objs()
|
||||||
|
.Get(fullscreen ? BasePython::ObjID::kSetConfigFullscreenOnCall
|
||||||
|
: BasePython::ObjID::kSetConfigFullscreenOffCall)
|
||||||
|
.Call();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AppAdapter::FullscreenControlKeyShortcut() const
|
||||||
|
-> std::optional<std::string> {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void AppAdapter::CursorPositionForDraw(float* x, float* y) {
|
void AppAdapter::CursorPositionForDraw(float* x, float* y) {
|
||||||
assert(x && y);
|
assert(x && y);
|
||||||
|
|
||||||
@ -271,14 +296,23 @@ auto AppAdapter::ShouldUseCursor() -> bool { return true; }
|
|||||||
|
|
||||||
auto AppAdapter::HasHardwareCursor() -> bool { return false; }
|
auto AppAdapter::HasHardwareCursor() -> bool { return false; }
|
||||||
|
|
||||||
void AppAdapter::SetHardwareCursorVisible(bool visible) {
|
void AppAdapter::SetHardwareCursorVisible(bool visible) {}
|
||||||
printf("SHOULD SET VIS %d\n", static_cast<int>(visible));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto AppAdapter::CanSoftQuit() -> bool { return false; }
|
auto AppAdapter::CanSoftQuit() -> bool { return false; }
|
||||||
auto AppAdapter::CanBackQuit() -> bool { return false; }
|
auto AppAdapter::CanBackQuit() -> bool { return false; }
|
||||||
void AppAdapter::DoBackQuit() { FatalError("Fixme unimplemented."); }
|
void AppAdapter::DoBackQuit() { FatalError("Fixme unimplemented."); }
|
||||||
void AppAdapter::DoSoftQuit() { FatalError("Fixme unimplemented."); }
|
void AppAdapter::DoSoftQuit() { FatalError("Fixme unimplemented."); }
|
||||||
void AppAdapter::TerminateApp() { FatalError("Fixme unimplemented."); }
|
void AppAdapter::TerminateApp() { FatalError("Fixme unimplemented."); }
|
||||||
|
auto AppAdapter::HasDirectKeyboardInput() -> bool { return false; }
|
||||||
|
|
||||||
|
void AppAdapter::ApplyGraphicsSettings(const GraphicsSettings* settings) {}
|
||||||
|
|
||||||
|
auto AppAdapter::GetGraphicsSettings() -> GraphicsSettings* {
|
||||||
|
return new GraphicsSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AppAdapter::GetGraphicsClientContext() -> GraphicsClientContext* {
|
||||||
|
return new GraphicsClientContext();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -30,6 +30,16 @@ class AppAdapter {
|
|||||||
virtual void OnScreenSizeChange();
|
virtual void OnScreenSizeChange();
|
||||||
virtual void DoApplyAppConfig();
|
virtual void DoApplyAppConfig();
|
||||||
|
|
||||||
|
/// When called, should allocate an instance of a GraphicsSettings
|
||||||
|
/// subclass using 'new', fill it out, and return it. Runs in the logic
|
||||||
|
/// thread.
|
||||||
|
virtual auto GetGraphicsSettings() -> GraphicsSettings*;
|
||||||
|
|
||||||
|
/// When called, should allocate an instance of a GraphicsClientContext
|
||||||
|
/// subclass using 'new', fill it out, and return it. Runs in the graphics
|
||||||
|
/// context.
|
||||||
|
virtual auto GetGraphicsClientContext() -> GraphicsClientContext*;
|
||||||
|
|
||||||
/// Return whether this class manages the main thread event loop itself.
|
/// Return whether this class manages the main thread event loop itself.
|
||||||
/// Default is true. If this is true, RunMainThreadEventLoopToCompletion()
|
/// Default is true. If this is true, RunMainThreadEventLoopToCompletion()
|
||||||
/// will be called to run the app. This should return false on builds
|
/// will be called to run the app. This should return false on builds
|
||||||
@ -113,9 +123,27 @@ class AppAdapter {
|
|||||||
auto app_suspended() const { return app_suspended_; }
|
auto app_suspended() const { return app_suspended_; }
|
||||||
|
|
||||||
/// Return whether this AppAdapter supports a 'fullscreen' toggle for its
|
/// Return whether this AppAdapter supports a 'fullscreen' toggle for its
|
||||||
/// display. This currently will simply affect whether that option is
|
/// display. This will affect whether that option is available in display
|
||||||
/// available in display settings or via a hotkey.
|
/// settings or via a hotkey. Must be called from the logic thread.
|
||||||
virtual auto CanToggleFullscreen() -> bool const;
|
virtual auto FullscreenControlAvailable() const -> bool;
|
||||||
|
|
||||||
|
/// AppAdapters supporting a 'fullscreen' control should return the
|
||||||
|
/// current fullscreen state here. By default this simply returns the
|
||||||
|
/// app-config fullscreen value (so assumes the actual state is synced to
|
||||||
|
/// that). Must be called from the logic thread.
|
||||||
|
virtual auto FullscreenControlGet() const -> bool;
|
||||||
|
|
||||||
|
/// AppAdapters supporting a 'fullscreen' control should set the
|
||||||
|
/// current fullscreen state here. By default this simply sets the
|
||||||
|
/// app-config fullscreen value (so assumes the actual state is synced to
|
||||||
|
/// that). Must be called from the logic thread.
|
||||||
|
virtual void FullscreenControlSet(bool fullscreen);
|
||||||
|
|
||||||
|
/// AppAdapters supporting a 'fullscreen' control can return a key name
|
||||||
|
/// here to display if they support toggling via key ('ctrl-F', etc.).
|
||||||
|
/// Must be called from the logic thread.
|
||||||
|
virtual auto FullscreenControlKeyShortcut() const
|
||||||
|
-> std::optional<std::string>;
|
||||||
|
|
||||||
/// Return whether this AppAdapter supports vsync controls for its display.
|
/// Return whether this AppAdapter supports vsync controls for its display.
|
||||||
virtual auto SupportsVSync() -> bool const;
|
virtual auto SupportsVSync() -> bool const;
|
||||||
@ -153,6 +181,22 @@ class AppAdapter {
|
|||||||
/// this point.
|
/// this point.
|
||||||
virtual void TerminateApp();
|
virtual void TerminateApp();
|
||||||
|
|
||||||
|
/// Should return whether there is a keyboard attached that will deliver
|
||||||
|
/// direct text-editing related events to the app. When this is false,
|
||||||
|
/// alternate entry methods such as keyboard-entry-dialogs and on-screen
|
||||||
|
/// keyboards will be used. This value can change based on conditions such
|
||||||
|
/// as a hardware keyboard getting attached or detached or the language
|
||||||
|
/// changing (it may be preferable to rely on dialogs for non-english
|
||||||
|
/// languages/etc.). Default implementation returns false. This function
|
||||||
|
/// should be callable from any thread.
|
||||||
|
virtual auto HasDirectKeyboardInput() -> bool;
|
||||||
|
|
||||||
|
/// Called in the graphics context to apply new settings coming in from
|
||||||
|
/// the logic subsystem. This will be called initially to jump-start the
|
||||||
|
/// graphics system as well as before frame draws to update any new
|
||||||
|
/// settings coming in.
|
||||||
|
virtual void ApplyGraphicsSettings(const GraphicsSettings* settings);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AppAdapter();
|
AppAdapter();
|
||||||
virtual ~AppAdapter();
|
virtual ~AppAdapter();
|
||||||
|
|||||||
@ -44,58 +44,27 @@ void AppAdapterApple::DoPushMainThreadRunnable(Runnable* runnable) {
|
|||||||
BallisticaKit::FromCppPushRawRunnableToMain(runnable);
|
BallisticaKit::FromCppPushRawRunnableToMain(runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppAdapterApple::DoApplyAppConfig() {
|
void AppAdapterApple::DoApplyAppConfig() { assert(g_base->InLogicThread()); }
|
||||||
assert(g_base->InLogicThread());
|
|
||||||
|
|
||||||
g_base->graphics_server->PushSetScreenPixelScaleCall(
|
void AppAdapterApple::ApplyGraphicsSettings(const GraphicsSettings* settings) {
|
||||||
g_base->app_config->Resolve(AppConfig::FloatID::kScreenPixelScale));
|
auto* graphics_server = g_base->graphics_server;
|
||||||
|
|
||||||
auto graphics_quality_requested =
|
// We need a full renderer reload if quality values have changed
|
||||||
g_base->graphics->GraphicsQualityFromAppConfig();
|
// or if we don't have a renderer yet.
|
||||||
|
bool need_full_reload = ((graphics_server->texture_quality_requested()
|
||||||
auto texture_quality_requested =
|
!= settings->texture_quality)
|
||||||
g_base->graphics->TextureQualityFromAppConfig();
|
|| (graphics_server->graphics_quality_requested()
|
||||||
|
!= settings->graphics_quality));
|
||||||
g_base->app_adapter->PushGraphicsContextCall([=] {
|
|
||||||
SetScreen_(texture_quality_requested, graphics_quality_requested);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppAdapterApple::SetScreen_(
|
|
||||||
TextureQualityRequest texture_quality_requested,
|
|
||||||
GraphicsQualityRequest graphics_quality_requested) {
|
|
||||||
// If we know what we support, filter our request types to what is
|
|
||||||
// supported. This will keep us from rebuilding contexts if request type
|
|
||||||
// is flipping between different types that we don't support.
|
|
||||||
if (g_base->graphics->has_supports_high_quality_graphics_value()) {
|
|
||||||
if (!g_base->graphics->supports_high_quality_graphics()
|
|
||||||
&& graphics_quality_requested > GraphicsQualityRequest::kMedium) {
|
|
||||||
graphics_quality_requested = GraphicsQualityRequest::kMedium;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* gs = g_base->graphics_server;
|
|
||||||
|
|
||||||
// We need a full renderer reload if quality values have changed or if we
|
// We need a full renderer reload if quality values have changed or if we
|
||||||
// don't have one yet.
|
// don't yet have a renderer.
|
||||||
bool need_full_reload =
|
|
||||||
((gs->texture_quality_requested() != texture_quality_requested)
|
|
||||||
|| (gs->graphics_quality_requested() != graphics_quality_requested)
|
|
||||||
|| !gs->texture_quality_set() || !gs->graphics_quality_set());
|
|
||||||
|
|
||||||
if (need_full_reload) {
|
if (need_full_reload) {
|
||||||
ReloadRenderer_(graphics_quality_requested, texture_quality_requested);
|
ReloadRenderer_(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let the logic thread know we've got a graphics system up and running.
|
|
||||||
// It may use this cue to kick off asset loads and other bootstrapping.
|
|
||||||
g_base->logic->event_loop()->PushCall(
|
|
||||||
[] { g_base->logic->OnGraphicsReady(); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppAdapterApple::ReloadRenderer_(
|
void AppAdapterApple::ReloadRenderer_(const GraphicsSettings* settings) {
|
||||||
GraphicsQualityRequest graphics_quality_requested,
|
|
||||||
TextureQualityRequest texture_quality_requested) {
|
|
||||||
auto* gs = g_base->graphics_server;
|
auto* gs = g_base->graphics_server;
|
||||||
|
|
||||||
if (gs->renderer() && gs->renderer_loaded()) {
|
if (gs->renderer() && gs->renderer_loaded()) {
|
||||||
@ -105,15 +74,9 @@ void AppAdapterApple::ReloadRenderer_(
|
|||||||
gs->set_renderer(new RendererGL());
|
gs->set_renderer(new RendererGL());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set a dummy screen resolution to start with. The main thread will kick
|
|
||||||
// along the latest real resolution just before each frame draw, but we
|
|
||||||
// need *something* here or else we'll get errors due to framebuffers
|
|
||||||
// getting made at size 0/etc.
|
|
||||||
g_base->graphics_server->SetScreenResolution(320.0, 240.0);
|
|
||||||
|
|
||||||
// Update graphics quality based on request.
|
// Update graphics quality based on request.
|
||||||
gs->set_graphics_quality_requested(graphics_quality_requested);
|
gs->set_graphics_quality_requested(settings->graphics_quality);
|
||||||
gs->set_texture_quality_requested(texture_quality_requested);
|
gs->set_texture_quality_requested(settings->texture_quality);
|
||||||
|
|
||||||
// (Re)load stuff with these latest quality settings.
|
// (Re)load stuff with these latest quality settings.
|
||||||
gs->LoadRenderer();
|
gs->LoadRenderer();
|
||||||
@ -123,12 +86,6 @@ void AppAdapterApple::UpdateScreenSizes_() {
|
|||||||
assert(g_base->app_adapter->InGraphicsContext());
|
assert(g_base->app_adapter->InGraphicsContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppAdapterApple::SetScreenResolution(float pixel_width,
|
|
||||||
float pixel_height) {
|
|
||||||
auto allow = ScopedAllowGraphics_(this);
|
|
||||||
g_base->graphics_server->SetScreenResolution(pixel_width, pixel_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto AppAdapterApple::TryRender() -> bool {
|
auto AppAdapterApple::TryRender() -> bool {
|
||||||
auto allow = ScopedAllowGraphics_(this);
|
auto allow = ScopedAllowGraphics_(this);
|
||||||
|
|
||||||
@ -146,10 +103,45 @@ auto AppAdapterApple::TryRender() -> bool {
|
|||||||
call->RunAndLogErrors();
|
call->RunAndLogErrors();
|
||||||
delete call;
|
delete call;
|
||||||
}
|
}
|
||||||
// Lastly render.
|
|
||||||
return g_base->graphics_server->TryRender();
|
|
||||||
|
|
||||||
return true;
|
// Lastly, render.
|
||||||
|
auto result = g_base->graphics_server->TryRender();
|
||||||
|
|
||||||
|
// A little trick to make mac resizing look a lot smoother. Because we
|
||||||
|
// render in a background thread, we often don't render at the most up to
|
||||||
|
// date window size during a window resize. Normally this makes our image
|
||||||
|
// jerk around in an ugly way, but if we just re-render once or twice in
|
||||||
|
// those cases we mostly always get the most up to date window size.
|
||||||
|
if (result && resize_friendly_frames_ > 0) {
|
||||||
|
// Leave this enabled for just a few frames every time it is set.
|
||||||
|
// (so just in case it breaks we won't draw each frame serveral times for
|
||||||
|
// eternity).
|
||||||
|
resize_friendly_frames_ -= 1;
|
||||||
|
|
||||||
|
// Keep on drawing until the drawn window size
|
||||||
|
// matches what we have (or until we try for too long or fail at drawing).
|
||||||
|
seconds_t start_time = g_core->GetAppTimeSeconds();
|
||||||
|
for (int i = 0; i < 5; ++i) {
|
||||||
|
if (((std::abs(resize_target_resolution_.x
|
||||||
|
- g_base->graphics_server->screen_pixel_width())
|
||||||
|
> 0.01f)
|
||||||
|
|| (std::abs(resize_target_resolution_.y
|
||||||
|
- g_base->graphics_server->screen_pixel_height())
|
||||||
|
> 0.01f))
|
||||||
|
&& g_core->GetAppTimeSeconds() - start_time < 0.1 && result) {
|
||||||
|
result = g_base->graphics_server->TryRender();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppAdapterApple::EnableResizeFriendlyMode(int width, int height) {
|
||||||
|
resize_friendly_frames_ = 5;
|
||||||
|
resize_target_resolution_ = Vector2f(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto AppAdapterApple::InGraphicsContext() -> bool {
|
auto AppAdapterApple::InGraphicsContext() -> bool {
|
||||||
@ -202,6 +194,36 @@ void AppAdapterApple::TerminateApp() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto AppAdapterApple::FullscreenControlAvailable() const -> bool {
|
||||||
|
// Currently Mac only. Any window-management stuff elsewhere such as
|
||||||
|
// iPadOS is out of our hands.
|
||||||
|
if (g_buildconfig.ostype_macos()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AppAdapterApple::FullscreenControlGet() const -> bool {
|
||||||
|
#if BA_OSTYPE_MACOS
|
||||||
|
return BallisticaKit::CocoaFromCppGetMainWindowIsFullscreen();
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppAdapterApple::FullscreenControlSet(bool fullscreen) {
|
||||||
|
#if BA_OSTYPE_MACOS
|
||||||
|
return BallisticaKit::CocoaFromCppSetMainWindowFullscreen(fullscreen);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AppAdapterApple::FullscreenControlKeyShortcut() const
|
||||||
|
-> std::optional<std::string> {
|
||||||
|
return "fn+F";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AppAdapterApple::HasDirectKeyboardInput() -> bool { return true; };
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|
||||||
#endif // BA_XCODE_BUILD
|
#endif // BA_XCODE_BUILD
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "ballistica/base/app_adapter/app_adapter.h"
|
#include "ballistica/base/app_adapter/app_adapter.h"
|
||||||
#include "ballistica/shared/generic/runnable.h"
|
#include "ballistica/shared/generic/runnable.h"
|
||||||
|
#include "ballistica/shared/math/vector2f.h"
|
||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
|
|
||||||
@ -31,8 +32,14 @@ class AppAdapterApple : public AppAdapter {
|
|||||||
/// Called by FromSwift.
|
/// Called by FromSwift.
|
||||||
auto TryRender() -> bool;
|
auto TryRender() -> bool;
|
||||||
|
|
||||||
/// Called by FromSwift.
|
auto FullscreenControlAvailable() const -> bool override;
|
||||||
void SetScreenResolution(float pixel_width, float pixel_height);
|
auto FullscreenControlGet() const -> bool override;
|
||||||
|
void FullscreenControlSet(bool fullscreen) override;
|
||||||
|
auto FullscreenControlKeyShortcut() const
|
||||||
|
-> std::optional<std::string> override;
|
||||||
|
|
||||||
|
auto HasDirectKeyboardInput() -> bool override;
|
||||||
|
void EnableResizeFriendlyMode(int width, int height);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
||||||
@ -42,16 +49,18 @@ class AppAdapterApple : public AppAdapter {
|
|||||||
auto HasHardwareCursor() -> bool override;
|
auto HasHardwareCursor() -> bool override;
|
||||||
void SetHardwareCursorVisible(bool visible) override;
|
void SetHardwareCursorVisible(bool visible) override;
|
||||||
void TerminateApp() override;
|
void TerminateApp() override;
|
||||||
|
void ApplyGraphicsSettings(const GraphicsSettings* settings) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateScreenSizes_();
|
|
||||||
class ScopedAllowGraphics_;
|
class ScopedAllowGraphics_;
|
||||||
void SetScreen_(TextureQualityRequest texture_quality_requested,
|
|
||||||
GraphicsQualityRequest graphics_quality_requested);
|
void UpdateScreenSizes_();
|
||||||
void ReloadRenderer_(GraphicsQualityRequest graphics_quality_requested,
|
void ReloadRenderer_(const GraphicsSettings* settings);
|
||||||
TextureQualityRequest texture_quality_requested);
|
|
||||||
std::thread::id graphics_thread_{};
|
std::thread::id graphics_thread_{};
|
||||||
bool graphics_allowed_;
|
bool graphics_allowed_ : 1 {};
|
||||||
|
uint8_t resize_friendly_frames_{};
|
||||||
|
Vector2f resize_target_resolution_{-1.0f, -1.0f};
|
||||||
std::mutex graphics_calls_mutex_;
|
std::mutex graphics_calls_mutex_;
|
||||||
std::vector<Runnable*> graphics_calls_;
|
std::vector<Runnable*> graphics_calls_;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include "ballistica/base/app_adapter/app_adapter_headless.h"
|
#include "ballistica/base/app_adapter/app_adapter_headless.h"
|
||||||
|
|
||||||
#include "ballistica/base/graphics/graphics_server.h"
|
#include "ballistica/base/graphics/graphics_server.h"
|
||||||
|
#include "ballistica/base/graphics/support/graphics_client_context.h"
|
||||||
#include "ballistica/shared/ballistica.h"
|
#include "ballistica/shared/ballistica.h"
|
||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
@ -19,12 +20,7 @@ void AppAdapterHeadless::OnMainThreadStartApp() {
|
|||||||
new EventLoop(EventLoopID::kMain, ThreadSource::kWrapCurrent);
|
new EventLoop(EventLoopID::kMain, ThreadSource::kWrapCurrent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppAdapterHeadless::DoApplyAppConfig() {
|
void AppAdapterHeadless::DoApplyAppConfig() {}
|
||||||
// Normal graphical app-adapters kick off screen creation here
|
|
||||||
// which then leads to remaining app bootstrapping. We create
|
|
||||||
// a 'null' screen purely for the same effect.
|
|
||||||
PushMainThreadCall([] { g_base->graphics_server->SetNullGraphics(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppAdapterHeadless::RunMainThreadEventLoopToCompletion() {
|
void AppAdapterHeadless::RunMainThreadEventLoopToCompletion() {
|
||||||
assert(g_core->InMainThread());
|
assert(g_core->InMainThread());
|
||||||
@ -40,6 +36,11 @@ void AppAdapterHeadless::DoExitMainThreadEventLoop() {
|
|||||||
main_event_loop_->Exit();
|
main_event_loop_->Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto AppAdapterHeadless::GetGraphicsClientContext() -> GraphicsClientContext* {
|
||||||
|
// Special dummy form.
|
||||||
|
return new GraphicsClientContext(0);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|
||||||
#endif // BA_HEADLESS_BUILD
|
#endif // BA_HEADLESS_BUILD
|
||||||
|
|||||||
@ -17,6 +17,8 @@ class AppAdapterHeadless : public AppAdapter {
|
|||||||
|
|
||||||
void DoApplyAppConfig() override;
|
void DoApplyAppConfig() override;
|
||||||
|
|
||||||
|
auto GetGraphicsClientContext() -> GraphicsClientContext* override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
||||||
void RunMainThreadEventLoopToCompletion() override;
|
void RunMainThreadEventLoopToCompletion() override;
|
||||||
|
|||||||
@ -104,32 +104,115 @@ void AppAdapterSDL::OnMainThreadStartApp() {
|
|||||||
SDL_ShowCursor(SDL_DISABLE);
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Our particular flavor of graphics settings.
|
||||||
|
struct AppAdapterSDL::GraphicsSettings_ : public GraphicsSettings {
|
||||||
|
bool fullscreen = g_base->app_config->Resolve(AppConfig::BoolID::kFullscreen);
|
||||||
|
VSyncRequest vsync = g_base->graphics->VSyncFromAppConfig();
|
||||||
|
int max_fps = g_base->app_config->Resolve(AppConfig::IntID::kMaxFPS);
|
||||||
|
};
|
||||||
|
|
||||||
void AppAdapterSDL::DoApplyAppConfig() {
|
void AppAdapterSDL::DoApplyAppConfig() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
g_base->graphics_server->PushSetScreenPixelScaleCall(
|
|
||||||
g_base->app_config->Resolve(AppConfig::FloatID::kScreenPixelScale));
|
|
||||||
|
|
||||||
auto graphics_quality_requested =
|
|
||||||
g_base->graphics->GraphicsQualityFromAppConfig();
|
|
||||||
|
|
||||||
auto texture_quality_requested =
|
|
||||||
g_base->graphics->TextureQualityFromAppConfig();
|
|
||||||
|
|
||||||
// Android res string.
|
// Android res string.
|
||||||
// std::string android_res =
|
// std::string android_res =
|
||||||
// g_base->app_config->Resolve(AppConfig::StringID::kResolutionAndroid);
|
// g_base->app_config->Resolve(AppConfig::StringID::kResolutionAndroid);
|
||||||
|
}
|
||||||
|
|
||||||
bool fullscreen = g_base->app_config->Resolve(AppConfig::BoolID::kFullscreen);
|
auto AppAdapterSDL::GetGraphicsSettings() -> GraphicsSettings* {
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
|
return new GraphicsSettings_();
|
||||||
|
}
|
||||||
|
|
||||||
auto vsync = g_base->graphics->VSyncFromAppConfig();
|
void AppAdapterSDL::ApplyGraphicsSettings(
|
||||||
int max_fps = g_base->app_config->Resolve(AppConfig::IntID::kMaxFPS);
|
const GraphicsSettings* settings_base) {
|
||||||
|
assert(g_core->InMainThread());
|
||||||
|
assert(!g_core->HeadlessMode());
|
||||||
|
|
||||||
// Tell the main thread to set up the screen with these settings.
|
// In strict mode, allow graphics stuff while in here.
|
||||||
g_base->app_adapter->PushMainThreadCall([=] {
|
auto allow = ScopedAllowGraphics_(this);
|
||||||
SetScreen_(fullscreen, max_fps, vsync, texture_quality_requested,
|
|
||||||
graphics_quality_requested);
|
// Settings will always be our subclass (since we created it).
|
||||||
});
|
auto* settings = static_cast<const GraphicsSettings_*>(settings_base);
|
||||||
|
|
||||||
|
// Apply any changes.
|
||||||
|
bool do_toggle_fs{};
|
||||||
|
bool do_set_existing_fullscreen{};
|
||||||
|
|
||||||
|
auto* graphics_server = g_base->graphics_server;
|
||||||
|
|
||||||
|
// We need a full renderer reload if quality values have changed
|
||||||
|
// or if we don't have a renderer yet.
|
||||||
|
bool need_full_reload = ((sdl_window_ == nullptr
|
||||||
|
|| graphics_server->texture_quality_requested()
|
||||||
|
!= settings->texture_quality)
|
||||||
|
|| (graphics_server->graphics_quality_requested()
|
||||||
|
!= settings->graphics_quality));
|
||||||
|
|
||||||
|
if (need_full_reload) {
|
||||||
|
ReloadRenderer_(settings);
|
||||||
|
} else if (settings->fullscreen != fullscreen_) {
|
||||||
|
SDL_SetWindowFullscreen(
|
||||||
|
sdl_window_, settings->fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||||
|
fullscreen_ = settings->fullscreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
// VSync always gets set independent of the screen (though we set it down
|
||||||
|
// here to make sure we have a screen when its set).
|
||||||
|
VSync vsync;
|
||||||
|
switch (settings->vsync) {
|
||||||
|
case VSyncRequest::kNever:
|
||||||
|
vsync = VSync::kNever;
|
||||||
|
break;
|
||||||
|
case VSyncRequest::kAlways:
|
||||||
|
vsync = VSync::kAlways;
|
||||||
|
break;
|
||||||
|
case VSyncRequest::kAuto:
|
||||||
|
vsync = VSync::kAdaptive;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vsync = VSync::kNever;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (vsync != vsync_) {
|
||||||
|
switch (vsync) {
|
||||||
|
case VSync::kUnset:
|
||||||
|
case VSync::kNever: {
|
||||||
|
SDL_GL_SetSwapInterval(0);
|
||||||
|
vsync_actually_enabled_ = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VSync::kAlways: {
|
||||||
|
SDL_GL_SetSwapInterval(1);
|
||||||
|
vsync_actually_enabled_ = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VSync::kAdaptive: {
|
||||||
|
// In this case, let's try setting to 'adaptive' and turn it off if
|
||||||
|
// that is unsupported.
|
||||||
|
auto result = SDL_GL_SetSwapInterval(-1);
|
||||||
|
if (result == 0) {
|
||||||
|
vsync_actually_enabled_ = true;
|
||||||
|
} else {
|
||||||
|
SDL_GL_SetSwapInterval(0);
|
||||||
|
vsync_actually_enabled_ = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vsync_ = vsync;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This we can set anytime. Probably could have just set it from the logic
|
||||||
|
// thread where we read it, but let's be pedantic and keep everything to
|
||||||
|
// the main thread.
|
||||||
|
max_fps_ = settings->max_fps;
|
||||||
|
|
||||||
|
// Take -1 to mean no max. Otherwise clamp to a reasonable range.
|
||||||
|
if (max_fps_ != -1) {
|
||||||
|
max_fps_ = std::max(10, max_fps_);
|
||||||
|
max_fps_ = std::min(99999, max_fps_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppAdapterSDL::RunMainThreadEventLoopToCompletion() {
|
void AppAdapterSDL::RunMainThreadEventLoopToCompletion() {
|
||||||
@ -158,7 +241,7 @@ void AppAdapterSDL::RunMainThreadEventLoopToCompletion() {
|
|||||||
|
|
||||||
auto AppAdapterSDL::TryRender() -> bool {
|
auto AppAdapterSDL::TryRender() -> bool {
|
||||||
if (strict_graphics_context_) {
|
if (strict_graphics_context_) {
|
||||||
// In strict mode, allow graphics stuff in here. Normally we allow it
|
// In strict mode, allow graphics stuff in here. Otherwise we allow it
|
||||||
// anywhere in the main thread.
|
// anywhere in the main thread.
|
||||||
auto allow = ScopedAllowGraphics_(this);
|
auto allow = ScopedAllowGraphics_(this);
|
||||||
|
|
||||||
@ -179,7 +262,7 @@ auto AppAdapterSDL::TryRender() -> bool {
|
|||||||
// Lastly render.
|
// Lastly render.
|
||||||
return g_base->graphics_server->TryRender();
|
return g_base->graphics_server->TryRender();
|
||||||
} else {
|
} else {
|
||||||
// Simple path; just render.
|
// Simpler path; just render.
|
||||||
return g_base->graphics_server->TryRender();
|
return g_base->graphics_server->TryRender();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,7 +271,7 @@ void AppAdapterSDL::SleepUntilNextEventCycle_(microsecs_t cycle_start_time) {
|
|||||||
// Special case: if we're hidden, we simply sleep for a long bit; no fancy
|
// Special case: if we're hidden, we simply sleep for a long bit; no fancy
|
||||||
// timing.
|
// timing.
|
||||||
if (hidden_) {
|
if (hidden_) {
|
||||||
g_core->platform->SleepMillisecs(100);
|
g_core->platform->SleepSeconds(0.1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,12 +442,14 @@ void AppAdapterSDL::HandleSDLEvent_(const SDL_Event& event) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
if (g_core->GetAppTimeMillisecs() - last_windowevent_close_time_ < 100) {
|
if (g_core->GetAppTimeSeconds() - last_windowevent_close_time_ < 0.1) {
|
||||||
// If they hit the window close button, skip the confirm.
|
// If they hit the window close button, skip the confirm.
|
||||||
g_base->QuitApp(false);
|
g_base->QuitApp(false);
|
||||||
} else {
|
} else {
|
||||||
// By default, confirm before quitting.
|
// For all other quits we might want to default to a confirm dialog.
|
||||||
g_base->QuitApp(true);
|
// Update: going to try without confirm for a bit and see how that
|
||||||
|
// feels.
|
||||||
|
g_base->QuitApp(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -378,7 +463,7 @@ void AppAdapterSDL::HandleSDLEvent_(const SDL_Event& event) {
|
|||||||
case SDL_WINDOWEVENT_CLOSE: {
|
case SDL_WINDOWEVENT_CLOSE: {
|
||||||
// Simply note that this happened. We use this to adjust our
|
// Simply note that this happened. We use this to adjust our
|
||||||
// SDL_QUIT behavior (quit is called right after this).
|
// SDL_QUIT behavior (quit is called right after this).
|
||||||
last_windowevent_close_time_ = g_core->GetAppTimeMillisecs();
|
last_windowevent_close_time_ = g_core->GetAppTimeSeconds();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +479,7 @@ void AppAdapterSDL::HandleSDLEvent_(const SDL_Event& event) {
|
|||||||
fullscreen_ = true;
|
fullscreen_ = true;
|
||||||
g_base->logic->event_loop()->PushCall([] {
|
g_base->logic->event_loop()->PushCall([] {
|
||||||
g_base->python->objs()
|
g_base->python->objs()
|
||||||
.Get(BasePython::ObjID::kSetConfigFullscreenOnCall)
|
.Get(BasePython::ObjID::kStoreConfigFullscreenOnCall)
|
||||||
.Call();
|
.Call();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -407,7 +492,7 @@ void AppAdapterSDL::HandleSDLEvent_(const SDL_Event& event) {
|
|||||||
fullscreen_ = false;
|
fullscreen_ = false;
|
||||||
g_base->logic->event_loop()->PushCall([] {
|
g_base->logic->event_loop()->PushCall([] {
|
||||||
g_base->python->objs()
|
g_base->python->objs()
|
||||||
.Get(BasePython::ObjID::kSetConfigFullscreenOffCall)
|
.Get(BasePython::ObjID::kStoreConfigFullscreenOffCall)
|
||||||
.Call();
|
.Call();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -544,114 +629,7 @@ auto AppAdapterSDL::GetSDLJoystickInput_(int sdl_joystick_id) const
|
|||||||
return nullptr; // Epic fail.
|
return nullptr; // Epic fail.
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppAdapterSDL::SetScreen_(
|
void AppAdapterSDL::ReloadRenderer_(const GraphicsSettings_* settings) {
|
||||||
bool fullscreen, int max_fps, VSyncRequest vsync_requested,
|
|
||||||
TextureQualityRequest texture_quality_requested,
|
|
||||||
GraphicsQualityRequest graphics_quality_requested) {
|
|
||||||
assert(g_core->InMainThread());
|
|
||||||
assert(!g_core->HeadlessMode());
|
|
||||||
|
|
||||||
// In strict mode, allow graphics stuff in here.
|
|
||||||
auto allow = ScopedAllowGraphics_(this);
|
|
||||||
|
|
||||||
// If we know what we support, filter our request types to what is
|
|
||||||
// supported. This will keep us from rebuilding contexts if request type
|
|
||||||
// is flipping between different types that we don't support.
|
|
||||||
if (g_base->graphics->has_supports_high_quality_graphics_value()) {
|
|
||||||
if (!g_base->graphics->supports_high_quality_graphics()
|
|
||||||
&& graphics_quality_requested > GraphicsQualityRequest::kMedium) {
|
|
||||||
graphics_quality_requested = GraphicsQualityRequest::kMedium;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool do_toggle_fs{};
|
|
||||||
bool do_set_existing_fullscreen{};
|
|
||||||
|
|
||||||
auto* gs = g_base->graphics_server;
|
|
||||||
|
|
||||||
// We need a full renderer reload if quality values have changed
|
|
||||||
// or if we don't have one yet.
|
|
||||||
bool need_full_reload =
|
|
||||||
((sdl_window_ == nullptr
|
|
||||||
|| gs->texture_quality_requested() != texture_quality_requested)
|
|
||||||
|| (gs->graphics_quality_requested() != graphics_quality_requested)
|
|
||||||
|| !gs->texture_quality_set() || !gs->graphics_quality_set());
|
|
||||||
|
|
||||||
if (need_full_reload) {
|
|
||||||
ReloadRenderer_(fullscreen, graphics_quality_requested,
|
|
||||||
texture_quality_requested);
|
|
||||||
} else if (fullscreen != fullscreen_) {
|
|
||||||
SDL_SetWindowFullscreen(sdl_window_,
|
|
||||||
fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
|
||||||
fullscreen_ = fullscreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
// VSync always gets set independent of the screen (though we set it down
|
|
||||||
// here to make sure we have a screen when its set).
|
|
||||||
VSync vsync;
|
|
||||||
switch (vsync_requested) {
|
|
||||||
case VSyncRequest::kNever:
|
|
||||||
vsync = VSync::kNever;
|
|
||||||
break;
|
|
||||||
case VSyncRequest::kAlways:
|
|
||||||
vsync = VSync::kAlways;
|
|
||||||
break;
|
|
||||||
case VSyncRequest::kAuto:
|
|
||||||
vsync = VSync::kAdaptive;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
vsync = VSync::kNever;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (vsync != vsync_) {
|
|
||||||
switch (vsync) {
|
|
||||||
case VSync::kUnset:
|
|
||||||
case VSync::kNever: {
|
|
||||||
SDL_GL_SetSwapInterval(0);
|
|
||||||
vsync_actually_enabled_ = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VSync::kAlways: {
|
|
||||||
SDL_GL_SetSwapInterval(1);
|
|
||||||
vsync_actually_enabled_ = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VSync::kAdaptive: {
|
|
||||||
// In this case, let's try setting to 'adaptive' and turn it off if
|
|
||||||
// that is unsupported.
|
|
||||||
auto result = SDL_GL_SetSwapInterval(-1);
|
|
||||||
if (result == 0) {
|
|
||||||
vsync_actually_enabled_ = true;
|
|
||||||
} else {
|
|
||||||
SDL_GL_SetSwapInterval(0);
|
|
||||||
vsync_actually_enabled_ = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vsync_ = vsync;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This we can set anytime. Probably could have just set it from the logic
|
|
||||||
// thread where we read it, but let's be pedantic and keep everything to
|
|
||||||
// the main thread.
|
|
||||||
max_fps_ = max_fps;
|
|
||||||
|
|
||||||
// Take -1 to mean no max. Otherwise clamp to a reasonable range.
|
|
||||||
if (max_fps_ != -1) {
|
|
||||||
max_fps_ = std::max(10, max_fps_);
|
|
||||||
max_fps_ = std::min(99999, max_fps_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let the logic thread know we've got a graphics system up and running.
|
|
||||||
// It may use this cue to kick off asset loads and other bootstrapping.
|
|
||||||
g_base->logic->event_loop()->PushCall(
|
|
||||||
[] { g_base->logic->OnGraphicsReady(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppAdapterSDL::ReloadRenderer_(
|
|
||||||
bool fullscreen, GraphicsQualityRequest graphics_quality_requested,
|
|
||||||
TextureQualityRequest texture_quality_requested) {
|
|
||||||
assert(g_base->app_adapter->InGraphicsContext());
|
assert(g_base->app_adapter->InGraphicsContext());
|
||||||
|
|
||||||
auto* gs = g_base->graphics_server;
|
auto* gs = g_base->graphics_server;
|
||||||
@ -662,7 +640,7 @@ void AppAdapterSDL::ReloadRenderer_(
|
|||||||
|
|
||||||
// If we don't haven't yet, create our window and renderer.
|
// If we don't haven't yet, create our window and renderer.
|
||||||
if (!sdl_window_) {
|
if (!sdl_window_) {
|
||||||
fullscreen_ = fullscreen;
|
fullscreen_ = settings->fullscreen;
|
||||||
|
|
||||||
// A reasonable default window size.
|
// A reasonable default window size.
|
||||||
auto width = static_cast<int>(kBaseVirtualResX * 0.8f);
|
auto width = static_cast<int>(kBaseVirtualResX * 0.8f);
|
||||||
@ -670,7 +648,7 @@ void AppAdapterSDL::ReloadRenderer_(
|
|||||||
|
|
||||||
uint32_t flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
|
uint32_t flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
|
||||||
| SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
|
| SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
|
||||||
if (fullscreen) {
|
if (settings->fullscreen) {
|
||||||
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -727,15 +705,16 @@ void AppAdapterSDL::ReloadRenderer_(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update graphics quality based on request.
|
// Update graphics-server's qualities based on request.
|
||||||
gs->set_graphics_quality_requested(graphics_quality_requested);
|
gs->set_graphics_quality_requested(settings->graphics_quality);
|
||||||
gs->set_texture_quality_requested(texture_quality_requested);
|
gs->set_texture_quality_requested(settings->texture_quality);
|
||||||
|
|
||||||
gs->LoadRenderer();
|
gs->LoadRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppAdapterSDL::UpdateScreenSizes_() {
|
void AppAdapterSDL::UpdateScreenSizes_() {
|
||||||
assert(g_base->app_adapter->InGraphicsContext());
|
// This runs in the main thread in response to SDL events.
|
||||||
|
assert(g_core->InMainThread());
|
||||||
|
|
||||||
// Grab logical window dimensions (points?). This is the coordinate space
|
// Grab logical window dimensions (points?). This is the coordinate space
|
||||||
// SDL's events deal in.
|
// SDL's events deal in.
|
||||||
@ -747,8 +726,13 @@ void AppAdapterSDL::UpdateScreenSizes_() {
|
|||||||
// dimensions.
|
// dimensions.
|
||||||
int pixels_x, pixels_y;
|
int pixels_x, pixels_y;
|
||||||
SDL_GL_GetDrawableSize(sdl_window_, &pixels_x, &pixels_y);
|
SDL_GL_GetDrawableSize(sdl_window_, &pixels_x, &pixels_y);
|
||||||
g_base->graphics_server->SetScreenResolution(static_cast<float>(pixels_x),
|
|
||||||
static_cast<float>(pixels_y));
|
// Push this over to the logic thread which owns the canonical value
|
||||||
|
// for this.
|
||||||
|
g_base->logic->event_loop()->PushCall([pixels_x, pixels_y] {
|
||||||
|
g_base->graphics->SetScreenResolution(static_cast<float>(pixels_x),
|
||||||
|
static_cast<float>(pixels_y));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto AppAdapterSDL::InGraphicsContext() -> bool {
|
auto AppAdapterSDL::InGraphicsContext() -> bool {
|
||||||
@ -818,10 +802,36 @@ void AppAdapterSDL::CursorPositionForDraw(float* x, float* y) {
|
|||||||
*y = immediate_y;
|
*y = immediate_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto AppAdapterSDL::CanToggleFullscreen() -> bool const { return true; }
|
auto AppAdapterSDL::FullscreenControlAvailable() const -> bool { return true; }
|
||||||
|
auto AppAdapterSDL::FullscreenControlKeyShortcut() const
|
||||||
|
-> std::optional<std::string> {
|
||||||
|
if (g_buildconfig.ostype_windows()) {
|
||||||
|
// On Windows we support F11 and Alt+Enter to toggle fullscreen. Let's
|
||||||
|
// mention Alt+Enter which seems like it might be more commonly used
|
||||||
|
return "Alt+Enter";
|
||||||
|
}
|
||||||
|
if (g_buildconfig.ostype_macos()) {
|
||||||
|
// The Mac+SDL situation is a bit of a mess. By default, there is 'Enter
|
||||||
|
// Full Screen' in the window menu which is mapped to fn-F, but that
|
||||||
|
// will only work if a window was created in SDL as windowed. If we
|
||||||
|
// fullscreen that window and restart the app, we'll then have a *real*
|
||||||
|
// fullscreen sdl window and that shortcut won't work anymore. So to
|
||||||
|
// keep things consistent we advertise ctrl-f which we always handle
|
||||||
|
// ourselves. Maybe this situation will be cleaned up in SDL 3, but its
|
||||||
|
// not a huge deal anyway since our Cocoa Mac version behaves cleanly.
|
||||||
|
return "Ctrl+F";
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
auto AppAdapterSDL::SupportsVSync() -> bool const { return true; }
|
auto AppAdapterSDL::SupportsVSync() -> bool const { return true; }
|
||||||
auto AppAdapterSDL::SupportsMaxFPS() -> bool const { return true; }
|
auto AppAdapterSDL::SupportsMaxFPS() -> bool const { return true; }
|
||||||
|
|
||||||
|
auto AppAdapterSDL::HasDirectKeyboardInput() -> bool {
|
||||||
|
// We always provide direct keyboard events.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|
||||||
#endif // BA_SDL_BUILD
|
#endif // BA_SDL_BUILD
|
||||||
|
|||||||
@ -34,10 +34,17 @@ class AppAdapterSDL : public AppAdapter {
|
|||||||
|
|
||||||
auto TryRender() -> bool;
|
auto TryRender() -> bool;
|
||||||
|
|
||||||
auto CanToggleFullscreen() -> bool const override;
|
auto FullscreenControlAvailable() const -> bool override;
|
||||||
|
auto FullscreenControlKeyShortcut() const
|
||||||
|
-> std::optional<std::string> override;
|
||||||
auto SupportsVSync() -> bool const override;
|
auto SupportsVSync() -> bool const override;
|
||||||
auto SupportsMaxFPS() -> bool const override;
|
auto SupportsMaxFPS() -> bool const override;
|
||||||
|
|
||||||
|
auto HasDirectKeyboardInput() -> bool override;
|
||||||
|
void ApplyGraphicsSettings(const GraphicsSettings* settings) override;
|
||||||
|
|
||||||
|
auto GetGraphicsSettings() -> GraphicsSettings* override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
||||||
void RunMainThreadEventLoopToCompletion() override;
|
void RunMainThreadEventLoopToCompletion() override;
|
||||||
@ -48,14 +55,11 @@ class AppAdapterSDL : public AppAdapter {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
class ScopedAllowGraphics_;
|
class ScopedAllowGraphics_;
|
||||||
void SetScreen_(bool fullscreen, int max_fps, VSyncRequest vsync_requested,
|
struct GraphicsSettings_;
|
||||||
TextureQualityRequest texture_quality_requested,
|
|
||||||
GraphicsQualityRequest graphics_quality_requested);
|
|
||||||
void HandleSDLEvent_(const SDL_Event& event);
|
void HandleSDLEvent_(const SDL_Event& event);
|
||||||
void UpdateScreenSizes_();
|
void UpdateScreenSizes_();
|
||||||
void ReloadRenderer_(bool fullscreen,
|
void ReloadRenderer_(const GraphicsSettings_* settings);
|
||||||
GraphicsQualityRequest graphics_quality_requested,
|
|
||||||
TextureQualityRequest texture_quality_requested);
|
|
||||||
void OnSDLJoystickAdded_(int index);
|
void OnSDLJoystickAdded_(int index);
|
||||||
void OnSDLJoystickRemoved_(int index);
|
void OnSDLJoystickRemoved_(int index);
|
||||||
// Given an SDL joystick ID, returns our Ballistica input for it.
|
// Given an SDL joystick ID, returns our Ballistica input for it.
|
||||||
@ -66,6 +70,7 @@ class AppAdapterSDL : public AppAdapter {
|
|||||||
void RemoveSDLInputDevice_(int index);
|
void RemoveSDLInputDevice_(int index);
|
||||||
void SleepUntilNextEventCycle_(microsecs_t cycle_start_time);
|
void SleepUntilNextEventCycle_(microsecs_t cycle_start_time);
|
||||||
|
|
||||||
|
int max_fps_{60};
|
||||||
bool done_ : 1 {};
|
bool done_ : 1 {};
|
||||||
bool fullscreen_ : 1 {};
|
bool fullscreen_ : 1 {};
|
||||||
bool vsync_actually_enabled_ : 1 {};
|
bool vsync_actually_enabled_ : 1 {};
|
||||||
@ -81,17 +86,16 @@ class AppAdapterSDL : public AppAdapter {
|
|||||||
/// that require such a setup.
|
/// that require such a setup.
|
||||||
bool strict_graphics_context_ : 1 {};
|
bool strict_graphics_context_ : 1 {};
|
||||||
bool strict_graphics_allowed_ : 1 {};
|
bool strict_graphics_allowed_ : 1 {};
|
||||||
std::mutex strict_graphics_calls_mutex_;
|
|
||||||
std::vector<Runnable*> strict_graphics_calls_;
|
|
||||||
VSync vsync_{VSync::kUnset};
|
VSync vsync_{VSync::kUnset};
|
||||||
uint32_t sdl_runnable_event_id_{};
|
uint32_t sdl_runnable_event_id_{};
|
||||||
int max_fps_{60};
|
std::mutex strict_graphics_calls_mutex_;
|
||||||
|
std::vector<Runnable*> strict_graphics_calls_;
|
||||||
microsecs_t oversleep_{};
|
microsecs_t oversleep_{};
|
||||||
std::vector<JoystickInput*> sdl_joysticks_;
|
std::vector<JoystickInput*> sdl_joysticks_;
|
||||||
Vector2f window_size_{1.0f, 1.0f};
|
Vector2f window_size_{1.0f, 1.0f};
|
||||||
SDL_Window* sdl_window_{};
|
SDL_Window* sdl_window_{};
|
||||||
void* sdl_gl_context_{};
|
void* sdl_gl_context_{};
|
||||||
millisecs_t last_windowevent_close_time_{};
|
seconds_t last_windowevent_close_time_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -40,7 +40,8 @@ void AppAdapterVR::PushVRSimpleRemoteStateCall(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AppAdapterVR::VRSetDrawDimensions(int w, int h) {
|
void AppAdapterVR::VRSetDrawDimensions(int w, int h) {
|
||||||
g_base->graphics_server->SetScreenResolution(w, h);
|
FatalError("FIXME UPDATE SET-SCREEN-RESOLUTION");
|
||||||
|
// g_base->graphics_server->SetScreenResolution(w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppAdapterVR::VRPreDraw() {
|
void AppAdapterVR::VRPreDraw() {
|
||||||
|
|||||||
@ -36,8 +36,6 @@ void AppMode::HandleGameQuery(const char* buffer, size_t size,
|
|||||||
|
|
||||||
auto AppMode::DoesWorldFillScreen() -> bool { return false; }
|
auto AppMode::DoesWorldFillScreen() -> bool { return false; }
|
||||||
|
|
||||||
void AppMode::GraphicsQualityChanged(GraphicsQuality quality) {}
|
|
||||||
|
|
||||||
void AppMode::DrawWorld(FrameDef* frame_def) {}
|
void AppMode::DrawWorld(FrameDef* frame_def) {}
|
||||||
|
|
||||||
void AppMode::ChangeGameSpeed(int offs) {}
|
void AppMode::ChangeGameSpeed(int offs) {}
|
||||||
|
|||||||
@ -62,8 +62,6 @@ class AppMode {
|
|||||||
|
|
||||||
virtual void DrawWorld(FrameDef* frame_def);
|
virtual void DrawWorld(FrameDef* frame_def);
|
||||||
|
|
||||||
virtual void GraphicsQualityChanged(GraphicsQuality quality);
|
|
||||||
|
|
||||||
/// Called whenever screen size changes.
|
/// Called whenever screen size changes.
|
||||||
virtual void OnScreenSizeChange();
|
virtual void OnScreenSizeChange();
|
||||||
|
|
||||||
|
|||||||
@ -82,10 +82,10 @@ void Assets::StartLoading() {
|
|||||||
assert(g_base);
|
assert(g_base);
|
||||||
assert(g_base->audio_server && g_base->assets_server
|
assert(g_base->audio_server && g_base->assets_server
|
||||||
&& g_base->graphics_server);
|
&& g_base->graphics_server);
|
||||||
assert(g_base->graphics_server->texture_compression_types_are_set());
|
assert(g_base->graphics->has_client_context());
|
||||||
assert(g_base->graphics_server->texture_quality_set());
|
|
||||||
|
|
||||||
assert(!asset_loads_allowed_); // We should only be called once.
|
// We should only be called once.
|
||||||
|
assert(!asset_loads_allowed_);
|
||||||
asset_loads_allowed_ = true;
|
asset_loads_allowed_ = true;
|
||||||
|
|
||||||
// Just grab the lock once for all this stuff for efficiency.
|
// Just grab the lock once for all this stuff for efficiency.
|
||||||
@ -1102,10 +1102,13 @@ auto Assets::FindAssetFile(FileType type, const std::string& name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(g_base->graphics_server
|
// Make sure we know what compression/quality to use.
|
||||||
&& g_base->graphics_server->texture_compression_types_are_set());
|
assert(g_base->graphics->has_client_context());
|
||||||
assert(g_base->graphics_server
|
// assert(g_base->graphics_server
|
||||||
&& g_base->graphics_server->texture_quality_set());
|
// &&
|
||||||
|
// g_base->graphics_server->texture_compression_types_are_set());
|
||||||
|
// assert(g_base->graphics_server
|
||||||
|
// && g_base->graphics_server->texture_quality_set());
|
||||||
prefix = "textures/";
|
prefix = "textures/";
|
||||||
|
|
||||||
#if BA_OSTYPE_ANDROID && !BA_ANDROID_DDS_BUILD
|
#if BA_OSTYPE_ANDROID && !BA_ANDROID_DDS_BUILD
|
||||||
|
|||||||
@ -117,6 +117,8 @@ class Assets {
|
|||||||
|
|
||||||
auto language_state() const { return language_state_; }
|
auto language_state() const { return language_state_; }
|
||||||
|
|
||||||
|
auto asset_loads_allowed() const { return asset_loads_allowed_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void MarkAssetForLoad(Asset* c);
|
static void MarkAssetForLoad(Asset* c);
|
||||||
void LoadSystemTexture(SysTextureID id, const char* name);
|
void LoadSystemTexture(SysTextureID id, const char* name);
|
||||||
@ -136,20 +138,21 @@ class Assets {
|
|||||||
std::unordered_map<std::string, Object::Ref<T> >* c_list)
|
std::unordered_map<std::string, Object::Ref<T> >* c_list)
|
||||||
-> Object::Ref<T>;
|
-> Object::Ref<T>;
|
||||||
|
|
||||||
std::vector<std::string> asset_paths_;
|
int language_state_{};
|
||||||
bool have_pending_loads_[static_cast<int>(AssetType::kLast)]{};
|
bool have_pending_loads_[static_cast<int>(AssetType::kLast)]{};
|
||||||
|
|
||||||
|
// Will be true while a AssetListLock exists. Good to debug-verify this
|
||||||
|
// during any asset list access.
|
||||||
|
bool asset_lists_locked_ : 1 {};
|
||||||
|
bool asset_loads_allowed_ : 1 {};
|
||||||
|
bool sys_assets_loaded_ : 1 {};
|
||||||
|
|
||||||
|
std::vector<std::string> asset_paths_;
|
||||||
std::unordered_map<std::string, std::string> packages_;
|
std::unordered_map<std::string, std::string> packages_;
|
||||||
|
|
||||||
// For use by AssetListLock; don't manually acquire.
|
// For use by AssetListLock; don't manually acquire.
|
||||||
std::mutex asset_lists_mutex_;
|
std::mutex asset_lists_mutex_;
|
||||||
|
|
||||||
// Will be true while a AssetListLock exists. Good to debug-verify this
|
|
||||||
// during any asset list access.
|
|
||||||
bool asset_lists_locked_{};
|
|
||||||
|
|
||||||
// 'hard-wired' internal assets
|
|
||||||
bool asset_loads_allowed_{};
|
|
||||||
bool sys_assets_loaded_{};
|
|
||||||
std::vector<Object::Ref<TextureAsset> > system_textures_;
|
std::vector<Object::Ref<TextureAsset> > system_textures_;
|
||||||
std::vector<Object::Ref<TextureAsset> > system_cube_map_textures_;
|
std::vector<Object::Ref<TextureAsset> > system_cube_map_textures_;
|
||||||
std::vector<Object::Ref<SoundAsset> > system_sounds_;
|
std::vector<Object::Ref<SoundAsset> > system_sounds_;
|
||||||
@ -177,7 +180,6 @@ class Assets {
|
|||||||
// Text & Language (need to mold this into more asset-like concepts).
|
// Text & Language (need to mold this into more asset-like concepts).
|
||||||
std::mutex language_mutex_;
|
std::mutex language_mutex_;
|
||||||
std::unordered_map<std::string, std::string> language_;
|
std::unordered_map<std::string, std::string> language_;
|
||||||
int language_state_{};
|
|
||||||
std::mutex special_char_mutex_;
|
std::mutex special_char_mutex_;
|
||||||
std::unordered_map<SpecialChar, std::string> special_char_strings_;
|
std::unordered_map<SpecialChar, std::string> special_char_strings_;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "ballistica/base/assets/asset.h"
|
#include "ballistica/base/assets/asset.h"
|
||||||
#include "ballistica/base/assets/assets.h"
|
#include "ballistica/base/assets/assets.h"
|
||||||
|
#include "ballistica/base/graphics/graphics.h"
|
||||||
#include "ballistica/base/graphics/graphics_server.h"
|
#include "ballistica/base/graphics/graphics_server.h"
|
||||||
#include "ballistica/base/support/huffman.h"
|
#include "ballistica/base/support/huffman.h"
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
@ -221,12 +222,18 @@ void AssetsServer::WriteReplayMessages() {
|
|||||||
void AssetsServer::Process() {
|
void AssetsServer::Process() {
|
||||||
// Make sure we don't do any loading until we know what kind/quality of
|
// Make sure we don't do any loading until we know what kind/quality of
|
||||||
// textures we'll be loading.
|
// textures we'll be loading.
|
||||||
if (!g_base->assets || !g_base->graphics_server
|
|
||||||
|| !g_base->graphics_server
|
// FIXME - we'll need to revisit this when adding support for
|
||||||
->texture_compression_types_are_set() // NOLINT
|
// renderer switches, since this is not especially thread-safe.
|
||||||
|| !g_base->graphics_server->texture_quality_set()) {
|
|
||||||
|
if (!g_base->graphics->has_client_context()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// if (!g_base->assets ||
|
||||||
|
// || !g_base->graphics->texture_compression_types_are_set() // NOLINT
|
||||||
|
// || !g_base->graphics_server->texture_quality_set()) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
// Process exactly 1 preload item. Empty out our non-audio list first
|
// Process exactly 1 preload item. Empty out our non-audio list first
|
||||||
// (audio is less likely to cause noticeable hitches if it needs to be loaded
|
// (audio is less likely to cause noticeable hitches if it needs to be loaded
|
||||||
|
|||||||
@ -93,11 +93,14 @@ auto TextureAsset::GetNameFull() const -> std::string {
|
|||||||
void TextureAsset::DoPreload() {
|
void TextureAsset::DoPreload() {
|
||||||
assert(valid_);
|
assert(valid_);
|
||||||
|
|
||||||
assert(g_base->graphics_server
|
// Make sure we're not loading without knowing what texture types we
|
||||||
&& g_base->graphics_server->texture_compression_types_are_set());
|
// support.
|
||||||
|
// assert(g_base->graphics->has_client_context());
|
||||||
|
// assert(g_base->graphics_server
|
||||||
|
// && g_base->graphics_server->texture_compression_types_are_set());
|
||||||
|
|
||||||
// We figure out which LOD should be our base level based on quality.
|
// Figure out which LOD should be our base level based on texture quality.
|
||||||
TextureQuality texture_quality = g_base->graphics_server->texture_quality();
|
auto texture_quality = g_base->graphics->placeholder_texture_quality();
|
||||||
|
|
||||||
// If we're a text-texture.
|
// If we're a text-texture.
|
||||||
if (packer_.Exists()) {
|
if (packer_.Exists()) {
|
||||||
@ -218,12 +221,14 @@ void TextureAsset::DoPreload() {
|
|||||||
&preload_datas_[0].base_level);
|
&preload_datas_[0].base_level);
|
||||||
|
|
||||||
// We should only be loading this if we support etc1 in hardware.
|
// We should only be loading this if we support etc1 in hardware.
|
||||||
assert(g_base->graphics_server->SupportsTextureCompressionType(
|
assert(g_base->graphics->placeholder_client_context()
|
||||||
TextureCompressionType::kETC1));
|
->SupportsTextureCompressionType(
|
||||||
|
TextureCompressionType::kETC1));
|
||||||
|
|
||||||
// Decompress dxt1/dxt5 ones if we don't natively support S3TC.
|
// Decompress dxt1/dxt5 ones if we don't natively support S3TC.
|
||||||
if (!g_base->graphics_server->SupportsTextureCompressionType(
|
if (!g_base->graphics->placeholder_client_context()
|
||||||
TextureCompressionType::kS3TC)) {
|
->SupportsTextureCompressionType(
|
||||||
|
TextureCompressionType::kS3TC)) {
|
||||||
if ((preload_datas_[0].formats[preload_datas_[0].base_level]
|
if ((preload_datas_[0].formats[preload_datas_[0].base_level]
|
||||||
== TextureFormat::kDXT5)
|
== TextureFormat::kDXT5)
|
||||||
|| (preload_datas_[0].formats[preload_datas_[0].base_level]
|
|| (preload_datas_[0].formats[preload_datas_[0].base_level]
|
||||||
@ -241,8 +246,9 @@ void TextureAsset::DoPreload() {
|
|||||||
&preload_datas_[0].base_level);
|
&preload_datas_[0].base_level);
|
||||||
|
|
||||||
// Decompress dxt1/dxt5 if we don't natively support it.
|
// Decompress dxt1/dxt5 if we don't natively support it.
|
||||||
if (!g_base->graphics_server->SupportsTextureCompressionType(
|
if (!g_base->graphics->placeholder_client_context()
|
||||||
TextureCompressionType::kS3TC)) {
|
->SupportsTextureCompressionType(
|
||||||
|
TextureCompressionType::kS3TC)) {
|
||||||
preload_datas_[0].ConvertToUncompressed(this);
|
preload_datas_[0].ConvertToUncompressed(this);
|
||||||
}
|
}
|
||||||
} else if (!strcmp(file_name_full_.c_str() + file_name_size - 4,
|
} else if (!strcmp(file_name_full_.c_str() + file_name_size - 4,
|
||||||
@ -264,16 +270,18 @@ void TextureAsset::DoPreload() {
|
|||||||
== TextureFormat::kETC2_RGB)
|
== TextureFormat::kETC2_RGB)
|
||||||
|| (preload_datas_[0].formats[preload_datas_[0].base_level]
|
|| (preload_datas_[0].formats[preload_datas_[0].base_level]
|
||||||
== TextureFormat::kETC2_RGBA))
|
== TextureFormat::kETC2_RGBA))
|
||||||
&& (!g_base->graphics_server->SupportsTextureCompressionType(
|
&& (!g_base->graphics->placeholder_client_context()
|
||||||
TextureCompressionType::kETC2))) {
|
->SupportsTextureCompressionType(
|
||||||
|
TextureCompressionType::kETC2))) {
|
||||||
preload_datas_[0].ConvertToUncompressed(this);
|
preload_datas_[0].ConvertToUncompressed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decompress etc1 if we don't natively support it.
|
// Decompress etc1 if we don't natively support it.
|
||||||
if ((preload_datas_[0].formats[preload_datas_[0].base_level]
|
if ((preload_datas_[0].formats[preload_datas_[0].base_level]
|
||||||
== TextureFormat::kETC1)
|
== TextureFormat::kETC1)
|
||||||
&& (!g_base->graphics_server->SupportsTextureCompressionType(
|
&& (!g_base->graphics->placeholder_client_context()
|
||||||
TextureCompressionType::kETC1))) {
|
->SupportsTextureCompressionType(
|
||||||
|
TextureCompressionType::kETC1))) {
|
||||||
preload_datas_[0].ConvertToUncompressed(this);
|
preload_datas_[0].ConvertToUncompressed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,8 +295,9 @@ void TextureAsset::DoPreload() {
|
|||||||
&preload_datas_[0].base_level);
|
&preload_datas_[0].base_level);
|
||||||
|
|
||||||
// We should only be loading this if we support pvr in hardware.
|
// We should only be loading this if we support pvr in hardware.
|
||||||
assert(g_base->graphics_server->SupportsTextureCompressionType(
|
assert(
|
||||||
TextureCompressionType::kPVR));
|
g_base->graphics->placeholder_client_context()
|
||||||
|
->SupportsTextureCompressionType(TextureCompressionType::kPVR));
|
||||||
} else if (!strcmp(file_name_full_.c_str() + file_name_size - 4,
|
} else if (!strcmp(file_name_full_.c_str() + file_name_size - 4,
|
||||||
".nop")) {
|
".nop")) {
|
||||||
// Dummy path for headless; nothing to do here.
|
// Dummy path for headless; nothing to do here.
|
||||||
@ -342,12 +351,14 @@ void TextureAsset::DoPreload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We should only be loading this if we support etc1 in hardware.
|
// We should only be loading this if we support etc1 in hardware.
|
||||||
assert(g_base->graphics_server->SupportsTextureCompressionType(
|
assert(g_base->graphics->placeholder_client_context()
|
||||||
TextureCompressionType::kETC1));
|
->SupportsTextureCompressionType(
|
||||||
|
TextureCompressionType::kETC1));
|
||||||
|
|
||||||
// Decompress dxt1/dxt5 ones if we don't natively support S3TC.
|
// Decompress dxt1/dxt5 ones if we don't natively support S3TC.
|
||||||
if (!g_base->graphics_server->SupportsTextureCompressionType(
|
if (!g_base->graphics->placeholder_client_context()
|
||||||
TextureCompressionType::kS3TC)) {
|
->SupportsTextureCompressionType(
|
||||||
|
TextureCompressionType::kS3TC)) {
|
||||||
if ((preload_datas_[d].formats[preload_datas_[d].base_level]
|
if ((preload_datas_[d].formats[preload_datas_[d].base_level]
|
||||||
== TextureFormat::kDXT5)
|
== TextureFormat::kDXT5)
|
||||||
|| (preload_datas_[d].formats[preload_datas_[d].base_level]
|
|| (preload_datas_[d].formats[preload_datas_[d].base_level]
|
||||||
@ -365,8 +376,9 @@ void TextureAsset::DoPreload() {
|
|||||||
&preload_datas_[d].base_level);
|
&preload_datas_[d].base_level);
|
||||||
|
|
||||||
// Decompress dxt1/dxt5 if we don't natively support it.
|
// Decompress dxt1/dxt5 if we don't natively support it.
|
||||||
if (!g_base->graphics_server->SupportsTextureCompressionType(
|
if (!g_base->graphics->placeholder_client_context()
|
||||||
TextureCompressionType::kS3TC)) {
|
->SupportsTextureCompressionType(
|
||||||
|
TextureCompressionType::kS3TC)) {
|
||||||
preload_datas_[d].ConvertToUncompressed(this);
|
preload_datas_[d].ConvertToUncompressed(this);
|
||||||
}
|
}
|
||||||
} else if (!strcmp(file_name_full_.c_str() + file_name_size - 4,
|
} else if (!strcmp(file_name_full_.c_str() + file_name_size - 4,
|
||||||
@ -383,16 +395,18 @@ void TextureAsset::DoPreload() {
|
|||||||
== TextureFormat::kETC2_RGB)
|
== TextureFormat::kETC2_RGB)
|
||||||
|| (preload_datas_[d].formats[preload_datas_[d].base_level]
|
|| (preload_datas_[d].formats[preload_datas_[d].base_level]
|
||||||
== TextureFormat::kETC2_RGBA))
|
== TextureFormat::kETC2_RGBA))
|
||||||
&& (!g_base->graphics_server->SupportsTextureCompressionType(
|
&& (!g_base->graphics->placeholder_client_context()
|
||||||
TextureCompressionType::kETC2))) {
|
->SupportsTextureCompressionType(
|
||||||
|
TextureCompressionType::kETC2))) {
|
||||||
preload_datas_[d].ConvertToUncompressed(this);
|
preload_datas_[d].ConvertToUncompressed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decompress etc1 if we don't natively support it.
|
// Decompress etc1 if we don't natively support it.
|
||||||
if ((preload_datas_[d].formats[preload_datas_[d].base_level]
|
if ((preload_datas_[d].formats[preload_datas_[d].base_level]
|
||||||
== TextureFormat::kETC1)
|
== TextureFormat::kETC1)
|
||||||
&& (!g_base->graphics_server->SupportsTextureCompressionType(
|
&& (!g_base->graphics->placeholder_client_context()
|
||||||
TextureCompressionType::kETC1))) {
|
->SupportsTextureCompressionType(
|
||||||
|
TextureCompressionType::kETC1))) {
|
||||||
preload_datas_[d].ConvertToUncompressed(this);
|
preload_datas_[d].ConvertToUncompressed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "ballistica/base/assets/sound_asset.h"
|
#include "ballistica/base/assets/sound_asset.h"
|
||||||
#include "ballistica/base/audio/audio_server.h"
|
#include "ballistica/base/audio/audio_server.h"
|
||||||
#include "ballistica/base/audio/audio_source.h"
|
#include "ballistica/base/audio/audio_source.h"
|
||||||
|
#include "ballistica/base/graphics/graphics.h"
|
||||||
#include "ballistica/base/support/app_config.h"
|
#include "ballistica/base/support/app_config.h"
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
|
|
||||||
@ -12,6 +13,19 @@ namespace ballistica::base {
|
|||||||
|
|
||||||
Audio::Audio() = default;
|
Audio::Audio() = default;
|
||||||
|
|
||||||
|
auto Audio::UseLowQualityAudio() -> bool {
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
|
// Currently just piggybacking off graphics quality here.
|
||||||
|
if (g_core->HeadlessMode() || g_base->graphics->has_client_context()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// We don't have a frame-def to look at so need to calc this ourself; ugh.
|
||||||
|
auto quality = Graphics::GraphicsQualityFromRequest(
|
||||||
|
g_base->graphics->settings()->graphics_quality,
|
||||||
|
g_base->graphics->client_context()->auto_graphics_quality);
|
||||||
|
return quality < GraphicsQuality::kMedium;
|
||||||
|
}
|
||||||
|
|
||||||
void Audio::Reset() {
|
void Audio::Reset() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
g_base->audio_server->PushResetCall();
|
g_base->audio_server->PushResetCall();
|
||||||
|
|||||||
@ -29,36 +29,41 @@ class Audio {
|
|||||||
virtual void OnScreenSizeChange();
|
virtual void OnScreenSizeChange();
|
||||||
virtual void StepDisplayTime();
|
virtual void StepDisplayTime();
|
||||||
|
|
||||||
|
/// Can be keyed off of to cut corners in audio (leaving sounds out, etc.)
|
||||||
|
/// Currently just piggybacks off graphics quality settings but this logic
|
||||||
|
/// may get fancier in the future.
|
||||||
|
auto UseLowQualityAudio() -> bool;
|
||||||
|
|
||||||
void SetVolumes(float music_volume, float sound_volume);
|
void SetVolumes(float music_volume, float sound_volume);
|
||||||
|
|
||||||
void SetListenerPosition(const Vector3f& p);
|
void SetListenerPosition(const Vector3f& p);
|
||||||
void SetListenerOrientation(const Vector3f& forward, const Vector3f& up);
|
void SetListenerOrientation(const Vector3f& forward, const Vector3f& up);
|
||||||
void SetSoundPitch(float pitch);
|
void SetSoundPitch(float pitch);
|
||||||
|
|
||||||
// Return a pointer to a locked sound source, or nullptr if they're all busy.
|
/// Return a pointer to a locked sound source, or nullptr if they're all busy.
|
||||||
// The sound source will be reset to standard settings (no loop, fade 1, pos
|
/// The sound source will be reset to standard settings (no loop, fade 1, pos
|
||||||
// 0,0,0, etc.).
|
/// 0,0,0, etc.).
|
||||||
// Send the source any immediate commands and then unlock it.
|
/// Send the source any immediate commands and then unlock it.
|
||||||
// For later modifications, re-retrieve the sound with GetPlayingSound()
|
/// For later modifications, re-retrieve the sound with GetPlayingSound()
|
||||||
auto SourceBeginNew() -> AudioSource*;
|
auto SourceBeginNew() -> AudioSource*;
|
||||||
|
|
||||||
// If a sound play id is playing, locks and returns its sound source.
|
/// If a sound play id is playing, locks and returns its sound source.
|
||||||
// on success, you must unlock the source once done with it.
|
/// on success, you must unlock the source once done with it.
|
||||||
auto SourceBeginExisting(uint32_t play_id, int debug_id) -> AudioSource*;
|
auto SourceBeginExisting(uint32_t play_id, int debug_id) -> AudioSource*;
|
||||||
|
|
||||||
// Return true if the sound id is currently valid. This is not guaranteed
|
/// Return true if the sound id is currently valid. This is not guaranteed
|
||||||
// to be super accurate, but can be used to determine if a sound is still
|
/// to be super accurate, but can be used to determine if a sound is still
|
||||||
// playing.
|
/// playing.
|
||||||
auto IsSoundPlaying(uint32_t play_id) -> bool;
|
auto IsSoundPlaying(uint32_t play_id) -> bool;
|
||||||
|
|
||||||
// Simple one-shot play functions.
|
/// Simple one-shot play functions.
|
||||||
auto PlaySound(SoundAsset* s, float volume = 1.0f) -> std::optional<uint32_t>;
|
auto PlaySound(SoundAsset* s, float volume = 1.0f) -> std::optional<uint32_t>;
|
||||||
auto PlaySoundAtPosition(SoundAsset* sound, float volume, float x, float y,
|
auto PlaySoundAtPosition(SoundAsset* sound, float volume, float x, float y,
|
||||||
float z) -> std::optional<uint32_t>;
|
float z) -> std::optional<uint32_t>;
|
||||||
|
|
||||||
// Call this if you want to prevent repeated plays of the same sound. It'll
|
/// Call this if you want to prevent repeated plays of the same sound. It'll
|
||||||
// tell you if the sound has been played recently. The one-shot sound-play
|
/// tell you if the sound has been played recently. The one-shot sound-play
|
||||||
// functions use this under the hood. (PlaySound, PlaySoundAtPosition).
|
/// functions use this under the hood. (PlaySound, PlaySoundAtPosition).
|
||||||
auto ShouldPlay(SoundAsset* s) -> bool;
|
auto ShouldPlay(SoundAsset* s) -> bool;
|
||||||
|
|
||||||
// Hmm; shouldn't these be accessed through the Source class?
|
// Hmm; shouldn't these be accessed through the Source class?
|
||||||
@ -73,15 +78,15 @@ class Audio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Flat list of client sources indexed by id.
|
/// Flat list of client sources indexed by id.
|
||||||
std::vector<AudioSource*> client_sources_;
|
std::vector<AudioSource*> client_sources_;
|
||||||
|
|
||||||
// List of sources that are ready to use.
|
/// List of sources that are ready to use.
|
||||||
// This is kept filled by the audio thread
|
/// This is kept filled by the audio thread
|
||||||
// and used by the client.
|
/// and used by the client.
|
||||||
std::vector<AudioSource*> available_sources_;
|
std::vector<AudioSource*> available_sources_;
|
||||||
|
|
||||||
// This must be locked whenever accessing the availableSources list.
|
/// This must be locked whenever accessing the availableSources list.
|
||||||
std::mutex available_sources_mutex_;
|
std::mutex available_sources_mutex_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -420,6 +420,10 @@ auto BaseFeatureSet::IsUnmodifiedBlessedBuild() -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto BaseFeatureSet::InMainThread() const -> bool {
|
||||||
|
return g_core->InMainThread();
|
||||||
|
}
|
||||||
|
|
||||||
auto BaseFeatureSet::InAssetsThread() const -> bool {
|
auto BaseFeatureSet::InAssetsThread() const -> bool {
|
||||||
if (auto* loop = assets_server->event_loop()) {
|
if (auto* loop = assets_server->event_loop()) {
|
||||||
return loop->ThreadIsCurrent();
|
return loop->ThreadIsCurrent();
|
||||||
@ -658,6 +662,10 @@ void BaseFeatureSet::DoPushObjCall(const PythonObjectSetBase* objset, int id,
|
|||||||
|
|
||||||
auto BaseFeatureSet::IsAppStarted() const -> bool { return app_started_; }
|
auto BaseFeatureSet::IsAppStarted() const -> bool { return app_started_; }
|
||||||
|
|
||||||
|
auto BaseFeatureSet::IsAppBootstrapped() const -> bool {
|
||||||
|
return logic->app_bootstrapping_complete();
|
||||||
|
}
|
||||||
|
|
||||||
auto BaseFeatureSet::ShutdownSuppressBegin() -> bool {
|
auto BaseFeatureSet::ShutdownSuppressBegin() -> bool {
|
||||||
std::scoped_lock lock(shutdown_suppress_lock_);
|
std::scoped_lock lock(shutdown_suppress_lock_);
|
||||||
|
|
||||||
|
|||||||
@ -59,6 +59,8 @@ class DataAsset;
|
|||||||
class FrameDef;
|
class FrameDef;
|
||||||
class Graphics;
|
class Graphics;
|
||||||
class GraphicsServer;
|
class GraphicsServer;
|
||||||
|
struct GraphicsSettings;
|
||||||
|
struct GraphicsClientContext;
|
||||||
class Huffman;
|
class Huffman;
|
||||||
class ImageMesh;
|
class ImageMesh;
|
||||||
class Input;
|
class Input;
|
||||||
@ -662,6 +664,7 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
|||||||
/// allowing certain functionality before this time.
|
/// allowing certain functionality before this time.
|
||||||
auto IsBaseCompletelyImported() -> bool;
|
auto IsBaseCompletelyImported() -> bool;
|
||||||
|
|
||||||
|
auto InMainThread() const -> bool;
|
||||||
auto InAssetsThread() const -> bool override;
|
auto InAssetsThread() const -> bool override;
|
||||||
auto InLogicThread() const -> bool override;
|
auto InLogicThread() const -> bool override;
|
||||||
auto InAudioThread() const -> bool override;
|
auto InAudioThread() const -> bool override;
|
||||||
@ -672,11 +675,18 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
|||||||
/// High level screen-message call usable from any thread.
|
/// High level screen-message call usable from any thread.
|
||||||
void ScreenMessage(const std::string& s, const Vector3f& color) override;
|
void ScreenMessage(const std::string& s, const Vector3f& color) override;
|
||||||
|
|
||||||
/// Has StartApp been called (and completely finished its work)?
|
/// Has StartApp been called (and completely finished its work)? Code that
|
||||||
/// Code that sends calls/messages to other threads or otherwise uses
|
/// sends calls/messages to other threads or otherwise uses app
|
||||||
/// app functionality may want to check this to avoid crashes.
|
/// functionality may want to check this to avoid crashes. Note that some
|
||||||
|
/// app functionality such as loading assets is not available until
|
||||||
|
/// IsAppBootstrapped returns true. This call is thread safe.
|
||||||
auto IsAppStarted() const -> bool override;
|
auto IsAppStarted() const -> bool override;
|
||||||
|
|
||||||
|
/// Has the app bootstrapping phase completed? The bootstrapping phase
|
||||||
|
/// involves initial screen/graphics setup. Asset loading is not allowed
|
||||||
|
/// until it is complete.
|
||||||
|
auto IsAppBootstrapped() const -> bool override;
|
||||||
|
|
||||||
void PlusDirectSendV1CloudLogs(const std::string& prefix,
|
void PlusDirectSendV1CloudLogs(const std::string& prefix,
|
||||||
const std::string& suffix, bool instant,
|
const std::string& suffix, bool instant,
|
||||||
int* result) override;
|
int* result) override;
|
||||||
|
|||||||
@ -39,10 +39,15 @@ void BGDynamics::Emit(const BGDynamicsEmission& e) {
|
|||||||
void BGDynamics::Step(const Vector3f& cam_pos, int step_millisecs) {
|
void BGDynamics::Step(const Vector3f& cam_pos, int step_millisecs) {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
|
// Don't actually start doing anything until there's a
|
||||||
|
// client-graphics-context. We need this to calculate qualities/etc.
|
||||||
|
if (!g_base->graphics->has_client_context()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// The BG dynamics thread just processes steps as fast as it can;
|
// The BG dynamics thread just processes steps as fast as it can;
|
||||||
// we need to throttle what we send or tell it to cut back if its behind
|
// we need to throttle what we send or tell it to cut back if its behind
|
||||||
int step_count = g_base->bg_dynamics_server->step_count();
|
int step_count = g_base->bg_dynamics_server->step_count();
|
||||||
// printf("STEP COUNT %d\n", step_count);
|
|
||||||
|
|
||||||
// If we're really getting behind, start pruning stuff.
|
// If we're really getting behind, start pruning stuff.
|
||||||
if (step_count > 3) {
|
if (step_count > 3) {
|
||||||
@ -62,6 +67,9 @@ void BGDynamics::Step(const Vector3f& cam_pos, int step_millisecs) {
|
|||||||
// Pass a newly allocated raw pointer to the bg-dynamics thread; it takes care
|
// Pass a newly allocated raw pointer to the bg-dynamics thread; it takes care
|
||||||
// of disposing it when done.
|
// of disposing it when done.
|
||||||
auto d = Object::NewDeferred<BGDynamicsServer::StepData>();
|
auto d = Object::NewDeferred<BGDynamicsServer::StepData>();
|
||||||
|
d->graphics_quality = Graphics::GraphicsQualityFromRequest(
|
||||||
|
g_base->graphics->settings()->graphics_quality,
|
||||||
|
g_base->graphics->client_context()->auto_graphics_quality);
|
||||||
d->step_millisecs = step_millisecs;
|
d->step_millisecs = step_millisecs;
|
||||||
d->cam_pos = cam_pos;
|
d->cam_pos = cam_pos;
|
||||||
|
|
||||||
@ -174,7 +182,7 @@ void BGDynamics::Draw(FrameDef* frame_def) {
|
|||||||
|
|
||||||
// In high-quality, we draw in the overlay pass so that we don't get wiped
|
// In high-quality, we draw in the overlay pass so that we don't get wiped
|
||||||
// out by depth-of-field.
|
// out by depth-of-field.
|
||||||
bool draw_in_overlay = (frame_def->quality() >= GraphicsQuality::kHigh);
|
bool draw_in_overlay = frame_def->quality() >= GraphicsQuality::kHigh;
|
||||||
SpriteComponent c(draw_in_overlay ? frame_def->overlay_3d_pass()
|
SpriteComponent c(draw_in_overlay ? frame_def->overlay_3d_pass()
|
||||||
: frame_def->beauty_pass());
|
: frame_def->beauty_pass());
|
||||||
c.SetCameraAligned(true);
|
c.SetCameraAligned(true);
|
||||||
@ -232,7 +240,7 @@ void BGDynamics::Draw(FrameDef* frame_def) {
|
|||||||
tendrils_mesh_->SetIndexData(ds->tendril_indices);
|
tendrils_mesh_->SetIndexData(ds->tendril_indices);
|
||||||
tendrils_mesh_->SetData(
|
tendrils_mesh_->SetData(
|
||||||
Object::Ref<MeshBuffer<VertexSmokeFull>>(ds->tendril_vertices));
|
Object::Ref<MeshBuffer<VertexSmokeFull>>(ds->tendril_vertices));
|
||||||
bool draw_in_overlay = (frame_def->quality() >= GraphicsQuality::kHigh);
|
bool draw_in_overlay = frame_def->quality() >= GraphicsQuality::kHigh;
|
||||||
SmokeComponent c(draw_in_overlay ? frame_def->overlay_3d_pass()
|
SmokeComponent c(draw_in_overlay ? frame_def->overlay_3d_pass()
|
||||||
: frame_def->beauty_pass());
|
: frame_def->beauty_pass());
|
||||||
c.SetOverlay(draw_in_overlay);
|
c.SetOverlay(draw_in_overlay);
|
||||||
|
|||||||
@ -2282,7 +2282,8 @@ void BGDynamicsServer::Step(StepData* step_data) {
|
|||||||
auto ref(Object::CompleteDeferred(step_data));
|
auto ref(Object::CompleteDeferred(step_data));
|
||||||
|
|
||||||
// Keep our quality in sync with the graphics thread's.
|
// Keep our quality in sync with the graphics thread's.
|
||||||
graphics_quality_ = g_base->graphics_server->graphics_quality();
|
graphics_quality_ = step_data->graphics_quality;
|
||||||
|
assert(graphics_quality_ != GraphicsQuality::kUnset);
|
||||||
|
|
||||||
cam_pos_ = step_data->cam_pos;
|
cam_pos_ = step_data->cam_pos;
|
||||||
|
|
||||||
|
|||||||
@ -73,6 +73,7 @@ class BGDynamicsServer {
|
|||||||
auto GetDefaultOwnerThread() const -> EventLoopID override {
|
auto GetDefaultOwnerThread() const -> EventLoopID override {
|
||||||
return EventLoopID::kBGDynamics;
|
return EventLoopID::kBGDynamics;
|
||||||
}
|
}
|
||||||
|
GraphicsQuality graphics_quality{};
|
||||||
int step_millisecs{};
|
int step_millisecs{};
|
||||||
Vector3f cam_pos{0.0f, 0.0f, 0.0f};
|
Vector3f cam_pos{0.0f, 0.0f, 0.0f};
|
||||||
|
|
||||||
|
|||||||
@ -238,10 +238,10 @@ class RendererGL::ProgramGL {
|
|||||||
|
|
||||||
// Update matrices as necessary.
|
// Update matrices as necessary.
|
||||||
|
|
||||||
uint32_t mvpState =
|
int mvp_state =
|
||||||
g_base->graphics_server->GetModelViewProjectionMatrixState();
|
g_base->graphics_server->GetModelViewProjectionMatrixState();
|
||||||
if (mvpState != mvp_state_) {
|
if (mvp_state != mvp_state_) {
|
||||||
mvp_state_ = mvpState;
|
mvp_state_ = mvp_state;
|
||||||
glUniformMatrix4fv(
|
glUniformMatrix4fv(
|
||||||
mvp_uniform_, 1, 0,
|
mvp_uniform_, 1, 0,
|
||||||
g_base->graphics_server->GetModelViewProjectionMatrix().m);
|
g_base->graphics_server->GetModelViewProjectionMatrix().m);
|
||||||
@ -251,7 +251,7 @@ class RendererGL::ProgramGL {
|
|||||||
if (pflags_ & PFLAG_USES_MODEL_WORLD_MATRIX) {
|
if (pflags_ & PFLAG_USES_MODEL_WORLD_MATRIX) {
|
||||||
// With world space points this would be identity; don't waste time.
|
// With world space points this would be identity; don't waste time.
|
||||||
assert(!(pflags_ & PFLAG_WORLD_SPACE_PTS));
|
assert(!(pflags_ & PFLAG_WORLD_SPACE_PTS));
|
||||||
uint32_t state = g_base->graphics_server->GetModelWorldMatrixState();
|
int state = g_base->graphics_server->GetModelWorldMatrixState();
|
||||||
if (state != model_world_matrix_state_) {
|
if (state != model_world_matrix_state_) {
|
||||||
model_world_matrix_state_ = state;
|
model_world_matrix_state_ = state;
|
||||||
glUniformMatrix4fv(model_world_matrix_uniform_, 1, 0,
|
glUniformMatrix4fv(model_world_matrix_uniform_, 1, 0,
|
||||||
@ -264,8 +264,7 @@ class RendererGL::ProgramGL {
|
|||||||
// With world space points this would be identity; don't waste time.
|
// With world space points this would be identity; don't waste time.
|
||||||
assert(!(pflags_ & PFLAG_WORLD_SPACE_PTS));
|
assert(!(pflags_ & PFLAG_WORLD_SPACE_PTS));
|
||||||
// There's no state for just modelview but this works.
|
// There's no state for just modelview but this works.
|
||||||
uint32_t state =
|
int state = g_base->graphics_server->GetModelViewProjectionMatrixState();
|
||||||
g_base->graphics_server->GetModelViewProjectionMatrixState();
|
|
||||||
if (state != model_view_matrix_state_) {
|
if (state != model_view_matrix_state_) {
|
||||||
model_view_matrix_state_ = state;
|
model_view_matrix_state_ = state;
|
||||||
glUniformMatrix4fv(model_view_matrix_uniform_, 1, 0,
|
glUniformMatrix4fv(model_view_matrix_uniform_, 1, 0,
|
||||||
@ -275,7 +274,7 @@ class RendererGL::ProgramGL {
|
|||||||
BA_DEBUG_CHECK_GL_ERROR;
|
BA_DEBUG_CHECK_GL_ERROR;
|
||||||
|
|
||||||
if (pflags_ & PFLAG_USES_CAM_POS) {
|
if (pflags_ & PFLAG_USES_CAM_POS) {
|
||||||
uint32_t state = g_base->graphics_server->cam_pos_state();
|
int state = g_base->graphics_server->cam_pos_state();
|
||||||
if (state != cam_pos_state_) {
|
if (state != cam_pos_state_) {
|
||||||
cam_pos_state_ = state;
|
cam_pos_state_ = state;
|
||||||
const Vector3f& p(g_base->graphics_server->cam_pos());
|
const Vector3f& p(g_base->graphics_server->cam_pos());
|
||||||
@ -285,7 +284,7 @@ class RendererGL::ProgramGL {
|
|||||||
BA_DEBUG_CHECK_GL_ERROR;
|
BA_DEBUG_CHECK_GL_ERROR;
|
||||||
|
|
||||||
if (pflags_ & PFLAG_USES_CAM_ORIENT_MATRIX) {
|
if (pflags_ & PFLAG_USES_CAM_ORIENT_MATRIX) {
|
||||||
uint32_t state = g_base->graphics_server->GetCamOrientMatrixState();
|
int state = g_base->graphics_server->GetCamOrientMatrixState();
|
||||||
if (state != cam_orient_matrix_state_) {
|
if (state != cam_orient_matrix_state_) {
|
||||||
cam_orient_matrix_state_ = state;
|
cam_orient_matrix_state_ = state;
|
||||||
glUniformMatrix4fv(cam_orient_matrix_uniform_, 1, 0,
|
glUniformMatrix4fv(cam_orient_matrix_uniform_, 1, 0,
|
||||||
@ -295,7 +294,7 @@ class RendererGL::ProgramGL {
|
|||||||
BA_DEBUG_CHECK_GL_ERROR;
|
BA_DEBUG_CHECK_GL_ERROR;
|
||||||
|
|
||||||
if (pflags_ & PFLAG_USES_SHADOW_PROJECTION_MATRIX) {
|
if (pflags_ & PFLAG_USES_SHADOW_PROJECTION_MATRIX) {
|
||||||
uint32_t state =
|
int state =
|
||||||
g_base->graphics_server->light_shadow_projection_matrix_state();
|
g_base->graphics_server->light_shadow_projection_matrix_state();
|
||||||
if (state != light_shadow_projection_matrix_state_) {
|
if (state != light_shadow_projection_matrix_state_) {
|
||||||
light_shadow_projection_matrix_state_ = state;
|
light_shadow_projection_matrix_state_ = state;
|
||||||
@ -336,19 +335,19 @@ class RendererGL::ProgramGL {
|
|||||||
Object::Ref<VertexShaderGL> vertex_shader_;
|
Object::Ref<VertexShaderGL> vertex_shader_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
GLuint program_{};
|
GLuint program_{};
|
||||||
int pflags_{};
|
|
||||||
uint32_t mvp_state_{};
|
|
||||||
GLint mvp_uniform_{};
|
GLint mvp_uniform_{};
|
||||||
GLint model_world_matrix_uniform_{};
|
GLint model_world_matrix_uniform_{};
|
||||||
GLint model_view_matrix_uniform_{};
|
GLint model_view_matrix_uniform_{};
|
||||||
GLint light_shadow_projection_matrix_uniform_{};
|
GLint light_shadow_projection_matrix_uniform_{};
|
||||||
uint32_t light_shadow_projection_matrix_state_{};
|
|
||||||
uint32_t model_world_matrix_state_{};
|
|
||||||
uint32_t model_view_matrix_state_{};
|
|
||||||
GLint cam_pos_uniform_{};
|
GLint cam_pos_uniform_{};
|
||||||
uint32_t cam_pos_state_{};
|
|
||||||
GLint cam_orient_matrix_uniform_{};
|
GLint cam_orient_matrix_uniform_{};
|
||||||
GLuint cam_orient_matrix_state_{};
|
int cam_orient_matrix_state_{};
|
||||||
|
int light_shadow_projection_matrix_state_{};
|
||||||
|
int pflags_{};
|
||||||
|
int mvp_state_{};
|
||||||
|
int cam_pos_state_{};
|
||||||
|
int model_world_matrix_state_{};
|
||||||
|
int model_view_matrix_state_{};
|
||||||
BA_DISALLOW_CLASS_COPIES(ProgramGL);
|
BA_DISALLOW_CLASS_COPIES(ProgramGL);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -366,7 +366,7 @@ void RendererGL::CheckGLCapabilities_() {
|
|||||||
|
|
||||||
// Both GL 3 and GL ES 3.0 support depth textures (and thus our high
|
// Both GL 3 and GL ES 3.0 support depth textures (and thus our high
|
||||||
// quality mode) as a core feature.
|
// quality mode) as a core feature.
|
||||||
g_base->graphics->SetSupportsHighQualityGraphics(true);
|
// g_base->graphics->SetSupportsHighQualityGraphics(true);
|
||||||
|
|
||||||
// Store the tex-compression type we support.
|
// Store the tex-compression type we support.
|
||||||
BA_DEBUG_CHECK_GL_ERROR;
|
BA_DEBUG_CHECK_GL_ERROR;
|
||||||
@ -2598,7 +2598,8 @@ void RendererGL::RetainShader_(ProgramGL* p) { shaders_.emplace_back(p); }
|
|||||||
void RendererGL::Load() {
|
void RendererGL::Load() {
|
||||||
assert(g_base->app_adapter->InGraphicsContext());
|
assert(g_base->app_adapter->InGraphicsContext());
|
||||||
assert(!data_loaded_);
|
assert(!data_loaded_);
|
||||||
assert(g_base->graphics_server->graphics_quality_set());
|
assert(g_base->graphics_server->graphics_quality()
|
||||||
|
!= GraphicsQuality::kUnset);
|
||||||
BA_DEBUG_CHECK_GL_ERROR;
|
BA_DEBUG_CHECK_GL_ERROR;
|
||||||
if (!got_screen_framebuffer_) {
|
if (!got_screen_framebuffer_) {
|
||||||
got_screen_framebuffer_ = true;
|
got_screen_framebuffer_ = true;
|
||||||
|
|||||||
@ -115,9 +115,14 @@ void Graphics::OnAppShutdownComplete() { assert(g_base->InLogicThread()); }
|
|||||||
void Graphics::DoApplyAppConfig() {
|
void Graphics::DoApplyAppConfig() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
|
// Any time we load the config we ship a new graphics-settings to
|
||||||
|
// the graphics server since something likely changed.
|
||||||
|
graphics_settings_dirty_ = true;
|
||||||
|
|
||||||
show_fps_ = g_base->app_config->Resolve(AppConfig::BoolID::kShowFPS);
|
show_fps_ = g_base->app_config->Resolve(AppConfig::BoolID::kShowFPS);
|
||||||
show_ping_ = g_base->app_config->Resolve(AppConfig::BoolID::kShowPing);
|
show_ping_ = g_base->app_config->Resolve(AppConfig::BoolID::kShowPing);
|
||||||
tv_border_ = g_base->app_config->Resolve(AppConfig::BoolID::kEnableTVBorder);
|
// tv_border_ =
|
||||||
|
// g_base->app_config->Resolve(AppConfig::BoolID::kEnableTVBorder);
|
||||||
|
|
||||||
bool disable_camera_shake =
|
bool disable_camera_shake =
|
||||||
g_base->app_config->Resolve(AppConfig::BoolID::kDisableCameraShake);
|
g_base->app_config->Resolve(AppConfig::BoolID::kDisableCameraShake);
|
||||||
@ -126,6 +131,52 @@ void Graphics::DoApplyAppConfig() {
|
|||||||
bool disable_camera_gyro =
|
bool disable_camera_gyro =
|
||||||
g_base->app_config->Resolve(AppConfig::BoolID::kDisableCameraGyro);
|
g_base->app_config->Resolve(AppConfig::BoolID::kDisableCameraGyro);
|
||||||
set_camera_gyro_explicitly_disabled(disable_camera_gyro);
|
set_camera_gyro_explicitly_disabled(disable_camera_gyro);
|
||||||
|
|
||||||
|
applied_app_config_ = true;
|
||||||
|
|
||||||
|
// At this point we may want to send initial graphics settings to the
|
||||||
|
// graphics server if we haven't.
|
||||||
|
UpdateInitialGraphicsSettingsSend_();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graphics::UpdateInitialGraphicsSettingsSend_() {
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
|
if (sent_initial_graphics_settings_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to send an initial graphics-settings to the server to kick
|
||||||
|
// things off, but we need a few things to be in place first.
|
||||||
|
auto app_config_ready = applied_app_config_;
|
||||||
|
// At some point we may want to wait to know our actual screen res before
|
||||||
|
// sending. This won't apply everywhere though since on some platforms the
|
||||||
|
// screen doesn't exist until we send this.
|
||||||
|
auto screen_resolution_ready = true;
|
||||||
|
|
||||||
|
if (app_config_ready && screen_resolution_ready) {
|
||||||
|
// Update/grab the current settings snapshot.
|
||||||
|
auto* settings = GetGraphicsSettingsSnapshot();
|
||||||
|
|
||||||
|
// We need to explicitly push settings to the graphics server to kick
|
||||||
|
// things off. We need to keep this settings instance alive until
|
||||||
|
// handled by the graphics context (which might be in another thread
|
||||||
|
// where we're not allowed to muck with settings' refs from). So let's
|
||||||
|
// explicitly increment its refcount here in the logic thread now and
|
||||||
|
// then push a call back here to decrement it when we're done.
|
||||||
|
settings->ObjectIncrementStrongRefCount();
|
||||||
|
// auto* s = settings_.Get();
|
||||||
|
g_base->app_adapter->PushGraphicsContextCall([settings] {
|
||||||
|
assert(g_base->app_adapter->InGraphicsContext());
|
||||||
|
g_base->graphics_server->ApplySettings(settings->Get());
|
||||||
|
g_base->logic->event_loop()->PushCall([settings] {
|
||||||
|
// Release our strong ref back here in the logic thread.
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
|
settings->ObjectDecrementStrongRefCount();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
sent_initial_graphics_settings_ = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::StepDisplayTime() { assert(g_base->InLogicThread()); }
|
void Graphics::StepDisplayTime() { assert(g_base->InLogicThread()); }
|
||||||
@ -976,6 +1027,20 @@ auto Graphics::GetEmptyFrameDef() -> FrameDef* {
|
|||||||
return frame_def;
|
return frame_def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Graphics::GetGraphicsSettingsSnapshot() -> Snapshot<GraphicsSettings>* {
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
|
// If need be, ask the app-adapter to build us a new settings instance.
|
||||||
|
if (graphics_settings_dirty_) {
|
||||||
|
auto* new_settings = g_base->app_adapter->GetGraphicsSettings();
|
||||||
|
new_settings->index = next_settings_index_++;
|
||||||
|
settings_snapshot_ = Object::New<Snapshot<GraphicsSettings>>(new_settings);
|
||||||
|
graphics_settings_dirty_ = false;
|
||||||
|
}
|
||||||
|
assert(settings_snapshot_.Exists());
|
||||||
|
return settings_snapshot_.Get();
|
||||||
|
}
|
||||||
|
|
||||||
void Graphics::ClearFrameDefDeleteList() {
|
void Graphics::ClearFrameDefDeleteList() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
std::scoped_lock lock(frame_def_delete_list_mutex_);
|
std::scoped_lock lock(frame_def_delete_list_mutex_);
|
||||||
@ -1120,6 +1185,8 @@ void Graphics::DrawDevUI(FrameDef* frame_def) {
|
|||||||
|
|
||||||
void Graphics::BuildAndPushFrameDef() {
|
void Graphics::BuildAndPushFrameDef() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
|
BA_PRECONDITION_FATAL(g_base->logic->app_bootstrapping_complete());
|
||||||
assert(camera_.Exists());
|
assert(camera_.Exists());
|
||||||
assert(!g_core->HeadlessMode());
|
assert(!g_core->HeadlessMode());
|
||||||
|
|
||||||
@ -1128,10 +1195,6 @@ void Graphics::BuildAndPushFrameDef() {
|
|||||||
assert(!building_frame_def_);
|
assert(!building_frame_def_);
|
||||||
building_frame_def_ = true;
|
building_frame_def_ = true;
|
||||||
|
|
||||||
// We should not be building/pushing any frames until the native
|
|
||||||
// layer is fully bootstrapped.
|
|
||||||
BA_PRECONDITION_FATAL(g_base->logic->app_bootstrapping_complete());
|
|
||||||
|
|
||||||
microsecs_t app_time_microsecs = g_core->GetAppTimeMicrosecs();
|
microsecs_t app_time_microsecs = g_core->GetAppTimeMicrosecs();
|
||||||
|
|
||||||
// Store how much time this frame_def represents.
|
// Store how much time this frame_def represents.
|
||||||
@ -1187,13 +1250,6 @@ void Graphics::BuildAndPushFrameDef() {
|
|||||||
internal_components_inited_ = true;
|
internal_components_inited_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If graphics quality has changed since our last draw, inform anyone who
|
|
||||||
// wants to know.
|
|
||||||
if (last_frame_def_graphics_quality_ != frame_def->quality()) {
|
|
||||||
last_frame_def_graphics_quality_ = frame_def->quality();
|
|
||||||
g_base->app_mode()->GraphicsQualityChanged(frame_def->quality());
|
|
||||||
}
|
|
||||||
|
|
||||||
ApplyCamera(frame_def);
|
ApplyCamera(frame_def);
|
||||||
|
|
||||||
if (progress_bar_) {
|
if (progress_bar_) {
|
||||||
@ -1254,7 +1310,7 @@ void Graphics::BuildAndPushFrameDef() {
|
|||||||
RunCleanFrameCommands();
|
RunCleanFrameCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_def->Finalize();
|
frame_def->Complete();
|
||||||
|
|
||||||
// Include all mesh-data loads and unloads that have accumulated up to
|
// Include all mesh-data loads and unloads that have accumulated up to
|
||||||
// this point the graphics thread will have to handle these before
|
// this point the graphics thread will have to handle these before
|
||||||
@ -1465,10 +1521,10 @@ void Graphics::DoDrawFade(FrameDef* frame_def, float amt) {
|
|||||||
void Graphics::DrawCursor(FrameDef* frame_def) {
|
void Graphics::DrawCursor(FrameDef* frame_def) {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
millisecs_t app_time_millisecs = frame_def->app_time_millisecs();
|
auto app_time = frame_def->app_time();
|
||||||
|
|
||||||
bool can_show_cursor = g_base->app_adapter->ShouldUseCursor();
|
auto can_show_cursor = g_base->app_adapter->ShouldUseCursor();
|
||||||
bool should_show_cursor =
|
auto should_show_cursor =
|
||||||
camera_->manual() || g_base->input->IsCursorVisible();
|
camera_->manual() || g_base->input->IsCursorVisible();
|
||||||
|
|
||||||
if (g_base->app_adapter->HasHardwareCursor()) {
|
if (g_base->app_adapter->HasHardwareCursor()) {
|
||||||
@ -1482,9 +1538,9 @@ void Graphics::DrawCursor(FrameDef* frame_def) {
|
|||||||
// Ship this state when it changes and also every now and then just in
|
// Ship this state when it changes and also every now and then just in
|
||||||
// case things go wonky.
|
// case things go wonky.
|
||||||
if (new_cursor_visibility != hardware_cursor_visible_
|
if (new_cursor_visibility != hardware_cursor_visible_
|
||||||
|| app_time_millisecs - last_cursor_visibility_event_time_ > 2000) {
|
|| app_time - last_cursor_visibility_event_time_ > 2.137) {
|
||||||
hardware_cursor_visible_ = new_cursor_visibility;
|
hardware_cursor_visible_ = new_cursor_visibility;
|
||||||
last_cursor_visibility_event_time_ = app_time_millisecs;
|
last_cursor_visibility_event_time_ = app_time;
|
||||||
g_base->app_adapter->PushMainThreadCall([this] {
|
g_base->app_adapter->PushMainThreadCall([this] {
|
||||||
assert(g_core && g_core->InMainThread());
|
assert(g_core && g_core->InMainThread());
|
||||||
g_base->app_adapter->SetHardwareCursorVisible(hardware_cursor_visible_);
|
g_base->app_adapter->SetHardwareCursorVisible(hardware_cursor_visible_);
|
||||||
@ -1555,11 +1611,6 @@ void Graphics::DrawBlotches(FrameDef* frame_def) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::SetSupportsHighQualityGraphics(bool s) {
|
|
||||||
supports_high_quality_graphics_ = s;
|
|
||||||
has_supports_high_quality_graphics_value_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Graphics::ClearScreenMessageTranslations() {
|
void Graphics::ClearScreenMessageTranslations() {
|
||||||
assert(g_base && g_base->InLogicThread());
|
assert(g_base && g_base->InLogicThread());
|
||||||
for (auto&& i : screen_messages_) {
|
for (auto&& i : screen_messages_) {
|
||||||
@ -1922,20 +1973,55 @@ auto Graphics::ScreenMessageEntry::GetText() -> TextGroup& {
|
|||||||
|
|
||||||
void Graphics::OnScreenSizeChange() {}
|
void Graphics::OnScreenSizeChange() {}
|
||||||
|
|
||||||
void Graphics::SetScreenSize(float virtual_width, float virtual_height,
|
void Graphics::CalcVirtualRes_(float* x, float* y) {
|
||||||
float pixel_width, float pixel_height) {
|
float x_in = *x;
|
||||||
|
float y_in = *y;
|
||||||
|
if (*x / *y > static_cast<float>(kBaseVirtualResX)
|
||||||
|
/ static_cast<float>(kBaseVirtualResY)) {
|
||||||
|
*y = kBaseVirtualResY;
|
||||||
|
*x = *y * (x_in / y_in);
|
||||||
|
} else {
|
||||||
|
*x = kBaseVirtualResX;
|
||||||
|
*y = *x * (y_in / x_in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graphics::SetScreenResolution(float x, float y) {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
res_x_virtual_ = virtual_width;
|
|
||||||
res_y_virtual_ = virtual_height;
|
// Ignore redundant sets.
|
||||||
res_x_ = pixel_width;
|
if (res_x_ == x && res_y_ == y) {
|
||||||
res_y_ = pixel_height;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll need to ship a new settings to the server with this change.
|
||||||
|
graphics_settings_dirty_ = true;
|
||||||
|
|
||||||
|
res_x_ = x;
|
||||||
|
res_y_ = y;
|
||||||
|
|
||||||
|
// Calc virtual res. In vr mode our virtual res is independent of our
|
||||||
|
// screen size (since it gets drawn to an overlay).
|
||||||
|
if (g_core->IsVRMode()) {
|
||||||
|
res_x_virtual_ = kBaseVirtualResX;
|
||||||
|
res_y_virtual_ = kBaseVirtualResY;
|
||||||
|
} else {
|
||||||
|
res_x_virtual_ = res_x_;
|
||||||
|
res_y_virtual_ = res_y_;
|
||||||
|
CalcVirtualRes_(&res_x_virtual_, &res_y_virtual_);
|
||||||
|
}
|
||||||
|
|
||||||
// Need to rebuild internal components (some are sized to the screen).
|
// Need to rebuild internal components (some are sized to the screen).
|
||||||
internal_components_inited_ = false;
|
internal_components_inited_ = false;
|
||||||
|
|
||||||
// This will inform all applicable logic thread subsystems.
|
// Inform all our logic thread buddies of this change.
|
||||||
g_base->logic->OnScreenSizeChange(virtual_width, virtual_height, pixel_width,
|
g_base->logic->OnScreenSizeChange(res_x_virtual_, res_y_virtual_, res_x_,
|
||||||
pixel_height);
|
res_y_);
|
||||||
|
|
||||||
|
// This may trigger us sending initial graphics settings to the
|
||||||
|
// graphics-server to kick off drawing.
|
||||||
|
got_screen_resolution_ = true;
|
||||||
|
UpdateInitialGraphicsSettingsSend_();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::ScreenMessageEntry::UpdateTranslation() {
|
void Graphics::ScreenMessageEntry::UpdateTranslation() {
|
||||||
@ -2030,4 +2116,61 @@ void Graphics::LanguageChanged() {
|
|||||||
ClearScreenMessageTranslations();
|
ClearScreenMessageTranslations();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Graphics::GraphicsQualityFromRequest(GraphicsQualityRequest request,
|
||||||
|
GraphicsQuality auto_val)
|
||||||
|
-> GraphicsQuality {
|
||||||
|
switch (request) {
|
||||||
|
case GraphicsQualityRequest::kLow:
|
||||||
|
return GraphicsQuality::kLow;
|
||||||
|
case GraphicsQualityRequest::kMedium:
|
||||||
|
return GraphicsQuality::kMedium;
|
||||||
|
case GraphicsQualityRequest::kHigh:
|
||||||
|
return GraphicsQuality::kHigh;
|
||||||
|
case GraphicsQualityRequest::kHigher:
|
||||||
|
return GraphicsQuality::kHigher;
|
||||||
|
case GraphicsQualityRequest::kAuto:
|
||||||
|
return auto_val;
|
||||||
|
default:
|
||||||
|
Log(LogLevel::kError, "Unhandled GraphicsQualityRequest value: "
|
||||||
|
+ std::to_string(static_cast<int>(request)));
|
||||||
|
return GraphicsQuality::kLow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto Graphics::TextureQualityFromRequest(TextureQualityRequest request,
|
||||||
|
TextureQuality auto_val)
|
||||||
|
-> TextureQuality {
|
||||||
|
switch (request) {
|
||||||
|
case TextureQualityRequest::kLow:
|
||||||
|
return TextureQuality::kLow;
|
||||||
|
case TextureQualityRequest::kMedium:
|
||||||
|
return TextureQuality::kMedium;
|
||||||
|
case TextureQualityRequest::kHigh:
|
||||||
|
return TextureQuality::kHigh;
|
||||||
|
case TextureQualityRequest::kAuto:
|
||||||
|
return auto_val;
|
||||||
|
default:
|
||||||
|
Log(LogLevel::kError, "Unhandled TextureQualityRequest value: "
|
||||||
|
+ std::to_string(static_cast<int>(request)));
|
||||||
|
return TextureQuality::kLow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graphics::set_client_context(Snapshot<GraphicsClientContext>* context) {
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
|
// Currently we only expect this to be set once. That will change
|
||||||
|
// once we support renderer swapping/etc.
|
||||||
|
assert(!g_base->logic->graphics_ready());
|
||||||
|
assert(!client_context_snapshot_.Exists());
|
||||||
|
client_context_snapshot_ = context;
|
||||||
|
|
||||||
|
// Update our static placeholder value (we don't want to calc it dynamically
|
||||||
|
// since it can be accessed from other threads).
|
||||||
|
texture_quality_placeholder_ = TextureQualityFromRequest(
|
||||||
|
settings()->texture_quality, client_context()->auto_texture_quality);
|
||||||
|
|
||||||
|
// Let the logic system know its free to proceed beyond bootstrapping.
|
||||||
|
g_base->logic->OnGraphicsReady();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -6,13 +6,15 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <set>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "ballistica/base/base.h"
|
#include "ballistica/base/base.h"
|
||||||
|
#include "ballistica/base/graphics/support/graphics_client_context.h"
|
||||||
|
#include "ballistica/base/graphics/support/graphics_settings.h"
|
||||||
#include "ballistica/shared/foundation/object.h"
|
#include "ballistica/shared/foundation/object.h"
|
||||||
#include "ballistica/shared/foundation/types.h"
|
#include "ballistica/shared/foundation/types.h"
|
||||||
|
#include "ballistica/shared/generic/snapshot.h"
|
||||||
#include "ballistica/shared/math/matrix44f.h"
|
#include "ballistica/shared/math/matrix44f.h"
|
||||||
#include "ballistica/shared/math/rect.h"
|
#include "ballistica/shared/math/rect.h"
|
||||||
#include "ballistica/shared/math/vector2f.h"
|
#include "ballistica/shared/math/vector2f.h"
|
||||||
@ -62,10 +64,10 @@ class Graphics {
|
|||||||
void OnScreenSizeChange();
|
void OnScreenSizeChange();
|
||||||
void DoApplyAppConfig();
|
void DoApplyAppConfig();
|
||||||
|
|
||||||
/// Called by the graphics server to keep us up to date in the logic
|
/// Should be called by the app-adapter to keep the engine informed
|
||||||
/// thread. Dispatches the news to all logic subsystems that care.
|
/// on the drawable area it has to work with (in pixels).
|
||||||
void SetScreenSize(float virtual_width, float virtual_height,
|
void SetScreenResolution(float x, float y);
|
||||||
float physical_width, float physical_height);
|
|
||||||
void StepDisplayTime();
|
void StepDisplayTime();
|
||||||
|
|
||||||
auto TextureQualityFromAppConfig() -> TextureQualityRequest;
|
auto TextureQualityFromAppConfig() -> TextureQualityRequest;
|
||||||
@ -97,13 +99,25 @@ class Graphics {
|
|||||||
// Called when the GraphicsServer has sent us a frame-def for deletion.
|
// Called when the GraphicsServer has sent us a frame-def for deletion.
|
||||||
void ReturnCompletedFrameDef(FrameDef* frame_def);
|
void ReturnCompletedFrameDef(FrameDef* frame_def);
|
||||||
|
|
||||||
auto screen_pixel_width() const { return res_x_; }
|
auto screen_pixel_width() const {
|
||||||
auto screen_pixel_height() const { return res_y_; }
|
assert(g_base->InLogicThread());
|
||||||
|
return res_x_;
|
||||||
|
}
|
||||||
|
auto screen_pixel_height() const {
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
|
return res_y_;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the size of the virtual screen. This value should always
|
// Return the current size of the virtual screen. This value should always
|
||||||
// be used for interface positioning, etc.
|
// be used for interface positioning, etc.
|
||||||
auto screen_virtual_width() const { return res_x_virtual_; }
|
auto screen_virtual_width() const {
|
||||||
auto screen_virtual_height() const { return res_y_virtual_; }
|
assert(g_base->InLogicThread());
|
||||||
|
return res_x_virtual_;
|
||||||
|
}
|
||||||
|
auto screen_virtual_height() const {
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
|
return res_y_virtual_;
|
||||||
|
}
|
||||||
|
|
||||||
void ClearScreenMessageTranslations();
|
void ClearScreenMessageTranslations();
|
||||||
|
|
||||||
@ -226,10 +240,10 @@ class Graphics {
|
|||||||
float upper_top);
|
float upper_top);
|
||||||
void ReleaseFadeEndCommand();
|
void ReleaseFadeEndCommand();
|
||||||
|
|
||||||
auto tv_border() const {
|
// auto tv_border() const {
|
||||||
assert(g_base->InLogicThread());
|
// assert(g_base->InLogicThread());
|
||||||
return tv_border_;
|
// return tv_border_;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Nodes that draw flat stuff into the overlay pass should query this z value
|
// Nodes that draw flat stuff into the overlay pass should query this z value
|
||||||
// for where to draw in z.
|
// for where to draw in z.
|
||||||
@ -270,17 +284,6 @@ class Graphics {
|
|||||||
return y * (res_y_virtual_ / res_y_);
|
return y * (res_y_virtual_ / res_y_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This should probably move to Renderer or AppAdapter once we
|
|
||||||
// support switching renderers.
|
|
||||||
auto supports_high_quality_graphics() const {
|
|
||||||
assert(has_supports_high_quality_graphics_value_);
|
|
||||||
return supports_high_quality_graphics_;
|
|
||||||
}
|
|
||||||
void SetSupportsHighQualityGraphics(bool s);
|
|
||||||
auto has_supports_high_quality_graphics_value() const {
|
|
||||||
return has_supports_high_quality_graphics_value_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_internal_components_inited(bool val) {
|
void set_internal_components_inited(bool val) {
|
||||||
internal_components_inited_ = val;
|
internal_components_inited_ = val;
|
||||||
}
|
}
|
||||||
@ -322,19 +325,65 @@ class Graphics {
|
|||||||
camera_gyro_explicitly_disabled_ = disabled;
|
camera_gyro_explicitly_disabled_ = disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* settings() const {
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
|
assert(settings_snapshot_.Exists());
|
||||||
|
return settings_snapshot_.Get()->Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetGraphicsSettingsSnapshot() -> Snapshot<GraphicsSettings>*;
|
||||||
|
|
||||||
|
/// Called by the graphics-server when a new client context is ready.
|
||||||
|
void set_client_context(Snapshot<GraphicsClientContext>* context);
|
||||||
|
|
||||||
|
auto has_client_context() -> bool {
|
||||||
|
return client_context_snapshot_.Exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto client_context() const -> const GraphicsClientContext* {
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
|
assert(client_context_snapshot_.Exists());
|
||||||
|
return client_context_snapshot_.Get()->Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto GraphicsQualityFromRequest(GraphicsQualityRequest request,
|
||||||
|
GraphicsQuality auto_val)
|
||||||
|
-> GraphicsQuality;
|
||||||
|
static auto TextureQualityFromRequest(TextureQualityRequest request,
|
||||||
|
TextureQuality auto_val)
|
||||||
|
-> TextureQuality;
|
||||||
|
|
||||||
|
/// For temporary use from arbitrary threads. This should be removed when
|
||||||
|
/// possible and replaced with proper safe thread-specific access patterns
|
||||||
|
/// (so we can support switching renderers/etc.).
|
||||||
|
auto placeholder_texture_quality() const {
|
||||||
|
assert(client_context_snapshot_.Exists());
|
||||||
|
return texture_quality_placeholder_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For temporary use in arbitrary threads. This should be removed when
|
||||||
|
/// possible and replaced with proper safe thread-specific access
|
||||||
|
/// patterns (so we can support switching renderers/etc.).
|
||||||
|
auto placeholder_client_context() const -> const GraphicsClientContext* {
|
||||||
|
// Using this from arbitrary threads is currently ok currently since
|
||||||
|
// context never changes once set. Will need to kill this call once that
|
||||||
|
// can happen though.
|
||||||
|
assert(client_context_snapshot_.Exists());
|
||||||
|
return client_context_snapshot_.Get()->Get();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
class ScreenMessageEntry;
|
||||||
|
|
||||||
Graphics();
|
Graphics();
|
||||||
virtual ~Graphics();
|
virtual ~Graphics();
|
||||||
virtual void DoDrawFade(FrameDef* frame_def, float amt);
|
virtual void DoDrawFade(FrameDef* frame_def, float amt);
|
||||||
|
static void CalcVirtualRes_(float* x, float* y);
|
||||||
private:
|
|
||||||
class ScreenMessageEntry;
|
|
||||||
void DrawBoxingGlovesTest(FrameDef* frame_def);
|
void DrawBoxingGlovesTest(FrameDef* frame_def);
|
||||||
void DrawBlotches(FrameDef* frame_def);
|
void DrawBlotches(FrameDef* frame_def);
|
||||||
void DrawCursor(FrameDef* frame_def);
|
void DrawCursor(FrameDef* frame_def);
|
||||||
void DrawFades(FrameDef* frame_def);
|
void DrawFades(FrameDef* frame_def);
|
||||||
void DrawDebugBuffers(RenderPass* pass);
|
void DrawDebugBuffers(RenderPass* pass);
|
||||||
|
|
||||||
void UpdateAndDrawProgressBar(FrameDef* frame_def);
|
void UpdateAndDrawProgressBar(FrameDef* frame_def);
|
||||||
void DoDrawBlotch(std::vector<uint16_t>* indices,
|
void DoDrawBlotch(std::vector<uint16_t>* indices,
|
||||||
std::vector<VertexSprite>* verts, const Vector3f& pos,
|
std::vector<VertexSprite>* verts, const Vector3f& pos,
|
||||||
@ -347,44 +396,47 @@ class Graphics {
|
|||||||
void DrawProgressBar(RenderPass* pass, float opacity);
|
void DrawProgressBar(RenderPass* pass, float opacity);
|
||||||
void UpdateProgressBarProgress(float target);
|
void UpdateProgressBarProgress(float target);
|
||||||
void UpdateGyro(microsecs_t time, microsecs_t elapsed);
|
void UpdateGyro(microsecs_t time, microsecs_t elapsed);
|
||||||
|
void UpdateInitialGraphicsSettingsSend_();
|
||||||
|
|
||||||
bool drawing_transparent_only_{};
|
int last_total_frames_rendered_{};
|
||||||
bool drawing_opaque_only_{};
|
int last_fps_{};
|
||||||
bool has_supports_high_quality_graphics_value_{};
|
int progress_bar_loads_{};
|
||||||
bool supports_high_quality_graphics_{};
|
int frame_def_count_{};
|
||||||
bool internal_components_inited_{};
|
int frame_def_count_filtered_{};
|
||||||
bool fade_out_{true};
|
int next_settings_index_{};
|
||||||
bool progress_bar_{};
|
TextureQuality texture_quality_placeholder_{};
|
||||||
bool progress_bar_fade_in_{};
|
bool drawing_transparent_only_ : 1 {};
|
||||||
bool debug_draw_{};
|
bool drawing_opaque_only_ : 1 {};
|
||||||
bool network_debug_display_enabled_{};
|
bool internal_components_inited_ : 1 {};
|
||||||
bool hardware_cursor_visible_{};
|
bool fade_out_ : 1 {true};
|
||||||
bool camera_shake_disabled_{};
|
bool progress_bar_ : 1 {};
|
||||||
bool camera_gyro_explicitly_disabled_{};
|
bool progress_bar_fade_in_ : 1 {};
|
||||||
bool gyro_enabled_{true};
|
bool debug_draw_ : 1 {};
|
||||||
bool show_fps_{};
|
bool network_debug_display_enabled_ : 1 {};
|
||||||
bool show_ping_{};
|
bool hardware_cursor_visible_ : 1 {};
|
||||||
bool show_net_info_{};
|
bool camera_shake_disabled_ : 1 {};
|
||||||
bool tv_border_{};
|
bool camera_gyro_explicitly_disabled_ : 1 {};
|
||||||
bool floor_reflection_{};
|
bool gyro_enabled_ : 1 {true};
|
||||||
bool building_frame_def_{};
|
bool show_fps_ : 1 {};
|
||||||
bool shadow_ortho_{};
|
bool show_ping_ : 1 {};
|
||||||
bool fetched_overlay_node_z_depth_{};
|
bool show_net_info_ : 1 {};
|
||||||
bool gyro_broken_{};
|
bool tv_border_ : 1 {};
|
||||||
GraphicsQuality last_frame_def_graphics_quality_{GraphicsQuality::kUnset};
|
bool floor_reflection_ : 1 {};
|
||||||
std::list<Object::Ref<PythonContextCall>> clean_frame_commands_;
|
bool building_frame_def_ : 1 {};
|
||||||
std::vector<MeshData*> mesh_data_creates_;
|
bool shadow_ortho_ : 1 {};
|
||||||
std::vector<MeshData*> mesh_data_destroys_;
|
bool fetched_overlay_node_z_depth_ : 1 {};
|
||||||
microsecs_t last_create_frame_def_time_microsecs_{};
|
bool gyro_broken_ : 1 {};
|
||||||
millisecs_t last_create_frame_def_time_millisecs_{};
|
bool set_fade_start_on_next_draw_ : 1 {};
|
||||||
|
bool graphics_settings_dirty_ : 1 {true};
|
||||||
|
bool applied_app_config_ : 1 {};
|
||||||
|
bool sent_initial_graphics_settings_ : 1 {};
|
||||||
|
bool got_screen_resolution_ : 1 {};
|
||||||
Vector3f shadow_offset_{0.0f, 0.0f, 0.0f};
|
Vector3f shadow_offset_{0.0f, 0.0f, 0.0f};
|
||||||
Vector2f shadow_scale_{1.0f, 1.0f};
|
Vector2f shadow_scale_{1.0f, 1.0f};
|
||||||
Vector3f tint_{1.0f, 1.0f, 1.0f};
|
Vector3f tint_{1.0f, 1.0f, 1.0f};
|
||||||
Vector3f ambient_color_{1.0f, 1.0f, 1.0f};
|
Vector3f ambient_color_{1.0f, 1.0f, 1.0f};
|
||||||
Vector3f vignette_outer_{0.0f, 0.0f, 0.0f};
|
Vector3f vignette_outer_{0.0f, 0.0f, 0.0f};
|
||||||
Vector3f vignette_inner_{1.0f, 1.0f, 1.0f};
|
Vector3f vignette_inner_{1.0f, 1.0f, 1.0f};
|
||||||
std::vector<FrameDef*> recycle_frame_defs_;
|
|
||||||
millisecs_t last_jitter_update_time_{};
|
|
||||||
Vector3f jitter_{0.0f, 0.0f, 0.0f};
|
Vector3f jitter_{0.0f, 0.0f, 0.0f};
|
||||||
Vector3f accel_smoothed_{0.0f, 0.0f, 0.0f};
|
Vector3f accel_smoothed_{0.0f, 0.0f, 0.0f};
|
||||||
Vector3f accel_smoothed2_{0.0f, 0.0f, 0.0f};
|
Vector3f accel_smoothed2_{0.0f, 0.0f, 0.0f};
|
||||||
@ -394,8 +446,50 @@ class Graphics {
|
|||||||
Vector3f tilt_smoothed_{0.0f, 0.0f, 0.0f};
|
Vector3f tilt_smoothed_{0.0f, 0.0f, 0.0f};
|
||||||
Vector3f tilt_vel_{0.0f, 0.0f, 0.0f};
|
Vector3f tilt_vel_{0.0f, 0.0f, 0.0f};
|
||||||
Vector3f tilt_pos_{0.0f, 0.0f, 0.0f};
|
Vector3f tilt_pos_{0.0f, 0.0f, 0.0f};
|
||||||
|
Vector3f gyro_vals_{0.0f, 0.0, 0.0f};
|
||||||
|
std::string fps_string_;
|
||||||
|
std::string ping_string_;
|
||||||
|
std::string net_info_string_;
|
||||||
|
std::map<std::string, Object::Ref<NetGraph>> debug_graphs_;
|
||||||
|
std::mutex frame_def_delete_list_mutex_;
|
||||||
|
std::list<Object::Ref<PythonContextCall>> clean_frame_commands_;
|
||||||
|
std::list<ScreenMessageEntry> screen_messages_;
|
||||||
|
std::list<ScreenMessageEntry> screen_messages_top_;
|
||||||
|
std::vector<FrameDef*> recycle_frame_defs_;
|
||||||
|
std::vector<uint16_t> blotch_indices_;
|
||||||
|
std::vector<VertexSprite> blotch_verts_;
|
||||||
|
std::vector<uint16_t> blotch_soft_indices_;
|
||||||
|
std::vector<VertexSprite> blotch_soft_verts_;
|
||||||
|
std::vector<uint16_t> blotch_soft_obj_indices_;
|
||||||
|
std::vector<VertexSprite> blotch_soft_obj_verts_;
|
||||||
|
std::vector<FrameDef*> frame_def_delete_list_;
|
||||||
|
std::vector<MeshData*> mesh_data_creates_;
|
||||||
|
std::vector<MeshData*> mesh_data_destroys_;
|
||||||
|
float fade_{};
|
||||||
|
float res_x_{256.0f};
|
||||||
|
float res_y_{256.0f};
|
||||||
|
float res_x_virtual_{256.0f};
|
||||||
|
float res_y_virtual_{256.0f};
|
||||||
float gyro_mag_test_{};
|
float gyro_mag_test_{};
|
||||||
float overlay_node_z_depth_{};
|
float overlay_node_z_depth_{};
|
||||||
|
float progress_bar_progress_{};
|
||||||
|
float screen_gamma_{1.0f};
|
||||||
|
float shadow_lower_bottom_{-4.0f};
|
||||||
|
float shadow_lower_top_{4.0f};
|
||||||
|
float shadow_upper_bottom_{30.0f};
|
||||||
|
float shadow_upper_top_{40.0f};
|
||||||
|
millisecs_t fade_start_{};
|
||||||
|
millisecs_t fade_time_{};
|
||||||
|
millisecs_t next_stat_update_time_{};
|
||||||
|
millisecs_t progress_bar_end_time_{-9999};
|
||||||
|
millisecs_t last_progress_bar_draw_time_{};
|
||||||
|
millisecs_t last_progress_bar_start_time_{};
|
||||||
|
microsecs_t last_suppress_gyro_time_{};
|
||||||
|
seconds_t last_cursor_visibility_event_time_{};
|
||||||
|
microsecs_t next_frame_number_filtered_increment_time_{};
|
||||||
|
microsecs_t last_create_frame_def_time_microsecs_{};
|
||||||
|
millisecs_t last_create_frame_def_time_millisecs_{};
|
||||||
|
millisecs_t last_jitter_update_time_{};
|
||||||
Object::Ref<ImageMesh> screen_mesh_;
|
Object::Ref<ImageMesh> screen_mesh_;
|
||||||
Object::Ref<ImageMesh> progress_bar_bottom_mesh_;
|
Object::Ref<ImageMesh> progress_bar_bottom_mesh_;
|
||||||
Object::Ref<ImageMesh> progress_bar_top_mesh_;
|
Object::Ref<ImageMesh> progress_bar_top_mesh_;
|
||||||
@ -406,49 +500,10 @@ class Graphics {
|
|||||||
Object::Ref<SpriteMesh> shadow_blotch_mesh_;
|
Object::Ref<SpriteMesh> shadow_blotch_mesh_;
|
||||||
Object::Ref<SpriteMesh> shadow_blotch_soft_mesh_;
|
Object::Ref<SpriteMesh> shadow_blotch_soft_mesh_;
|
||||||
Object::Ref<SpriteMesh> shadow_blotch_soft_obj_mesh_;
|
Object::Ref<SpriteMesh> shadow_blotch_soft_obj_mesh_;
|
||||||
std::string fps_string_;
|
|
||||||
std::string ping_string_;
|
|
||||||
std::string net_info_string_;
|
|
||||||
std::vector<uint16_t> blotch_indices_;
|
|
||||||
std::vector<VertexSprite> blotch_verts_;
|
|
||||||
std::vector<uint16_t> blotch_soft_indices_;
|
|
||||||
std::vector<VertexSprite> blotch_soft_verts_;
|
|
||||||
std::vector<uint16_t> blotch_soft_obj_indices_;
|
|
||||||
std::vector<VertexSprite> blotch_soft_obj_verts_;
|
|
||||||
std::map<std::string, Object::Ref<NetGraph>> debug_graphs_;
|
|
||||||
std::mutex frame_def_delete_list_mutex_;
|
|
||||||
std::vector<FrameDef*> frame_def_delete_list_;
|
|
||||||
Object::Ref<Camera> camera_;
|
Object::Ref<Camera> camera_;
|
||||||
millisecs_t next_stat_update_time_{};
|
|
||||||
int last_total_frames_rendered_{};
|
|
||||||
int last_fps_{};
|
|
||||||
std::list<ScreenMessageEntry> screen_messages_;
|
|
||||||
std::list<ScreenMessageEntry> screen_messages_top_;
|
|
||||||
bool set_fade_start_on_next_draw_{};
|
|
||||||
millisecs_t fade_start_{};
|
|
||||||
millisecs_t fade_time_{};
|
|
||||||
float fade_{};
|
|
||||||
Vector3f gyro_vals_{0.0f, 0.0, 0.0f};
|
|
||||||
float res_x_{100};
|
|
||||||
float res_y_{100};
|
|
||||||
float res_x_virtual_{100};
|
|
||||||
float res_y_virtual_{100};
|
|
||||||
int progress_bar_loads_{};
|
|
||||||
millisecs_t progress_bar_end_time_{-9999};
|
|
||||||
millisecs_t last_progress_bar_draw_time_{};
|
|
||||||
millisecs_t last_progress_bar_start_time_{};
|
|
||||||
float progress_bar_progress_{};
|
|
||||||
float screen_gamma_{1.0f};
|
|
||||||
float shadow_lower_bottom_{-4.0f};
|
|
||||||
float shadow_lower_top_{4.0f};
|
|
||||||
float shadow_upper_bottom_{30.0f};
|
|
||||||
float shadow_upper_top_{40.0f};
|
|
||||||
millisecs_t last_cursor_visibility_event_time_{};
|
|
||||||
microsecs_t next_frame_number_filtered_increment_time_{};
|
|
||||||
int64_t frame_def_count_{};
|
|
||||||
int64_t frame_def_count_filtered_{};
|
|
||||||
microsecs_t last_suppress_gyro_time_{};
|
|
||||||
Object::Ref<PythonContextCall> fade_end_call_;
|
Object::Ref<PythonContextCall> fade_end_call_;
|
||||||
|
Object::Ref<Snapshot<GraphicsSettings>> settings_snapshot_;
|
||||||
|
Object::Ref<Snapshot<GraphicsClientContext>> client_context_snapshot_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -32,15 +32,88 @@ void GraphicsServer::EnqueueFrameDef(FrameDef* framedef) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GraphicsServer::ApplySettings(const GraphicsSettings* settings) {
|
||||||
|
assert(g_base->InGraphicsContext());
|
||||||
|
|
||||||
|
// Only push each unique settings instance through once.
|
||||||
|
if (settings->index == settings_index_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
settings_index_ = settings->index;
|
||||||
|
|
||||||
|
assert(settings->resolution.x >= 0.0f && settings->resolution.y >= 0.0f
|
||||||
|
&& settings->resolution_virtual.x >= 0.0f
|
||||||
|
&& settings->resolution_virtual.y >= 0.0f);
|
||||||
|
|
||||||
|
// Pull a few things out ourself such as screen resolution.
|
||||||
|
tv_border_ = settings->tv_border;
|
||||||
|
if (renderer_) {
|
||||||
|
renderer_->set_pixel_scale(settings->pixel_scale);
|
||||||
|
}
|
||||||
|
// Note: not checking virtual res here; assuming it only changes when
|
||||||
|
// actual res changes.
|
||||||
|
if (res_x_ != settings->resolution.x || res_y_ != settings->resolution.y) {
|
||||||
|
res_x_ = settings->resolution.x;
|
||||||
|
res_y_ = settings->resolution.y;
|
||||||
|
res_x_virtual_ = settings->resolution_virtual.x;
|
||||||
|
res_y_virtual_ = settings->resolution_virtual.y;
|
||||||
|
if (renderer_) {
|
||||||
|
renderer_->OnScreenSizeChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kick this over to the app-adapter to apply whatever settings they
|
||||||
|
// gathered for themself.
|
||||||
|
g_base->app_adapter->ApplyGraphicsSettings(settings);
|
||||||
|
|
||||||
|
// Lastly, if we've not yet sent a context to the client, do so.
|
||||||
|
if (client_context_ == nullptr) {
|
||||||
|
set_client_context(g_base->app_adapter->GetGraphicsClientContext());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphicsServer::set_client_context(GraphicsClientContext* context) {
|
||||||
|
assert(g_base->InGraphicsContext());
|
||||||
|
|
||||||
|
// We have to do a bit of a song and dance with these context pointers.
|
||||||
|
// We wrap the context in an immutable object wrapper which is owned by
|
||||||
|
// the logic thread and that takes care of killing it when no longer
|
||||||
|
// used there, but we also need to keep it alive here in our thread.
|
||||||
|
// (which may not be the logic thread). So to accomplish that, we
|
||||||
|
// immediately ship a refcount increment over to the logic thread, and
|
||||||
|
// once we're done with an obj we ship a decrement.
|
||||||
|
|
||||||
|
auto* old_wrapper = client_context_;
|
||||||
|
auto* new_wrapper =
|
||||||
|
Object::NewDeferred<Snapshot<GraphicsClientContext>>(context);
|
||||||
|
|
||||||
|
client_context_ = new_wrapper;
|
||||||
|
|
||||||
|
g_base->logic->event_loop()->PushCall([old_wrapper, new_wrapper] {
|
||||||
|
// (This has to happen in logic thread).
|
||||||
|
auto ref = Object::CompleteDeferred(new_wrapper);
|
||||||
|
|
||||||
|
// Free the old one which the graphics server doesn't need anymore.
|
||||||
|
if (old_wrapper) {
|
||||||
|
old_wrapper->ObjectDecrementStrongRefCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep the new one alive for the graphics server.
|
||||||
|
ref->ObjectIncrementStrongRefCount();
|
||||||
|
|
||||||
|
// Plug the new one in for logic to start using.
|
||||||
|
g_base->graphics->set_client_context(new_wrapper);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
auto GraphicsServer::TryRender() -> bool {
|
auto GraphicsServer::TryRender() -> bool {
|
||||||
assert(g_base->app_adapter->InGraphicsContext());
|
assert(g_base->app_adapter->InGraphicsContext());
|
||||||
|
|
||||||
bool success{};
|
bool success{};
|
||||||
|
|
||||||
if (FrameDef* frame_def = WaitForRenderFrameDef_()) {
|
if (FrameDef* frame_def = WaitForRenderFrameDef_()) {
|
||||||
// Apply settings such as tv-mode that were passed along via the
|
// Apply any new graphics settings passed along via the frame-def.
|
||||||
// frame-def.
|
ApplySettings(frame_def->settings());
|
||||||
ApplyFrameDefSettings(frame_def);
|
|
||||||
|
|
||||||
// Note: we run mesh-updates on each frame-def that comes through even
|
// Note: we run mesh-updates on each frame-def that comes through even
|
||||||
// if we don't actually render the frame.
|
// if we don't actually render the frame.
|
||||||
@ -58,6 +131,7 @@ auto GraphicsServer::TryRender() -> bool {
|
|||||||
// Send this frame_def back to the logic thread for deletion or recycling.
|
// Send this frame_def back to the logic thread for deletion or recycling.
|
||||||
g_base->graphics->ReturnCompletedFrameDef(frame_def);
|
g_base->graphics->ReturnCompletedFrameDef(frame_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,11 +187,6 @@ auto GraphicsServer::WaitForRenderFrameDef_() -> FrameDef* {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsServer::ApplyFrameDefSettings(FrameDef* frame_def) {
|
|
||||||
assert(g_base->app_adapter->InGraphicsContext());
|
|
||||||
tv_border_ = frame_def->tv_border();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Runs any mesh updates contained in the frame-def.
|
// Runs any mesh updates contained in the frame-def.
|
||||||
void GraphicsServer::RunFrameDefMeshUpdates(FrameDef* frame_def) {
|
void GraphicsServer::RunFrameDefMeshUpdates(FrameDef* frame_def) {
|
||||||
assert(g_base->app_adapter->InGraphicsContext());
|
assert(g_base->app_adapter->InGraphicsContext());
|
||||||
@ -242,24 +311,6 @@ void GraphicsServer::ReloadLostRenderer() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsServer::SetNullGraphics() {
|
|
||||||
// We don't actually make or update a renderer in headless, but we
|
|
||||||
// still need to set our list of supported textures types/etc. to avoid
|
|
||||||
// complaints.
|
|
||||||
std::list<TextureCompressionType> c_types;
|
|
||||||
SetTextureCompressionTypes(c_types);
|
|
||||||
graphics_quality_requested_ = GraphicsQualityRequest::kLow;
|
|
||||||
graphics_quality_ = GraphicsQuality::kLow;
|
|
||||||
graphics_quality_set_ = true;
|
|
||||||
texture_quality_requested_ = TextureQualityRequest::kLow;
|
|
||||||
texture_quality_ = TextureQuality::kLow;
|
|
||||||
texture_quality_set_ = true;
|
|
||||||
|
|
||||||
// Let the logic thread know screen creation is done (or lack thereof).
|
|
||||||
g_base->logic->event_loop()->PushCall(
|
|
||||||
[] { g_base->logic->OnGraphicsReady(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphicsServer::set_renderer(Renderer* renderer) {
|
void GraphicsServer::set_renderer(Renderer* renderer) {
|
||||||
assert(g_base->app_adapter->InGraphicsContext());
|
assert(g_base->app_adapter->InGraphicsContext());
|
||||||
assert(!renderer_loaded_);
|
assert(!renderer_loaded_);
|
||||||
@ -279,59 +330,43 @@ void GraphicsServer::LoadRenderer() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (graphics_quality_requested_) {
|
graphics_quality_ = Graphics::GraphicsQualityFromRequest(
|
||||||
case GraphicsQualityRequest::kLow:
|
graphics_quality_requested_, renderer_->GetAutoGraphicsQuality());
|
||||||
graphics_quality_ = GraphicsQuality::kLow;
|
|
||||||
break;
|
texture_quality_ = Graphics::TextureQualityFromRequest(
|
||||||
case GraphicsQualityRequest::kMedium:
|
texture_quality_requested_, renderer_->GetAutoTextureQuality());
|
||||||
graphics_quality_ = GraphicsQuality::kMedium;
|
|
||||||
break;
|
|
||||||
case GraphicsQualityRequest::kHigh:
|
|
||||||
graphics_quality_ = GraphicsQuality::kHigh;
|
|
||||||
break;
|
|
||||||
case GraphicsQualityRequest::kHigher:
|
|
||||||
graphics_quality_ = GraphicsQuality::kHigher;
|
|
||||||
break;
|
|
||||||
case GraphicsQualityRequest::kAuto:
|
|
||||||
graphics_quality_ = renderer_->GetAutoGraphicsQuality();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Log(LogLevel::kError,
|
|
||||||
"Unhandled GraphicsQualityRequest value: "
|
|
||||||
+ std::to_string(static_cast<int>(graphics_quality_requested_)));
|
|
||||||
graphics_quality_ = GraphicsQuality::kLow;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we don't support high quality graphics, make sure we're no higher than
|
// If we don't support high quality graphics, make sure we're no higher than
|
||||||
// medium.
|
// medium.
|
||||||
BA_PRECONDITION(g_base->graphics->has_supports_high_quality_graphics_value());
|
// BA_PRECONDITION(g_base->graphics->has_supports_high_quality_graphics_value());
|
||||||
if (!g_base->graphics->supports_high_quality_graphics()
|
// if (!g_base->graphics->supports_high_quality_graphics()
|
||||||
&& graphics_quality_ > GraphicsQuality::kMedium) {
|
// && graphics_quality_ > GraphicsQuality::kMedium) {
|
||||||
graphics_quality_ = GraphicsQuality::kMedium;
|
// graphics_quality_ = GraphicsQuality::kMedium;
|
||||||
}
|
// }
|
||||||
graphics_quality_set_ = true;
|
// graphics_quality_set_ = true;
|
||||||
|
|
||||||
// Update texture quality based on request.
|
// Update texture quality based on request.
|
||||||
switch (texture_quality_requested_) {
|
// switch (texture_quality_requested_) {
|
||||||
case TextureQualityRequest::kLow:
|
// case TextureQualityRequest::kLow:
|
||||||
texture_quality_ = TextureQuality::kLow;
|
// texture_quality_ = TextureQuality::kLow;
|
||||||
break;
|
// break;
|
||||||
case TextureQualityRequest::kMedium:
|
// case TextureQualityRequest::kMedium:
|
||||||
texture_quality_ = TextureQuality::kMedium;
|
// texture_quality_ = TextureQuality::kMedium;
|
||||||
break;
|
// break;
|
||||||
case TextureQualityRequest::kHigh:
|
// case TextureQualityRequest::kHigh:
|
||||||
texture_quality_ = TextureQuality::kHigh;
|
// texture_quality_ = TextureQuality::kHigh;
|
||||||
break;
|
// break;
|
||||||
case TextureQualityRequest::kAuto:
|
// case TextureQualityRequest::kAuto:
|
||||||
texture_quality_ = renderer_->GetAutoTextureQuality();
|
// texture_quality_ = renderer_->GetAutoTextureQuality();
|
||||||
break;
|
// break;
|
||||||
default:
|
// default:
|
||||||
Log(LogLevel::kError,
|
// Log(LogLevel::kError,
|
||||||
"Unhandled TextureQualityRequest value: "
|
// "Unhandled TextureQualityRequest value: "
|
||||||
+ std::to_string(static_cast<int>(texture_quality_requested_)));
|
// +
|
||||||
texture_quality_ = TextureQuality::kLow;
|
// std::to_string(static_cast<int>(texture_quality_requested_)));
|
||||||
}
|
// texture_quality_ = TextureQuality::kLow;
|
||||||
texture_quality_set_ = true;
|
// }
|
||||||
|
// texture_quality_set_ = true;
|
||||||
|
|
||||||
// Ok we've got our qualities figured out; now load/update the renderer.
|
// Ok we've got our qualities figured out; now load/update the renderer.
|
||||||
renderer_->Load();
|
renderer_->Load();
|
||||||
@ -389,56 +424,56 @@ void GraphicsServer::UnloadRenderer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Given physical res, calculate virtual res.
|
// Given physical res, calculate virtual res.
|
||||||
void GraphicsServer::CalcVirtualRes_(float* x, float* y) {
|
// void GraphicsServer::CalcVirtualRes_(float* x, float* y) {
|
||||||
float x_in = *x;
|
// float x_in = *x;
|
||||||
float y_in = *y;
|
// float y_in = *y;
|
||||||
if (*x / *y > static_cast<float>(kBaseVirtualResX)
|
// if (*x / *y > static_cast<float>(kBaseVirtualResX)
|
||||||
/ static_cast<float>(kBaseVirtualResY)) {
|
// / static_cast<float>(kBaseVirtualResY)) {
|
||||||
*y = kBaseVirtualResY;
|
// *y = kBaseVirtualResY;
|
||||||
*x = *y * (x_in / y_in);
|
// *x = *y * (x_in / y_in);
|
||||||
} else {
|
// } else {
|
||||||
*x = kBaseVirtualResX;
|
// *x = kBaseVirtualResX;
|
||||||
*y = *x * (y_in / x_in);
|
// *y = *x * (y_in / x_in);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
void GraphicsServer::UpdateVirtualScreenRes_() {
|
// void GraphicsServer::UpdateVirtualScreenRes_() {
|
||||||
assert(g_base->app_adapter->InGraphicsContext());
|
// assert(g_base->app_adapter->InGraphicsContext());
|
||||||
|
|
||||||
// In vr mode our virtual res is independent of our screen size.
|
// // In vr mode our virtual res is independent of our screen size.
|
||||||
// (since it gets drawn to an overlay)
|
// // (since it gets drawn to an overlay)
|
||||||
if (g_core->IsVRMode()) {
|
// if (g_core->IsVRMode()) {
|
||||||
res_x_virtual_ = kBaseVirtualResX;
|
// res_x_virtual_ = kBaseVirtualResX;
|
||||||
res_y_virtual_ = kBaseVirtualResY;
|
// res_y_virtual_ = kBaseVirtualResY;
|
||||||
} else {
|
// } else {
|
||||||
res_x_virtual_ = res_x_;
|
// res_x_virtual_ = res_x_;
|
||||||
res_y_virtual_ = res_y_;
|
// res_y_virtual_ = res_y_;
|
||||||
CalcVirtualRes_(&res_x_virtual_, &res_y_virtual_);
|
// CalcVirtualRes_(&res_x_virtual_, &res_y_virtual_);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
void GraphicsServer::SetScreenResolution(float h, float v) {
|
// void GraphicsServer::SetScreenResolution(float h, float v) {
|
||||||
assert(g_base->app_adapter->InGraphicsContext());
|
// assert(g_base->app_adapter->InGraphicsContext());
|
||||||
|
|
||||||
// Ignore redundant sets.
|
// // Ignore redundant sets.
|
||||||
if (res_x_ == h && res_y_ == v) {
|
// if (res_x_ == h && res_y_ == v) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
res_x_ = h;
|
// res_x_ = h;
|
||||||
res_y_ = v;
|
// res_y_ = v;
|
||||||
UpdateVirtualScreenRes_();
|
// // UpdateVirtualScreenRes_();
|
||||||
|
|
||||||
// Inform renderer of the change.
|
// // Inform renderer of the change.
|
||||||
if (renderer_) {
|
// if (renderer_) {
|
||||||
renderer_->OnScreenSizeChange();
|
// renderer_->OnScreenSizeChange();
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Inform all logic thread bits of this change.
|
// // Inform all logic thread bits of this change.
|
||||||
g_base->logic->event_loop()->PushCall(
|
// g_base->logic->event_loop()->PushCall(
|
||||||
[vx = res_x_virtual_, vy = res_y_virtual_, x = res_x_, y = res_y_] {
|
// [vx = res_x_virtual_, vy = res_y_virtual_, x = res_x_, y = res_y_] {
|
||||||
g_base->graphics->SetScreenSize(vx, vy, x, y);
|
// g_base->graphics->SetScreenSize(vx, vy, x, y);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
// FIXME: Shouldn't have android-specific code in here.
|
// FIXME: Shouldn't have android-specific code in here.
|
||||||
void GraphicsServer::HandlePushAndroidRes(const std::string& android_res) {
|
void GraphicsServer::HandlePushAndroidRes(const std::string& android_res) {
|
||||||
@ -579,15 +614,15 @@ void GraphicsServer::PushReloadMediaCall() {
|
|||||||
g_base->app_adapter->PushGraphicsContextCall([this] { ReloadMedia_(); });
|
g_base->app_adapter->PushGraphicsContextCall([this] { ReloadMedia_(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsServer::PushSetScreenPixelScaleCall(float pixel_scale) {
|
// void GraphicsServer::PushSetScreenPixelScaleCall(float pixel_scale) {
|
||||||
g_base->app_adapter->PushGraphicsContextCall([this, pixel_scale] {
|
// g_base->app_adapter->PushGraphicsContextCall([this, pixel_scale] {
|
||||||
assert(g_base->app_adapter->InGraphicsContext());
|
// assert(g_base->app_adapter->InGraphicsContext());
|
||||||
if (!renderer_) {
|
// if (!renderer_) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
renderer_->set_pixel_scale(pixel_scale);
|
// renderer_->set_pixel_scale(pixel_scale);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
void GraphicsServer::PushComponentUnloadCall(
|
void GraphicsServer::PushComponentUnloadCall(
|
||||||
const std::vector<Object::Ref<Asset>*>& components) {
|
const std::vector<Object::Ref<Asset>*>& components) {
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "ballistica/base/base.h"
|
#include "ballistica/base/base.h"
|
||||||
#include "ballistica/shared/foundation/object.h"
|
#include "ballistica/shared/foundation/object.h"
|
||||||
|
#include "ballistica/shared/generic/snapshot.h"
|
||||||
#include "ballistica/shared/math/matrix44f.h"
|
#include "ballistica/shared/math/matrix44f.h"
|
||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
@ -51,16 +52,8 @@ class GraphicsServer {
|
|||||||
return renderer_loaded_;
|
return renderer_loaded_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The AppAdapter should call this to inform the engine of screen size
|
void ApplySettings(const GraphicsSettings* settings);
|
||||||
/// changes. Changes will be applied to the server and then sent to the
|
|
||||||
/// logic thread to apply to various app systems (ui, etc.).
|
|
||||||
void SetScreenResolution(float h, float v);
|
|
||||||
|
|
||||||
/// Used by headless builds to init the graphics-server into a
|
|
||||||
/// non-functional state.
|
|
||||||
void SetNullGraphics();
|
|
||||||
|
|
||||||
void PushSetScreenPixelScaleCall(float pixel_scale);
|
|
||||||
void PushReloadMediaCall();
|
void PushReloadMediaCall();
|
||||||
void PushRemoveRenderHoldCall();
|
void PushRemoveRenderHoldCall();
|
||||||
void PushComponentUnloadCall(
|
void PushComponentUnloadCall(
|
||||||
@ -71,8 +64,6 @@ class GraphicsServer {
|
|||||||
/// rendering.
|
/// rendering.
|
||||||
void EnqueueFrameDef(FrameDef* framedef);
|
void EnqueueFrameDef(FrameDef* framedef);
|
||||||
|
|
||||||
void ApplyFrameDefSettings(FrameDef* frame_def);
|
|
||||||
|
|
||||||
void RunFrameDefMeshUpdates(FrameDef* frame_def);
|
void RunFrameDefMeshUpdates(FrameDef* frame_def);
|
||||||
|
|
||||||
// Renders shadow passes and other common parts of a frame_def.
|
// Renders shadow passes and other common parts of a frame_def.
|
||||||
@ -108,9 +99,7 @@ class GraphicsServer {
|
|||||||
projection_matrix_state_++;
|
projection_matrix_state_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto projection_matrix_state() -> uint32_t {
|
auto projection_matrix_state() { return projection_matrix_state_; }
|
||||||
return projection_matrix_state_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetLightShadowProjectionMatrix(const Matrix44f& p) {
|
void SetLightShadowProjectionMatrix(const Matrix44f& p) {
|
||||||
// This will generally get repeatedly set to the same value
|
// This will generally get repeatedly set to the same value
|
||||||
@ -121,61 +110,57 @@ class GraphicsServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto light_shadow_projection_matrix_state() const -> uint32_t {
|
auto light_shadow_projection_matrix_state() const {
|
||||||
return light_shadow_projection_matrix_state_;
|
return light_shadow_projection_matrix_state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto light_shadow_projection_matrix() const -> const Matrix44f& {
|
const auto& light_shadow_projection_matrix() const {
|
||||||
return light_shadow_projection_matrix_;
|
return light_shadow_projection_matrix_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the modelview * projection matrix.
|
// Return the modelview * projection matrix.
|
||||||
auto GetModelViewProjectionMatrix() -> const Matrix44f& {
|
const auto& GetModelViewProjectionMatrix() {
|
||||||
UpdateModelViewProjectionMatrix_();
|
UpdateModelViewProjectionMatrix_();
|
||||||
return model_view_projection_matrix_;
|
return model_view_projection_matrix_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GetModelViewProjectionMatrixState() -> uint32_t {
|
auto GetModelViewProjectionMatrixState() {
|
||||||
UpdateModelViewProjectionMatrix_();
|
UpdateModelViewProjectionMatrix_();
|
||||||
return model_view_projection_matrix_state_;
|
return model_view_projection_matrix_state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GetModelWorldMatrix() -> const Matrix44f& {
|
const auto& GetModelWorldMatrix() {
|
||||||
UpdateModelWorldMatrix_();
|
UpdateModelWorldMatrix_();
|
||||||
return model_world_matrix_;
|
return model_world_matrix_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GetModelWorldMatrixState() -> uint32_t {
|
auto GetModelWorldMatrixState() {
|
||||||
UpdateModelWorldMatrix_();
|
UpdateModelWorldMatrix_();
|
||||||
return model_world_matrix_state_;
|
return model_world_matrix_state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cam_pos() -> const Vector3f& { return cam_pos_; }
|
const auto& cam_pos() { return cam_pos_; }
|
||||||
|
|
||||||
auto cam_pos_state() -> uint32_t { return cam_pos_state_; }
|
auto cam_pos_state() { return cam_pos_state_; }
|
||||||
|
|
||||||
auto GetCamOrientMatrix() -> const Matrix44f& {
|
const auto& GetCamOrientMatrix() {
|
||||||
UpdateCamOrientMatrix_();
|
UpdateCamOrientMatrix_();
|
||||||
return cam_orient_matrix_;
|
return cam_orient_matrix_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GetCamOrientMatrixState() -> uint32_t {
|
auto GetCamOrientMatrixState() {
|
||||||
UpdateCamOrientMatrix_();
|
UpdateCamOrientMatrix_();
|
||||||
return cam_orient_matrix_state_;
|
return cam_orient_matrix_state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto model_view_matrix() const -> const Matrix44f& {
|
const auto& model_view_matrix() const { return model_view_matrix_; }
|
||||||
return model_view_matrix_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetModelViewMatrix(const Matrix44f& m) {
|
void SetModelViewMatrix(const Matrix44f& m) {
|
||||||
model_view_matrix_ = m;
|
model_view_matrix_ = m;
|
||||||
model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true;
|
model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto projection_matrix() const -> const Matrix44f& {
|
const auto& projection_matrix() const { return projection_matrix_; }
|
||||||
return projection_matrix_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PushTransform() {
|
void PushTransform() {
|
||||||
model_view_stack_.push_back(model_view_matrix_);
|
model_view_stack_.push_back(model_view_matrix_);
|
||||||
@ -209,32 +194,34 @@ class GraphicsServer {
|
|||||||
model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true;
|
model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto quality() const -> GraphicsQuality {
|
auto quality() const {
|
||||||
assert(graphics_quality_set_);
|
assert(InGraphicsContext_());
|
||||||
|
assert(graphics_quality_ != GraphicsQuality::kUnset);
|
||||||
return graphics_quality_;
|
return graphics_quality_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto texture_quality() const -> TextureQuality {
|
auto texture_quality() const {
|
||||||
assert(texture_quality_set_);
|
assert(InGraphicsContext_());
|
||||||
|
assert(texture_quality_ != TextureQuality::kUnset);
|
||||||
return texture_quality_;
|
return texture_quality_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto screen_pixel_width() const -> float {
|
auto screen_pixel_width() const {
|
||||||
assert(InGraphicsContext_());
|
assert(InGraphicsContext_());
|
||||||
return res_x_;
|
return res_x_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto screen_pixel_height() const -> float {
|
auto screen_pixel_height() const {
|
||||||
assert(InGraphicsContext_());
|
assert(InGraphicsContext_());
|
||||||
return res_y_;
|
return res_y_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto screen_virtual_width() const -> float {
|
auto screen_virtual_width() const {
|
||||||
assert(InGraphicsContext_());
|
assert(InGraphicsContext_());
|
||||||
return res_x_virtual_;
|
return res_x_virtual_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto screen_virtual_height() const -> float {
|
auto screen_virtual_height() const {
|
||||||
assert(InGraphicsContext_());
|
assert(InGraphicsContext_());
|
||||||
return res_y_virtual_;
|
return res_y_virtual_;
|
||||||
}
|
}
|
||||||
@ -244,45 +231,69 @@ class GraphicsServer {
|
|||||||
return tv_border_;
|
return tv_border_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto graphics_quality_set() const { return graphics_quality_set_; }
|
// auto graphics_quality_set() const {
|
||||||
|
// return graphics_quality_ != GraphicsQuality::kUnset;
|
||||||
|
// }
|
||||||
|
|
||||||
auto texture_quality_set() const { return texture_quality_set_; }
|
// auto texture_quality_set() const {
|
||||||
|
// return texture_quality_ != TextureQuality::kUnset;
|
||||||
|
// }
|
||||||
|
|
||||||
auto SupportsTextureCompressionType(TextureCompressionType t) const -> bool {
|
auto SupportsTextureCompressionType(TextureCompressionType t) const -> bool {
|
||||||
|
assert(InGraphicsContext_());
|
||||||
assert(texture_compression_types_set_);
|
assert(texture_compression_types_set_);
|
||||||
return ((texture_compression_types_ & (0x01u << static_cast<uint32_t>(t)))
|
return ((texture_compression_types_ & (0x01u << static_cast<uint32_t>(t)))
|
||||||
!= 0u);
|
!= 0u);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTextureCompressionTypes(
|
void SetTextureCompressionTypes(
|
||||||
const std::list<TextureCompressionType>& types);
|
const std::list<TextureCompressionType>& types);
|
||||||
|
|
||||||
auto texture_compression_types_are_set() const {
|
// auto texture_compression_types_are_set() const {
|
||||||
return texture_compression_types_set_;
|
// return texture_compression_types_set_;
|
||||||
}
|
// }
|
||||||
|
|
||||||
void set_renderer_context_lost(bool lost) { renderer_context_lost_ = lost; }
|
void set_renderer_context_lost(bool lost) { renderer_context_lost_ = lost; }
|
||||||
|
|
||||||
auto renderer_context_lost() const { return renderer_context_lost_; }
|
auto renderer_context_lost() const { return renderer_context_lost_; }
|
||||||
|
|
||||||
auto graphics_quality_requested() const {
|
auto graphics_quality_requested() const {
|
||||||
|
assert(InGraphicsContext_());
|
||||||
return graphics_quality_requested_;
|
return graphics_quality_requested_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_graphics_quality_requested(GraphicsQualityRequest val) {
|
void set_graphics_quality_requested(GraphicsQualityRequest val) {
|
||||||
|
assert(InGraphicsContext_());
|
||||||
graphics_quality_requested_ = val;
|
graphics_quality_requested_ = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_texture_quality_requested(TextureQualityRequest val) {
|
void set_texture_quality_requested(TextureQualityRequest val) {
|
||||||
|
assert(InGraphicsContext_());
|
||||||
texture_quality_requested_ = val;
|
texture_quality_requested_ = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto graphics_quality() const { return graphics_quality_; }
|
auto graphics_quality() const {
|
||||||
|
assert(InGraphicsContext_());
|
||||||
|
return graphics_quality_;
|
||||||
|
}
|
||||||
|
|
||||||
auto texture_quality_requested() const { return texture_quality_requested_; }
|
auto texture_quality_requested() const {
|
||||||
|
assert(InGraphicsContext_());
|
||||||
|
return texture_quality_requested_;
|
||||||
|
}
|
||||||
|
|
||||||
void HandlePushAndroidRes(const std::string& android_res);
|
void HandlePushAndroidRes(const std::string& android_res);
|
||||||
|
|
||||||
|
auto texture_compression_types() const {
|
||||||
|
assert(texture_compression_types_set_);
|
||||||
|
return texture_compression_types_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// Pass a freshly allocated GraphicsContext instance, which the graphics
|
||||||
|
/// system will take ownership of.
|
||||||
|
void set_client_context(GraphicsClientContext* context);
|
||||||
|
|
||||||
// So we don't have to include app_adapter.h here for asserts.
|
// So we don't have to include app_adapter.h here for asserts.
|
||||||
auto InGraphicsContext_() const -> bool;
|
auto InGraphicsContext_() const -> bool;
|
||||||
|
|
||||||
@ -293,8 +304,8 @@ class GraphicsServer {
|
|||||||
auto WaitForRenderFrameDef_() -> FrameDef*;
|
auto WaitForRenderFrameDef_() -> FrameDef*;
|
||||||
|
|
||||||
// Update virtual screen dimensions based on the current physical ones.
|
// Update virtual screen dimensions based on the current physical ones.
|
||||||
static void CalcVirtualRes_(float* x, float* y);
|
// static void CalcVirtualRes_(float* x, float* y);
|
||||||
void UpdateVirtualScreenRes_();
|
// void UpdateVirtualScreenRes_();
|
||||||
void UpdateCamOrientMatrix_();
|
void UpdateCamOrientMatrix_();
|
||||||
void ReloadMedia_();
|
void ReloadMedia_();
|
||||||
void UpdateModelViewProjectionMatrix_() {
|
void UpdateModelViewProjectionMatrix_() {
|
||||||
@ -314,23 +325,17 @@ class GraphicsServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool renderer_loaded_ : 1 {};
|
bool renderer_loaded_ : 1 {};
|
||||||
bool v_sync_ : 1 {};
|
|
||||||
bool auto_vsync_ : 1 {};
|
|
||||||
bool model_view_projection_matrix_dirty_ : 1 {true};
|
bool model_view_projection_matrix_dirty_ : 1 {true};
|
||||||
bool model_world_matrix_dirty_ : 1 {true};
|
bool model_world_matrix_dirty_ : 1 {true};
|
||||||
bool graphics_quality_set_ : 1 {};
|
|
||||||
bool texture_quality_set_ : 1 {};
|
|
||||||
bool tv_border_ : 1 {};
|
bool tv_border_ : 1 {};
|
||||||
bool renderer_context_lost_ : 1 {};
|
bool renderer_context_lost_ : 1 {};
|
||||||
bool texture_compression_types_set_ : 1 {};
|
bool texture_compression_types_set_ : 1 {};
|
||||||
bool cam_orient_matrix_dirty_ : 1 {true};
|
bool cam_orient_matrix_dirty_ : 1 {true};
|
||||||
TextureQualityRequest texture_quality_requested_{
|
Snapshot<GraphicsClientContext>* client_context_{};
|
||||||
TextureQualityRequest::kUnset};
|
TextureQualityRequest texture_quality_requested_{};
|
||||||
TextureQuality texture_quality_{TextureQuality::kLow};
|
TextureQuality texture_quality_{};
|
||||||
GraphicsQualityRequest graphics_quality_requested_{
|
GraphicsQualityRequest graphics_quality_requested_{};
|
||||||
GraphicsQualityRequest::kUnset};
|
GraphicsQuality graphics_quality_{};
|
||||||
GraphicsQuality graphics_quality_{GraphicsQuality::kUnset};
|
|
||||||
int render_hold_{};
|
|
||||||
float res_x_{};
|
float res_x_{};
|
||||||
float res_y_{};
|
float res_y_{};
|
||||||
float res_x_virtual_{};
|
float res_x_virtual_{};
|
||||||
@ -340,20 +345,21 @@ class GraphicsServer {
|
|||||||
Matrix44f projection_matrix_{kMatrix44fIdentity};
|
Matrix44f projection_matrix_{kMatrix44fIdentity};
|
||||||
Matrix44f model_view_projection_matrix_{kMatrix44fIdentity};
|
Matrix44f model_view_projection_matrix_{kMatrix44fIdentity};
|
||||||
Matrix44f model_world_matrix_{kMatrix44fIdentity};
|
Matrix44f model_world_matrix_{kMatrix44fIdentity};
|
||||||
std::vector<Matrix44f> model_view_stack_;
|
|
||||||
uint32_t texture_compression_types_{};
|
uint32_t texture_compression_types_{};
|
||||||
uint32_t projection_matrix_state_{1};
|
int render_hold_{};
|
||||||
uint32_t model_view_projection_matrix_state_{1};
|
int projection_matrix_state_{};
|
||||||
uint32_t model_world_matrix_state_{1};
|
int model_view_projection_matrix_state_{};
|
||||||
uint32_t light_shadow_projection_matrix_state_{1};
|
int model_world_matrix_state_{};
|
||||||
uint32_t cam_pos_state_{1};
|
int light_shadow_projection_matrix_state_{};
|
||||||
uint32_t cam_orient_matrix_state_{1};
|
int cam_pos_state_{};
|
||||||
|
int cam_orient_matrix_state_{};
|
||||||
|
int settings_index_{-1};
|
||||||
Vector3f cam_pos_{0.0f, 0.0f, 0.0f};
|
Vector3f cam_pos_{0.0f, 0.0f, 0.0f};
|
||||||
Vector3f cam_target_{0.0f, 0.0f, 0.0f};
|
Vector3f cam_target_{0.0f, 0.0f, 0.0f};
|
||||||
Matrix44f light_shadow_projection_matrix_{kMatrix44fIdentity};
|
Matrix44f light_shadow_projection_matrix_{kMatrix44fIdentity};
|
||||||
Matrix44f cam_orient_matrix_ = kMatrix44fIdentity;
|
Matrix44f cam_orient_matrix_ = kMatrix44fIdentity;
|
||||||
|
std::vector<Matrix44f> model_view_stack_;
|
||||||
std::list<MeshData*> mesh_datas_;
|
std::list<MeshData*> mesh_datas_;
|
||||||
Timer* render_timer_{};
|
|
||||||
Renderer* renderer_{};
|
Renderer* renderer_{};
|
||||||
FrameDef* frame_def_{};
|
FrameDef* frame_def_{};
|
||||||
std::mutex frame_def_mutex_{};
|
std::mutex frame_def_mutex_{};
|
||||||
|
|||||||
@ -487,7 +487,7 @@ void RenderPass::SetFrustum(float near_val, float far_val) {
|
|||||||
g_base->graphics_server->SetProjectionMatrix(projection_matrix_);
|
g_base->graphics_server->SetProjectionMatrix(projection_matrix_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderPass::Finalize() {
|
void RenderPass::Complete() {
|
||||||
if (UsesWorldLists()) {
|
if (UsesWorldLists()) {
|
||||||
for (auto& command : commands_) {
|
for (auto& command : commands_) {
|
||||||
command->Finalize();
|
command->Finalize();
|
||||||
|
|||||||
@ -112,7 +112,7 @@ class RenderPass {
|
|||||||
return model_view_projection_matrix_;
|
return model_view_projection_matrix_;
|
||||||
}
|
}
|
||||||
auto HasDrawCommands() const -> bool;
|
auto HasDrawCommands() const -> bool;
|
||||||
void Finalize();
|
void Complete();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
// Whether this pass draws stuff from the per-shader command lists
|
// Whether this pass draws stuff from the per-shader command lists
|
||||||
|
|||||||
@ -35,10 +35,12 @@ void Renderer::PreprocessFrameDef(FrameDef* frame_def) {
|
|||||||
|
|
||||||
// If this frame_def was made in a different quality mode than we're
|
// If this frame_def was made in a different quality mode than we're
|
||||||
// currently in, don't attempt to render it.
|
// currently in, don't attempt to render it.
|
||||||
if (frame_def->quality() != g_base->graphics_server->quality()) {
|
// UPDATE - scratch that; we now set our quality FROM the frame def.
|
||||||
frame_def->set_rendering(false);
|
// if (frame_def->quality() != g_base->graphics_server->quality()) {
|
||||||
return;
|
// frame_def->set_rendering(false);
|
||||||
}
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
frame_def->set_rendering(true);
|
frame_def->set_rendering(true);
|
||||||
|
|
||||||
// Some VR environments muck with render states before/after
|
// Some VR environments muck with render states before/after
|
||||||
|
|||||||
@ -82,7 +82,6 @@ class Renderer {
|
|||||||
auto light_pitch() const -> float { return light_pitch_; }
|
auto light_pitch() const -> float { return light_pitch_; }
|
||||||
auto light_heading() const -> float { return light_heading_; }
|
auto light_heading() const -> float { return light_heading_; }
|
||||||
void set_pixel_scale(float s) { pixel_scale_requested_ = s; }
|
void set_pixel_scale(float s) { pixel_scale_requested_ = s; }
|
||||||
// void set_screen_gamma(float val) { screen_gamma_requested_ = val; }
|
|
||||||
void set_debug_draw_mode(bool debugModeIn) { debug_draw_mode_ = debugModeIn; }
|
void set_debug_draw_mode(bool debugModeIn) { debug_draw_mode_ = debugModeIn; }
|
||||||
auto debug_draw_mode() -> bool { return debug_draw_mode_; }
|
auto debug_draw_mode() -> bool { return debug_draw_mode_; }
|
||||||
|
|
||||||
@ -269,7 +268,6 @@ class Renderer {
|
|||||||
Vector3f vignette_outer_{0.0f, 0.0f, 0.0f};
|
Vector3f vignette_outer_{0.0f, 0.0f, 0.0f};
|
||||||
Vector3f vignette_inner_{1.0f, 1.0f, 1.0f};
|
Vector3f vignette_inner_{1.0f, 1.0f, 1.0f};
|
||||||
int shadow_res_{-1};
|
int shadow_res_{-1};
|
||||||
// float screen_gamma_requested_{1.0f};
|
|
||||||
float screen_gamma_{1.0f};
|
float screen_gamma_{1.0f};
|
||||||
float pixel_scale_requested_{1.0f};
|
float pixel_scale_requested_{1.0f};
|
||||||
float pixel_scale_{1.0f};
|
float pixel_scale_{1.0f};
|
||||||
|
|||||||
@ -1013,7 +1013,7 @@ void Camera::ApplyToFrameDef(FrameDef* frame_def) {
|
|||||||
up_, 4, 1000.0f,
|
up_, 4, 1000.0f,
|
||||||
-1.0f, // Auto x fov.
|
-1.0f, // Auto x fov.
|
||||||
final_fov_y
|
final_fov_y
|
||||||
* (g_base->graphics->tv_border() ? (1.0f + kTVBorder) : 1.0f),
|
* (frame_def->settings()->tv_border ? (1.0f + kTVBorder) : 1.0f),
|
||||||
false, 0, 0, 0, 0, // Not using tangent fovs.
|
false, 0, 0, 0, 0, // Not using tangent fovs.
|
||||||
area_of_interest_points_);
|
area_of_interest_points_);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,6 +49,13 @@ auto FrameDef::GetOverlayFlatPass() -> RenderPass* {
|
|||||||
|
|
||||||
void FrameDef::Reset() {
|
void FrameDef::Reset() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
|
// Update & grab the current settings.
|
||||||
|
settings_snapshot_ = g_base->graphics->GetGraphicsSettingsSnapshot();
|
||||||
|
|
||||||
|
auto* settings = settings_snapshot_->Get();
|
||||||
|
auto* client_context = g_base->graphics->client_context();
|
||||||
|
|
||||||
app_time_microsecs_ = 0;
|
app_time_microsecs_ = 0;
|
||||||
display_time_microsecs_ = 0;
|
display_time_microsecs_ = 0;
|
||||||
display_time_elapsed_microsecs_ = 0;
|
display_time_elapsed_microsecs_ = 0;
|
||||||
@ -68,11 +75,17 @@ void FrameDef::Reset() {
|
|||||||
mesh_index_sizes_.clear();
|
mesh_index_sizes_.clear();
|
||||||
mesh_buffers_.clear();
|
mesh_buffers_.clear();
|
||||||
|
|
||||||
quality_ = g_base->graphics_server->quality();
|
quality_ = Graphics::GraphicsQualityFromRequest(
|
||||||
|
settings->graphics_quality, client_context->auto_graphics_quality);
|
||||||
|
|
||||||
assert(g_base->graphics->has_supports_high_quality_graphics_value());
|
texture_quality_ = Graphics::TextureQualityFromRequest(
|
||||||
|
settings->texture_quality, client_context->auto_texture_quality);
|
||||||
|
|
||||||
|
// pixel_scale_ = g_base->graphics->settings()->pixel_scale;
|
||||||
|
|
||||||
|
// assert(g_base->graphics->has_supports_high_quality_graphics_value());
|
||||||
orbiting_ = (g_base->graphics->camera()->mode() == CameraMode::kOrbit);
|
orbiting_ = (g_base->graphics->camera()->mode() == CameraMode::kOrbit);
|
||||||
tv_border_ = g_base->graphics->tv_border();
|
// tv_border_ = g_base->graphics->tv_border();
|
||||||
|
|
||||||
shadow_offset_ = g_base->graphics->shadow_offset();
|
shadow_offset_ = g_base->graphics->shadow_offset();
|
||||||
shadow_scale_ = g_base->graphics->shadow_scale();
|
shadow_scale_ = g_base->graphics->shadow_scale();
|
||||||
@ -99,21 +112,21 @@ void FrameDef::Reset() {
|
|||||||
beauty_pass_->set_floor_reflection(g_base->graphics->floor_reflection());
|
beauty_pass_->set_floor_reflection(g_base->graphics->floor_reflection());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameDef::Finalize() {
|
void FrameDef::Complete() {
|
||||||
assert(!defining_component_);
|
assert(!defining_component_);
|
||||||
light_pass_->Finalize();
|
light_pass_->Complete();
|
||||||
light_shadow_pass_->Finalize();
|
light_shadow_pass_->Complete();
|
||||||
beauty_pass_->Finalize();
|
beauty_pass_->Complete();
|
||||||
beauty_pass_bg_->Finalize();
|
beauty_pass_bg_->Complete();
|
||||||
overlay_pass_->Finalize();
|
overlay_pass_->Complete();
|
||||||
overlay_front_pass_->Finalize();
|
overlay_front_pass_->Complete();
|
||||||
if (g_core->IsVRMode()) {
|
if (g_core->IsVRMode()) {
|
||||||
overlay_fixed_pass_->Finalize();
|
overlay_fixed_pass_->Complete();
|
||||||
overlay_flat_pass_->Finalize();
|
overlay_flat_pass_->Complete();
|
||||||
vr_cover_pass_->Finalize();
|
vr_cover_pass_->Complete();
|
||||||
}
|
}
|
||||||
overlay_3d_pass_->Finalize();
|
overlay_3d_pass_->Complete();
|
||||||
blit_pass_->Finalize();
|
blit_pass_->Complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameDef::AddMesh(Mesh* mesh) {
|
void FrameDef::AddMesh(Mesh* mesh) {
|
||||||
|
|||||||
@ -7,13 +7,14 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "ballistica/base/assets/asset.h"
|
#include "ballistica/base/assets/asset.h"
|
||||||
|
#include "ballistica/shared/generic/snapshot.h"
|
||||||
#include "ballistica/shared/math/matrix44f.h"
|
#include "ballistica/shared/math/matrix44f.h"
|
||||||
#include "ballistica/shared/math/vector2f.h"
|
#include "ballistica/shared/math/vector2f.h"
|
||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
|
|
||||||
/// A flattened representation of a frame; generated by the logic thread and
|
/// A flattened representation of a frame; generated by the logic thread and
|
||||||
/// sent to the graphics thread to render.
|
/// sent to the graphics server to render.
|
||||||
class FrameDef {
|
class FrameDef {
|
||||||
public:
|
public:
|
||||||
auto light_pass() -> RenderPass* { return light_pass_.get(); }
|
auto light_pass() -> RenderPass* { return light_pass_.get(); }
|
||||||
@ -43,21 +44,21 @@ class FrameDef {
|
|||||||
return app_time_microsecs_ / 1000;
|
return app_time_microsecs_ / 1000;
|
||||||
}
|
}
|
||||||
auto app_time_microsecs() const -> microsecs_t { return app_time_microsecs_; }
|
auto app_time_microsecs() const -> microsecs_t { return app_time_microsecs_; }
|
||||||
auto app_time() const -> double {
|
auto app_time() const {
|
||||||
return static_cast<double>(app_time_microsecs_) / 1000000.0;
|
return static_cast<seconds_t>(app_time_microsecs_) / 1000000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A number incremented for each frame renderered. Note that graphics code
|
// A number incremented for each frame renderered. Note that graphics code
|
||||||
// should not plug this directly into things like flash calculations since
|
// should not plug this directly into things like flash calculations since
|
||||||
// frame-rates will vary a lot these days. A 30hz flash will look a lot
|
// frame-rates vary a lot these days. A 30hz flash will look a lot
|
||||||
// different than a 240hz flash. Use frame_number_filtered() for such
|
// different than a 240hz flash. Use frame_number_filtered() for such
|
||||||
// purposes.
|
// purposes.
|
||||||
auto frame_number() const { return frame_number_; }
|
auto frame_number() const { return frame_number_; }
|
||||||
|
|
||||||
// A number incremented for each frame rendered, but a maximum of 60 times
|
// A number incremented for each frame rendered, but a maximum of 60 times
|
||||||
// per second. Code for drawing flashes or other exact effects should use
|
// per second. Code for drawing flashes or other crisp blink-y effects
|
||||||
// this value instead of regular frame_number so that things don't turn
|
// should use this value instead of regular frame_number so that things
|
||||||
// muddy at extremely high frame rates.
|
// don't turn muddy at extremely high frame rates.
|
||||||
auto frame_number_filtered() const { return frame_number_filtered_; }
|
auto frame_number_filtered() const { return frame_number_filtered_; }
|
||||||
|
|
||||||
// Returns the display-time this frame-def was created at (tries to match
|
// Returns the display-time this frame-def was created at (tries to match
|
||||||
@ -66,14 +67,19 @@ class FrameDef {
|
|||||||
auto display_time_millisecs() const -> millisecs_t {
|
auto display_time_millisecs() const -> millisecs_t {
|
||||||
return display_time_microsecs_ / 1000;
|
return display_time_microsecs_ / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto display_time_microsecs() const -> microsecs_t {
|
auto display_time_microsecs() const -> microsecs_t {
|
||||||
return display_time_microsecs_;
|
return display_time_microsecs_;
|
||||||
}
|
}
|
||||||
auto display_time() const -> double {
|
|
||||||
return static_cast<double>(display_time_microsecs_) / 1000000.0;
|
auto display_time() const -> seconds_t {
|
||||||
|
return static_cast<seconds_t>(display_time_microsecs_) / 1000000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto display_time_elapsed() const -> seconds_t {
|
||||||
|
return static_cast<seconds_t>(display_time_elapsed_microsecs_) / 1000000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// How much display time does this frame-def represent.
|
|
||||||
auto display_time_elapsed_millisecs() const -> millisecs_t {
|
auto display_time_elapsed_millisecs() const -> millisecs_t {
|
||||||
return display_time_elapsed_millisecs_;
|
return display_time_elapsed_millisecs_;
|
||||||
}
|
}
|
||||||
@ -82,7 +88,9 @@ class FrameDef {
|
|||||||
return display_time_elapsed_microsecs_;
|
return display_time_elapsed_microsecs_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto quality() const -> GraphicsQuality { return quality_; }
|
auto quality() const { return quality_; }
|
||||||
|
auto texture_quality() const { return texture_quality_; }
|
||||||
|
|
||||||
auto orbiting() const -> bool { return orbiting_; }
|
auto orbiting() const -> bool { return orbiting_; }
|
||||||
auto shadow_offset() const -> const Vector3f& { return shadow_offset_; }
|
auto shadow_offset() const -> const Vector3f& { return shadow_offset_; }
|
||||||
auto shadow_scale() const -> const Vector2f& { return shadow_scale_; }
|
auto shadow_scale() const -> const Vector2f& { return shadow_scale_; }
|
||||||
@ -115,11 +123,12 @@ class FrameDef {
|
|||||||
vr_overlay_screen_matrix_fixed_ = mat;
|
vr_overlay_screen_matrix_fixed_ = mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Effects requiring availability of a depth texture should
|
// Effects requiring availability of a depth texture should check this to
|
||||||
// check this to determine whether they should draw.
|
// determine whether they should draw.
|
||||||
auto has_depth_texture() const -> bool {
|
auto HasDepthTexture() const -> bool {
|
||||||
return (quality_ >= GraphicsQuality::kHigh);
|
return (quality_ >= GraphicsQuality::kHigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddComponent(const Object::Ref<Asset>& component) {
|
void AddComponent(const Object::Ref<Asset>& component) {
|
||||||
// Add a reference to this component only if we havn't yet.
|
// Add a reference to this component only if we havn't yet.
|
||||||
if (component->last_frame_def_num() != frame_number_) {
|
if (component->last_frame_def_num() != frame_number_) {
|
||||||
@ -134,7 +143,7 @@ class FrameDef {
|
|||||||
FrameDef();
|
FrameDef();
|
||||||
~FrameDef();
|
~FrameDef();
|
||||||
void Reset();
|
void Reset();
|
||||||
void Finalize();
|
void Complete();
|
||||||
|
|
||||||
void set_display_time_elapsed_microsecs(microsecs_t val) {
|
void set_display_time_elapsed_microsecs(microsecs_t val) {
|
||||||
display_time_elapsed_microsecs_ = val;
|
display_time_elapsed_microsecs_ = val;
|
||||||
@ -187,7 +196,7 @@ class FrameDef {
|
|||||||
auto media_components() const -> const std::vector<Object::Ref<Asset>>& {
|
auto media_components() const -> const std::vector<Object::Ref<Asset>>& {
|
||||||
return media_components_;
|
return media_components_;
|
||||||
}
|
}
|
||||||
auto tv_border() const { return tv_border_; }
|
// auto tv_border() const { return tv_border_; }
|
||||||
|
|
||||||
void set_camera_mode(CameraMode val) { camera_mode_ = val; }
|
void set_camera_mode(CameraMode val) { camera_mode_ = val; }
|
||||||
void set_rendering(bool val) { rendering_ = val; }
|
void set_rendering(bool val) { rendering_ = val; }
|
||||||
@ -204,18 +213,27 @@ class FrameDef {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// auto pixel_scale() const { return pixel_scale_; }
|
||||||
|
|
||||||
|
auto* settings() const {
|
||||||
|
assert(settings_snapshot_.Exists());
|
||||||
|
return settings_snapshot_->Get();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool needs_clear_{};
|
Object::Ref<Snapshot<GraphicsSettings>> settings_snapshot_;
|
||||||
bool rendering_{};
|
bool needs_clear_ : 1 {};
|
||||||
bool orbiting_{};
|
bool rendering_ : 1 {};
|
||||||
bool tv_border_{};
|
bool orbiting_ : 1 {};
|
||||||
bool shadow_ortho_{};
|
// bool tv_border_ : 1 {};
|
||||||
|
bool shadow_ortho_ : 1 {};
|
||||||
BenchmarkType benchmark_type_{BenchmarkType::kNone};
|
BenchmarkType benchmark_type_{BenchmarkType::kNone};
|
||||||
CameraMode camera_mode_{CameraMode::kFollow};
|
CameraMode camera_mode_{CameraMode::kFollow};
|
||||||
Vector3f cam_original_{0.0f, 0.0f, 0.0f};
|
Vector3f cam_original_{0.0f, 0.0f, 0.0f};
|
||||||
Vector3f cam_target_original_{0.0f, 0.0f, 0.0f};
|
Vector3f cam_target_original_{0.0f, 0.0f, 0.0f};
|
||||||
Vector3f shake_original_{0.0f, 0.0f, 0.0f};
|
Vector3f shake_original_{0.0f, 0.0f, 0.0f};
|
||||||
float vr_near_clip_{};
|
float vr_near_clip_{};
|
||||||
|
// float pixel_scale_{};
|
||||||
Matrix44f vr_overlay_screen_matrix_ = kMatrix44fIdentity;
|
Matrix44f vr_overlay_screen_matrix_ = kMatrix44fIdentity;
|
||||||
Matrix44f vr_overlay_screen_matrix_fixed_ = kMatrix44fIdentity;
|
Matrix44f vr_overlay_screen_matrix_fixed_ = kMatrix44fIdentity;
|
||||||
std::vector<MeshData*> mesh_data_creates_;
|
std::vector<MeshData*> mesh_data_creates_;
|
||||||
@ -245,7 +263,8 @@ class FrameDef {
|
|||||||
std::unique_ptr<RenderPass> vr_cover_pass_;
|
std::unique_ptr<RenderPass> vr_cover_pass_;
|
||||||
std::unique_ptr<RenderPass> overlay_3d_pass_;
|
std::unique_ptr<RenderPass> overlay_3d_pass_;
|
||||||
std::unique_ptr<RenderPass> blit_pass_;
|
std::unique_ptr<RenderPass> blit_pass_;
|
||||||
GraphicsQuality quality_{GraphicsQuality::kLow};
|
GraphicsQuality quality_{};
|
||||||
|
TextureQuality texture_quality_{};
|
||||||
microsecs_t app_time_microsecs_{};
|
microsecs_t app_time_microsecs_{};
|
||||||
microsecs_t display_time_microsecs_{};
|
microsecs_t display_time_microsecs_{};
|
||||||
microsecs_t display_time_elapsed_microsecs_{};
|
microsecs_t display_time_elapsed_microsecs_{};
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
// Released under the MIT License. See LICENSE for details.
|
||||||
|
|
||||||
|
#include "ballistica/base/graphics/support/graphics_client_context.h"
|
||||||
|
|
||||||
|
#include "ballistica/base/graphics/graphics_server.h"
|
||||||
|
#include "ballistica/base/graphics/renderer/renderer.h"
|
||||||
|
|
||||||
|
namespace ballistica::base {
|
||||||
|
|
||||||
|
GraphicsClientContext::GraphicsClientContext()
|
||||||
|
: auto_graphics_quality{g_base->graphics_server->renderer()
|
||||||
|
->GetAutoGraphicsQuality()},
|
||||||
|
auto_texture_quality{
|
||||||
|
g_base->graphics_server->renderer()->GetAutoTextureQuality()},
|
||||||
|
texture_compression_types{
|
||||||
|
g_base->graphics_server->texture_compression_types()} {}
|
||||||
|
|
||||||
|
GraphicsClientContext::GraphicsClientContext(int dummy)
|
||||||
|
: auto_graphics_quality{GraphicsQuality::kLow},
|
||||||
|
auto_texture_quality{TextureQuality::kLow},
|
||||||
|
texture_compression_types{0} {}
|
||||||
|
|
||||||
|
} // namespace ballistica::base
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
// Released under the MIT License. See LICENSE for details.
|
||||||
|
|
||||||
|
#ifndef BALLISTICA_BASE_GRAPHICS_SUPPORT_GRAPHICS_CLIENT_CONTEXT_H_
|
||||||
|
#define BALLISTICA_BASE_GRAPHICS_SUPPORT_GRAPHICS_CLIENT_CONTEXT_H_
|
||||||
|
|
||||||
|
#include "ballistica/base/base.h"
|
||||||
|
|
||||||
|
namespace ballistica::base {
|
||||||
|
|
||||||
|
/// Represents a valid graphics setup delivered by the graphics server to
|
||||||
|
/// the logic thread. It contains various info about concrete graphics
|
||||||
|
/// settings and capabilities.
|
||||||
|
struct GraphicsClientContext {
|
||||||
|
GraphicsClientContext();
|
||||||
|
|
||||||
|
/// Special constructor to create a dummy context (used by headless builds).
|
||||||
|
explicit GraphicsClientContext(int dummy);
|
||||||
|
|
||||||
|
auto SupportsTextureCompressionType(TextureCompressionType t) const -> bool {
|
||||||
|
return ((texture_compression_types & (0x01u << static_cast<uint32_t>(t)))
|
||||||
|
!= 0u);
|
||||||
|
}
|
||||||
|
|
||||||
|
GraphicsQuality auto_graphics_quality;
|
||||||
|
TextureQuality auto_texture_quality;
|
||||||
|
uint32_t texture_compression_types;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ballistica::base
|
||||||
|
|
||||||
|
#endif // BALLISTICA_BASE_GRAPHICS_SUPPORT_GRAPHICS_CLIENT_CONTEXT_H_
|
||||||
27
src/ballistica/base/graphics/support/graphics_settings.cc
Normal file
27
src/ballistica/base/graphics/support/graphics_settings.cc
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Released under the MIT License. See LICENSE for details.
|
||||||
|
|
||||||
|
#include "ballistica/base/graphics/support/graphics_settings.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "ballistica/base/graphics/graphics.h"
|
||||||
|
#include "ballistica/base/support/app_config.h"
|
||||||
|
#include "ballistica/shared/foundation/object.h"
|
||||||
|
|
||||||
|
namespace ballistica::base {
|
||||||
|
|
||||||
|
GraphicsSettings::GraphicsSettings()
|
||||||
|
|
||||||
|
: resolution{g_base->graphics->screen_pixel_width(),
|
||||||
|
g_base->graphics->screen_pixel_height()},
|
||||||
|
resolution_virtual{g_base->graphics->screen_virtual_width(),
|
||||||
|
g_base->graphics->screen_virtual_height()},
|
||||||
|
pixel_scale{std::clamp(
|
||||||
|
g_base->app_config->Resolve(AppConfig::FloatID::kScreenPixelScale),
|
||||||
|
0.1f, 1.0f)},
|
||||||
|
graphics_quality{g_base->graphics->GraphicsQualityFromAppConfig()},
|
||||||
|
texture_quality{g_base->graphics->TextureQualityFromAppConfig()},
|
||||||
|
tv_border{
|
||||||
|
g_base->app_config->Resolve(AppConfig::BoolID::kEnableTVBorder)} {}
|
||||||
|
|
||||||
|
} // namespace ballistica::base
|
||||||
33
src/ballistica/base/graphics/support/graphics_settings.h
Normal file
33
src/ballistica/base/graphics/support/graphics_settings.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Released under the MIT License. See LICENSE for details.
|
||||||
|
|
||||||
|
#ifndef BALLISTICA_BASE_GRAPHICS_SUPPORT_GRAPHICS_SETTINGS_H_
|
||||||
|
#define BALLISTICA_BASE_GRAPHICS_SUPPORT_GRAPHICS_SETTINGS_H_
|
||||||
|
|
||||||
|
#include "ballistica/base/base.h"
|
||||||
|
#include "ballistica/shared/math/vector2f.h"
|
||||||
|
|
||||||
|
namespace ballistica::base {
|
||||||
|
|
||||||
|
/// A set of settings for graphics, covering things like screen
|
||||||
|
/// resolution, texture quality, etc. These are filled out by the
|
||||||
|
/// AppAdapter in the logic thread and passed up to the GraphicsServer
|
||||||
|
/// either through standalone calls or attached to a FrameDef. Generally
|
||||||
|
/// AppAdapters define their own subclass of this containing additional
|
||||||
|
/// settings specific to themselves or the renderer(s) they use.
|
||||||
|
struct GraphicsSettings {
|
||||||
|
GraphicsSettings();
|
||||||
|
// Each new settings instance will be assigned a unique incrementing index.
|
||||||
|
int index{-1};
|
||||||
|
|
||||||
|
// Some standard settings used by most renderers.
|
||||||
|
Vector2f resolution;
|
||||||
|
Vector2f resolution_virtual;
|
||||||
|
float pixel_scale;
|
||||||
|
GraphicsQualityRequest graphics_quality;
|
||||||
|
TextureQualityRequest texture_quality;
|
||||||
|
bool tv_border;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ballistica::base
|
||||||
|
|
||||||
|
#endif // BALLISTICA_BASE_GRAPHICS_SUPPORT_GRAPHICS_SETTINGS_H_
|
||||||
@ -15,6 +15,7 @@
|
|||||||
#include "ballistica/base/support/app_config.h"
|
#include "ballistica/base/support/app_config.h"
|
||||||
#include "ballistica/base/ui/dev_console.h"
|
#include "ballistica/base/ui/dev_console.h"
|
||||||
#include "ballistica/base/ui/ui.h"
|
#include "ballistica/base/ui/ui.h"
|
||||||
|
#include "ballistica/shared/buildconfig/buildconfig_common.h"
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
#include "ballistica/shared/generic/utils.h"
|
#include "ballistica/shared/generic/utils.h"
|
||||||
|
|
||||||
@ -158,16 +159,16 @@ void Input::AnnounceConnects_() {
|
|||||||
|
|
||||||
// For the first announcement just say "X controllers detected" and don't
|
// For the first announcement just say "X controllers detected" and don't
|
||||||
// have a sound.
|
// have a sound.
|
||||||
if (first_print && g_core->GetAppTimeMillisecs() < 10000) {
|
if (first_print && g_core->GetAppTimeSeconds() < 5.0) {
|
||||||
first_print = false;
|
first_print = false;
|
||||||
|
|
||||||
// Disabling this completely for now; being more lenient with devices
|
// Disabling this completely on Android for now; we often get large
|
||||||
// allowed on Android means this will often come back with large
|
// numbers of devices there that aren't actually devices.
|
||||||
// numbers.
|
|
||||||
bool do_print{false};
|
bool do_print_initial_counts{!g_buildconfig.ostype_android()};
|
||||||
|
|
||||||
// If there's been several connected, just give a number.
|
// If there's been several connected, just give a number.
|
||||||
if (explicit_bool(do_print)) {
|
if (explicit_bool(do_print_initial_counts)) {
|
||||||
if (newly_connected_controllers_.size() > 1) {
|
if (newly_connected_controllers_.size() > 1) {
|
||||||
std::string s =
|
std::string s =
|
||||||
g_base->assets->GetResourceString("controllersDetectedText");
|
g_base->assets->GetResourceString("controllersDetectedText");
|
||||||
@ -532,23 +533,28 @@ void Input::UpdateEnabledControllerSubsystems_() {
|
|||||||
|
|
||||||
// First off, on mac, let's update whether we want to completely ignore
|
// First off, on mac, let's update whether we want to completely ignore
|
||||||
// either the classic or the iOS/Mac controller subsystems.
|
// either the classic or the iOS/Mac controller subsystems.
|
||||||
if (g_buildconfig.ostype_macos()) {
|
//
|
||||||
std::string sys = g_base->app_config->Resolve(
|
// UPDATE - these days we're mfi-only on our xcode builds (which should
|
||||||
AppConfig::StringID::kMacControllerSubsystem);
|
// support older controllers too). So we don't need to touch ignore vals
|
||||||
if (sys == "Classic") {
|
// anywhere since we'll not get sdl ones on those builds.
|
||||||
ignore_mfi_controllers_ = true;
|
|
||||||
ignore_sdl_controllers_ = false;
|
// if (g_buildconfig.ostype_macos()) {
|
||||||
} else if (sys == "MFi") {
|
// std::string sys = g_base->app_config->Resolve(
|
||||||
ignore_mfi_controllers_ = false;
|
// AppConfig::StringID::kMacControllerSubsystem);
|
||||||
ignore_sdl_controllers_ = true;
|
// if (sys == "Classic") {
|
||||||
} else if (sys == "Both") {
|
// ignore_mfi_controllers_ = true;
|
||||||
ignore_mfi_controllers_ = false;
|
// ignore_sdl_controllers_ = false;
|
||||||
ignore_sdl_controllers_ = false;
|
// } else if (sys == "MFi") {
|
||||||
} else {
|
// ignore_mfi_controllers_ = false;
|
||||||
BA_LOG_ONCE(LogLevel::kError,
|
// ignore_sdl_controllers_ = true;
|
||||||
"Invalid mac-controller-subsystem value: '" + sys + "'");
|
// } else if (sys == "Both") {
|
||||||
}
|
// ignore_mfi_controllers_ = false;
|
||||||
}
|
// ignore_sdl_controllers_ = false;
|
||||||
|
// } else {
|
||||||
|
// BA_LOG_ONCE(LogLevel::kError,
|
||||||
|
// "Invalid mac-controller-subsystem value: '" + sys + "'");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::OnAppStart() { assert(g_base->InLogicThread()); }
|
void Input::OnAppStart() { assert(g_base->InLogicThread()); }
|
||||||
@ -809,10 +815,35 @@ void Input::PushTextInputEvent(const std::string& text) {
|
|||||||
g_base->logic->event_loop()->PushCall([this, text] {
|
g_base->logic->event_loop()->PushCall([this, text] {
|
||||||
MarkInputActive();
|
MarkInputActive();
|
||||||
|
|
||||||
// Ignore if input is locked.
|
// If if the app doesn't want direct text input right now.
|
||||||
|
if (!g_base->app_adapter->HasDirectKeyboardInput()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore if input is locked.
|
||||||
if (IsInputLocked()) {
|
if (IsInputLocked()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We try to handle char filtering here (to keep it consistent across
|
||||||
|
// platforms) but make a stink if they sent us something that we can't
|
||||||
|
// at least translate to unicode.
|
||||||
|
if (!Utils::IsValidUTF8(text)) {
|
||||||
|
Log(LogLevel::kWarning, "PushTextInputEvent passed invalid utf-8 text.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now scan through unicode vals and ignore stuff like tabs and newlines
|
||||||
|
// and backspaces. We want to limit this mechanism to direct simple
|
||||||
|
// lines of text. Anything needing something fancier should go through a
|
||||||
|
// proper OS-managed text input dialog or whatnot.
|
||||||
|
auto univals = Utils::UnicodeFromUTF8(text, "80ff83");
|
||||||
|
for (auto&& unival : univals) {
|
||||||
|
if (unival < 32) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (g_base && g_base->ui->dev_console() != nullptr
|
if (g_base && g_base->ui->dev_console() != nullptr
|
||||||
&& g_base->ui->dev_console()->HandleTextEditing(text)) {
|
&& g_base->ui->dev_console()->HandleTextEditing(text)) {
|
||||||
return;
|
return;
|
||||||
@ -997,10 +1028,26 @@ void Input::HandleKeyPress_(const SDL_Keysym& keysym) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command-F or Control-F toggles full-screen if the app-adapter supports it.
|
// Explicitly handle fullscreen-toggles in some cases.
|
||||||
if (g_base->app_adapter->CanToggleFullscreen()) {
|
if (g_base->app_adapter->FullscreenControlAvailable()) {
|
||||||
if (!repeat_press && keysym.sym == SDLK_f
|
bool do_toggle{};
|
||||||
&& ((keysym.mod & KMOD_CTRL) || (keysym.mod & KMOD_GUI))) {
|
// On our Mac SDL builds we support ctrl+F for toggling fullscreen.
|
||||||
|
// On our nice Cocoa build, fullscreening happens magically through the
|
||||||
|
// view menu fullscreen controls.
|
||||||
|
if (g_buildconfig.ostype_macos() && !g_buildconfig.xcode_build()) {
|
||||||
|
if (!repeat_press && keysym.sym == SDLK_f && ((keysym.mod & KMOD_CTRL))) {
|
||||||
|
do_toggle = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// On Windows we support both F11 and Alt+Enter for toggling fullscreen.
|
||||||
|
if (g_buildconfig.ostype_windows()) {
|
||||||
|
if (!repeat_press
|
||||||
|
&& (keysym.sym == SDLK_F11
|
||||||
|
|| (keysym.sym == SDLK_RETURN && ((keysym.mod & KMOD_ALT))))) {
|
||||||
|
do_toggle = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (do_toggle) {
|
||||||
g_base->python->objs()
|
g_base->python->objs()
|
||||||
.Get(BasePython::ObjID::kToggleFullscreenCall)
|
.Get(BasePython::ObjID::kToggleFullscreenCall)
|
||||||
.Call();
|
.Call();
|
||||||
@ -1008,12 +1055,15 @@ void Input::HandleKeyPress_(const SDL_Keysym& keysym) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Control-Q quits. On Mac, the usual Cmd-Q gets handled
|
// Control-Q quits. On Mac, the usual Cmd-Q gets handled implicitly by the
|
||||||
// by the app-adapter implicitly.
|
// app-adapter.
|
||||||
if (!repeat_press && keysym.sym == SDLK_q && (keysym.mod & KMOD_CTRL)) {
|
// UPDATE: Disabling this for now. Looks like standard OS shortcuts like
|
||||||
g_base->QuitApp(true);
|
// Alt+F4 on windows or Cmd-Q on Mac are doing the right thing with SDL
|
||||||
return;
|
// builds these days so these are not needed.
|
||||||
}
|
// if (!repeat_press && keysym.sym == SDLK_q && (keysym.mod & KMOD_CTRL)) {
|
||||||
|
// g_base->QuitApp(true);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
// Let the console intercept stuff if it wants at this point.
|
// Let the console intercept stuff if it wants at this point.
|
||||||
if (auto* console = g_base->ui->dev_console()) {
|
if (auto* console = g_base->ui->dev_console()) {
|
||||||
@ -1247,7 +1297,7 @@ void Input::HandleSmoothMouseScroll_(const Vector2f& velocity, bool momentum) {
|
|||||||
WidgetMessage(WidgetMessage::Type::kMouseWheelVelocityH, nullptr,
|
WidgetMessage(WidgetMessage::Type::kMouseWheelVelocityH, nullptr,
|
||||||
cursor_pos_x_, cursor_pos_y_, velocity.x, momentum));
|
cursor_pos_x_, cursor_pos_y_, velocity.x, momentum));
|
||||||
|
|
||||||
last_mouse_move_time_ = g_core->GetAppTimeMillisecs();
|
last_mouse_move_time_ = g_core->GetAppTimeSeconds();
|
||||||
mouse_move_count_++;
|
mouse_move_count_++;
|
||||||
|
|
||||||
Camera* camera = g_base->graphics->camera();
|
Camera* camera = g_base->graphics->camera();
|
||||||
@ -1283,7 +1333,7 @@ void Input::HandleMouseMotion_(const Vector2f& position) {
|
|||||||
cursor_pos_y_ = g_base->graphics->PixelToVirtualY(
|
cursor_pos_y_ = g_base->graphics->PixelToVirtualY(
|
||||||
position.y * g_base->graphics->screen_pixel_height());
|
position.y * g_base->graphics->screen_pixel_height());
|
||||||
|
|
||||||
last_mouse_move_time_ = g_core->GetAppTimeMillisecs();
|
last_mouse_move_time_ = g_core->GetAppTimeSeconds();
|
||||||
mouse_move_count_++;
|
mouse_move_count_++;
|
||||||
|
|
||||||
// If we have a touch-input in editing mode, pass along events to it.
|
// If we have a touch-input in editing mode, pass along events to it.
|
||||||
@ -1324,7 +1374,7 @@ void Input::HandleMouseDown_(int button, const Vector2f& position) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_mouse_move_time_ = g_core->GetAppTimeMillisecs();
|
last_mouse_move_time_ = g_core->GetAppTimeSeconds();
|
||||||
mouse_move_count_++;
|
mouse_move_count_++;
|
||||||
|
|
||||||
// Convert normalized view coords to our virtual ones.
|
// Convert normalized view coords to our virtual ones.
|
||||||
@ -1389,8 +1439,8 @@ void Input::HandleMouseUp_(int button, const Vector2f& position) {
|
|||||||
position.y * g_base->graphics->screen_pixel_height());
|
position.y * g_base->graphics->screen_pixel_height());
|
||||||
|
|
||||||
// If we have a touch-input in editing mode, pass along events to it.
|
// If we have a touch-input in editing mode, pass along events to it.
|
||||||
// (it usually handles its own events but here we want it to play nice
|
// It usually handles its own events but here we want it to play nice
|
||||||
// with stuff under it by blocking touches, etc)
|
// with stuff under it by blocking touches, etc.
|
||||||
if (touch_input_ && touch_input_->editing()) {
|
if (touch_input_ && touch_input_->editing()) {
|
||||||
touch_input_->HandleTouchUp(reinterpret_cast<void*>(1), cursor_pos_x_,
|
touch_input_->HandleTouchUp(reinterpret_cast<void*>(1), cursor_pos_x_,
|
||||||
cursor_pos_y_);
|
cursor_pos_y_);
|
||||||
@ -1431,9 +1481,6 @@ void Input::HandleTouchEvent_(const TouchEvent& e) {
|
|||||||
|
|
||||||
MarkInputActive();
|
MarkInputActive();
|
||||||
|
|
||||||
// float x = e.x;
|
|
||||||
// float y = e.y;
|
|
||||||
|
|
||||||
if (g_buildconfig.ostype_ios_tvos()) {
|
if (g_buildconfig.ostype_ios_tvos()) {
|
||||||
printf("FIXME: update touch handling\n");
|
printf("FIXME: update touch handling\n");
|
||||||
}
|
}
|
||||||
@ -1463,8 +1510,8 @@ void Input::HandleTouchEvent_(const TouchEvent& e) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We keep track of one 'single' touch which we pass along as
|
// We keep track of one 'single' touch which we pass along as mouse events
|
||||||
// mouse events which covers most UI stuff.
|
// which covers most UI stuff.
|
||||||
if (e.type == TouchEvent::Type::kDown && single_touch_ == nullptr) {
|
if (e.type == TouchEvent::Type::kDown && single_touch_ == nullptr) {
|
||||||
single_touch_ = e.touch;
|
single_touch_ = e.touch;
|
||||||
HandleMouseDown_(SDL_BUTTON_LEFT, Vector2f(e.x, e.y));
|
HandleMouseDown_(SDL_BUTTON_LEFT, Vector2f(e.x, e.y));
|
||||||
@ -1474,8 +1521,8 @@ void Input::HandleTouchEvent_(const TouchEvent& e) {
|
|||||||
HandleMouseMotion_(Vector2f(e.x, e.y));
|
HandleMouseMotion_(Vector2f(e.x, e.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently just applying touch-cancel the same as touch-up here;
|
// Currently just applying touch-cancel the same as touch-up here; perhaps
|
||||||
// perhaps should be smarter in the future.
|
// should be smarter in the future.
|
||||||
if ((e.type == TouchEvent::Type::kUp || e.type == TouchEvent::Type::kCanceled)
|
if ((e.type == TouchEvent::Type::kUp || e.type == TouchEvent::Type::kCanceled)
|
||||||
&& (e.touch == single_touch_ || e.overall)) {
|
&& (e.touch == single_touch_ || e.overall)) {
|
||||||
single_touch_ = nullptr;
|
single_touch_ = nullptr;
|
||||||
@ -1529,13 +1576,9 @@ auto Input::IsCursorVisible() const -> bool {
|
|||||||
}
|
}
|
||||||
bool val;
|
bool val;
|
||||||
|
|
||||||
// Show our cursor if any dialogs/windows are up or else if its been moved
|
// Show our cursor only if its been moved recently.
|
||||||
// very recently.
|
val = (g_core->GetAppTimeSeconds() - last_mouse_move_time_ < 2.071);
|
||||||
if (g_base->ui->MainMenuVisible()) {
|
|
||||||
val = (g_core->GetAppTimeMillisecs() - last_mouse_move_time_ < 5000);
|
|
||||||
} else {
|
|
||||||
val = (g_core->GetAppTimeMillisecs() - last_mouse_move_time_ < 1000);
|
|
||||||
}
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "ballistica/base/base.h"
|
#include "ballistica/base/base.h"
|
||||||
#include "ballistica/shared/foundation/object.h"
|
#include "ballistica/shared/foundation/object.h"
|
||||||
|
#include "ballistica/shared/foundation/types.h"
|
||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
|
|
||||||
@ -179,49 +180,49 @@ class Input {
|
|||||||
void DestroyKeyboardInputDevices_();
|
void DestroyKeyboardInputDevices_();
|
||||||
void AddFakeMods_(SDL_Keysym* sym);
|
void AddFakeMods_(SDL_Keysym* sym);
|
||||||
|
|
||||||
HandleKeyPressCall* keyboard_input_capture_press_{};
|
|
||||||
HandleKeyReleaseCall* keyboard_input_capture_release_{};
|
|
||||||
HandleJoystickEventCall* joystick_input_capture_{};
|
|
||||||
bool input_active_{};
|
|
||||||
millisecs_t input_idle_time_{};
|
|
||||||
int local_active_input_device_count_{};
|
|
||||||
millisecs_t last_get_local_active_input_device_count_check_time_{};
|
|
||||||
std::unordered_map<std::string, std::unordered_map<std::string, int> >
|
|
||||||
reserved_identifiers_;
|
|
||||||
int max_controller_count_so_far_{};
|
|
||||||
std::list<std::string> newly_connected_controllers_;
|
|
||||||
std::list<std::string> newly_disconnected_controllers_;
|
|
||||||
int connect_print_timer_id_{};
|
int connect_print_timer_id_{};
|
||||||
int disconnect_print_timer_id_{};
|
int disconnect_print_timer_id_{};
|
||||||
bool have_button_using_inputs_{};
|
int max_controller_count_so_far_{};
|
||||||
bool have_start_activated_default_button_inputs_{};
|
int local_active_input_device_count_{};
|
||||||
bool have_non_touch_inputs_{};
|
int mouse_move_count_{};
|
||||||
|
int input_lock_count_temp_{};
|
||||||
|
int input_lock_count_permanent_{};
|
||||||
|
bool input_active_ : 1 {};
|
||||||
|
bool have_button_using_inputs_ : 1 {};
|
||||||
|
bool have_start_activated_default_button_inputs_ : 1 {};
|
||||||
|
bool have_non_touch_inputs_ : 1 {};
|
||||||
|
bool ignore_mfi_controllers_ : 1 {};
|
||||||
|
bool ignore_sdl_controllers_ : 1 {};
|
||||||
|
millisecs_t input_idle_time_{};
|
||||||
|
millisecs_t last_get_local_active_input_device_count_check_time_{};
|
||||||
float cursor_pos_x_{};
|
float cursor_pos_x_{};
|
||||||
float cursor_pos_y_{};
|
float cursor_pos_y_{};
|
||||||
millisecs_t last_click_time_{};
|
millisecs_t last_click_time_{};
|
||||||
millisecs_t double_click_time_{200};
|
millisecs_t double_click_time_{200};
|
||||||
millisecs_t last_mouse_move_time_{};
|
seconds_t last_mouse_move_time_{};
|
||||||
int mouse_move_count_{};
|
|
||||||
std::vector<Object::Ref<InputDevice> > input_devices_;
|
|
||||||
KeyboardInput* keyboard_input_{};
|
|
||||||
KeyboardInput* keyboard_input_2_{};
|
|
||||||
TouchInput* touch_input_{};
|
|
||||||
int input_lock_count_temp_{};
|
|
||||||
int input_lock_count_permanent_{};
|
|
||||||
std::list<std::string> input_lock_temp_labels_;
|
std::list<std::string> input_lock_temp_labels_;
|
||||||
std::list<std::string> input_unlock_temp_labels_;
|
std::list<std::string> input_unlock_temp_labels_;
|
||||||
std::list<std::string> input_lock_permanent_labels_;
|
std::list<std::string> input_lock_permanent_labels_;
|
||||||
std::list<std::string> input_unlock_permanent_labels_;
|
std::list<std::string> input_unlock_permanent_labels_;
|
||||||
std::list<std::string> recent_input_locks_unlocks_;
|
std::list<std::string> recent_input_locks_unlocks_;
|
||||||
|
std::list<TestInput*> test_inputs_;
|
||||||
|
std::list<std::string> newly_connected_controllers_;
|
||||||
|
std::list<std::string> newly_disconnected_controllers_;
|
||||||
|
std::unordered_map<std::string, std::unordered_map<std::string, int> >
|
||||||
|
reserved_identifiers_;
|
||||||
|
std::vector<Object::Ref<InputDevice> > input_devices_;
|
||||||
std::set<int> keys_held_;
|
std::set<int> keys_held_;
|
||||||
millisecs_t last_input_device_count_update_time_{};
|
millisecs_t last_input_device_count_update_time_{};
|
||||||
millisecs_t last_input_temp_lock_time_{};
|
millisecs_t last_input_temp_lock_time_{};
|
||||||
bool ignore_mfi_controllers_{};
|
|
||||||
bool ignore_sdl_controllers_{};
|
|
||||||
std::list<TestInput*> test_inputs_;
|
|
||||||
millisecs_t stress_test_time_{};
|
millisecs_t stress_test_time_{};
|
||||||
millisecs_t stress_test_last_leave_time_{};
|
millisecs_t stress_test_last_leave_time_{};
|
||||||
void* single_touch_{};
|
void* single_touch_{};
|
||||||
|
KeyboardInput* keyboard_input_{};
|
||||||
|
KeyboardInput* keyboard_input_2_{};
|
||||||
|
TouchInput* touch_input_{};
|
||||||
|
HandleKeyPressCall* keyboard_input_capture_press_{};
|
||||||
|
HandleKeyReleaseCall* keyboard_input_capture_release_{};
|
||||||
|
HandleJoystickEventCall* joystick_input_capture_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -76,11 +76,11 @@ void Logic::OnAppStart() {
|
|||||||
|
|
||||||
void Logic::OnGraphicsReady() {
|
void Logic::OnGraphicsReady() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
if (on_initial_screen_creation_complete_called_) {
|
if (graphics_ready_) {
|
||||||
// Only want to fire this logic the first time.
|
// Only want to fire this logic the first time.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
on_initial_screen_creation_complete_called_ = true;
|
graphics_ready_ = true;
|
||||||
|
|
||||||
// Ok; graphics-server is telling us we've got a screen (or no screen in
|
// Ok; graphics-server is telling us we've got a screen (or no screen in
|
||||||
// the case of headless-mode). We use this as a cue to kick off our
|
// the case of headless-mode). We use this as a cue to kick off our
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
#define BALLISTICA_BASE_LOGIC_LOGIC_H_
|
#define BALLISTICA_BASE_LOGIC_LOGIC_H_
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "ballistica/shared/foundation/object.h"
|
#include "ballistica/shared/foundation/object.h"
|
||||||
@ -118,6 +117,8 @@ class Logic {
|
|||||||
auto shutting_down() const { return shutting_down_; }
|
auto shutting_down() const { return shutting_down_; }
|
||||||
auto shutdown_completed() const { return shutdown_completed_; }
|
auto shutdown_completed() const { return shutdown_completed_; }
|
||||||
|
|
||||||
|
auto graphics_ready() const { return graphics_ready_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateDisplayTimeForFrameDraw_();
|
void UpdateDisplayTimeForFrameDraw_();
|
||||||
void UpdateDisplayTimeForHeadlessMode_();
|
void UpdateDisplayTimeForHeadlessMode_();
|
||||||
@ -127,31 +128,31 @@ class Logic {
|
|||||||
void UpdatePendingWorkTimer_();
|
void UpdatePendingWorkTimer_();
|
||||||
void StepDisplayTime_();
|
void StepDisplayTime_();
|
||||||
|
|
||||||
double display_time_{};
|
seconds_t display_time_{};
|
||||||
double display_time_increment_{1.0 / 60.0};
|
seconds_t display_time_increment_{1.0 / 60.0};
|
||||||
microsecs_t display_time_microsecs_{};
|
microsecs_t display_time_microsecs_{};
|
||||||
microsecs_t display_time_increment_microsecs_{1000000 / 60};
|
microsecs_t display_time_increment_microsecs_{1000000 / 60};
|
||||||
|
|
||||||
// GUI scheduling.
|
|
||||||
double last_display_time_update_app_time_{-1.0};
|
|
||||||
double recent_display_time_increments_[kDisplayTimeSampleCount]{};
|
|
||||||
int recent_display_time_increments_index_{-1};
|
|
||||||
|
|
||||||
// Headless scheduling.
|
// Headless scheduling.
|
||||||
Timer* headless_display_time_step_timer_{};
|
Timer* headless_display_time_step_timer_{};
|
||||||
|
|
||||||
Timer* process_pending_work_timer_{};
|
// GUI scheduling.
|
||||||
Timer* asset_prune_timer_{};
|
seconds_t last_display_time_update_app_time_{-1.0};
|
||||||
Timer* debug_timer_{};
|
seconds_t recent_display_time_increments_[kDisplayTimeSampleCount]{};
|
||||||
EventLoop* event_loop_{};
|
int recent_display_time_increments_index_{-1};
|
||||||
std::unique_ptr<TimerList> display_timers_;
|
|
||||||
bool app_bootstrapping_complete_ : 1 {};
|
bool app_bootstrapping_complete_ : 1 {};
|
||||||
bool have_pending_loads_ : 1 {};
|
bool have_pending_loads_ : 1 {};
|
||||||
bool debug_log_display_time_ : 1 {};
|
bool debug_log_display_time_ : 1 {};
|
||||||
bool applied_app_config_ : 1 {};
|
bool applied_app_config_ : 1 {};
|
||||||
bool shutting_down_ : 1 {};
|
bool shutting_down_ : 1 {};
|
||||||
bool shutdown_completed_ : 1 {};
|
bool shutdown_completed_ : 1 {};
|
||||||
bool on_initial_screen_creation_complete_called_ : 1 {};
|
bool graphics_ready_ : 1 {};
|
||||||
|
Timer* process_pending_work_timer_{};
|
||||||
|
Timer* asset_prune_timer_{};
|
||||||
|
Timer* debug_timer_{};
|
||||||
|
EventLoop* event_loop_{};
|
||||||
|
std::unique_ptr<TimerList> display_timers_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -4,9 +4,8 @@
|
|||||||
#include "ballistica/base/platform/apple/base_platform_apple.h"
|
#include "ballistica/base/platform/apple/base_platform_apple.h"
|
||||||
|
|
||||||
#if BA_XCODE_BUILD
|
#if BA_XCODE_BUILD
|
||||||
#include <unistd.h>
|
#include <BallisticaKit-Swift.h>
|
||||||
#endif
|
#endif
|
||||||
#include <uuid/uuid.h>
|
|
||||||
|
|
||||||
#if BA_XCODE_BUILD
|
#if BA_XCODE_BUILD
|
||||||
#include "ballistica/base/platform/apple/apple_utils.h"
|
#include "ballistica/base/platform/apple/apple_utils.h"
|
||||||
@ -14,12 +13,7 @@
|
|||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
|
|
||||||
#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && BA_SDL_BUILD
|
BasePlatformApple::BasePlatformApple() {
|
||||||
extern void DoSetCursor(bool show);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
BasePlatformApple::BasePlatformApple() { // NOLINT: trivial constructor false
|
|
||||||
// positive
|
|
||||||
// On iOS, keep the device from falling asleep in our app
|
// On iOS, keep the device from falling asleep in our app
|
||||||
#if BA_OSTYPE_IOS_TVOS
|
#if BA_OSTYPE_IOS_TVOS
|
||||||
AppleUtils::DisableIdleTimer();
|
AppleUtils::DisableIdleTimer();
|
||||||
@ -53,24 +47,17 @@ void BasePlatformApple::PurchaseAck(const std::string& purchase,
|
|||||||
|
|
||||||
void BasePlatformApple::DoOpenURL(const std::string& url) {
|
void BasePlatformApple::DoOpenURL(const std::string& url) {
|
||||||
#if BA_XCODE_BUILD
|
#if BA_XCODE_BUILD
|
||||||
// Go ahead and do this ourself. Though perhaps the default
|
#if BA_OSTYPE_MACOS
|
||||||
// Python path would be fine.
|
BallisticaKit::CocoaFromCppOpenURL(url);
|
||||||
AppleUtils::OpenURL(url.c_str());
|
|
||||||
#else
|
#else
|
||||||
// Otherwise go with the default (Python webbrowser module).
|
BallisticaKit::UIKitFromCppOpenURL(url);
|
||||||
BasePlatform::DoOpenURL(url);
|
#endif // BA_OSTYPE_MACOS
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// void BasePlatformApple::SetHardwareCursorVisible(bool visible) {
|
#else
|
||||||
// // Set our nifty custom hardware cursor on mac;
|
// For non-xcode builds, go with the default (Python webbrowser module).
|
||||||
// // otherwise fall back to default.
|
BasePlatform::DoOpenURL(url);
|
||||||
// #if BA_OSTYPE_MACOS && BA_XCODE_BUILD && !BA_HEADLESS_BUILD && BA_SDL_BUILD
|
#endif // BA_XCODE_BUILD
|
||||||
// base::DoSetCursor(visible);
|
}
|
||||||
// #else
|
|
||||||
// return BasePlatform::SetHardwareCursorVisible(visible);
|
|
||||||
// #endif
|
|
||||||
// }
|
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|
||||||
|
|||||||
@ -11,15 +11,11 @@ namespace ballistica::base {
|
|||||||
class BasePlatformApple : public BasePlatform {
|
class BasePlatformApple : public BasePlatform {
|
||||||
public:
|
public:
|
||||||
BasePlatformApple();
|
BasePlatformApple();
|
||||||
|
|
||||||
void DoPurchase(const std::string& item) override;
|
void DoPurchase(const std::string& item) override;
|
||||||
void RestorePurchases() override;
|
void RestorePurchases() override;
|
||||||
void PurchaseAck(const std::string& purchase,
|
void PurchaseAck(const std::string& purchase,
|
||||||
const std::string& order_id) override;
|
const std::string& order_id) override;
|
||||||
|
|
||||||
void DoOpenURL(const std::string& url) override;
|
void DoOpenURL(const std::string& url) override;
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -38,6 +38,8 @@ class BasePython {
|
|||||||
kConfig,
|
kConfig,
|
||||||
kAppOnNativeBootstrappingCompleteCall,
|
kAppOnNativeBootstrappingCompleteCall,
|
||||||
kResetToMainMenuCall,
|
kResetToMainMenuCall,
|
||||||
|
kStoreConfigFullscreenOnCall,
|
||||||
|
kStoreConfigFullscreenOffCall,
|
||||||
kSetConfigFullscreenOnCall,
|
kSetConfigFullscreenOnCall,
|
||||||
kSetConfigFullscreenOffCall,
|
kSetConfigFullscreenOffCall,
|
||||||
kNotSignedInScreenMessageCall,
|
kNotSignedInScreenMessageCall,
|
||||||
@ -108,6 +110,7 @@ class BasePython {
|
|||||||
kDevConsoleStringEditAdapterClass,
|
kDevConsoleStringEditAdapterClass,
|
||||||
kGetDevConsoleTabNamesCall,
|
kGetDevConsoleTabNamesCall,
|
||||||
kAppDevConsoleDoRefreshTabCall,
|
kAppDevConsoleDoRefreshTabCall,
|
||||||
|
kUnsupportedControllerMessageCall,
|
||||||
kLast // Sentinel; must be at end.
|
kLast // Sentinel; must be at end.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -810,9 +810,9 @@ static PyMethodDef PySetStressTestingDef = {
|
|||||||
"(internal)",
|
"(internal)",
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------ display_log ----------------------------------
|
// -------------------------------- emit_log -----------------------------------
|
||||||
|
|
||||||
static auto PyDisplayLog(PyObject* self, PyObject* args, PyObject* keywds)
|
static auto PyEmitLog(PyObject* self, PyObject* args, PyObject* keywds)
|
||||||
-> PyObject* {
|
-> PyObject* {
|
||||||
BA_PYTHON_TRY;
|
BA_PYTHON_TRY;
|
||||||
static const char* kwlist[] = {"name", "level", "message", nullptr};
|
static const char* kwlist[] = {"name", "level", "message", nullptr};
|
||||||
@ -839,25 +839,25 @@ static auto PyDisplayLog(PyObject* self, PyObject* args, PyObject* keywds)
|
|||||||
level = LogLevel::kCritical;
|
level = LogLevel::kCritical;
|
||||||
} else {
|
} else {
|
||||||
// Assume we should avoid Log() calls here since it could infinite loop.
|
// Assume we should avoid Log() calls here since it could infinite loop.
|
||||||
fprintf(stderr, "Invalid log level to display_log(): %s\n", levelstr);
|
fprintf(stderr, "Invalid log level to emit_log(): %s\n", levelstr);
|
||||||
level = LogLevel::kInfo;
|
level = LogLevel::kInfo;
|
||||||
}
|
}
|
||||||
Logging::DisplayLog(name, level, message);
|
Logging::EmitLog(name, level, message);
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
BA_PYTHON_CATCH;
|
BA_PYTHON_CATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef PyDisplayLogDef = {
|
static PyMethodDef PyEmitLogDef = {
|
||||||
"display_log", // name
|
"emit_log", // name
|
||||||
(PyCFunction)PyDisplayLog, // method
|
(PyCFunction)PyEmitLog, // method
|
||||||
METH_VARARGS | METH_KEYWORDS, // flags
|
METH_VARARGS | METH_KEYWORDS, // flags
|
||||||
|
|
||||||
"display_log(name: str, level: str, message: str) -> None\n"
|
"emit_log(name: str, level: str, message: str) -> None\n"
|
||||||
"\n"
|
"\n"
|
||||||
"(internal)\n"
|
"(internal)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Sends a log message to the in-game console and any per-platform\n"
|
"Sends a log message to the in-app console and any per-platform\n"
|
||||||
"log destinations (Android log, etc.). This generally is not called\n"
|
"log destinations (Android log, etc.). This generally is not called\n"
|
||||||
"directly and should instead be fed Python logging output.",
|
"directly and should instead be fed Python logging output.",
|
||||||
};
|
};
|
||||||
@ -1654,7 +1654,7 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
|
|||||||
PyAppNameUpperDef,
|
PyAppNameUpperDef,
|
||||||
PyIsXCodeBuildDef,
|
PyIsXCodeBuildDef,
|
||||||
PyCanDisplayFullUnicodeDef,
|
PyCanDisplayFullUnicodeDef,
|
||||||
PyDisplayLogDef,
|
PyEmitLogDef,
|
||||||
PyV1CloudLogDef,
|
PyV1CloudLogDef,
|
||||||
PySetStressTestingDef,
|
PySetStressTestingDef,
|
||||||
PyEnvDef,
|
PyEnvDef,
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
#include "ballistica/base/python/support/python_context_call_runnable.h"
|
#include "ballistica/base/python/support/python_context_call_runnable.h"
|
||||||
#include "ballistica/core/core.h"
|
#include "ballistica/core/core.h"
|
||||||
#include "ballistica/core/platform/core_platform.h"
|
#include "ballistica/core/platform/core_platform.h"
|
||||||
|
#include "ballistica/shared/foundation/macros.h"
|
||||||
#include "ballistica/shared/generic/utils.h"
|
#include "ballistica/shared/generic/utils.h"
|
||||||
#include "ballistica/shared/python/python.h"
|
#include "ballistica/shared/python/python.h"
|
||||||
#include "ballistica/shared/python/python_sys.h"
|
#include "ballistica/shared/python/python_sys.h"
|
||||||
@ -345,23 +346,23 @@ static PyMethodDef PySafeColorDef = {
|
|||||||
|
|
||||||
// ------------------------ get_max_graphics_quality ---------------------------
|
// ------------------------ get_max_graphics_quality ---------------------------
|
||||||
|
|
||||||
static auto PyGetMaxGraphicsQuality(PyObject* self, PyObject* args)
|
static auto PyGetMaxGraphicsQuality(PyObject* self) -> PyObject* {
|
||||||
-> PyObject* {
|
|
||||||
BA_PYTHON_TRY;
|
BA_PYTHON_TRY;
|
||||||
if (g_base->graphics
|
// if (g_base->graphics
|
||||||
&& g_base->graphics->has_supports_high_quality_graphics_value()
|
// && g_base->graphics->has_supports_high_quality_graphics_value()
|
||||||
&& g_base->graphics->supports_high_quality_graphics()) {
|
// && g_base->graphics->supports_high_quality_graphics()) {
|
||||||
return Py_BuildValue("s", "High");
|
// return Py_BuildValue("s", "High");
|
||||||
} else {
|
// } else {
|
||||||
return Py_BuildValue("s", "Medium");
|
// return Py_BuildValue("s", "Medium");
|
||||||
}
|
// }
|
||||||
|
return Py_BuildValue("s", "Higher");
|
||||||
BA_PYTHON_CATCH;
|
BA_PYTHON_CATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef PyGetMaxGraphicsQualityDef = {
|
static PyMethodDef PyGetMaxGraphicsQualityDef = {
|
||||||
"get_max_graphics_quality", // name
|
"get_max_graphics_quality", // name
|
||||||
PyGetMaxGraphicsQuality, // method
|
(PyCFunction)PyGetMaxGraphicsQuality, // method
|
||||||
METH_VARARGS, // flags
|
METH_NOARGS, // flags
|
||||||
|
|
||||||
"get_max_graphics_quality() -> str\n"
|
"get_max_graphics_quality() -> str\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -619,24 +620,105 @@ static PyMethodDef PyGetDisplayResolutionDef = {
|
|||||||
"display. Returns None if resolutions cannot be directly set.",
|
"display. Returns None if resolutions cannot be directly set.",
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------- can_toggle_fullscreen ----------------------------
|
// ---------------------- fullscreen_control_available -------------------------
|
||||||
|
|
||||||
static auto PyCanToggleFullscreen(PyObject* self) -> PyObject* {
|
static auto PyFullscreenControlAvailable(PyObject* self) -> PyObject* {
|
||||||
BA_PYTHON_TRY;
|
BA_PYTHON_TRY;
|
||||||
|
|
||||||
if (g_base->app_adapter->CanToggleFullscreen()) {
|
BA_PRECONDITION(g_base->InLogicThread());
|
||||||
|
if (g_base->app_adapter->FullscreenControlAvailable()) {
|
||||||
Py_RETURN_TRUE;
|
Py_RETURN_TRUE;
|
||||||
}
|
}
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
BA_PYTHON_CATCH;
|
BA_PYTHON_CATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef PyCanToggleFullscreenDef = {
|
static PyMethodDef PyFullscreenControlAvailableDef = {
|
||||||
"can_toggle_fullscreen", // name
|
"fullscreen_control_available", // name
|
||||||
(PyCFunction)PyCanToggleFullscreen, // method
|
(PyCFunction)PyFullscreenControlAvailable, // method
|
||||||
METH_NOARGS, // flags
|
METH_NOARGS, // flags
|
||||||
|
|
||||||
"can_toggle_fullscreen() -> bool\n"
|
"fullscreen_control_available() -> bool\n"
|
||||||
|
"\n"
|
||||||
|
"(internal)\n",
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------- fullscreen_control_key_shortcut -----------------------
|
||||||
|
|
||||||
|
static auto PyFullscreenControlKeyShortcut(PyObject* self) -> PyObject* {
|
||||||
|
BA_PYTHON_TRY;
|
||||||
|
|
||||||
|
BA_PRECONDITION(g_base->InLogicThread());
|
||||||
|
BA_PRECONDITION(g_base->app_adapter->FullscreenControlAvailable());
|
||||||
|
|
||||||
|
auto val = g_base->app_adapter->FullscreenControlKeyShortcut();
|
||||||
|
if (val.has_value()) {
|
||||||
|
return PyUnicode_FromString(val->c_str());
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
BA_PYTHON_CATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef PyFullscreenControlKeyShortcutDef = {
|
||||||
|
"fullscreen_control_key_shortcut", // name
|
||||||
|
(PyCFunction)PyFullscreenControlKeyShortcut, // method
|
||||||
|
METH_NOARGS, // flags
|
||||||
|
|
||||||
|
"fullscreen_control_key_shortcut() -> str | None\n"
|
||||||
|
"\n"
|
||||||
|
"(internal)\n",
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------------ fullscreen_control_get -----------------------------
|
||||||
|
|
||||||
|
static auto PyFullscreenControlGet(PyObject* self) -> PyObject* {
|
||||||
|
BA_PYTHON_TRY;
|
||||||
|
|
||||||
|
BA_PRECONDITION(g_base->InLogicThread());
|
||||||
|
if (g_base->app_adapter->FullscreenControlGet()) {
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
}
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
BA_PYTHON_CATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef PyFullscreenControlGetDef = {
|
||||||
|
"fullscreen_control_get", // name
|
||||||
|
(PyCFunction)PyFullscreenControlGet, // method
|
||||||
|
METH_NOARGS, // flags
|
||||||
|
|
||||||
|
"fullscreen_control_get() -> bool\n"
|
||||||
|
"\n"
|
||||||
|
"(internal)\n",
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------------ fullscreen_control_set -----------------------------
|
||||||
|
|
||||||
|
static auto PyFullscreenControlSet(PyObject* self, PyObject* args,
|
||||||
|
PyObject* keywds) -> PyObject* {
|
||||||
|
BA_PYTHON_TRY;
|
||||||
|
|
||||||
|
BA_PRECONDITION(g_base->InLogicThread());
|
||||||
|
|
||||||
|
int val{};
|
||||||
|
static const char* kwlist[] = {"val", nullptr};
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args, keywds, "p",
|
||||||
|
const_cast<char**>(kwlist), &val)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_base->app_adapter->FullscreenControlSet(val);
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
BA_PYTHON_CATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef PyFullscreenControlSetDef = {
|
||||||
|
"fullscreen_control_set", // name
|
||||||
|
(PyCFunction)PyFullscreenControlSet, // method
|
||||||
|
METH_VARARGS | METH_KEYWORDS, // flags
|
||||||
|
|
||||||
|
"fullscreen_control_set(val: bool) -> None\n"
|
||||||
"\n"
|
"\n"
|
||||||
"(internal)\n",
|
"(internal)\n",
|
||||||
};
|
};
|
||||||
@ -728,10 +810,13 @@ auto PythonMethodsGraphics::GetMethods() -> std::vector<PyMethodDef> {
|
|||||||
PyGetMaxGraphicsQualityDef,
|
PyGetMaxGraphicsQualityDef,
|
||||||
PySafeColorDef,
|
PySafeColorDef,
|
||||||
PyCharStrDef,
|
PyCharStrDef,
|
||||||
PyCanToggleFullscreenDef,
|
PyFullscreenControlAvailableDef,
|
||||||
PySupportsVSyncDef,
|
PySupportsVSyncDef,
|
||||||
PySupportsMaxFPSDef,
|
PySupportsMaxFPSDef,
|
||||||
PyShowProgressBarDef,
|
PyShowProgressBarDef,
|
||||||
|
PyFullscreenControlKeyShortcutDef,
|
||||||
|
PyFullscreenControlGetDef,
|
||||||
|
PyFullscreenControlSetDef,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -33,6 +33,8 @@ static auto PyGetSimpleSound(PyObject* self, PyObject* args, PyObject* keywds)
|
|||||||
const_cast<char**>(kwlist), &name)) {
|
const_cast<char**>(kwlist), &name)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
BA_PRECONDITION(g_base->InLogicThread());
|
||||||
|
BA_PRECONDITION(g_base->assets->asset_loads_allowed());
|
||||||
{
|
{
|
||||||
Assets::AssetListLock lock;
|
Assets::AssetListLock lock;
|
||||||
return PythonClassSimpleSound::Create(g_base->assets->GetSound(name));
|
return PythonClassSimpleSound::Create(g_base->assets->GetSound(name));
|
||||||
@ -1658,6 +1660,27 @@ static PyMethodDef PyDevConsoleRequestRefreshDef = {
|
|||||||
"(internal)",
|
"(internal)",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// -------------------------- asset_loads_allowed ------------------------------
|
||||||
|
|
||||||
|
static auto PyAssetLoadsAllowed(PyObject* self) -> PyObject* {
|
||||||
|
BA_PYTHON_TRY;
|
||||||
|
if (g_base->assets->asset_loads_allowed()) {
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
}
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
BA_PYTHON_CATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef PyAssetLoadsAllowedDef = {
|
||||||
|
"asset_loads_allowed", // name
|
||||||
|
(PyCFunction)PyAssetLoadsAllowed, // method
|
||||||
|
METH_NOARGS, // flags
|
||||||
|
|
||||||
|
"asset_loads_allowed() -> bool\n"
|
||||||
|
"\n"
|
||||||
|
"(internal)",
|
||||||
|
};
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
auto PythonMethodsMisc::GetMethods() -> std::vector<PyMethodDef> {
|
auto PythonMethodsMisc::GetMethods() -> std::vector<PyMethodDef> {
|
||||||
@ -1720,6 +1743,7 @@ auto PythonMethodsMisc::GetMethods() -> std::vector<PyMethodDef> {
|
|||||||
PyDevConsoleTabHeightDef,
|
PyDevConsoleTabHeightDef,
|
||||||
PyDevConsoleBaseScaleDef,
|
PyDevConsoleBaseScaleDef,
|
||||||
PyDevConsoleRequestRefreshDef,
|
PyDevConsoleRequestRefreshDef,
|
||||||
|
PyAssetLoadsAllowedDef,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "ballistica/base/ui/ui.h"
|
#include "ballistica/base/ui/ui.h"
|
||||||
|
|
||||||
|
#include "ballistica/base/app_adapter/app_adapter.h"
|
||||||
#include "ballistica/base/audio/audio.h"
|
#include "ballistica/base/audio/audio.h"
|
||||||
#include "ballistica/base/graphics/component/simple_component.h"
|
#include "ballistica/base/graphics/component/simple_component.h"
|
||||||
#include "ballistica/base/input/device/keyboard_input.h"
|
#include "ballistica/base/input/device/keyboard_input.h"
|
||||||
@ -184,15 +185,14 @@ void UI::HandleMouseUp(int button, float x, float y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto UI::UIHasDirectKeyboardInput() const -> bool {
|
auto UI::UIHasDirectKeyboardInput() const -> bool {
|
||||||
// Currently limiting this to desktop operating systems, but should
|
// As a first gate, ask the app-adapter if it is providing keyboard
|
||||||
// generalize this, as situations such as tablets with hardware keyboards
|
// events at all.
|
||||||
// should behave similarly to desktop PCs. Though perhaps we should make
|
if (g_base->app_adapter->HasDirectKeyboardInput()) {
|
||||||
// this optional everywhere (or language dependent) since direct keyboard
|
// Ok, direct keyboard input is a thing.
|
||||||
// input might not work well for some languages even on desktops.
|
// Now let's also require the keyboard (or nothing) to be currently
|
||||||
if (g_buildconfig.ostype_macos() || g_buildconfig.ostype_windows()
|
// driving the UI. If something like a game-controller is driving,
|
||||||
|| g_buildconfig.ostype_linux()) {
|
// we'll probably want to pop up a controller-centric on-screen-keyboard
|
||||||
// Return true if we've got a keyboard attached and either it or nothing
|
// thingie instead.
|
||||||
// is active.
|
|
||||||
auto* ui_input_device = g_base->ui->GetUIInputDevice();
|
auto* ui_input_device = g_base->ui->GetUIInputDevice();
|
||||||
if (auto* keyboard = g_base->ui->GetUIInputDevice()) {
|
if (auto* keyboard = g_base->ui->GetUIInputDevice()) {
|
||||||
if (ui_input_device == keyboard || ui_input_device == nullptr) {
|
if (ui_input_device == keyboard || ui_input_device == nullptr) {
|
||||||
|
|||||||
@ -147,17 +147,17 @@ auto CorePlatformApple::IsRunningOnDesktop() -> bool {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CorePlatformApple::DisplayLog(const std::string& name, LogLevel level,
|
void CorePlatformApple::EmitPlatformLog(const std::string& name, LogLevel level,
|
||||||
const std::string& msg) {
|
const std::string& msg) {
|
||||||
#if BA_XCODE_BUILD && !BA_HEADLESS_BUILD
|
#if BA_XCODE_BUILD && !BA_HEADLESS_BUILD
|
||||||
|
|
||||||
// HMM: do we want to use proper logging APIs here or simple printing?
|
// HMM: do we want to use proper logging APIs here or simple printing?
|
||||||
// base::AppleUtils::NSLogStr(msg);
|
// base::AppleUtils::NSLogStr(msg);
|
||||||
CorePlatform::DisplayLog(name, level, msg);
|
CorePlatform::EmitPlatformLog(name, level, msg);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// Fall back to default handler...
|
// Fall back to default handler...
|
||||||
CorePlatform::DisplayLog(name, level, msg);
|
CorePlatform::EmitPlatformLog(name, level, msg);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,8 +26,8 @@ class CorePlatformApple : public CorePlatform {
|
|||||||
auto DoHasTouchScreen() -> bool override;
|
auto DoHasTouchScreen() -> bool override;
|
||||||
auto GetDefaultUIScale() -> UIScale override;
|
auto GetDefaultUIScale() -> UIScale override;
|
||||||
auto IsRunningOnDesktop() -> bool override;
|
auto IsRunningOnDesktop() -> bool override;
|
||||||
void DisplayLog(const std::string& name, LogLevel level,
|
void EmitPlatformLog(const std::string& name, LogLevel level,
|
||||||
const std::string& msg) override;
|
const std::string& msg) override;
|
||||||
void GetTextBoundsAndWidth(const std::string& text, Rect* r,
|
void GetTextBoundsAndWidth(const std::string& text, Rect* r,
|
||||||
float* width) override;
|
float* width) override;
|
||||||
void FreeTextTexture(void* tex) override;
|
void FreeTextTexture(void* tex) override;
|
||||||
|
|||||||
@ -465,12 +465,17 @@ auto CorePlatform::IsRunningOnDesktop() -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CorePlatform::SleepMillisecs(millisecs_t ms) {
|
void CorePlatform::SleepSeconds(seconds_t duration) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
std::this_thread::sleep_for(
|
||||||
|
std::chrono::microseconds(static_cast<microsecs_t>(duration * 1000000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CorePlatform::SleepMicrosecs(millisecs_t ms) {
|
void CorePlatform::SleepMillisecs(millisecs_t duration) {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(ms));
|
std::this_thread::sleep_for(std::chrono::milliseconds(duration));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CorePlatform::SleepMicrosecs(millisecs_t duration) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::microseconds(duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
@ -481,8 +486,8 @@ auto CorePlatform::GetDefaultUIScale() -> UIScale {
|
|||||||
return UIScale::kLarge;
|
return UIScale::kLarge;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CorePlatform::DisplayLog(const std::string& name, LogLevel level,
|
void CorePlatform::EmitPlatformLog(const std::string& name, LogLevel level,
|
||||||
const std::string& msg) {
|
const std::string& msg) {
|
||||||
// Do nothing by default.
|
// Do nothing by default.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -99,8 +99,8 @@ class CorePlatform {
|
|||||||
/// Display a message to any default log for the platform (android log,
|
/// Display a message to any default log for the platform (android log,
|
||||||
/// etc.) Note that this can be called from any thread. Default
|
/// etc.) Note that this can be called from any thread. Default
|
||||||
/// implementation does nothing.
|
/// implementation does nothing.
|
||||||
virtual void DisplayLog(const std::string& name, LogLevel level,
|
virtual void EmitPlatformLog(const std::string& name, LogLevel level,
|
||||||
const std::string& msg);
|
const std::string& msg);
|
||||||
|
|
||||||
#pragma mark ENVIRONMENT -------------------------------------------------------
|
#pragma mark ENVIRONMENT -------------------------------------------------------
|
||||||
|
|
||||||
@ -381,9 +381,9 @@ class CorePlatform {
|
|||||||
/// to not go backwards.
|
/// to not go backwards.
|
||||||
static auto GetCurrentWholeSeconds() -> int64_t;
|
static auto GetCurrentWholeSeconds() -> int64_t;
|
||||||
|
|
||||||
static void SleepMillisecs(millisecs_t ms);
|
static void SleepSeconds(seconds_t duration);
|
||||||
|
static void SleepMillisecs(millisecs_t duration);
|
||||||
static void SleepMicrosecs(microsecs_t ms);
|
static void SleepMicrosecs(microsecs_t duration);
|
||||||
|
|
||||||
/// Given a C++ symbol, attempt to return a pretty one.
|
/// Given a C++ symbol, attempt to return a pretty one.
|
||||||
virtual auto DemangleCXXSymbol(const std::string& s) -> std::string;
|
virtual auto DemangleCXXSymbol(const std::string& s) -> std::string;
|
||||||
|
|||||||
@ -827,11 +827,12 @@ std::string CorePlatformWindows::DoGetDeviceName() {
|
|||||||
|
|
||||||
bool CorePlatformWindows::DoHasTouchScreen() { return false; }
|
bool CorePlatformWindows::DoHasTouchScreen() { return false; }
|
||||||
|
|
||||||
void CorePlatformWindows::DisplayLog(const std::string& name, LogLevel level,
|
void CorePlatformWindows::EmitPlatformLog(const std::string& name,
|
||||||
const std::string& msg) {
|
LogLevel level,
|
||||||
|
const std::string& msg) {
|
||||||
// if (have_stdin_stdout_) {
|
// if (have_stdin_stdout_) {
|
||||||
// // On headless builds we use default handler (simple stdout).
|
// // On headless builds we use default handler (simple stdout).
|
||||||
// return CorePlatform::DisplayLog(msg);
|
// return CorePlatform::EmitPlatformLog(msg);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Also spit this out as a debug-string for when running from msvc.
|
// Also spit this out as a debug-string for when running from msvc.
|
||||||
|
|||||||
@ -41,8 +41,8 @@ class CorePlatformWindows : public CorePlatform {
|
|||||||
auto GetLocale() -> std::string override;
|
auto GetLocale() -> std::string override;
|
||||||
auto DoGetDeviceName() -> std::string override;
|
auto DoGetDeviceName() -> std::string override;
|
||||||
auto DoHasTouchScreen() -> bool override;
|
auto DoHasTouchScreen() -> bool override;
|
||||||
void DisplayLog(const std::string& name, LogLevel level,
|
void EmitPlatformLog(const std::string& name, LogLevel level,
|
||||||
const std::string& msg) override;
|
const std::string& msg) override;
|
||||||
void SetEnv(const std::string& name, const std::string& value) override;
|
void SetEnv(const std::string& name, const std::string& value) override;
|
||||||
auto GetEnv(const std::string& name) -> std::optional<std::string> override;
|
auto GetEnv(const std::string& name) -> std::optional<std::string> override;
|
||||||
auto GetIsStdinATerminal() -> bool override;
|
auto GetIsStdinATerminal() -> bool override;
|
||||||
|
|||||||
@ -307,8 +307,8 @@ void CorePython::LoggingCall(LogLevel loglevel, const std::string& msg) {
|
|||||||
"CorePython::LoggingCall() called before Python"
|
"CorePython::LoggingCall() called before Python"
|
||||||
" logging available."};
|
" logging available."};
|
||||||
if (g_core->platform) {
|
if (g_core->platform) {
|
||||||
g_core->platform->DisplayLog("root", LogLevel::kError, errmsg);
|
g_core->platform->EmitPlatformLog("root", LogLevel::kError, errmsg);
|
||||||
g_core->platform->DisplayLog("root", loglevel, msg);
|
g_core->platform->EmitPlatformLog("root", loglevel, msg);
|
||||||
}
|
}
|
||||||
fprintf(stderr, "%s\n%s\n", errmsg, msg.c_str());
|
fprintf(stderr, "%s\n%s\n", errmsg, msg.c_str());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,7 @@ class CorePython {
|
|||||||
|
|
||||||
/// Calls Python logging function (logging.error, logging.warning, etc.)
|
/// Calls Python logging function (logging.error, logging.warning, etc.)
|
||||||
/// Can be called from any thread at any time. If called before Python
|
/// Can be called from any thread at any time. If called before Python
|
||||||
/// logging is available, logs locally using Logging::DisplayLog()
|
/// logging is available, logs locally using Logging::EmitPlatformLog()
|
||||||
/// (with an added warning).
|
/// (with an added warning).
|
||||||
void LoggingCall(LogLevel loglevel, const std::string& msg);
|
void LoggingCall(LogLevel loglevel, const std::string& msg);
|
||||||
void ImportPythonObjs();
|
void ImportPythonObjs();
|
||||||
|
|||||||
@ -42,6 +42,7 @@ class BaseSoftInterface {
|
|||||||
virtual void DoPushObjCall(const PythonObjectSetBase* objset, int id,
|
virtual void DoPushObjCall(const PythonObjectSetBase* objset, int id,
|
||||||
const std::string& arg) = 0;
|
const std::string& arg) = 0;
|
||||||
virtual auto IsAppStarted() const -> bool = 0;
|
virtual auto IsAppStarted() const -> bool = 0;
|
||||||
|
virtual auto IsAppBootstrapped() const -> bool = 0;
|
||||||
virtual auto GetReturnValue() const -> int = 0;
|
virtual auto GetReturnValue() const -> int = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -12,11 +12,12 @@
|
|||||||
|
|
||||||
namespace ballistica::scene_v1 {
|
namespace ballistica::scene_v1 {
|
||||||
|
|
||||||
// Stores info about an occurring collision.
|
/// Stores info about an occurring collision.
|
||||||
// Note than just because a collision exists between two parts doesn't mean
|
///
|
||||||
// they're physically colliding in the simulation. It is just a shortcut to
|
/// Note than just because a collision exists between two parts doesn't mean
|
||||||
// determine what behavior, if any, exists between two parts which are currently
|
/// they're physically colliding in the simulation. It is just a shortcut to
|
||||||
// overlapping in the simulation.
|
/// determine what behavior, if any, exists between two parts which are
|
||||||
|
/// currently overlapping in the simulation.
|
||||||
class Collision : public Object {
|
class Collision : public Object {
|
||||||
public:
|
public:
|
||||||
explicit Collision(Scene* scene) : src_context(scene), dst_context(scene) {}
|
explicit Collision(Scene* scene) : src_context(scene), dst_context(scene) {}
|
||||||
|
|||||||
@ -66,77 +66,77 @@ void do_dBodyGetLocalFeedback(dBodyID b, dReal px, dReal py, dReal pz,
|
|||||||
|
|
||||||
// Stores info about a collision needing a reset
|
// Stores info about a collision needing a reset
|
||||||
// (used when parts change materials).
|
// (used when parts change materials).
|
||||||
class Dynamics::CollisionReset {
|
class Dynamics::CollisionReset_ {
|
||||||
public:
|
public:
|
||||||
int node1;
|
int node1;
|
||||||
int node2;
|
int node2;
|
||||||
int part1;
|
int part1;
|
||||||
int part2;
|
int part2;
|
||||||
CollisionReset(int node1_in, int part1_in, int node2_in, int part2_in)
|
CollisionReset_(int node1_in, int part1_in, int node2_in, int part2_in)
|
||||||
: node1(node1_in), node2(node2_in), part1(part1_in), part2(part2_in) {}
|
: node1(node1_in), node2(node2_in), part1(part1_in), part2(part2_in) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Dynamics::CollisionEvent {
|
class Dynamics::CollisionEvent_ {
|
||||||
public:
|
public:
|
||||||
Object::Ref<MaterialAction> action;
|
Object::Ref<MaterialAction> action;
|
||||||
Object::Ref<Collision> collision;
|
Object::Ref<Collision> collision;
|
||||||
Object::WeakRef<Node> node1; // first event node
|
Object::WeakRef<Node> node1; // first event node
|
||||||
Object::WeakRef<Node> node2; // second event node
|
Object::WeakRef<Node> node2; // second event node
|
||||||
CollisionEvent(Node* node1_in, Node* node2_in,
|
CollisionEvent_(Node* node1_in, Node* node2_in,
|
||||||
const Object::Ref<MaterialAction>& action_in,
|
const Object::Ref<MaterialAction>& action_in,
|
||||||
const Object::Ref<Collision>& collision_in)
|
const Object::Ref<Collision>& collision_in)
|
||||||
: node1(node1_in),
|
: node1(node1_in),
|
||||||
node2(node2_in),
|
node2(node2_in),
|
||||||
action(action_in),
|
action(action_in),
|
||||||
collision(collision_in) {}
|
collision(collision_in) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Dynamics::SrcPartCollideMap {
|
class Dynamics::SrcPartCollideMap_ {
|
||||||
public:
|
public:
|
||||||
std::unordered_map<int, Object::Ref<Collision> > dst_part_collisions;
|
std::unordered_map<int, Object::Ref<Collision> > dst_part_collisions;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Dynamics::DstNodeCollideMap {
|
class Dynamics::DstNodeCollideMap_ {
|
||||||
public:
|
public:
|
||||||
std::unordered_map<int, SrcPartCollideMap> src_parts;
|
std::unordered_map<int, SrcPartCollideMap_> src_parts;
|
||||||
int collideDisabled;
|
int collideDisabled;
|
||||||
DstNodeCollideMap() : collideDisabled(0) {}
|
DstNodeCollideMap_() : collideDisabled(0) {}
|
||||||
~DstNodeCollideMap() = default;
|
~DstNodeCollideMap_() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Dynamics::SrcNodeCollideMap {
|
class Dynamics::SrcNodeCollideMap_ {
|
||||||
public:
|
public:
|
||||||
std::unordered_map<int64_t, DstNodeCollideMap> dst_nodes;
|
std::unordered_map<int64_t, DstNodeCollideMap_> dst_nodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Dynamics::Impl {
|
class Dynamics::Impl_ {
|
||||||
public:
|
public:
|
||||||
explicit Impl(Dynamics* dynamics) : dynamics_(dynamics) {}
|
explicit Impl_(Dynamics* dynamics) : dynamics_(dynamics) {}
|
||||||
|
|
||||||
// NOTE: we need to implement this here in an Impl class because
|
// NOTE: we need to implement this here in an Impl class because
|
||||||
// gcc currently chokes on unordered_maps with forward-declared types,
|
// gcc currently chokes on unordered_maps with forward-declared types,
|
||||||
// so we can't have this in our header without pushing all our map/collision
|
// so we can't have this in our header without pushing all our map/collision
|
||||||
// types there too.
|
// types there too.
|
||||||
void HandleDisconnect(
|
void HandleDisconnect(
|
||||||
const std::unordered_map<int64_t, Dynamics::SrcNodeCollideMap>::iterator&
|
const std::unordered_map<int64_t, Dynamics::SrcNodeCollideMap_>::iterator&
|
||||||
i,
|
i,
|
||||||
const std::unordered_map<int64_t, Dynamics::DstNodeCollideMap>::iterator&
|
const std::unordered_map<int64_t, Dynamics::DstNodeCollideMap_>::iterator&
|
||||||
j,
|
j,
|
||||||
const std::unordered_map<int, SrcPartCollideMap>::iterator& k,
|
const std::unordered_map<int, SrcPartCollideMap_>::iterator& k,
|
||||||
const std::unordered_map<int, Object::Ref<Collision> >::iterator& l);
|
const std::unordered_map<int, Object::Ref<Collision> >::iterator& l);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Dynamics* dynamics_{};
|
Dynamics* dynamics_{};
|
||||||
// Contains in-progress collisions for current nodes.
|
// Contains in-progress collisions for current nodes.
|
||||||
std::unordered_map<int64_t, SrcNodeCollideMap> node_collisions_;
|
std::unordered_map<int64_t, SrcNodeCollideMap_> node_collisions_;
|
||||||
friend class Dynamics;
|
friend class Dynamics;
|
||||||
};
|
};
|
||||||
|
|
||||||
Dynamics::Dynamics(Scene* scene_in)
|
Dynamics::Dynamics(Scene* scene_in)
|
||||||
: scene_(scene_in),
|
: scene_(scene_in),
|
||||||
collision_cache_(new base::CollisionCache()),
|
collision_cache_(new base::CollisionCache()),
|
||||||
impl_(std::make_unique<Impl>(this)) {
|
impl_(std::make_unique<Impl_>(this)) {
|
||||||
ResetODE();
|
ResetODE_();
|
||||||
}
|
}
|
||||||
|
|
||||||
Dynamics::~Dynamics() {
|
Dynamics::~Dynamics() {
|
||||||
@ -145,7 +145,7 @@ Dynamics::~Dynamics() {
|
|||||||
"Dynamics going down within Process() call;"
|
"Dynamics going down within Process() call;"
|
||||||
" should not happen.");
|
" should not happen.");
|
||||||
}
|
}
|
||||||
ShutdownODE();
|
ShutdownODE_();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dynamics::Draw(base::FrameDef* frame_def) {
|
void Dynamics::Draw(base::FrameDef* frame_def) {
|
||||||
@ -203,7 +203,7 @@ void Dynamics::RemoveTrimesh(dGeomID g) {
|
|||||||
throw Exception("trimesh not found");
|
throw Exception("trimesh not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Dynamics::AreColliding(const Part& p1_in, const Part& p2_in) -> bool {
|
auto Dynamics::AreColliding_(const Part& p1_in, const Part& p2_in) -> bool {
|
||||||
const Part* p1;
|
const Part* p1;
|
||||||
const Part* p2;
|
const Part* p2;
|
||||||
if (IsInStoreOrder(p1_in.node()->id(), p1_in.id(), p2_in.node()->id(),
|
if (IsInStoreOrder(p1_in.node()->id(), p1_in.id(), p2_in.node()->id(),
|
||||||
@ -279,7 +279,7 @@ auto Dynamics::GetCollision(Part* p1_in, Part* p2_in, MaterialContext** cc1,
|
|||||||
p2->ApplyMaterials(*cc2, p2, p1);
|
p2->ApplyMaterials(*cc2, p2, p1);
|
||||||
|
|
||||||
// If either disabled collisions between these two nodes, store that.
|
// If either disabled collisions between these two nodes, store that.
|
||||||
DstNodeCollideMap* dncm =
|
DstNodeCollideMap_* dncm =
|
||||||
&impl_->node_collisions_[p1->node()->id()].dst_nodes[p2->node()->id()];
|
&impl_->node_collisions_[p1->node()->id()].dst_nodes[p2->node()->id()];
|
||||||
if (!(*cc1)->node_collide || !(*cc2)->node_collide) {
|
if (!(*cc1)->node_collide || !(*cc2)->node_collide) {
|
||||||
dncm->collideDisabled = true;
|
dncm->collideDisabled = true;
|
||||||
@ -319,10 +319,12 @@ auto Dynamics::GetCollision(Part* p1_in, Part* p2_in, MaterialContext** cc1,
|
|||||||
return &(*(i.first->second));
|
return &(*(i.first->second));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dynamics::Impl::HandleDisconnect(
|
void Dynamics::Impl_::HandleDisconnect(
|
||||||
const std::unordered_map<int64_t, Dynamics::SrcNodeCollideMap>::iterator& i,
|
const std::unordered_map<int64_t, Dynamics::SrcNodeCollideMap_>::iterator&
|
||||||
const std::unordered_map<int64_t, Dynamics::DstNodeCollideMap>::iterator& j,
|
i,
|
||||||
const std::unordered_map<int, SrcPartCollideMap>::iterator& k,
|
const std::unordered_map<int64_t, Dynamics::DstNodeCollideMap_>::iterator&
|
||||||
|
j,
|
||||||
|
const std::unordered_map<int, SrcPartCollideMap_>::iterator& k,
|
||||||
const std::unordered_map<int, Object::Ref<Collision> >::iterator& l) {
|
const std::unordered_map<int, Object::Ref<Collision> >::iterator& l) {
|
||||||
// Handle disconnect equivalents if they were colliding.
|
// Handle disconnect equivalents if they were colliding.
|
||||||
if (l->second->collide) {
|
if (l->second->collide) {
|
||||||
@ -367,7 +369,7 @@ void Dynamics::Impl::HandleDisconnect(
|
|||||||
k->second.dst_part_collisions.erase(l);
|
k->second.dst_part_collisions.erase(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dynamics::ProcessCollisions() {
|
void Dynamics::ProcessCollision_() {
|
||||||
processing_collisions_ = true;
|
processing_collisions_ = true;
|
||||||
|
|
||||||
collision_count_ = 0;
|
collision_count_ = 0;
|
||||||
@ -441,10 +443,10 @@ void Dynamics::ProcessCollisions() {
|
|||||||
// Process all standard collisions. This will trigger our callback which
|
// Process all standard collisions. This will trigger our callback which
|
||||||
// do the real work (add collisions to list, store commands to be
|
// do the real work (add collisions to list, store commands to be
|
||||||
// called, etc).
|
// called, etc).
|
||||||
dSpaceCollide(ode_space_, this, &DoCollideCallback);
|
dSpaceCollide(ode_space_, this, &DoCollideCallback_);
|
||||||
|
|
||||||
// Collide our trimeshes against everything.
|
// Collide our trimeshes against everything.
|
||||||
collision_cache_->CollideAgainstSpace(ode_space_, this, &DoCollideCallback);
|
collision_cache_->CollideAgainstSpace(ode_space_, this, &DoCollideCallback_);
|
||||||
|
|
||||||
// Do a bit of precalc each cycle.
|
// Do a bit of precalc each cycle.
|
||||||
collision_cache_->Precalc();
|
collision_cache_->Precalc();
|
||||||
@ -453,9 +455,9 @@ void Dynamics::ProcessCollisions() {
|
|||||||
// setting parts' currently-colliding-with lists
|
// setting parts' currently-colliding-with lists
|
||||||
// based on current info,
|
// based on current info,
|
||||||
// removing unclaimed collisions and empty groups.
|
// removing unclaimed collisions and empty groups.
|
||||||
std::unordered_map<int64_t, SrcNodeCollideMap>::iterator i_next;
|
std::unordered_map<int64_t, SrcNodeCollideMap_>::iterator i_next;
|
||||||
std::unordered_map<int64_t, DstNodeCollideMap>::iterator j_next;
|
std::unordered_map<int64_t, DstNodeCollideMap_>::iterator j_next;
|
||||||
std::unordered_map<int, SrcPartCollideMap>::iterator k_next;
|
std::unordered_map<int, SrcPartCollideMap_>::iterator k_next;
|
||||||
std::unordered_map<int, Object::Ref<Collision> >::iterator l_next;
|
std::unordered_map<int, Object::Ref<Collision> >::iterator l_next;
|
||||||
for (auto i = impl_->node_collisions_.begin();
|
for (auto i = impl_->node_collisions_.begin();
|
||||||
i != impl_->node_collisions_.end(); i = i_next) {
|
i != impl_->node_collisions_.end(); i = i_next) {
|
||||||
@ -507,26 +509,26 @@ void Dynamics::ProcessCollisions() {
|
|||||||
collision_events_.clear();
|
collision_events_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dynamics::process() {
|
void Dynamics::Process() {
|
||||||
in_process_ = true;
|
in_process_ = true;
|
||||||
// Update this once so we can recycle results.
|
// Update this once so we can recycle results.
|
||||||
real_time_ = g_core->GetAppTimeMillisecs();
|
real_time_ = g_core->GetAppTimeMillisecs();
|
||||||
ProcessCollisions();
|
ProcessCollision_();
|
||||||
dWorldQuickStep(ode_world_, kGameStepSeconds);
|
dWorldQuickStep(ode_world_, kGameStepSeconds);
|
||||||
dJointGroupEmpty(ode_contact_group_);
|
dJointGroupEmpty(ode_contact_group_);
|
||||||
in_process_ = false;
|
in_process_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dynamics::DoCollideCallback(void* data, dGeomID o1, dGeomID o2) {
|
void Dynamics::DoCollideCallback_(void* data, dGeomID o1, dGeomID o2) {
|
||||||
auto* d = static_cast<Dynamics*>(data);
|
auto* d = static_cast<Dynamics*>(data);
|
||||||
d->CollideCallback(o1, o2);
|
d->CollideCallback_(o1, o2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run collisions for everything. Store any callbacks that will need to be made
|
// Run collisions for everything. Store any callbacks that will need to be made
|
||||||
// and run them after all collision constraints are made.
|
// and run them after all collision constraints are made.
|
||||||
// This way we know all bodies and their associated nodes, etc are valid
|
// This way we know all bodies and their associated nodes, etc are valid
|
||||||
// throughout collision processing.
|
// throughout collision processing.
|
||||||
void Dynamics::CollideCallback(dGeomID o1, dGeomID o2) {
|
void Dynamics::CollideCallback_(dGeomID o1, dGeomID o2) {
|
||||||
dBodyID b1 = dGeomGetBody(o1);
|
dBodyID b1 = dGeomGetBody(o1);
|
||||||
dBodyID b2 = dGeomGetBody(o2);
|
dBodyID b2 = dGeomGetBody(o2);
|
||||||
|
|
||||||
@ -1103,7 +1105,7 @@ void Dynamics::CollideCallback(dGeomID o1, dGeomID o2) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dynamics::ShutdownODE() {
|
void Dynamics::ShutdownODE_() {
|
||||||
if (ode_space_) {
|
if (ode_space_) {
|
||||||
dSpaceDestroy(ode_space_);
|
dSpaceDestroy(ode_space_);
|
||||||
ode_space_ = nullptr;
|
ode_space_ = nullptr;
|
||||||
@ -1118,8 +1120,8 @@ void Dynamics::ShutdownODE() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dynamics::ResetODE() {
|
void Dynamics::ResetODE_() {
|
||||||
ShutdownODE();
|
ShutdownODE_();
|
||||||
ode_world_ = dWorldCreate();
|
ode_world_ = dWorldCreate();
|
||||||
assert(ode_world_);
|
assert(ode_world_);
|
||||||
dWorldSetGravity(ode_world_, 0, -20, 0);
|
dWorldSetGravity(ode_world_, 0, -20, 0);
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
#define BALLISTICA_SCENE_V1_DYNAMICS_DYNAMICS_H_
|
#define BALLISTICA_SCENE_V1_DYNAMICS_DYNAMICS_H_
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "ballistica/base/base.h"
|
#include "ballistica/base/base.h"
|
||||||
@ -16,12 +15,12 @@ namespace ballistica::scene_v1 {
|
|||||||
|
|
||||||
class Dynamics : public Object {
|
class Dynamics : public Object {
|
||||||
public:
|
public:
|
||||||
explicit Dynamics(Scene* scene_in);
|
explicit Dynamics(Scene* scene);
|
||||||
~Dynamics() override;
|
~Dynamics() override;
|
||||||
void Draw(base::FrameDef* frame_def); // Draw any debug stuff, etc.
|
void Draw(base::FrameDef* frame_def); // Draw any debug stuff, etc.
|
||||||
auto ode_world() -> dWorldID { return ode_world_; }
|
auto ode_world() -> dWorldID { return ode_world_; }
|
||||||
auto getContactGroup() -> dJointGroupID { return ode_contact_group_; }
|
auto ode_contact_group() -> dJointGroupID { return ode_contact_group_; }
|
||||||
auto space() -> dSpaceID { return ode_space_; }
|
auto ode_space() -> dSpaceID { return ode_space_; }
|
||||||
|
|
||||||
// Discontinues a collision. Used by parts when changing materials
|
// Discontinues a collision. Used by parts when changing materials
|
||||||
// so that new collisions may enter effect.
|
// so that new collisions may enter effect.
|
||||||
@ -37,6 +36,7 @@ class Dynamics : public Object {
|
|||||||
: active_collide_src_node_)
|
: active_collide_src_node_)
|
||||||
.Get();
|
.Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by collision callbacks - internal.
|
// Used by collision callbacks - internal.
|
||||||
auto GetActiveCollideDstNode() -> Node* {
|
auto GetActiveCollideDstNode() -> Node* {
|
||||||
assert(active_collision_);
|
assert(active_collision_);
|
||||||
@ -49,19 +49,19 @@ class Dynamics : public Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Used by collide message handlers.
|
// Used by collide message handlers.
|
||||||
void set_collide_message_state(bool inCollideMessageIn,
|
void set_collide_message_state(bool in_collide_message,
|
||||||
bool target_other_in = false) {
|
bool target_other = false) {
|
||||||
in_collide_message_ = inCollideMessageIn;
|
in_collide_message_ = in_collide_message;
|
||||||
collide_message_reverse_order_ = target_other_in;
|
collide_message_reverse_order_ = target_other;
|
||||||
}
|
}
|
||||||
auto in_collide_message() const -> bool { return in_collide_message_; }
|
auto in_collide_message() const { return in_collide_message_; }
|
||||||
void process();
|
void Process();
|
||||||
void increment_skid_sound_count() { skid_sound_count_++; }
|
void IncrementSkidSoundCount() { skid_sound_count_++; }
|
||||||
void decrement_skid_sound_count() { skid_sound_count_--; }
|
void DecrementSkidSoundCount() { skid_sound_count_--; }
|
||||||
auto skid_sound_count() const -> int { return skid_sound_count_; }
|
auto skid_sound_count() const { return skid_sound_count_; }
|
||||||
void incrementRollSoundCount() { roll_sound_count_++; }
|
void IncrementRollSoundCount() { roll_sound_count_++; }
|
||||||
void decrement_roll_sound_count() { roll_sound_count_--; }
|
void DecrementRollSoundCount() { roll_sound_count_--; }
|
||||||
auto getRollSoundCount() const -> int { return roll_sound_count_; }
|
auto roll_sound_count() const { return roll_sound_count_; }
|
||||||
|
|
||||||
// We do some fancy collision testing stuff for trimeshes instead
|
// We do some fancy collision testing stuff for trimeshes instead
|
||||||
// of going through regular ODE space collision testing.. so we have
|
// of going through regular ODE space collision testing.. so we have
|
||||||
@ -69,55 +69,52 @@ class Dynamics : public Object {
|
|||||||
void AddTrimesh(dGeomID g);
|
void AddTrimesh(dGeomID g);
|
||||||
void RemoveTrimesh(dGeomID g);
|
void RemoveTrimesh(dGeomID g);
|
||||||
|
|
||||||
auto collision_count() const -> int { return collision_count_; }
|
auto collision_count() const { return collision_count_; }
|
||||||
auto process_real_time() const -> millisecs_t { return real_time_; }
|
auto process_real_time() const { return real_time_; }
|
||||||
auto last_impact_sound_time() const -> millisecs_t {
|
auto last_impact_sound_time() const { return last_impact_sound_time_; }
|
||||||
return last_impact_sound_time_;
|
auto in_process() const { return in_process_; }
|
||||||
}
|
|
||||||
auto in_process() const -> bool { return in_process_; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto AreColliding(const Part& p1, const Part& p2) -> bool;
|
auto AreColliding_(const Part& p1, const Part& p2) -> bool;
|
||||||
class SrcNodeCollideMap;
|
class SrcNodeCollideMap_;
|
||||||
class DstNodeCollideMap;
|
class DstNodeCollideMap_;
|
||||||
class SrcPartCollideMap;
|
class SrcPartCollideMap_;
|
||||||
class CollisionEvent;
|
class CollisionEvent_;
|
||||||
class CollisionReset;
|
class CollisionReset_;
|
||||||
class Impl;
|
class Impl_;
|
||||||
std::vector<CollisionReset> collision_resets_;
|
std::vector<CollisionReset_> collision_resets_;
|
||||||
|
|
||||||
// Return a collision object between these two parts,
|
// Return a collision object between these two parts,
|
||||||
// creating a new one if need be.
|
// creating a new one if need be.
|
||||||
auto GetCollision(Part* p1, Part* p2, MaterialContext** cc1,
|
auto GetCollision(Part* p1, Part* p2, MaterialContext** cc1,
|
||||||
MaterialContext** cc2) -> Collision*;
|
MaterialContext** cc2) -> Collision*;
|
||||||
|
|
||||||
std::vector<CollisionEvent> collision_events_;
|
std::vector<CollisionEvent_> collision_events_;
|
||||||
void ResetODE();
|
void ResetODE_();
|
||||||
void ShutdownODE();
|
void ShutdownODE_();
|
||||||
static void DoCollideCallback(void* data, dGeomID o1, dGeomID o2);
|
static void DoCollideCallback_(void* data, dGeomID o1, dGeomID o2);
|
||||||
void CollideCallback(dGeomID o1, dGeomID o2);
|
void CollideCallback_(dGeomID o1, dGeomID o2);
|
||||||
void ProcessCollisions();
|
void ProcessCollision_();
|
||||||
|
|
||||||
std::unique_ptr<Impl> impl_;
|
int skid_sound_count_{};
|
||||||
bool processing_collisions_{};
|
int roll_sound_count_{};
|
||||||
|
int collision_count_{};
|
||||||
|
bool in_process_ : 1 {};
|
||||||
|
bool in_collide_message_ : 1 {};
|
||||||
|
bool collide_message_reverse_order_ : 1 {};
|
||||||
|
bool processing_collisions_ : 1 {};
|
||||||
dWorldID ode_world_{};
|
dWorldID ode_world_{};
|
||||||
dJointGroupID ode_contact_group_{};
|
dJointGroupID ode_contact_group_{};
|
||||||
dSpaceID ode_space_{};
|
dSpaceID ode_space_{};
|
||||||
millisecs_t real_time_{};
|
millisecs_t real_time_{};
|
||||||
bool in_process_{};
|
|
||||||
std::vector<dGeomID> trimeshes_;
|
|
||||||
millisecs_t last_impact_sound_time_{};
|
millisecs_t last_impact_sound_time_{};
|
||||||
int skid_sound_count_{};
|
|
||||||
int roll_sound_count_{};
|
|
||||||
int collision_count_{};
|
|
||||||
Scene* scene_{};
|
Scene* scene_{};
|
||||||
bool in_collide_message_{};
|
|
||||||
bool collide_message_reverse_order_{};
|
|
||||||
Collision* active_collision_{};
|
Collision* active_collision_{};
|
||||||
Object::WeakRef<Node> active_collide_src_node_;
|
Object::WeakRef<Node> active_collide_src_node_;
|
||||||
Object::WeakRef<Node> active_collide_dst_node_;
|
Object::WeakRef<Node> active_collide_dst_node_;
|
||||||
|
std::vector<dGeomID> trimeshes_;
|
||||||
|
std::unique_ptr<Impl_> impl_;
|
||||||
std::unique_ptr<base::CollisionCache> collision_cache_;
|
std::unique_ptr<base::CollisionCache> collision_cache_;
|
||||||
friend class Impl;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::scene_v1
|
} // namespace ballistica::scene_v1
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "ballistica/scene_v1/dynamics/material/impact_sound_material_action.h"
|
#include "ballistica/scene_v1/dynamics/material/impact_sound_material_action.h"
|
||||||
|
|
||||||
#include "ballistica/base/graphics/graphics_server.h"
|
#include "ballistica/base/audio/audio.h"
|
||||||
#include "ballistica/scene_v1/dynamics/dynamics.h"
|
#include "ballistica/scene_v1/dynamics/dynamics.h"
|
||||||
#include "ballistica/scene_v1/dynamics/material/material_context.h"
|
#include "ballistica/scene_v1/dynamics/material/material_context.h"
|
||||||
#include "ballistica/scene_v1/support/client_session.h"
|
#include "ballistica/scene_v1/support/client_session.h"
|
||||||
@ -50,10 +50,8 @@ void ImpactSoundMaterialAction::Apply(MaterialContext* context,
|
|||||||
assert(context->dynamics.Exists());
|
assert(context->dynamics.Exists());
|
||||||
assert(context->dynamics->in_process());
|
assert(context->dynamics->in_process());
|
||||||
|
|
||||||
// For now lets avoid this in low-quality graphics mode (should we make
|
// Avoid this if we're cutting corners.
|
||||||
// a low-quality sound mode?)
|
if (g_base->audio->UseLowQualityAudio()) {
|
||||||
if (g_base->graphics_server
|
|
||||||
&& g_base->graphics_server->quality() < base::GraphicsQuality::kMedium) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -42,7 +42,7 @@ MaterialContext::SkidSoundEntry::SkidSoundEntry(
|
|||||||
assert(context->dynamics.Exists());
|
assert(context->dynamics.Exists());
|
||||||
#endif
|
#endif
|
||||||
assert(context->dynamics->in_process());
|
assert(context->dynamics->in_process());
|
||||||
context->dynamics->increment_skid_sound_count();
|
context->dynamics->IncrementSkidSoundCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialContext::SkidSoundEntry::SkidSoundEntry(MaterialContext* context_in,
|
MaterialContext::SkidSoundEntry::SkidSoundEntry(MaterialContext* context_in,
|
||||||
@ -57,13 +57,13 @@ MaterialContext::SkidSoundEntry::SkidSoundEntry(MaterialContext* context_in,
|
|||||||
assert(context);
|
assert(context);
|
||||||
assert(context->dynamics.Exists());
|
assert(context->dynamics.Exists());
|
||||||
assert(context->dynamics->in_process());
|
assert(context->dynamics->in_process());
|
||||||
context->dynamics->increment_skid_sound_count();
|
context->dynamics->IncrementSkidSoundCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialContext::SkidSoundEntry::~SkidSoundEntry() {
|
MaterialContext::SkidSoundEntry::~SkidSoundEntry() {
|
||||||
assert(context);
|
assert(context);
|
||||||
assert(context->dynamics.Exists());
|
assert(context->dynamics.Exists());
|
||||||
context->dynamics->decrement_skid_sound_count();
|
context->dynamics->DecrementSkidSoundCount();
|
||||||
if (playing) {
|
if (playing) {
|
||||||
g_base->audio->PushSourceFadeOutCall(play_id, 200);
|
g_base->audio->PushSourceFadeOutCall(play_id, 200);
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ MaterialContext::RollSoundEntry::RollSoundEntry(MaterialContext* context_in,
|
|||||||
assert(context);
|
assert(context);
|
||||||
assert(context->dynamics.Exists());
|
assert(context->dynamics.Exists());
|
||||||
assert(context->dynamics->in_process());
|
assert(context->dynamics->in_process());
|
||||||
context->dynamics->incrementRollSoundCount();
|
context->dynamics->IncrementRollSoundCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialContext::RollSoundEntry::RollSoundEntry(
|
MaterialContext::RollSoundEntry::RollSoundEntry(
|
||||||
@ -90,13 +90,13 @@ MaterialContext::RollSoundEntry::RollSoundEntry(
|
|||||||
assert(context);
|
assert(context);
|
||||||
assert(context->dynamics.Exists());
|
assert(context->dynamics.Exists());
|
||||||
assert(context->dynamics->in_process());
|
assert(context->dynamics->in_process());
|
||||||
context->dynamics->incrementRollSoundCount();
|
context->dynamics->IncrementRollSoundCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialContext::RollSoundEntry::~RollSoundEntry() {
|
MaterialContext::RollSoundEntry::~RollSoundEntry() {
|
||||||
assert(context);
|
assert(context);
|
||||||
assert(context->dynamics.Exists());
|
assert(context->dynamics.Exists());
|
||||||
context->dynamics->decrement_roll_sound_count();
|
context->dynamics->DecrementRollSoundCount();
|
||||||
if (playing) {
|
if (playing) {
|
||||||
g_base->audio->PushSourceFadeOutCall(play_id, 200);
|
g_base->audio->PushSourceFadeOutCall(play_id, 200);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "ballistica/scene_v1/dynamics/material/roll_sound_material_action.h"
|
#include "ballistica/scene_v1/dynamics/material/roll_sound_material_action.h"
|
||||||
|
|
||||||
#include "ballistica/base/graphics/graphics_server.h"
|
#include "ballistica/base/audio/audio.h"
|
||||||
#include "ballistica/scene_v1/dynamics/dynamics.h"
|
#include "ballistica/scene_v1/dynamics/dynamics.h"
|
||||||
#include "ballistica/scene_v1/dynamics/material/material_context.h"
|
#include "ballistica/scene_v1/dynamics/material/material_context.h"
|
||||||
#include "ballistica/scene_v1/support/client_session.h"
|
#include "ballistica/scene_v1/support/client_session.h"
|
||||||
@ -34,16 +34,14 @@ void RollSoundMaterialAction::Apply(MaterialContext* context,
|
|||||||
assert(context->dynamics.Exists());
|
assert(context->dynamics.Exists());
|
||||||
assert(context->dynamics->in_process());
|
assert(context->dynamics->in_process());
|
||||||
|
|
||||||
// For now lets avoid this in low-quality graphics mode
|
// Avoid this if we're cutting corners.
|
||||||
// (should we make a low-quality sound mode?)
|
if (g_base->audio->UseLowQualityAudio()) {
|
||||||
if (g_base->graphics
|
|
||||||
&& g_base->graphics_server->quality() < base::GraphicsQuality::kMedium) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let's limit the amount of skid-sounds we spawn, otherwise we'll
|
// Let's limit the amount of skid-sounds we spawn, otherwise we'll
|
||||||
// start using up all our sound resources on skids when things get messy
|
// start using up all our sound resources on skids when things get messy
|
||||||
if (context->dynamics->getRollSoundCount() < 2) {
|
if (context->dynamics->roll_sound_count() < 2) {
|
||||||
context->roll_sounds.emplace_back(context, sound.Get(), target_impulse,
|
context->roll_sounds.emplace_back(context, sound.Get(), target_impulse,
|
||||||
volume);
|
volume);
|
||||||
context->complex_sound = true;
|
context->complex_sound = true;
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "ballistica/scene_v1/dynamics/material/skid_sound_material_action.h"
|
#include "ballistica/scene_v1/dynamics/material/skid_sound_material_action.h"
|
||||||
|
|
||||||
#include "ballistica/base/graphics/graphics_server.h"
|
#include "ballistica/base/audio/audio.h"
|
||||||
#include "ballistica/scene_v1/dynamics/dynamics.h"
|
#include "ballistica/scene_v1/dynamics/dynamics.h"
|
||||||
#include "ballistica/scene_v1/dynamics/material/material_context.h"
|
#include "ballistica/scene_v1/dynamics/material/material_context.h"
|
||||||
#include "ballistica/scene_v1/support/client_session.h"
|
#include "ballistica/scene_v1/support/client_session.h"
|
||||||
@ -34,10 +34,8 @@ void SkidSoundMaterialAction::Apply(MaterialContext* context,
|
|||||||
assert(context->dynamics.Exists());
|
assert(context->dynamics.Exists());
|
||||||
assert(context->dynamics->in_process());
|
assert(context->dynamics->in_process());
|
||||||
|
|
||||||
// For now lets avoid this in low-quality graphics mode
|
// Avoid this if we're cutting corners.
|
||||||
// (should we make a low-quality sound mode?).
|
if (g_base->audio->UseLowQualityAudio()) {
|
||||||
if (g_base->graphics_server
|
|
||||||
&& g_base->graphics_server->quality() < base::GraphicsQuality::kMedium) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -65,23 +65,23 @@ RigidBody::RigidBody(int id_in, Part* part_in, Type type_in, Shape shape_in,
|
|||||||
case Shape::kSphere: {
|
case Shape::kSphere: {
|
||||||
dimensions_[0] = dimensions_[1] = dimensions_[2] = 0.3f;
|
dimensions_[0] = dimensions_[1] = dimensions_[2] = 0.3f;
|
||||||
geoms_.resize(1);
|
geoms_.resize(1);
|
||||||
geoms_[0] = dCreateSphere(dynamics_->space(), dimensions_[0]);
|
geoms_[0] = dCreateSphere(dynamics_->ode_space(), dimensions_[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Shape::kBox: {
|
case Shape::kBox: {
|
||||||
dimensions_[0] = dimensions_[1] = dimensions_[2] = 0.6f;
|
dimensions_[0] = dimensions_[1] = dimensions_[2] = 0.6f;
|
||||||
geoms_.resize(1);
|
geoms_.resize(1);
|
||||||
geoms_[0] = dCreateBox(dynamics_->space(), dimensions_[0], dimensions_[1],
|
geoms_[0] = dCreateBox(dynamics_->ode_space(), dimensions_[0],
|
||||||
dimensions_[2]);
|
dimensions_[1], dimensions_[2]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Shape::kCapsule: {
|
case Shape::kCapsule: {
|
||||||
dimensions_[0] = dimensions_[1] = 0.3f;
|
dimensions_[0] = dimensions_[1] = 0.3f;
|
||||||
geoms_.resize(1);
|
geoms_.resize(1);
|
||||||
geoms_[0] =
|
geoms_[0] = dCreateCCylinder(dynamics_->ode_space(), dimensions_[0],
|
||||||
dCreateCCylinder(dynamics_->space(), dimensions_[0], dimensions_[1]);
|
dimensions_[1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,14 +98,15 @@ RigidBody::RigidBody(int id_in, Part* part_in, Type type_in, Shape shape_in,
|
|||||||
Vector3f p =
|
Vector3f p =
|
||||||
Matrix44fRotate(Vector3f(0, 1, 0), static_cast<float>(i) * inc)
|
Matrix44fRotate(Vector3f(0, 1, 0), static_cast<float>(i) * inc)
|
||||||
* Vector3f(offset, 0, 0);
|
* Vector3f(offset, 0, 0);
|
||||||
geoms_[i * 2] = dCreateGeomTransform(dynamics_->space());
|
geoms_[i * 2] = dCreateGeomTransform(dynamics_->ode_space());
|
||||||
geoms_[i * 2 + 1] = dCreateSphere(nullptr, sub_rad);
|
geoms_[i * 2 + 1] = dCreateSphere(nullptr, sub_rad);
|
||||||
dGeomTransformSetGeom(geoms_[i * 2], geoms_[i * 2 + 1]);
|
dGeomTransformSetGeom(geoms_[i * 2], geoms_[i * 2 + 1]);
|
||||||
dGeomSetPosition(geoms_[i * 2 + 1], p.v[0], p.v[1], p.v[2]);
|
dGeomSetPosition(geoms_[i * 2 + 1], p.v[0], p.v[1], p.v[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// One last center sphere to keep stuff from getting stuck in our middle.
|
// One last center sphere to keep stuff from getting stuck in our middle.
|
||||||
geoms_[geoms_.size() - 1] = dCreateSphere(dynamics_->space(), sub_rad);
|
geoms_[geoms_.size() - 1] =
|
||||||
|
dCreateSphere(dynamics_->ode_space(), sub_rad);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -129,9 +129,6 @@ FlagNode::FlagNode(Scene* scene) : Node(scene, node_type), part_(this) {
|
|||||||
|
|
||||||
mesh_.SetIndexData(indices);
|
mesh_.SetIndexData(indices);
|
||||||
mesh_.SetStaticData(v_static);
|
mesh_.SetStaticData(v_static);
|
||||||
|
|
||||||
// Create our shadow set.
|
|
||||||
UpdateForGraphicsQuality(g_base->graphics_server->quality());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FlagNode::getPosition() const -> std::vector<float> {
|
auto FlagNode::getPosition() const -> std::vector<float> {
|
||||||
@ -257,6 +254,11 @@ void FlagNode::HandleMessage(const char* data_in) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FlagNode::Draw(base::FrameDef* frame_def) {
|
void FlagNode::Draw(base::FrameDef* frame_def) {
|
||||||
|
if (graphics_quality_ != frame_def->quality()) {
|
||||||
|
graphics_quality_ = frame_def->quality();
|
||||||
|
UpdateForGraphicsQuality(graphics_quality_);
|
||||||
|
}
|
||||||
|
|
||||||
// Flag cloth.
|
// Flag cloth.
|
||||||
{
|
{
|
||||||
// Update the dynamic portion of our mesh data.
|
// Update the dynamic portion of our mesh data.
|
||||||
@ -309,47 +311,60 @@ void FlagNode::Draw(base::FrameDef* frame_def) {
|
|||||||
c.SetTexture(g_base->assets->SysTexture(base::SysTextureID::kShadow));
|
c.SetTexture(g_base->assets->SysTexture(base::SysTextureID::kShadow));
|
||||||
c.SetTransparent(true);
|
c.SetTransparent(true);
|
||||||
|
|
||||||
FullShadowSet* full_shadows = full_shadow_set_.Get();
|
// Update our shadow objects.
|
||||||
|
if (!g_core->HeadlessMode()) {
|
||||||
|
dBodyID b = body_->body();
|
||||||
|
assert(b);
|
||||||
|
dVector3 p;
|
||||||
|
if (FullShadowSet* full_shadows = full_shadow_set_.Get()) {
|
||||||
|
full_shadows->shadow_flag_.SetPosition(
|
||||||
|
flag_points_[kFlagSizeX * (kFlagSizeY / 2) + (kFlagSizeX / 2)]);
|
||||||
|
dBodyGetRelPointPos(b, 0, 0, kFlagHeight * -0.4f, p);
|
||||||
|
full_shadows->shadow_pole_bottom_.SetPosition(Vector3f(p));
|
||||||
|
full_shadows->shadow_pole_middle_.SetPosition(
|
||||||
|
Vector3f(dBodyGetPosition(b)));
|
||||||
|
dBodyGetRelPointPos(b, 0, 0, kFlagHeight * 0.4f, p);
|
||||||
|
full_shadows->shadow_pole_top_.SetPosition(Vector3f(p));
|
||||||
|
// Pole bottom.
|
||||||
|
{
|
||||||
|
full_shadows->shadow_pole_bottom_.GetValues(&s_scale, &s_density);
|
||||||
|
const Vector3f& p(full_shadows->shadow_pole_bottom_.GetPosition());
|
||||||
|
g_base->graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0,
|
||||||
|
s_density * 0.25f);
|
||||||
|
}
|
||||||
|
|
||||||
if (full_shadows) {
|
// Pole middle.
|
||||||
// Pole bottom.
|
{
|
||||||
{
|
full_shadows->shadow_pole_middle_.GetValues(&s_scale, &s_density);
|
||||||
full_shadows->shadow_pole_bottom_.GetValues(&s_scale, &s_density);
|
const Vector3f& p(full_shadows->shadow_pole_middle_.GetPosition());
|
||||||
const Vector3f& p(full_shadows->shadow_pole_bottom_.GetPosition());
|
g_base->graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0,
|
||||||
g_base->graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0,
|
s_density * 0.25f);
|
||||||
s_density * 0.25f);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Pole middle.
|
// Pole top.
|
||||||
{
|
{
|
||||||
full_shadows->shadow_pole_middle_.GetValues(&s_scale, &s_density);
|
full_shadows->shadow_pole_middle_.GetValues(&s_scale, &s_density);
|
||||||
const Vector3f& p(full_shadows->shadow_pole_middle_.GetPosition());
|
const Vector3f& p(full_shadows->shadow_pole_top_.GetPosition());
|
||||||
g_base->graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0,
|
g_base->graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0,
|
||||||
s_density * 0.25f);
|
s_density * 0.25f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pole top.
|
// Flag center.
|
||||||
{
|
{
|
||||||
full_shadows->shadow_pole_middle_.GetValues(&s_scale, &s_density);
|
full_shadows->shadow_flag_.GetValues(&s_scale, &s_density);
|
||||||
const Vector3f& p(full_shadows->shadow_pole_top_.GetPosition());
|
const Vector3f& p(full_shadows->shadow_flag_.GetPosition());
|
||||||
g_base->graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0,
|
g_base->graphics->DrawBlotch(p, 0.8f * s_scale, 0, 0, 0,
|
||||||
s_density * 0.25f);
|
s_density * 0.3f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flag center.
|
} else if (SimpleShadowSet* simple_shadows = simple_shadow_set_.Get()) {
|
||||||
{
|
dBodyGetRelPointPos(b, 0, 0, kFlagHeight * -0.3f, p);
|
||||||
full_shadows->shadow_flag_.GetValues(&s_scale, &s_density);
|
simple_shadows->shadow_.SetPosition(Vector3f(p));
|
||||||
const Vector3f& p(full_shadows->shadow_flag_.GetPosition());
|
simple_shadows->shadow_.GetValues(&s_scale, &s_density);
|
||||||
|
const Vector3f& p(simple_shadows->shadow_.GetPosition());
|
||||||
g_base->graphics->DrawBlotch(p, 0.8f * s_scale, 0, 0, 0,
|
g_base->graphics->DrawBlotch(p, 0.8f * s_scale, 0, 0, 0,
|
||||||
s_density * 0.3f);
|
s_density * 0.5f);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
SimpleShadowSet* simple_shadows = simple_shadow_set_.Get();
|
|
||||||
assert(simple_shadows);
|
|
||||||
simple_shadows->shadow_.GetValues(&s_scale, &s_density);
|
|
||||||
const Vector3f& p(simple_shadows->shadow_.GetPosition());
|
|
||||||
g_base->graphics->DrawBlotch(p, 0.8f * s_scale, 0, 0, 0,
|
|
||||||
s_density * 0.5f);
|
|
||||||
}
|
}
|
||||||
c.Submit();
|
c.Submit();
|
||||||
}
|
}
|
||||||
@ -398,30 +413,6 @@ void FlagNode::Step() {
|
|||||||
// FIXME: This should probably happen for RBDs automatically?
|
// FIXME: This should probably happen for RBDs automatically?
|
||||||
body_->UpdateBlending();
|
body_->UpdateBlending();
|
||||||
|
|
||||||
// Update our shadow objects.
|
|
||||||
dBodyID b = body_->body();
|
|
||||||
assert(b);
|
|
||||||
|
|
||||||
if (!g_core->HeadlessMode()) {
|
|
||||||
dVector3 p;
|
|
||||||
FullShadowSet* full_shadows = full_shadow_set_.Get();
|
|
||||||
if (full_shadows) {
|
|
||||||
full_shadows->shadow_flag_.SetPosition(
|
|
||||||
flag_points_[kFlagSizeX * (kFlagSizeY / 2) + (kFlagSizeX / 2)]);
|
|
||||||
dBodyGetRelPointPos(b, 0, 0, kFlagHeight * -0.4f, p);
|
|
||||||
full_shadows->shadow_pole_bottom_.SetPosition(Vector3f(p));
|
|
||||||
full_shadows->shadow_pole_middle_.SetPosition(
|
|
||||||
Vector3f(dBodyGetPosition(b)));
|
|
||||||
dBodyGetRelPointPos(b, 0, 0, kFlagHeight * 0.4f, p);
|
|
||||||
full_shadows->shadow_pole_top_.SetPosition(Vector3f(p));
|
|
||||||
} else {
|
|
||||||
SimpleShadowSet* simple_shadows = simple_shadow_set_.Get();
|
|
||||||
assert(simple_shadows);
|
|
||||||
dBodyGetRelPointPos(b, 0, 0, kFlagHeight * -0.3f, p);
|
|
||||||
simple_shadows->shadow_.SetPosition(Vector3f(p));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dBodyIsEnabled(body_->body())) {
|
if (dBodyIsEnabled(body_->body())) {
|
||||||
// Try to keep upright by pushing the top of the
|
// Try to keep upright by pushing the top of the
|
||||||
// flag to be above the bottom.
|
// flag to be above the bottom.
|
||||||
@ -675,10 +666,6 @@ void FlagNode::GetRigidBodyPickupLocations(int id, float* obj, float* character,
|
|||||||
hand1[2] = -0.05f;
|
hand1[2] = -0.05f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlagNode::OnGraphicsQualityChanged(base::GraphicsQuality q) {
|
|
||||||
UpdateForGraphicsQuality(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlagNode::UpdateForGraphicsQuality(base::GraphicsQuality quality) {
|
void FlagNode::UpdateForGraphicsQuality(base::GraphicsQuality quality) {
|
||||||
if (!g_core->HeadlessMode()) {
|
if (!g_core->HeadlessMode()) {
|
||||||
if (quality >= base::GraphicsQuality::kMedium) {
|
if (quality >= base::GraphicsQuality::kMedium) {
|
||||||
|
|||||||
@ -44,10 +44,13 @@ class FlagNode : public Node {
|
|||||||
void UpdateDimensions();
|
void UpdateDimensions();
|
||||||
void ResetFlagMesh();
|
void ResetFlagMesh();
|
||||||
void UpdateFlagMesh();
|
void UpdateFlagMesh();
|
||||||
void OnGraphicsQualityChanged(base::GraphicsQuality q) override;
|
|
||||||
void UpdateForGraphicsQuality(base::GraphicsQuality q);
|
void UpdateForGraphicsQuality(base::GraphicsQuality q);
|
||||||
void UpdateSpringPoint(int p1, int p2, float rest_length);
|
void UpdateSpringPoint(int p1, int p2, float rest_length);
|
||||||
base::AreaOfInterest* area_of_interest_ = nullptr;
|
|
||||||
|
base::GraphicsQuality graphics_quality_{};
|
||||||
|
bool light_weight_ : 1 {};
|
||||||
|
bool have_flag_impulse_ : 1 {};
|
||||||
|
base::AreaOfInterest* area_of_interest_{};
|
||||||
Part part_;
|
Part part_;
|
||||||
std::vector<float> color_ = {1.0f, 1.0f, 1.0f};
|
std::vector<float> color_ = {1.0f, 1.0f, 1.0f};
|
||||||
Object::Ref<RigidBody> body_;
|
Object::Ref<RigidBody> body_;
|
||||||
@ -56,15 +59,13 @@ class FlagNode : public Node {
|
|||||||
Object::Ref<FullShadowSet> full_shadow_set_;
|
Object::Ref<FullShadowSet> full_shadow_set_;
|
||||||
Object::Ref<SimpleShadowSet> simple_shadow_set_;
|
Object::Ref<SimpleShadowSet> simple_shadow_set_;
|
||||||
int wind_rand_{};
|
int wind_rand_{};
|
||||||
|
int footing_{};
|
||||||
float wind_rand_x_{};
|
float wind_rand_x_{};
|
||||||
float wind_rand_y_{};
|
float wind_rand_y_{};
|
||||||
float wind_rand_z_{};
|
float wind_rand_z_{};
|
||||||
float flag_impulse_add_x_{};
|
float flag_impulse_add_x_{};
|
||||||
float flag_impulse_add_y_{};
|
float flag_impulse_add_y_{};
|
||||||
float flag_impulse_add_z_{};
|
float flag_impulse_add_z_{};
|
||||||
bool have_flag_impulse_{};
|
|
||||||
int footing_{};
|
|
||||||
bool light_weight_{};
|
|
||||||
Vector3f flag_points_[25]{};
|
Vector3f flag_points_[25]{};
|
||||||
Vector3f flag_normals_[25]{};
|
Vector3f flag_normals_[25]{};
|
||||||
Vector3f flag_velocities_[25]{};
|
Vector3f flag_velocities_[25]{};
|
||||||
|
|||||||
@ -40,7 +40,6 @@ class Node : public Object {
|
|||||||
|
|
||||||
/// Called when the language changes.
|
/// Called when the language changes.
|
||||||
virtual void OnLanguageChange() {}
|
virtual void OnLanguageChange() {}
|
||||||
virtual void OnGraphicsQualityChanged(base::GraphicsQuality q) {}
|
|
||||||
|
|
||||||
/// The node can rule out collisions between particular bodies using this.
|
/// The node can rule out collisions between particular bodies using this.
|
||||||
virtual auto PreFilterCollision(RigidBody* b1, RigidBody* r2) -> bool {
|
virtual auto PreFilterCollision(RigidBody* b1, RigidBody* r2) -> bool {
|
||||||
|
|||||||
@ -576,7 +576,7 @@ auto PropNode::CollideCallback(dContact* c, int count,
|
|||||||
dBodyGetMass(b2, &m);
|
dBodyGetMass(b2, &m);
|
||||||
dJointID j =
|
dJointID j =
|
||||||
dJointCreateFixed(scene()->dynamics()->ode_world(),
|
dJointCreateFixed(scene()->dynamics()->ode_world(),
|
||||||
scene()->dynamics()->getContactGroup());
|
scene()->dynamics()->ode_contact_group());
|
||||||
dJointAttach(j, b1, b2);
|
dJointAttach(j, b1, b2);
|
||||||
dJointSetFixed(j);
|
dJointSetFixed(j);
|
||||||
dJointSetFixedSpringMode(j, 1, 1, false);
|
dJointSetFixedSpringMode(j, 1, 1, false);
|
||||||
|
|||||||
@ -260,7 +260,7 @@ void ShieldNode::Draw(base::FrameDef* frame_def) {
|
|||||||
c.Submit();
|
c.Submit();
|
||||||
|
|
||||||
// Nifty intersection effects in fancy graphics mode.
|
// Nifty intersection effects in fancy graphics mode.
|
||||||
if (frame_def->has_depth_texture()) {
|
if (frame_def->HasDepthTexture()) {
|
||||||
base::ShieldComponent c2(frame_def->overlay_3d_pass());
|
base::ShieldComponent c2(frame_def->overlay_3d_pass());
|
||||||
{
|
{
|
||||||
auto xf = c2.ScopedTransform();
|
auto xf = c2.ScopedTransform();
|
||||||
@ -273,7 +273,7 @@ void ShieldNode::Draw(base::FrameDef* frame_def) {
|
|||||||
}
|
}
|
||||||
c2.Submit();
|
c2.Submit();
|
||||||
}
|
}
|
||||||
if (frame_def->has_depth_texture()) {
|
if (frame_def->HasDepthTexture()) {
|
||||||
base::PostProcessComponent c2(frame_def->blit_pass());
|
base::PostProcessComponent c2(frame_def->blit_pass());
|
||||||
c2.SetNormalDistort(distort);
|
c2.SetNormalDistort(distort);
|
||||||
{
|
{
|
||||||
|
|||||||
@ -916,9 +916,6 @@ SpazNode::SpazNode(Scene* scene)
|
|||||||
// Give joints initial vals.
|
// Give joints initial vals.
|
||||||
UpdateJoints();
|
UpdateJoints();
|
||||||
|
|
||||||
// FIXME: should do this on draw.
|
|
||||||
UpdateForGraphicsQuality(g_base->graphics_server->quality());
|
|
||||||
|
|
||||||
// We want to have an area of interest by default.
|
// We want to have an area of interest by default.
|
||||||
SetIsAreaOfInterest(true);
|
SetIsAreaOfInterest(true);
|
||||||
|
|
||||||
@ -2079,40 +2076,6 @@ void SpazNode::Step() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update shadows.
|
|
||||||
#if !BA_HEADLESS_BUILD
|
|
||||||
FullShadowSet* full_shadows = full_shadow_set_.Get();
|
|
||||||
if (full_shadows) {
|
|
||||||
full_shadows->torso_shadow_.SetPosition(
|
|
||||||
Vector3f(dBodyGetPosition(body_torso_->body())));
|
|
||||||
full_shadows->head_shadow_.SetPosition(
|
|
||||||
Vector3f(dBodyGetPosition(body_head_->body())));
|
|
||||||
full_shadows->pelvis_shadow_.SetPosition(
|
|
||||||
Vector3f(dBodyGetPosition(body_pelvis_->body())));
|
|
||||||
full_shadows->lower_left_leg_shadow_.SetPosition(
|
|
||||||
Vector3f(dBodyGetPosition(lower_left_leg_body_->body())));
|
|
||||||
full_shadows->lower_right_leg_shadow_.SetPosition(
|
|
||||||
Vector3f(dBodyGetPosition(lower_right_leg_body_->body())));
|
|
||||||
full_shadows->upper_left_leg_shadow_.SetPosition(
|
|
||||||
Vector3f(dBodyGetPosition(upper_left_leg_body_->body())));
|
|
||||||
full_shadows->upper_right_leg_shadow_.SetPosition(
|
|
||||||
Vector3f(dBodyGetPosition(upper_right_leg_body_->body())));
|
|
||||||
full_shadows->lower_right_arm_shadow_.SetPosition(
|
|
||||||
Vector3f(dBodyGetPosition(lower_right_arm_body_->body())));
|
|
||||||
full_shadows->upper_right_arm_shadow_.SetPosition(
|
|
||||||
Vector3f(dBodyGetPosition(upper_right_arm_body_->body())));
|
|
||||||
full_shadows->lower_left_arm_shadow_.SetPosition(
|
|
||||||
Vector3f(dBodyGetPosition(lower_left_arm_body_->body())));
|
|
||||||
full_shadows->upper_left_arm_shadow_.SetPosition(
|
|
||||||
Vector3f(dBodyGetPosition(upper_left_arm_body_->body())));
|
|
||||||
} else {
|
|
||||||
SimpleShadowSet* simple_shadows = simple_shadow_set_.Get();
|
|
||||||
assert(simple_shadows);
|
|
||||||
simple_shadows->shadow_.SetPosition(
|
|
||||||
Vector3f(dBodyGetPosition(body_pelvis_->body())));
|
|
||||||
}
|
|
||||||
#endif // !BA_HEADLESS_BUILD
|
|
||||||
|
|
||||||
// Update wings if we've got 'em.
|
// Update wings if we've got 'em.
|
||||||
if (wings_) {
|
if (wings_) {
|
||||||
float maxDist = 0.8f;
|
float maxDist = 0.8f;
|
||||||
@ -4547,6 +4510,11 @@ static void DrawRadialMeter(base::MeshIndexedSimpleFull* m,
|
|||||||
void SpazNode::Draw(base::FrameDef* frame_def) {
|
void SpazNode::Draw(base::FrameDef* frame_def) {
|
||||||
#if !BA_HEADLESS_BUILD
|
#if !BA_HEADLESS_BUILD
|
||||||
|
|
||||||
|
if (graphics_quality_ != frame_def->quality()) {
|
||||||
|
graphics_quality_ = frame_def->quality();
|
||||||
|
UpdateForGraphicsQuality(graphics_quality_);
|
||||||
|
}
|
||||||
|
|
||||||
#if BA_OSTYPE_MACOS
|
#if BA_OSTYPE_MACOS
|
||||||
if (g_base->graphics_server->renderer()->debug_draw_mode()) {
|
if (g_base->graphics_server->renderer()->debug_draw_mode()) {
|
||||||
base::SimpleComponent c(frame_def->overlay_3d_pass());
|
base::SimpleComponent c(frame_def->overlay_3d_pass());
|
||||||
@ -5356,49 +5324,68 @@ void SpazNode::Draw(base::FrameDef* frame_def) {
|
|||||||
sc[2] = weight * freeze_color[2] + (1.0f - weight) * sc[2];
|
sc[2] = weight * freeze_color[2] + (1.0f - weight) * sc[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
FullShadowSet* full_shadows = full_shadow_set_.Get();
|
// Update and draw shadows.
|
||||||
if (full_shadows) {
|
if (!g_core->HeadlessMode()) {
|
||||||
DrawBrightSpot(full_shadows->lower_left_leg_shadow_, 0.3f * death_scale,
|
if (FullShadowSet* full_shadows = full_shadow_set_.Get()) {
|
||||||
death_fade * (frozen_ ? 0.3f : 0.2f), sc);
|
full_shadows->torso_shadow_.SetPosition(
|
||||||
DrawBrightSpot(full_shadows->lower_right_leg_shadow_, 0.3f * death_scale,
|
Vector3f(dBodyGetPosition(body_torso_->body())));
|
||||||
death_fade * (frozen_ ? 0.3f : 0.2f), sc);
|
full_shadows->head_shadow_.SetPosition(
|
||||||
DrawBrightSpot(full_shadows->head_shadow_, 0.45f * death_scale,
|
Vector3f(dBodyGetPosition(body_head_->body())));
|
||||||
death_fade * (frozen_ ? 0.8f : 0.14f), sc);
|
full_shadows->pelvis_shadow_.SetPosition(
|
||||||
}
|
Vector3f(dBodyGetPosition(body_pelvis_->body())));
|
||||||
|
full_shadows->lower_left_leg_shadow_.SetPosition(
|
||||||
|
Vector3f(dBodyGetPosition(lower_left_leg_body_->body())));
|
||||||
|
full_shadows->lower_right_leg_shadow_.SetPosition(
|
||||||
|
Vector3f(dBodyGetPosition(lower_right_leg_body_->body())));
|
||||||
|
full_shadows->upper_left_leg_shadow_.SetPosition(
|
||||||
|
Vector3f(dBodyGetPosition(upper_left_leg_body_->body())));
|
||||||
|
full_shadows->upper_right_leg_shadow_.SetPosition(
|
||||||
|
Vector3f(dBodyGetPosition(upper_right_leg_body_->body())));
|
||||||
|
full_shadows->lower_right_arm_shadow_.SetPosition(
|
||||||
|
Vector3f(dBodyGetPosition(lower_right_arm_body_->body())));
|
||||||
|
full_shadows->upper_right_arm_shadow_.SetPosition(
|
||||||
|
Vector3f(dBodyGetPosition(upper_right_arm_body_->body())));
|
||||||
|
full_shadows->lower_left_arm_shadow_.SetPosition(
|
||||||
|
Vector3f(dBodyGetPosition(lower_left_arm_body_->body())));
|
||||||
|
full_shadows->upper_left_arm_shadow_.SetPosition(
|
||||||
|
Vector3f(dBodyGetPosition(upper_left_arm_body_->body())));
|
||||||
|
|
||||||
if (full_shadows) {
|
DrawBrightSpot(full_shadows->lower_left_leg_shadow_, 0.3f * death_scale,
|
||||||
DrawShadow(full_shadows->torso_shadow_, 0.19f * death_scale, 0.9f, sc);
|
death_fade * (frozen_ ? 0.3f : 0.2f), sc);
|
||||||
DrawShadow(full_shadows->head_shadow_, 0.15f * death_scale, 0.7f, sc);
|
DrawBrightSpot(full_shadows->lower_right_leg_shadow_,
|
||||||
DrawShadow(full_shadows->pelvis_shadow_, 0.15f * death_scale, 0.7f, sc);
|
0.3f * death_scale, death_fade * (frozen_ ? 0.3f : 0.2f),
|
||||||
DrawShadow(full_shadows->lower_left_leg_shadow_, 0.08f * death_scale,
|
sc);
|
||||||
1.0f, sc);
|
DrawBrightSpot(full_shadows->head_shadow_, 0.45f * death_scale,
|
||||||
DrawShadow(full_shadows->lower_right_leg_shadow_, 0.08f * death_scale,
|
death_fade * (frozen_ ? 0.8f : 0.14f), sc);
|
||||||
1.0f, sc);
|
DrawShadow(full_shadows->torso_shadow_, 0.19f * death_scale, 0.9f, sc);
|
||||||
DrawShadow(full_shadows->upper_left_leg_shadow_, 0.08f * death_scale,
|
DrawShadow(full_shadows->head_shadow_, 0.15f * death_scale, 0.7f, sc);
|
||||||
1.0f, sc);
|
DrawShadow(full_shadows->pelvis_shadow_, 0.15f * death_scale, 0.7f, sc);
|
||||||
DrawShadow(full_shadows->upper_right_leg_shadow_, 0.08f * death_scale,
|
DrawShadow(full_shadows->lower_left_leg_shadow_, 0.08f * death_scale,
|
||||||
1.0f, sc);
|
1.0f, sc);
|
||||||
DrawShadow(full_shadows->upper_left_arm_shadow_, 0.08f * death_scale,
|
DrawShadow(full_shadows->lower_right_leg_shadow_, 0.08f * death_scale,
|
||||||
0.5f, sc);
|
1.0f, sc);
|
||||||
DrawShadow(full_shadows->lower_left_arm_shadow_, 0.08f * death_scale,
|
DrawShadow(full_shadows->upper_left_leg_shadow_, 0.08f * death_scale,
|
||||||
0.3f, sc);
|
1.0f, sc);
|
||||||
DrawShadow(full_shadows->lower_right_arm_shadow_, 0.08f * death_scale,
|
DrawShadow(full_shadows->upper_right_leg_shadow_, 0.08f * death_scale,
|
||||||
0.3f, sc);
|
1.0f, sc);
|
||||||
DrawShadow(full_shadows->upper_right_arm_shadow_, 0.08f * death_scale,
|
DrawShadow(full_shadows->upper_left_arm_shadow_, 0.08f * death_scale,
|
||||||
0.5f, sc);
|
0.5f, sc);
|
||||||
} else {
|
DrawShadow(full_shadows->lower_left_arm_shadow_, 0.08f * death_scale,
|
||||||
SimpleShadowSet* simple_shadows = simple_shadow_set_.Get();
|
0.3f, sc);
|
||||||
assert(simple_shadows);
|
DrawShadow(full_shadows->lower_right_arm_shadow_, 0.08f * death_scale,
|
||||||
DrawShadow(simple_shadows->shadow_, 0.2f * death_scale, 2.0f, sc);
|
0.3f, sc);
|
||||||
|
DrawShadow(full_shadows->upper_right_arm_shadow_, 0.08f * death_scale,
|
||||||
|
0.5f, sc);
|
||||||
|
} else if (SimpleShadowSet* simple_shadows = simple_shadow_set_.Get()) {
|
||||||
|
simple_shadows->shadow_.SetPosition(
|
||||||
|
Vector3f(dBodyGetPosition(body_pelvis_->body())));
|
||||||
|
DrawShadow(simple_shadows->shadow_, 0.2f * death_scale, 2.0f, sc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // !BA_HEADLESS_BUILD
|
#endif // !BA_HEADLESS_BUILD
|
||||||
} // NOLINT (yes i know this is too big)
|
} // NOLINT (yes i know this is too big)
|
||||||
|
|
||||||
void SpazNode::OnGraphicsQualityChanged(base::GraphicsQuality q) {
|
|
||||||
UpdateForGraphicsQuality(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpazNode::UpdateForGraphicsQuality(base::GraphicsQuality quality) {
|
void SpazNode::UpdateForGraphicsQuality(base::GraphicsQuality quality) {
|
||||||
#if !BA_HEADLESS_BUILD
|
#if !BA_HEADLESS_BUILD
|
||||||
if (quality >= base::GraphicsQuality::kMedium) {
|
if (quality >= base::GraphicsQuality::kMedium) {
|
||||||
|
|||||||
@ -277,7 +277,6 @@ class SpazNode : public Node {
|
|||||||
|
|
||||||
// Reset to a standing, non-moving state at the given point.
|
// Reset to a standing, non-moving state at the given point.
|
||||||
void Stand(float x, float y, float z, float angle);
|
void Stand(float x, float y, float z, float angle);
|
||||||
void OnGraphicsQualityChanged(base::GraphicsQuality q) override;
|
|
||||||
void UpdateForGraphicsQuality(base::GraphicsQuality q);
|
void UpdateForGraphicsQuality(base::GraphicsQuality q);
|
||||||
void UpdateAreaOfInterest();
|
void UpdateAreaOfInterest();
|
||||||
auto CollideCallback(dContact* c, int count, RigidBody* colliding_body,
|
auto CollideCallback(dContact* c, int count, RigidBody* colliding_body,
|
||||||
@ -515,6 +514,7 @@ class SpazNode : public Node {
|
|||||||
bool has_eyelids_{true};
|
bool has_eyelids_{true};
|
||||||
bool running_{};
|
bool running_{};
|
||||||
bool billboard_cross_out_{};
|
bool billboard_cross_out_{};
|
||||||
|
base::GraphicsQuality graphics_quality_{};
|
||||||
Object::Ref<RigidBody> hair_front_right_body_;
|
Object::Ref<RigidBody> hair_front_right_body_;
|
||||||
JointFixedEF* hair_front_right_joint_{};
|
JointFixedEF* hair_front_right_joint_{};
|
||||||
Object::Ref<RigidBody> hair_front_left_body_;
|
Object::Ref<RigidBody> hair_front_left_body_;
|
||||||
|
|||||||
@ -32,7 +32,12 @@ void PythonClassInputDevice::SetupType(PyTypeObject* cls) {
|
|||||||
"Attributes:\n"
|
"Attributes:\n"
|
||||||
"\n"
|
"\n"
|
||||||
" allows_configuring (bool):\n"
|
" allows_configuring (bool):\n"
|
||||||
" Whether the input-device can be configured.\n"
|
" Whether the input-device can be configured in the app.\n"
|
||||||
|
"\n"
|
||||||
|
" allows_configuring_in_system_settings (bool):\n"
|
||||||
|
" Whether the input-device can be configured in the system.\n"
|
||||||
|
" setings app. This can be used to redirect the user to go there\n"
|
||||||
|
" if they attempt to configure the device.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" has_meaningful_button_names (bool):\n"
|
" has_meaningful_button_names (bool):\n"
|
||||||
" Whether button names returned by this instance match labels\n"
|
" Whether button names returned by this instance match labels\n"
|
||||||
@ -189,6 +194,16 @@ auto PythonClassInputDevice::tp_getattro(PythonClassInputDevice* self,
|
|||||||
} else {
|
} else {
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
}
|
}
|
||||||
|
} else if (!strcmp(s, "allows_configuring_in_system_settings")) {
|
||||||
|
auto* d = self->input_device_delegate_->Get();
|
||||||
|
if (!d) {
|
||||||
|
throw Exception(PyExcType::kInputDeviceNotFound);
|
||||||
|
}
|
||||||
|
if (d->input_device().IsMFiController()) {
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
} else {
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
}
|
||||||
} else if (!strcmp(s, "has_meaningful_button_names")) {
|
} else if (!strcmp(s, "has_meaningful_button_names")) {
|
||||||
auto* d = self->input_device_delegate_->Get();
|
auto* d = self->input_device_delegate_->Get();
|
||||||
if (!d) {
|
if (!d) {
|
||||||
|
|||||||
@ -483,9 +483,6 @@ void HostActivity::PruneSessionBaseTimers() {
|
|||||||
void HostActivity::OnScreenSizeChange() { scene()->OnScreenSizeChange(); }
|
void HostActivity::OnScreenSizeChange() { scene()->OnScreenSizeChange(); }
|
||||||
void HostActivity::LanguageChanged() { scene()->LanguageChanged(); }
|
void HostActivity::LanguageChanged() { scene()->LanguageChanged(); }
|
||||||
void HostActivity::DebugSpeedMultChanged() { UpdateStepTimerLength(); }
|
void HostActivity::DebugSpeedMultChanged() { UpdateStepTimerLength(); }
|
||||||
void HostActivity::GraphicsQualityChanged(base::GraphicsQuality q) {
|
|
||||||
scene()->GraphicsQualityChanged(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HostActivity::Draw(base::FrameDef* frame_def) {
|
void HostActivity::Draw(base::FrameDef* frame_def) {
|
||||||
if (!started_) {
|
if (!started_) {
|
||||||
|
|||||||
@ -57,7 +57,6 @@ class HostActivity : public SceneV1Context {
|
|||||||
void OnScreenSizeChange();
|
void OnScreenSizeChange();
|
||||||
void LanguageChanged();
|
void LanguageChanged();
|
||||||
void DebugSpeedMultChanged();
|
void DebugSpeedMultChanged();
|
||||||
void GraphicsQualityChanged(base::GraphicsQuality q);
|
|
||||||
|
|
||||||
// Used to register python calls created in this context so we can make sure
|
// Used to register python calls created in this context so we can make sure
|
||||||
// they got properly cleaned up.
|
// they got properly cleaned up.
|
||||||
|
|||||||
@ -154,16 +154,6 @@ void HostSession::LanguageChanged() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostSession::GraphicsQualityChanged(base::GraphicsQuality q) {
|
|
||||||
// Let our internal scene know.
|
|
||||||
scene()->GraphicsQualityChanged(q);
|
|
||||||
|
|
||||||
// Let all our activities know.
|
|
||||||
for (auto&& i : host_activities_) {
|
|
||||||
i->GraphicsQualityChanged(q);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto HostSession::DoesFillScreen() const -> bool {
|
auto HostSession::DoesFillScreen() const -> bool {
|
||||||
// FIXME not necessarily the case.
|
// FIXME not necessarily the case.
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -70,7 +70,6 @@ class HostSession : public Session {
|
|||||||
void Draw(base::FrameDef* f) override;
|
void Draw(base::FrameDef* f) override;
|
||||||
void OnScreenSizeChange() override;
|
void OnScreenSizeChange() override;
|
||||||
void LanguageChanged() override;
|
void LanguageChanged() override;
|
||||||
void GraphicsQualityChanged(base::GraphicsQuality q) override;
|
|
||||||
void DebugSpeedMultChanged() override;
|
void DebugSpeedMultChanged() override;
|
||||||
auto GetHostSession() -> HostSession* override;
|
auto GetHostSession() -> HostSession* override;
|
||||||
auto GetMutableScene() -> Scene* override;
|
auto GetMutableScene() -> Scene* override;
|
||||||
|
|||||||
@ -166,7 +166,7 @@ void Scene::Step() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lastly step our sim.
|
// Lastly step our sim.
|
||||||
dynamics_->process();
|
dynamics_->Process();
|
||||||
|
|
||||||
time_ += kGameStepMilliseconds;
|
time_ += kGameStepMilliseconds;
|
||||||
stepnum_++;
|
stepnum_++;
|
||||||
@ -227,13 +227,6 @@ void Scene::DeleteNode(Node* node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::GraphicsQualityChanged(base::GraphicsQuality q) {
|
|
||||||
assert(g_base->InLogicThread());
|
|
||||||
for (auto&& i : nodes_) {
|
|
||||||
i->OnGraphicsQualityChanged(q);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scene::OnScreenSizeChange() {
|
void Scene::OnScreenSizeChange() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
for (auto&& i : nodes_) {
|
for (auto&& i : nodes_) {
|
||||||
|
|||||||
@ -43,7 +43,6 @@ class Scene : public Object {
|
|||||||
void SetMapBounds(float x, float y, float z, float X, float Y, float Z);
|
void SetMapBounds(float x, float y, float z, float X, float Y, float Z);
|
||||||
void OnScreenSizeChange();
|
void OnScreenSizeChange();
|
||||||
void LanguageChanged();
|
void LanguageChanged();
|
||||||
void GraphicsQualityChanged(base::GraphicsQuality q);
|
|
||||||
auto out_of_bounds_nodes() -> const std::vector<Object::WeakRef<Node> >& {
|
auto out_of_bounds_nodes() -> const std::vector<Object::WeakRef<Node> >& {
|
||||||
return out_of_bounds_nodes_;
|
return out_of_bounds_nodes_;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1312,15 +1312,6 @@ void SceneV1AppMode::SetPublicPartyStatsURL(const std::string& url) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneV1AppMode::GraphicsQualityChanged(base::GraphicsQuality quality) {
|
|
||||||
for (auto&& i : sessions_) {
|
|
||||||
if (!i.Exists()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
i->GraphicsQualityChanged(quality);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SceneV1AppMode::SetPublicPartyPlayerCount(int count) {
|
void SceneV1AppMode::SetPublicPartyPlayerCount(int count) {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
if (count == public_party_player_count_) {
|
if (count == public_party_player_count_) {
|
||||||
|
|||||||
@ -172,7 +172,6 @@ class SceneV1AppMode : public base::AppMode {
|
|||||||
sockaddr_storage* from) override;
|
sockaddr_storage* from) override;
|
||||||
void DrawWorld(base::FrameDef* frame_def) override;
|
void DrawWorld(base::FrameDef* frame_def) override;
|
||||||
auto DoesWorldFillScreen() -> bool override;
|
auto DoesWorldFillScreen() -> bool override;
|
||||||
void GraphicsQualityChanged(base::GraphicsQuality quality) override;
|
|
||||||
void RunMainMenu();
|
void RunMainMenu();
|
||||||
|
|
||||||
auto dynamics_sync_time() const { return dynamics_sync_time_; }
|
auto dynamics_sync_time() const { return dynamics_sync_time_; }
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user