mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-03 05:53:15 +08:00
work in progress on apple/android build overhauls
This commit is contained in:
parent
feb010f497
commit
93be4ddcf6
102
.efrocachemap
generated
102
.efrocachemap
generated
@ -1416,10 +1416,10 @@
|
|||||||
"build/assets/ba_data/textures/crossOutMask.pvr": "94110cc4e3e47f81b68f548951a33c2b",
|
"build/assets/ba_data/textures/crossOutMask.pvr": "94110cc4e3e47f81b68f548951a33c2b",
|
||||||
"build/assets/ba_data/textures/crossOutMask_preview.png": "d5df4d494cfbf700e3c8726b3693716c",
|
"build/assets/ba_data/textures/crossOutMask_preview.png": "d5df4d494cfbf700e3c8726b3693716c",
|
||||||
"build/assets/ba_data/textures/crossOut_preview.png": "a0628f1e6b7e9f7d3b73d1c835ec9286",
|
"build/assets/ba_data/textures/crossOut_preview.png": "a0628f1e6b7e9f7d3b73d1c835ec9286",
|
||||||
"build/assets/ba_data/textures/cursor.dds": "575b05e3adc74adf5a5d4b482a54adc9",
|
"build/assets/ba_data/textures/cursor.dds": "4655d0746ba75bcd5f44f47dde9e9fec",
|
||||||
"build/assets/ba_data/textures/cursor.ktx": "56ef6481222c23cbc1ab0fe825f19b03",
|
"build/assets/ba_data/textures/cursor.ktx": "7835afb0579c2ca3a6477314121f49a5",
|
||||||
"build/assets/ba_data/textures/cursor.pvr": "344b8856a315af23f495ebd283ee54fa",
|
"build/assets/ba_data/textures/cursor.pvr": "18803c269b9b544d6c0606d7b9fb2d85",
|
||||||
"build/assets/ba_data/textures/cursor_preview.png": "0f6820abfe6b79b4133971ace8f3bc42",
|
"build/assets/ba_data/textures/cursor_preview.png": "d7189625af474f06f1c953dd41e701a0",
|
||||||
"build/assets/ba_data/textures/cuteSpaz.dds": "5876162f89e558a2220935a1d63493c3",
|
"build/assets/ba_data/textures/cuteSpaz.dds": "5876162f89e558a2220935a1d63493c3",
|
||||||
"build/assets/ba_data/textures/cuteSpaz.ktx": "4a3bc3c1739991298d21a66256289d57",
|
"build/assets/ba_data/textures/cuteSpaz.ktx": "4a3bc3c1739991298d21a66256289d57",
|
||||||
"build/assets/ba_data/textures/cuteSpaz.pvr": "a236803464dc49b61b63a5e83d305c4c",
|
"build/assets/ba_data/textures/cuteSpaz.pvr": "a236803464dc49b61b63a5e83d305c4c",
|
||||||
@ -4056,54 +4056,54 @@
|
|||||||
"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": "6d1f9c2c53c02a35d87bb0aea62f7408",
|
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "f95cb344f9625388ba515653e16a57d0",
|
||||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "cfbf3e80472077cbccc98b681d24e7cd",
|
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "8411e881bd378c7566141fed884e5309",
|
||||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "7af76def8c480e88ddd6257ab4d0dfff",
|
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "eada0564b59414246e3abbf6b24e1075",
|
||||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "6c3372ab5283cbd91362c23a32629ee5",
|
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "db71a3f6b0dde0f08779234e3a282bdc",
|
||||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "80f3683bc192c94a6d1a1dc2137f0844",
|
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "be58bd18ab06b41a841583d861051312",
|
||||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "9fb5cc47cfd4bf4c717acf3877dde233",
|
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "0e2f02f50d73c994be1ca67776508b2a",
|
||||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "095a758aacb5940b793d82dddc142d34",
|
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "ecd907487811de6f2be80b08a59a290a",
|
||||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "f312f5066c8bc883a24b0e3a86884bb3",
|
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "4550688501a83fa07129b4963cee6c35",
|
||||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "b9f8a78b14d439e8ace4c70e18ae9e19",
|
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "49911dd6d771adbef4887054f7acf540",
|
||||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "5a25d4de9c3124822538602fb9273280",
|
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "24c000f2bc084f61947b3995898b5a9c",
|
||||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "7ea84daf12222b10517bf71870b82b53",
|
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "3932fe9e30c54029ea1865b352e1d9cb",
|
||||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "28dba23a69dc1159cf340f899f78f4d9",
|
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "67aed132732ca49751aaa273a331e221",
|
||||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "3b653a753ac0cb919431528908c9cccc",
|
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "e7c86080f4dd6f44785a5d0d73b2a850",
|
||||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "9df409c73fb121b4d5fcd0fde6d4e42f",
|
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "064f456b4aa848a3068821e42a0b79f1",
|
||||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "be64f13a639454d8b82311dcfd6815e0",
|
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "4255d8b6715e5b4736e2e74c704c8351",
|
||||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "f713443831ee2d9f912ca3c5e10201d8",
|
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "3bb13904e2b109bf5b2d0442a2b02eb5",
|
||||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "6135e6256411bf24e44834d3445f94af",
|
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "edd14687dbc36da44c127af32bfa13c9",
|
||||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "e782b975adada7282b5aaa6b1b1b0e1d",
|
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "acd8766e2b7343cae274796b1915d2f1",
|
||||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "142aa10ee8c2747b011ef18062d5de48",
|
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "86ec71be2ef0004ec6c6f1599654adc7",
|
||||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "01d7543c88bf94b9478b261003c5521c",
|
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "c1984c5e329209bca542d098bdc0705e",
|
||||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "dd14e0abacf5a27d9823b0a41127e3e3",
|
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "58946f3534363d88f713c54d3d643d6d",
|
||||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "bd994ca8a1896ada5c582be155db5c36",
|
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "be356d05ecccd68043258d87b1892805",
|
||||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "dd14e0abacf5a27d9823b0a41127e3e3",
|
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "58946f3534363d88f713c54d3d643d6d",
|
||||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "bd994ca8a1896ada5c582be155db5c36",
|
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "be356d05ecccd68043258d87b1892805",
|
||||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "d855693f8342c4080ce0f452784e5cf9",
|
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "bf7d793d62416db7273590a796001cb6",
|
||||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "eeaf4e383752fdcdaaae1cb863208870",
|
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "b309e0cc3ec04024712c4ca938efdb92",
|
||||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "d855693f8342c4080ce0f452784e5cf9",
|
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "bf7d793d62416db7273590a796001cb6",
|
||||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "eeaf4e383752fdcdaaae1cb863208870",
|
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "b309e0cc3ec04024712c4ca938efdb92",
|
||||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "ba391e47cc87b609ea794cdf9e693163",
|
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "a86b09c31abf0b5ec934ef28c8bd9fa3",
|
||||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "84e913835ae280a59045bed189c920b0",
|
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "87be7a2f6e83c495f99024bb68660e17",
|
||||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "ba391e47cc87b609ea794cdf9e693163",
|
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "a86b09c31abf0b5ec934ef28c8bd9fa3",
|
||||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "84e913835ae280a59045bed189c920b0",
|
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "87be7a2f6e83c495f99024bb68660e17",
|
||||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "8f147ca53e6e261becb37d7ff5490b59",
|
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "9fb5d3cb36dd53bd18c7ca831e7c73ee",
|
||||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "7d386ab4fc78cc7598188df82bf4f04a",
|
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "88332859e6e9ee70848f5252e5ee6ce0",
|
||||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "5627e6b08b61024650420b849d41721b",
|
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "55b6db8700acfc573cc3db31c6b210f7",
|
||||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "7d386ab4fc78cc7598188df82bf4f04a",
|
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "88332859e6e9ee70848f5252e5ee6ce0",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "cc3c3f837962636cbcd542b9b54946f2",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "fcfb653b2a8da60f97290e419e9bda9d",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "b6a9ccfc44c215d7f31e985bbc8eab06",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "ef23df71f54e6c7266a710cdfe13b012",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "056a71331f28fbe6a07ae4086e3e8391",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "80598a8db7d98d30b4445eb17a2fc183",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "ae9f5d7069310cb18f7dfc90ad207203",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "9269b604b35896bd4152608ec08cd203",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "b014ca1f2fec594cb149f11d783ee165",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "55a68ea970b1759b228b0f5daab69d1b",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "2085834b3d1523f6e29cd89011d4c062",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "ae6adcbf6e4ac9c9e7f4dbb178cfb9a4",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "aa9fadf3a2410df7b5aca9c88194cfcc",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "75faadb19df40ec9f1e24c38716fa632",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "d6ccc0796e64abab851caac47ce54a86",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "637a6544a45279a075d456a00ea438ae",
|
||||||
"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": "f8cd3af311ac63147882590123b78318",
|
"src/assets/ba_data/python/babase/_mgen/enums.py": "28323912b56ec07701eda3d41a6a4101",
|
||||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "9f71f171464dc004dbaab87e9bb4b03b",
|
"src/ballistica/base/mgen/pyembed/binding_base.inc": "ba8ce3ca3858b4c2d20db68f99b788b2",
|
||||||
"src/ballistica/base/mgen/pyembed/binding_base_app.inc": "a521bc86a7e98e56fec14cea029996f8",
|
"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",
|
||||||
"src/ballistica/core/mgen/pyembed/env.inc": "8be46e5818f360d10b7b0224a9e91d07",
|
"src/ballistica/core/mgen/pyembed/env.inc": "8be46e5818f360d10b7b0224a9e91d07",
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -120,6 +120,7 @@ xcuserdata/
|
|||||||
/ballisticakit-android/BallisticaKit/src/main/res/mipmap-*/ic_launcher*.png
|
/ballisticakit-android/BallisticaKit/src/main/res/mipmap-*/ic_launcher*.png
|
||||||
/ballisticakit-android/BallisticaKit/src/cardboard/res/mipmap-*/ic_launcher*.png
|
/ballisticakit-android/BallisticaKit/src/cardboard/res/mipmap-*/ic_launcher*.png
|
||||||
BallisticaKit.ico
|
BallisticaKit.ico
|
||||||
|
/ballisticakit-xcode/BallisticaKit Shared/Assets.xcassets/Cursor macOS.appiconset/cursor_*.png
|
||||||
/ballisticakit-xcode/BallisticaKit Shared/Assets.xcassets/AppIcon iOS.appiconset/icon_*.png
|
/ballisticakit-xcode/BallisticaKit Shared/Assets.xcassets/AppIcon iOS.appiconset/icon_*.png
|
||||||
/ballisticakit-xcode/BallisticaKit Shared/Assets.xcassets/AppIcon macOS.appiconset/icon_*.png
|
/ballisticakit-xcode/BallisticaKit Shared/Assets.xcassets/AppIcon macOS.appiconset/icon_*.png
|
||||||
/ballisticakit-xcode/BallisticaKit Shared/Assets.xcassets/tvOS App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Layer*.imagestacklayer/Content.imageset/*.png
|
/ballisticakit-xcode/BallisticaKit Shared/Assets.xcassets/tvOS App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Layer*.imagestacklayer/Content.imageset/*.png
|
||||||
|
|||||||
2
.idea/dictionaries/ericf.xml
generated
2
.idea/dictionaries/ericf.xml
generated
@ -3192,6 +3192,8 @@
|
|||||||
<w>unstripped</w>
|
<w>unstripped</w>
|
||||||
<w>unstrl</w>
|
<w>unstrl</w>
|
||||||
<w>unsubscriptable</w>
|
<w>unsubscriptable</w>
|
||||||
|
<w>unsuspend</w>
|
||||||
|
<w>unsuspending</w>
|
||||||
<w>untracked</w>
|
<w>untracked</w>
|
||||||
<w>unwritable</w>
|
<w>unwritable</w>
|
||||||
<w>upcase</w>
|
<w>upcase</w>
|
||||||
|
|||||||
28
CHANGELOG.md
28
CHANGELOG.md
@ -1,4 +1,4 @@
|
|||||||
### 1.7.28 (build 21422, api 8, 2023-10-05)
|
### 1.7.28 (build 21441, api 8, 2023-10-11)
|
||||||
|
|
||||||
- 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
|
||||||
@ -104,6 +104,32 @@
|
|||||||
- Created a custom icon for BallisticaKit (previously it was just the BombSquad
|
- Created a custom icon for BallisticaKit (previously it was just the BombSquad
|
||||||
icon with an ugly 'C' on it). BombSquad itself will still have the BombSquad
|
icon with an ugly 'C' on it). BombSquad itself will still have the BombSquad
|
||||||
icon.
|
icon.
|
||||||
|
- Changed `AppState.NOT_RUNNING` to `AppState.NOT_STARTED` since not-running
|
||||||
|
could be confused with a state such as paused.
|
||||||
|
- Changed the general app-state terms 'pause' and 'resume' to 'suspend' and
|
||||||
|
'unsuspend'. (note this has nothing to do with pausing in the game which is
|
||||||
|
still called pausing). The suspend state is used by mobile versions when
|
||||||
|
backgrounded and basically stops all activity in the app. I may later add
|
||||||
|
another state called 'paused' for when the app is still running but there is
|
||||||
|
an OS dialog or ad or something in front of it. Though perhaps another term
|
||||||
|
would be better to avoid confusion with the act of pausing in the game
|
||||||
|
('inactive' maybe?).
|
||||||
|
- Fixed an issue that could cause a few seconds delay when shutting down if
|
||||||
|
internet access is unavailable.
|
||||||
|
- Generalized the UI system to accept a delegate object, of which UIV1 is now
|
||||||
|
one. In the future this will allow plugging in UIV2 instead or other UI
|
||||||
|
systems.
|
||||||
|
- Headless builds now plug in *no* ui delegate instead of UIV1, so one must
|
||||||
|
avoid calling UI code from servers now. This should reduce server resource
|
||||||
|
usage a bit. Please holler if this causes non-trivial problems. In general,
|
||||||
|
code that brings up UI from gameplay contexts should check the value of
|
||||||
|
`ba.app.env.headless` and avoid doing so when that is True.
|
||||||
|
- Cleaned up quit behavior a bit more. The `babase.quit()` call now takes a
|
||||||
|
single `babase.QuitType` enum instead of the multiple bool options it took
|
||||||
|
before. It also takes a `confirm` bool arg which allows it to be used to bring
|
||||||
|
up a confirm dialog.
|
||||||
|
- Clicking on a window close button to quit no longer brings up a confirm dialog
|
||||||
|
and instead quits immediately (though with a proper graceful shutdown).
|
||||||
|
|
||||||
### 1.7.27 (build 21282, api 8, 2023-08-30)
|
### 1.7.27 (build 21282, api 8, 2023-08-30)
|
||||||
|
|
||||||
|
|||||||
2
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
2
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
@ -1876,6 +1876,8 @@
|
|||||||
<w>unpremultiply</w>
|
<w>unpremultiply</w>
|
||||||
<w>unsignaled</w>
|
<w>unsignaled</w>
|
||||||
<w>unstuff</w>
|
<w>unstuff</w>
|
||||||
|
<w>unsuspend</w>
|
||||||
|
<w>unsuspending</w>
|
||||||
<w>unsynchronized</w>
|
<w>unsynchronized</w>
|
||||||
<w>unwritable</w>
|
<w>unwritable</w>
|
||||||
<w>uppercased</w>
|
<w>uppercased</w>
|
||||||
|
|||||||
@ -442,11 +442,11 @@ set(BALLISTICA_SOURCES
|
|||||||
${BA_SRC_ROOT}/ballistica/base/support/stdio_console.h
|
${BA_SRC_ROOT}/ballistica/base/support/stdio_console.h
|
||||||
${BA_SRC_ROOT}/ballistica/base/support/stress_test.cc
|
${BA_SRC_ROOT}/ballistica/base/support/stress_test.cc
|
||||||
${BA_SRC_ROOT}/ballistica/base/support/stress_test.h
|
${BA_SRC_ROOT}/ballistica/base/support/stress_test.h
|
||||||
${BA_SRC_ROOT}/ballistica/base/support/ui_v1_soft.h
|
|
||||||
${BA_SRC_ROOT}/ballistica/base/ui/dev_console.cc
|
${BA_SRC_ROOT}/ballistica/base/ui/dev_console.cc
|
||||||
${BA_SRC_ROOT}/ballistica/base/ui/dev_console.h
|
${BA_SRC_ROOT}/ballistica/base/ui/dev_console.h
|
||||||
${BA_SRC_ROOT}/ballistica/base/ui/ui.cc
|
${BA_SRC_ROOT}/ballistica/base/ui/ui.cc
|
||||||
${BA_SRC_ROOT}/ballistica/base/ui/ui.h
|
${BA_SRC_ROOT}/ballistica/base/ui/ui.h
|
||||||
|
${BA_SRC_ROOT}/ballistica/base/ui/ui_delegate.h
|
||||||
${BA_SRC_ROOT}/ballistica/base/ui/widget_message.h
|
${BA_SRC_ROOT}/ballistica/base/ui/widget_message.h
|
||||||
${BA_SRC_ROOT}/ballistica/classic/classic.cc
|
${BA_SRC_ROOT}/ballistica/classic/classic.cc
|
||||||
${BA_SRC_ROOT}/ballistica/classic/classic.h
|
${BA_SRC_ROOT}/ballistica/classic/classic.h
|
||||||
|
|||||||
@ -148,7 +148,7 @@
|
|||||||
<ExceptionHandling>SyncCThrow</ExceptionHandling>
|
<ExceptionHandling>SyncCThrow</ExceptionHandling>
|
||||||
<SDLCheck>false</SDLCheck>
|
<SDLCheck>false</SDLCheck>
|
||||||
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||||
<FloatingPointModel>Fast</FloatingPointModel>
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@ -173,7 +173,7 @@
|
|||||||
<ExceptionHandling>SyncCThrow</ExceptionHandling>
|
<ExceptionHandling>SyncCThrow</ExceptionHandling>
|
||||||
<SDLCheck>false</SDLCheck>
|
<SDLCheck>false</SDLCheck>
|
||||||
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||||
<FloatingPointModel>Fast</FloatingPointModel>
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@ -434,11 +434,11 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\base\support\stdio_console.h" />
|
<ClInclude Include="..\..\src\ballistica\base\support\stdio_console.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\base\support\stress_test.cc" />
|
<ClCompile Include="..\..\src\ballistica\base\support\stress_test.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\support\stress_test.h" />
|
<ClInclude Include="..\..\src\ballistica\base\support\stress_test.h" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\support\ui_v1_soft.h" />
|
|
||||||
<ClCompile Include="..\..\src\ballistica\base\ui\dev_console.cc" />
|
<ClCompile Include="..\..\src\ballistica\base\ui\dev_console.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\ui\dev_console.h" />
|
<ClInclude Include="..\..\src\ballistica\base\ui\dev_console.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\base\ui\ui.cc" />
|
<ClCompile Include="..\..\src\ballistica\base\ui\ui.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\ui\ui.h" />
|
<ClInclude Include="..\..\src\ballistica\base\ui\ui.h" />
|
||||||
|
<ClInclude Include="..\..\src\ballistica\base\ui\ui_delegate.h" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\ui\widget_message.h" />
|
<ClInclude Include="..\..\src\ballistica\base\ui\widget_message.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\classic\classic.cc" />
|
<ClCompile Include="..\..\src\ballistica\classic\classic.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\classic\classic.h" />
|
<ClInclude Include="..\..\src\ballistica\classic\classic.h" />
|
||||||
|
|||||||
@ -736,9 +736,6 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\base\support\stress_test.h">
|
<ClInclude Include="..\..\src\ballistica\base\support\stress_test.h">
|
||||||
<Filter>ballistica\base\support</Filter>
|
<Filter>ballistica\base\support</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ballistica\base\support\ui_v1_soft.h">
|
|
||||||
<Filter>ballistica\base\support</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ballistica\base\ui\dev_console.cc">
|
<ClCompile Include="..\..\src\ballistica\base\ui\dev_console.cc">
|
||||||
<Filter>ballistica\base\ui</Filter>
|
<Filter>ballistica\base\ui</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -751,6 +748,9 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\base\ui\ui.h">
|
<ClInclude Include="..\..\src\ballistica\base\ui\ui.h">
|
||||||
<Filter>ballistica\base\ui</Filter>
|
<Filter>ballistica\base\ui</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ballistica\base\ui\ui_delegate.h">
|
||||||
|
<Filter>ballistica\base\ui</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ballistica\base\ui\widget_message.h">
|
<ClInclude Include="..\..\src\ballistica\base\ui\widget_message.h">
|
||||||
<Filter>ballistica\base\ui</Filter>
|
<Filter>ballistica\base\ui</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|||||||
@ -145,7 +145,7 @@
|
|||||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||||
<ExceptionHandling>SyncCThrow</ExceptionHandling>
|
<ExceptionHandling>SyncCThrow</ExceptionHandling>
|
||||||
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||||
<FloatingPointModel>Fast</FloatingPointModel>
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@ -169,7 +169,7 @@
|
|||||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||||
<FloatingPointModel>Fast</FloatingPointModel>
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@ -429,11 +429,11 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\base\support\stdio_console.h" />
|
<ClInclude Include="..\..\src\ballistica\base\support\stdio_console.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\base\support\stress_test.cc" />
|
<ClCompile Include="..\..\src\ballistica\base\support\stress_test.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\support\stress_test.h" />
|
<ClInclude Include="..\..\src\ballistica\base\support\stress_test.h" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\support\ui_v1_soft.h" />
|
|
||||||
<ClCompile Include="..\..\src\ballistica\base\ui\dev_console.cc" />
|
<ClCompile Include="..\..\src\ballistica\base\ui\dev_console.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\ui\dev_console.h" />
|
<ClInclude Include="..\..\src\ballistica\base\ui\dev_console.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\base\ui\ui.cc" />
|
<ClCompile Include="..\..\src\ballistica\base\ui\ui.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\ui\ui.h" />
|
<ClInclude Include="..\..\src\ballistica\base\ui\ui.h" />
|
||||||
|
<ClInclude Include="..\..\src\ballistica\base\ui\ui_delegate.h" />
|
||||||
<ClInclude Include="..\..\src\ballistica\base\ui\widget_message.h" />
|
<ClInclude Include="..\..\src\ballistica\base\ui\widget_message.h" />
|
||||||
<ClCompile Include="..\..\src\ballistica\classic\classic.cc" />
|
<ClCompile Include="..\..\src\ballistica\classic\classic.cc" />
|
||||||
<ClInclude Include="..\..\src\ballistica\classic\classic.h" />
|
<ClInclude Include="..\..\src\ballistica\classic\classic.h" />
|
||||||
|
|||||||
@ -736,9 +736,6 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\base\support\stress_test.h">
|
<ClInclude Include="..\..\src\ballistica\base\support\stress_test.h">
|
||||||
<Filter>ballistica\base\support</Filter>
|
<Filter>ballistica\base\support</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ballistica\base\support\ui_v1_soft.h">
|
|
||||||
<Filter>ballistica\base\support</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ballistica\base\ui\dev_console.cc">
|
<ClCompile Include="..\..\src\ballistica\base\ui\dev_console.cc">
|
||||||
<Filter>ballistica\base\ui</Filter>
|
<Filter>ballistica\base\ui</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -751,6 +748,9 @@
|
|||||||
<ClInclude Include="..\..\src\ballistica\base\ui\ui.h">
|
<ClInclude Include="..\..\src\ballistica\base\ui\ui.h">
|
||||||
<Filter>ballistica\base\ui</Filter>
|
<Filter>ballistica\base\ui</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ballistica\base\ui\ui_delegate.h">
|
||||||
|
<Filter>ballistica\base\ui</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ballistica\base\ui\widget_message.h">
|
<ClInclude Include="..\..\src\ballistica\base\ui\widget_message.h">
|
||||||
<Filter>ballistica\base\ui</Filter>
|
<Filter>ballistica\base\ui</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|||||||
@ -162,6 +162,7 @@ from babase._mgen.enums import (
|
|||||||
SpecialChar,
|
SpecialChar,
|
||||||
InputType,
|
InputType,
|
||||||
UIScale,
|
UIScale,
|
||||||
|
QuitType,
|
||||||
)
|
)
|
||||||
from babase._math import normalized_color, is_point_in_box, vec3validate
|
from babase._math import normalized_color, is_point_in_box, vec3validate
|
||||||
from babase._meta import MetadataSubsystem
|
from babase._meta import MetadataSubsystem
|
||||||
@ -286,6 +287,7 @@ __all__ = [
|
|||||||
'print_load_info',
|
'print_load_info',
|
||||||
'pushcall',
|
'pushcall',
|
||||||
'quit',
|
'quit',
|
||||||
|
'QuitType',
|
||||||
'reload_media',
|
'reload_media',
|
||||||
'request_permission',
|
'request_permission',
|
||||||
'safecolor',
|
'safecolor',
|
||||||
|
|||||||
@ -70,7 +70,7 @@ class App:
|
|||||||
|
|
||||||
# The app has not yet begun starting and should not be used in
|
# The app has not yet begun starting and should not be used in
|
||||||
# any way.
|
# any way.
|
||||||
NOT_RUNNING = 0
|
NOT_STARTED = 0
|
||||||
|
|
||||||
# The native layer is spinning up its machinery (screens,
|
# The native layer is spinning up its machinery (screens,
|
||||||
# renderers, etc.). Nothing should happen in the Python layer
|
# renderers, etc.). Nothing should happen in the Python layer
|
||||||
@ -90,13 +90,23 @@ class App:
|
|||||||
# All pieces are in place and the app is now doing its thing.
|
# All pieces are in place and the app is now doing its thing.
|
||||||
RUNNING = 4
|
RUNNING = 4
|
||||||
|
|
||||||
# The app is backgrounded or otherwise suspended.
|
# Used on platforms such as mobile where the app basically needs
|
||||||
PAUSED = 5
|
# to shut down while backgrounded. In this state, all event
|
||||||
|
# loops are suspended and all graphics and audio should cease
|
||||||
|
# completely. Be aware that the suspended state can be entered
|
||||||
|
# from any other state including NATIVE_BOOTSTRAPPING and
|
||||||
|
# SHUTTING_DOWN.
|
||||||
|
SUSPENDED = 5
|
||||||
|
|
||||||
# The app is shutting down.
|
# The app is shutting down. This process may involve sending
|
||||||
|
# network messages or other things that can take up to a few
|
||||||
|
# seconds, so ideally graphics and audio should remain
|
||||||
|
# functional (with fades or spinners or whatever to show
|
||||||
|
# something is happening).
|
||||||
SHUTTING_DOWN = 6
|
SHUTTING_DOWN = 6
|
||||||
|
|
||||||
# The app has completed shutdown.
|
# The app has completed shutdown. Any code running here should
|
||||||
|
# be basically immediate.
|
||||||
SHUTDOWN_COMPLETE = 7
|
SHUTDOWN_COMPLETE = 7
|
||||||
|
|
||||||
class DefaultAppModeSelector(AppModeSelector):
|
class DefaultAppModeSelector(AppModeSelector):
|
||||||
@ -150,7 +160,7 @@ class App:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.env: babase.Env = _babase.Env()
|
self.env: babase.Env = _babase.Env()
|
||||||
self.state = self.State.NOT_RUNNING
|
self.state = self.State.NOT_STARTED
|
||||||
|
|
||||||
# Default executor which can be used for misc background
|
# Default executor which can be used for misc background
|
||||||
# processing. It should also be passed to any additional asyncio
|
# processing. It should also be passed to any additional asyncio
|
||||||
@ -179,7 +189,7 @@ class App:
|
|||||||
self._init_completed = False
|
self._init_completed = False
|
||||||
self._meta_scan_completed = False
|
self._meta_scan_completed = False
|
||||||
self._native_start_called = False
|
self._native_start_called = False
|
||||||
self._native_paused = False
|
self._native_suspended = False
|
||||||
self._native_shutdown_called = False
|
self._native_shutdown_called = False
|
||||||
self._native_shutdown_complete_called = False
|
self._native_shutdown_complete_called = False
|
||||||
self._initial_sign_in_completed = False
|
self._initial_sign_in_completed = False
|
||||||
@ -197,7 +207,8 @@ class App:
|
|||||||
self._mode_selector: babase.AppModeSelector | None = None
|
self._mode_selector: babase.AppModeSelector | None = None
|
||||||
self._shutdown_task: asyncio.Task[None] | None = None
|
self._shutdown_task: asyncio.Task[None] | None = None
|
||||||
self._shutdown_tasks: list[Coroutine[None, None, None]] = [
|
self._shutdown_tasks: list[Coroutine[None, None, None]] = [
|
||||||
self._wait_for_shutdown_suppressions()
|
self._wait_for_shutdown_suppressions(),
|
||||||
|
self._fade_for_shutdown(),
|
||||||
]
|
]
|
||||||
self._pool_thread_count = 0
|
self._pool_thread_count = 0
|
||||||
|
|
||||||
@ -315,7 +326,7 @@ class App:
|
|||||||
def add_shutdown_task(self, coro: Coroutine[None, None, None]) -> None:
|
def add_shutdown_task(self, coro: Coroutine[None, None, None]) -> None:
|
||||||
"""Add a task to be run on app shutdown.
|
"""Add a task to be run on app shutdown.
|
||||||
|
|
||||||
Note that tasks will be killed after
|
Note that shutdown tasks will be canceled after
|
||||||
App.SHUTDOWN_TASK_TIMEOUT_SECONDS if they are still running.
|
App.SHUTDOWN_TASK_TIMEOUT_SECONDS if they are still running.
|
||||||
"""
|
"""
|
||||||
if (
|
if (
|
||||||
@ -389,18 +400,18 @@ class App:
|
|||||||
self._native_bootstrapping_completed = True
|
self._native_bootstrapping_completed = True
|
||||||
self._update_state()
|
self._update_state()
|
||||||
|
|
||||||
def on_native_pause(self) -> None:
|
def on_native_suspend(self) -> None:
|
||||||
"""Called by the native layer when the app pauses."""
|
"""Called by the native layer when the app is suspended."""
|
||||||
assert _babase.in_logic_thread()
|
assert _babase.in_logic_thread()
|
||||||
assert not self._native_paused # Should avoid redundant calls.
|
assert not self._native_suspended # Should avoid redundant calls.
|
||||||
self._native_paused = True
|
self._native_suspended = True
|
||||||
self._update_state()
|
self._update_state()
|
||||||
|
|
||||||
def on_native_resume(self) -> None:
|
def on_native_unsuspend(self) -> None:
|
||||||
"""Called by the native layer when the app resumes."""
|
"""Called by the native layer when the app suspension ends."""
|
||||||
assert _babase.in_logic_thread()
|
assert _babase.in_logic_thread()
|
||||||
assert self._native_paused # Should avoid redundant calls.
|
assert self._native_suspended # Should avoid redundant calls.
|
||||||
self._native_paused = False
|
self._native_suspended = False
|
||||||
self._update_state()
|
self._update_state()
|
||||||
|
|
||||||
def on_native_shutdown(self) -> None:
|
def on_native_shutdown(self) -> None:
|
||||||
@ -730,15 +741,15 @@ class App:
|
|||||||
_babase.lifecyclelog('app state shutting down')
|
_babase.lifecyclelog('app state shutting down')
|
||||||
self._on_shutting_down()
|
self._on_shutting_down()
|
||||||
|
|
||||||
elif self._native_paused:
|
elif self._native_suspended:
|
||||||
# Entering paused state:
|
# Entering suspended state:
|
||||||
if self.state is not self.State.PAUSED:
|
if self.state is not self.State.SUSPENDED:
|
||||||
self.state = self.State.PAUSED
|
self.state = self.State.SUSPENDED
|
||||||
self._on_pause()
|
self._on_suspend()
|
||||||
else:
|
else:
|
||||||
# Leaving paused state:
|
# Leaving suspended state:
|
||||||
if self.state is self.State.PAUSED:
|
if self.state is self.State.SUSPENDED:
|
||||||
self._on_resume()
|
self._on_unsuspend()
|
||||||
|
|
||||||
# Entering or returning to running state
|
# Entering or returning to running state
|
||||||
if self._initial_sign_in_completed and self._meta_scan_completed:
|
if self._initial_sign_in_completed and self._meta_scan_completed:
|
||||||
@ -772,7 +783,7 @@ class App:
|
|||||||
self.state = self.State.NATIVE_BOOTSTRAPPING
|
self.state = self.State.NATIVE_BOOTSTRAPPING
|
||||||
_babase.lifecyclelog('app state native bootstrapping')
|
_babase.lifecyclelog('app state native bootstrapping')
|
||||||
else:
|
else:
|
||||||
# Only logical possibility left is NOT_RUNNING, in which
|
# Only logical possibility left is NOT_STARTED, in which
|
||||||
# case we should not be getting called.
|
# case we should not be getting called.
|
||||||
logging.warning(
|
logging.warning(
|
||||||
'App._update_state called while in %s state;'
|
'App._update_state called while in %s state;'
|
||||||
@ -813,33 +824,33 @@ class App:
|
|||||||
try:
|
try:
|
||||||
await asyncio.wait_for(task, self.SHUTDOWN_TASK_TIMEOUT_SECONDS)
|
await asyncio.wait_for(task, self.SHUTDOWN_TASK_TIMEOUT_SECONDS)
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.exception('Error in shutdown task.')
|
logging.exception('Error in shutdown task (%s).', coro)
|
||||||
|
|
||||||
def _on_pause(self) -> None:
|
def _on_suspend(self) -> None:
|
||||||
"""Called when the app goes to a paused state."""
|
"""Called when the app goes to a suspended state."""
|
||||||
assert _babase.in_logic_thread()
|
assert _babase.in_logic_thread()
|
||||||
|
|
||||||
# Pause all app subsystems in the opposite order they were inited.
|
# Suspend all app subsystems in the opposite order they were inited.
|
||||||
for subsystem in reversed(self._subsystems):
|
for subsystem in reversed(self._subsystems):
|
||||||
try:
|
try:
|
||||||
subsystem.on_app_pause()
|
subsystem.on_app_suspend()
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.exception(
|
logging.exception(
|
||||||
'Error in on_app_pause for subsystem %s.', subsystem
|
'Error in on_app_suspend for subsystem %s.', subsystem
|
||||||
)
|
)
|
||||||
|
|
||||||
def _on_resume(self) -> None:
|
def _on_unsuspend(self) -> None:
|
||||||
"""Called when resuming."""
|
"""Called when unsuspending."""
|
||||||
assert _babase.in_logic_thread()
|
assert _babase.in_logic_thread()
|
||||||
self.fg_state += 1
|
self.fg_state += 1
|
||||||
|
|
||||||
# Resume all app subsystems in the same order they were inited.
|
# Unsuspend all app subsystems in the same order they were inited.
|
||||||
for subsystem in self._subsystems:
|
for subsystem in self._subsystems:
|
||||||
try:
|
try:
|
||||||
subsystem.on_app_resume()
|
subsystem.on_app_unsuspend()
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.exception(
|
logging.exception(
|
||||||
'Error in on_app_resume for subsystem %s.', subsystem
|
'Error in on_app_unsuspend for subsystem %s.', subsystem
|
||||||
)
|
)
|
||||||
|
|
||||||
def _on_shutting_down(self) -> None:
|
def _on_shutting_down(self) -> None:
|
||||||
@ -884,6 +895,19 @@ class App:
|
|||||||
await asyncio.sleep(0.001)
|
await asyncio.sleep(0.001)
|
||||||
_babase.lifecyclelog('shutdown-suppress wait end')
|
_babase.lifecyclelog('shutdown-suppress wait end')
|
||||||
|
|
||||||
|
async def _fade_for_shutdown(self) -> None:
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
# Kick off a fade, block input, and wait for a short bit.
|
||||||
|
# Ideally most shutdown activity completes during the fade so
|
||||||
|
# there's no tangible wait.
|
||||||
|
_babase.lifecyclelog('fade-for-shutdown begin')
|
||||||
|
_babase.fade_screen(False, time=0.15)
|
||||||
|
_babase.lock_all_input()
|
||||||
|
# _babase.getsimplesound('swish2').play()
|
||||||
|
await asyncio.sleep(0.15)
|
||||||
|
_babase.lifecyclelog('fade-for-shutdown end')
|
||||||
|
|
||||||
def _threadpool_no_wait_done(self, fut: Future) -> None:
|
def _threadpool_no_wait_done(self, fut: Future) -> None:
|
||||||
try:
|
try:
|
||||||
fut.result()
|
fut.result()
|
||||||
|
|||||||
@ -39,10 +39,10 @@ class AppSubsystem:
|
|||||||
def on_app_running(self) -> None:
|
def on_app_running(self) -> None:
|
||||||
"""Called when the app reaches the running state."""
|
"""Called when the app reaches the running state."""
|
||||||
|
|
||||||
def on_app_pause(self) -> None:
|
def on_app_suspend(self) -> None:
|
||||||
"""Called when the app enters the paused state."""
|
"""Called when the app enters the paused state."""
|
||||||
|
|
||||||
def on_app_resume(self) -> None:
|
def on_app_unsuspend(self) -> None:
|
||||||
"""Called when the app exits the paused state."""
|
"""Called when the app exits the paused state."""
|
||||||
|
|
||||||
def on_app_shutdown(self) -> None:
|
def on_app_shutdown(self) -> None:
|
||||||
|
|||||||
@ -64,7 +64,9 @@ def get_remote_app_name() -> babase.Lstr:
|
|||||||
|
|
||||||
def should_submit_debug_info() -> bool:
|
def should_submit_debug_info() -> bool:
|
||||||
"""(internal)"""
|
"""(internal)"""
|
||||||
return _babase.app.config.get('Submit Debug Info', True)
|
val = _babase.app.config.get('Submit Debug Info', True)
|
||||||
|
assert isinstance(val, bool)
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
def handle_v1_cloud_log() -> None:
|
def handle_v1_cloud_log() -> None:
|
||||||
@ -442,10 +444,10 @@ class AppHealthMonitor(AppSubsystem):
|
|||||||
|
|
||||||
self._first_check = False
|
self._first_check = False
|
||||||
|
|
||||||
def on_app_pause(self) -> None:
|
def on_app_suspend(self) -> None:
|
||||||
assert _babase.in_logic_thread()
|
assert _babase.in_logic_thread()
|
||||||
self._running = False
|
self._running = False
|
||||||
|
|
||||||
def on_app_resume(self) -> None:
|
def on_app_unsuspend(self) -> None:
|
||||||
assert _babase.in_logic_thread()
|
assert _babase.in_logic_thread()
|
||||||
self._running = True
|
self._running = True
|
||||||
|
|||||||
@ -170,23 +170,23 @@ class PluginSubsystem(AppSubsystem):
|
|||||||
|
|
||||||
_error.print_exception('Error in plugin on_app_running()')
|
_error.print_exception('Error in plugin on_app_running()')
|
||||||
|
|
||||||
def on_app_pause(self) -> None:
|
def on_app_suspend(self) -> None:
|
||||||
for plugin in self.active_plugins:
|
for plugin in self.active_plugins:
|
||||||
try:
|
try:
|
||||||
plugin.on_app_pause()
|
plugin.on_app_suspend()
|
||||||
except Exception:
|
except Exception:
|
||||||
from babase import _error
|
from babase import _error
|
||||||
|
|
||||||
_error.print_exception('Error in plugin on_app_pause()')
|
_error.print_exception('Error in plugin on_app_suspend()')
|
||||||
|
|
||||||
def on_app_resume(self) -> None:
|
def on_app_unsuspend(self) -> None:
|
||||||
for plugin in self.active_plugins:
|
for plugin in self.active_plugins:
|
||||||
try:
|
try:
|
||||||
plugin.on_app_resume()
|
plugin.on_app_unsuspend()
|
||||||
except Exception:
|
except Exception:
|
||||||
from babase import _error
|
from babase import _error
|
||||||
|
|
||||||
_error.print_exception('Error in plugin on_app_resume()')
|
_error.print_exception('Error in plugin on_app_unsuspend()')
|
||||||
|
|
||||||
def on_app_shutdown(self) -> None:
|
def on_app_shutdown(self) -> None:
|
||||||
for plugin in self.active_plugins:
|
for plugin in self.active_plugins:
|
||||||
@ -327,11 +327,11 @@ class Plugin:
|
|||||||
def on_app_running(self) -> None:
|
def on_app_running(self) -> None:
|
||||||
"""Called when the app reaches the running state."""
|
"""Called when the app reaches the running state."""
|
||||||
|
|
||||||
def on_app_pause(self) -> None:
|
def on_app_suspend(self) -> None:
|
||||||
"""Called when the app is switching to a paused state."""
|
"""Called when the app enters the suspended state."""
|
||||||
|
|
||||||
def on_app_resume(self) -> None:
|
def on_app_unsuspend(self) -> None:
|
||||||
"""Called when the app is resuming from a paused state."""
|
"""Called when the app exits the suspended state."""
|
||||||
|
|
||||||
def on_app_shutdown(self) -> None:
|
def on_app_shutdown(self) -> None:
|
||||||
"""Called when the app is beginning the shutdown process."""
|
"""Called when the app is beginning the shutdown process."""
|
||||||
|
|||||||
@ -49,10 +49,10 @@ class AccountV1Subsystem:
|
|||||||
|
|
||||||
babase.pushcall(do_auto_sign_in)
|
babase.pushcall(do_auto_sign_in)
|
||||||
|
|
||||||
def on_app_pause(self) -> None:
|
def on_app_suspend(self) -> None:
|
||||||
"""Should be called when app is pausing."""
|
"""Should be called when app is pausing."""
|
||||||
|
|
||||||
def on_app_resume(self) -> None:
|
def on_app_unsuspend(self) -> None:
|
||||||
"""Should be called when the app is resumed."""
|
"""Should be called when the app is resumed."""
|
||||||
|
|
||||||
# Mark our cached tourneys as invalid so anyone using them knows
|
# Mark our cached tourneys as invalid so anyone using them knows
|
||||||
|
|||||||
@ -239,7 +239,7 @@ class MusicSubsystem:
|
|||||||
logging.exception('Error in get_soundtrack_entry_name.')
|
logging.exception('Error in get_soundtrack_entry_name.')
|
||||||
return 'default'
|
return 'default'
|
||||||
|
|
||||||
def on_app_resume(self) -> None:
|
def on_app_unsuspend(self) -> None:
|
||||||
"""Should be run when the app resumes from a suspended state."""
|
"""Should be run when the app resumes from a suspended state."""
|
||||||
if babase.is_os_playing_music():
|
if babase.is_os_playing_music():
|
||||||
self.do_play_music(None)
|
self.do_play_music(None)
|
||||||
|
|||||||
@ -229,12 +229,12 @@ class ClassicSubsystem(babase.AppSubsystem):
|
|||||||
|
|
||||||
self.accounts.on_app_loading()
|
self.accounts.on_app_loading()
|
||||||
|
|
||||||
def on_app_pause(self) -> None:
|
def on_app_suspend(self) -> None:
|
||||||
self.accounts.on_app_pause()
|
self.accounts.on_app_suspend()
|
||||||
|
|
||||||
def on_app_resume(self) -> None:
|
def on_app_unsuspend(self) -> None:
|
||||||
self.accounts.on_app_resume()
|
self.accounts.on_app_unsuspend()
|
||||||
self.music.on_app_resume()
|
self.music.on_app_unsuspend()
|
||||||
|
|
||||||
def on_app_shutdown(self) -> None:
|
def on_app_shutdown(self) -> None:
|
||||||
self.music.on_app_shutdown()
|
self.music.on_app_shutdown()
|
||||||
@ -701,11 +701,11 @@ class ClassicSubsystem(babase.AppSubsystem):
|
|||||||
|
|
||||||
ShowURLWindow(address)
|
ShowURLWindow(address)
|
||||||
|
|
||||||
def quit_window(self) -> None:
|
def quit_window(self, quit_type: babase.QuitType) -> None:
|
||||||
"""(internal)"""
|
"""(internal)"""
|
||||||
from bauiv1lib.confirm import QuitWindow
|
from bauiv1lib.confirm import QuitWindow
|
||||||
|
|
||||||
QuitWindow()
|
QuitWindow(quit_type)
|
||||||
|
|
||||||
def tournament_entry_window(
|
def tournament_entry_window(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@ -52,7 +52,7 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
# 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 = 21422
|
TARGET_BALLISTICA_BUILD = 21441
|
||||||
TARGET_BALLISTICA_VERSION = '1.7.28'
|
TARGET_BALLISTICA_VERSION = '1.7.28'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -87,7 +87,9 @@ class Campaign:
|
|||||||
|
|
||||||
def get_selected_level(self) -> str:
|
def get_selected_level(self) -> str:
|
||||||
"""Return the name of the Level currently selected in the UI."""
|
"""Return the name of the Level currently selected in the UI."""
|
||||||
return self.configdict.get('Selection', self._levels[0].name)
|
val = self.configdict.get('Selection', self._levels[0].name)
|
||||||
|
assert isinstance(val, str)
|
||||||
|
return val
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def configdict(self) -> dict[str, Any]:
|
def configdict(self) -> dict[str, Any]:
|
||||||
|
|||||||
@ -105,7 +105,9 @@ class Level:
|
|||||||
def complete(self) -> bool:
|
def complete(self) -> bool:
|
||||||
"""Whether this Level has been completed."""
|
"""Whether this Level has been completed."""
|
||||||
config = self._get_config_dict()
|
config = self._get_config_dict()
|
||||||
return config.get('Complete', False)
|
val = config.get('Complete', False)
|
||||||
|
assert isinstance(val, bool)
|
||||||
|
return val
|
||||||
|
|
||||||
def set_complete(self, val: bool) -> None:
|
def set_complete(self, val: bool) -> None:
|
||||||
"""Set whether or not this level is complete."""
|
"""Set whether or not this level is complete."""
|
||||||
@ -147,7 +149,9 @@ class Level:
|
|||||||
@property
|
@property
|
||||||
def rating(self) -> float:
|
def rating(self) -> float:
|
||||||
"""The current rating for this Level."""
|
"""The current rating for this Level."""
|
||||||
return self._get_config_dict().get('Rating', 0.0)
|
val = self._get_config_dict().get('Rating', 0.0)
|
||||||
|
assert isinstance(val, float)
|
||||||
|
return val
|
||||||
|
|
||||||
def set_rating(self, rating: float) -> None:
|
def set_rating(self, rating: float) -> None:
|
||||||
"""Set a rating for this Level, replacing the old ONLY IF higher."""
|
"""Set a rating for this Level, replacing the old ONLY IF higher."""
|
||||||
|
|||||||
@ -162,8 +162,11 @@ class MultiTeamSession(Session):
|
|||||||
def get_max_players(self) -> int:
|
def get_max_players(self) -> int:
|
||||||
"""Return max number of Players allowed to join the game at once."""
|
"""Return max number of Players allowed to join the game at once."""
|
||||||
if self.use_teams:
|
if self.use_teams:
|
||||||
return babase.app.config.get('Team Game Max Players', 8)
|
val = babase.app.config.get('Team Game Max Players', 8)
|
||||||
return babase.app.config.get('Free-for-All Max Players', 8)
|
else:
|
||||||
|
val = babase.app.config.get('Free-for-All Max Players', 8)
|
||||||
|
assert isinstance(val, int)
|
||||||
|
return val
|
||||||
|
|
||||||
def _instantiate_next_game(self) -> None:
|
def _instantiate_next_game(self) -> None:
|
||||||
self._next_game_instance = _bascenev1.newactivity(
|
self._next_game_instance = _bascenev1.newactivity(
|
||||||
|
|||||||
@ -14,13 +14,12 @@ from bascenev1lib.actor.flag import Flag
|
|||||||
from bascenev1lib.actor.scoreboard import Scoreboard
|
from bascenev1lib.actor.scoreboard import Scoreboard
|
||||||
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
from bascenev1lib.actor.playerspaz import PlayerSpaz
|
||||||
from bascenev1lib.gameutils import SharedObjects
|
from bascenev1lib.gameutils import SharedObjects
|
||||||
|
from bascenev1lib.actor.respawnicon import RespawnIcon
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Any, Sequence
|
from typing import Any, Sequence
|
||||||
|
|
||||||
from bascenev1lib.actor.respawnicon import RespawnIcon
|
|
||||||
|
|
||||||
|
|
||||||
class ConquestFlag(Flag):
|
class ConquestFlag(Flag):
|
||||||
"""A custom flag for use with Conquest games."""
|
"""A custom flag for use with Conquest games."""
|
||||||
@ -49,7 +48,9 @@ class Player(bs.Player['Team']):
|
|||||||
@property
|
@property
|
||||||
def respawn_timer(self) -> bs.Timer | None:
|
def respawn_timer(self) -> bs.Timer | None:
|
||||||
"""Type safe access to standard respawn timer."""
|
"""Type safe access to standard respawn timer."""
|
||||||
return self.customdata.get('respawn_timer', None)
|
val = self.customdata.get('respawn_timer', None)
|
||||||
|
assert isinstance(val, (bs.Timer, type(None)))
|
||||||
|
return val
|
||||||
|
|
||||||
@respawn_timer.setter
|
@respawn_timer.setter
|
||||||
def respawn_timer(self, value: bs.Timer | None) -> None:
|
def respawn_timer(self, value: bs.Timer | None) -> None:
|
||||||
@ -58,7 +59,9 @@ class Player(bs.Player['Team']):
|
|||||||
@property
|
@property
|
||||||
def respawn_icon(self) -> RespawnIcon | None:
|
def respawn_icon(self) -> RespawnIcon | None:
|
||||||
"""Type safe access to standard respawn icon."""
|
"""Type safe access to standard respawn icon."""
|
||||||
return self.customdata.get('respawn_icon', None)
|
val = self.customdata.get('respawn_icon', None)
|
||||||
|
assert isinstance(val, (RespawnIcon, type(None)))
|
||||||
|
return val
|
||||||
|
|
||||||
@respawn_icon.setter
|
@respawn_icon.setter
|
||||||
def respawn_icon(self, value: RespawnIcon | None) -> None:
|
def respawn_icon(self, value: RespawnIcon | None) -> None:
|
||||||
|
|||||||
@ -300,7 +300,10 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
|||||||
from bauiv1lib import specialoffer
|
from bauiv1lib import specialoffer
|
||||||
|
|
||||||
assert bs.app.classic is not None
|
assert bs.app.classic is not None
|
||||||
if bool(False):
|
if bui.app.env.headless:
|
||||||
|
# UI stuff fails now in headless builds; avoid it.
|
||||||
|
pass
|
||||||
|
elif bool(False):
|
||||||
uicontroller = bs.app.ui_v1.controller
|
uicontroller = bs.app.ui_v1.controller
|
||||||
assert uicontroller is not None
|
assert uicontroller is not None
|
||||||
uicontroller.show_main_menu()
|
uicontroller.show_main_menu()
|
||||||
|
|||||||
@ -69,6 +69,7 @@ from babase import (
|
|||||||
PluginSpec,
|
PluginSpec,
|
||||||
pushcall,
|
pushcall,
|
||||||
quit,
|
quit,
|
||||||
|
QuitType,
|
||||||
request_permission,
|
request_permission,
|
||||||
safecolor,
|
safecolor,
|
||||||
screenmessage,
|
screenmessage,
|
||||||
@ -192,6 +193,7 @@ __all__ = [
|
|||||||
'PluginSpec',
|
'PluginSpec',
|
||||||
'pushcall',
|
'pushcall',
|
||||||
'quit',
|
'quit',
|
||||||
|
'QuitType',
|
||||||
'request_permission',
|
'request_permission',
|
||||||
'rowwidget',
|
'rowwidget',
|
||||||
'safecolor',
|
'safecolor',
|
||||||
|
|||||||
@ -13,6 +13,8 @@ import _bauiv1
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
|
import babase
|
||||||
|
|
||||||
|
|
||||||
def ticket_icon_press() -> None:
|
def ticket_icon_press() -> None:
|
||||||
from babase import app
|
from babase import app
|
||||||
@ -57,14 +59,14 @@ def party_icon_activate(origin: Sequence[float]) -> None:
|
|||||||
logging.warning('party_icon_activate: no classic.')
|
logging.warning('party_icon_activate: no classic.')
|
||||||
|
|
||||||
|
|
||||||
def quit_window() -> None:
|
def quit_window(quit_type: babase.QuitType) -> None:
|
||||||
from babase import app
|
from babase import app
|
||||||
|
|
||||||
if app.classic is None:
|
if app.classic is None:
|
||||||
logging.exception('Classic not present.')
|
logging.exception('Classic not present.')
|
||||||
return
|
return
|
||||||
|
|
||||||
app.classic.quit_window()
|
app.classic.quit_window(quit_type)
|
||||||
|
|
||||||
|
|
||||||
def device_menu_press(device_id: int | None) -> None:
|
def device_menu_press(device_id: int | None) -> None:
|
||||||
|
|||||||
@ -153,15 +153,15 @@ class QuitWindow:
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
quit_type: bui.QuitType | None = None,
|
||||||
swish: bool = False,
|
swish: bool = False,
|
||||||
back: bool = False,
|
|
||||||
origin_widget: bui.Widget | None = None,
|
origin_widget: bui.Widget | None = None,
|
||||||
):
|
):
|
||||||
classic = bui.app.classic
|
classic = bui.app.classic
|
||||||
assert classic is not None
|
assert classic is not None
|
||||||
ui = bui.app.ui_v1
|
ui = bui.app.ui_v1
|
||||||
app = bui.app
|
app = bui.app
|
||||||
self._back = back
|
self._quit_type = quit_type
|
||||||
|
|
||||||
# If there's already one of us up somewhere, kill it.
|
# If there's already one of us up somewhere, kill it.
|
||||||
if ui.quit_window is not None:
|
if ui.quit_window is not None:
|
||||||
@ -187,29 +187,8 @@ class QuitWindow:
|
|||||||
resource=quit_resource,
|
resource=quit_resource,
|
||||||
subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))],
|
subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))],
|
||||||
),
|
),
|
||||||
self._fade_and_quit,
|
lambda: bui.quit(confirm=False, quit_type=self._quit_type)
|
||||||
|
if self._quit_type is not None
|
||||||
|
else bui.quit(confirm=False),
|
||||||
origin_widget=origin_widget,
|
origin_widget=origin_widget,
|
||||||
).root_widget
|
).root_widget
|
||||||
|
|
||||||
def _fade_and_quit(self) -> None:
|
|
||||||
bui.fade_screen(
|
|
||||||
False,
|
|
||||||
time=0.2,
|
|
||||||
endcall=lambda: bui.quit(soft=True, back=self._back),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Prevent the user from doing anything else while we're on our
|
|
||||||
# way out.
|
|
||||||
bui.lock_all_input()
|
|
||||||
|
|
||||||
# On systems supporting soft-quit, unlock and fade back in shortly
|
|
||||||
# (soft-quit basically just backgrounds/hides the app).
|
|
||||||
if bui.app.env.supports_soft_quit:
|
|
||||||
# Unlock and fade back in shortly. Just in case something goes
|
|
||||||
# wrong (or on Android where quit just backs out of our activity
|
|
||||||
# and we may come back after).
|
|
||||||
def _come_back() -> None:
|
|
||||||
bui.unlock_all_input()
|
|
||||||
bui.fade_screen(True)
|
|
||||||
|
|
||||||
bui.apptimer(0.5, _come_back)
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ class KioskWindow(bui.Window):
|
|||||||
self._height = 340.0
|
self._height = 340.0
|
||||||
|
|
||||||
def _do_cancel() -> None:
|
def _do_cancel() -> None:
|
||||||
QuitWindow(swish=True, back=True)
|
QuitWindow(swish=True, quit_type=bui.QuitType.BACK)
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
root_widget=bui.containerwidget(
|
root_widget=bui.containerwidget(
|
||||||
|
|||||||
@ -190,7 +190,6 @@ class MainMenuWindow(bui.Window):
|
|||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
# pylint: disable=too-many-statements
|
# pylint: disable=too-many-statements
|
||||||
from bauiv1lib.confirm import QuitWindow
|
|
||||||
from bauiv1lib.store.button import StoreButton
|
from bauiv1lib.store.button import StoreButton
|
||||||
|
|
||||||
plus = bui.app.plus
|
plus = bui.app.plus
|
||||||
@ -422,7 +421,7 @@ class MainMenuWindow(bui.Window):
|
|||||||
):
|
):
|
||||||
|
|
||||||
def _do_quit() -> None:
|
def _do_quit() -> None:
|
||||||
QuitWindow(swish=True, back=True)
|
bui.quit(confirm=True, quit_type=bui.QuitType.BACK)
|
||||||
|
|
||||||
bui.containerwidget(
|
bui.containerwidget(
|
||||||
edit=self._root_widget, on_cancel_call=_do_quit
|
edit=self._root_widget, on_cancel_call=_do_quit
|
||||||
@ -1040,6 +1039,9 @@ class MainMenuWindow(bui.Window):
|
|||||||
# pylint: disable=cyclic-import
|
# pylint: disable=cyclic-import
|
||||||
from bauiv1lib.confirm import QuitWindow
|
from bauiv1lib.confirm import QuitWindow
|
||||||
|
|
||||||
|
# Note: Normally we should go through bui.quit(confirm=True) but
|
||||||
|
# invoking the window directly lets us scale it up from the
|
||||||
|
# button.
|
||||||
QuitWindow(origin_widget=self._quit_button)
|
QuitWindow(origin_widget=self._quit_button)
|
||||||
|
|
||||||
def _demo_menu_press(self) -> None:
|
def _demo_menu_press(self) -> None:
|
||||||
|
|||||||
@ -431,7 +431,9 @@ class GamepadSettingsWindow(bui.Window):
|
|||||||
def get_unassigned_buttons_run_value(self) -> bool:
|
def get_unassigned_buttons_run_value(self) -> bool:
|
||||||
"""(internal)"""
|
"""(internal)"""
|
||||||
assert self._settings is not None
|
assert self._settings is not None
|
||||||
return self._settings.get('unassignedButtonsRun', True)
|
val = self._settings.get('unassignedButtonsRun', True)
|
||||||
|
assert isinstance(val, bool)
|
||||||
|
return val
|
||||||
|
|
||||||
def set_unassigned_buttons_run_value(self, value: bool) -> None:
|
def set_unassigned_buttons_run_value(self, value: bool) -> None:
|
||||||
"""(internal)"""
|
"""(internal)"""
|
||||||
@ -446,7 +448,9 @@ class GamepadSettingsWindow(bui.Window):
|
|||||||
def get_start_button_activates_default_widget_value(self) -> bool:
|
def get_start_button_activates_default_widget_value(self) -> bool:
|
||||||
"""(internal)"""
|
"""(internal)"""
|
||||||
assert self._settings is not None
|
assert self._settings is not None
|
||||||
return self._settings.get('startButtonActivatesDefaultWidget', True)
|
val = self._settings.get('startButtonActivatesDefaultWidget', True)
|
||||||
|
assert isinstance(val, bool)
|
||||||
|
return val
|
||||||
|
|
||||||
def set_start_button_activates_default_widget_value(
|
def set_start_button_activates_default_widget_value(
|
||||||
self, value: bool
|
self, value: bool
|
||||||
@ -463,7 +467,9 @@ class GamepadSettingsWindow(bui.Window):
|
|||||||
def get_ui_only_value(self) -> bool:
|
def get_ui_only_value(self) -> bool:
|
||||||
"""(internal)"""
|
"""(internal)"""
|
||||||
assert self._settings is not None
|
assert self._settings is not None
|
||||||
return self._settings.get('uiOnly', False)
|
val = self._settings.get('uiOnly', False)
|
||||||
|
assert isinstance(val, bool)
|
||||||
|
return val
|
||||||
|
|
||||||
def set_ui_only_value(self, value: bool) -> None:
|
def set_ui_only_value(self, value: bool) -> None:
|
||||||
"""(internal)"""
|
"""(internal)"""
|
||||||
@ -478,7 +484,9 @@ class GamepadSettingsWindow(bui.Window):
|
|||||||
def get_ignore_completely_value(self) -> bool:
|
def get_ignore_completely_value(self) -> bool:
|
||||||
"""(internal)"""
|
"""(internal)"""
|
||||||
assert self._settings is not None
|
assert self._settings is not None
|
||||||
return self._settings.get('ignoreCompletely', False)
|
val = self._settings.get('ignoreCompletely', False)
|
||||||
|
assert isinstance(val, bool)
|
||||||
|
return val
|
||||||
|
|
||||||
def set_ignore_completely_value(self, value: bool) -> None:
|
def set_ignore_completely_value(self, value: bool) -> None:
|
||||||
"""(internal)"""
|
"""(internal)"""
|
||||||
@ -493,7 +501,9 @@ class GamepadSettingsWindow(bui.Window):
|
|||||||
def get_auto_recalibrate_analog_stick_value(self) -> bool:
|
def get_auto_recalibrate_analog_stick_value(self) -> bool:
|
||||||
"""(internal)"""
|
"""(internal)"""
|
||||||
assert self._settings is not None
|
assert self._settings is not None
|
||||||
return self._settings.get('autoRecalibrateAnalogStick', False)
|
val = self._settings.get('autoRecalibrateAnalogStick', False)
|
||||||
|
assert isinstance(val, bool)
|
||||||
|
return val
|
||||||
|
|
||||||
def set_auto_recalibrate_analog_stick_value(self, value: bool) -> None:
|
def set_auto_recalibrate_analog_stick_value(self, value: bool) -> None:
|
||||||
"""(internal)"""
|
"""(internal)"""
|
||||||
@ -510,7 +520,9 @@ class GamepadSettingsWindow(bui.Window):
|
|||||||
assert self._settings is not None
|
assert self._settings is not None
|
||||||
if not self._is_secondary:
|
if not self._is_secondary:
|
||||||
raise RuntimeError('Enable value only applies to secondary editor.')
|
raise RuntimeError('Enable value only applies to secondary editor.')
|
||||||
return self._settings.get('enableSecondary', False)
|
val = self._settings.get('enableSecondary', False)
|
||||||
|
assert isinstance(val, bool)
|
||||||
|
return val
|
||||||
|
|
||||||
def show_secondary_editor(self) -> None:
|
def show_secondary_editor(self) -> None:
|
||||||
"""(internal)"""
|
"""(internal)"""
|
||||||
|
|||||||
@ -1411,6 +1411,6 @@ def _check_merch_availability_in_bg_thread() -> None:
|
|||||||
# to do this during docs generation/etc.)
|
# to do this during docs generation/etc.)
|
||||||
if (
|
if (
|
||||||
os.environ.get('BA_RUNNING_WITH_DUMMY_MODULES') != '1'
|
os.environ.get('BA_RUNNING_WITH_DUMMY_MODULES') != '1'
|
||||||
and bui.app.state is not bui.app.State.NOT_RUNNING
|
and bui.app.state is not bui.app.State.NOT_STARTED
|
||||||
):
|
):
|
||||||
Thread(target=_check_merch_availability_in_bg_thread, daemon=True).start()
|
Thread(target=_check_merch_availability_in_bg_thread, daemon=True).start()
|
||||||
|
|||||||
@ -76,7 +76,7 @@ void AppAdapter::OnMainThreadStartApp() {
|
|||||||
if (!g_core->HeadlessMode()) {
|
if (!g_core->HeadlessMode()) {
|
||||||
// If we've got a nice themed hardware cursor, show it. Otherwise we'll
|
// If we've got a nice themed hardware cursor, show it. Otherwise we'll
|
||||||
// render it manually, which is laggier but gets the job done.
|
// render it manually, which is laggier but gets the job done.
|
||||||
g_base->platform->SetHardwareCursorVisible(g_buildconfig.hardware_cursor());
|
// g_base->platform->SetHardwareCursorVisible(g_buildconfig.hardware_cursor());
|
||||||
|
|
||||||
// On desktop systems we just assume keyboard input exists and add it
|
// On desktop systems we just assume keyboard input exists and add it
|
||||||
// immediately.
|
// immediately.
|
||||||
@ -100,7 +100,7 @@ void AppAdapter::OnAppShutdownComplete() { assert(g_base->InLogicThread()); }
|
|||||||
void AppAdapter::OnScreenSizeChange() { assert(g_base->InLogicThread()); }
|
void AppAdapter::OnScreenSizeChange() { assert(g_base->InLogicThread()); }
|
||||||
void AppAdapter::DoApplyAppConfig() { assert(g_base->InLogicThread()); }
|
void AppAdapter::DoApplyAppConfig() { assert(g_base->InLogicThread()); }
|
||||||
|
|
||||||
void AppAdapter::OnAppPause_() {
|
void AppAdapter::OnAppSuspend_() {
|
||||||
assert(g_core->InMainThread());
|
assert(g_core->InMainThread());
|
||||||
|
|
||||||
// IMPORTANT: Any pause related stuff that event-loop-threads need to do
|
// IMPORTANT: Any pause related stuff that event-loop-threads need to do
|
||||||
@ -109,7 +109,7 @@ void AppAdapter::OnAppPause_() {
|
|||||||
// their event-loop is actually paused.
|
// their event-loop is actually paused.
|
||||||
|
|
||||||
// Pause all event loops.
|
// Pause all event loops.
|
||||||
EventLoop::SetEventLoopsPaused(true);
|
EventLoop::SetEventLoopsSuspended(true);
|
||||||
|
|
||||||
if (g_base->network_reader) {
|
if (g_base->network_reader) {
|
||||||
g_base->network_reader->OnAppPause();
|
g_base->network_reader->OnAppPause();
|
||||||
@ -117,24 +117,26 @@ void AppAdapter::OnAppPause_() {
|
|||||||
g_base->networking->OnAppPause();
|
g_base->networking->OnAppPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppAdapter::OnAppResume_() {
|
void AppAdapter::OnAppUnsuspend_() {
|
||||||
assert(g_core->InMainThread());
|
assert(g_core->InMainThread());
|
||||||
|
|
||||||
// Spin all event-loops back up.
|
// Spin all event-loops back up.
|
||||||
EventLoop::SetEventLoopsPaused(false);
|
EventLoop::SetEventLoopsSuspended(false);
|
||||||
|
|
||||||
// Run resumes that expect to happen in the main thread.
|
// Run resumes that expect to happen in the main thread.
|
||||||
g_base->network_reader->OnAppResume();
|
g_base->network_reader->OnAppResume();
|
||||||
g_base->networking->OnAppResume();
|
g_base->networking->OnAppResume();
|
||||||
|
|
||||||
// When resuming from a paused state, we may want to pause whatever game
|
// When resuming from a suspended state, we may want to pause whatever
|
||||||
// was running when we last were active.
|
// game was running when we last were active.
|
||||||
//
|
//
|
||||||
// TODO(efro): we should make this smarter so it doesn't happen if we're
|
// TODO(efro): we should make this smarter so it doesn't happen if we're
|
||||||
// in a network game or something that we can't pause; bringing up the
|
// in a network game or something that we can't pause; bringing up the
|
||||||
// menu doesn't really accomplish anything there.
|
// menu doesn't really accomplish anything there.
|
||||||
if (g_core->should_pause) {
|
//
|
||||||
g_core->should_pause = false;
|
// In general this probably should be handled at a higher level.
|
||||||
|
if (g_core->should_pause_active_game) {
|
||||||
|
g_core->should_pause_active_game = false;
|
||||||
|
|
||||||
// If we've been completely backgrounded, send a menu-press command to
|
// If we've been completely backgrounded, send a menu-press command to
|
||||||
// the game; this will bring up a pause menu if we're in the game/etc.
|
// the game; this will bring up a pause menu if we're in the game/etc.
|
||||||
@ -144,13 +146,13 @@ void AppAdapter::OnAppResume_() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppAdapter::PauseApp() {
|
void AppAdapter::SuspendApp() {
|
||||||
assert(g_core);
|
assert(g_core);
|
||||||
assert(g_core->InMainThread());
|
assert(g_core->InMainThread());
|
||||||
|
|
||||||
if (app_paused_) {
|
if (app_suspended_) {
|
||||||
Log(LogLevel::kWarning,
|
Log(LogLevel::kWarning,
|
||||||
"AppAdapter::PauseApp() called with app already paused.");
|
"AppAdapter::SuspendApp() called with app already suspended.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,11 +163,12 @@ void AppAdapter::PauseApp() {
|
|||||||
millisecs_t max_duration{2000};
|
millisecs_t max_duration{2000};
|
||||||
|
|
||||||
g_core->platform->DebugLog(
|
g_core->platform->DebugLog(
|
||||||
"PauseApp@" + std::to_string(core::CorePlatform::GetCurrentMillisecs()));
|
"SuspendApp@"
|
||||||
|
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()));
|
||||||
// assert(!app_pause_requested_);
|
// assert(!app_pause_requested_);
|
||||||
// app_pause_requested_ = true;
|
// app_pause_requested_ = true;
|
||||||
app_paused_ = true;
|
app_suspended_ = true;
|
||||||
OnAppPause_();
|
OnAppSuspend_();
|
||||||
// UpdatePauseResume_();
|
// UpdatePauseResume_();
|
||||||
|
|
||||||
// We assume that the OS will completely suspend our process the moment we
|
// We assume that the OS will completely suspend our process the moment we
|
||||||
@ -177,12 +180,12 @@ void AppAdapter::PauseApp() {
|
|||||||
< max_duration) {
|
< max_duration) {
|
||||||
// If/when we get to a point with no threads waiting to be paused, we're
|
// If/when we get to a point with no threads waiting to be paused, we're
|
||||||
// good to go.
|
// good to go.
|
||||||
auto threads{EventLoop::GetStillPausingThreads()};
|
auto threads{EventLoop::GetStillSuspendingEventLoops()};
|
||||||
running_thread_count = threads.size();
|
running_thread_count = threads.size();
|
||||||
if (running_thread_count == 0) {
|
if (running_thread_count == 0) {
|
||||||
if (g_buildconfig.debug_build()) {
|
if (g_buildconfig.debug_build()) {
|
||||||
Log(LogLevel::kDebug,
|
Log(LogLevel::kDebug,
|
||||||
"PauseApp() completed in "
|
"SuspendApp() completed in "
|
||||||
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()
|
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()
|
||||||
- start_time)
|
- start_time)
|
||||||
+ "ms.");
|
+ "ms.");
|
||||||
@ -193,7 +196,7 @@ void AppAdapter::PauseApp() {
|
|||||||
|
|
||||||
// If we made it here, we timed out. Complain.
|
// If we made it here, we timed out. Complain.
|
||||||
Log(LogLevel::kError,
|
Log(LogLevel::kError,
|
||||||
std::string("PauseApp() took too long; ")
|
std::string("SuspendApp() took too long; ")
|
||||||
+ std::to_string(running_thread_count)
|
+ std::to_string(running_thread_count)
|
||||||
+ " threads not yet paused after "
|
+ " threads not yet paused after "
|
||||||
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()
|
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()
|
||||||
@ -201,26 +204,27 @@ void AppAdapter::PauseApp() {
|
|||||||
+ " ms.");
|
+ " ms.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppAdapter::ResumeApp() {
|
void AppAdapter::UnsuspendApp() {
|
||||||
assert(g_core);
|
assert(g_core);
|
||||||
assert(g_core->InMainThread());
|
assert(g_core->InMainThread());
|
||||||
|
|
||||||
if (!app_paused_) {
|
if (!app_suspended_) {
|
||||||
Log(LogLevel::kWarning,
|
Log(LogLevel::kWarning,
|
||||||
"AppAdapter::ResumeApp() called with app not in paused state.");
|
"AppAdapter::UnsuspendApp() called with app not in paused state.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
millisecs_t start_time{core::CorePlatform::GetCurrentMillisecs()};
|
millisecs_t start_time{core::CorePlatform::GetCurrentMillisecs()};
|
||||||
g_core->platform->DebugLog(
|
g_core->platform->DebugLog(
|
||||||
"ResumeApp@" + std::to_string(core::CorePlatform::GetCurrentMillisecs()));
|
"UnsuspendApp@"
|
||||||
|
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()));
|
||||||
// assert(app_pause_requested_);
|
// assert(app_pause_requested_);
|
||||||
// app_pause_requested_ = false;
|
// app_pause_requested_ = false;
|
||||||
// UpdatePauseResume_();
|
// UpdatePauseResume_();
|
||||||
app_paused_ = false;
|
app_suspended_ = false;
|
||||||
OnAppResume_();
|
OnAppUnsuspend_();
|
||||||
if (g_buildconfig.debug_build()) {
|
if (g_buildconfig.debug_build()) {
|
||||||
Log(LogLevel::kDebug,
|
Log(LogLevel::kDebug,
|
||||||
"ResumeApp() completed in "
|
"UnsuspendApp() completed in "
|
||||||
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()
|
+ std::to_string(core::CorePlatform::GetCurrentMillisecs()
|
||||||
- start_time)
|
- start_time)
|
||||||
+ "ms.");
|
+ "ms.");
|
||||||
@ -249,4 +253,32 @@ void AppAdapter::DoPushGraphicsContextRunnable(Runnable* runnable) {
|
|||||||
DoPushMainThreadRunnable(runnable);
|
DoPushMainThreadRunnable(runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppAdapter::CursorPositionForDraw(float* x, float* y) {
|
||||||
|
assert(x && y);
|
||||||
|
|
||||||
|
// By default, just use our latest event-delivered cursor position;
|
||||||
|
// this should work everywhere though perhaps might not be most optimal.
|
||||||
|
if (g_base->input == nullptr) {
|
||||||
|
*x = 0.0f;
|
||||||
|
*y = 0.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*x = g_base->input->cursor_pos_x();
|
||||||
|
*y = g_base->input->cursor_pos_y();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AppAdapter::ShouldUseCursor() -> bool { return true; }
|
||||||
|
|
||||||
|
auto AppAdapter::HasHardwareCursor() -> bool { return false; }
|
||||||
|
|
||||||
|
void AppAdapter::SetHardwareCursorVisible(bool visible) {
|
||||||
|
printf("SHOULD SET VIS %d\n", static_cast<int>(visible));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AppAdapter::CanSoftQuit() -> bool { return false; }
|
||||||
|
auto AppAdapter::CanBackQuit() -> bool { return false; }
|
||||||
|
void AppAdapter::DoBackQuit() { FatalError("Fixme unimplemented."); }
|
||||||
|
void AppAdapter::DoSoftQuit() { FatalError("Fixme unimplemented."); }
|
||||||
|
void AppAdapter::TerminateApp() { FatalError("Fixme unimplemented."); }
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -55,30 +55,62 @@ class AppAdapter {
|
|||||||
|
|
||||||
/// Should return whether the current thread and/or context setup is the
|
/// Should return whether the current thread and/or context setup is the
|
||||||
/// one where graphics calls should be made. For the default
|
/// one where graphics calls should be made. For the default
|
||||||
/// implementation, this simply returns true in the main thread.
|
/// implementation, this simply returns true in the main thread. Note
|
||||||
|
/// that, while it is valid for the graphics context thread to change over
|
||||||
|
/// time, no more than one thread at a time should ever be considered the
|
||||||
|
/// graphics context.
|
||||||
virtual auto InGraphicsContext() -> bool;
|
virtual auto InGraphicsContext() -> bool;
|
||||||
|
|
||||||
/// Push a call to be run in the app's graphics context. Be aware that
|
/// Push a call to be run in the app's graphics context. This may mean
|
||||||
/// this may mean different threads on different platforms.
|
/// different things depending on the graphics architecture in use. On
|
||||||
|
/// some platforms this simply pushes to the main thread. On others it may
|
||||||
|
/// schedule a call to be run just before or after a frame draw in a
|
||||||
|
/// dedicated render thread. The default implementation pushes to the main
|
||||||
|
/// thread.
|
||||||
template <typename F>
|
template <typename F>
|
||||||
void PushGraphicsContextCall(const F& lambda) {
|
void PushGraphicsContextCall(const F& lambda) {
|
||||||
DoPushGraphicsContextRunnable(NewLambdaRunnableUnmanaged(lambda));
|
DoPushGraphicsContextRunnable(NewLambdaRunnableUnmanaged(lambda));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return whether the current setup should show a cursor for mouse
|
||||||
|
/// motion. This generally should be true for desktop type situations or
|
||||||
|
/// if a mouse is present on a mobile device and false for purely touch
|
||||||
|
/// based situations. This value may change over time if a mouse is
|
||||||
|
/// plugged in or unplugged/etc. Default implementation returns true.
|
||||||
|
virtual auto ShouldUseCursor() -> bool;
|
||||||
|
|
||||||
|
/// Return whether the app-adapter is having the OS show a cursor.
|
||||||
|
/// If this returns false, the engine will take care of drawing a cursor
|
||||||
|
/// when necessary. If true, SetHardwareCursorVisible will be called
|
||||||
|
/// periodically to inform the adapter what the cursor state should be.
|
||||||
|
/// The default implementation returns false;
|
||||||
|
virtual auto HasHardwareCursor() -> bool;
|
||||||
|
|
||||||
|
/// If HasHardwareCursor() returns true, this will be called in the main
|
||||||
|
/// thread periodically when the adapter should be hiding/showing the
|
||||||
|
/// cursor.
|
||||||
|
virtual void SetHardwareCursorVisible(bool visible);
|
||||||
|
|
||||||
|
/// Called to get the cursor position when drawing. Default implementation
|
||||||
|
/// returns the latest position delivered through the input subsystem, but
|
||||||
|
/// subclasses may want to override to provide slightly more up to date
|
||||||
|
/// values.
|
||||||
|
virtual void CursorPositionForDraw(float* x, float* y);
|
||||||
|
|
||||||
/// Put the app into a paused state. Should be called from the main
|
/// Put the app into a paused state. Should be called from the main
|
||||||
/// thread. Pauses work, closes network sockets, etc. May correspond to
|
/// thread. Pauses work, closes network sockets, etc. May correspond to
|
||||||
/// being backgrounded on mobile, being minimized on desktop, etc. It is
|
/// being backgrounded on mobile, being minimized on desktop, etc. It is
|
||||||
/// assumed that, as soon as this call returns, all work is finished and
|
/// assumed that, as soon as this call returns, all work is finished and
|
||||||
/// all threads can be suspended by the OS without any negative side
|
/// all threads can be suspended by the OS without any negative side
|
||||||
/// effects.
|
/// effects.
|
||||||
void PauseApp();
|
void SuspendApp();
|
||||||
|
|
||||||
/// Resume the app; can correspond to foregrounding on mobile,
|
/// Resume the app; can correspond to foregrounding on mobile,
|
||||||
/// unminimizing on desktop, etc. Spins threads back up, re-opens network
|
/// unminimizing on desktop, etc. Spins threads back up, re-opens network
|
||||||
/// sockets, etc.
|
/// sockets, etc.
|
||||||
void ResumeApp();
|
void UnsuspendApp();
|
||||||
|
|
||||||
auto app_paused() const { return app_paused_; }
|
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 currently will simply affect whether that option is
|
||||||
@ -91,6 +123,36 @@ class AppAdapter {
|
|||||||
/// Return whether this AppAdapter supports max-fps controls for its display.
|
/// Return whether this AppAdapter supports max-fps controls for its display.
|
||||||
virtual auto SupportsMaxFPS() -> bool const;
|
virtual auto SupportsMaxFPS() -> bool const;
|
||||||
|
|
||||||
|
/// Return whether this platform supports soft-quit. A soft quit is
|
||||||
|
/// when the app is reset/backgrounded/etc. but remains running in case
|
||||||
|
/// needed again. Generally this is the behavior on mobile apps.
|
||||||
|
virtual auto CanSoftQuit() -> bool;
|
||||||
|
|
||||||
|
/// Implement soft-quit behavior. Will always be called in the logic
|
||||||
|
/// thread. Make sure to also override CanBackQuit to reflect this being
|
||||||
|
/// present. Note that when quitting the app yourself, you should use
|
||||||
|
/// g_base->QuitApp(); do not call this directly.
|
||||||
|
virtual void DoSoftQuit();
|
||||||
|
|
||||||
|
/// Return whether this platform supports back-quit. A back quit is a
|
||||||
|
/// variation of soft-quit generally triggered by a back button, which may
|
||||||
|
/// give different results in the OS. For example on Android this may
|
||||||
|
/// result in jumping back to the previous Android activity instead of
|
||||||
|
/// just ending the current one and dumping to the home screen as normal
|
||||||
|
/// soft quit might do.
|
||||||
|
virtual auto CanBackQuit() -> bool;
|
||||||
|
|
||||||
|
/// Implement back-quit behavior. Will always be called in the logic
|
||||||
|
/// thread. Make sure to also override CanBackQuit to reflect this being
|
||||||
|
/// present. Note that when quitting the app yourself, you should use
|
||||||
|
/// g_base->QuitApp(); do not call this directly.
|
||||||
|
virtual void DoBackQuit();
|
||||||
|
|
||||||
|
/// Terminate the app. This can be immediate or by posting some high
|
||||||
|
/// level event. There should be nothing left to do in the engine at
|
||||||
|
/// this point.
|
||||||
|
virtual void TerminateApp();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AppAdapter();
|
AppAdapter();
|
||||||
virtual ~AppAdapter();
|
virtual ~AppAdapter();
|
||||||
@ -104,9 +166,9 @@ class AppAdapter {
|
|||||||
virtual void DoPushGraphicsContextRunnable(Runnable* runnable);
|
virtual void DoPushGraphicsContextRunnable(Runnable* runnable);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnAppPause_();
|
void OnAppSuspend_();
|
||||||
void OnAppResume_();
|
void OnAppUnsuspend_();
|
||||||
bool app_paused_{};
|
bool app_suspended_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -5,10 +5,34 @@
|
|||||||
|
|
||||||
#include <BallisticaKit-Swift.h>
|
#include <BallisticaKit-Swift.h>
|
||||||
|
|
||||||
|
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
||||||
|
#include "ballistica/base/graphics/graphics.h"
|
||||||
|
#include "ballistica/base/graphics/graphics_server.h"
|
||||||
|
#include "ballistica/base/logic/logic.h"
|
||||||
|
#include "ballistica/base/support/app_config.h"
|
||||||
#include "ballistica/shared/ballistica.h"
|
#include "ballistica/shared/ballistica.h"
|
||||||
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
|
|
||||||
|
/// RAII-friendly way to mark the thread and calls we're allowed to run graphics
|
||||||
|
/// stuff in.
|
||||||
|
class AppAdapterApple::ScopedAllowGraphics_ {
|
||||||
|
public:
|
||||||
|
explicit ScopedAllowGraphics_(AppAdapterApple* adapter) : adapter_{adapter} {
|
||||||
|
assert(!adapter_->graphics_allowed_);
|
||||||
|
adapter->graphics_thread_ = std::this_thread::get_id();
|
||||||
|
adapter->graphics_allowed_ = true;
|
||||||
|
}
|
||||||
|
~ScopedAllowGraphics_() {
|
||||||
|
assert(adapter_->graphics_allowed_);
|
||||||
|
adapter_->graphics_allowed_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AppAdapterApple* adapter_;
|
||||||
|
};
|
||||||
|
|
||||||
auto AppAdapterApple::ManagesMainThreadEventLoop() const -> bool {
|
auto AppAdapterApple::ManagesMainThreadEventLoop() const -> bool {
|
||||||
// Nope; we run under a standard Cocoa/UIKit environment and they call us; we
|
// Nope; we run under a standard Cocoa/UIKit environment and they call us; we
|
||||||
// don't call them.
|
// don't call them.
|
||||||
@ -17,7 +41,166 @@ auto AppAdapterApple::ManagesMainThreadEventLoop() const -> bool {
|
|||||||
|
|
||||||
void AppAdapterApple::DoPushMainThreadRunnable(Runnable* runnable) {
|
void AppAdapterApple::DoPushMainThreadRunnable(Runnable* runnable) {
|
||||||
// Kick this along to swift.
|
// Kick this along to swift.
|
||||||
BallisticaKit::PushRawRunnableToMain(runnable);
|
BallisticaKit::FromCppPushRawRunnableToMain(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppAdapterApple::DoApplyAppConfig() {
|
||||||
|
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();
|
||||||
|
|
||||||
|
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 don't have one yet.
|
||||||
|
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) {
|
||||||
|
ReloadRenderer_(graphics_quality_requested, texture_quality_requested);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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_(
|
||||||
|
GraphicsQualityRequest graphics_quality_requested,
|
||||||
|
TextureQualityRequest texture_quality_requested) {
|
||||||
|
auto* gs = g_base->graphics_server;
|
||||||
|
|
||||||
|
if (gs->renderer() && gs->renderer_loaded()) {
|
||||||
|
gs->UnloadRenderer();
|
||||||
|
}
|
||||||
|
if (!gs->renderer()) {
|
||||||
|
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.
|
||||||
|
gs->set_graphics_quality_requested(graphics_quality_requested);
|
||||||
|
gs->set_texture_quality_requested(texture_quality_requested);
|
||||||
|
|
||||||
|
// (Re)load stuff with these latest quality settings.
|
||||||
|
gs->LoadRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppAdapterApple::UpdateScreenSizes_() {
|
||||||
|
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 allow = ScopedAllowGraphics_(this);
|
||||||
|
|
||||||
|
// Run & release any pending runnables.
|
||||||
|
std::vector<Runnable*> calls;
|
||||||
|
{
|
||||||
|
// Pull calls off the list before running them; this way we only need
|
||||||
|
// to grab the list lock for a moment.
|
||||||
|
auto lock = std::scoped_lock(graphics_calls_mutex_);
|
||||||
|
if (!graphics_calls_.empty()) {
|
||||||
|
graphics_calls_.swap(calls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto* call : calls) {
|
||||||
|
call->RunAndLogErrors();
|
||||||
|
delete call;
|
||||||
|
}
|
||||||
|
// Lastly render.
|
||||||
|
return g_base->graphics_server->TryRender();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AppAdapterApple::InGraphicsContext() -> bool {
|
||||||
|
return std::this_thread::get_id() == graphics_thread_ && graphics_allowed_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppAdapterApple::DoPushGraphicsContextRunnable(Runnable* runnable) {
|
||||||
|
// In strict mode, make sure we're in our TryRender() call.
|
||||||
|
auto lock = std::scoped_lock(graphics_calls_mutex_);
|
||||||
|
if (graphics_calls_.size() > 1000) {
|
||||||
|
BA_LOG_ONCE(LogLevel::kError, "graphics_calls_ got too big.");
|
||||||
|
}
|
||||||
|
graphics_calls_.push_back(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AppAdapterApple::ShouldUseCursor() -> bool {
|
||||||
|
// On Mac of course we want our nice custom hardware cursor.
|
||||||
|
if (g_buildconfig.ostype_macos()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anywhere else (iOS, tvOS, etc.) just say no cursor for now. The OS
|
||||||
|
// may draw one in some cases (trackpad connected to iPad, etc.) but we
|
||||||
|
// don't interfere and just let the OS draw its normal cursor in that
|
||||||
|
// case. Can revisit this later if that becomes a more common scenario.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AppAdapterApple::HasHardwareCursor() -> bool {
|
||||||
|
// (mac should be only build getting called here)
|
||||||
|
assert(g_buildconfig.ostype_macos());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppAdapterApple::SetHardwareCursorVisible(bool visible) {
|
||||||
|
// (mac should be only build getting called here)
|
||||||
|
assert(g_buildconfig.ostype_macos());
|
||||||
|
assert(g_core->InMainThread());
|
||||||
|
|
||||||
|
#if BA_OSTYPE_MACOS
|
||||||
|
BallisticaKit::CocoaSupportSetCursorVisible(visible);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppAdapterApple::TerminateApp() {
|
||||||
|
#if BA_OSTYPE_MACOS
|
||||||
|
BallisticaKit::CocoaSupportTerminateApp();
|
||||||
|
#else
|
||||||
|
AppAdapter::TerminateApp();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -5,18 +5,55 @@
|
|||||||
|
|
||||||
#if BA_XCODE_BUILD
|
#if BA_XCODE_BUILD
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "ballistica/base/app_adapter/app_adapter.h"
|
#include "ballistica/base/app_adapter/app_adapter.h"
|
||||||
|
#include "ballistica/shared/generic/runnable.h"
|
||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
|
|
||||||
class AppAdapterApple : public AppAdapter {
|
class AppAdapterApple : public AppAdapter {
|
||||||
public:
|
public:
|
||||||
|
/// Given base, returns app-adapter cast to our type. This assumes it
|
||||||
|
/// actually *is* our type.
|
||||||
|
static auto Get(BaseFeatureSet* base) -> AppAdapterApple* {
|
||||||
|
auto* val = static_cast<AppAdapterApple*>(base->app_adapter);
|
||||||
|
assert(val);
|
||||||
|
assert(dynamic_cast<AppAdapterApple*>(base->app_adapter) == val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
auto ManagesMainThreadEventLoop() const -> bool override;
|
auto ManagesMainThreadEventLoop() const -> bool override;
|
||||||
|
void DoApplyAppConfig() override;
|
||||||
|
|
||||||
|
/// Called by FromSwift.
|
||||||
|
auto TryRender() -> bool;
|
||||||
|
|
||||||
|
/// Called by FromSwift.
|
||||||
|
void SetScreenResolution(float pixel_width, float pixel_height);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
||||||
|
void DoPushGraphicsContextRunnable(Runnable* runnable) override;
|
||||||
|
auto InGraphicsContext() -> bool override;
|
||||||
|
auto ShouldUseCursor() -> bool override;
|
||||||
|
auto HasHardwareCursor() -> bool override;
|
||||||
|
void SetHardwareCursorVisible(bool visible) override;
|
||||||
|
void TerminateApp() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void UpdateScreenSizes_();
|
||||||
|
class ScopedAllowGraphics_;
|
||||||
|
void SetScreen_(TextureQualityRequest texture_quality_requested,
|
||||||
|
GraphicsQualityRequest graphics_quality_requested);
|
||||||
|
void ReloadRenderer_(GraphicsQualityRequest graphics_quality_requested,
|
||||||
|
TextureQualityRequest texture_quality_requested);
|
||||||
|
std::thread::id graphics_thread_{};
|
||||||
|
bool graphics_allowed_;
|
||||||
|
std::mutex graphics_calls_mutex_;
|
||||||
|
std::vector<Runnable*> graphics_calls_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
// Released under the MIT License. See LICENSE for details.
|
// Released under the MIT License. See LICENSE for details.
|
||||||
|
|
||||||
#include "ballistica/shared/buildconfig/buildconfig_common.h"
|
|
||||||
#if BA_SDL_BUILD
|
#if BA_SDL_BUILD
|
||||||
|
|
||||||
#include "ballistica/base/app_adapter/app_adapter_sdl.h"
|
#include "ballistica/base/app_adapter/app_adapter_sdl.h"
|
||||||
|
|
||||||
#include "ballistica/base/base.h"
|
#include "ballistica/base/base.h"
|
||||||
#include "ballistica/base/dynamics/bg/bg_dynamics.h"
|
#include "ballistica/base/dynamics/bg/bg_dynamics.h"
|
||||||
#include "ballistica/base/graphics/gl/gl_sys.h"
|
#include "ballistica/base/graphics/gl/gl_sys.h"
|
||||||
@ -17,10 +17,28 @@
|
|||||||
#include "ballistica/base/support/app_config.h"
|
#include "ballistica/base/support/app_config.h"
|
||||||
#include "ballistica/base/ui/ui.h"
|
#include "ballistica/base/ui/ui.h"
|
||||||
#include "ballistica/core/platform/core_platform.h"
|
#include "ballistica/core/platform/core_platform.h"
|
||||||
|
#include "ballistica/shared/buildconfig/buildconfig_common.h"
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
|
|
||||||
|
/// RAII-friendly way to mark where in the main thread we're allowed to run
|
||||||
|
/// graphics code (only applies in strict-graphics-context mode).
|
||||||
|
class AppAdapterSDL::ScopedAllowGraphics_ {
|
||||||
|
public:
|
||||||
|
explicit ScopedAllowGraphics_(AppAdapterSDL* adapter) : adapter_{adapter} {
|
||||||
|
assert(!adapter_->strict_graphics_allowed_);
|
||||||
|
adapter->strict_graphics_allowed_ = true;
|
||||||
|
}
|
||||||
|
~ScopedAllowGraphics_() {
|
||||||
|
assert(adapter_->strict_graphics_allowed_);
|
||||||
|
adapter_->strict_graphics_allowed_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AppAdapterSDL* adapter_;
|
||||||
|
};
|
||||||
|
|
||||||
AppAdapterSDL::AppAdapterSDL() {
|
AppAdapterSDL::AppAdapterSDL() {
|
||||||
assert(!g_core->HeadlessMode());
|
assert(!g_core->HeadlessMode());
|
||||||
assert(g_core->InMainThread());
|
assert(g_core->InMainThread());
|
||||||
@ -36,6 +54,11 @@ void AppAdapterSDL::OnMainThreadStartApp() {
|
|||||||
// App is starting. Let's fire up the ol' SDL.
|
// App is starting. Let's fire up the ol' SDL.
|
||||||
uint32_t sdl_flags{SDL_INIT_VIDEO | SDL_INIT_JOYSTICK};
|
uint32_t sdl_flags{SDL_INIT_VIDEO | SDL_INIT_JOYSTICK};
|
||||||
|
|
||||||
|
if (strict_graphics_context_) {
|
||||||
|
Log(LogLevel::kWarning,
|
||||||
|
"AppAdapterSDL strict_graphics_context_ is enabled."
|
||||||
|
" Remember to turn this off.");
|
||||||
|
}
|
||||||
// We may or may not want xinput on windows.
|
// We may or may not want xinput on windows.
|
||||||
if (g_buildconfig.ostype_windows()) {
|
if (g_buildconfig.ostype_windows()) {
|
||||||
if (!g_core->platform->GetLowLevelConfigValue("enablexinput", 1)) {
|
if (!g_core->platform->GetLowLevelConfigValue("enablexinput", 1)) {
|
||||||
@ -72,6 +95,9 @@ void AppAdapterSDL::OnMainThreadStartApp() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We currently use a software cursor, so hide the system one.
|
||||||
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppAdapterSDL::DoApplyAppConfig() {
|
void AppAdapterSDL::DoApplyAppConfig() {
|
||||||
@ -91,6 +117,7 @@ void AppAdapterSDL::DoApplyAppConfig() {
|
|||||||
// 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);
|
bool fullscreen = g_base->app_config->Resolve(AppConfig::BoolID::kFullscreen);
|
||||||
|
fullscreen = false;
|
||||||
auto vsync = g_base->graphics->VSyncFromAppConfig();
|
auto vsync = g_base->graphics->VSyncFromAppConfig();
|
||||||
int max_fps = g_base->app_config->Resolve(AppConfig::IntID::kMaxFPS);
|
int max_fps = g_base->app_config->Resolve(AppConfig::IntID::kMaxFPS);
|
||||||
|
|
||||||
@ -114,7 +141,7 @@ void AppAdapterSDL::RunMainThreadEventLoopToCompletion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw.
|
// Draw.
|
||||||
if (!hidden_ && g_base->graphics_server->TryRender()) {
|
if (!hidden_ && TryRender()) {
|
||||||
SDL_GL_SwapWindow(sdl_window_);
|
SDL_GL_SwapWindow(sdl_window_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +152,34 @@ void AppAdapterSDL::RunMainThreadEventLoopToCompletion() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto AppAdapterSDL::TryRender() -> bool {
|
||||||
|
if (strict_graphics_context_) {
|
||||||
|
// In strict mode, allow graphics stuff in here. Normally we allow it
|
||||||
|
// anywhere in the main thread.
|
||||||
|
auto allow = ScopedAllowGraphics_(this);
|
||||||
|
|
||||||
|
// Run & release any pending runnables.
|
||||||
|
std::vector<Runnable*> calls;
|
||||||
|
{
|
||||||
|
// Pull calls off the list before running them; this way we only need
|
||||||
|
// to grab the list lock for a moment.
|
||||||
|
auto lock = std::scoped_lock(strict_graphics_calls_mutex_);
|
||||||
|
if (!strict_graphics_calls_.empty()) {
|
||||||
|
strict_graphics_calls_.swap(calls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto* call : calls) {
|
||||||
|
call->RunAndLogErrors();
|
||||||
|
delete call;
|
||||||
|
}
|
||||||
|
// Lastly render.
|
||||||
|
return g_base->graphics_server->TryRender();
|
||||||
|
} else {
|
||||||
|
// Simple path; just render.
|
||||||
|
return g_base->graphics_server->TryRender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AppAdapterSDL::SleepUntilNextEventCycle_(microsecs_t cycle_start_time) {
|
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.
|
||||||
@ -300,7 +355,13 @@ void AppAdapterSDL::HandleSDLEvent_(const SDL_Event& event) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
g_base->logic->event_loop()->PushCall([] { g_base->ui->ConfirmQuit(); });
|
if (g_core->GetAppTimeMillisecs() - last_windowevent_close_time_ < 100) {
|
||||||
|
// If they hit the window close button, skip the confirm.
|
||||||
|
g_base->QuitApp(false);
|
||||||
|
} else {
|
||||||
|
// By default, confirm before quitting.
|
||||||
|
g_base->QuitApp(true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_TEXTINPUT: {
|
case SDL_TEXTINPUT: {
|
||||||
@ -310,6 +371,13 @@ void AppAdapterSDL::HandleSDLEvent_(const SDL_Event& event) {
|
|||||||
|
|
||||||
case SDL_WINDOWEVENT: {
|
case SDL_WINDOWEVENT: {
|
||||||
switch (event.window.event) {
|
switch (event.window.event) {
|
||||||
|
case SDL_WINDOWEVENT_CLOSE: {
|
||||||
|
// Simply note that this happened. We use this to adjust our
|
||||||
|
// SDL_QUIT behavior (quit is called right after this).
|
||||||
|
last_windowevent_close_time_ = g_core->GetAppTimeMillisecs();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SDL_WINDOWEVENT_MAXIMIZED: {
|
case SDL_WINDOWEVENT_MAXIMIZED: {
|
||||||
if (g_buildconfig.ostype_macos() && !fullscreen_) {
|
if (g_buildconfig.ostype_macos() && !fullscreen_) {
|
||||||
// Special case: on Mac, we wind up here if someone fullscreens
|
// Special case: on Mac, we wind up here if someone fullscreens
|
||||||
@ -476,9 +544,12 @@ void AppAdapterSDL::SetScreen_(
|
|||||||
bool fullscreen, int max_fps, VSyncRequest vsync_requested,
|
bool fullscreen, int max_fps, VSyncRequest vsync_requested,
|
||||||
TextureQualityRequest texture_quality_requested,
|
TextureQualityRequest texture_quality_requested,
|
||||||
GraphicsQualityRequest graphics_quality_requested) {
|
GraphicsQualityRequest graphics_quality_requested) {
|
||||||
assert(InGraphicsContext());
|
assert(g_core->InMainThread());
|
||||||
assert(!g_core->HeadlessMode());
|
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
|
// If we know what we support, filter our request types to what is
|
||||||
// supported. This will keep us from rebuilding contexts if request type
|
// supported. This will keep us from rebuilding contexts if request type
|
||||||
// is flipping between different types that we don't support.
|
// is flipping between different types that we don't support.
|
||||||
@ -676,6 +747,74 @@ void AppAdapterSDL::UpdateScreenSizes_() {
|
|||||||
static_cast<float>(pixels_y));
|
static_cast<float>(pixels_y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// As a default, allow graphics stuff in the main thread.
|
||||||
|
auto AppAdapterSDL::InGraphicsContext() -> bool {
|
||||||
|
// In strict mode, make sure we're in the right thread *and* within our
|
||||||
|
// render call.
|
||||||
|
if (strict_graphics_context_) {
|
||||||
|
return g_core->InMainThread() && strict_graphics_allowed_;
|
||||||
|
}
|
||||||
|
// By default, allow anywhere in main thread.
|
||||||
|
return g_core->InMainThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppAdapterSDL::DoPushGraphicsContextRunnable(Runnable* runnable) {
|
||||||
|
// In strict mode, make sure we're in our TryRender() call.
|
||||||
|
if (strict_graphics_context_) {
|
||||||
|
auto lock = std::scoped_lock(strict_graphics_calls_mutex_);
|
||||||
|
if (strict_graphics_calls_.size() > 1000) {
|
||||||
|
BA_LOG_ONCE(LogLevel::kError, "strict_graphics_calls_ got too big.");
|
||||||
|
}
|
||||||
|
strict_graphics_calls_.push_back(runnable);
|
||||||
|
} else {
|
||||||
|
DoPushMainThreadRunnable(runnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppAdapterSDL::CursorPositionForDraw(float* x, float* y) {
|
||||||
|
// Note: disabling this code, but leaving it in here for now as a proof of
|
||||||
|
// concept in case its worth revisiting later. In my current tests on Mac,
|
||||||
|
// Windows, and Linux, I'm seeing basicaly zero difference between
|
||||||
|
// immediate calculated values and ones from the event system, so I'm
|
||||||
|
// guessing remaining latency might be coming from the fact that frames
|
||||||
|
// tend to get assembled 1/60th of a second before it is displayed or
|
||||||
|
// whatnot. It'd probably be a better use of time to just wire up hardware
|
||||||
|
// cursor support for this build.
|
||||||
|
if (explicit_bool(true)) {
|
||||||
|
AppAdapter::CursorPositionForDraw(x, y);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(x && y);
|
||||||
|
|
||||||
|
// Grab latest values from the input subsystem (what would get used by
|
||||||
|
// default).
|
||||||
|
float event_x = g_base->input->cursor_pos_x();
|
||||||
|
float event_y = g_base->input->cursor_pos_y();
|
||||||
|
|
||||||
|
// Now ask sdl for it's latest values and wrangle the math ourself.
|
||||||
|
int sdl_x, sdl_y;
|
||||||
|
SDL_GetMouseState(&sdl_x, &sdl_y);
|
||||||
|
|
||||||
|
// Convert window coords to normalized.
|
||||||
|
float normalized_x = static_cast<float>(sdl_x) / window_size_.x;
|
||||||
|
float normalized_y = 1.0f - static_cast<float>(sdl_y) / window_size_.y;
|
||||||
|
|
||||||
|
// Convert normalized coords to virtual coords.
|
||||||
|
float immediate_x = g_base->graphics->PixelToVirtualX(
|
||||||
|
normalized_x * g_base->graphics->screen_pixel_width());
|
||||||
|
float immediate_y = g_base->graphics->PixelToVirtualY(
|
||||||
|
normalized_y * g_base->graphics->screen_pixel_height());
|
||||||
|
|
||||||
|
float diff_x = immediate_x - event_x;
|
||||||
|
float diff_y = immediate_y - event_y;
|
||||||
|
printf("DIFFS: %.2f %.2f\n", diff_x, diff_y);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
*x = immediate_x;
|
||||||
|
*y = immediate_y;
|
||||||
|
}
|
||||||
|
|
||||||
auto AppAdapterSDL::CanToggleFullscreen() -> bool const { return true; }
|
auto AppAdapterSDL::CanToggleFullscreen() -> bool const { return true; }
|
||||||
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; }
|
||||||
|
|||||||
@ -32,6 +32,8 @@ class AppAdapterSDL : public AppAdapter {
|
|||||||
void OnMainThreadStartApp() override;
|
void OnMainThreadStartApp() override;
|
||||||
void DoApplyAppConfig() override;
|
void DoApplyAppConfig() override;
|
||||||
|
|
||||||
|
auto TryRender() -> bool;
|
||||||
|
|
||||||
auto CanToggleFullscreen() -> bool const override;
|
auto CanToggleFullscreen() -> bool const override;
|
||||||
auto SupportsVSync() -> bool const override;
|
auto SupportsVSync() -> bool const override;
|
||||||
auto SupportsMaxFPS() -> bool const override;
|
auto SupportsMaxFPS() -> bool const override;
|
||||||
@ -40,8 +42,12 @@ class AppAdapterSDL : public AppAdapter {
|
|||||||
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
||||||
void RunMainThreadEventLoopToCompletion() override;
|
void RunMainThreadEventLoopToCompletion() override;
|
||||||
void DoExitMainThreadEventLoop() override;
|
void DoExitMainThreadEventLoop() override;
|
||||||
|
auto InGraphicsContext() -> bool override;
|
||||||
|
void DoPushGraphicsContextRunnable(Runnable* runnable) override;
|
||||||
|
void CursorPositionForDraw(float* x, float* y) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class ScopedAllowGraphics_;
|
||||||
void SetScreen_(bool fullscreen, int max_fps, VSyncRequest vsync_requested,
|
void SetScreen_(bool fullscreen, int max_fps, VSyncRequest vsync_requested,
|
||||||
TextureQualityRequest texture_quality_requested,
|
TextureQualityRequest texture_quality_requested,
|
||||||
GraphicsQualityRequest graphics_quality_requested);
|
GraphicsQualityRequest graphics_quality_requested);
|
||||||
@ -60,11 +66,23 @@ 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);
|
||||||
|
|
||||||
bool done_{};
|
bool done_ : 1 {};
|
||||||
bool fullscreen_{};
|
bool fullscreen_ : 1 {};
|
||||||
bool vsync_actually_enabled_{};
|
bool vsync_actually_enabled_ : 1 {};
|
||||||
bool debug_log_sdl_frame_timing_{};
|
bool debug_log_sdl_frame_timing_ : 1 {};
|
||||||
bool hidden_{};
|
bool hidden_ : 1 {};
|
||||||
|
|
||||||
|
/// With this off, graphics call pushes simply get pushed to the main
|
||||||
|
/// thread and graphics code is allowed to run any time in the main
|
||||||
|
/// thread. When this is on, pushed graphics-context calls get enqueued
|
||||||
|
/// and run as part of drawing, and graphics context calls are only
|
||||||
|
/// allowed during draws. This strictness is generally not needed here but
|
||||||
|
/// can be useful to test with, as it more closely matches other platforms
|
||||||
|
/// that require such a setup.
|
||||||
|
bool strict_graphics_context_ : 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};
|
int max_fps_{60};
|
||||||
@ -73,6 +91,7 @@ class AppAdapterSDL : public AppAdapter {
|
|||||||
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_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -1327,6 +1327,10 @@ void Assets::SetLanguageKeys(
|
|||||||
std::scoped_lock lock(language_mutex_);
|
std::scoped_lock lock(language_mutex_);
|
||||||
language_ = language;
|
language_ = language;
|
||||||
}
|
}
|
||||||
|
// Log our unique change state so things that go inactive and stop
|
||||||
|
// receiving callbacks can see if they're out of date if they become
|
||||||
|
// active again.
|
||||||
|
language_state_++;
|
||||||
|
|
||||||
// Let some subsystems know that language has changed.
|
// Let some subsystems know that language has changed.
|
||||||
g_base->app_mode()->LanguageChanged();
|
g_base->app_mode()->LanguageChanged();
|
||||||
|
|||||||
@ -115,6 +115,8 @@ class Assets {
|
|||||||
|
|
||||||
auto sys_assets_loaded() const { return sys_assets_loaded_; }
|
auto sys_assets_loaded() const { return sys_assets_loaded_; }
|
||||||
|
|
||||||
|
auto language_state() const { return language_state_; }
|
||||||
|
|
||||||
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);
|
||||||
@ -175,6 +177,7 @@ 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_;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -15,7 +15,7 @@ AssetsServer::AssetsServer() = default;
|
|||||||
void AssetsServer::OnMainThreadStartApp() {
|
void AssetsServer::OnMainThreadStartApp() {
|
||||||
// Spin up our thread.
|
// Spin up our thread.
|
||||||
event_loop_ = new EventLoop(EventLoopID::kAssets);
|
event_loop_ = new EventLoop(EventLoopID::kAssets);
|
||||||
g_core->pausable_event_loops.push_back(event_loop_);
|
g_core->suspendable_event_loops.push_back(event_loop_);
|
||||||
|
|
||||||
event_loop_->PushCallSynchronous([this] { OnAppStartInThread(); });
|
event_loop_->PushCallSynchronous([this] { OnAppStartInThread(); });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,8 +11,8 @@ namespace ballistica::base {
|
|||||||
// this is provided by the renderer
|
// this is provided by the renderer
|
||||||
class MeshAssetRendererData : public Object {
|
class MeshAssetRendererData : public Object {
|
||||||
public:
|
public:
|
||||||
auto GetDefaultOwnerThread() const -> EventLoopID override {
|
auto GetThreadOwnership() const -> ThreadOwnership override {
|
||||||
return EventLoopID::kMain;
|
return ThreadOwnership::kGraphicsContext;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -5,14 +5,12 @@
|
|||||||
#include "ballistica/base/app_adapter/app_adapter.h"
|
#include "ballistica/base/app_adapter/app_adapter.h"
|
||||||
#include "ballistica/base/assets/texture_asset_preload_data.h"
|
#include "ballistica/base/assets/texture_asset_preload_data.h"
|
||||||
#include "ballistica/base/assets/texture_asset_renderer_data.h"
|
#include "ballistica/base/assets/texture_asset_renderer_data.h"
|
||||||
#include "ballistica/base/graphics/graphics.h"
|
|
||||||
#include "ballistica/base/graphics/graphics_server.h"
|
#include "ballistica/base/graphics/graphics_server.h"
|
||||||
#include "ballistica/base/graphics/renderer/renderer.h"
|
#include "ballistica/base/graphics/renderer/renderer.h"
|
||||||
#include "ballistica/base/graphics/text/text_packer.h"
|
#include "ballistica/base/graphics/text/text_packer.h"
|
||||||
#include "ballistica/base/graphics/texture/dds.h"
|
#include "ballistica/base/graphics/texture/dds.h"
|
||||||
#include "ballistica/base/graphics/texture/ktx.h"
|
#include "ballistica/base/graphics/texture/ktx.h"
|
||||||
#include "ballistica/base/graphics/texture/pvr.h"
|
#include "ballistica/base/graphics/texture/pvr.h"
|
||||||
#include "ballistica/core/core.h"
|
|
||||||
#include "external/qr_code_generator/QrCode.hpp"
|
#include "external/qr_code_generator/QrCode.hpp"
|
||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
|
|||||||
@ -10,8 +10,8 @@ namespace ballistica::base {
|
|||||||
// Renderer-specific data (gl tex, etc). To be extended by the renderer.
|
// Renderer-specific data (gl tex, etc). To be extended by the renderer.
|
||||||
class TextureAssetRendererData : public Object {
|
class TextureAssetRendererData : public Object {
|
||||||
public:
|
public:
|
||||||
auto GetDefaultOwnerThread() const -> EventLoopID override {
|
auto GetThreadOwnership() const -> ThreadOwnership override {
|
||||||
return EventLoopID::kMain;
|
return ThreadOwnership::kGraphicsContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the renderer data but don't load it in yet.
|
// Create the renderer data but don't load it in yet.
|
||||||
|
|||||||
@ -136,14 +136,14 @@ AudioServer::AudioServer() : impl_{new AudioServer::Impl()} {}
|
|||||||
void AudioServer::OnMainThreadStartApp() {
|
void AudioServer::OnMainThreadStartApp() {
|
||||||
// Spin up our thread.
|
// Spin up our thread.
|
||||||
event_loop_ = new EventLoop(EventLoopID::kAudio);
|
event_loop_ = new EventLoop(EventLoopID::kAudio);
|
||||||
g_core->pausable_event_loops.push_back(event_loop_);
|
g_core->suspendable_event_loops.push_back(event_loop_);
|
||||||
|
|
||||||
// Run some setup stuff from our shiny new thread.
|
// Run some setup stuff from our shiny new thread.
|
||||||
event_loop_->PushCall([this] {
|
event_loop_->PushCall([this] {
|
||||||
// We want to be informed when our event-loop is pausing and unpausing.
|
// We want to be informed when our event-loop is pausing and unpausing.
|
||||||
event_loop()->AddPauseCallback(
|
event_loop()->AddSuspendCallback(
|
||||||
NewLambdaRunnableUnmanaged([this] { OnThreadPause(); }));
|
NewLambdaRunnableUnmanaged([this] { OnThreadPause(); }));
|
||||||
event_loop()->AddResumeCallback(
|
event_loop()->AddUnsuspendCallback(
|
||||||
NewLambdaRunnableUnmanaged([this] { OnThreadResume(); }));
|
NewLambdaRunnableUnmanaged([this] { OnThreadResume(); }));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1136,7 +1136,7 @@ void AudioServer::PushSetSoundPitchCall(float val) {
|
|||||||
event_loop()->PushCall([this, val] { SetSoundPitch(val); });
|
event_loop()->PushCall([this, val] { SetSoundPitch(val); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioServer::PushSetPausedCall(bool pause) {
|
void AudioServer::PushSetSuspendedCall(bool pause) {
|
||||||
event_loop()->PushCall([this, pause] {
|
event_loop()->PushCall([this, pause] {
|
||||||
if (g_buildconfig.ostype_android()) {
|
if (g_buildconfig.ostype_android()) {
|
||||||
Log(LogLevel::kError, "Shouldn't be getting SetPausedCall on android.");
|
Log(LogLevel::kError, "Shouldn't be getting SetPausedCall on android.");
|
||||||
@ -1189,7 +1189,7 @@ void AudioServer::ClearSoundRefDeleteList() {
|
|||||||
|
|
||||||
void AudioServer::BeginInterruption() {
|
void AudioServer::BeginInterruption() {
|
||||||
assert(!g_base->InAudioThread());
|
assert(!g_base->InAudioThread());
|
||||||
g_base->audio_server->PushSetPausedCall(true);
|
g_base->audio_server->PushSetSuspendedCall(true);
|
||||||
|
|
||||||
// Wait a reasonable amount of time for the thread to act on it.
|
// Wait a reasonable amount of time for the thread to act on it.
|
||||||
millisecs_t t = g_core->GetAppTimeMillisecs();
|
millisecs_t t = g_core->GetAppTimeMillisecs();
|
||||||
@ -1211,7 +1211,7 @@ void AudioServer::OnThreadResume() { SetPaused(false); }
|
|||||||
|
|
||||||
void AudioServer::EndInterruption() {
|
void AudioServer::EndInterruption() {
|
||||||
assert(!g_base->InAudioThread());
|
assert(!g_base->InAudioThread());
|
||||||
g_base->audio_server->PushSetPausedCall(false);
|
g_base->audio_server->PushSetSuspendedCall(false);
|
||||||
|
|
||||||
// Wait a reasonable amount of time for the thread to act on it.
|
// Wait a reasonable amount of time for the thread to act on it.
|
||||||
millisecs_t t = g_core->GetAppTimeMillisecs();
|
millisecs_t t = g_core->GetAppTimeMillisecs();
|
||||||
|
|||||||
@ -28,7 +28,7 @@ class AudioServer {
|
|||||||
|
|
||||||
void PushSetVolumesCall(float music_volume, float sound_volume);
|
void PushSetVolumesCall(float music_volume, float sound_volume);
|
||||||
void PushSetSoundPitchCall(float val);
|
void PushSetSoundPitchCall(float val);
|
||||||
void PushSetPausedCall(bool pause);
|
void PushSetSuspendedCall(bool pause);
|
||||||
|
|
||||||
static void BeginInterruption();
|
static void BeginInterruption();
|
||||||
static void EndInterruption();
|
static void EndInterruption();
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
#include "ballistica/base/support/stress_test.h"
|
#include "ballistica/base/support/stress_test.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/base/ui/ui_delegate.h"
|
||||||
#include "ballistica/core/python/core_python.h"
|
#include "ballistica/core/python/core_python.h"
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
#include "ballistica/shared/foundation/logging.h"
|
#include "ballistica/shared/foundation/logging.h"
|
||||||
@ -226,7 +227,7 @@ void BaseFeatureSet::OnAppShutdownComplete() {
|
|||||||
if (app_adapter->ManagesMainThreadEventLoop()) {
|
if (app_adapter->ManagesMainThreadEventLoop()) {
|
||||||
app_adapter->DoExitMainThreadEventLoop();
|
app_adapter->DoExitMainThreadEventLoop();
|
||||||
} else {
|
} else {
|
||||||
platform->TerminateApp();
|
app_adapter->TerminateApp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,10 +298,6 @@ void BaseFeatureSet::RunAppToCompletion() {
|
|||||||
g_base->app_adapter->RunMainThreadEventLoopToCompletion();
|
g_base->app_adapter->RunMainThreadEventLoopToCompletion();
|
||||||
}
|
}
|
||||||
|
|
||||||
// void BaseFeatureSet::PrimeAppMainThreadEventPump() {
|
|
||||||
// app_adapter->PrimeMainThreadEventPump();
|
|
||||||
// }
|
|
||||||
|
|
||||||
auto BaseFeatureSet::HavePlus() -> bool {
|
auto BaseFeatureSet::HavePlus() -> bool {
|
||||||
if (!plus_soft_ && !tried_importing_plus_) {
|
if (!plus_soft_ && !tried_importing_plus_) {
|
||||||
python->SoftImportPlus();
|
python->SoftImportPlus();
|
||||||
@ -363,37 +360,6 @@ void BaseFeatureSet::set_classic(ClassicSoftInterface* classic) {
|
|||||||
classic_soft_ = classic;
|
classic_soft_ = classic;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto BaseFeatureSet::HaveUIV1() -> bool {
|
|
||||||
if (!ui_v1_soft_ && !tried_importing_ui_v1_) {
|
|
||||||
python->SoftImportUIV1();
|
|
||||||
// Important to set this *after* import attempt, or a second import
|
|
||||||
// attempt while first is ongoing can insta-fail. Multiple import
|
|
||||||
// attempts shouldn't hurt anything.
|
|
||||||
tried_importing_ui_v1_ = true;
|
|
||||||
}
|
|
||||||
return ui_v1_soft_ != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Access the plus feature-set. Will throw an exception if not present.
|
|
||||||
auto BaseFeatureSet::ui_v1() -> UIV1SoftInterface* {
|
|
||||||
if (!ui_v1_soft_ && !tried_importing_ui_v1_) {
|
|
||||||
python->SoftImportUIV1();
|
|
||||||
// Important to set this *after* import attempt, or a second import
|
|
||||||
// attempt while first is ongoing can insta-fail. Multiple import
|
|
||||||
// attempts shouldn't hurt anything.
|
|
||||||
tried_importing_ui_v1_ = true;
|
|
||||||
}
|
|
||||||
if (!ui_v1_soft_) {
|
|
||||||
throw Exception("ui_v1 feature-set not present.");
|
|
||||||
}
|
|
||||||
return ui_v1_soft_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseFeatureSet::set_ui_v1(UIV1SoftInterface* ui_v1) {
|
|
||||||
assert(ui_v1_soft_ == nullptr);
|
|
||||||
ui_v1_soft_ = ui_v1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto BaseFeatureSet::GetAppInstanceUUID() -> const std::string& {
|
auto BaseFeatureSet::GetAppInstanceUUID() -> const std::string& {
|
||||||
static std::string app_instance_uuid;
|
static std::string app_instance_uuid;
|
||||||
static bool have_app_instance_uuid = false;
|
static bool have_app_instance_uuid = false;
|
||||||
@ -489,6 +455,10 @@ auto BaseFeatureSet::InNetworkWriteThread() const -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto BaseFeatureSet::InGraphicsContext() const -> bool {
|
||||||
|
return app_adapter->InGraphicsContext();
|
||||||
|
}
|
||||||
|
|
||||||
void BaseFeatureSet::ScreenMessage(const std::string& s,
|
void BaseFeatureSet::ScreenMessage(const std::string& s,
|
||||||
const Vector3f& color) {
|
const Vector3f& color) {
|
||||||
logic->event_loop()->PushCall(
|
logic->event_loop()->PushCall(
|
||||||
@ -719,15 +689,25 @@ void BaseFeatureSet::ShutdownSuppressDisallow() {
|
|||||||
|
|
||||||
auto BaseFeatureSet::GetReturnValue() const -> int { return return_value(); }
|
auto BaseFeatureSet::GetReturnValue() const -> int { return return_value(); }
|
||||||
|
|
||||||
void BaseFeatureSet::QuitApp(QuitType quit_type) {
|
void BaseFeatureSet::QuitApp(bool confirm, QuitType quit_type) {
|
||||||
// If they ask for 'back' and we support that, do it.
|
// If they want a confirm dialog and we're able to present one, do that.
|
||||||
// Otherwise if they want 'back' or 'soft' and we support soft, do it.
|
if (confirm && !g_core->HeadlessMode() && !g_base->input->IsInputLocked()
|
||||||
// Otherwise go with a regular app shutdown.
|
&& g_base->ui->delegate()
|
||||||
if (quit_type == QuitType::kBack && g_base->platform->CanBackQuit()) {
|
&& g_base->ui->delegate()->HasQuitConfirmDialog()) {
|
||||||
logic->event_loop()->PushCall([this] { platform->DoBackQuit(); });
|
logic->event_loop()->PushCall(
|
||||||
|
[this, quit_type] { g_base->ui->delegate()->ConfirmQuit(quit_type); });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Ok looks like we're quitting immediately.
|
||||||
|
//
|
||||||
|
// If they ask for 'back' and we support that, do it. Otherwise if they
|
||||||
|
// want 'back' or 'soft' and we support soft, do it. Otherwise go with a
|
||||||
|
// regular app shutdown.
|
||||||
|
if (quit_type == QuitType::kBack && app_adapter->CanBackQuit()) {
|
||||||
|
logic->event_loop()->PushCall([this] { app_adapter->DoBackQuit(); });
|
||||||
} else if ((quit_type == QuitType::kBack || quit_type == QuitType::kSoft)
|
} else if ((quit_type == QuitType::kBack || quit_type == QuitType::kSoft)
|
||||||
&& g_base->platform->CanSoftQuit()) {
|
&& app_adapter->CanSoftQuit()) {
|
||||||
logic->event_loop()->PushCall([this] { platform->DoSoftQuit(); });
|
logic->event_loop()->PushCall([this] { app_adapter->DoSoftQuit(); });
|
||||||
} else {
|
} else {
|
||||||
logic->event_loop()->PushCall([this] { logic->Shutdown(); });
|
logic->event_loop()->PushCall([this] { logic->Shutdown(); });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -115,22 +115,10 @@ class TextureAssetPreloadData;
|
|||||||
class TextureAssetRendererData;
|
class TextureAssetRendererData;
|
||||||
class TouchInput;
|
class TouchInput;
|
||||||
class UI;
|
class UI;
|
||||||
class UIV1SoftInterface;
|
class UIDelegateInterface;
|
||||||
class AppAdapterVR;
|
class AppAdapterVR;
|
||||||
class GraphicsVR;
|
class GraphicsVR;
|
||||||
|
|
||||||
enum class QuitType : uint8_t {
|
|
||||||
/// Leads to the process exiting.
|
|
||||||
kHard,
|
|
||||||
/// May hide/reset the app but keep the process running. Generally how
|
|
||||||
/// mobile apps behave.
|
|
||||||
kSoft,
|
|
||||||
/// Same as kSoft but gives 'back-button-pressed' behavior which may
|
|
||||||
/// differ depending on the OS (returning to a previous Activity in
|
|
||||||
/// Android instead of dumping to the home screen, etc.)
|
|
||||||
kBack,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class AssetType : uint8_t {
|
enum class AssetType : uint8_t {
|
||||||
kTexture,
|
kTexture,
|
||||||
kCollisionMesh,
|
kCollisionMesh,
|
||||||
@ -619,9 +607,11 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
|||||||
/// 'soft' means the app can simply reset/hide itself instead of actually
|
/// 'soft' means the app can simply reset/hide itself instead of actually
|
||||||
/// exiting the process (common behavior on mobile platforms). 'back'
|
/// exiting the process (common behavior on mobile platforms). 'back'
|
||||||
/// means that a soft-quit should behave as if a back-button was pressed,
|
/// means that a soft-quit should behave as if a back-button was pressed,
|
||||||
/// whic may trigger different behavior in the OS than a standard soft
|
/// which may trigger different behavior in the OS than a standard soft
|
||||||
/// quit.
|
/// quit. If 'confirm' is true, a confirmation dialog will be presented if
|
||||||
void QuitApp(QuitType quit_type = QuitType::kSoft);
|
/// the current app-mode provides one and the app is in gui mode.
|
||||||
|
/// Otherwise the quit will be immediate.
|
||||||
|
void QuitApp(bool confirm = false, QuitType quit_type = QuitType::kSoft);
|
||||||
|
|
||||||
/// Called when app shutdown process completes. Sets app to exit.
|
/// Called when app shutdown process completes. Sets app to exit.
|
||||||
void OnAppShutdownComplete();
|
void OnAppShutdownComplete();
|
||||||
@ -657,14 +647,6 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
|||||||
|
|
||||||
void set_classic(ClassicSoftInterface* classic);
|
void set_classic(ClassicSoftInterface* classic);
|
||||||
|
|
||||||
/// Try to load the ui_v1 feature-set and return whether it is available.
|
|
||||||
auto HaveUIV1() -> bool;
|
|
||||||
|
|
||||||
/// Access the ui_v1 feature-set. Will throw an exception if not present.
|
|
||||||
auto ui_v1() -> UIV1SoftInterface*;
|
|
||||||
|
|
||||||
void set_ui_v1(UIV1SoftInterface* ui_v1);
|
|
||||||
|
|
||||||
/// Return a string that should be universally unique to this particular
|
/// Return a string that should be universally unique to this particular
|
||||||
/// running instance of the app.
|
/// running instance of the app.
|
||||||
auto GetAppInstanceUUID() -> const std::string&;
|
auto GetAppInstanceUUID() -> const std::string&;
|
||||||
@ -686,6 +668,7 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
|||||||
auto InAudioThread() const -> bool override;
|
auto InAudioThread() const -> bool override;
|
||||||
auto InBGDynamicsThread() const -> bool override;
|
auto InBGDynamicsThread() const -> bool override;
|
||||||
auto InNetworkWriteThread() const -> bool override;
|
auto InNetworkWriteThread() const -> bool override;
|
||||||
|
auto InGraphicsContext() const -> bool override;
|
||||||
|
|
||||||
/// 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;
|
||||||
@ -755,9 +738,10 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
|||||||
Utils* const utils;
|
Utils* const utils;
|
||||||
|
|
||||||
// Variable subsystems.
|
// Variable subsystems.
|
||||||
auto* app_mode() const { return app_mode_; }
|
|
||||||
auto* stress_test() const { return stress_test_; }
|
|
||||||
void set_app_mode(AppMode* mode);
|
void set_app_mode(AppMode* mode);
|
||||||
|
auto* app_mode() const { return app_mode_; }
|
||||||
|
|
||||||
|
auto* stress_test() const { return stress_test_; }
|
||||||
|
|
||||||
/// Whether we're running under ballisticakit_server.py
|
/// Whether we're running under ballisticakit_server.py
|
||||||
/// (affects some app behavior).
|
/// (affects some app behavior).
|
||||||
@ -781,7 +765,6 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
|||||||
AppMode* app_mode_;
|
AppMode* app_mode_;
|
||||||
PlusSoftInterface* plus_soft_{};
|
PlusSoftInterface* plus_soft_{};
|
||||||
ClassicSoftInterface* classic_soft_{};
|
ClassicSoftInterface* classic_soft_{};
|
||||||
UIV1SoftInterface* ui_v1_soft_{};
|
|
||||||
StressTest* stress_test_;
|
StressTest* stress_test_;
|
||||||
|
|
||||||
std::mutex shutdown_suppress_lock_;
|
std::mutex shutdown_suppress_lock_;
|
||||||
|
|||||||
@ -142,7 +142,7 @@ void BGDynamics::SetDrawSnapshot(BGDynamicsDrawSnapshot* s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BGDynamics::TooSlow() {
|
void BGDynamics::TooSlow() {
|
||||||
if (!EventLoop::AreEventLoopsPaused()) {
|
if (!EventLoop::AreEventLoopsSuspended()) {
|
||||||
g_base->bg_dynamics_server->PushTooSlowCall();
|
g_base->bg_dynamics_server->PushTooSlowCall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -691,7 +691,7 @@ BGDynamicsServer::BGDynamicsServer()
|
|||||||
void BGDynamicsServer::OnMainThreadStartApp() {
|
void BGDynamicsServer::OnMainThreadStartApp() {
|
||||||
// Spin up our thread.
|
// Spin up our thread.
|
||||||
event_loop_ = new EventLoop(EventLoopID::kBGDynamics);
|
event_loop_ = new EventLoop(EventLoopID::kBGDynamics);
|
||||||
g_core->pausable_event_loops.push_back(event_loop_);
|
g_core->suspendable_event_loops.push_back(event_loop_);
|
||||||
}
|
}
|
||||||
|
|
||||||
BGDynamicsServer::Tendril::~Tendril() {
|
BGDynamicsServer::Tendril::~Tendril() {
|
||||||
|
|||||||
@ -14,8 +14,8 @@ namespace ballistica::base {
|
|||||||
// Base class for fragment/vertex shaders.
|
// Base class for fragment/vertex shaders.
|
||||||
class RendererGL::ShaderGL : public Object {
|
class RendererGL::ShaderGL : public Object {
|
||||||
public:
|
public:
|
||||||
auto GetDefaultOwnerThread() const -> EventLoopID override {
|
auto GetThreadOwnership() const -> ThreadOwnership override {
|
||||||
return EventLoopID::kMain;
|
return ThreadOwnership::kGraphicsContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderGL(GLenum type_in, const std::string& src_in) : type_(type_in) {
|
ShaderGL(GLenum type_in, const std::string& src_in) : type_(type_in) {
|
||||||
|
|||||||
@ -2080,7 +2080,7 @@ void RendererGL::ProcessRenderCommandBuffer(RenderCommandBuffer* buffer,
|
|||||||
}
|
}
|
||||||
case RenderCommandBuffer::Command::kCursorTranslate: {
|
case RenderCommandBuffer::Command::kCursorTranslate: {
|
||||||
float x, y;
|
float x, y;
|
||||||
g_base->platform->GetCursorPosition(&x, &y);
|
g_base->app_adapter->CursorPositionForDraw(&x, &y);
|
||||||
g_base->graphics_server->Translate(Vector3f(x, y, 0));
|
g_base->graphics_server->Translate(Vector3f(x, y, 0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1452,11 +1452,11 @@ void Graphics::DrawCursor(FrameDef* frame_def) {
|
|||||||
|
|
||||||
millisecs_t app_time_millisecs = frame_def->app_time_millisecs();
|
millisecs_t app_time_millisecs = frame_def->app_time_millisecs();
|
||||||
|
|
||||||
bool can_show_cursor = g_core->platform->IsRunningOnDesktop();
|
bool can_show_cursor = g_base->app_adapter->ShouldUseCursor();
|
||||||
bool should_show_cursor =
|
bool should_show_cursor =
|
||||||
camera_->manual() || g_base->input->IsCursorVisible();
|
camera_->manual() || g_base->input->IsCursorVisible();
|
||||||
|
|
||||||
if (g_buildconfig.hardware_cursor()) {
|
if (g_base->app_adapter->HasHardwareCursor()) {
|
||||||
// If we're using a hardware cursor, ship hardware cursor visibility
|
// If we're using a hardware cursor, ship hardware cursor visibility
|
||||||
// updates to the app thread periodically.
|
// updates to the app thread periodically.
|
||||||
bool new_cursor_visibility = false;
|
bool new_cursor_visibility = false;
|
||||||
@ -1472,7 +1472,7 @@ void Graphics::DrawCursor(FrameDef* frame_def) {
|
|||||||
last_cursor_visibility_event_time_ = app_time_millisecs;
|
last_cursor_visibility_event_time_ = app_time_millisecs;
|
||||||
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->platform->SetHardwareCursorVisible(hardware_cursor_visible_);
|
g_base->app_adapter->SetHardwareCursorVisible(hardware_cursor_visible_);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1486,10 +1486,10 @@ void Graphics::DrawCursor(FrameDef* frame_def) {
|
|||||||
auto xf = c.ScopedTransform();
|
auto xf = c.ScopedTransform();
|
||||||
|
|
||||||
// Note: we don't plug in known cursor position values here; we tell the
|
// Note: we don't plug in known cursor position values here; we tell the
|
||||||
// renderer to insert the latest values on its end; this lessens cursor
|
// renderer to insert the latest values on its end; this can lessen
|
||||||
// lag substantially.
|
// cursor lag substantially.
|
||||||
c.CursorTranslate();
|
c.CursorTranslate();
|
||||||
c.Translate(csize * 0.44f, csize * -0.44f, kCursorZDepth);
|
c.Translate(csize * 0.40f, csize * -0.38f, kCursorZDepth);
|
||||||
c.Scale(csize, csize);
|
c.Scale(csize, csize);
|
||||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kImage1x1));
|
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kImage1x1));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,22 +2,9 @@
|
|||||||
|
|
||||||
#include "ballistica/base/graphics/graphics_server.h"
|
#include "ballistica/base/graphics/graphics_server.h"
|
||||||
|
|
||||||
// Kill this.
|
|
||||||
#include "ballistica/base/graphics/gl/renderer_gl.h"
|
|
||||||
|
|
||||||
// FIXME: clear out this conditional stuff.
|
|
||||||
#if BA_SDL_BUILD
|
|
||||||
#include "ballistica/base/app_adapter/app_adapter_sdl.h"
|
|
||||||
#else
|
|
||||||
#include "ballistica/base/app_adapter/app_adapter.h"
|
#include "ballistica/base/app_adapter/app_adapter.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "ballistica/base/assets/assets.h"
|
|
||||||
#include "ballistica/base/graphics/mesh/mesh_data.h"
|
|
||||||
#include "ballistica/base/graphics/renderer/renderer.h"
|
#include "ballistica/base/graphics/renderer/renderer.h"
|
||||||
#include "ballistica/base/graphics/support/frame_def.h"
|
|
||||||
#include "ballistica/base/logic/logic.h"
|
#include "ballistica/base/logic/logic.h"
|
||||||
#include "ballistica/core/platform/core_platform.h"
|
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
@ -83,7 +70,7 @@ auto GraphicsServer::WaitForRenderFrameDef_() -> FrameDef* {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the app is paused, never render.
|
// If the app is paused, never render.
|
||||||
if (g_base->app_adapter->app_paused()) {
|
if (g_base->app_adapter->app_suspended()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -264,16 +264,6 @@ class GraphicsServer {
|
|||||||
|
|
||||||
auto renderer_context_lost() const { return renderer_context_lost_; }
|
auto renderer_context_lost() const { return renderer_context_lost_; }
|
||||||
|
|
||||||
// auto fullscreen_enabled() const { return fullscreen_enabled_; }
|
|
||||||
|
|
||||||
// This doesn't actually toggle fullscreen. It is used to inform the game
|
|
||||||
// when fullscreen changes under it.
|
|
||||||
// auto set_fullscreen_enabled(bool fs) { fullscreen_enabled_ = fs; }
|
|
||||||
|
|
||||||
// #if BA_ENABLE_OPENGL
|
|
||||||
// auto gl_context() const -> GLContext* { return gl_context_.get(); }
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
auto graphics_quality_requested() const {
|
auto graphics_quality_requested() const {
|
||||||
return graphics_quality_requested_;
|
return graphics_quality_requested_;
|
||||||
}
|
}
|
||||||
@ -290,17 +280,8 @@ class GraphicsServer {
|
|||||||
|
|
||||||
auto texture_quality_requested() const { return texture_quality_requested_; }
|
auto texture_quality_requested() const { return texture_quality_requested_; }
|
||||||
|
|
||||||
// auto initial_screen_created() const { return initial_screen_created_; }
|
|
||||||
|
|
||||||
void HandlePushAndroidRes(const std::string& android_res);
|
void HandlePushAndroidRes(const std::string& android_res);
|
||||||
|
|
||||||
// void HandleFullContextScreenRebuild(
|
|
||||||
// bool need_full_context_rebuild, bool fullscreen,
|
|
||||||
// GraphicsQualityRequest graphics_quality_requested,
|
|
||||||
// TextureQualityRequest texture_quality_requested);
|
|
||||||
// void HandleFullscreenToggling(bool do_set_existing_fs, bool do_toggle_fs,
|
|
||||||
// bool fullscreen);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// 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;
|
||||||
@ -332,53 +313,49 @@ class GraphicsServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float res_x_{};
|
bool renderer_loaded_ : 1 {};
|
||||||
float res_y_{};
|
bool v_sync_ : 1 {};
|
||||||
float res_x_virtual_{};
|
bool auto_vsync_ : 1 {};
|
||||||
float res_y_virtual_{};
|
bool model_view_projection_matrix_dirty_ : 1 {true};
|
||||||
uint32_t texture_compression_types_{};
|
bool model_world_matrix_dirty_ : 1 {true};
|
||||||
|
bool graphics_quality_set_ : 1 {};
|
||||||
|
bool texture_quality_set_ : 1 {};
|
||||||
|
bool tv_border_ : 1 {};
|
||||||
|
bool renderer_context_lost_ : 1 {};
|
||||||
|
bool texture_compression_types_set_ : 1 {};
|
||||||
|
bool cam_orient_matrix_dirty_ : 1 {true};
|
||||||
TextureQualityRequest texture_quality_requested_{
|
TextureQualityRequest texture_quality_requested_{
|
||||||
TextureQualityRequest::kUnset};
|
TextureQualityRequest::kUnset};
|
||||||
TextureQuality texture_quality_{TextureQuality::kLow};
|
TextureQuality texture_quality_{TextureQuality::kLow};
|
||||||
GraphicsQualityRequest graphics_quality_requested_{
|
GraphicsQualityRequest graphics_quality_requested_{
|
||||||
GraphicsQualityRequest::kUnset};
|
GraphicsQualityRequest::kUnset};
|
||||||
GraphicsQuality graphics_quality_{GraphicsQuality::kUnset};
|
GraphicsQuality graphics_quality_{GraphicsQuality::kUnset};
|
||||||
// bool fullscreen_enabled_{};
|
int render_hold_{};
|
||||||
// float target_res_x_{800.0f};
|
float res_x_{};
|
||||||
// float target_res_y_{600.0f};
|
float res_y_{};
|
||||||
|
float res_x_virtual_{};
|
||||||
|
float res_y_virtual_{};
|
||||||
Matrix44f model_view_matrix_{kMatrix44fIdentity};
|
Matrix44f model_view_matrix_{kMatrix44fIdentity};
|
||||||
Matrix44f view_world_matrix_{kMatrix44fIdentity};
|
Matrix44f view_world_matrix_{kMatrix44fIdentity};
|
||||||
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_;
|
std::vector<Matrix44f> model_view_stack_;
|
||||||
|
uint32_t texture_compression_types_{};
|
||||||
uint32_t projection_matrix_state_{1};
|
uint32_t projection_matrix_state_{1};
|
||||||
uint32_t model_view_projection_matrix_state_{1};
|
uint32_t model_view_projection_matrix_state_{1};
|
||||||
uint32_t model_world_matrix_state_{1};
|
uint32_t model_world_matrix_state_{1};
|
||||||
Matrix44f light_shadow_projection_matrix_{kMatrix44fIdentity};
|
|
||||||
uint32_t light_shadow_projection_matrix_state_{1};
|
uint32_t light_shadow_projection_matrix_state_{1};
|
||||||
|
uint32_t cam_pos_state_{1};
|
||||||
|
uint32_t cam_orient_matrix_state_{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};
|
||||||
uint32_t cam_pos_state_{1};
|
Matrix44f light_shadow_projection_matrix_{kMatrix44fIdentity};
|
||||||
Matrix44f cam_orient_matrix_ = kMatrix44fIdentity;
|
Matrix44f cam_orient_matrix_ = kMatrix44fIdentity;
|
||||||
uint32_t cam_orient_matrix_state_{1};
|
|
||||||
std::list<MeshData*> mesh_datas_;
|
std::list<MeshData*> mesh_datas_;
|
||||||
Timer* render_timer_{};
|
Timer* render_timer_{};
|
||||||
Renderer* renderer_{};
|
Renderer* renderer_{};
|
||||||
FrameDef* frame_def_{};
|
FrameDef* frame_def_{};
|
||||||
// bool initial_screen_created_{};
|
|
||||||
bool renderer_loaded_{};
|
|
||||||
bool v_sync_{};
|
|
||||||
bool auto_vsync_{};
|
|
||||||
bool model_view_projection_matrix_dirty_{true};
|
|
||||||
bool model_world_matrix_dirty_{true};
|
|
||||||
bool graphics_quality_set_{};
|
|
||||||
bool texture_quality_set_{};
|
|
||||||
bool tv_border_{};
|
|
||||||
bool renderer_context_lost_{};
|
|
||||||
bool texture_compression_types_set_{};
|
|
||||||
bool cam_orient_matrix_dirty_{true};
|
|
||||||
int render_hold_{};
|
|
||||||
std::mutex frame_def_mutex_{};
|
std::mutex frame_def_mutex_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
#include "ballistica/base/graphics/mesh/nine_patch_mesh.h"
|
#include "ballistica/base/graphics/mesh/nine_patch_mesh.h"
|
||||||
|
|
||||||
#include "ballistica/shared/foundation/macros.h"
|
|
||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
|
|
||||||
NinePatchMesh::NinePatchMesh(float x, float y, float z, float width,
|
NinePatchMesh::NinePatchMesh(float x, float y, float z, float width,
|
||||||
|
|||||||
@ -9,8 +9,8 @@ namespace ballistica::base {
|
|||||||
|
|
||||||
class Framebuffer : public Object {
|
class Framebuffer : public Object {
|
||||||
public:
|
public:
|
||||||
auto GetDefaultOwnerThread() const -> EventLoopID override {
|
auto GetThreadOwnership() const -> ThreadOwnership override {
|
||||||
return EventLoopID::kMain;
|
return ThreadOwnership::kGraphicsContext;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -11,8 +11,8 @@ namespace ballistica::base {
|
|||||||
// Encapsulates framebuffers, main windows, etc.
|
// Encapsulates framebuffers, main windows, etc.
|
||||||
class RenderTarget : public Object {
|
class RenderTarget : public Object {
|
||||||
public:
|
public:
|
||||||
auto GetDefaultOwnerThread() const -> EventLoopID override {
|
auto GetThreadOwnership() const -> ThreadOwnership override {
|
||||||
return EventLoopID::kMain;
|
return ThreadOwnership::kGraphicsContext;
|
||||||
}
|
}
|
||||||
enum class Type { kScreen, kFramebuffer };
|
enum class Type { kScreen, kFramebuffer };
|
||||||
explicit RenderTarget(Type type);
|
explicit RenderTarget(Type type);
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "ballistica/base/graphics/texture/dds.h"
|
#include "ballistica/base/graphics/texture/dds.h"
|
||||||
|
|
||||||
#include "ballistica/core/core.h"
|
|
||||||
#include "ballistica/core/platform/core_platform.h"
|
#include "ballistica/core/platform/core_platform.h"
|
||||||
|
|
||||||
/* DDS loader written by Jon Watte 2002 */
|
/* DDS loader written by Jon Watte 2002 */
|
||||||
|
|||||||
@ -113,9 +113,6 @@ auto KeyboardInput::HandleKey(const SDL_Keysym* keysym, bool repeat, bool down)
|
|||||||
pass = true;
|
pass = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma ide diagnostic ignored "ConstantConditionsOC"
|
|
||||||
|
|
||||||
// if we're keyboard 1 we always send at least a key press event
|
// if we're keyboard 1 we always send at least a key press event
|
||||||
// along..
|
// along..
|
||||||
if (!parent_keyboard_input_ && !pass) {
|
if (!parent_keyboard_input_ && !pass) {
|
||||||
@ -123,8 +120,6 @@ auto KeyboardInput::HandleKey(const SDL_Keysym* keysym, bool repeat, bool down)
|
|||||||
pass = true;
|
pass = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pass) {
|
if (pass) {
|
||||||
|
|||||||
@ -15,7 +15,6 @@
|
|||||||
#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"
|
||||||
|
|
||||||
@ -26,10 +25,10 @@ Input::Input() = default;
|
|||||||
void Input::PushCreateKeyboardInputDevices() {
|
void Input::PushCreateKeyboardInputDevices() {
|
||||||
assert(g_base->logic->event_loop());
|
assert(g_base->logic->event_loop());
|
||||||
g_base->logic->event_loop()->PushCall(
|
g_base->logic->event_loop()->PushCall(
|
||||||
[this] { CreateKeyboardInputDevices(); });
|
[this] { CreateKeyboardInputDevices_(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::CreateKeyboardInputDevices() {
|
void Input::CreateKeyboardInputDevices_() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
if (keyboard_input_ != nullptr || keyboard_input_2_ != nullptr) {
|
if (keyboard_input_ != nullptr || keyboard_input_2_ != nullptr) {
|
||||||
Log(LogLevel::kError,
|
Log(LogLevel::kError,
|
||||||
@ -45,10 +44,10 @@ void Input::CreateKeyboardInputDevices() {
|
|||||||
void Input::PushDestroyKeyboardInputDevices() {
|
void Input::PushDestroyKeyboardInputDevices() {
|
||||||
assert(g_base->logic->event_loop());
|
assert(g_base->logic->event_loop());
|
||||||
g_base->logic->event_loop()->PushCall(
|
g_base->logic->event_loop()->PushCall(
|
||||||
[this] { DestroyKeyboardInputDevices(); });
|
[this] { DestroyKeyboardInputDevices_(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::DestroyKeyboardInputDevices() {
|
void Input::DestroyKeyboardInputDevices_() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
if (keyboard_input_ == nullptr || keyboard_input_2_ == nullptr) {
|
if (keyboard_input_ == nullptr || keyboard_input_2_ == nullptr) {
|
||||||
Log(LogLevel::kError,
|
Log(LogLevel::kError,
|
||||||
@ -80,8 +79,8 @@ auto Input::GetInputDevice(const std::string& name,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Input::GetNewNumberedIdentifier(const std::string& name,
|
auto Input::GetNewNumberedIdentifier_(const std::string& name,
|
||||||
const std::string& identifier) -> int {
|
const std::string& identifier) -> int {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
// Stuff like reserved_identifiers["JoyStickType"]["0x812312314"] = 2;
|
// Stuff like reserved_identifiers["JoyStickType"]["0x812312314"] = 2;
|
||||||
@ -154,7 +153,7 @@ void Input::CreateTouchInput() {
|
|||||||
PushAddInputDeviceCall(touch_input_, false);
|
PushAddInputDeviceCall(touch_input_, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::AnnounceConnects() {
|
void Input::AnnounceConnects_() {
|
||||||
static bool first_print = true;
|
static bool first_print = true;
|
||||||
|
|
||||||
// For the first announcement just say "X controllers detected" and don't
|
// For the first announcement just say "X controllers detected" and don't
|
||||||
@ -205,7 +204,7 @@ void Input::AnnounceConnects() {
|
|||||||
newly_connected_controllers_.clear();
|
newly_connected_controllers_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::AnnounceDisconnects() {
|
void Input::AnnounceDisconnects_() {
|
||||||
// If there's been several connected, just give a number.
|
// If there's been several connected, just give a number.
|
||||||
if (newly_disconnected_controllers_.size() > 1) {
|
if (newly_disconnected_controllers_.size() > 1) {
|
||||||
std::string s =
|
std::string s =
|
||||||
@ -228,7 +227,7 @@ void Input::AnnounceDisconnects() {
|
|||||||
newly_disconnected_controllers_.clear();
|
newly_disconnected_controllers_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::ShowStandardInputDeviceConnectedMessage(InputDevice* j) {
|
void Input::ShowStandardInputDeviceConnectedMessage_(InputDevice* j) {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
std::string suffix;
|
std::string suffix;
|
||||||
suffix += j->GetPersistentIdentifier();
|
suffix += j->GetPersistentIdentifier();
|
||||||
@ -243,10 +242,10 @@ void Input::ShowStandardInputDeviceConnectedMessage(InputDevice* j) {
|
|||||||
g_base->logic->DeleteAppTimer(connect_print_timer_id_);
|
g_base->logic->DeleteAppTimer(connect_print_timer_id_);
|
||||||
}
|
}
|
||||||
connect_print_timer_id_ = g_base->logic->NewAppTimer(
|
connect_print_timer_id_ = g_base->logic->NewAppTimer(
|
||||||
250, false, NewLambdaRunnable([this] { AnnounceConnects(); }));
|
250, false, NewLambdaRunnable([this] { AnnounceConnects_(); }));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::ShowStandardInputDeviceDisconnectedMessage(InputDevice* j) {
|
void Input::ShowStandardInputDeviceDisconnectedMessage_(InputDevice* j) {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
newly_disconnected_controllers_.push_back(j->GetDeviceName() + " "
|
newly_disconnected_controllers_.push_back(j->GetDeviceName() + " "
|
||||||
@ -258,7 +257,7 @@ void Input::ShowStandardInputDeviceDisconnectedMessage(InputDevice* j) {
|
|||||||
g_base->logic->DeleteAppTimer(disconnect_print_timer_id_);
|
g_base->logic->DeleteAppTimer(disconnect_print_timer_id_);
|
||||||
}
|
}
|
||||||
disconnect_print_timer_id_ = g_base->logic->NewAppTimer(
|
disconnect_print_timer_id_ = g_base->logic->NewAppTimer(
|
||||||
250, false, NewLambdaRunnable([this] { AnnounceDisconnects(); }));
|
250, false, NewLambdaRunnable([this] { AnnounceDisconnects_(); }));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::PushAddInputDeviceCall(InputDevice* input_device,
|
void Input::PushAddInputDeviceCall(InputDevice* input_device,
|
||||||
@ -313,8 +312,8 @@ void Input::AddInputDevice(InputDevice* device, bool standard_message) {
|
|||||||
// or something, but if it doesn't and thus matches an already-existing one,
|
// or something, but if it doesn't and thus matches an already-existing one,
|
||||||
// we tack an index on to it. that way we can at least uniquely address them
|
// we tack an index on to it. that way we can at least uniquely address them
|
||||||
// based off how many are connected.
|
// based off how many are connected.
|
||||||
device->set_number(GetNewNumberedIdentifier(device->GetRawDeviceName(),
|
device->set_number(GetNewNumberedIdentifier_(device->GetRawDeviceName(),
|
||||||
device->GetDeviceIdentifier()));
|
device->GetDeviceIdentifier()));
|
||||||
|
|
||||||
// Let the device know it's been added (for custom announcements, etc.)
|
// Let the device know it's been added (for custom announcements, etc.)
|
||||||
device->OnAdded();
|
device->OnAdded();
|
||||||
@ -327,7 +326,7 @@ void Input::AddInputDevice(InputDevice* device, bool standard_message) {
|
|||||||
|
|
||||||
// Need to do this after updating controls, as some control settings can
|
// Need to do this after updating controls, as some control settings can
|
||||||
// affect things we count (such as whether start activates default button).
|
// affect things we count (such as whether start activates default button).
|
||||||
UpdateInputDeviceCounts();
|
UpdateInputDeviceCounts_();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_buildconfig.ostype_macos()) {
|
if (g_buildconfig.ostype_macos()) {
|
||||||
@ -344,7 +343,7 @@ void Input::AddInputDevice(InputDevice* device, bool standard_message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (standard_message && !device->ShouldBeHiddenFromUser()) {
|
if (standard_message && !device->ShouldBeHiddenFromUser()) {
|
||||||
ShowStandardInputDeviceConnectedMessage(device);
|
ShowStandardInputDeviceConnectedMessage_(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,7 +359,7 @@ void Input::RemoveInputDevice(InputDevice* input, bool standard_message) {
|
|||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
if (standard_message && !input->ShouldBeHiddenFromUser()) {
|
if (standard_message && !input->ShouldBeHiddenFromUser()) {
|
||||||
ShowStandardInputDeviceDisconnectedMessage(input);
|
ShowStandardInputDeviceDisconnectedMessage_(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just look for it in our list.. if we find it, simply clear the ref
|
// Just look for it in our list.. if we find it, simply clear the ref
|
||||||
@ -380,14 +379,14 @@ void Input::RemoveInputDevice(InputDevice* input, bool standard_message) {
|
|||||||
|
|
||||||
// This should kill the device.
|
// This should kill the device.
|
||||||
device.Clear();
|
device.Clear();
|
||||||
UpdateInputDeviceCounts();
|
UpdateInputDeviceCounts_();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw Exception("Input::RemoveInputDevice: invalid device provided");
|
throw Exception("Input::RemoveInputDevice: invalid device provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::UpdateInputDeviceCounts() {
|
void Input::UpdateInputDeviceCounts_() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
auto current_time_millisecs =
|
auto current_time_millisecs =
|
||||||
@ -528,7 +527,7 @@ auto Input::ShouldCompletelyIgnoreInputDevice(InputDevice* input_device)
|
|||||||
return ignore_sdl_controllers_ && input_device->IsSDLController();
|
return ignore_sdl_controllers_ && input_device->IsSDLController();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::UpdateEnabledControllerSubsystems() {
|
void Input::UpdateEnabledControllerSubsystems_() {
|
||||||
assert(g_base);
|
assert(g_base);
|
||||||
|
|
||||||
// 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
|
||||||
@ -566,7 +565,7 @@ void Input::OnAppShutdownComplete() { assert(g_base->InLogicThread()); }
|
|||||||
void Input::DoApplyAppConfig() {
|
void Input::DoApplyAppConfig() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
UpdateEnabledControllerSubsystems();
|
UpdateEnabledControllerSubsystems_();
|
||||||
|
|
||||||
// It's technically possible that updating these controls will add or
|
// It's technically possible that updating these controls will add or
|
||||||
// remove devices, thus changing the input_devices_ list, so lets work
|
// remove devices, thus changing the input_devices_ list, so lets work
|
||||||
@ -579,7 +578,7 @@ void Input::DoApplyAppConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Some config settings can affect this.
|
// Some config settings can affect this.
|
||||||
UpdateInputDeviceCounts();
|
UpdateInputDeviceCounts_();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::OnScreenSizeChange() { assert(g_base->InLogicThread()); }
|
void Input::OnScreenSizeChange() { assert(g_base->InLogicThread()); }
|
||||||
@ -595,7 +594,7 @@ void Input::StepDisplayTime() {
|
|||||||
Log(LogLevel::kError,
|
Log(LogLevel::kError,
|
||||||
"Input has been temp-locked for 10 seconds; unlocking.");
|
"Input has been temp-locked for 10 seconds; unlocking.");
|
||||||
input_lock_count_temp_ = 0;
|
input_lock_count_temp_ = 0;
|
||||||
PrintLockLabels();
|
PrintLockLabels_();
|
||||||
input_lock_temp_labels_.clear();
|
input_lock_temp_labels_.clear();
|
||||||
input_unlock_temp_labels_.clear();
|
input_unlock_temp_labels_.clear();
|
||||||
}
|
}
|
||||||
@ -610,7 +609,7 @@ void Input::StepDisplayTime() {
|
|||||||
// now.
|
// now.
|
||||||
millisecs_t incr = 249;
|
millisecs_t incr = 249;
|
||||||
if (real_time - last_input_device_count_update_time_ > incr) {
|
if (real_time - last_input_device_count_update_time_ > incr) {
|
||||||
UpdateInputDeviceCounts();
|
UpdateInputDeviceCounts_();
|
||||||
last_input_device_count_update_time_ = real_time;
|
last_input_device_count_update_time_ = real_time;
|
||||||
|
|
||||||
// Keep our idle-time up to date.
|
// Keep our idle-time up to date.
|
||||||
@ -682,7 +681,7 @@ void Input::UnlockAllInput(bool permanent, const std::string& label) {
|
|||||||
input_unlock_permanent_labels_.push_back(label);
|
input_unlock_permanent_labels_.push_back(label);
|
||||||
if (input_lock_count_permanent_ < 0) {
|
if (input_lock_count_permanent_ < 0) {
|
||||||
BA_LOG_PYTHON_TRACE_ONCE("lock-count-permanent < 0");
|
BA_LOG_PYTHON_TRACE_ONCE("lock-count-permanent < 0");
|
||||||
PrintLockLabels();
|
PrintLockLabels_();
|
||||||
input_lock_count_permanent_ = 0;
|
input_lock_count_permanent_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -713,7 +712,7 @@ void Input::UnlockAllInput(bool permanent, const std::string& label) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::PrintLockLabels() {
|
void Input::PrintLockLabels_() {
|
||||||
std::string s = "INPUT LOCK REPORT (time="
|
std::string s = "INPUT LOCK REPORT (time="
|
||||||
+ std::to_string(g_core->GetAppTimeMillisecs()) + "):";
|
+ std::to_string(g_core->GetAppTimeMillisecs()) + "):";
|
||||||
int num;
|
int num;
|
||||||
@ -827,12 +826,12 @@ void Input::PushJoystickEvent(const SDL_Event& event,
|
|||||||
InputDevice* input_device) {
|
InputDevice* input_device) {
|
||||||
assert(g_base->logic->event_loop());
|
assert(g_base->logic->event_loop());
|
||||||
g_base->logic->event_loop()->PushCall([this, event, input_device] {
|
g_base->logic->event_loop()->PushCall([this, event, input_device] {
|
||||||
HandleJoystickEvent(event, input_device);
|
HandleJoystickEvent_(event, input_device);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::HandleJoystickEvent(const SDL_Event& event,
|
void Input::HandleJoystickEvent_(const SDL_Event& event,
|
||||||
InputDevice* input_device) {
|
InputDevice* input_device) {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
assert(input_device);
|
assert(input_device);
|
||||||
|
|
||||||
@ -859,16 +858,28 @@ void Input::HandleJoystickEvent(const SDL_Event& event,
|
|||||||
input_device->HandleSDLEvent(&event);
|
input_device->HandleSDLEvent(&event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Input::PushKeyPressEventSimple(int key) {
|
||||||
|
assert(g_base->logic->event_loop());
|
||||||
|
g_base->logic->event_loop()->PushCall(
|
||||||
|
[this, key] { HandleKeyPressSimple_(key); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Input::PushKeyReleaseEventSimple(int key) {
|
||||||
|
assert(g_base->logic->event_loop());
|
||||||
|
g_base->logic->event_loop()->PushCall(
|
||||||
|
[this, key] { HandleKeyReleaseSimple_(key); });
|
||||||
|
}
|
||||||
|
|
||||||
void Input::PushKeyPressEvent(const SDL_Keysym& keysym) {
|
void Input::PushKeyPressEvent(const SDL_Keysym& keysym) {
|
||||||
assert(g_base->logic->event_loop());
|
assert(g_base->logic->event_loop());
|
||||||
g_base->logic->event_loop()->PushCall(
|
g_base->logic->event_loop()->PushCall(
|
||||||
[this, keysym] { HandleKeyPress(&keysym); });
|
[this, keysym] { HandleKeyPress_(keysym); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::PushKeyReleaseEvent(const SDL_Keysym& keysym) {
|
void Input::PushKeyReleaseEvent(const SDL_Keysym& keysym) {
|
||||||
assert(g_base->logic->event_loop());
|
assert(g_base->logic->event_loop());
|
||||||
g_base->logic->event_loop()->PushCall(
|
g_base->logic->event_loop()->PushCall(
|
||||||
[this, keysym] { HandleKeyRelease(&keysym); });
|
[this, keysym] { HandleKeyRelease_(keysym); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::CaptureKeyboardInput(HandleKeyPressCall* press_call,
|
void Input::CaptureKeyboardInput(HandleKeyPressCall* press_call,
|
||||||
@ -900,7 +911,41 @@ void Input::ReleaseJoystickInput() {
|
|||||||
joystick_input_capture_ = nullptr;
|
joystick_input_capture_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
void Input::AddFakeMods_(SDL_Keysym* sym) {
|
||||||
|
// In cases where we are only passed simple keycodes, we fill in modifiers
|
||||||
|
// ourself by looking at currently held key states. This is less than
|
||||||
|
// ideal because modifier key states can fall out of sync in some cases
|
||||||
|
// but is generally 'good enough' for our minimal keyboard needs.
|
||||||
|
if (keys_held_.contains(SDLK_LCTRL) || keys_held_.contains(SDLK_RCTRL)) {
|
||||||
|
sym->mod |= KMOD_CTRL;
|
||||||
|
}
|
||||||
|
if (keys_held_.contains(SDLK_LSHIFT) || keys_held_.contains(SDLK_RSHIFT)) {
|
||||||
|
sym->mod |= KMOD_SHIFT;
|
||||||
|
}
|
||||||
|
if (keys_held_.contains(SDLK_LALT) || keys_held_.contains(SDLK_RALT)) {
|
||||||
|
sym->mod |= KMOD_ALT;
|
||||||
|
}
|
||||||
|
if (keys_held_.contains(SDLK_LGUI) || keys_held_.contains(SDLK_RGUI)) {
|
||||||
|
sym->mod |= KMOD_GUI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Input::HandleKeyPressSimple_(int keycode) {
|
||||||
|
SDL_Keysym keysym{};
|
||||||
|
keysym.sym = keycode;
|
||||||
|
AddFakeMods_(&keysym);
|
||||||
|
HandleKeyPress_(keysym);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Input::HandleKeyReleaseSimple_(int keycode) {
|
||||||
|
// See notes above.
|
||||||
|
SDL_Keysym keysym{};
|
||||||
|
keysym.sym = keycode;
|
||||||
|
AddFakeMods_(&keysym);
|
||||||
|
HandleKeyRelease_(keysym);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Input::HandleKeyPress_(const SDL_Keysym& keysym) {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
MarkInputActive();
|
MarkInputActive();
|
||||||
@ -912,7 +957,7 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
|||||||
|
|
||||||
// If someone is capturing these events, give them a crack at it.
|
// If someone is capturing these events, give them a crack at it.
|
||||||
if (keyboard_input_capture_press_) {
|
if (keyboard_input_capture_press_) {
|
||||||
if (keyboard_input_capture_press_(*keysym)) {
|
if (keyboard_input_capture_press_(keysym)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -920,19 +965,19 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
|||||||
// Regardless of what else we do, keep track of mod key states.
|
// Regardless of what else we do, keep track of mod key states.
|
||||||
// (for things like manual camera moves. For individual key presses
|
// (for things like manual camera moves. For individual key presses
|
||||||
// ideally we should use the modifiers bundled with the key presses)
|
// ideally we should use the modifiers bundled with the key presses)
|
||||||
UpdateModKeyStates(keysym, true);
|
UpdateModKeyStates_(&keysym, true);
|
||||||
|
|
||||||
bool repeat_press;
|
bool repeat_press;
|
||||||
if (keys_held_.count(keysym->sym) != 0) {
|
if (keys_held_.count(keysym.sym) != 0) {
|
||||||
repeat_press = true;
|
repeat_press = true;
|
||||||
} else {
|
} else {
|
||||||
repeat_press = false;
|
repeat_press = false;
|
||||||
keys_held_.insert(keysym->sym);
|
keys_held_.insert(keysym.sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mobile-specific stuff.
|
// Mobile-specific stuff.
|
||||||
if (g_buildconfig.ostype_ios_tvos() || g_buildconfig.ostype_android()) {
|
if (g_buildconfig.ostype_ios_tvos() || g_buildconfig.ostype_android()) {
|
||||||
switch (keysym->sym) {
|
switch (keysym.sym) {
|
||||||
// FIXME: See if this stuff is still necessary. Was this perhaps
|
// FIXME: See if this stuff is still necessary. Was this perhaps
|
||||||
// specifically to support the console?
|
// specifically to support the console?
|
||||||
case SDLK_DELETE:
|
case SDLK_DELETE:
|
||||||
@ -944,7 +989,7 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
|||||||
// them a TEXT_INPUT message with no string.. I made them resistant
|
// them a TEXT_INPUT message with no string.. I made them resistant
|
||||||
// to that case but wondering if we can take this out?
|
// to that case but wondering if we can take this out?
|
||||||
g_base->ui->SendWidgetMessage(
|
g_base->ui->SendWidgetMessage(
|
||||||
WidgetMessage(WidgetMessage::Type::kTextInput, keysym));
|
WidgetMessage(WidgetMessage::Type::kTextInput, &keysym));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -954,8 +999,8 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
|||||||
|
|
||||||
// Command-F or Control-F toggles full-screen if the app-adapter supports it.
|
// Command-F or Control-F toggles full-screen if the app-adapter supports it.
|
||||||
if (g_base->app_adapter->CanToggleFullscreen()) {
|
if (g_base->app_adapter->CanToggleFullscreen()) {
|
||||||
if (!repeat_press && keysym->sym == SDLK_f
|
if (!repeat_press && keysym.sym == SDLK_f
|
||||||
&& ((keysym->mod & KMOD_CTRL) || (keysym->mod & KMOD_GUI))) {
|
&& ((keysym.mod & KMOD_CTRL) || (keysym.mod & KMOD_GUI))) {
|
||||||
g_base->python->objs()
|
g_base->python->objs()
|
||||||
.Get(BasePython::ObjID::kToggleFullscreenCall)
|
.Get(BasePython::ObjID::kToggleFullscreenCall)
|
||||||
.Call();
|
.Call();
|
||||||
@ -963,24 +1008,24 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Control-Q quits. On Mac, the usual cmd-q gets handled by SDL/etc.
|
// Control-Q quits. On Mac, the usual Cmd-Q gets handled
|
||||||
// implicitly.
|
// by the app-adapter implicitly.
|
||||||
if (!repeat_press && keysym->sym == SDLK_q && (keysym->mod & KMOD_CTRL)) {
|
if (!repeat_press && keysym.sym == SDLK_q && (keysym.mod & KMOD_CTRL)) {
|
||||||
g_base->ui->ConfirmQuit();
|
g_base->QuitApp(true);
|
||||||
return;
|
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()) {
|
||||||
if (console->HandleKeyPress(keysym)) {
|
if (console->HandleKeyPress(&keysym)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ctrl-V or Cmd-V sends paste commands to any interested text fields.
|
// Ctrl-V or Cmd-V sends paste commands to any interested text fields.
|
||||||
// Command-Q or Control-Q quits.
|
// Command-Q or Control-Q quits.
|
||||||
if (!repeat_press && keysym->sym == SDLK_v
|
if (!repeat_press && keysym.sym == SDLK_v
|
||||||
&& ((keysym->mod & KMOD_CTRL) || (keysym->mod & KMOD_GUI))) {
|
&& ((keysym.mod & KMOD_CTRL) || (keysym.mod & KMOD_GUI))) {
|
||||||
g_base->ui->SendWidgetMessage(WidgetMessage(WidgetMessage::Type::kPaste));
|
g_base->ui->SendWidgetMessage(WidgetMessage(WidgetMessage::Type::kPaste));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -989,7 +1034,7 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
|||||||
|
|
||||||
// None of the following stuff accepts key repeats.
|
// None of the following stuff accepts key repeats.
|
||||||
if (!repeat_press) {
|
if (!repeat_press) {
|
||||||
switch (keysym->sym) {
|
switch (keysym.sym) {
|
||||||
// Menu button on android/etc. pops up the menu.
|
// Menu button on android/etc. pops up the menu.
|
||||||
case SDLK_MENU: {
|
case SDLK_MENU: {
|
||||||
if (!g_base->ui->MainMenuVisible()) {
|
if (!g_base->ui->MainMenuVisible()) {
|
||||||
@ -1001,14 +1046,14 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
|||||||
|
|
||||||
case SDLK_EQUALS:
|
case SDLK_EQUALS:
|
||||||
case SDLK_PLUS:
|
case SDLK_PLUS:
|
||||||
if (keysym->mod & KMOD_CTRL) {
|
if (keysym.mod & KMOD_CTRL) {
|
||||||
g_base->app_mode()->ChangeGameSpeed(1);
|
g_base->app_mode()->ChangeGameSpeed(1);
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_MINUS:
|
case SDLK_MINUS:
|
||||||
if (keysym->mod & KMOD_CTRL) {
|
if (keysym.mod & KMOD_CTRL) {
|
||||||
g_base->app_mode()->ChangeGameSpeed(-1);
|
g_base->app_mode()->ChangeGameSpeed(-1);
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
@ -1073,12 +1118,12 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
|||||||
// If we haven't claimed it, pass it along as potential player/widget input.
|
// If we haven't claimed it, pass it along as potential player/widget input.
|
||||||
if (!handled) {
|
if (!handled) {
|
||||||
if (keyboard_input_) {
|
if (keyboard_input_) {
|
||||||
keyboard_input_->HandleKey(keysym, repeat_press, true);
|
keyboard_input_->HandleKey(&keysym, repeat_press, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::HandleKeyRelease(const SDL_Keysym* keysym) {
|
void Input::HandleKeyRelease_(const SDL_Keysym& keysym) {
|
||||||
assert(g_base);
|
assert(g_base);
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
@ -1089,32 +1134,32 @@ void Input::HandleKeyRelease(const SDL_Keysym* keysym) {
|
|||||||
// In some cases we may receive duplicate key-release events (if a
|
// In some cases we may receive duplicate key-release events (if a
|
||||||
// keyboard reset was run, it deals out key releases, but then the
|
// keyboard reset was run, it deals out key releases, but then the
|
||||||
// keyboard driver issues them as well).
|
// keyboard driver issues them as well).
|
||||||
if (keys_held_.count(keysym->sym) == 0) {
|
if (keys_held_.count(keysym.sym) == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If someone is capturing these events, give them a crack at it.
|
// If someone is capturing these events, give them a crack at it.
|
||||||
if (keyboard_input_capture_release_) {
|
if (keyboard_input_capture_release_) {
|
||||||
(keyboard_input_capture_release_(*keysym));
|
(keyboard_input_capture_release_(keysym));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep track of mod key states for things like manual camera moves. For
|
// Keep track of mod key states for things like manual camera moves. For
|
||||||
// individual key presses ideally we should instead use modifiers bundled
|
// individual key presses ideally we should instead use modifiers bundled
|
||||||
// with the key press events.
|
// with the key press events.
|
||||||
UpdateModKeyStates(keysym, false);
|
UpdateModKeyStates_(&keysym, false);
|
||||||
|
|
||||||
keys_held_.erase(keysym->sym);
|
keys_held_.erase(keysym.sym);
|
||||||
|
|
||||||
if (g_base->ui->dev_console() != nullptr) {
|
if (g_base->ui->dev_console() != nullptr) {
|
||||||
g_base->ui->dev_console()->HandleKeyRelease(keysym);
|
g_base->ui->dev_console()->HandleKeyRelease(&keysym);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyboard_input_) {
|
if (keyboard_input_) {
|
||||||
keyboard_input_->HandleKey(keysym, false, false);
|
keyboard_input_->HandleKey(&keysym, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::UpdateModKeyStates(const SDL_Keysym* keysym, bool press) {
|
void Input::UpdateModKeyStates_(const SDL_Keysym* keysym, bool press) {
|
||||||
switch (keysym->sym) {
|
switch (keysym->sym) {
|
||||||
case SDLK_LCTRL:
|
case SDLK_LCTRL:
|
||||||
case SDLK_RCTRL: {
|
case SDLK_RCTRL: {
|
||||||
@ -1145,10 +1190,10 @@ void Input::UpdateModKeyStates(const SDL_Keysym* keysym, bool press) {
|
|||||||
void Input::PushMouseScrollEvent(const Vector2f& amount) {
|
void Input::PushMouseScrollEvent(const Vector2f& amount) {
|
||||||
assert(g_base->logic->event_loop());
|
assert(g_base->logic->event_loop());
|
||||||
g_base->logic->event_loop()->PushCall(
|
g_base->logic->event_loop()->PushCall(
|
||||||
[this, amount] { HandleMouseScroll(amount); });
|
[this, amount] { HandleMouseScroll_(amount); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::HandleMouseScroll(const Vector2f& amount) {
|
void Input::HandleMouseScroll_(const Vector2f& amount) {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
// If input is locked, allow it to mark us active but nothing more.
|
// If input is locked, allow it to mark us active but nothing more.
|
||||||
@ -1181,11 +1226,11 @@ void Input::PushSmoothMouseScrollEvent(const Vector2f& velocity,
|
|||||||
bool momentum) {
|
bool momentum) {
|
||||||
assert(g_base->logic->event_loop());
|
assert(g_base->logic->event_loop());
|
||||||
g_base->logic->event_loop()->PushCall([this, velocity, momentum] {
|
g_base->logic->event_loop()->PushCall([this, velocity, momentum] {
|
||||||
HandleSmoothMouseScroll(velocity, momentum);
|
HandleSmoothMouseScroll_(velocity, momentum);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::HandleSmoothMouseScroll(const Vector2f& velocity, bool momentum) {
|
void Input::HandleSmoothMouseScroll_(const Vector2f& velocity, bool momentum) {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
// If input is locked, allow it to mark us active but nothing more.
|
// If input is locked, allow it to mark us active but nothing more.
|
||||||
@ -1216,10 +1261,10 @@ void Input::HandleSmoothMouseScroll(const Vector2f& velocity, bool momentum) {
|
|||||||
void Input::PushMouseMotionEvent(const Vector2f& position) {
|
void Input::PushMouseMotionEvent(const Vector2f& position) {
|
||||||
assert(g_base->logic->event_loop());
|
assert(g_base->logic->event_loop());
|
||||||
g_base->logic->event_loop()->PushCall(
|
g_base->logic->event_loop()->PushCall(
|
||||||
[this, position] { HandleMouseMotion(position); });
|
[this, position] { HandleMouseMotion_(position); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::HandleMouseMotion(const Vector2f& position) {
|
void Input::HandleMouseMotion_(const Vector2f& position) {
|
||||||
assert(g_base);
|
assert(g_base);
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
@ -1266,10 +1311,10 @@ void Input::HandleMouseMotion(const Vector2f& position) {
|
|||||||
void Input::PushMouseDownEvent(int button, const Vector2f& position) {
|
void Input::PushMouseDownEvent(int button, const Vector2f& position) {
|
||||||
assert(g_base->logic->event_loop());
|
assert(g_base->logic->event_loop());
|
||||||
g_base->logic->event_loop()->PushCall(
|
g_base->logic->event_loop()->PushCall(
|
||||||
[this, button, position] { HandleMouseDown(button, position); });
|
[this, button, position] { HandleMouseDown_(button, position); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::HandleMouseDown(int button, const Vector2f& position) {
|
void Input::HandleMouseDown_(int button, const Vector2f& position) {
|
||||||
assert(g_base);
|
assert(g_base);
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
@ -1330,10 +1375,10 @@ void Input::HandleMouseDown(int button, const Vector2f& position) {
|
|||||||
void Input::PushMouseUpEvent(int button, const Vector2f& position) {
|
void Input::PushMouseUpEvent(int button, const Vector2f& position) {
|
||||||
assert(g_base->logic->event_loop());
|
assert(g_base->logic->event_loop());
|
||||||
g_base->logic->event_loop()->PushCall(
|
g_base->logic->event_loop()->PushCall(
|
||||||
[this, button, position] { HandleMouseUp(button, position); });
|
[this, button, position] { HandleMouseUp_(button, position); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::HandleMouseUp(int button, const Vector2f& position) {
|
void Input::HandleMouseUp_(int button, const Vector2f& position) {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
MarkInputActive();
|
MarkInputActive();
|
||||||
|
|
||||||
@ -1373,10 +1418,10 @@ void Input::HandleMouseUp(int button, const Vector2f& position) {
|
|||||||
|
|
||||||
void Input::PushTouchEvent(const TouchEvent& e) {
|
void Input::PushTouchEvent(const TouchEvent& e) {
|
||||||
assert(g_base->logic->event_loop());
|
assert(g_base->logic->event_loop());
|
||||||
g_base->logic->event_loop()->PushCall([e, this] { HandleTouchEvent(e); });
|
g_base->logic->event_loop()->PushCall([e, this] { HandleTouchEvent_(e); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::HandleTouchEvent(const TouchEvent& e) {
|
void Input::HandleTouchEvent_(const TouchEvent& e) {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
assert(g_base->graphics);
|
assert(g_base->graphics);
|
||||||
|
|
||||||
@ -1422,11 +1467,11 @@ void Input::HandleTouchEvent(const TouchEvent& e) {
|
|||||||
// mouse events which covers most UI stuff.
|
// mouse events 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.type == TouchEvent::Type::kMoved && e.touch == single_touch_) {
|
if (e.type == TouchEvent::Type::kMoved && e.touch == single_touch_) {
|
||||||
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;
|
||||||
@ -1434,7 +1479,7 @@ void Input::HandleTouchEvent(const TouchEvent& e) {
|
|||||||
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;
|
||||||
HandleMouseUp(SDL_BUTTON_LEFT, Vector2f(e.x, e.y));
|
HandleMouseUp_(SDL_BUTTON_LEFT, Vector2f(e.x, e.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we've got a touch input device, forward events along to it.
|
// If we've got a touch input device, forward events along to it.
|
||||||
@ -1460,7 +1505,7 @@ void Input::ResetKeyboardHeldKeys() {
|
|||||||
SDL_Keysym k;
|
SDL_Keysym k;
|
||||||
memset(&k, 0, sizeof(k));
|
memset(&k, 0, sizeof(k));
|
||||||
k.sym = (SDL_Keycode)(*keys_held_.begin());
|
k.sym = (SDL_Keycode)(*keys_held_.begin());
|
||||||
HandleKeyRelease(&k);
|
HandleKeyRelease_(k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -119,6 +119,8 @@ class Input {
|
|||||||
void CreateTouchInput();
|
void CreateTouchInput();
|
||||||
|
|
||||||
void PushTextInputEvent(const std::string& text);
|
void PushTextInputEvent(const std::string& text);
|
||||||
|
void PushKeyPressEventSimple(int keycode);
|
||||||
|
void PushKeyReleaseEventSimple(int keycode);
|
||||||
void PushKeyPressEvent(const SDL_Keysym& keysym);
|
void PushKeyPressEvent(const SDL_Keysym& keysym);
|
||||||
void PushKeyReleaseEvent(const SDL_Keysym& keysym);
|
void PushKeyReleaseEvent(const SDL_Keysym& keysym);
|
||||||
void PushMouseDownEvent(int button, const Vector2f& position);
|
void PushMouseDownEvent(int button, const Vector2f& position);
|
||||||
@ -152,27 +154,30 @@ class Input {
|
|||||||
void RebuildInputDeviceDelegates();
|
void RebuildInputDeviceDelegates();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateInputDeviceCounts();
|
void UpdateInputDeviceCounts_();
|
||||||
auto GetNewNumberedIdentifier(const std::string& name,
|
auto GetNewNumberedIdentifier_(const std::string& name,
|
||||||
const std::string& identifier) -> int;
|
const std::string& identifier) -> int;
|
||||||
void UpdateEnabledControllerSubsystems();
|
void UpdateEnabledControllerSubsystems_();
|
||||||
void AnnounceConnects();
|
void AnnounceConnects_();
|
||||||
void AnnounceDisconnects();
|
void AnnounceDisconnects_();
|
||||||
void HandleKeyPress(const SDL_Keysym* keysym);
|
void HandleKeyPressSimple_(int keycode);
|
||||||
void HandleKeyRelease(const SDL_Keysym* keysym);
|
void HandleKeyReleaseSimple_(int keycode);
|
||||||
void HandleMouseMotion(const Vector2f& position);
|
void HandleKeyPress_(const SDL_Keysym& keysym);
|
||||||
void HandleMouseDown(int button, const Vector2f& position);
|
void HandleKeyRelease_(const SDL_Keysym& keysym);
|
||||||
void HandleMouseUp(int button, const Vector2f& position);
|
void HandleMouseMotion_(const Vector2f& position);
|
||||||
void HandleMouseScroll(const Vector2f& amount);
|
void HandleMouseDown_(int button, const Vector2f& position);
|
||||||
void HandleSmoothMouseScroll(const Vector2f& velocity, bool momentum);
|
void HandleMouseUp_(int button, const Vector2f& position);
|
||||||
void HandleJoystickEvent(const SDL_Event& event, InputDevice* input_device);
|
void HandleMouseScroll_(const Vector2f& amount);
|
||||||
void HandleTouchEvent(const TouchEvent& e);
|
void HandleSmoothMouseScroll_(const Vector2f& velocity, bool momentum);
|
||||||
void ShowStandardInputDeviceConnectedMessage(InputDevice* j);
|
void HandleJoystickEvent_(const SDL_Event& event, InputDevice* input_device);
|
||||||
void ShowStandardInputDeviceDisconnectedMessage(InputDevice* j);
|
void HandleTouchEvent_(const TouchEvent& e);
|
||||||
void PrintLockLabels();
|
void ShowStandardInputDeviceConnectedMessage_(InputDevice* j);
|
||||||
void UpdateModKeyStates(const SDL_Keysym* keysym, bool press);
|
void ShowStandardInputDeviceDisconnectedMessage_(InputDevice* j);
|
||||||
void CreateKeyboardInputDevices();
|
void PrintLockLabels_();
|
||||||
void DestroyKeyboardInputDevices();
|
void UpdateModKeyStates_(const SDL_Keysym* keysym, bool press);
|
||||||
|
void CreateKeyboardInputDevices_();
|
||||||
|
void DestroyKeyboardInputDevices_();
|
||||||
|
void AddFakeMods_(SDL_Keysym* sym);
|
||||||
|
|
||||||
HandleKeyPressCall* keyboard_input_capture_press_{};
|
HandleKeyPressCall* keyboard_input_capture_press_{};
|
||||||
HandleKeyReleaseCall* keyboard_input_capture_release_{};
|
HandleKeyReleaseCall* keyboard_input_capture_release_{};
|
||||||
|
|||||||
@ -29,7 +29,7 @@ Logic::Logic() : display_timers_(new TimerList()) {
|
|||||||
void Logic::OnMainThreadStartApp() {
|
void Logic::OnMainThreadStartApp() {
|
||||||
// Spin up our logic thread and sit and wait for it to init.
|
// Spin up our logic thread and sit and wait for it to init.
|
||||||
event_loop_ = new EventLoop(EventLoopID::kLogic);
|
event_loop_ = new EventLoop(EventLoopID::kLogic);
|
||||||
g_core->pausable_event_loops.push_back(event_loop_);
|
g_core->suspendable_event_loops.push_back(event_loop_);
|
||||||
event_loop_->PushCallSynchronous([this] { OnAppStart(); });
|
event_loop_->PushCallSynchronous([this] { OnAppStart(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,9 +47,9 @@ void Logic::OnAppStart() {
|
|||||||
event_loop_->SetAcquiresPythonGIL();
|
event_loop_->SetAcquiresPythonGIL();
|
||||||
|
|
||||||
// Stay informed when our event loop is pausing/unpausing.
|
// Stay informed when our event loop is pausing/unpausing.
|
||||||
event_loop_->AddPauseCallback(
|
event_loop_->AddSuspendCallback(
|
||||||
NewLambdaRunnableUnmanaged([this] { OnAppPause(); }));
|
NewLambdaRunnableUnmanaged([this] { OnAppPause(); }));
|
||||||
event_loop_->AddResumeCallback(
|
event_loop_->AddUnsuspendCallback(
|
||||||
NewLambdaRunnableUnmanaged([this] { OnAppResume(); }));
|
NewLambdaRunnableUnmanaged([this] { OnAppResume(); }));
|
||||||
|
|
||||||
// Running in a specific order here and should try to stick to it in
|
// Running in a specific order here and should try to stick to it in
|
||||||
@ -454,7 +454,7 @@ void Logic::UpdateDisplayTimeForFrameDraw() {
|
|||||||
// look like the game is slowing down or speeding up.
|
// look like the game is slowing down or speeding up.
|
||||||
|
|
||||||
// Flip debug-log-display-time on to debug this stuff.
|
// Flip debug-log-display-time on to debug this stuff.
|
||||||
// Things to look for:'
|
// Things to look for:
|
||||||
// - 'final' value should mostly stay constant.
|
// - 'final' value should mostly stay constant.
|
||||||
// - 'final' value should not be *too* far from 'current'.
|
// - 'final' value should not be *too* far from 'current'.
|
||||||
// - 'current' should mostly show '(avg)'; rarely '(sample)'.
|
// - 'current' should mostly show '(avg)'; rarely '(sample)'.
|
||||||
@ -484,51 +484,16 @@ void Logic::UpdateDisplayTimeForFrameDraw() {
|
|||||||
(recent_display_time_increments_index_ + 1) % kDisplayTimeSampleCount;
|
(recent_display_time_increments_index_ + 1) % kDisplayTimeSampleCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It seems that when things get thrown off it is often due to a single
|
|
||||||
// rogue sample being unusually long and often the next one being
|
|
||||||
// unusually short. Let's try to filter out some of these cases by
|
|
||||||
// ignoring both the longest and shortest sample in our set.
|
|
||||||
//
|
|
||||||
// SCRATCH THAT; we want to gracefully handle cases where vsync combined
|
|
||||||
// with target-framerate might give us crazy sample times like 5, 10, 5,
|
|
||||||
// 10, etc. So we can't expect filtering a single sample to help.
|
|
||||||
//
|
|
||||||
// int max_index{};
|
|
||||||
// int min_index{};
|
|
||||||
// double max_val{recent_display_time_increments_[0]};
|
|
||||||
// double min_val{recent_display_time_increments_[0]};
|
|
||||||
// for (int i = 0; i < kDisplayTimeSampleCount; ++i) {
|
|
||||||
// auto val = recent_display_time_increments_[i];
|
|
||||||
// if (val > max_val) {
|
|
||||||
// max_val = val;
|
|
||||||
// max_index = i;
|
|
||||||
// }
|
|
||||||
// if (val < min_val) {
|
|
||||||
// min_val = val;
|
|
||||||
// min_index = i;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
double avg{};
|
double avg{};
|
||||||
double min{};
|
double min, max;
|
||||||
double max{};
|
min = max = recent_display_time_increments_[0];
|
||||||
int count{};
|
|
||||||
for (int i = 0; i < kDisplayTimeSampleCount; ++i) {
|
for (int i = 0; i < kDisplayTimeSampleCount; ++i) {
|
||||||
// if (i == min_index || i == max_index) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
auto val = recent_display_time_increments_[i];
|
auto val = recent_display_time_increments_[i];
|
||||||
if (count == 0) {
|
|
||||||
// We may have skipped first index(es) so need to do this here
|
|
||||||
// instead of initing min/max to first value.
|
|
||||||
min = max = val;
|
|
||||||
}
|
|
||||||
avg += val;
|
avg += val;
|
||||||
min = std::min(min, val);
|
min = std::min(min, val);
|
||||||
max = std::max(max, val);
|
max = std::max(max, val);
|
||||||
count += 1;
|
|
||||||
}
|
}
|
||||||
avg /= count;
|
avg /= kDisplayTimeSampleCount;
|
||||||
double range = max - min;
|
double range = max - min;
|
||||||
|
|
||||||
// If our range of recent increment values is somewhat large relative to
|
// If our range of recent increment values is somewhat large relative to
|
||||||
@ -541,19 +506,16 @@ void Logic::UpdateDisplayTimeForFrameDraw() {
|
|||||||
// the lower chaos will be and thus the more the engine will stick to
|
// the lower chaos will be and thus the more the engine will stick to
|
||||||
// smoothed values. A good way to determine if this value is too high is
|
// smoothed values. A good way to determine if this value is too high is
|
||||||
// to launch the game and watch the menu animation. If it visibly speeds
|
// to launch the game and watch the menu animation. If it visibly speeds
|
||||||
// up or slows down in the moment after launch, it means the value is
|
// up or slows down in a 'rubber band' looking way the moment after
|
||||||
// too high and the engine is sticking with smoothed values when it
|
// launch, it means the value is too high and the engine is sticking
|
||||||
// should instead be reacting immediately. So basically this value
|
// with smoothed values when it should instead be reacting immediately.
|
||||||
// should be as high as possible while avoiding that look.
|
// So basically this value should be as high as possible while avoiding
|
||||||
|
// that look.
|
||||||
double chaos_fudge{1.25};
|
double chaos_fudge{1.25};
|
||||||
double chaos = (range / avg) / chaos_fudge;
|
double chaos = (range / avg) / chaos_fudge;
|
||||||
bool use_avg = chaos < 1.0;
|
bool use_avg = chaos < 1.0;
|
||||||
auto used = use_avg ? avg : this_increment;
|
auto used = use_avg ? avg : this_increment;
|
||||||
|
|
||||||
// double chaos = 0.0;
|
|
||||||
// bool use_avg = true;
|
|
||||||
// auto used = use_avg ? avg : this_increment;
|
|
||||||
|
|
||||||
// Lastly use this 'used' value to update our actual increment - our
|
// Lastly use this 'used' value to update our actual increment - our
|
||||||
// increment moves only if 'used' value gets farther than [trail_buffer]
|
// increment moves only if 'used' value gets farther than [trail_buffer]
|
||||||
// from it. So ideally it will sit in the middle of the smoothed value
|
// from it. So ideally it will sit in the middle of the smoothed value
|
||||||
@ -595,6 +557,7 @@ void Logic::UpdateDisplayTimeForFrameDraw() {
|
|||||||
Log(LogLevel::kDebug, buffer);
|
Log(LogLevel::kDebug, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lastly, apply our updated increment value to our time.
|
// Lastly, apply our updated increment value to our time.
|
||||||
display_time_ += display_time_increment_;
|
display_time_ += display_time_increment_;
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ NetworkWriter::NetworkWriter() {}
|
|||||||
void NetworkWriter::OnMainThreadStartApp() {
|
void NetworkWriter::OnMainThreadStartApp() {
|
||||||
// Spin up our thread.
|
// Spin up our thread.
|
||||||
event_loop_ = new EventLoop(EventLoopID::kNetworkWrite);
|
event_loop_ = new EventLoop(EventLoopID::kNetworkWrite);
|
||||||
g_core->pausable_event_loops.push_back(event_loop_);
|
g_core->suspendable_event_loops.push_back(event_loop_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkWriter::PushSendToCall(const std::vector<uint8_t>& msg,
|
void NetworkWriter::PushSendToCall(const std::vector<uint8_t>& msg,
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
#include "ballistica/base/app_adapter/app_adapter.h"
|
#include "ballistica/base/app_adapter/app_adapter.h"
|
||||||
#include "ballistica/base/networking/network_reader.h"
|
#include "ballistica/base/networking/network_reader.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/networking/sockaddr.h"
|
#include "ballistica/shared/networking/sockaddr.h"
|
||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
|
|||||||
@ -62,14 +62,6 @@ void BasePlatformApple::DoOpenURL(const std::string& url) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePlatformApple::TerminateApp() {
|
|
||||||
#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && !BA_HEADLESS_BUILD
|
|
||||||
AppleUtils::TerminateApp();
|
|
||||||
#else
|
|
||||||
BasePlatform::TerminateApp();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// void BasePlatformApple::SetHardwareCursorVisible(bool visible) {
|
// void BasePlatformApple::SetHardwareCursorVisible(bool visible) {
|
||||||
// // Set our nifty custom hardware cursor on mac;
|
// // Set our nifty custom hardware cursor on mac;
|
||||||
// // otherwise fall back to default.
|
// // otherwise fall back to default.
|
||||||
|
|||||||
@ -16,12 +16,9 @@ class BasePlatformApple : public BasePlatform {
|
|||||||
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 TerminateApp() override;
|
|
||||||
|
|
||||||
void DoOpenURL(const std::string& url) override;
|
void DoOpenURL(const std::string& url) override;
|
||||||
|
|
||||||
// void SetHardwareCursorVisible(bool visible) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -245,20 +245,6 @@ void BasePlatform::SetupInterruptHandling() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePlatform::GetCursorPosition(float* x, float* y) {
|
|
||||||
assert(x && y);
|
|
||||||
|
|
||||||
// By default, just use our latest event-delivered cursor position;
|
|
||||||
// this should work everywhere though perhaps might not be most optimal.
|
|
||||||
if (g_base->input == nullptr) {
|
|
||||||
*x = 0.0f;
|
|
||||||
*y = 0.0f;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*x = g_base->input->cursor_pos_x();
|
|
||||||
*y = g_base->input->cursor_pos_y();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BasePlatform::OnMainThreadStartAppComplete() {}
|
void BasePlatform::OnMainThreadStartAppComplete() {}
|
||||||
|
|
||||||
void BasePlatform::OnAppStart() { assert(g_base->InLogicThread()); }
|
void BasePlatform::OnAppStart() { assert(g_base->InLogicThread()); }
|
||||||
@ -269,13 +255,6 @@ void BasePlatform::OnAppShutdownComplete() { assert(g_base->InLogicThread()); }
|
|||||||
void BasePlatform::OnScreenSizeChange() { assert(g_base->InLogicThread()); }
|
void BasePlatform::OnScreenSizeChange() { assert(g_base->InLogicThread()); }
|
||||||
void BasePlatform::DoApplyAppConfig() { assert(g_base->InLogicThread()); }
|
void BasePlatform::DoApplyAppConfig() { assert(g_base->InLogicThread()); }
|
||||||
|
|
||||||
void BasePlatform::TerminateApp() { exit(g_base->return_value()); }
|
|
||||||
|
|
||||||
auto BasePlatform::CanSoftQuit() -> bool { return false; }
|
|
||||||
auto BasePlatform::CanBackQuit() -> bool { return false; }
|
|
||||||
void BasePlatform::DoBackQuit() {}
|
|
||||||
void BasePlatform::DoSoftQuit() {}
|
|
||||||
|
|
||||||
auto BasePlatform::HaveStringEditor() -> bool { return false; }
|
auto BasePlatform::HaveStringEditor() -> bool { return false; }
|
||||||
|
|
||||||
void BasePlatform::InvokeStringEditor(PyObject* string_edit_adapter) {
|
void BasePlatform::InvokeStringEditor(PyObject* string_edit_adapter) {
|
||||||
@ -322,11 +301,4 @@ void BasePlatform::DoInvokeStringEditor(const std::string& title,
|
|||||||
Log(LogLevel::kError, "FIXME: DoInvokeStringEditor() unimplemented");
|
Log(LogLevel::kError, "FIXME: DoInvokeStringEditor() unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePlatform::SetHardwareCursorVisible(bool visible) {
|
|
||||||
// FIXME: Move/forward this to AppAdapter.
|
|
||||||
#if BA_SDL_BUILD
|
|
||||||
SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -33,36 +33,6 @@ class BasePlatform {
|
|||||||
virtual void OnScreenSizeChange();
|
virtual void OnScreenSizeChange();
|
||||||
virtual void DoApplyAppConfig();
|
virtual void DoApplyAppConfig();
|
||||||
|
|
||||||
/// Return whether this platform supports soft-quit. A soft quit is
|
|
||||||
/// when the app is reset/backgrounded/etc. but remains running in case
|
|
||||||
/// needed again. Generally this is the behavior on mobile apps.
|
|
||||||
virtual auto CanSoftQuit() -> bool;
|
|
||||||
|
|
||||||
/// Implement soft-quit behavior. Will always be called in the logic
|
|
||||||
/// thread. Make sure to also override CanBackQuit to reflect this being
|
|
||||||
/// present. Note that when quitting the app yourself, you should use
|
|
||||||
/// g_base->QuitApp(); do not call this directly.
|
|
||||||
virtual void DoSoftQuit();
|
|
||||||
|
|
||||||
/// Return whether this platform supports back-quit. A back quit is a
|
|
||||||
/// variation of soft-quit generally triggered by a back button, which may
|
|
||||||
/// give different results in the OS. For example on Android this may
|
|
||||||
/// result in jumping back to the previous Android activity instead of
|
|
||||||
/// just ending the current one and dumping to the home screen as normal
|
|
||||||
/// soft quit might do.
|
|
||||||
virtual auto CanBackQuit() -> bool;
|
|
||||||
|
|
||||||
/// Implement back-quit behavior. Will always be called in the logic
|
|
||||||
/// thread. Make sure to also override CanBackQuit to reflect this being
|
|
||||||
/// present. Note that when quitting the app yourself, you should use
|
|
||||||
/// g_base->QuitApp(); do not call this directly.
|
|
||||||
virtual void DoBackQuit();
|
|
||||||
|
|
||||||
/// Terminate the app. This can be immediate or by posting some high
|
|
||||||
/// level event. There should be nothing left to do in the engine at
|
|
||||||
/// this point.
|
|
||||||
virtual void TerminateApp();
|
|
||||||
|
|
||||||
#pragma mark IN APP PURCHASES --------------------------------------------------
|
#pragma mark IN APP PURCHASES --------------------------------------------------
|
||||||
|
|
||||||
void Purchase(const std::string& item);
|
void Purchase(const std::string& item);
|
||||||
@ -116,12 +86,6 @@ class BasePlatform {
|
|||||||
/// Open the provided URL in a browser or whatnot.
|
/// Open the provided URL in a browser or whatnot.
|
||||||
void OpenURL(const std::string& url);
|
void OpenURL(const std::string& url);
|
||||||
|
|
||||||
/// Get the most up-to-date cursor position.
|
|
||||||
void GetCursorPosition(float* x, float* y);
|
|
||||||
|
|
||||||
/// Show/hide the hardware cursor.
|
|
||||||
virtual void SetHardwareCursorVisible(bool visible);
|
|
||||||
|
|
||||||
/// Should be called by platform StringEditor to apply a value.
|
/// Should be called by platform StringEditor to apply a value.
|
||||||
/// Must be called in the logic thread.
|
/// Must be called in the logic thread.
|
||||||
void StringEditorApply(const std::string& val);
|
void StringEditorApply(const std::string& val);
|
||||||
|
|||||||
@ -103,20 +103,20 @@ void BasePython::SoftImportClassic() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePython::SoftImportUIV1() {
|
// void BasePython::SoftImportUIV1() {
|
||||||
// To keep our init order clean, we want to root out any attempted uses
|
// // To keep our init order clean, we want to root out any attempted uses
|
||||||
// of this before _babase/babase has been fully imported.
|
// // of this before _babase/babase has been fully imported.
|
||||||
assert(g_base);
|
// assert(g_base);
|
||||||
assert(g_base->IsBaseCompletelyImported());
|
// assert(g_base->IsBaseCompletelyImported());
|
||||||
|
|
||||||
auto gil{Python::ScopedInterpreterLock()};
|
// auto gil{Python::ScopedInterpreterLock()};
|
||||||
auto result = PythonRef::StolenSoft(PyImport_ImportModule("_bauiv1"));
|
// auto result = PythonRef::StolenSoft(PyImport_ImportModule("_bauiv1"));
|
||||||
if (!result.Exists()) {
|
// if (!result.Exists()) {
|
||||||
// Ignore any errors here for now. All that will matter is whether plus
|
// // Ignore any errors here for now. All that will matter is whether plus
|
||||||
// gave us its interface.
|
// // gave us its interface.
|
||||||
PyErr_Clear();
|
// PyErr_Clear();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
void BasePython::ReadConfig() {
|
void BasePython::ReadConfig() {
|
||||||
auto gil{Python::ScopedInterpreterLock()};
|
auto gil{Python::ScopedInterpreterLock()};
|
||||||
@ -151,12 +151,12 @@ void BasePython::OnAppStart() {
|
|||||||
|
|
||||||
void BasePython::OnAppPause() {
|
void BasePython::OnAppPause() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
objs().Get(BasePython::ObjID::kAppOnNativePauseCall).Call();
|
objs().Get(BasePython::ObjID::kAppOnNativeSuspendCall).Call();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePython::OnAppResume() {
|
void BasePython::OnAppResume() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
objs().Get(BasePython::ObjID::kAppOnNativeResumeCall).Call();
|
objs().Get(BasePython::ObjID::kAppOnNativeUnsuspendCall).Call();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePython::OnAppShutdown() {
|
void BasePython::OnAppShutdown() {
|
||||||
@ -467,6 +467,10 @@ auto BasePython::GetPyEnum_TimeType(PyObject* obj) -> TimeType {
|
|||||||
return GetPyEnum<TimeType>(BasePython::ObjID::kTimeTypeClass, obj);
|
return GetPyEnum<TimeType>(BasePython::ObjID::kTimeTypeClass, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto BasePython::GetPyEnum_QuitType(PyObject* obj) -> QuitType {
|
||||||
|
return GetPyEnum<QuitType>(BasePython::ObjID::kQuitTypeClass, obj);
|
||||||
|
}
|
||||||
|
|
||||||
auto BasePython::GetPyEnum_TimeFormat(PyObject* obj) -> TimeFormat {
|
auto BasePython::GetPyEnum_TimeFormat(PyObject* obj) -> TimeFormat {
|
||||||
return GetPyEnum<TimeFormat>(BasePython::ObjID::kTimeFormatClass, obj);
|
return GetPyEnum<TimeFormat>(BasePython::ObjID::kTimeFormatClass, obj);
|
||||||
}
|
}
|
||||||
@ -479,6 +483,14 @@ auto BasePython::GetPyEnum_InputType(PyObject* obj) -> InputType {
|
|||||||
return GetPyEnum<InputType>(BasePython::ObjID::kInputTypeClass, obj);
|
return GetPyEnum<InputType>(BasePython::ObjID::kInputTypeClass, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(ericf): Make this a template.
|
||||||
|
auto BasePython::PyQuitType(QuitType val) -> PythonRef {
|
||||||
|
auto args = PythonRef::Stolen(Py_BuildValue("(d)", static_cast<int>(val)));
|
||||||
|
auto out = objs().Get(BasePython::ObjID::kQuitTypeClass).Call(args);
|
||||||
|
BA_PRECONDITION(out.Exists());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
auto BasePython::GetResource(const char* key, const char* fallback_resource,
|
auto BasePython::GetResource(const char* key, const char* fallback_resource,
|
||||||
const char* fallback_value) -> std::string {
|
const char* fallback_value) -> std::string {
|
||||||
assert(Python::HaveGIL());
|
assert(Python::HaveGIL());
|
||||||
|
|||||||
@ -70,8 +70,8 @@ class BasePython {
|
|||||||
kUIRemotePressCall,
|
kUIRemotePressCall,
|
||||||
kRemoveInGameAdsMessageCall,
|
kRemoveInGameAdsMessageCall,
|
||||||
kAppOnNativeStartCall,
|
kAppOnNativeStartCall,
|
||||||
kAppOnNativePauseCall,
|
kAppOnNativeSuspendCall,
|
||||||
kAppOnNativeResumeCall,
|
kAppOnNativeUnsuspendCall,
|
||||||
kAppOnNativeShutdownCall,
|
kAppOnNativeShutdownCall,
|
||||||
kAppOnNativeShutdownCompleteCall,
|
kAppOnNativeShutdownCompleteCall,
|
||||||
kQuitCall,
|
kQuitCall,
|
||||||
@ -88,6 +88,7 @@ class BasePython {
|
|||||||
kSessionNotFoundError,
|
kSessionNotFoundError,
|
||||||
kTimeFormatClass,
|
kTimeFormatClass,
|
||||||
kTimeTypeClass,
|
kTimeTypeClass,
|
||||||
|
kQuitTypeClass,
|
||||||
kInputTypeClass,
|
kInputTypeClass,
|
||||||
kPermissionClass,
|
kPermissionClass,
|
||||||
kSpecialCharClass,
|
kSpecialCharClass,
|
||||||
@ -151,6 +152,9 @@ class BasePython {
|
|||||||
static auto GetPyEnum_TimeFormat(PyObject* obj) -> TimeFormat;
|
static auto GetPyEnum_TimeFormat(PyObject* obj) -> TimeFormat;
|
||||||
static auto IsPyEnum_InputType(PyObject* obj) -> bool;
|
static auto IsPyEnum_InputType(PyObject* obj) -> bool;
|
||||||
static auto GetPyEnum_InputType(PyObject* obj) -> InputType;
|
static auto GetPyEnum_InputType(PyObject* obj) -> InputType;
|
||||||
|
static auto GetPyEnum_QuitType(PyObject* obj) -> QuitType;
|
||||||
|
|
||||||
|
auto PyQuitType(QuitType val) -> PythonRef;
|
||||||
|
|
||||||
auto CanPyStringEditAdapterBeReplaced(PyObject* o) -> bool;
|
auto CanPyStringEditAdapterBeReplaced(PyObject* o) -> bool;
|
||||||
|
|
||||||
@ -167,7 +171,7 @@ class BasePython {
|
|||||||
|
|
||||||
void SoftImportPlus();
|
void SoftImportPlus();
|
||||||
void SoftImportClassic();
|
void SoftImportClassic();
|
||||||
void SoftImportUIV1();
|
// void SoftImportUIV1();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::set<std::string> do_once_locations_;
|
std::set<std::string> do_once_locations_;
|
||||||
|
|||||||
@ -6,13 +6,11 @@
|
|||||||
#include "ballistica/base/app_mode/app_mode_empty.h"
|
#include "ballistica/base/app_mode/app_mode_empty.h"
|
||||||
#include "ballistica/base/graphics/graphics_server.h"
|
#include "ballistica/base/graphics/graphics_server.h"
|
||||||
#include "ballistica/base/logic/logic.h"
|
#include "ballistica/base/logic/logic.h"
|
||||||
#include "ballistica/base/platform/base_platform.h"
|
|
||||||
#include "ballistica/base/python/base_python.h"
|
#include "ballistica/base/python/base_python.h"
|
||||||
#include "ballistica/base/python/support/python_context_call_runnable.h"
|
#include "ballistica/base/python/support/python_context_call_runnable.h"
|
||||||
#include "ballistica/base/support/stress_test.h"
|
#include "ballistica/base/support/stress_test.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/core/platform/core_platform.h"
|
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
#include "ballistica/shared/foundation/logging.h"
|
#include "ballistica/shared/foundation/logging.h"
|
||||||
#include "ballistica/shared/python/python.h"
|
#include "ballistica/shared/python/python.h"
|
||||||
@ -511,26 +509,20 @@ static auto PyQuit(PyObject* self, PyObject* args, PyObject* keywds)
|
|||||||
BA_PYTHON_TRY;
|
BA_PYTHON_TRY;
|
||||||
BA_PRECONDITION(g_base->IsAppStarted());
|
BA_PRECONDITION(g_base->IsAppStarted());
|
||||||
|
|
||||||
static const char* kwlist[] = {"soft", "back", nullptr};
|
static const char* kwlist[] = {"confirm", "quit_type", nullptr};
|
||||||
int soft = 0;
|
QuitType quit_type = QuitType::kSoft;
|
||||||
int back = 0;
|
PyObject* quit_type_obj{Py_None};
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|pp",
|
int confirm{};
|
||||||
const_cast<char**>(kwlist), &soft, &back)) {
|
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|pO",
|
||||||
|
const_cast<char**>(kwlist), &confirm,
|
||||||
|
&quit_type_obj)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
QuitType quit_type{};
|
if (quit_type_obj != Py_None) {
|
||||||
if (back) {
|
quit_type = BasePython::GetPyEnum_QuitType(quit_type_obj);
|
||||||
if (!soft) {
|
|
||||||
Log(LogLevel::kWarning,
|
|
||||||
"Got soft=False back=True in quit() which is ambiguous.");
|
|
||||||
}
|
|
||||||
quit_type = QuitType::kBack;
|
|
||||||
} else if (soft) {
|
|
||||||
quit_type = QuitType::kSoft;
|
|
||||||
} else {
|
|
||||||
quit_type = QuitType::kHard;
|
|
||||||
}
|
}
|
||||||
g_base->QuitApp(quit_type);
|
|
||||||
|
g_base->QuitApp(confirm, quit_type);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
BA_PYTHON_CATCH;
|
BA_PYTHON_CATCH;
|
||||||
}
|
}
|
||||||
@ -540,18 +532,17 @@ static PyMethodDef PyQuitDef = {
|
|||||||
(PyCFunction)PyQuit, // method
|
(PyCFunction)PyQuit, // method
|
||||||
METH_VARARGS | METH_KEYWORDS, // flags
|
METH_VARARGS | METH_KEYWORDS, // flags
|
||||||
|
|
||||||
"quit(soft: bool = True, back: bool = False) -> None\n"
|
"quit(confirm: bool = False,\n"
|
||||||
|
" quit_type: babase.QuitType = babase.QuitType.SOFT\n"
|
||||||
|
") -> None\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Quit the app.\n"
|
"Quit the app.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Category: **General Utility Functions**\n"
|
"Category: **General Utility Functions**\n"
|
||||||
"\n"
|
"\n"
|
||||||
"On platforms such as mobile, a 'soft' quit may background and/or reset\n"
|
"If 'confirm' is True, a confirm dialog will be presented if conditions\n"
|
||||||
"the app but keep it running. A 'back' quit is a special form of soft\n"
|
"allow; otherwise the quit will still be immediate.\n"
|
||||||
"quit that may trigger different behavior in the OS. On Android, for\n"
|
"See docs for babase.QuitType for explanations of its behavior."};
|
||||||
"example, a back-quit may simply jump to the previous Android activity,\n"
|
|
||||||
"while a regular soft quit may just exit the current activity and dump\n"
|
|
||||||
"the user at their home screen."};
|
|
||||||
|
|
||||||
// ----------------------------- apply_config ----------------------------------
|
// ----------------------------- apply_config ----------------------------------
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "ballistica/base/assets/assets.h"
|
|
||||||
#include "ballistica/base/assets/sound_asset.h"
|
#include "ballistica/base/assets/sound_asset.h"
|
||||||
#include "ballistica/base/input/input.h"
|
#include "ballistica/base/input/input.h"
|
||||||
#include "ballistica/base/platform/base_platform.h"
|
#include "ballistica/base/platform/base_platform.h"
|
||||||
|
|||||||
@ -26,7 +26,7 @@ void StdioConsole::StartInMainThread() {
|
|||||||
|
|
||||||
// Spin up our thread.
|
// Spin up our thread.
|
||||||
event_loop_ = new EventLoop(EventLoopID::kStdin);
|
event_loop_ = new EventLoop(EventLoopID::kStdin);
|
||||||
g_core->pausable_event_loops.push_back(event_loop_);
|
g_core->suspendable_event_loops.push_back(event_loop_);
|
||||||
|
|
||||||
// Tell our thread to start reading.
|
// Tell our thread to start reading.
|
||||||
event_loop()->PushCall([this] {
|
event_loop()->PushCall([this] {
|
||||||
|
|||||||
@ -11,12 +11,8 @@
|
|||||||
#include "ballistica/base/logic/logic.h"
|
#include "ballistica/base/logic/logic.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/python/base_python.h"
|
||||||
#include "ballistica/base/support/context.h"
|
|
||||||
#include "ballistica/base/ui/ui.h"
|
#include "ballistica/base/ui/ui.h"
|
||||||
#include "ballistica/core/core.h"
|
|
||||||
#include "ballistica/core/platform/support/min_sdl.h"
|
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
#include "ballistica/shared/foundation/macros.h"
|
|
||||||
#include "ballistica/shared/generic/utils.h"
|
#include "ballistica/shared/generic/utils.h"
|
||||||
#include "ballistica/shared/python/python_command.h"
|
#include "ballistica/shared/python/python_command.h"
|
||||||
#include "ballistica/shared/python/python_sys.h"
|
#include "ballistica/shared/python/python_sys.h"
|
||||||
@ -102,20 +98,6 @@ static void DrawRect(RenderPass* pass, Mesh* mesh, float bottom, float x,
|
|||||||
c.Translate(x, y + bottom, kDevConsoleZDepth);
|
c.Translate(x, y + bottom, kDevConsoleZDepth);
|
||||||
c.DrawMesh(mesh);
|
c.DrawMesh(mesh);
|
||||||
}
|
}
|
||||||
// Draw text.
|
|
||||||
// {
|
|
||||||
// auto xf = c.ScopedTransform();
|
|
||||||
// c.Translate(x + width * 0.5f, y + bottom + height * 0.5f,
|
|
||||||
// kDevConsoleZDepth);
|
|
||||||
// c.Scale(tscale, tscale, 1.0f);
|
|
||||||
// int elem_count = tgrp->GetElementCount();
|
|
||||||
// c.SetColor(fgcolor.x, fgcolor.y, fgcolor.z, 1.0f);
|
|
||||||
// c.SetFlatness(1.0f);
|
|
||||||
// for (int e = 0; e < elem_count; e++) {
|
|
||||||
// c.SetTexture(tgrp->GetElementTexture(e));
|
|
||||||
// c.DrawMesh(tgrp->GetElementMesh(e));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawText(RenderPass* pass, TextGroup* tgrp, float tscale,
|
static void DrawText(RenderPass* pass, TextGroup* tgrp, float tscale,
|
||||||
|
|||||||
@ -7,12 +7,10 @@
|
|||||||
#include "ballistica/base/input/device/keyboard_input.h"
|
#include "ballistica/base/input/device/keyboard_input.h"
|
||||||
#include "ballistica/base/input/input.h"
|
#include "ballistica/base/input/input.h"
|
||||||
#include "ballistica/base/logic/logic.h"
|
#include "ballistica/base/logic/logic.h"
|
||||||
#include "ballistica/base/python/base_python.h"
|
|
||||||
#include "ballistica/base/support/app_config.h"
|
#include "ballistica/base/support/app_config.h"
|
||||||
#include "ballistica/base/support/ui_v1_soft.h"
|
|
||||||
#include "ballistica/base/ui/dev_console.h"
|
#include "ballistica/base/ui/dev_console.h"
|
||||||
|
#include "ballistica/base/ui/ui_delegate.h"
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
#include "ballistica/shared/foundation/inline.h"
|
|
||||||
#include "ballistica/shared/generic/utils.h"
|
#include "ballistica/shared/generic/utils.h"
|
||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
@ -59,9 +57,11 @@ void UI::StepDisplayTime() {
|
|||||||
void UI::OnAppStart() {
|
void UI::OnAppStart() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|
||||||
if (g_base->HaveUIV1()) {
|
// if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
g_base->ui_v1()->OnAppStart();
|
// printf("HAVE DEL %d\n",
|
||||||
}
|
// static_cast<int>(g_base->ui->delegate() != nullptr));
|
||||||
|
// g_base->ui_v1()->OnAppStart();
|
||||||
|
// }
|
||||||
|
|
||||||
// Make sure user knows when forced-ui-scale is enabled.
|
// Make sure user knows when forced-ui-scale is enabled.
|
||||||
if (force_scale_) {
|
if (force_scale_) {
|
||||||
@ -92,36 +92,36 @@ void UI::OnAppShutdownComplete() { assert(g_base->InLogicThread()); }
|
|||||||
|
|
||||||
void UI::DoApplyAppConfig() {
|
void UI::DoApplyAppConfig() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
g_base->ui_v1()->DoApplyAppConfig();
|
ui_delegate->DoApplyAppConfig();
|
||||||
}
|
}
|
||||||
show_dev_console_button_ =
|
show_dev_console_button_ =
|
||||||
g_base->app_config->Resolve(AppConfig::BoolID::kShowDevConsoleButton);
|
g_base->app_config->Resolve(AppConfig::BoolID::kShowDevConsoleButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto UI::MainMenuVisible() const -> bool {
|
auto UI::MainMenuVisible() const -> bool {
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
return g_base->ui_v1()->MainMenuVisible();
|
return ui_delegate->MainMenuVisible();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto UI::PartyIconVisible() -> bool {
|
auto UI::PartyIconVisible() -> bool {
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
return g_base->ui_v1()->PartyIconVisible();
|
return ui_delegate->PartyIconVisible();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI::ActivatePartyIcon() {
|
void UI::ActivatePartyIcon() {
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
g_base->ui_v1()->ActivatePartyIcon();
|
ui_delegate->ActivatePartyIcon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto UI::PartyWindowOpen() -> bool {
|
auto UI::PartyWindowOpen() -> bool {
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
return g_base->ui_v1()->PartyWindowOpen();
|
return ui_delegate->PartyWindowOpen();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -145,8 +145,10 @@ auto UI::HandleMouseDown(int button, float x, float y, bool double_click)
|
|||||||
handled = dev_console_->HandleMouseDown(button, x, y);
|
handled = dev_console_->HandleMouseDown(button, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handled && g_base->HaveUIV1()) {
|
if (!handled) {
|
||||||
handled = g_base->ui_v1()->HandleLegacyRootUIMouseDown(x, y);
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
|
handled = ui_delegate->HandleLegacyRootUIMouseDown(x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handled) {
|
if (!handled) {
|
||||||
@ -176,8 +178,8 @@ void UI::HandleMouseUp(int button, float x, float y) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
g_base->ui_v1()->HandleLegacyRootUIMouseUp(x, y);
|
ui_delegate->HandleLegacyRootUIMouseUp(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,8 +207,8 @@ void UI::HandleMouseMotion(float x, float y) {
|
|||||||
SendWidgetMessage(
|
SendWidgetMessage(
|
||||||
WidgetMessage(WidgetMessage::Type::kMouseMove, nullptr, x, y));
|
WidgetMessage(WidgetMessage::Type::kMouseMove, nullptr, x, y));
|
||||||
|
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
g_base->ui_v1()->HandleLegacyRootUIMouseMotion(x, y);
|
ui_delegate->HandleLegacyRootUIMouseMotion(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,8 +234,8 @@ void UI::PushMainMenuPressCall(InputDevice* device) {
|
|||||||
|
|
||||||
void UI::MainMenuPress_(InputDevice* device) {
|
void UI::MainMenuPress_(InputDevice* device) {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
g_base->ui_v1()->DoHandleDeviceMenuPress(device);
|
ui_delegate->DoHandleDeviceMenuPress(device);
|
||||||
} else {
|
} else {
|
||||||
Log(LogLevel::kWarning,
|
Log(LogLevel::kWarning,
|
||||||
"UI::MainMenuPress called without ui_v1 present; unexpected.");
|
"UI::MainMenuPress called without ui_v1 present; unexpected.");
|
||||||
@ -250,8 +252,8 @@ void UI::SetUIInputDevice(InputDevice* input_device) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UI::Reset() {
|
void UI::Reset() {
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
g_base->ui_v1()->Reset();
|
ui_delegate->Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,21 +269,21 @@ auto UI::ShouldShowButtonShortcuts() const -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto UI::SendWidgetMessage(const WidgetMessage& m) -> int {
|
auto UI::SendWidgetMessage(const WidgetMessage& m) -> int {
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
return g_base->ui_v1()->SendWidgetMessage(m);
|
return ui_delegate->SendWidgetMessage(m);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI::OnScreenSizeChange() {
|
void UI::OnScreenSizeChange() {
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
g_base->ui_v1()->OnScreenSizeChange();
|
ui_delegate->OnScreenSizeChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI::LanguageChanged() {
|
void UI::LanguageChanged() {
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
g_base->ui_v1()->OnLanguageChange();
|
ui_delegate->OnLanguageChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,7 +315,9 @@ auto UI::GetWidgetForInput(InputDevice* input_device) -> ui_v1::Widget* {
|
|||||||
// events are received by that device for a long time, it is up for grabs
|
// events are received by that device for a long time, it is up for grabs
|
||||||
// to the next device that requests it.
|
// to the next device that requests it.
|
||||||
|
|
||||||
if (!g_base->HaveUIV1()) {
|
auto* ui_delegate = g_base->ui->delegate();
|
||||||
|
|
||||||
|
if (!ui_delegate) {
|
||||||
ret_val = nullptr;
|
ret_val = nullptr;
|
||||||
} else if ((GetUIInputDevice() == nullptr)
|
} else if ((GetUIInputDevice() == nullptr)
|
||||||
|| (input_device == GetUIInputDevice())
|
|| (input_device == GetUIInputDevice())
|
||||||
@ -325,7 +329,7 @@ auto UI::GetWidgetForInput(InputDevice* input_device) -> ui_v1::Widget* {
|
|||||||
// seconds ago to automatically own a newly created widget).
|
// seconds ago to automatically own a newly created widget).
|
||||||
last_input_device_use_time_ = time;
|
last_input_device_use_time_ = time;
|
||||||
ui_input_device_ = input_device;
|
ui_input_device_ = input_device;
|
||||||
ret_val = g_base->ui_v1()->GetRootWidget();
|
ret_val = ui_delegate->GetRootWidget();
|
||||||
} else {
|
} else {
|
||||||
// For rejected input devices, play error sounds sometimes so they know
|
// For rejected input devices, play error sounds sometimes so they know
|
||||||
// they're not the chosen one.
|
// they're not the chosen one.
|
||||||
@ -382,8 +386,8 @@ auto UI::GetWidgetForInput(InputDevice* input_device) -> ui_v1::Widget* {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UI::Draw(FrameDef* frame_def) {
|
void UI::Draw(FrameDef* frame_def) {
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
g_base->ui_v1()->Draw(frame_def);
|
ui_delegate->Draw(frame_def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,40 +472,43 @@ void UI::DrawDevConsoleButton_(FrameDef* frame_def) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UI::ShowURL(const std::string& url) {
|
void UI::ShowURL(const std::string& url) {
|
||||||
if (g_base->HaveUIV1()) {
|
if (auto* ui_delegate = g_base->ui->delegate()) {
|
||||||
g_base->ui_v1()->DoShowURL(url);
|
ui_delegate->DoShowURL(url);
|
||||||
} else {
|
} else {
|
||||||
Log(LogLevel::kWarning,
|
Log(LogLevel::kWarning, "UI::ShowURL called without ui_delegate present.");
|
||||||
"UI::ShowURL called without g_ui_v1_soft present; unexpected.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI::ConfirmQuit() {
|
void UI::set_ui_delegate(base::UIDelegateInterface* delegate) {
|
||||||
g_base->logic->event_loop()->PushCall([this] {
|
assert(g_base->InLogicThread());
|
||||||
// If the in-app console is active, dismiss it.
|
|
||||||
if (dev_console_ != nullptr && dev_console_->IsActive()) {
|
|
||||||
dev_console_->Dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(g_base->InLogicThread());
|
if (delegate == delegate_) {
|
||||||
// If we're headless or we don't have ui-v1, just quit immediately; a
|
return;
|
||||||
// confirm screen wouldn't work anyway.
|
}
|
||||||
if (g_core->HeadlessMode() || g_base->input->IsInputLocked()
|
|
||||||
|| !g_base->HaveUIV1()) {
|
|
||||||
g_base->QuitApp();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
ScopedSetContext ssc(nullptr);
|
|
||||||
g_base->audio->PlaySound(g_base->assets->SysSound(SysSoundID::kSwish));
|
|
||||||
g_base->ui_v1()->DoQuitWindow();
|
|
||||||
|
|
||||||
// If we have a keyboard, give it UI ownership.
|
try {
|
||||||
InputDevice* keyboard = g_base->input->keyboard_input();
|
auto* old_delegate = delegate_;
|
||||||
if (keyboard) {
|
delegate_ = nullptr;
|
||||||
g_base->ui->SetUIInputDevice(keyboard);
|
if (old_delegate) {
|
||||||
}
|
old_delegate->OnDeactivate();
|
||||||
}
|
}
|
||||||
});
|
delegate_ = delegate;
|
||||||
|
if (delegate_) {
|
||||||
|
delegate_->OnActivate();
|
||||||
|
|
||||||
|
// Inform them that a few things changed, since they might have since
|
||||||
|
// the last time they were active (these callbacks only go to the *active*
|
||||||
|
// ui delegate).
|
||||||
|
delegate_->DoApplyAppConfig();
|
||||||
|
delegate_->OnScreenSizeChange();
|
||||||
|
delegate_->OnLanguageChange();
|
||||||
|
}
|
||||||
|
} catch (const Exception& exc) {
|
||||||
|
// Switching UI delegates is a big deal; don't try to continue if
|
||||||
|
// something goes wrong.
|
||||||
|
FatalError(std::string("Error setting native layer ui-delegate: ")
|
||||||
|
+ exc.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI::PushDevConsolePrintCall(const std::string& msg) {
|
void UI::PushDevConsolePrintCall(const std::string& msg) {
|
||||||
|
|||||||
@ -40,6 +40,8 @@ class UI {
|
|||||||
/// switching app-modes or when resetting things within an app mode.
|
/// switching app-modes or when resetting things within an app mode.
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
|
void set_ui_delegate(base::UIDelegateInterface* delegate);
|
||||||
|
|
||||||
/// Pop up an in-app window to display a URL (NOT to open the URL in a
|
/// Pop up an in-app window to display a URL (NOT to open the URL in a
|
||||||
/// browser). Can be called from any thread.
|
/// browser). Can be called from any thread.
|
||||||
void ShowURL(const std::string& url);
|
void ShowURL(const std::string& url);
|
||||||
@ -47,7 +49,7 @@ class UI {
|
|||||||
/// High level call to request a quit; ideally with a confirmation ui.
|
/// High level call to request a quit; ideally with a confirmation ui.
|
||||||
/// When a UI can't be shown, triggers an immediate shutdown. This can be
|
/// When a UI can't be shown, triggers an immediate shutdown. This can be
|
||||||
/// called from any thread.
|
/// called from any thread.
|
||||||
void ConfirmQuit();
|
// void ConfirmQuit();
|
||||||
|
|
||||||
/// Return whether there is UI present in either the main or overlay
|
/// Return whether there is UI present in either the main or overlay
|
||||||
/// stacks. Generally this implies the focus should be on the UI.
|
/// stacks. Generally this implies the focus should be on the UI.
|
||||||
@ -111,12 +113,15 @@ class UI {
|
|||||||
|
|
||||||
void PushDevConsolePrintCall(const std::string& msg);
|
void PushDevConsolePrintCall(const std::string& msg);
|
||||||
|
|
||||||
|
auto* delegate() const { return delegate_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void MainMenuPress_(InputDevice* device);
|
void MainMenuPress_(InputDevice* device);
|
||||||
auto DevConsoleButtonSize_() const -> float;
|
auto DevConsoleButtonSize_() const -> float;
|
||||||
auto InDevConsoleButton_(float x, float y) const -> bool;
|
auto InDevConsoleButton_(float x, float y) const -> bool;
|
||||||
void DrawDevConsoleButton_(FrameDef* frame_def);
|
void DrawDevConsoleButton_(FrameDef* frame_def);
|
||||||
|
|
||||||
|
base::UIDelegateInterface* delegate_{};
|
||||||
DevConsole* dev_console_{};
|
DevConsole* dev_console_{};
|
||||||
std::string dev_console_startup_messages_;
|
std::string dev_console_startup_messages_;
|
||||||
Object::WeakRef<InputDevice> ui_input_device_;
|
Object::WeakRef<InputDevice> ui_input_device_;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// Released under the MIT License. See LICENSE for details.
|
// Released under the MIT License. See LICENSE for details.
|
||||||
|
|
||||||
#ifndef BALLISTICA_BASE_SUPPORT_UI_V1_SOFT_H_
|
#ifndef BALLISTICA_BASE_UI_UI_DELEGATE_H_
|
||||||
#define BALLISTICA_BASE_SUPPORT_UI_V1_SOFT_H_
|
#define BALLISTICA_BASE_UI_UI_DELEGATE_H_
|
||||||
|
|
||||||
#include "ballistica/base/ui/ui.h"
|
#include "ballistica/base/ui/ui.h"
|
||||||
|
|
||||||
@ -14,15 +14,21 @@ class Widget;
|
|||||||
|
|
||||||
namespace ballistica::base {
|
namespace ballistica::base {
|
||||||
|
|
||||||
/// 'Soft' interface to the ui_v1 feature-set, managed by base. Feature-sets
|
class UIDelegateInterface {
|
||||||
/// listing ui_v1 as a soft requirement must limit their use of it to these
|
|
||||||
/// methods and should be prepared to handle the not-present case.
|
|
||||||
class UIV1SoftInterface {
|
|
||||||
public:
|
public:
|
||||||
|
/// Called when this delegate is becoming the active one.
|
||||||
|
virtual void OnActivate() = 0;
|
||||||
|
|
||||||
|
/// Called when this delegate is resigning active status.
|
||||||
|
virtual void OnDeactivate() = 0;
|
||||||
|
|
||||||
|
virtual void OnScreenSizeChange() = 0;
|
||||||
|
virtual void OnLanguageChange() = 0;
|
||||||
|
virtual void DoApplyAppConfig() = 0;
|
||||||
|
|
||||||
virtual void DoHandleDeviceMenuPress(base::InputDevice* device) = 0;
|
virtual void DoHandleDeviceMenuPress(base::InputDevice* device) = 0;
|
||||||
virtual void DoShowURL(const std::string& url) = 0;
|
virtual void DoShowURL(const std::string& url) = 0;
|
||||||
virtual void DoQuitWindow() = 0;
|
// virtual void DoQuitWindow() = 0;
|
||||||
virtual auto NewRootUI() -> ui_v1::RootUI* = 0;
|
|
||||||
virtual auto MainMenuVisible() -> bool = 0;
|
virtual auto MainMenuVisible() -> bool = 0;
|
||||||
virtual auto PartyIconVisible() -> bool = 0;
|
virtual auto PartyIconVisible() -> bool = 0;
|
||||||
virtual void ActivatePartyIcon() = 0;
|
virtual void ActivatePartyIcon() = 0;
|
||||||
@ -30,16 +36,20 @@ class UIV1SoftInterface {
|
|||||||
virtual auto HandleLegacyRootUIMouseDown(float x, float y) -> bool = 0;
|
virtual auto HandleLegacyRootUIMouseDown(float x, float y) -> bool = 0;
|
||||||
virtual void HandleLegacyRootUIMouseUp(float x, float y) = 0;
|
virtual void HandleLegacyRootUIMouseUp(float x, float y) = 0;
|
||||||
virtual void Draw(FrameDef* frame_def) = 0;
|
virtual void Draw(FrameDef* frame_def) = 0;
|
||||||
virtual void OnAppStart() = 0;
|
|
||||||
virtual auto PartyWindowOpen() -> bool = 0;
|
virtual auto PartyWindowOpen() -> bool = 0;
|
||||||
virtual void Reset() = 0;
|
virtual void Reset() = 0;
|
||||||
virtual void OnScreenSizeChange() = 0;
|
|
||||||
virtual void OnLanguageChange() = 0;
|
|
||||||
virtual auto GetRootWidget() -> ui_v1::Widget* = 0;
|
virtual auto GetRootWidget() -> ui_v1::Widget* = 0;
|
||||||
virtual auto SendWidgetMessage(const WidgetMessage& m) -> int = 0;
|
virtual auto SendWidgetMessage(const WidgetMessage& m) -> int = 0;
|
||||||
virtual void DoApplyAppConfig() = 0;
|
|
||||||
|
/// Should return true if this app mode can confirm quitting the app.
|
||||||
|
virtual auto HasQuitConfirmDialog() -> bool = 0;
|
||||||
|
|
||||||
|
/// Will be called in the logic thread if HasQuitConfirmDialog() returns
|
||||||
|
/// true. Should present a quit confirmation dialog to the user and call
|
||||||
|
/// BaseFeatureSet::QuitApp() with the provided quit_type if confirmed.
|
||||||
|
virtual void ConfirmQuit(QuitType quit_type) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|
||||||
#endif // BALLISTICA_BASE_SUPPORT_UI_V1_SOFT_H_
|
#endif // BALLISTICA_BASE_UI_UI_DELEGATE_H_
|
||||||
@ -157,10 +157,10 @@ class CoreFeatureSet {
|
|||||||
|
|
||||||
// The following are misc values that should be migrated to applicable
|
// The following are misc values that should be migrated to applicable
|
||||||
// subsystem classes.
|
// subsystem classes.
|
||||||
bool threads_paused{};
|
bool event_loops_suspended{};
|
||||||
bool workspaces_in_use{};
|
bool workspaces_in_use{};
|
||||||
bool replay_open{};
|
bool replay_open{};
|
||||||
std::vector<EventLoop*> pausable_event_loops;
|
std::vector<EventLoop*> suspendable_event_loops;
|
||||||
std::mutex v1_cloud_log_mutex;
|
std::mutex v1_cloud_log_mutex;
|
||||||
std::string v1_cloud_log;
|
std::string v1_cloud_log;
|
||||||
bool did_put_v1_cloud_log{};
|
bool did_put_v1_cloud_log{};
|
||||||
@ -168,7 +168,7 @@ class CoreFeatureSet {
|
|||||||
int master_server_source{};
|
int master_server_source{};
|
||||||
int session_count{};
|
int session_count{};
|
||||||
bool have_incentivized_ad{false};
|
bool have_incentivized_ad{false};
|
||||||
bool should_pause{};
|
bool should_pause_active_game{};
|
||||||
bool reset_vr_orientation{};
|
bool reset_vr_orientation{};
|
||||||
bool user_ran_commands{};
|
bool user_ran_commands{};
|
||||||
std::thread::id main_thread_id{};
|
std::thread::id main_thread_id{};
|
||||||
|
|||||||
@ -21,6 +21,7 @@ class BaseSoftInterface {
|
|||||||
virtual auto InAssetsThread() const -> bool = 0;
|
virtual auto InAssetsThread() const -> bool = 0;
|
||||||
virtual auto InLogicThread() const -> bool = 0;
|
virtual auto InLogicThread() const -> bool = 0;
|
||||||
virtual auto InAudioThread() const -> bool = 0;
|
virtual auto InAudioThread() const -> bool = 0;
|
||||||
|
virtual auto InGraphicsContext() const -> bool = 0;
|
||||||
virtual auto InBGDynamicsThread() const -> bool = 0;
|
virtual auto InBGDynamicsThread() const -> bool = 0;
|
||||||
virtual auto InNetworkWriteThread() const -> bool = 0;
|
virtual auto InNetworkWriteThread() const -> bool = 0;
|
||||||
virtual void PlusDirectSendV1CloudLogs(const std::string& prefix,
|
virtual void PlusDirectSendV1CloudLogs(const std::string& prefix,
|
||||||
|
|||||||
@ -28,20 +28,26 @@ class Node : public Object {
|
|||||||
public:
|
public:
|
||||||
Node(Scene* scene, NodeType* node_type);
|
Node(Scene* scene, NodeType* node_type);
|
||||||
~Node() override;
|
~Node() override;
|
||||||
auto id() const -> int64_t {
|
|
||||||
return id_;
|
/// Return the node's id in its scene.
|
||||||
} // Return the node's id in its scene.
|
auto id() const -> int64_t { return id_; }
|
||||||
virtual void Step() {} // Called for each step of the sim.
|
|
||||||
virtual void OnScreenSizeChange() {} // Called when screen size changes.
|
/// Called for each step of the sim.
|
||||||
virtual void OnLanguageChange() {} // Called when the language changes.
|
virtual void Step() {}
|
||||||
|
|
||||||
|
/// Called when screen size changes.
|
||||||
|
virtual void OnScreenSizeChange() {}
|
||||||
|
|
||||||
|
/// Called when the language changes.
|
||||||
|
virtual void OnLanguageChange() {}
|
||||||
virtual void OnGraphicsQualityChanged(base::GraphicsQuality q) {}
|
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 {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull a node type out of a buffer.
|
/// Pull a node type out of a buffer.
|
||||||
static auto extract_node_message_type(const char** b) -> NodeMessageType {
|
static auto extract_node_message_type(const char** b) -> NodeMessageType {
|
||||||
auto t = static_cast<NodeMessageType>(**b);
|
auto t = static_cast<NodeMessageType>(**b);
|
||||||
(*b) += 1;
|
(*b) += 1;
|
||||||
@ -51,10 +57,10 @@ class Node : public Object {
|
|||||||
void ConnectAttribute(NodeAttributeUnbound* src_attr, Node* dst_node,
|
void ConnectAttribute(NodeAttributeUnbound* src_attr, Node* dst_node,
|
||||||
NodeAttributeUnbound* dst_attr);
|
NodeAttributeUnbound* dst_attr);
|
||||||
|
|
||||||
// Return an attribute by name.
|
/// Return an attribute by name.
|
||||||
auto GetAttribute(const std::string& name) -> NodeAttribute;
|
auto GetAttribute(const std::string& name) -> NodeAttribute;
|
||||||
|
|
||||||
// Return an attribute by index.
|
/// Return an attribute by index.
|
||||||
auto GetAttribute(int index) -> NodeAttribute;
|
auto GetAttribute(int index) -> NodeAttribute;
|
||||||
|
|
||||||
void SetDelegate(PyObject* delegate_obj);
|
void SetDelegate(PyObject* delegate_obj);
|
||||||
@ -62,37 +68,35 @@ class Node : public Object {
|
|||||||
auto NewPyRef() -> PyObject* { return GetPyRef(true); }
|
auto NewPyRef() -> PyObject* { return GetPyRef(true); }
|
||||||
auto BorrowPyRef() -> PyObject* { return GetPyRef(false); }
|
auto BorrowPyRef() -> PyObject* { return GetPyRef(false); }
|
||||||
|
|
||||||
// Return the delegate, or nullptr if it doesn't have one
|
/// Return the delegate, or nullptr if it doesn't have one (or if the
|
||||||
// (or if the delegate has since died).
|
/// delegate has since died).
|
||||||
auto GetDelegate() -> PyObject*;
|
auto GetDelegate() -> PyObject*;
|
||||||
|
|
||||||
void AddNodeDeathAction(PyObject* call_obj);
|
void AddNodeDeathAction(PyObject* call_obj);
|
||||||
|
|
||||||
// Add a node to auto-kill when this one dies.
|
/// Add a node to auto-kill when this one dies.
|
||||||
void AddDependentNode(Node* node);
|
void AddDependentNode(Node* node);
|
||||||
|
|
||||||
// Update birth times for all the node's parts.
|
/// Update birth times for all the node's parts. This should be done when
|
||||||
// This should be done when teleporting or otherwise spawning at
|
/// teleporting or otherwise spawning at a new location.
|
||||||
// a new location.
|
|
||||||
void UpdatePartBirthTimes();
|
void UpdatePartBirthTimes();
|
||||||
|
|
||||||
// Retrieve an existing part from a node.
|
/// Retrieve an existing part from a node.
|
||||||
auto GetPart(unsigned int id) -> Part* {
|
auto GetPart(unsigned int id) -> Part* {
|
||||||
assert(id < parts_.size());
|
assert(id < parts_.size());
|
||||||
return parts_[id];
|
return parts_[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by RigidBodies when adding themselves to the part.
|
/// Used by RigidBodies when adding themselves to the part.
|
||||||
auto AddPart(Part* part_in) -> int {
|
auto AddPart(Part* part_in) -> int {
|
||||||
parts_.push_back(part_in);
|
parts_.push_back(part_in);
|
||||||
return static_cast<int>(parts_.size() - 1);
|
return static_cast<int>(parts_.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to send messages to a node
|
/// Used to send messages to a node
|
||||||
void DispatchNodeMessage(const char* buffer);
|
void DispatchNodeMessage(const char* buffer);
|
||||||
|
|
||||||
// Used to send custom user messages to a node
|
/// Used to send custom user messages to a node.
|
||||||
// returns true if handled.
|
|
||||||
void DispatchUserMessage(PyObject* obj, const char* label);
|
void DispatchUserMessage(PyObject* obj, const char* label);
|
||||||
void DispatchOutOfBoundsMessage();
|
void DispatchOutOfBoundsMessage();
|
||||||
void DispatchPickedUpMessage(Node* n);
|
void DispatchPickedUpMessage(Node* n);
|
||||||
@ -102,21 +106,21 @@ class Node : public Object {
|
|||||||
void DispatchShouldShatterMessage();
|
void DispatchShouldShatterMessage();
|
||||||
void DispatchImpactDamageMessage(float intensity);
|
void DispatchImpactDamageMessage(float intensity);
|
||||||
|
|
||||||
// Utility function to get a rigid body.
|
/// Utility function to get a rigid body.
|
||||||
virtual auto GetRigidBody(int id) -> RigidBody* { return nullptr; }
|
virtual auto GetRigidBody(int id) -> RigidBody* { return nullptr; }
|
||||||
|
|
||||||
// Given a rigid body, return the relative position where it should be picked
|
/// Given a rigid body, return the relative position where it should be
|
||||||
// up from.
|
/// picked up from.
|
||||||
virtual void GetRigidBodyPickupLocations(int id, float* posObj,
|
virtual void GetRigidBodyPickupLocations(int id, float* posObj,
|
||||||
float* pos_char,
|
float* pos_char,
|
||||||
float* hand_offset_1,
|
float* hand_offset_1,
|
||||||
float* hand_offset_2);
|
float* hand_offset_2);
|
||||||
|
|
||||||
// Called for each Node when it should render itself.
|
/// Called for each Node when it should render itself.
|
||||||
virtual void Draw(base::FrameDef* frame_def);
|
virtual void Draw(base::FrameDef* frame_def);
|
||||||
|
|
||||||
// Called for each node once construction is completed
|
/// Called for each node once construction is completed this can be a good
|
||||||
// this can be a good time to create things from the initial attr set, etc
|
/// time to create things from the initial attr set, etc
|
||||||
virtual void OnCreate();
|
virtual void OnCreate();
|
||||||
|
|
||||||
auto scene() const -> Scene* {
|
auto scene() const -> Scene* {
|
||||||
@ -124,14 +128,14 @@ class Node : public Object {
|
|||||||
return scene_;
|
return scene_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to re-sync client versions of a node from the host version.
|
/// Used to re-sync client versions of a node from the host version.
|
||||||
virtual auto GetResyncDataSize() -> int;
|
virtual auto GetResyncDataSize() -> int;
|
||||||
virtual auto GetResyncData() -> std::vector<uint8_t>;
|
virtual auto GetResyncData() -> std::vector<uint8_t>;
|
||||||
virtual void ApplyResyncData(const std::vector<uint8_t>& data);
|
virtual void ApplyResyncData(const std::vector<uint8_t>& data);
|
||||||
auto context_ref() const -> const ContextRefSceneV1& { return context_ref_; }
|
auto context_ref() const -> const ContextRefSceneV1& { return context_ref_; }
|
||||||
|
|
||||||
// Node labels are purely for local debugging - they aren't unique or sent
|
/// Node labels are purely for local debugging - they aren't unique or
|
||||||
// across the network or anything.
|
/// sent across the network or anything.
|
||||||
void set_label(const std::string& label) { label_ = label; }
|
void set_label(const std::string& label) { label_ = label; }
|
||||||
auto label() const -> const std::string& { return label_; }
|
auto label() const -> const std::string& { return label_; }
|
||||||
|
|
||||||
@ -156,17 +160,21 @@ class Node : public Object {
|
|||||||
auto GetObjectDescription() const -> std::string override;
|
auto GetObjectDescription() const -> std::string override;
|
||||||
|
|
||||||
auto parts() const -> const std::vector<Part*>& { return parts_; }
|
auto parts() const -> const std::vector<Part*>& { return parts_; }
|
||||||
|
|
||||||
auto death_actions() const
|
auto death_actions() const
|
||||||
-> const std::vector<Object::Ref<base::PythonContextCall> >& {
|
-> const std::vector<Object::Ref<base::PythonContextCall> >& {
|
||||||
return death_actions_;
|
return death_actions_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dependent_nodes() const -> const std::vector<Object::WeakRef<Node> >& {
|
auto dependent_nodes() const -> const std::vector<Object::WeakRef<Node> >& {
|
||||||
return dependent_nodes_;
|
return dependent_nodes_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto attribute_connections() const
|
auto attribute_connections() const
|
||||||
-> const std::list<Object::Ref<NodeAttributeConnection> >& {
|
-> const std::list<Object::Ref<NodeAttributeConnection> >& {
|
||||||
return attribute_connections_;
|
return attribute_connections_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto attribute_connections_incoming() const
|
auto attribute_connections_incoming() const
|
||||||
-> const std::unordered_map<int, Object::Ref<NodeAttributeConnection> >& {
|
-> const std::unordered_map<int, Object::Ref<NodeAttributeConnection> >& {
|
||||||
return attribute_connections_incoming_;
|
return attribute_connections_incoming_;
|
||||||
@ -177,13 +185,14 @@ class Node : public Object {
|
|||||||
assert(stream_id_ == -1);
|
assert(stream_id_ == -1);
|
||||||
stream_id_ = val;
|
stream_id_ = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_stream_id() {
|
void clear_stream_id() {
|
||||||
assert(stream_id_ != -1);
|
assert(stream_id_ != -1);
|
||||||
stream_id_ = -1;
|
stream_id_ = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a reference to a python wrapper for this node,
|
/// Return a reference to a python wrapper for this node, creating one if
|
||||||
// creating one if need be.
|
/// need be.
|
||||||
auto GetPyRef(bool new_ref = true) -> PyObject*;
|
auto GetPyRef(bool new_ref = true) -> PyObject*;
|
||||||
|
|
||||||
void AddToScene(Scene* scene);
|
void AddToScene(Scene* scene);
|
||||||
@ -197,8 +206,8 @@ class Node : public Object {
|
|||||||
|
|
||||||
PyObject* py_ref_ = nullptr;
|
PyObject* py_ref_ = nullptr;
|
||||||
|
|
||||||
// FIXME - We can get by with *just* a pointer to our scene
|
/// FIXME - We can get by with *just* a pointer to our scene if we add a
|
||||||
// if we add a way to pull context from a scene.
|
/// way to pull context from a scene.
|
||||||
ContextRefSceneV1 context_ref_;
|
ContextRefSceneV1 context_ref_;
|
||||||
Scene* scene_{};
|
Scene* scene_{};
|
||||||
std::string label_;
|
std::string label_;
|
||||||
@ -211,10 +220,10 @@ class Node : public Object {
|
|||||||
PythonRef delegate_;
|
PythonRef delegate_;
|
||||||
std::vector<Object::Ref<base::PythonContextCall> > death_actions_;
|
std::vector<Object::Ref<base::PythonContextCall> > death_actions_;
|
||||||
|
|
||||||
// Outgoing attr connections in order created.
|
/// Outgoing attr connections in order created.
|
||||||
std::list<Object::Ref<NodeAttributeConnection> > attribute_connections_;
|
std::list<Object::Ref<NodeAttributeConnection> > attribute_connections_;
|
||||||
|
|
||||||
// Incoming attr connections by attr index.
|
/// Incoming attr connections by attr index.
|
||||||
std::unordered_map<int, Object::Ref<NodeAttributeConnection> >
|
std::unordered_map<int, Object::Ref<NodeAttributeConnection> >
|
||||||
attribute_connections_incoming_;
|
attribute_connections_incoming_;
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
#include "ballistica/shared/foundation/event_loop.h"
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
#include "ballistica/shared/generic/json.h"
|
#include "ballistica/shared/generic/json.h"
|
||||||
#include "ballistica/shared/generic/utils.h"
|
#include "ballistica/shared/generic/utils.h"
|
||||||
|
#include "ballistica/ui_v1/ui_v1.h"
|
||||||
|
|
||||||
namespace ballistica::scene_v1 {
|
namespace ballistica::scene_v1 {
|
||||||
|
|
||||||
@ -76,8 +77,14 @@ bool SceneV1AppMode::InClassicMainMenuSession() const {
|
|||||||
static SceneV1AppMode* g_scene_v1_app_mode{};
|
static SceneV1AppMode* g_scene_v1_app_mode{};
|
||||||
|
|
||||||
void SceneV1AppMode::OnActivate() {
|
void SceneV1AppMode::OnActivate() {
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
Reset();
|
Reset();
|
||||||
|
|
||||||
|
// We use UIV1.
|
||||||
|
if (!g_core->HeadlessMode()) {
|
||||||
|
g_base->ui->set_ui_delegate(ui_v1::UIV1FeatureSet::Import());
|
||||||
|
}
|
||||||
|
|
||||||
// To set initial states, explicitly fire some of our 'On-Foo-Changed'
|
// To set initial states, explicitly fire some of our 'On-Foo-Changed'
|
||||||
// callbacks.
|
// callbacks.
|
||||||
DoApplyAppConfig();
|
DoApplyAppConfig();
|
||||||
|
|||||||
@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
|
|||||||
namespace ballistica {
|
namespace ballistica {
|
||||||
|
|
||||||
// These are set automatically via script; don't modify them here.
|
// These are set automatically via script; don't modify them here.
|
||||||
const int kEngineBuildNumber = 21422;
|
const int kEngineBuildNumber = 21441;
|
||||||
const char* kEngineVersion = "1.7.28";
|
const char* kEngineVersion = "1.7.28";
|
||||||
const int kEngineApiVersion = 8;
|
const int kEngineApiVersion = 8;
|
||||||
|
|
||||||
|
|||||||
@ -140,10 +140,6 @@ namespace ballistica {
|
|||||||
#define BA_ENABLE_STDIO_CONSOLE 0
|
#define BA_ENABLE_STDIO_CONSOLE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef BA_HARDWARE_CURSOR
|
|
||||||
#define BA_HARDWARE_CURSOR 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef BA_ENABLE_OS_FONT_RENDERING
|
#ifndef BA_ENABLE_OS_FONT_RENDERING
|
||||||
#define BA_ENABLE_OS_FONT_RENDERING 0
|
#define BA_ENABLE_OS_FONT_RENDERING 0
|
||||||
#endif
|
#endif
|
||||||
@ -277,7 +273,6 @@ class BuildConfig {
|
|||||||
bool enable_os_font_rendering() const {
|
bool enable_os_font_rendering() const {
|
||||||
return EXPBOOL_(BA_ENABLE_OS_FONT_RENDERING);
|
return EXPBOOL_(BA_ENABLE_OS_FONT_RENDERING);
|
||||||
}
|
}
|
||||||
bool hardware_cursor() const { return EXPBOOL_(BA_HARDWARE_CURSOR); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef EXPBOOL_
|
#undef EXPBOOL_
|
||||||
|
|||||||
@ -171,12 +171,13 @@ auto EventLoop::ThreadMainAssetsP_(void* data) -> void* {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventLoop::PushSetPaused(bool paused) {
|
void EventLoop::PushSetSuspended(bool suspended) {
|
||||||
assert(g_core);
|
assert(g_core);
|
||||||
// Can be toggled from the main thread only.
|
// Can be toggled from the main thread only.
|
||||||
assert(std::this_thread::get_id() == g_core->main_thread_id);
|
assert(std::this_thread::get_id() == g_core->main_thread_id);
|
||||||
PushThreadMessage_(ThreadMessage_(paused ? ThreadMessage_::Type::kPause
|
PushThreadMessage_(ThreadMessage_(suspended
|
||||||
: ThreadMessage_::Type::kResume));
|
? ThreadMessage_::Type::kSuspend
|
||||||
|
: ThreadMessage_::Type::kUnsuspend));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventLoop::WaitForNextEvent_(bool single_cycle) {
|
void EventLoop::WaitForNextEvent_(bool single_cycle) {
|
||||||
@ -184,24 +185,27 @@ void EventLoop::WaitForNextEvent_(bool single_cycle) {
|
|||||||
|
|
||||||
// If we're running a single cycle we never stop to wait.
|
// If we're running a single cycle we never stop to wait.
|
||||||
if (single_cycle) {
|
if (single_cycle) {
|
||||||
// Need to revisit this if we ever do single-cycle for
|
// Need to revisit this if we ever do single-cycle for the gil-holding
|
||||||
// the gil-holding thread so we don't starve other Python threads.
|
// thread so we don't starve other Python threads.
|
||||||
assert(!acquires_python_gil_);
|
assert(!acquires_python_gil_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We also never wait if we have pending runnables; we want to run
|
// We also never wait if we have pending runnables; we want to run things
|
||||||
// things as soon as we can. We chew through all runnables at the end
|
// as soon as we can. We chew through all runnables at the end of the loop
|
||||||
// of the loop so it might seem like there should never be any here,
|
// so it might seem like there should never be any here, but runnables can
|
||||||
// but runnables can add other runnables that won't get processed until
|
// add other runnables that won't get processed until the next time
|
||||||
// the next time through.
|
// through.
|
||||||
// BUG FIX: We now skip this if we're paused since we don't run runnables
|
//
|
||||||
// in that case. This was preventing us from releasing the GIL while paused
|
// BUG FIX: We now skip this if we're suspended since we don't run
|
||||||
// (and I assume causing us to spin full-speed through the loop; ugh).
|
// runnables in that case. This was preventing us from releasing the GIL
|
||||||
// NOTE: It is theoretically possible for a runnable to add another runnable
|
// while suspended (and I assume causing us to spin full-speed through
|
||||||
// each time through the loop which would effectively starve the GIL as
|
// the loop; ugh).
|
||||||
// well; do we need to worry about that case?
|
//
|
||||||
if (has_pending_runnables() && !paused_) {
|
// NOTE: It is theoretically possible for a runnable to add another
|
||||||
|
// runnable each time through the loop which would effectively starve the
|
||||||
|
// GIL as well; do we need to worry about that case?
|
||||||
|
if (has_pending_runnables() && !suspended_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +216,7 @@ void EventLoop::WaitForNextEvent_(bool single_cycle) {
|
|||||||
|
|
||||||
// If we've got active timers, wait for messages with a timeout so we can
|
// If we've got active timers, wait for messages with a timeout so we can
|
||||||
// run the next timer payload.
|
// run the next timer payload.
|
||||||
if (!paused_ && timers_.ActiveTimerCount() > 0) {
|
if (!suspended_ && timers_.ActiveTimerCount() > 0) {
|
||||||
millisecs_t apptime = g_core->GetAppTimeMillisecs();
|
millisecs_t apptime = g_core->GetAppTimeMillisecs();
|
||||||
millisecs_t wait_time = timers_.TimeToNextExpire(apptime);
|
millisecs_t wait_time = timers_.TimeToNextExpire(apptime);
|
||||||
if (wait_time > 0) {
|
if (wait_time > 0) {
|
||||||
@ -287,18 +291,18 @@ void EventLoop::Run_(bool single_cycle) {
|
|||||||
done_ = true;
|
done_ = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ThreadMessage_::Type::kPause: {
|
case ThreadMessage_::Type::kSuspend: {
|
||||||
assert(!paused_);
|
assert(!suspended_);
|
||||||
RunPauseCallbacks_();
|
RunSuspendCallbacks_();
|
||||||
paused_ = true;
|
suspended_ = true;
|
||||||
last_pause_time_ = g_core->GetAppTimeMillisecs();
|
last_suspend_time_ = g_core->GetAppTimeMillisecs();
|
||||||
messages_since_paused_ = 0;
|
messages_since_suspended_ = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ThreadMessage_::Type::kResume: {
|
case ThreadMessage_::Type::kUnsuspend: {
|
||||||
assert(paused_);
|
assert(suspended_);
|
||||||
RunResumeCallbacks_();
|
RunUnsuspendCallbacks_();
|
||||||
paused_ = false;
|
suspended_ = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@ -311,7 +315,7 @@ void EventLoop::Run_(bool single_cycle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!paused_) {
|
if (!suspended_) {
|
||||||
timers_.Run(g_core->GetAppTimeMillisecs());
|
timers_.Run(g_core->GetAppTimeMillisecs());
|
||||||
RunPendingRunnables_();
|
RunPendingRunnables_();
|
||||||
}
|
}
|
||||||
@ -473,11 +477,11 @@ void EventLoop::LogThreadMessageTally_(
|
|||||||
case ThreadMessage_::Type::kRunnable:
|
case ThreadMessage_::Type::kRunnable:
|
||||||
s += "kRunnable";
|
s += "kRunnable";
|
||||||
break;
|
break;
|
||||||
case ThreadMessage_::Type::kPause:
|
case ThreadMessage_::Type::kSuspend:
|
||||||
s += "kPause";
|
s += "kSuspend";
|
||||||
break;
|
break;
|
||||||
case ThreadMessage_::Type::kResume:
|
case ThreadMessage_::Type::kUnsuspend:
|
||||||
s += "kResume";
|
s += "kUnsuspend";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
s += "UNKNOWN(" + std::to_string(static_cast<int>(m.type)) + ")";
|
s += "UNKNOWN(" + std::to_string(static_cast<int>(m.type)) + ")";
|
||||||
@ -570,24 +574,24 @@ void EventLoop::PushThreadMessage_(const ThreadMessage_& t) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventLoop::SetEventLoopsPaused(bool paused) {
|
void EventLoop::SetEventLoopsSuspended(bool suspended) {
|
||||||
assert(g_core);
|
assert(g_core);
|
||||||
assert(std::this_thread::get_id() == g_core->main_thread_id);
|
assert(std::this_thread::get_id() == g_core->main_thread_id);
|
||||||
g_core->threads_paused = paused;
|
g_core->event_loops_suspended = suspended;
|
||||||
for (auto&& i : g_core->pausable_event_loops) {
|
for (auto&& i : g_core->suspendable_event_loops) {
|
||||||
i->PushSetPaused(paused);
|
i->PushSetSuspended(suspended);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EventLoop::GetStillPausingThreads() -> std::vector<EventLoop*> {
|
auto EventLoop::GetStillSuspendingEventLoops() -> std::vector<EventLoop*> {
|
||||||
assert(g_core);
|
assert(g_core);
|
||||||
std::vector<EventLoop*> threads;
|
std::vector<EventLoop*> threads;
|
||||||
assert(std::this_thread::get_id() == g_core->main_thread_id);
|
assert(std::this_thread::get_id() == g_core->main_thread_id);
|
||||||
|
|
||||||
// Only return results if an actual pause is in effect.
|
// Only return results if an actual suspend is in effect.
|
||||||
if (g_core->threads_paused) {
|
if (g_core->event_loops_suspended) {
|
||||||
for (auto&& i : g_core->pausable_event_loops) {
|
for (auto&& i : g_core->suspendable_event_loops) {
|
||||||
if (!i->paused()) {
|
if (!i->suspended()) {
|
||||||
threads.push_back(i);
|
threads.push_back(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -595,9 +599,9 @@ auto EventLoop::GetStillPausingThreads() -> std::vector<EventLoop*> {
|
|||||||
return threads;
|
return threads;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EventLoop::AreEventLoopsPaused() -> bool {
|
auto EventLoop::AreEventLoopsSuspended() -> bool {
|
||||||
assert(g_core);
|
assert(g_core);
|
||||||
return g_core->threads_paused;
|
return g_core->event_loops_suspended;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EventLoop::NewTimer(millisecs_t length, bool repeat,
|
auto EventLoop::NewTimer(millisecs_t length, bool repeat,
|
||||||
@ -678,14 +682,14 @@ void EventLoop::RunPendingRunnables_() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventLoop::RunPauseCallbacks_() {
|
void EventLoop::RunSuspendCallbacks_() {
|
||||||
for (Runnable* i : pause_callbacks_) {
|
for (Runnable* i : suspend_callbacks_) {
|
||||||
i->RunAndLogErrors();
|
i->RunAndLogErrors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventLoop::RunResumeCallbacks_() {
|
void EventLoop::RunUnsuspendCallbacks_() {
|
||||||
for (Runnable* i : resume_callbacks_) {
|
for (Runnable* i : unsuspend_callbacks_) {
|
||||||
i->RunAndLogErrors();
|
i->RunAndLogErrors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -701,14 +705,14 @@ void EventLoop::PushCrossThreadRunnable_(Runnable* runnable,
|
|||||||
EventLoop::ThreadMessage_::Type::kRunnable, runnable, completion_flag));
|
EventLoop::ThreadMessage_::Type::kRunnable, runnable, completion_flag));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventLoop::AddPauseCallback(Runnable* runnable) {
|
void EventLoop::AddSuspendCallback(Runnable* runnable) {
|
||||||
assert(std::this_thread::get_id() == thread_id());
|
assert(std::this_thread::get_id() == thread_id());
|
||||||
pause_callbacks_.push_back(runnable);
|
suspend_callbacks_.push_back(runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventLoop::AddResumeCallback(Runnable* runnable) {
|
void EventLoop::AddUnsuspendCallback(Runnable* runnable) {
|
||||||
assert(std::this_thread::get_id() == thread_id());
|
assert(std::this_thread::get_id() == thread_id());
|
||||||
resume_callbacks_.push_back(runnable);
|
unsuspend_callbacks_.push_back(runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventLoop::PushRunnable(Runnable* runnable) {
|
void EventLoop::PushRunnable(Runnable* runnable) {
|
||||||
|
|||||||
@ -29,8 +29,8 @@ class EventLoop {
|
|||||||
|
|
||||||
static auto CurrentThreadName() -> std::string;
|
static auto CurrentThreadName() -> std::string;
|
||||||
|
|
||||||
static void SetEventLoopsPaused(bool enable);
|
static void SetEventLoopsSuspended(bool enable);
|
||||||
static auto AreEventLoopsPaused() -> bool;
|
static auto AreEventLoopsSuspended() -> bool;
|
||||||
|
|
||||||
auto ThreadIsCurrent() const -> bool {
|
auto ThreadIsCurrent() const -> bool {
|
||||||
return std::this_thread::get_id() == thread_id();
|
return std::this_thread::get_id() == thread_id();
|
||||||
@ -41,7 +41,7 @@ class EventLoop {
|
|||||||
|
|
||||||
void SetAcquiresPythonGIL();
|
void SetAcquiresPythonGIL();
|
||||||
|
|
||||||
void PushSetPaused(bool paused);
|
void PushSetSuspended(bool suspended);
|
||||||
|
|
||||||
auto thread_id() const -> std::thread::id { return thread_id_; }
|
auto thread_id() const -> std::thread::id { return thread_id_; }
|
||||||
|
|
||||||
@ -81,11 +81,11 @@ class EventLoop {
|
|||||||
PushRunnableSynchronous(NewLambdaRunnableUnmanaged(lambda));
|
PushRunnableSynchronous(NewLambdaRunnableUnmanaged(lambda));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a callback to be run on event-loop pauses.
|
/// Add a callback to be run on event-loop suspends.
|
||||||
void AddPauseCallback(Runnable* runnable);
|
void AddSuspendCallback(Runnable* runnable);
|
||||||
|
|
||||||
/// Add a callback to be run on event-loop resumes.
|
/// Add a callback to be run on event-loop unsuspends.
|
||||||
void AddResumeCallback(Runnable* runnable);
|
void AddUnsuspendCallback(Runnable* runnable);
|
||||||
|
|
||||||
auto has_pending_runnables() const -> bool { return !runnables_.empty(); }
|
auto has_pending_runnables() const -> bool { return !runnables_.empty(); }
|
||||||
|
|
||||||
@ -97,14 +97,14 @@ class EventLoop {
|
|||||||
/// the app through a flood of packets.
|
/// the app through a flood of packets.
|
||||||
auto CheckPushSafety() -> bool;
|
auto CheckPushSafety() -> bool;
|
||||||
|
|
||||||
static auto GetStillPausingThreads() -> std::vector<EventLoop*>;
|
static auto GetStillSuspendingEventLoops() -> std::vector<EventLoop*>;
|
||||||
|
|
||||||
auto paused() { return paused_; }
|
auto suspended() { return suspended_; }
|
||||||
auto done() -> bool { return done_; }
|
auto done() -> bool { return done_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct ThreadMessage_ {
|
struct ThreadMessage_ {
|
||||||
enum class Type { kShutdown = 999, kRunnable, kPause, kResume };
|
enum class Type { kShutdown = 999, kRunnable, kSuspend, kUnsuspend };
|
||||||
Type type;
|
Type type;
|
||||||
union {
|
union {
|
||||||
Runnable* runnable{};
|
Runnable* runnable{};
|
||||||
@ -147,8 +147,8 @@ class EventLoop {
|
|||||||
void PushThreadMessage_(const ThreadMessage_& t);
|
void PushThreadMessage_(const ThreadMessage_& t);
|
||||||
|
|
||||||
void RunPendingRunnables_();
|
void RunPendingRunnables_();
|
||||||
void RunPauseCallbacks_();
|
void RunSuspendCallbacks_();
|
||||||
void RunResumeCallbacks_();
|
void RunUnsuspendCallbacks_();
|
||||||
|
|
||||||
void AcquireGIL_();
|
void AcquireGIL_();
|
||||||
void ReleaseGIL_();
|
void ReleaseGIL_();
|
||||||
@ -156,10 +156,10 @@ class EventLoop {
|
|||||||
void BootstrapThread_();
|
void BootstrapThread_();
|
||||||
|
|
||||||
bool writing_tally_{};
|
bool writing_tally_{};
|
||||||
bool paused_{};
|
bool suspended_{};
|
||||||
millisecs_t last_pause_time_{};
|
millisecs_t last_suspend_time_{};
|
||||||
int messages_since_paused_{};
|
int messages_since_suspended_{};
|
||||||
millisecs_t last_paused_message_report_time_{};
|
millisecs_t last_suspended_message_report_time_{};
|
||||||
bool done_{};
|
bool done_{};
|
||||||
ThreadSource source_;
|
ThreadSource source_;
|
||||||
int listen_sd_{};
|
int listen_sd_{};
|
||||||
@ -175,8 +175,8 @@ class EventLoop {
|
|||||||
|
|
||||||
bool bootstrapped_{};
|
bool bootstrapped_{};
|
||||||
std::list<std::pair<Runnable*, bool*>> runnables_;
|
std::list<std::pair<Runnable*, bool*>> runnables_;
|
||||||
std::list<Runnable*> pause_callbacks_;
|
std::list<Runnable*> suspend_callbacks_;
|
||||||
std::list<Runnable*> resume_callbacks_;
|
std::list<Runnable*> unsuspend_callbacks_;
|
||||||
std::condition_variable thread_message_cv_;
|
std::condition_variable thread_message_cv_;
|
||||||
std::mutex thread_message_mutex_;
|
std::mutex thread_message_mutex_;
|
||||||
std::list<ThreadMessage_> thread_messages_;
|
std::list<ThreadMessage_> thread_messages_;
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#include "ballistica/core/platform/core_platform.h"
|
#include "ballistica/core/platform/core_platform.h"
|
||||||
#include "ballistica/core/support/base_soft.h"
|
#include "ballistica/core/support/base_soft.h"
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
|
||||||
#include "ballistica/shared/foundation/logging.h"
|
#include "ballistica/shared/foundation/logging.h"
|
||||||
|
|
||||||
namespace ballistica {
|
namespace ballistica {
|
||||||
|
|||||||
@ -199,6 +199,16 @@ void Object::ObjectThreadCheck() {
|
|||||||
|
|
||||||
ThreadOwnership thread_ownership = GetThreadOwnership();
|
ThreadOwnership thread_ownership = GetThreadOwnership();
|
||||||
|
|
||||||
|
// Special case; graphics context (not simply a thread so have to handle
|
||||||
|
// specially).
|
||||||
|
if (thread_ownership == ThreadOwnership::kGraphicsContext) {
|
||||||
|
if (!(g_base_soft && g_base_soft->InGraphicsContext())) {
|
||||||
|
throw Exception("ObjectThreadCheck failed for " + GetObjectDescription()
|
||||||
|
+ "; expected graphics context.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
EventLoopID t;
|
EventLoopID t;
|
||||||
if (thread_ownership == ThreadOwnership::kClassDefault) {
|
if (thread_ownership == ThreadOwnership::kClassDefault) {
|
||||||
t = GetDefaultOwnerThread();
|
t = GetDefaultOwnerThread();
|
||||||
|
|||||||
@ -32,8 +32,12 @@ class Object {
|
|||||||
virtual auto GetObjectDescription() const -> std::string;
|
virtual auto GetObjectDescription() const -> std::string;
|
||||||
|
|
||||||
enum class ThreadOwnership {
|
enum class ThreadOwnership {
|
||||||
kClassDefault, // Uses class' GetDefaultOwnerThread() call.
|
/// Uses class' GetDefaultOwnerThread() call.
|
||||||
kNextReferencing // Uses whichever thread next acquires/accesses a ref.
|
kClassDefault,
|
||||||
|
/// Requires graphics context to be active.
|
||||||
|
kGraphicsContext,
|
||||||
|
/// Uses whichever thread next acquires/accesses a reference.
|
||||||
|
kNextReferencing
|
||||||
};
|
};
|
||||||
|
|
||||||
#if BA_DEBUG_BUILD
|
#if BA_DEBUG_BUILD
|
||||||
|
|||||||
@ -97,6 +97,27 @@ enum class InputType {
|
|||||||
kLast // Sentinel
|
kLast // Sentinel
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// BA_EXPORT_PYTHON_ENUM
|
||||||
|
/// Types of input a controller can send to the game.
|
||||||
|
///
|
||||||
|
/// Category: Enums
|
||||||
|
///
|
||||||
|
/// 'soft' may hide/reset the app but keep the process running, depending
|
||||||
|
/// on the platform.
|
||||||
|
///
|
||||||
|
/// 'back' is a variant of 'soft' which may give 'back-button-pressed'
|
||||||
|
/// behavior depending on the platform. (returning to some previous
|
||||||
|
/// activity instead of dumping to the home screen, etc.)
|
||||||
|
///
|
||||||
|
/// 'hard' leads to the process exiting. This generally should be avoided
|
||||||
|
/// on platforms such as mobile.
|
||||||
|
enum class QuitType {
|
||||||
|
kSoft,
|
||||||
|
kBack,
|
||||||
|
kHard,
|
||||||
|
kLast // Sentinel.
|
||||||
|
};
|
||||||
|
|
||||||
typedef int64_t TimerMedium;
|
typedef int64_t TimerMedium;
|
||||||
|
|
||||||
// BA_EXPORT_PYTHON_ENUM
|
// BA_EXPORT_PYTHON_ENUM
|
||||||
|
|||||||
@ -9,7 +9,6 @@
|
|||||||
#include "ballistica/base/platform/base_platform.h"
|
#include "ballistica/base/platform/base_platform.h"
|
||||||
#include "ballistica/base/python/base_python.h"
|
#include "ballistica/base/python/base_python.h"
|
||||||
#include "ballistica/base/support/plus_soft.h"
|
#include "ballistica/base/support/plus_soft.h"
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
|
||||||
#include "ballistica/ui_v1/python/class/python_class_ui_mesh.h"
|
#include "ballistica/ui_v1/python/class/python_class_ui_mesh.h"
|
||||||
#include "ballistica/ui_v1/python/class/python_class_ui_sound.h"
|
#include "ballistica/ui_v1/python/class/python_class_ui_sound.h"
|
||||||
#include "ballistica/ui_v1/python/class/python_class_ui_texture.h"
|
#include "ballistica/ui_v1/python/class/python_class_ui_texture.h"
|
||||||
|
|||||||
@ -4,9 +4,12 @@
|
|||||||
|
|
||||||
#include "ballistica/base/assets/assets.h"
|
#include "ballistica/base/assets/assets.h"
|
||||||
#include "ballistica/base/audio/audio.h"
|
#include "ballistica/base/audio/audio.h"
|
||||||
|
#include "ballistica/base/input/device/keyboard_input.h"
|
||||||
#include "ballistica/base/input/input.h"
|
#include "ballistica/base/input/input.h"
|
||||||
#include "ballistica/base/logic/logic.h"
|
#include "ballistica/base/logic/logic.h"
|
||||||
|
#include "ballistica/base/python/base_python.h"
|
||||||
#include "ballistica/base/python/support/python_context_call.h"
|
#include "ballistica/base/python/support/python_context_call.h"
|
||||||
|
#include "ballistica/base/ui/dev_console.h"
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
#include "ballistica/shared/foundation/event_loop.h"
|
||||||
#include "ballistica/shared/python/python_command.h"
|
#include "ballistica/shared/python/python_command.h"
|
||||||
#include "ballistica/shared/python/python_module_builder.h"
|
#include "ballistica/shared/python/python_module_builder.h"
|
||||||
@ -132,4 +135,27 @@ void UIV1Python::LaunchStringEditOld(TextWidget* w) {
|
|||||||
->Schedule(args);
|
->Schedule(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UIV1Python::InvokeQuitWindow(QuitType quit_type) {
|
||||||
|
assert(g_base->InLogicThread());
|
||||||
|
base::ScopedSetContext ssc(nullptr);
|
||||||
|
|
||||||
|
// If the in-app console is active, dismiss it.
|
||||||
|
if (auto* dev_console = g_base->ui->dev_console()) {
|
||||||
|
if (dev_console->IsActive()) {
|
||||||
|
dev_console->Dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_base->audio->PlaySound(g_base->assets->SysSound(base::SysSoundID::kSwish));
|
||||||
|
auto py_enum = g_base->python->PyQuitType(quit_type);
|
||||||
|
auto args = PythonRef::Stolen(Py_BuildValue("(O)", py_enum.Get()));
|
||||||
|
objs().Get(UIV1Python::ObjID::kQuitWindowCall).Call(args);
|
||||||
|
|
||||||
|
// If we have a keyboard, give it UI ownership.
|
||||||
|
base::InputDevice* keyboard = g_base->input->keyboard_input();
|
||||||
|
if (keyboard) {
|
||||||
|
g_base->ui->SetUIInputDevice(keyboard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ballistica::ui_v1
|
} // namespace ballistica::ui_v1
|
||||||
|
|||||||
@ -23,6 +23,7 @@ class UIV1Python {
|
|||||||
void ShowURL(const std::string& url);
|
void ShowURL(const std::string& url);
|
||||||
|
|
||||||
static auto GetPyWidget(PyObject* o) -> Widget*;
|
static auto GetPyWidget(PyObject* o) -> Widget*;
|
||||||
|
void InvokeQuitWindow(QuitType quit_type);
|
||||||
|
|
||||||
/// Specific Python objects we hold in objs_.
|
/// Specific Python objects we hold in objs_.
|
||||||
enum class ObjID {
|
enum class ObjID {
|
||||||
|
|||||||
@ -3,14 +3,15 @@
|
|||||||
#include "ballistica/ui_v1/ui_v1.h"
|
#include "ballistica/ui_v1/ui_v1.h"
|
||||||
|
|
||||||
#include "ballistica/base/app_mode/app_mode.h"
|
#include "ballistica/base/app_mode/app_mode.h"
|
||||||
|
#include "ballistica/base/audio/audio.h"
|
||||||
#include "ballistica/base/graphics/component/empty_component.h"
|
#include "ballistica/base/graphics/component/empty_component.h"
|
||||||
#include "ballistica/base/input/input.h"
|
#include "ballistica/base/input/input.h"
|
||||||
|
#include "ballistica/base/python/base_python.h"
|
||||||
#include "ballistica/base/support/app_config.h"
|
#include "ballistica/base/support/app_config.h"
|
||||||
#include "ballistica/ui_v1/python/ui_v1_python.h"
|
#include "ballistica/ui_v1/python/ui_v1_python.h"
|
||||||
#include "ballistica/ui_v1/support/root_ui.h"
|
#include "ballistica/ui_v1/support/root_ui.h"
|
||||||
#include "ballistica/ui_v1/widget/root_widget.h"
|
#include "ballistica/ui_v1/widget/root_widget.h"
|
||||||
#include "ballistica/ui_v1/widget/stack_widget.h"
|
#include "ballistica/ui_v1/widget/stack_widget.h"
|
||||||
#include "ballistica/ui_v1/widget/text_widget.h"
|
|
||||||
|
|
||||||
namespace ballistica::ui_v1 {
|
namespace ballistica::ui_v1 {
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ void UIV1FeatureSet::OnModuleExec(PyObject* module) {
|
|||||||
|
|
||||||
// Let base know we exist.
|
// Let base know we exist.
|
||||||
// (save it the trouble of trying to load us if it uses us passively).
|
// (save it the trouble of trying to load us if it uses us passively).
|
||||||
g_base->set_ui_v1(g_ui_v1);
|
// g_base->set_ui_v1(g_ui_v1);
|
||||||
|
|
||||||
g_core->LifecycleLog("_bauiv1 exec end");
|
g_core->LifecycleLog("_bauiv1 exec end");
|
||||||
}
|
}
|
||||||
@ -72,11 +73,9 @@ void UIV1FeatureSet::DoHandleDeviceMenuPress(base::InputDevice* device) {
|
|||||||
|
|
||||||
void UIV1FeatureSet::DoShowURL(const std::string& url) { python->ShowURL(url); }
|
void UIV1FeatureSet::DoShowURL(const std::string& url) { python->ShowURL(url); }
|
||||||
|
|
||||||
void UIV1FeatureSet::DoQuitWindow() {
|
// void UIV1FeatureSet::DoQuitWindow() {
|
||||||
g_ui_v1->python->objs().Get(UIV1Python::ObjID::kQuitWindowCall).Call();
|
// g_ui_v1->python->objs().Get(UIV1Python::ObjID::kQuitWindowCall).Call();
|
||||||
}
|
// }
|
||||||
|
|
||||||
RootUI* UIV1FeatureSet::NewRootUI() { return new RootUI(); }
|
|
||||||
|
|
||||||
bool UIV1FeatureSet::MainMenuVisible() {
|
bool UIV1FeatureSet::MainMenuVisible() {
|
||||||
// We consider anything on our screen or overlay stacks to be a 'main menu'.
|
// We consider anything on our screen or overlay stacks to be a 'main menu'.
|
||||||
@ -101,6 +100,7 @@ void UIV1FeatureSet::ActivatePartyIcon() {
|
|||||||
r->ActivatePartyIcon();
|
r->ActivatePartyIcon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UIV1FeatureSet::PartyWindowOpen() {
|
bool UIV1FeatureSet::PartyWindowOpen() {
|
||||||
if (auto* r = root_ui()) {
|
if (auto* r = root_ui()) {
|
||||||
return r->party_window_open();
|
return r->party_window_open();
|
||||||
@ -182,16 +182,16 @@ void UIV1FeatureSet::Draw(base::FrameDef* frame_def) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIV1FeatureSet::OnAppStart() {
|
void UIV1FeatureSet::OnActivate() {
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
root_ui_ = g_base->ui_v1()->NewRootUI();
|
if (root_ui_ == nullptr) {
|
||||||
|
root_ui_ = new RootUI();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
void UIV1FeatureSet::OnDeactivate() { assert(g_base->InLogicThread()); }
|
||||||
|
|
||||||
void UIV1FeatureSet::Reset() {
|
void UIV1FeatureSet::Reset() {
|
||||||
// Hmm; technically we don't need to recreate these each time we reset.
|
|
||||||
root_widget_.Clear();
|
root_widget_.Clear();
|
||||||
|
|
||||||
// Kill our screen-root widget.
|
|
||||||
screen_root_widget_.Clear();
|
screen_root_widget_.Clear();
|
||||||
|
|
||||||
// (Re)create our screen-root widget.
|
// (Re)create our screen-root widget.
|
||||||
@ -252,9 +252,15 @@ void UIV1FeatureSet::OnScreenSizeChange() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UIV1FeatureSet::OnLanguageChange() {
|
void UIV1FeatureSet::OnLanguageChange() {
|
||||||
// As well as existing UI stuff.
|
// Since switching languages is a bit costly, ignore redundant change
|
||||||
if (auto* r = root_widget()) {
|
// notifications. These will tend to happen nowadays since change
|
||||||
r->OnLanguageChange();
|
// notifications go out anytime the ui-delegate switches.
|
||||||
|
auto asset_language_state = g_base->assets->language_state();
|
||||||
|
if (asset_language_state != language_state_) {
|
||||||
|
language_state_ = asset_language_state;
|
||||||
|
if (auto* r = root_widget()) {
|
||||||
|
r->OnLanguageChange();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,6 +288,11 @@ void UIV1FeatureSet::DoApplyAppConfig() {
|
|||||||
base::AppConfig::BoolID::kAlwaysUseInternalKeyboard);
|
base::AppConfig::BoolID::kAlwaysUseInternalKeyboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto UIV1FeatureSet::HasQuitConfirmDialog() -> bool { return true; }
|
||||||
|
void UIV1FeatureSet::ConfirmQuit(QuitType quit_type) {
|
||||||
|
python->InvokeQuitWindow(quit_type);
|
||||||
|
}
|
||||||
|
|
||||||
UIV1FeatureSet::UILock::UILock(bool write) {
|
UIV1FeatureSet::UILock::UILock(bool write) {
|
||||||
assert(g_base->ui);
|
assert(g_base->ui);
|
||||||
assert(g_base->InLogicThread());
|
assert(g_base->InLogicThread());
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include <ballistica/base/input/device/input_device.h>
|
#include <ballistica/base/input/device/input_device.h>
|
||||||
|
|
||||||
#include "ballistica/base/support/ui_v1_soft.h"
|
#include "ballistica/base/ui/ui_delegate.h"
|
||||||
#include "ballistica/shared/foundation/feature_set_native_component.h"
|
#include "ballistica/shared/foundation/feature_set_native_component.h"
|
||||||
|
|
||||||
// Common header that most everything using our feature-set should include.
|
// Common header that most everything using our feature-set should include.
|
||||||
@ -64,7 +64,7 @@ extern UIV1FeatureSet* g_ui_v1;
|
|||||||
/// Our C++ front-end to our feature set. This is what other C++
|
/// Our C++ front-end to our feature set. This is what other C++
|
||||||
/// feature-sets can 'Import' from us.
|
/// feature-sets can 'Import' from us.
|
||||||
class UIV1FeatureSet : public FeatureSetNativeComponent,
|
class UIV1FeatureSet : public FeatureSetNativeComponent,
|
||||||
public base::UIV1SoftInterface {
|
public base::UIDelegateInterface {
|
||||||
public:
|
public:
|
||||||
/// Instantiate our FeatureSet if needed and return the single instance of
|
/// Instantiate our FeatureSet if needed and return the single instance of
|
||||||
/// it. Basically a Python import statement.
|
/// it. Basically a Python import statement.
|
||||||
@ -85,8 +85,7 @@ class UIV1FeatureSet : public FeatureSetNativeComponent,
|
|||||||
static void OnModuleExec(PyObject* module);
|
static void OnModuleExec(PyObject* module);
|
||||||
void DoHandleDeviceMenuPress(base::InputDevice* device) override;
|
void DoHandleDeviceMenuPress(base::InputDevice* device) override;
|
||||||
void DoShowURL(const std::string& url) override;
|
void DoShowURL(const std::string& url) override;
|
||||||
void DoQuitWindow() override;
|
// void DoQuitWindow() override;
|
||||||
auto NewRootUI() -> ui_v1::RootUI* override;
|
|
||||||
auto MainMenuVisible() -> bool override;
|
auto MainMenuVisible() -> bool override;
|
||||||
auto PartyIconVisible() -> bool override;
|
auto PartyIconVisible() -> bool override;
|
||||||
void ActivatePartyIcon() override;
|
void ActivatePartyIcon() override;
|
||||||
@ -101,7 +100,10 @@ class UIV1FeatureSet : public FeatureSetNativeComponent,
|
|||||||
assert(root_ui_);
|
assert(root_ui_);
|
||||||
return root_ui_;
|
return root_ui_;
|
||||||
}
|
}
|
||||||
void OnAppStart() override;
|
// void OnAppStart() override;
|
||||||
|
void OnActivate() override;
|
||||||
|
void OnDeactivate() override;
|
||||||
|
|
||||||
auto PartyWindowOpen() -> bool override;
|
auto PartyWindowOpen() -> bool override;
|
||||||
|
|
||||||
// Return the root widget containing all windows & dialogs. Whenever this
|
// Return the root widget containing all windows & dialogs. Whenever this
|
||||||
@ -134,6 +136,9 @@ class UIV1FeatureSet : public FeatureSetNativeComponent,
|
|||||||
return always_use_internal_on_screen_keyboard_;
|
return always_use_internal_on_screen_keyboard_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto HasQuitConfirmDialog() -> bool override;
|
||||||
|
void ConfirmQuit(QuitType quit_type) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UIV1FeatureSet();
|
UIV1FeatureSet();
|
||||||
RootUI* root_ui_{};
|
RootUI* root_ui_{};
|
||||||
@ -142,6 +147,7 @@ class UIV1FeatureSet : public FeatureSetNativeComponent,
|
|||||||
Object::Ref<RootWidget> root_widget_;
|
Object::Ref<RootWidget> root_widget_;
|
||||||
bool always_use_internal_on_screen_keyboard_{};
|
bool always_use_internal_on_screen_keyboard_{};
|
||||||
int ui_lock_count_{};
|
int ui_lock_count_{};
|
||||||
|
int language_state_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::ui_v1
|
} // namespace ballistica::ui_v1
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "ballistica/ui_v1/widget/text_widget.h"
|
#include "ballistica/ui_v1/widget/text_widget.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/empty_component.h"
|
#include "ballistica/base/graphics/component/empty_component.h"
|
||||||
#include "ballistica/base/graphics/component/simple_component.h"
|
#include "ballistica/base/graphics/component/simple_component.h"
|
||||||
@ -13,11 +12,6 @@
|
|||||||
#include "ballistica/base/platform/base_platform.h"
|
#include "ballistica/base/platform/base_platform.h"
|
||||||
#include "ballistica/base/python/base_python.h"
|
#include "ballistica/base/python/base_python.h"
|
||||||
#include "ballistica/base/python/support/python_context_call.h"
|
#include "ballistica/base/python/support/python_context_call.h"
|
||||||
#include "ballistica/base/ui/ui.h"
|
|
||||||
#include "ballistica/core/core.h"
|
|
||||||
#include "ballistica/shared/foundation/event_loop.h"
|
|
||||||
#include "ballistica/shared/foundation/logging.h"
|
|
||||||
#include "ballistica/shared/foundation/types.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"
|
||||||
|
|||||||
@ -69,6 +69,7 @@ values = [
|
|||||||
_error.SessionNotFoundError, # kSessionNotFoundError
|
_error.SessionNotFoundError, # kSessionNotFoundError
|
||||||
enums.TimeFormat, # kTimeFormatClass
|
enums.TimeFormat, # kTimeFormatClass
|
||||||
enums.TimeType, # kTimeTypeClass
|
enums.TimeType, # kTimeTypeClass
|
||||||
|
enums.QuitType, # kQuitTypeClass
|
||||||
enums.InputType, # kInputTypeClass
|
enums.InputType, # kInputTypeClass
|
||||||
enums.Permission, # kPermissionClass
|
enums.Permission, # kPermissionClass
|
||||||
enums.SpecialChar, # kSpecialCharClass
|
enums.SpecialChar, # kSpecialCharClass
|
||||||
|
|||||||
@ -14,8 +14,8 @@ values = [
|
|||||||
app.push_apply_app_config, # kAppPushApplyAppConfigCall
|
app.push_apply_app_config, # kAppPushApplyAppConfigCall
|
||||||
app.on_native_start, # kAppOnNativeStartCall
|
app.on_native_start, # kAppOnNativeStartCall
|
||||||
app.on_native_bootstrapping_complete, # kAppOnNativeBootstrappingCompleteCall
|
app.on_native_bootstrapping_complete, # kAppOnNativeBootstrappingCompleteCall
|
||||||
app.on_native_pause, # kAppOnNativePauseCall
|
app.on_native_suspend, # kAppOnNativeSuspendCall
|
||||||
app.on_native_resume, # kAppOnNativeResumeCall
|
app.on_native_unsuspend, # kAppOnNativeUnsuspendCall
|
||||||
app.on_native_shutdown, # kAppOnNativeShutdownCall
|
app.on_native_shutdown, # kAppOnNativeShutdownCall
|
||||||
app.on_native_shutdown_complete, # kAppOnNativeShutdownCompleteCall
|
app.on_native_shutdown_complete, # kAppOnNativeShutdownCompleteCall
|
||||||
app.read_config, # kAppReadConfigCall
|
app.read_config, # kAppReadConfigCall
|
||||||
|
|||||||
BIN
src/resources/cursor.png
Normal file
BIN
src/resources/cursor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@ -48,7 +48,7 @@ def _gen_lprop_file(local_properties_path: str) -> str:
|
|||||||
if not found:
|
if not found:
|
||||||
home = os.getenv('HOME')
|
home = os.getenv('HOME')
|
||||||
assert home is not None
|
assert home is not None
|
||||||
test_paths = [home + '/Library/Android/sdk']
|
test_paths = [home + '/Library/Android/sdk', home + '/AndroidSDK']
|
||||||
for sdk_dir in test_paths:
|
for sdk_dir in test_paths:
|
||||||
if os.path.exists(sdk_dir):
|
if os.path.exists(sdk_dir):
|
||||||
found = True
|
found = True
|
||||||
@ -58,12 +58,10 @@ def _gen_lprop_file(local_properties_path: str) -> str:
|
|||||||
assert sdk_dir is not None
|
assert sdk_dir is not None
|
||||||
if not found:
|
if not found:
|
||||||
if not os.path.exists(sdk_dir):
|
if not os.path.exists(sdk_dir):
|
||||||
print(
|
raise CleanError(
|
||||||
'ERROR: Android sdk not found; install '
|
f'Android sdk not found at {sdk_dir}; install '
|
||||||
'the android sdk and try again',
|
'the android sdk and try again.',
|
||||||
file=sys.stderr,
|
|
||||||
)
|
)
|
||||||
sys.exit(255)
|
|
||||||
config = (
|
config = (
|
||||||
'\n# This file was automatically generated by '
|
'\n# This file was automatically generated by '
|
||||||
+ os.path.abspath(sys.argv[0])
|
+ os.path.abspath(sys.argv[0])
|
||||||
|
|||||||
@ -43,8 +43,8 @@ class PyRequirement:
|
|||||||
# remove our custom module based stuff soon if nobody complains, which
|
# remove our custom module based stuff soon if nobody complains, which
|
||||||
# would free us to theoretically move to a requirements.txt based setup.
|
# would free us to theoretically move to a requirements.txt based setup.
|
||||||
PY_REQUIREMENTS = [
|
PY_REQUIREMENTS = [
|
||||||
PyRequirement(pipname='pylint', minversion=[3, 0, 0]),
|
PyRequirement(pipname='pylint', minversion=[3, 0, 1]),
|
||||||
PyRequirement(pipname='mypy', minversion=[1, 5, 1]),
|
PyRequirement(pipname='mypy', minversion=[1, 6, 0]),
|
||||||
PyRequirement(pipname='cpplint', minversion=[1, 6, 1]),
|
PyRequirement(pipname='cpplint', minversion=[1, 6, 1]),
|
||||||
PyRequirement(pipname='pytest', minversion=[7, 4, 2]),
|
PyRequirement(pipname='pytest', minversion=[7, 4, 2]),
|
||||||
PyRequirement(pipname='pytz', minversion=[2023, 3]),
|
PyRequirement(pipname='pytz', minversion=[2023, 3]),
|
||||||
@ -706,7 +706,7 @@ def cmake_prep_dir(dirname: str, verbose: bool = False) -> None:
|
|||||||
# away all cmake builds everywhere (to keep things clean if we
|
# away all cmake builds everywhere (to keep things clean if we
|
||||||
# rename or move something in the build dir or if we change
|
# rename or move something in the build dir or if we change
|
||||||
# something cmake doesn't properly handle without a fresh start).
|
# something cmake doesn't properly handle without a fresh start).
|
||||||
entries: list[Entry] = [Entry('explicit cmake rebuild', '3')]
|
entries: list[Entry] = [Entry('explicit cmake rebuild', '4')]
|
||||||
|
|
||||||
# Start fresh if cmake version changes.
|
# Start fresh if cmake version changes.
|
||||||
cmake_ver_output = subprocess.run(
|
cmake_ver_output = subprocess.run(
|
||||||
|
|||||||
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