mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-19 13:25:31 +08:00
cleaned up interaction between graphics server and client which will make alternate renderers more doable
This commit is contained in:
parent
a3b51abb03
commit
b5b34b4455
106
.efrocachemap
generated
106
.efrocachemap
generated
@ -421,7 +421,7 @@
|
||||
"build/assets/ba_data/audio/zoeOw.ogg": "74befe45a8417e95b6a2233c51992a26",
|
||||
"build/assets/ba_data/audio/zoePickup01.ogg": "48ab8cddfcde36a750856f3f81dd20c8",
|
||||
"build/assets/ba_data/audio/zoeScream01.ogg": "2b468aedfa8741090247f04eb9e6df55",
|
||||
"build/assets/ba_data/data/langdata.json": "7a5f49ae1738b012a6d7c16740af80a0",
|
||||
"build/assets/ba_data/data/langdata.json": "1a960da2db069ca3926b8ee6b8f82df7",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "295c559911fa251f401f8cdcad91c226",
|
||||
"build/assets/ba_data/data/languages/belarussian.json": "e151808b6b4f6dc159cf55ee62adad3c",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "b0d4e874ba8d22c8fd0d7a0eaaf96ac9",
|
||||
@ -433,30 +433,30 @@
|
||||
"build/assets/ba_data/data/languages/english.json": "e70277fc6325126d3d893524c8df03c9",
|
||||
"build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880",
|
||||
"build/assets/ba_data/data/languages/filipino.json": "347f38524816691170d266708fe25894",
|
||||
"build/assets/ba_data/data/languages/french.json": "d8527da977a563185de25ef02bacf826",
|
||||
"build/assets/ba_data/data/languages/french.json": "4e218dcd488fa63e7db5b4da2261b9e1",
|
||||
"build/assets/ba_data/data/languages/german.json": "450fa41ae264f29a5d1af22143d0d0ad",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "7863ceeedb1e87eef46f7769bae5f842",
|
||||
"build/assets/ba_data/data/languages/greek.json": "a65d78f912e9a89f98de004405167a6a",
|
||||
"build/assets/ba_data/data/languages/hindi.json": "88ee0cda537bab9ac827def5e236fe1a",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "b8dfd407fb7fd9b268129c364b70ca54",
|
||||
"build/assets/ba_data/data/languages/greek.json": "287c0ec437b38772284ef9d3e4fb2fc3",
|
||||
"build/assets/ba_data/data/languages/hindi.json": "8ea0c58a44a24edb131d0e53b074d1f6",
|
||||
"build/assets/ba_data/data/languages/hungarian.json": "796a290a8c44a1e7635208c2ff5fdc6e",
|
||||
"build/assets/ba_data/data/languages/indonesian.json": "bff88ce57744a639810b93a1d1dd79f4",
|
||||
"build/assets/ba_data/data/languages/indonesian.json": "53961b1484a1831f32bec2cc2941e672",
|
||||
"build/assets/ba_data/data/languages/italian.json": "58ecf53a963dbeca1bbf3605e5ab6a2f",
|
||||
"build/assets/ba_data/data/languages/korean.json": "ca1122a9ee551da3f75ae632012bd0e2",
|
||||
"build/assets/ba_data/data/languages/malay.json": "832562ce997fc70704b9234c95fb2e38",
|
||||
"build/assets/ba_data/data/languages/persian.json": "71cc5b33abda0f285b970b8cc4a014a8",
|
||||
"build/assets/ba_data/data/languages/persian.json": "a391d80ff58ea22926499e4b19d2c0d0",
|
||||
"build/assets/ba_data/data/languages/polish.json": "e1a1a801851924748ad38fa68216439a",
|
||||
"build/assets/ba_data/data/languages/portuguese.json": "9fcd6b4da9e5d0dc0e337ab00b5debe2",
|
||||
"build/assets/ba_data/data/languages/romanian.json": "aeebdd54f65939c2facc6ac50c117826",
|
||||
"build/assets/ba_data/data/languages/russian.json": "70f79c606ccc5ec7bd6ce0303fdece70",
|
||||
"build/assets/ba_data/data/languages/serbian.json": "d7452dd72ac0e51680cb39b5ebaa1c69",
|
||||
"build/assets/ba_data/data/languages/slovak.json": "27962d53dc3f7dd4e877cd40faafeeef",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "6ccd728df4766be1969434d6f04c36d2",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "e72e394f94b99d3e838c1b81a9d17615",
|
||||
"build/assets/ba_data/data/languages/swedish.json": "77d671f10613291ebf9c71da66f18a18",
|
||||
"build/assets/ba_data/data/languages/tamil.json": "65ab7798d637fa62a703750179eeb723",
|
||||
"build/assets/ba_data/data/languages/thai.json": "33f63753c9af9a5b238d229a0bf23fbc",
|
||||
"build/assets/ba_data/data/languages/turkish.json": "42318070b817663f671d78a9c8f3019c",
|
||||
"build/assets/ba_data/data/languages/ukrainian.json": "f72eb51abfbbb56e27866895d7e947d2",
|
||||
"build/assets/ba_data/data/languages/venetian.json": "88595b7ee696b4094d7874c3c4188852",
|
||||
"build/assets/ba_data/data/languages/venetian.json": "9fe1a58d9e5dfb00f31ce3b2eb9993f4",
|
||||
"build/assets/ba_data/data/languages/vietnamese.json": "921cd1e50f60fe3e101f246e172750ba",
|
||||
"build/assets/ba_data/data/maps/big_g.json": "1dd301d490643088a435ce75df971054",
|
||||
"build/assets/ba_data/data/maps/bridgit.json": "6aea74805f4880cc11237c5734a24422",
|
||||
@ -4056,50 +4056,50 @@
|
||||
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
|
||||
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
|
||||
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "ece14cc6d7a449f581c810a2d6d3449d",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "b0b75bde134af8c73aa1f7e239bd84dc",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "f0742e77993c006a5f2df3e9bee6732e",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "b803f154b4bf2aeb908a603fa7888301",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "2be90b3e6fc6908448a7677dd3cfb594",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "4d12d1887901f7c77b5df965bb0b4622",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "987f4e024c7ed08e58223369b40aa309",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "7dd6ce5ab63d9d255029fb907cf6fb63",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "ad505c3ad979b2cf52c664ee79798575",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "3773aa5c6d396b4c38883321067f5523",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "748f3877c0ac40f48ebc5d8aab442173",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "2d059f03286603ac416718eb262241ab",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "3bd988564ed41c15b4d0f493eced88ef",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "f01539e046d72d86d63da0b4b6fc28df",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "d554e6d3ef9709ad7d7c848633901089",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "967375f76d43831afd7e10208502dcc1",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "7dba8e8a0b8ffbe7f8d73b33b0c41ed5",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "11ccabb65197c9f2e3059ac434888e11",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "8d79aece6620eb017896a7e816a78f0d",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "a3331c3d60962e7f0c2b62728bf7f43e",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "1636f9569ee8b8a6c0abed5c9e31e3f7",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "3fc153ee973090358916b90938429931",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "1636f9569ee8b8a6c0abed5c9e31e3f7",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "3fc153ee973090358916b90938429931",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "1c7ed5b60c2961cf7d1a918157f90bce",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "0cbfd345b7e6a02d2a6bdfe7966d03d1",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "1c7ed5b60c2961cf7d1a918157f90bce",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "0cbfd345b7e6a02d2a6bdfe7966d03d1",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "1360496e008c0d0fb631b2fde94e0d54",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "f64f8060f46a1f7088c7aadef33220dd",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "1360496e008c0d0fb631b2fde94e0d54",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "f64f8060f46a1f7088c7aadef33220dd",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "dc45874c7796f4fc740c224243efac28",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "c7e7528347b1ec5bc37b13ed8ae88df1",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "abeca8c975a6cd5766fc90df99e8dcd1",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "c7e7528347b1ec5bc37b13ed8ae88df1",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "7aa3fa305f66461ec5e5bbc550aa742d",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "89c02f2300860fded6b44855f9b8407f",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "69f97da125d43fc396eeaea8013cb133",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "9e56ac32e0cc2785811a162de68c69da",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "a62570a46fed2002590be0bafe5055e8",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "b2a10b1eb917197da8f981d5a5daed44",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "c3af2f896ddb7a0b5f2ee2f35bac0318",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "30628de8aa6a7d9cfccf09f102ff9953",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "48b5a58b401a2b22b88491f7bcd0e22a",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "6d83849db3e1398503e2bb682eb4323e",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "b054c284b778dc77edc9c9b046303f46",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "b16789743a603fac02763c09bbca446b",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "ab0a78d42cc511b4041478205e892897",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "4bbb41936ffe72a7fe9bdc803761b937",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "a1427251545496f84c4d4e2d90e6e25a",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "729bec30bafe25cac07f920c0cc30ab8",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "f8b086fdf6bca929ebc75b117b80f522",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "7d8f3ffe791e5a665ecbb2c517483814",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "5f4207138b152a110593c6c5ea8a9b32",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "4211f250197995e7df6942d32cffd202",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "40be1e38cbac3baf88dee161eeb912e1",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "d4aacb95a1855e969d1cc8db33732c40",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "570f49dc1de66e3fe75d76ee5f9306e0",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "ad319e6fb3cd7043a597f0780de42a98",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "4c15b26f43b4cb81f433beeb927c8aa6",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "a06aaa7a95abb56d49ba7925cc503a28",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "82619b88184faf3ef7ae4bf41ea282ce",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "61251e6fe58347224750fdf30d4bf8bc",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "bbd5b31cd9b4d30e48ce46e2cf968fcf",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "4e11b895cbf2e1339cf34bc06c54a4ea",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "bbd5b31cd9b4d30e48ce46e2cf968fcf",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "4e11b895cbf2e1339cf34bc06c54a4ea",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "b483573e1ef7e6be1090c67187e9d1d8",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "ae5f87286947575463c386cfe1c443e4",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "b483573e1ef7e6be1090c67187e9d1d8",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "ae5f87286947575463c386cfe1c443e4",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "cf4e9ef8006953c365b0928c68f5a21b",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "2692dc69f7cb2501f0aaa8675f559987",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "cf4e9ef8006953c365b0928c68f5a21b",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "2692dc69f7cb2501f0aaa8675f559987",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "840e96e79a56393c353184475cf28fbc",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "48c4873dae2344c1d4092a1d85dab424",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "d0940a2237c33b922cf3747cbf3910ef",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "48c4873dae2344c1d4092a1d85dab424",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "52ccfcbba95dcf3d06620748690446be",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "8369a217dc8cd95db308851de9f35d86",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "6bc8e9e67a0cbe50ab2c6891d454570f",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "2ce9d1659647bca4725f404d192c3554",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "8fd2fd1ec12170942823e809332e8cb9",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "f40bd1a61620168791b88901975ea8ee",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "4e3f244ac43cd400ffdbd2ac2e887399",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "a5e5e62c259e23429eca4af7054cc7cb",
|
||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "28323912b56ec07701eda3d41a6a4101",
|
||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "bb96031e3f844704fcc9a0549a6d2c41",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
### 1.7.28 (build 21479, api 8, 2023-10-17)
|
||||
### 1.7.28 (build 21486, api 8, 2023-10-20)
|
||||
|
||||
- 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
|
||||
|
||||
@ -353,6 +353,10 @@ set(BALLISTICA_SOURCES
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/camera.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/frame_def.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/frame_def.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/graphics_client_context.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/graphics_client_context.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/graphics_settings.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/graphics_settings.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/net_graph.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/net_graph.h
|
||||
${BA_SRC_ROOT}/ballistica/base/graphics/support/render_command_buffer.h
|
||||
@ -688,6 +692,7 @@ set(BALLISTICA_SOURCES
|
||||
${BA_SRC_ROOT}/ballistica/shared/generic/lambda_runnable.h
|
||||
${BA_SRC_ROOT}/ballistica/shared/generic/runnable.cc
|
||||
${BA_SRC_ROOT}/ballistica/shared/generic/runnable.h
|
||||
${BA_SRC_ROOT}/ballistica/shared/generic/snapshot.h
|
||||
${BA_SRC_ROOT}/ballistica/shared/generic/timer_list.cc
|
||||
${BA_SRC_ROOT}/ballistica/shared/generic/timer_list.h
|
||||
${BA_SRC_ROOT}/ballistica/shared/generic/utf8.cc
|
||||
|
||||
@ -345,6 +345,10 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\camera.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\frame_def.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\frame_def.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_settings.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_settings.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\net_graph.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\net_graph.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\render_command_buffer.h" />
|
||||
@ -680,6 +684,7 @@
|
||||
<ClInclude Include="..\..\src\ballistica\shared\generic\lambda_runnable.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\shared\generic\runnable.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\shared\generic\runnable.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\shared\generic\snapshot.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\shared\generic\timer_list.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\shared\generic\timer_list.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\shared\generic\utf8.cc" />
|
||||
|
||||
@ -469,6 +469,18 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\frame_def.h">
|
||||
<Filter>ballistica\base\graphics\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.cc">
|
||||
<Filter>ballistica\base\graphics\support</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.h">
|
||||
<Filter>ballistica\base\graphics\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_settings.cc">
|
||||
<Filter>ballistica\base\graphics\support</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_settings.h">
|
||||
<Filter>ballistica\base\graphics\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\net_graph.cc">
|
||||
<Filter>ballistica\base\graphics\support</Filter>
|
||||
</ClCompile>
|
||||
@ -1474,6 +1486,9 @@
|
||||
<ClInclude Include="..\..\src\ballistica\shared\generic\runnable.h">
|
||||
<Filter>ballistica\shared\generic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\shared\generic\snapshot.h">
|
||||
<Filter>ballistica\shared\generic</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\shared\generic\timer_list.cc">
|
||||
<Filter>ballistica\shared\generic</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@ -340,6 +340,10 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\camera.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\frame_def.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\frame_def.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_settings.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_settings.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\net_graph.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\net_graph.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\render_command_buffer.h" />
|
||||
@ -675,6 +679,7 @@
|
||||
<ClInclude Include="..\..\src\ballistica\shared\generic\lambda_runnable.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\shared\generic\runnable.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\shared\generic\runnable.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\shared\generic\snapshot.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\shared\generic\timer_list.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\shared\generic\timer_list.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\shared\generic\utf8.cc" />
|
||||
|
||||
@ -469,6 +469,18 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\frame_def.h">
|
||||
<Filter>ballistica\base\graphics\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.cc">
|
||||
<Filter>ballistica\base\graphics\support</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_client_context.h">
|
||||
<Filter>ballistica\base\graphics\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\graphics_settings.cc">
|
||||
<Filter>ballistica\base\graphics\support</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\graphics\support\graphics_settings.h">
|
||||
<Filter>ballistica\base\graphics\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\graphics\support\net_graph.cc">
|
||||
<Filter>ballistica\base\graphics\support</Filter>
|
||||
</ClCompile>
|
||||
@ -1474,6 +1486,9 @@
|
||||
<ClInclude Include="..\..\src\ballistica\shared\generic\runnable.h">
|
||||
<Filter>ballistica\shared\generic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ballistica\shared\generic\snapshot.h">
|
||||
<Filter>ballistica\shared\generic</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\shared\generic\timer_list.cc">
|
||||
<Filter>ballistica\shared\generic</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@ -185,10 +185,8 @@ def _feed_logs_to_babase(log_handler: LogHandler) -> None:
|
||||
def _on_log(entry: LogEntry) -> None:
|
||||
# Forward this along to the engine to display in the in-app
|
||||
# console, in the Android log, etc.
|
||||
_babase.display_log(
|
||||
name=entry.name,
|
||||
level=entry.level.name,
|
||||
message=entry.message,
|
||||
_babase.emit_log(
|
||||
name=entry.name, level=entry.level.name, message=entry.message
|
||||
)
|
||||
|
||||
# We also want to feed some logs to the old v1-cloud-log system.
|
||||
|
||||
@ -52,7 +52,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 21479
|
||||
TARGET_BALLISTICA_BUILD = 21486
|
||||
TARGET_BALLISTICA_VERSION = '1.7.28'
|
||||
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
#include "ballistica/base/app_adapter/app_adapter.h"
|
||||
|
||||
#if BA_OSTYPE_ANDROID
|
||||
#if BA_OSTYPE_ANDROID // Remove conditional once android sources are public.
|
||||
#include "ballistica/base/app_adapter/app_adapter_android.h"
|
||||
#endif
|
||||
#include "ballistica/base/app_adapter/app_adapter_apple.h"
|
||||
@ -305,4 +305,14 @@ void AppAdapter::DoSoftQuit() { FatalError("Fixme unimplemented."); }
|
||||
void AppAdapter::TerminateApp() { FatalError("Fixme unimplemented."); }
|
||||
auto AppAdapter::HasDirectKeyboardInput() -> bool { return false; }
|
||||
|
||||
void AppAdapter::ApplyGraphicsSettings(const GraphicsSettings* settings) {}
|
||||
|
||||
auto AppAdapter::GetGraphicsSettings() -> GraphicsSettings* {
|
||||
return new GraphicsSettings();
|
||||
}
|
||||
|
||||
auto AppAdapter::GetGraphicsClientContext() -> GraphicsClientContext* {
|
||||
return new GraphicsClientContext();
|
||||
}
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -30,6 +30,16 @@ class AppAdapter {
|
||||
virtual void OnScreenSizeChange();
|
||||
virtual void DoApplyAppConfig();
|
||||
|
||||
/// When called, should allocate an instance of a GraphicsSettings
|
||||
/// subclass using 'new', fill it out, and return it. Runs in the logic
|
||||
/// thread.
|
||||
virtual auto GetGraphicsSettings() -> GraphicsSettings*;
|
||||
|
||||
/// When called, should allocate an instance of a GraphicsClientContext
|
||||
/// subclass using 'new', fill it out, and return it. Runs in the graphics
|
||||
/// context.
|
||||
virtual auto GetGraphicsClientContext() -> GraphicsClientContext*;
|
||||
|
||||
/// Return whether this class manages the main thread event loop itself.
|
||||
/// Default is true. If this is true, RunMainThreadEventLoopToCompletion()
|
||||
/// will be called to run the app. This should return false on builds
|
||||
@ -181,6 +191,17 @@ class AppAdapter {
|
||||
/// should be callable from any thread.
|
||||
virtual auto HasDirectKeyboardInput() -> bool;
|
||||
|
||||
/// Called in the graphics context to apply new settings coming in from
|
||||
/// the logic subsystem. This will be called initially to jump-start the
|
||||
/// graphics system as well as before frame draws to update any new
|
||||
/// settings coming in.
|
||||
///
|
||||
/// Whenever graphics settings will result in a change to the graphics
|
||||
/// context (ie: something visible to rendering code in the logic thread)
|
||||
/// the adapter should call g_base->graphics_server->set_context() with
|
||||
/// the updated context.
|
||||
virtual void ApplyGraphicsSettings(const GraphicsSettings* settings);
|
||||
|
||||
protected:
|
||||
AppAdapter();
|
||||
virtual ~AppAdapter();
|
||||
|
||||
@ -44,58 +44,27 @@ void AppAdapterApple::DoPushMainThreadRunnable(Runnable* runnable) {
|
||||
BallisticaKit::FromCppPushRawRunnableToMain(runnable);
|
||||
}
|
||||
|
||||
void AppAdapterApple::DoApplyAppConfig() {
|
||||
assert(g_base->InLogicThread());
|
||||
void AppAdapterApple::DoApplyAppConfig() { assert(g_base->InLogicThread()); }
|
||||
|
||||
g_base->graphics_server->PushSetScreenPixelScaleCall(
|
||||
g_base->app_config->Resolve(AppConfig::FloatID::kScreenPixelScale));
|
||||
void AppAdapterApple::ApplyGraphicsSettings(const GraphicsSettings* settings) {
|
||||
auto* graphics_server = g_base->graphics_server;
|
||||
|
||||
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 a renderer yet.
|
||||
bool need_full_reload = ((graphics_server->texture_quality_requested()
|
||||
!= settings->texture_quality)
|
||||
|| (graphics_server->graphics_quality_requested()
|
||||
!= settings->graphics_quality));
|
||||
|
||||
// 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());
|
||||
// don't yet have a renderer.
|
||||
|
||||
if (need_full_reload) {
|
||||
ReloadRenderer_(graphics_quality_requested, texture_quality_requested);
|
||||
ReloadRenderer_(settings);
|
||||
}
|
||||
|
||||
// Let the logic thread know we've got a graphics system up and running.
|
||||
// It may use this cue to kick off asset loads and other bootstrapping.
|
||||
g_base->logic->event_loop()->PushCall(
|
||||
[] { g_base->logic->OnGraphicsReady(); });
|
||||
}
|
||||
|
||||
void AppAdapterApple::ReloadRenderer_(
|
||||
GraphicsQualityRequest graphics_quality_requested,
|
||||
TextureQualityRequest texture_quality_requested) {
|
||||
void AppAdapterApple::ReloadRenderer_(const GraphicsSettings* settings) {
|
||||
auto* gs = g_base->graphics_server;
|
||||
|
||||
if (gs->renderer() && gs->renderer_loaded()) {
|
||||
@ -109,11 +78,11 @@ void AppAdapterApple::ReloadRenderer_(
|
||||
// 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);
|
||||
// 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);
|
||||
gs->set_graphics_quality_requested(settings->graphics_quality);
|
||||
gs->set_texture_quality_requested(settings->texture_quality);
|
||||
|
||||
// (Re)load stuff with these latest quality settings.
|
||||
gs->LoadRenderer();
|
||||
@ -123,12 +92,6 @@ 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);
|
||||
|
||||
@ -146,10 +109,45 @@ auto AppAdapterApple::TryRender() -> bool {
|
||||
call->RunAndLogErrors();
|
||||
delete call;
|
||||
}
|
||||
// Lastly render.
|
||||
return g_base->graphics_server->TryRender();
|
||||
|
||||
return true;
|
||||
// Lastly, render.
|
||||
auto result = g_base->graphics_server->TryRender();
|
||||
|
||||
// A little trick to make mac resizing look a lot smoother. Because we
|
||||
// render in a background thread, we often don't render at the most up to
|
||||
// date window size during a window resize. Normally this makes our image
|
||||
// jerk around in an ugly way, but if we just re-render once or twice in
|
||||
// those cases we mostly always get the most up to date window size.
|
||||
if (result && resize_friendly_frames_ > 0) {
|
||||
// Leave this enabled for just a few frames every time it is set.
|
||||
// (so just in case it breaks we won't draw each frame serveral times for
|
||||
// eternity).
|
||||
resize_friendly_frames_ -= 1;
|
||||
|
||||
// Keep on drawing until the drawn window size
|
||||
// matches what we have (or until we try for too long or fail at drawing).
|
||||
seconds_t start_time = g_core->GetAppTimeSeconds();
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
if (((std::abs(resize_target_resolution_.x
|
||||
- g_base->graphics_server->screen_pixel_width())
|
||||
> 0.01f)
|
||||
|| (std::abs(resize_target_resolution_.y
|
||||
- g_base->graphics_server->screen_pixel_height())
|
||||
> 0.01f))
|
||||
&& g_core->GetAppTimeSeconds() - start_time < 0.1 && result) {
|
||||
result = g_base->graphics_server->TryRender();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void AppAdapterApple::EnableResizeFriendlyMode(int width, int height) {
|
||||
resize_friendly_frames_ = 5;
|
||||
resize_target_resolution_ = Vector2f(width, height);
|
||||
}
|
||||
|
||||
auto AppAdapterApple::InGraphicsContext() -> bool {
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
#include "ballistica/base/app_adapter/app_adapter.h"
|
||||
#include "ballistica/shared/generic/runnable.h"
|
||||
#include "ballistica/shared/math/vector2f.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
@ -32,7 +33,7 @@ class AppAdapterApple : public AppAdapter {
|
||||
auto TryRender() -> bool;
|
||||
|
||||
/// Called by FromSwift.
|
||||
void SetScreenResolution(float pixel_width, float pixel_height);
|
||||
// void SetScreenResolution(float pixel_width, float pixel_height);
|
||||
|
||||
auto FullscreenControlAvailable() const -> bool override;
|
||||
auto FullscreenControlGet() const -> bool override;
|
||||
@ -42,6 +43,8 @@ class AppAdapterApple : public AppAdapter {
|
||||
|
||||
auto HasDirectKeyboardInput() -> bool override;
|
||||
|
||||
void EnableResizeFriendlyMode(int width, int height);
|
||||
|
||||
protected:
|
||||
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
||||
void DoPushGraphicsContextRunnable(Runnable* runnable) override;
|
||||
@ -50,16 +53,18 @@ class AppAdapterApple : public AppAdapter {
|
||||
auto HasHardwareCursor() -> bool override;
|
||||
void SetHardwareCursorVisible(bool visible) override;
|
||||
void TerminateApp() override;
|
||||
void ApplyGraphicsSettings(const GraphicsSettings* settings) override;
|
||||
|
||||
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);
|
||||
|
||||
void UpdateScreenSizes_();
|
||||
void ReloadRenderer_(const GraphicsSettings* settings);
|
||||
|
||||
std::thread::id graphics_thread_{};
|
||||
bool graphics_allowed_;
|
||||
bool graphics_allowed_ : 1 {};
|
||||
uint8_t resize_friendly_frames_{};
|
||||
Vector2f resize_target_resolution_{-1.0f, -1.0f};
|
||||
std::mutex graphics_calls_mutex_;
|
||||
std::vector<Runnable*> graphics_calls_;
|
||||
};
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "ballistica/base/app_adapter/app_adapter_headless.h"
|
||||
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
#include "ballistica/base/graphics/support/graphics_client_context.h"
|
||||
#include "ballistica/shared/ballistica.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
@ -19,12 +20,7 @@ void AppAdapterHeadless::OnMainThreadStartApp() {
|
||||
new EventLoop(EventLoopID::kMain, ThreadSource::kWrapCurrent);
|
||||
}
|
||||
|
||||
void AppAdapterHeadless::DoApplyAppConfig() {
|
||||
// Normal graphical app-adapters kick off screen creation here
|
||||
// which then leads to remaining app bootstrapping. We create
|
||||
// a 'null' screen purely for the same effect.
|
||||
PushMainThreadCall([] { g_base->graphics_server->SetNullGraphics(); });
|
||||
}
|
||||
void AppAdapterHeadless::DoApplyAppConfig() {}
|
||||
|
||||
void AppAdapterHeadless::RunMainThreadEventLoopToCompletion() {
|
||||
assert(g_core->InMainThread());
|
||||
@ -40,6 +36,11 @@ void AppAdapterHeadless::DoExitMainThreadEventLoop() {
|
||||
main_event_loop_->Exit();
|
||||
}
|
||||
|
||||
auto AppAdapterHeadless::GetGraphicsClientContext() -> GraphicsClientContext* {
|
||||
// Special dummy form.
|
||||
return new GraphicsClientContext(0);
|
||||
}
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BA_HEADLESS_BUILD
|
||||
|
||||
@ -17,6 +17,8 @@ class AppAdapterHeadless : public AppAdapter {
|
||||
|
||||
void DoApplyAppConfig() override;
|
||||
|
||||
auto GetGraphicsClientContext() -> GraphicsClientContext* override;
|
||||
|
||||
protected:
|
||||
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
||||
void RunMainThreadEventLoopToCompletion() override;
|
||||
|
||||
@ -104,32 +104,115 @@ void AppAdapterSDL::OnMainThreadStartApp() {
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
}
|
||||
|
||||
/// Our particular flavor of graphics settings.
|
||||
struct AppAdapterSDL::GraphicsSettings_ : public GraphicsSettings {
|
||||
bool fullscreen = g_base->app_config->Resolve(AppConfig::BoolID::kFullscreen);
|
||||
VSyncRequest vsync = g_base->graphics->VSyncFromAppConfig();
|
||||
int max_fps = g_base->app_config->Resolve(AppConfig::IntID::kMaxFPS);
|
||||
};
|
||||
|
||||
void AppAdapterSDL::DoApplyAppConfig() {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
g_base->graphics_server->PushSetScreenPixelScaleCall(
|
||||
g_base->app_config->Resolve(AppConfig::FloatID::kScreenPixelScale));
|
||||
|
||||
auto graphics_quality_requested =
|
||||
g_base->graphics->GraphicsQualityFromAppConfig();
|
||||
|
||||
auto texture_quality_requested =
|
||||
g_base->graphics->TextureQualityFromAppConfig();
|
||||
|
||||
// Android res string.
|
||||
// std::string android_res =
|
||||
// g_base->app_config->Resolve(AppConfig::StringID::kResolutionAndroid);
|
||||
}
|
||||
|
||||
bool fullscreen = g_base->app_config->Resolve(AppConfig::BoolID::kFullscreen);
|
||||
auto AppAdapterSDL::GetGraphicsSettings() -> GraphicsSettings* {
|
||||
assert(g_base->InLogicThread());
|
||||
return new GraphicsSettings_();
|
||||
}
|
||||
|
||||
auto vsync = g_base->graphics->VSyncFromAppConfig();
|
||||
int max_fps = g_base->app_config->Resolve(AppConfig::IntID::kMaxFPS);
|
||||
void AppAdapterSDL::ApplyGraphicsSettings(
|
||||
const GraphicsSettings* settings_base) {
|
||||
assert(g_core->InMainThread());
|
||||
assert(!g_core->HeadlessMode());
|
||||
|
||||
// Tell the main thread to set up the screen with these settings.
|
||||
g_base->app_adapter->PushMainThreadCall([=] {
|
||||
SetScreen_(fullscreen, max_fps, vsync, texture_quality_requested,
|
||||
graphics_quality_requested);
|
||||
});
|
||||
// In strict mode, allow graphics stuff while in here.
|
||||
auto allow = ScopedAllowGraphics_(this);
|
||||
|
||||
// Settings will always be our subclass (since we created it).
|
||||
auto* settings = static_cast<const GraphicsSettings_*>(settings_base);
|
||||
|
||||
// Apply any changes.
|
||||
bool do_toggle_fs{};
|
||||
bool do_set_existing_fullscreen{};
|
||||
|
||||
auto* graphics_server = g_base->graphics_server;
|
||||
|
||||
// We need a full renderer reload if quality values have changed
|
||||
// or if we don't have a renderer yet.
|
||||
bool need_full_reload = ((sdl_window_ == nullptr
|
||||
|| graphics_server->texture_quality_requested()
|
||||
!= settings->texture_quality)
|
||||
|| (graphics_server->graphics_quality_requested()
|
||||
!= settings->graphics_quality));
|
||||
|
||||
if (need_full_reload) {
|
||||
ReloadRenderer_(settings);
|
||||
} else if (settings->fullscreen != fullscreen_) {
|
||||
SDL_SetWindowFullscreen(
|
||||
sdl_window_, settings->fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||
fullscreen_ = settings->fullscreen;
|
||||
}
|
||||
|
||||
// VSync always gets set independent of the screen (though we set it down
|
||||
// here to make sure we have a screen when its set).
|
||||
VSync vsync;
|
||||
switch (settings->vsync) {
|
||||
case VSyncRequest::kNever:
|
||||
vsync = VSync::kNever;
|
||||
break;
|
||||
case VSyncRequest::kAlways:
|
||||
vsync = VSync::kAlways;
|
||||
break;
|
||||
case VSyncRequest::kAuto:
|
||||
vsync = VSync::kAdaptive;
|
||||
break;
|
||||
default:
|
||||
vsync = VSync::kNever;
|
||||
break;
|
||||
}
|
||||
if (vsync != vsync_) {
|
||||
switch (vsync) {
|
||||
case VSync::kUnset:
|
||||
case VSync::kNever: {
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
vsync_actually_enabled_ = false;
|
||||
break;
|
||||
}
|
||||
case VSync::kAlways: {
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
vsync_actually_enabled_ = true;
|
||||
break;
|
||||
}
|
||||
case VSync::kAdaptive: {
|
||||
// In this case, let's try setting to 'adaptive' and turn it off if
|
||||
// that is unsupported.
|
||||
auto result = SDL_GL_SetSwapInterval(-1);
|
||||
if (result == 0) {
|
||||
vsync_actually_enabled_ = true;
|
||||
} else {
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
vsync_actually_enabled_ = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
vsync_ = vsync;
|
||||
}
|
||||
|
||||
// This we can set anytime. Probably could have just set it from the logic
|
||||
// thread where we read it, but let's be pedantic and keep everything to
|
||||
// the main thread.
|
||||
max_fps_ = settings->max_fps;
|
||||
|
||||
// Take -1 to mean no max. Otherwise clamp to a reasonable range.
|
||||
if (max_fps_ != -1) {
|
||||
max_fps_ = std::max(10, max_fps_);
|
||||
max_fps_ = std::min(99999, max_fps_);
|
||||
}
|
||||
}
|
||||
|
||||
void AppAdapterSDL::RunMainThreadEventLoopToCompletion() {
|
||||
@ -158,7 +241,7 @@ void AppAdapterSDL::RunMainThreadEventLoopToCompletion() {
|
||||
|
||||
auto AppAdapterSDL::TryRender() -> bool {
|
||||
if (strict_graphics_context_) {
|
||||
// In strict mode, allow graphics stuff in here. Normally we allow it
|
||||
// In strict mode, allow graphics stuff in here. Otherwise we allow it
|
||||
// anywhere in the main thread.
|
||||
auto allow = ScopedAllowGraphics_(this);
|
||||
|
||||
@ -179,7 +262,7 @@ auto AppAdapterSDL::TryRender() -> bool {
|
||||
// Lastly render.
|
||||
return g_base->graphics_server->TryRender();
|
||||
} else {
|
||||
// Simple path; just render.
|
||||
// Simpler path; just render.
|
||||
return g_base->graphics_server->TryRender();
|
||||
}
|
||||
}
|
||||
@ -188,7 +271,7 @@ void AppAdapterSDL::SleepUntilNextEventCycle_(microsecs_t cycle_start_time) {
|
||||
// Special case: if we're hidden, we simply sleep for a long bit; no fancy
|
||||
// timing.
|
||||
if (hidden_) {
|
||||
g_core->platform->SleepMillisecs(100);
|
||||
g_core->platform->SleepSeconds(0.1);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -359,7 +442,7 @@ void AppAdapterSDL::HandleSDLEvent_(const SDL_Event& event) {
|
||||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
if (g_core->GetAppTimeMillisecs() - last_windowevent_close_time_ < 100) {
|
||||
if (g_core->GetAppTimeSeconds() - last_windowevent_close_time_ < 0.1) {
|
||||
// If they hit the window close button, skip the confirm.
|
||||
g_base->QuitApp(false);
|
||||
} else {
|
||||
@ -380,7 +463,7 @@ void AppAdapterSDL::HandleSDLEvent_(const SDL_Event& 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();
|
||||
last_windowevent_close_time_ = g_core->GetAppTimeSeconds();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -546,114 +629,96 @@ auto AppAdapterSDL::GetSDLJoystickInput_(int sdl_joystick_id) const
|
||||
return nullptr; // Epic fail.
|
||||
}
|
||||
|
||||
void AppAdapterSDL::SetScreen_(
|
||||
bool fullscreen, int max_fps, VSyncRequest vsync_requested,
|
||||
TextureQualityRequest texture_quality_requested,
|
||||
GraphicsQualityRequest graphics_quality_requested) {
|
||||
assert(g_core->InMainThread());
|
||||
assert(!g_core->HeadlessMode());
|
||||
// void AppAdapterSDL::ApplyGraphicsSettings_(const GraphicsSettings_* settings)
|
||||
// {
|
||||
// assert(g_core->InMainThread());
|
||||
// assert(!g_core->HeadlessMode());
|
||||
|
||||
// In strict mode, allow graphics stuff in here.
|
||||
auto allow = ScopedAllowGraphics_(this);
|
||||
// // In strict mode, allow graphics stuff while in here.
|
||||
// auto allow = ScopedAllowGraphics_(this);
|
||||
|
||||
// If we know what we support, filter our request types to what is
|
||||
// supported. This will keep us from rebuilding contexts if request type
|
||||
// is flipping between different types that we don't support.
|
||||
if (g_base->graphics->has_supports_high_quality_graphics_value()) {
|
||||
if (!g_base->graphics->supports_high_quality_graphics()
|
||||
&& graphics_quality_requested > GraphicsQualityRequest::kMedium) {
|
||||
graphics_quality_requested = GraphicsQualityRequest::kMedium;
|
||||
}
|
||||
}
|
||||
// bool do_toggle_fs{};
|
||||
// bool do_set_existing_fullscreen{};
|
||||
|
||||
bool do_toggle_fs{};
|
||||
bool do_set_existing_fullscreen{};
|
||||
// auto* graphics_server = g_base->graphics_server;
|
||||
|
||||
auto* gs = g_base->graphics_server;
|
||||
// // We need a full renderer reload if quality values have changed
|
||||
// // or if we don't have a renderer yet.
|
||||
// bool need_full_reload = ((sdl_window_ == nullptr
|
||||
// || graphics_server->texture_quality_requested()
|
||||
// != settings->texture_quality)
|
||||
// || (graphics_server->graphics_quality_requested()
|
||||
// != settings->graphics_quality));
|
||||
|
||||
// We need a full renderer reload if quality values have changed
|
||||
// or if we don't have one yet.
|
||||
bool need_full_reload =
|
||||
((sdl_window_ == nullptr
|
||||
|| gs->texture_quality_requested() != texture_quality_requested)
|
||||
|| (gs->graphics_quality_requested() != graphics_quality_requested)
|
||||
|| !gs->texture_quality_set() || !gs->graphics_quality_set());
|
||||
// if (need_full_reload) {
|
||||
// ReloadRenderer_(settings->fullscreen, settings->graphics_quality,
|
||||
// settings->texture_quality);
|
||||
// } else if (settings->fullscreen != fullscreen_) {
|
||||
// SDL_SetWindowFullscreen(
|
||||
// sdl_window_, settings->fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP :
|
||||
// 0);
|
||||
// fullscreen_ = settings->fullscreen;
|
||||
// }
|
||||
|
||||
if (need_full_reload) {
|
||||
ReloadRenderer_(fullscreen, graphics_quality_requested,
|
||||
texture_quality_requested);
|
||||
} else if (fullscreen != fullscreen_) {
|
||||
SDL_SetWindowFullscreen(sdl_window_,
|
||||
fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||
fullscreen_ = fullscreen;
|
||||
}
|
||||
// // VSync always gets set independent of the screen (though we set it down
|
||||
// // here to make sure we have a screen when its set).
|
||||
// VSync vsync;
|
||||
// switch (settings->vsync) {
|
||||
// case VSyncRequest::kNever:
|
||||
// vsync = VSync::kNever;
|
||||
// break;
|
||||
// case VSyncRequest::kAlways:
|
||||
// vsync = VSync::kAlways;
|
||||
// break;
|
||||
// case VSyncRequest::kAuto:
|
||||
// vsync = VSync::kAdaptive;
|
||||
// break;
|
||||
// default:
|
||||
// vsync = VSync::kNever;
|
||||
// break;
|
||||
// }
|
||||
// if (vsync != vsync_) {
|
||||
// switch (vsync) {
|
||||
// case VSync::kUnset:
|
||||
// case VSync::kNever: {
|
||||
// SDL_GL_SetSwapInterval(0);
|
||||
// vsync_actually_enabled_ = false;
|
||||
// break;
|
||||
// }
|
||||
// case VSync::kAlways: {
|
||||
// SDL_GL_SetSwapInterval(1);
|
||||
// vsync_actually_enabled_ = true;
|
||||
// break;
|
||||
// }
|
||||
// case VSync::kAdaptive: {
|
||||
// // In this case, let's try setting to 'adaptive' and turn it off if
|
||||
// // that is unsupported.
|
||||
// auto result = SDL_GL_SetSwapInterval(-1);
|
||||
// if (result == 0) {
|
||||
// vsync_actually_enabled_ = true;
|
||||
// } else {
|
||||
// SDL_GL_SetSwapInterval(0);
|
||||
// vsync_actually_enabled_ = false;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// vsync_ = vsync;
|
||||
// }
|
||||
|
||||
// VSync always gets set independent of the screen (though we set it down
|
||||
// here to make sure we have a screen when its set).
|
||||
VSync vsync;
|
||||
switch (vsync_requested) {
|
||||
case VSyncRequest::kNever:
|
||||
vsync = VSync::kNever;
|
||||
break;
|
||||
case VSyncRequest::kAlways:
|
||||
vsync = VSync::kAlways;
|
||||
break;
|
||||
case VSyncRequest::kAuto:
|
||||
vsync = VSync::kAdaptive;
|
||||
break;
|
||||
default:
|
||||
vsync = VSync::kNever;
|
||||
break;
|
||||
}
|
||||
if (vsync != vsync_) {
|
||||
switch (vsync) {
|
||||
case VSync::kUnset:
|
||||
case VSync::kNever: {
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
vsync_actually_enabled_ = false;
|
||||
break;
|
||||
}
|
||||
case VSync::kAlways: {
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
vsync_actually_enabled_ = true;
|
||||
break;
|
||||
}
|
||||
case VSync::kAdaptive: {
|
||||
// In this case, let's try setting to 'adaptive' and turn it off if
|
||||
// that is unsupported.
|
||||
auto result = SDL_GL_SetSwapInterval(-1);
|
||||
if (result == 0) {
|
||||
vsync_actually_enabled_ = true;
|
||||
} else {
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
vsync_actually_enabled_ = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
vsync_ = vsync;
|
||||
}
|
||||
// // This we can set anytime. Probably could have just set it from the logic
|
||||
// // thread where we read it, but let's be pedantic and keep everything to
|
||||
// // the main thread.
|
||||
// max_fps_ = settings->max_fps;
|
||||
|
||||
// This we can set anytime. Probably could have just set it from the logic
|
||||
// thread where we read it, but let's be pedantic and keep everything to
|
||||
// the main thread.
|
||||
max_fps_ = max_fps;
|
||||
// // Take -1 to mean no max. Otherwise clamp to a reasonable range.
|
||||
// if (max_fps_ != -1) {
|
||||
// max_fps_ = std::max(10, max_fps_);
|
||||
// max_fps_ = std::min(99999, max_fps_);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Take -1 to mean no max. Otherwise clamp to a reasonable range.
|
||||
if (max_fps_ != -1) {
|
||||
max_fps_ = std::max(10, max_fps_);
|
||||
max_fps_ = std::min(99999, max_fps_);
|
||||
}
|
||||
|
||||
// Let the logic thread know we've got a graphics system up and running.
|
||||
// It may use this cue to kick off asset loads and other bootstrapping.
|
||||
g_base->logic->event_loop()->PushCall(
|
||||
[] { g_base->logic->OnGraphicsReady(); });
|
||||
}
|
||||
|
||||
void AppAdapterSDL::ReloadRenderer_(
|
||||
bool fullscreen, GraphicsQualityRequest graphics_quality_requested,
|
||||
TextureQualityRequest texture_quality_requested) {
|
||||
void AppAdapterSDL::ReloadRenderer_(const GraphicsSettings_* settings) {
|
||||
assert(g_base->app_adapter->InGraphicsContext());
|
||||
|
||||
auto* gs = g_base->graphics_server;
|
||||
@ -664,7 +729,7 @@ void AppAdapterSDL::ReloadRenderer_(
|
||||
|
||||
// If we don't haven't yet, create our window and renderer.
|
||||
if (!sdl_window_) {
|
||||
fullscreen_ = fullscreen;
|
||||
fullscreen_ = settings->fullscreen;
|
||||
|
||||
// A reasonable default window size.
|
||||
auto width = static_cast<int>(kBaseVirtualResX * 0.8f);
|
||||
@ -672,7 +737,7 @@ void AppAdapterSDL::ReloadRenderer_(
|
||||
|
||||
uint32_t flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
|
||||
| SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
|
||||
if (fullscreen) {
|
||||
if (settings->fullscreen) {
|
||||
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
}
|
||||
|
||||
@ -729,15 +794,16 @@ void AppAdapterSDL::ReloadRenderer_(
|
||||
}
|
||||
}
|
||||
|
||||
// Update graphics quality based on request.
|
||||
gs->set_graphics_quality_requested(graphics_quality_requested);
|
||||
gs->set_texture_quality_requested(texture_quality_requested);
|
||||
// Update graphics-server's qualities based on request.
|
||||
gs->set_graphics_quality_requested(settings->graphics_quality);
|
||||
gs->set_texture_quality_requested(settings->texture_quality);
|
||||
|
||||
gs->LoadRenderer();
|
||||
}
|
||||
|
||||
void AppAdapterSDL::UpdateScreenSizes_() {
|
||||
assert(g_base->app_adapter->InGraphicsContext());
|
||||
// This runs in the main thread in response to SDL events.
|
||||
assert(g_core->InMainThread());
|
||||
|
||||
// Grab logical window dimensions (points?). This is the coordinate space
|
||||
// SDL's events deal in.
|
||||
@ -749,8 +815,13 @@ void AppAdapterSDL::UpdateScreenSizes_() {
|
||||
// dimensions.
|
||||
int pixels_x, pixels_y;
|
||||
SDL_GL_GetDrawableSize(sdl_window_, &pixels_x, &pixels_y);
|
||||
g_base->graphics_server->SetScreenResolution(static_cast<float>(pixels_x),
|
||||
static_cast<float>(pixels_y));
|
||||
|
||||
// Push this over to the logic thread which owns the canonical value
|
||||
// for this.
|
||||
g_base->logic->event_loop()->PushCall([pixels_x, pixels_y] {
|
||||
g_base->graphics->SetScreenResolution(static_cast<float>(pixels_x),
|
||||
static_cast<float>(pixels_y));
|
||||
});
|
||||
}
|
||||
|
||||
auto AppAdapterSDL::InGraphicsContext() -> bool {
|
||||
|
||||
@ -41,6 +41,9 @@ class AppAdapterSDL : public AppAdapter {
|
||||
auto SupportsMaxFPS() -> bool const override;
|
||||
|
||||
auto HasDirectKeyboardInput() -> bool override;
|
||||
void ApplyGraphicsSettings(const GraphicsSettings* settings) override;
|
||||
|
||||
auto GetGraphicsSettings() -> GraphicsSettings* override;
|
||||
|
||||
protected:
|
||||
void DoPushMainThreadRunnable(Runnable* runnable) override;
|
||||
@ -52,14 +55,11 @@ class AppAdapterSDL : public AppAdapter {
|
||||
|
||||
private:
|
||||
class ScopedAllowGraphics_;
|
||||
void SetScreen_(bool fullscreen, int max_fps, VSyncRequest vsync_requested,
|
||||
TextureQualityRequest texture_quality_requested,
|
||||
GraphicsQualityRequest graphics_quality_requested);
|
||||
struct GraphicsSettings_;
|
||||
|
||||
void HandleSDLEvent_(const SDL_Event& event);
|
||||
void UpdateScreenSizes_();
|
||||
void ReloadRenderer_(bool fullscreen,
|
||||
GraphicsQualityRequest graphics_quality_requested,
|
||||
TextureQualityRequest texture_quality_requested);
|
||||
void ReloadRenderer_(const GraphicsSettings_* settings);
|
||||
void OnSDLJoystickAdded_(int index);
|
||||
void OnSDLJoystickRemoved_(int index);
|
||||
// Given an SDL joystick ID, returns our Ballistica input for it.
|
||||
@ -70,6 +70,7 @@ class AppAdapterSDL : public AppAdapter {
|
||||
void RemoveSDLInputDevice_(int index);
|
||||
void SleepUntilNextEventCycle_(microsecs_t cycle_start_time);
|
||||
|
||||
int max_fps_{60};
|
||||
bool done_ : 1 {};
|
||||
bool fullscreen_ : 1 {};
|
||||
bool vsync_actually_enabled_ : 1 {};
|
||||
@ -85,17 +86,16 @@ class AppAdapterSDL : public AppAdapter {
|
||||
/// 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};
|
||||
uint32_t sdl_runnable_event_id_{};
|
||||
int max_fps_{60};
|
||||
std::mutex strict_graphics_calls_mutex_;
|
||||
std::vector<Runnable*> strict_graphics_calls_;
|
||||
microsecs_t oversleep_{};
|
||||
std::vector<JoystickInput*> sdl_joysticks_;
|
||||
Vector2f window_size_{1.0f, 1.0f};
|
||||
SDL_Window* sdl_window_{};
|
||||
void* sdl_gl_context_{};
|
||||
millisecs_t last_windowevent_close_time_{};
|
||||
seconds_t last_windowevent_close_time_{};
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -40,7 +40,8 @@ void AppAdapterVR::PushVRSimpleRemoteStateCall(
|
||||
}
|
||||
|
||||
void AppAdapterVR::VRSetDrawDimensions(int w, int h) {
|
||||
g_base->graphics_server->SetScreenResolution(w, h);
|
||||
FatalError("FIXME UPDATE SET-SCREEN-RESOLUTION");
|
||||
// g_base->graphics_server->SetScreenResolution(w, h);
|
||||
}
|
||||
|
||||
void AppAdapterVR::VRPreDraw() {
|
||||
|
||||
@ -36,8 +36,6 @@ void AppMode::HandleGameQuery(const char* buffer, size_t size,
|
||||
|
||||
auto AppMode::DoesWorldFillScreen() -> bool { return false; }
|
||||
|
||||
void AppMode::GraphicsQualityChanged(GraphicsQuality quality) {}
|
||||
|
||||
void AppMode::DrawWorld(FrameDef* frame_def) {}
|
||||
|
||||
void AppMode::ChangeGameSpeed(int offs) {}
|
||||
|
||||
@ -62,8 +62,6 @@ class AppMode {
|
||||
|
||||
virtual void DrawWorld(FrameDef* frame_def);
|
||||
|
||||
virtual void GraphicsQualityChanged(GraphicsQuality quality);
|
||||
|
||||
/// Called whenever screen size changes.
|
||||
virtual void OnScreenSizeChange();
|
||||
|
||||
|
||||
@ -82,8 +82,9 @@ void Assets::StartLoading() {
|
||||
assert(g_base);
|
||||
assert(g_base->audio_server && g_base->assets_server
|
||||
&& g_base->graphics_server);
|
||||
assert(g_base->graphics_server->texture_compression_types_are_set());
|
||||
assert(g_base->graphics_server->texture_quality_set());
|
||||
assert(g_base->graphics->has_client_context());
|
||||
// assert(g_base->graphics_server->texture_compression_types_are_set());
|
||||
// assert(g_base->graphics_server->texture_quality_set());
|
||||
|
||||
assert(!asset_loads_allowed_); // We should only be called once.
|
||||
asset_loads_allowed_ = true;
|
||||
@ -1102,10 +1103,13 @@ auto Assets::FindAssetFile(FileType type, const std::string& name)
|
||||
}
|
||||
}
|
||||
|
||||
assert(g_base->graphics_server
|
||||
&& g_base->graphics_server->texture_compression_types_are_set());
|
||||
assert(g_base->graphics_server
|
||||
&& g_base->graphics_server->texture_quality_set());
|
||||
// Make sure we know what compression/quality to use.
|
||||
assert(g_base->graphics->has_client_context());
|
||||
// assert(g_base->graphics_server
|
||||
// &&
|
||||
// g_base->graphics_server->texture_compression_types_are_set());
|
||||
// assert(g_base->graphics_server
|
||||
// && g_base->graphics_server->texture_quality_set());
|
||||
prefix = "textures/";
|
||||
|
||||
#if BA_OSTYPE_ANDROID && !BA_ANDROID_DDS_BUILD
|
||||
|
||||
@ -136,20 +136,21 @@ class Assets {
|
||||
std::unordered_map<std::string, Object::Ref<T> >* c_list)
|
||||
-> Object::Ref<T>;
|
||||
|
||||
std::vector<std::string> asset_paths_;
|
||||
int language_state_{};
|
||||
bool have_pending_loads_[static_cast<int>(AssetType::kLast)]{};
|
||||
|
||||
// Will be true while a AssetListLock exists. Good to debug-verify this
|
||||
// during any asset list access.
|
||||
bool asset_lists_locked_ : 1 {};
|
||||
bool asset_loads_allowed_ : 1 {};
|
||||
bool sys_assets_loaded_ : 1 {};
|
||||
|
||||
std::vector<std::string> asset_paths_;
|
||||
std::unordered_map<std::string, std::string> packages_;
|
||||
|
||||
// For use by AssetListLock; don't manually acquire.
|
||||
std::mutex asset_lists_mutex_;
|
||||
|
||||
// Will be true while a AssetListLock exists. Good to debug-verify this
|
||||
// during any asset list access.
|
||||
bool asset_lists_locked_{};
|
||||
|
||||
// 'hard-wired' internal assets
|
||||
bool asset_loads_allowed_{};
|
||||
bool sys_assets_loaded_{};
|
||||
std::vector<Object::Ref<TextureAsset> > system_textures_;
|
||||
std::vector<Object::Ref<TextureAsset> > system_cube_map_textures_;
|
||||
std::vector<Object::Ref<SoundAsset> > system_sounds_;
|
||||
@ -177,7 +178,6 @@ class Assets {
|
||||
// Text & Language (need to mold this into more asset-like concepts).
|
||||
std::mutex language_mutex_;
|
||||
std::unordered_map<std::string, std::string> language_;
|
||||
int language_state_{};
|
||||
std::mutex special_char_mutex_;
|
||||
std::unordered_map<SpecialChar, std::string> special_char_strings_;
|
||||
};
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#include "ballistica/base/assets/asset.h"
|
||||
#include "ballistica/base/assets/assets.h"
|
||||
#include "ballistica/base/graphics/graphics.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
#include "ballistica/base/support/huffman.h"
|
||||
#include "ballistica/shared/foundation/event_loop.h"
|
||||
@ -221,12 +222,18 @@ void AssetsServer::WriteReplayMessages() {
|
||||
void AssetsServer::Process() {
|
||||
// Make sure we don't do any loading until we know what kind/quality of
|
||||
// textures we'll be loading.
|
||||
if (!g_base->assets || !g_base->graphics_server
|
||||
|| !g_base->graphics_server
|
||||
->texture_compression_types_are_set() // NOLINT
|
||||
|| !g_base->graphics_server->texture_quality_set()) {
|
||||
|
||||
// FIXME - we'll need to revisit this when adding support for
|
||||
// renderer switches, since this is not especially thread-safe.
|
||||
|
||||
if (!g_base->graphics->has_client_context()) {
|
||||
return;
|
||||
}
|
||||
// if (!g_base->assets ||
|
||||
// || !g_base->graphics->texture_compression_types_are_set() // NOLINT
|
||||
// || !g_base->graphics_server->texture_quality_set()) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Process exactly 1 preload item. Empty out our non-audio list first
|
||||
// (audio is less likely to cause noticeable hitches if it needs to be loaded
|
||||
|
||||
@ -93,11 +93,14 @@ auto TextureAsset::GetNameFull() const -> std::string {
|
||||
void TextureAsset::DoPreload() {
|
||||
assert(valid_);
|
||||
|
||||
assert(g_base->graphics_server
|
||||
&& g_base->graphics_server->texture_compression_types_are_set());
|
||||
// Make sure we're not loading without knowing what texture types we
|
||||
// support.
|
||||
// assert(g_base->graphics->has_client_context());
|
||||
// assert(g_base->graphics_server
|
||||
// && g_base->graphics_server->texture_compression_types_are_set());
|
||||
|
||||
// We figure out which LOD should be our base level based on quality.
|
||||
TextureQuality texture_quality = g_base->graphics_server->texture_quality();
|
||||
// Figure out which LOD should be our base level based on texture quality.
|
||||
auto texture_quality = g_base->graphics->placeholder_texture_quality();
|
||||
|
||||
// If we're a text-texture.
|
||||
if (packer_.Exists()) {
|
||||
@ -218,12 +221,14 @@ void TextureAsset::DoPreload() {
|
||||
&preload_datas_[0].base_level);
|
||||
|
||||
// We should only be loading this if we support etc1 in hardware.
|
||||
assert(g_base->graphics_server->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kETC1));
|
||||
assert(g_base->graphics->placeholder_client_context()
|
||||
->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kETC1));
|
||||
|
||||
// Decompress dxt1/dxt5 ones if we don't natively support S3TC.
|
||||
if (!g_base->graphics_server->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kS3TC)) {
|
||||
if (!g_base->graphics->placeholder_client_context()
|
||||
->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kS3TC)) {
|
||||
if ((preload_datas_[0].formats[preload_datas_[0].base_level]
|
||||
== TextureFormat::kDXT5)
|
||||
|| (preload_datas_[0].formats[preload_datas_[0].base_level]
|
||||
@ -241,8 +246,9 @@ void TextureAsset::DoPreload() {
|
||||
&preload_datas_[0].base_level);
|
||||
|
||||
// Decompress dxt1/dxt5 if we don't natively support it.
|
||||
if (!g_base->graphics_server->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kS3TC)) {
|
||||
if (!g_base->graphics->placeholder_client_context()
|
||||
->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kS3TC)) {
|
||||
preload_datas_[0].ConvertToUncompressed(this);
|
||||
}
|
||||
} else if (!strcmp(file_name_full_.c_str() + file_name_size - 4,
|
||||
@ -264,16 +270,18 @@ void TextureAsset::DoPreload() {
|
||||
== TextureFormat::kETC2_RGB)
|
||||
|| (preload_datas_[0].formats[preload_datas_[0].base_level]
|
||||
== TextureFormat::kETC2_RGBA))
|
||||
&& (!g_base->graphics_server->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kETC2))) {
|
||||
&& (!g_base->graphics->placeholder_client_context()
|
||||
->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kETC2))) {
|
||||
preload_datas_[0].ConvertToUncompressed(this);
|
||||
}
|
||||
|
||||
// Decompress etc1 if we don't natively support it.
|
||||
if ((preload_datas_[0].formats[preload_datas_[0].base_level]
|
||||
== TextureFormat::kETC1)
|
||||
&& (!g_base->graphics_server->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kETC1))) {
|
||||
&& (!g_base->graphics->placeholder_client_context()
|
||||
->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kETC1))) {
|
||||
preload_datas_[0].ConvertToUncompressed(this);
|
||||
}
|
||||
|
||||
@ -287,8 +295,9 @@ void TextureAsset::DoPreload() {
|
||||
&preload_datas_[0].base_level);
|
||||
|
||||
// We should only be loading this if we support pvr in hardware.
|
||||
assert(g_base->graphics_server->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kPVR));
|
||||
assert(
|
||||
g_base->graphics->placeholder_client_context()
|
||||
->SupportsTextureCompressionType(TextureCompressionType::kPVR));
|
||||
} else if (!strcmp(file_name_full_.c_str() + file_name_size - 4,
|
||||
".nop")) {
|
||||
// Dummy path for headless; nothing to do here.
|
||||
@ -342,12 +351,14 @@ void TextureAsset::DoPreload() {
|
||||
}
|
||||
|
||||
// We should only be loading this if we support etc1 in hardware.
|
||||
assert(g_base->graphics_server->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kETC1));
|
||||
assert(g_base->graphics->placeholder_client_context()
|
||||
->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kETC1));
|
||||
|
||||
// Decompress dxt1/dxt5 ones if we don't natively support S3TC.
|
||||
if (!g_base->graphics_server->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kS3TC)) {
|
||||
if (!g_base->graphics->placeholder_client_context()
|
||||
->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kS3TC)) {
|
||||
if ((preload_datas_[d].formats[preload_datas_[d].base_level]
|
||||
== TextureFormat::kDXT5)
|
||||
|| (preload_datas_[d].formats[preload_datas_[d].base_level]
|
||||
@ -365,8 +376,9 @@ void TextureAsset::DoPreload() {
|
||||
&preload_datas_[d].base_level);
|
||||
|
||||
// Decompress dxt1/dxt5 if we don't natively support it.
|
||||
if (!g_base->graphics_server->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kS3TC)) {
|
||||
if (!g_base->graphics->placeholder_client_context()
|
||||
->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kS3TC)) {
|
||||
preload_datas_[d].ConvertToUncompressed(this);
|
||||
}
|
||||
} else if (!strcmp(file_name_full_.c_str() + file_name_size - 4,
|
||||
@ -383,16 +395,18 @@ void TextureAsset::DoPreload() {
|
||||
== TextureFormat::kETC2_RGB)
|
||||
|| (preload_datas_[d].formats[preload_datas_[d].base_level]
|
||||
== TextureFormat::kETC2_RGBA))
|
||||
&& (!g_base->graphics_server->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kETC2))) {
|
||||
&& (!g_base->graphics->placeholder_client_context()
|
||||
->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kETC2))) {
|
||||
preload_datas_[d].ConvertToUncompressed(this);
|
||||
}
|
||||
|
||||
// Decompress etc1 if we don't natively support it.
|
||||
if ((preload_datas_[d].formats[preload_datas_[d].base_level]
|
||||
== TextureFormat::kETC1)
|
||||
&& (!g_base->graphics_server->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kETC1))) {
|
||||
&& (!g_base->graphics->placeholder_client_context()
|
||||
->SupportsTextureCompressionType(
|
||||
TextureCompressionType::kETC1))) {
|
||||
preload_datas_[d].ConvertToUncompressed(this);
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "ballistica/base/assets/sound_asset.h"
|
||||
#include "ballistica/base/audio/audio_server.h"
|
||||
#include "ballistica/base/audio/audio_source.h"
|
||||
#include "ballistica/base/graphics/graphics.h"
|
||||
#include "ballistica/base/support/app_config.h"
|
||||
#include "ballistica/shared/foundation/event_loop.h"
|
||||
|
||||
@ -12,6 +13,19 @@ namespace ballistica::base {
|
||||
|
||||
Audio::Audio() = default;
|
||||
|
||||
auto Audio::UseLowQualityAudio() -> bool {
|
||||
assert(g_base->InLogicThread());
|
||||
// Currently just piggybacking off graphics quality here.
|
||||
if (g_core->HeadlessMode() || g_base->graphics->has_client_context()) {
|
||||
return true;
|
||||
}
|
||||
// We don't have a frame-def to look at so need to calc this ourself; ugh.
|
||||
auto quality = Graphics::GraphicsQualityFromRequest(
|
||||
g_base->graphics->settings()->graphics_quality,
|
||||
g_base->graphics->client_context()->auto_graphics_quality);
|
||||
return quality < GraphicsQuality::kMedium;
|
||||
}
|
||||
|
||||
void Audio::Reset() {
|
||||
assert(g_base->InLogicThread());
|
||||
g_base->audio_server->PushResetCall();
|
||||
|
||||
@ -29,36 +29,41 @@ class Audio {
|
||||
virtual void OnScreenSizeChange();
|
||||
virtual void StepDisplayTime();
|
||||
|
||||
/// Can be keyed off of to cut corners in audio (leaving sounds out, etc.)
|
||||
/// Currently just piggybacks off graphics quality settings but this logic
|
||||
/// may get fancier in the future.
|
||||
auto UseLowQualityAudio() -> bool;
|
||||
|
||||
void SetVolumes(float music_volume, float sound_volume);
|
||||
|
||||
void SetListenerPosition(const Vector3f& p);
|
||||
void SetListenerOrientation(const Vector3f& forward, const Vector3f& up);
|
||||
void SetSoundPitch(float pitch);
|
||||
|
||||
// Return a pointer to a locked sound source, or nullptr if they're all busy.
|
||||
// The sound source will be reset to standard settings (no loop, fade 1, pos
|
||||
// 0,0,0, etc.).
|
||||
// Send the source any immediate commands and then unlock it.
|
||||
// For later modifications, re-retrieve the sound with GetPlayingSound()
|
||||
/// Return a pointer to a locked sound source, or nullptr if they're all busy.
|
||||
/// The sound source will be reset to standard settings (no loop, fade 1, pos
|
||||
/// 0,0,0, etc.).
|
||||
/// Send the source any immediate commands and then unlock it.
|
||||
/// For later modifications, re-retrieve the sound with GetPlayingSound()
|
||||
auto SourceBeginNew() -> AudioSource*;
|
||||
|
||||
// If a sound play id is playing, locks and returns its sound source.
|
||||
// on success, you must unlock the source once done with it.
|
||||
/// If a sound play id is playing, locks and returns its sound source.
|
||||
/// on success, you must unlock the source once done with it.
|
||||
auto SourceBeginExisting(uint32_t play_id, int debug_id) -> AudioSource*;
|
||||
|
||||
// Return true if the sound id is currently valid. This is not guaranteed
|
||||
// to be super accurate, but can be used to determine if a sound is still
|
||||
// playing.
|
||||
/// Return true if the sound id is currently valid. This is not guaranteed
|
||||
/// to be super accurate, but can be used to determine if a sound is still
|
||||
/// playing.
|
||||
auto IsSoundPlaying(uint32_t play_id) -> bool;
|
||||
|
||||
// Simple one-shot play functions.
|
||||
/// Simple one-shot play functions.
|
||||
auto PlaySound(SoundAsset* s, float volume = 1.0f) -> std::optional<uint32_t>;
|
||||
auto PlaySoundAtPosition(SoundAsset* sound, float volume, float x, float y,
|
||||
float z) -> std::optional<uint32_t>;
|
||||
|
||||
// Call this if you want to prevent repeated plays of the same sound. It'll
|
||||
// tell you if the sound has been played recently. The one-shot sound-play
|
||||
// functions use this under the hood. (PlaySound, PlaySoundAtPosition).
|
||||
/// Call this if you want to prevent repeated plays of the same sound. It'll
|
||||
/// tell you if the sound has been played recently. The one-shot sound-play
|
||||
/// functions use this under the hood. (PlaySound, PlaySoundAtPosition).
|
||||
auto ShouldPlay(SoundAsset* s) -> bool;
|
||||
|
||||
// Hmm; shouldn't these be accessed through the Source class?
|
||||
@ -73,15 +78,15 @@ class Audio {
|
||||
}
|
||||
|
||||
private:
|
||||
// Flat list of client sources indexed by id.
|
||||
/// Flat list of client sources indexed by id.
|
||||
std::vector<AudioSource*> client_sources_;
|
||||
|
||||
// List of sources that are ready to use.
|
||||
// This is kept filled by the audio thread
|
||||
// and used by the client.
|
||||
/// List of sources that are ready to use.
|
||||
/// This is kept filled by the audio thread
|
||||
/// and used by the client.
|
||||
std::vector<AudioSource*> available_sources_;
|
||||
|
||||
// This must be locked whenever accessing the availableSources list.
|
||||
/// This must be locked whenever accessing the availableSources list.
|
||||
std::mutex available_sources_mutex_;
|
||||
};
|
||||
|
||||
|
||||
@ -420,6 +420,10 @@ auto BaseFeatureSet::IsUnmodifiedBlessedBuild() -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto BaseFeatureSet::InMainThread() const -> bool {
|
||||
return g_core->InMainThread();
|
||||
}
|
||||
|
||||
auto BaseFeatureSet::InAssetsThread() const -> bool {
|
||||
if (auto* loop = assets_server->event_loop()) {
|
||||
return loop->ThreadIsCurrent();
|
||||
|
||||
@ -59,6 +59,8 @@ class DataAsset;
|
||||
class FrameDef;
|
||||
class Graphics;
|
||||
class GraphicsServer;
|
||||
struct GraphicsSettings;
|
||||
struct GraphicsClientContext;
|
||||
class Huffman;
|
||||
class ImageMesh;
|
||||
class Input;
|
||||
@ -662,6 +664,7 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
||||
/// allowing certain functionality before this time.
|
||||
auto IsBaseCompletelyImported() -> bool;
|
||||
|
||||
auto InMainThread() const -> bool;
|
||||
auto InAssetsThread() const -> bool override;
|
||||
auto InLogicThread() const -> bool override;
|
||||
auto InAudioThread() const -> bool override;
|
||||
|
||||
@ -39,10 +39,15 @@ void BGDynamics::Emit(const BGDynamicsEmission& e) {
|
||||
void BGDynamics::Step(const Vector3f& cam_pos, int step_millisecs) {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// Don't actually start doing anything until there's a
|
||||
// client-graphics-context. We need this to calculate qualities/etc.
|
||||
if (!g_base->graphics->has_client_context()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The BG dynamics thread just processes steps as fast as it can;
|
||||
// we need to throttle what we send or tell it to cut back if its behind
|
||||
int step_count = g_base->bg_dynamics_server->step_count();
|
||||
// printf("STEP COUNT %d\n", step_count);
|
||||
|
||||
// If we're really getting behind, start pruning stuff.
|
||||
if (step_count > 3) {
|
||||
@ -62,6 +67,9 @@ void BGDynamics::Step(const Vector3f& cam_pos, int step_millisecs) {
|
||||
// Pass a newly allocated raw pointer to the bg-dynamics thread; it takes care
|
||||
// of disposing it when done.
|
||||
auto d = Object::NewDeferred<BGDynamicsServer::StepData>();
|
||||
d->graphics_quality = Graphics::GraphicsQualityFromRequest(
|
||||
g_base->graphics->settings()->graphics_quality,
|
||||
g_base->graphics->client_context()->auto_graphics_quality);
|
||||
d->step_millisecs = step_millisecs;
|
||||
d->cam_pos = cam_pos;
|
||||
|
||||
@ -174,7 +182,7 @@ void BGDynamics::Draw(FrameDef* frame_def) {
|
||||
|
||||
// In high-quality, we draw in the overlay pass so that we don't get wiped
|
||||
// out by depth-of-field.
|
||||
bool draw_in_overlay = (frame_def->quality() >= GraphicsQuality::kHigh);
|
||||
bool draw_in_overlay = frame_def->quality() >= GraphicsQuality::kHigh;
|
||||
SpriteComponent c(draw_in_overlay ? frame_def->overlay_3d_pass()
|
||||
: frame_def->beauty_pass());
|
||||
c.SetCameraAligned(true);
|
||||
@ -232,7 +240,7 @@ void BGDynamics::Draw(FrameDef* frame_def) {
|
||||
tendrils_mesh_->SetIndexData(ds->tendril_indices);
|
||||
tendrils_mesh_->SetData(
|
||||
Object::Ref<MeshBuffer<VertexSmokeFull>>(ds->tendril_vertices));
|
||||
bool draw_in_overlay = (frame_def->quality() >= GraphicsQuality::kHigh);
|
||||
bool draw_in_overlay = frame_def->quality() >= GraphicsQuality::kHigh;
|
||||
SmokeComponent c(draw_in_overlay ? frame_def->overlay_3d_pass()
|
||||
: frame_def->beauty_pass());
|
||||
c.SetOverlay(draw_in_overlay);
|
||||
|
||||
@ -2282,7 +2282,8 @@ void BGDynamicsServer::Step(StepData* step_data) {
|
||||
auto ref(Object::CompleteDeferred(step_data));
|
||||
|
||||
// Keep our quality in sync with the graphics thread's.
|
||||
graphics_quality_ = g_base->graphics_server->graphics_quality();
|
||||
graphics_quality_ = step_data->graphics_quality;
|
||||
assert(graphics_quality_ != GraphicsQuality::kUnset);
|
||||
|
||||
cam_pos_ = step_data->cam_pos;
|
||||
|
||||
|
||||
@ -73,6 +73,7 @@ class BGDynamicsServer {
|
||||
auto GetDefaultOwnerThread() const -> EventLoopID override {
|
||||
return EventLoopID::kBGDynamics;
|
||||
}
|
||||
GraphicsQuality graphics_quality{};
|
||||
int step_millisecs{};
|
||||
Vector3f cam_pos{0.0f, 0.0f, 0.0f};
|
||||
|
||||
|
||||
@ -238,10 +238,10 @@ class RendererGL::ProgramGL {
|
||||
|
||||
// Update matrices as necessary.
|
||||
|
||||
uint32_t mvpState =
|
||||
int mvp_state =
|
||||
g_base->graphics_server->GetModelViewProjectionMatrixState();
|
||||
if (mvpState != mvp_state_) {
|
||||
mvp_state_ = mvpState;
|
||||
if (mvp_state != mvp_state_) {
|
||||
mvp_state_ = mvp_state;
|
||||
glUniformMatrix4fv(
|
||||
mvp_uniform_, 1, 0,
|
||||
g_base->graphics_server->GetModelViewProjectionMatrix().m);
|
||||
@ -251,7 +251,7 @@ class RendererGL::ProgramGL {
|
||||
if (pflags_ & PFLAG_USES_MODEL_WORLD_MATRIX) {
|
||||
// With world space points this would be identity; don't waste time.
|
||||
assert(!(pflags_ & PFLAG_WORLD_SPACE_PTS));
|
||||
uint32_t state = g_base->graphics_server->GetModelWorldMatrixState();
|
||||
int state = g_base->graphics_server->GetModelWorldMatrixState();
|
||||
if (state != model_world_matrix_state_) {
|
||||
model_world_matrix_state_ = state;
|
||||
glUniformMatrix4fv(model_world_matrix_uniform_, 1, 0,
|
||||
@ -264,8 +264,7 @@ class RendererGL::ProgramGL {
|
||||
// With world space points this would be identity; don't waste time.
|
||||
assert(!(pflags_ & PFLAG_WORLD_SPACE_PTS));
|
||||
// There's no state for just modelview but this works.
|
||||
uint32_t state =
|
||||
g_base->graphics_server->GetModelViewProjectionMatrixState();
|
||||
int state = g_base->graphics_server->GetModelViewProjectionMatrixState();
|
||||
if (state != model_view_matrix_state_) {
|
||||
model_view_matrix_state_ = state;
|
||||
glUniformMatrix4fv(model_view_matrix_uniform_, 1, 0,
|
||||
@ -275,7 +274,7 @@ class RendererGL::ProgramGL {
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
if (pflags_ & PFLAG_USES_CAM_POS) {
|
||||
uint32_t state = g_base->graphics_server->cam_pos_state();
|
||||
int state = g_base->graphics_server->cam_pos_state();
|
||||
if (state != cam_pos_state_) {
|
||||
cam_pos_state_ = state;
|
||||
const Vector3f& p(g_base->graphics_server->cam_pos());
|
||||
@ -285,7 +284,7 @@ class RendererGL::ProgramGL {
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
if (pflags_ & PFLAG_USES_CAM_ORIENT_MATRIX) {
|
||||
uint32_t state = g_base->graphics_server->GetCamOrientMatrixState();
|
||||
int state = g_base->graphics_server->GetCamOrientMatrixState();
|
||||
if (state != cam_orient_matrix_state_) {
|
||||
cam_orient_matrix_state_ = state;
|
||||
glUniformMatrix4fv(cam_orient_matrix_uniform_, 1, 0,
|
||||
@ -295,7 +294,7 @@ class RendererGL::ProgramGL {
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
|
||||
if (pflags_ & PFLAG_USES_SHADOW_PROJECTION_MATRIX) {
|
||||
uint32_t state =
|
||||
int state =
|
||||
g_base->graphics_server->light_shadow_projection_matrix_state();
|
||||
if (state != light_shadow_projection_matrix_state_) {
|
||||
light_shadow_projection_matrix_state_ = state;
|
||||
@ -336,19 +335,19 @@ class RendererGL::ProgramGL {
|
||||
Object::Ref<VertexShaderGL> vertex_shader_;
|
||||
std::string name_;
|
||||
GLuint program_{};
|
||||
int pflags_{};
|
||||
uint32_t mvp_state_{};
|
||||
GLint mvp_uniform_{};
|
||||
GLint model_world_matrix_uniform_{};
|
||||
GLint model_view_matrix_uniform_{};
|
||||
GLint light_shadow_projection_matrix_uniform_{};
|
||||
uint32_t light_shadow_projection_matrix_state_{};
|
||||
uint32_t model_world_matrix_state_{};
|
||||
uint32_t model_view_matrix_state_{};
|
||||
GLint cam_pos_uniform_{};
|
||||
uint32_t cam_pos_state_{};
|
||||
GLint cam_orient_matrix_uniform_{};
|
||||
GLuint cam_orient_matrix_state_{};
|
||||
int cam_orient_matrix_state_{};
|
||||
int light_shadow_projection_matrix_state_{};
|
||||
int pflags_{};
|
||||
int mvp_state_{};
|
||||
int cam_pos_state_{};
|
||||
int model_world_matrix_state_{};
|
||||
int model_view_matrix_state_{};
|
||||
BA_DISALLOW_CLASS_COPIES(ProgramGL);
|
||||
};
|
||||
|
||||
|
||||
@ -366,7 +366,7 @@ void RendererGL::CheckGLCapabilities_() {
|
||||
|
||||
// Both GL 3 and GL ES 3.0 support depth textures (and thus our high
|
||||
// quality mode) as a core feature.
|
||||
g_base->graphics->SetSupportsHighQualityGraphics(true);
|
||||
// g_base->graphics->SetSupportsHighQualityGraphics(true);
|
||||
|
||||
// Store the tex-compression type we support.
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
@ -2598,7 +2598,8 @@ void RendererGL::RetainShader_(ProgramGL* p) { shaders_.emplace_back(p); }
|
||||
void RendererGL::Load() {
|
||||
assert(g_base->app_adapter->InGraphicsContext());
|
||||
assert(!data_loaded_);
|
||||
assert(g_base->graphics_server->graphics_quality_set());
|
||||
assert(g_base->graphics_server->graphics_quality()
|
||||
!= GraphicsQuality::kUnset);
|
||||
BA_DEBUG_CHECK_GL_ERROR;
|
||||
if (!got_screen_framebuffer_) {
|
||||
got_screen_framebuffer_ = true;
|
||||
|
||||
@ -115,9 +115,14 @@ void Graphics::OnAppShutdownComplete() { assert(g_base->InLogicThread()); }
|
||||
void Graphics::DoApplyAppConfig() {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// Any time we load the config we ship a new graphics-settings to
|
||||
// the graphics server since something likely changed.
|
||||
graphics_settings_dirty_ = true;
|
||||
|
||||
show_fps_ = g_base->app_config->Resolve(AppConfig::BoolID::kShowFPS);
|
||||
show_ping_ = g_base->app_config->Resolve(AppConfig::BoolID::kShowPing);
|
||||
tv_border_ = g_base->app_config->Resolve(AppConfig::BoolID::kEnableTVBorder);
|
||||
// tv_border_ =
|
||||
// g_base->app_config->Resolve(AppConfig::BoolID::kEnableTVBorder);
|
||||
|
||||
bool disable_camera_shake =
|
||||
g_base->app_config->Resolve(AppConfig::BoolID::kDisableCameraShake);
|
||||
@ -126,6 +131,52 @@ void Graphics::DoApplyAppConfig() {
|
||||
bool disable_camera_gyro =
|
||||
g_base->app_config->Resolve(AppConfig::BoolID::kDisableCameraGyro);
|
||||
set_camera_gyro_explicitly_disabled(disable_camera_gyro);
|
||||
|
||||
applied_app_config_ = true;
|
||||
|
||||
// At this point we may want to send initial graphics settings to the
|
||||
// graphics server if we haven't.
|
||||
UpdateInitialGraphicsSettingsSend_();
|
||||
}
|
||||
|
||||
void Graphics::UpdateInitialGraphicsSettingsSend_() {
|
||||
assert(g_base->InLogicThread());
|
||||
if (sent_initial_graphics_settings_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to send an initial graphics-settings to the server to kick
|
||||
// things off, but we need a few things to be in place first.
|
||||
auto app_config_ready = applied_app_config_;
|
||||
// At some point we may want to wait to know our actual screen res before
|
||||
// sending. This won't apply everywhere though since on some platforms the
|
||||
// screen doesn't exist until we send this.
|
||||
auto screen_resolution_ready = true;
|
||||
|
||||
if (app_config_ready && screen_resolution_ready) {
|
||||
// Update/grab the current settings snapshot.
|
||||
auto* settings = GetGraphicsSettingsSnapshot();
|
||||
|
||||
// We need to explicitly push settings to the graphics server to kick
|
||||
// things off. We need to keep this settings instance alive until
|
||||
// handled by the graphics context (which might be in another thread
|
||||
// where we're not allowed to muck with settings' refs from). So let's
|
||||
// explicitly increment its refcount here in the logic thread now and
|
||||
// then push a call back here to decrement it when we're done.
|
||||
settings->ObjectIncrementStrongRefCount();
|
||||
// auto* s = settings_.Get();
|
||||
g_base->app_adapter->PushGraphicsContextCall([settings] {
|
||||
assert(g_base->app_adapter->InGraphicsContext());
|
||||
g_base->graphics_server->ApplySettings(settings->Get());
|
||||
g_base->logic->event_loop()->PushCall([settings] {
|
||||
// Release our strong ref back here in the logic thread.
|
||||
assert(g_base->InLogicThread());
|
||||
settings->ObjectDecrementStrongRefCount();
|
||||
});
|
||||
});
|
||||
|
||||
sent_initial_graphics_settings_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::StepDisplayTime() { assert(g_base->InLogicThread()); }
|
||||
@ -976,6 +1027,20 @@ auto Graphics::GetEmptyFrameDef() -> FrameDef* {
|
||||
return frame_def;
|
||||
}
|
||||
|
||||
auto Graphics::GetGraphicsSettingsSnapshot() -> Snapshot<GraphicsSettings>* {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// If need be, ask the app-adapter to build us a new settings instance.
|
||||
if (graphics_settings_dirty_) {
|
||||
auto* new_settings = g_base->app_adapter->GetGraphicsSettings();
|
||||
new_settings->index = next_settings_index_++;
|
||||
settings_snapshot_ = Object::New<Snapshot<GraphicsSettings>>(new_settings);
|
||||
graphics_settings_dirty_ = false;
|
||||
}
|
||||
assert(settings_snapshot_.Exists());
|
||||
return settings_snapshot_.Get();
|
||||
}
|
||||
|
||||
void Graphics::ClearFrameDefDeleteList() {
|
||||
assert(g_base->InLogicThread());
|
||||
std::scoped_lock lock(frame_def_delete_list_mutex_);
|
||||
@ -1120,6 +1185,8 @@ void Graphics::DrawDevUI(FrameDef* frame_def) {
|
||||
|
||||
void Graphics::BuildAndPushFrameDef() {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
BA_PRECONDITION_FATAL(g_base->logic->app_bootstrapping_complete());
|
||||
assert(camera_.Exists());
|
||||
assert(!g_core->HeadlessMode());
|
||||
|
||||
@ -1128,10 +1195,6 @@ void Graphics::BuildAndPushFrameDef() {
|
||||
assert(!building_frame_def_);
|
||||
building_frame_def_ = true;
|
||||
|
||||
// We should not be building/pushing any frames until the native
|
||||
// layer is fully bootstrapped.
|
||||
BA_PRECONDITION_FATAL(g_base->logic->app_bootstrapping_complete());
|
||||
|
||||
microsecs_t app_time_microsecs = g_core->GetAppTimeMicrosecs();
|
||||
|
||||
// Store how much time this frame_def represents.
|
||||
@ -1187,13 +1250,6 @@ void Graphics::BuildAndPushFrameDef() {
|
||||
internal_components_inited_ = true;
|
||||
}
|
||||
|
||||
// If graphics quality has changed since our last draw, inform anyone who
|
||||
// wants to know.
|
||||
if (last_frame_def_graphics_quality_ != frame_def->quality()) {
|
||||
last_frame_def_graphics_quality_ = frame_def->quality();
|
||||
g_base->app_mode()->GraphicsQualityChanged(frame_def->quality());
|
||||
}
|
||||
|
||||
ApplyCamera(frame_def);
|
||||
|
||||
if (progress_bar_) {
|
||||
@ -1254,7 +1310,7 @@ void Graphics::BuildAndPushFrameDef() {
|
||||
RunCleanFrameCommands();
|
||||
}
|
||||
|
||||
frame_def->Finalize();
|
||||
frame_def->Complete();
|
||||
|
||||
// Include all mesh-data loads and unloads that have accumulated up to
|
||||
// this point the graphics thread will have to handle these before
|
||||
@ -1555,11 +1611,6 @@ void Graphics::DrawBlotches(FrameDef* frame_def) {
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::SetSupportsHighQualityGraphics(bool s) {
|
||||
supports_high_quality_graphics_ = s;
|
||||
has_supports_high_quality_graphics_value_ = true;
|
||||
}
|
||||
|
||||
void Graphics::ClearScreenMessageTranslations() {
|
||||
assert(g_base && g_base->InLogicThread());
|
||||
for (auto&& i : screen_messages_) {
|
||||
@ -1922,20 +1973,55 @@ auto Graphics::ScreenMessageEntry::GetText() -> TextGroup& {
|
||||
|
||||
void Graphics::OnScreenSizeChange() {}
|
||||
|
||||
void Graphics::SetScreenSize(float virtual_width, float virtual_height,
|
||||
float pixel_width, float pixel_height) {
|
||||
void Graphics::CalcVirtualRes_(float* x, float* y) {
|
||||
float x_in = *x;
|
||||
float y_in = *y;
|
||||
if (*x / *y > static_cast<float>(kBaseVirtualResX)
|
||||
/ static_cast<float>(kBaseVirtualResY)) {
|
||||
*y = kBaseVirtualResY;
|
||||
*x = *y * (x_in / y_in);
|
||||
} else {
|
||||
*x = kBaseVirtualResX;
|
||||
*y = *x * (y_in / x_in);
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::SetScreenResolution(float x, float y) {
|
||||
assert(g_base->InLogicThread());
|
||||
res_x_virtual_ = virtual_width;
|
||||
res_y_virtual_ = virtual_height;
|
||||
res_x_ = pixel_width;
|
||||
res_y_ = pixel_height;
|
||||
|
||||
// Ignore redundant sets.
|
||||
if (res_x_ == x && res_y_ == y) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We'll need to ship a new settings to the server with this change.
|
||||
graphics_settings_dirty_ = true;
|
||||
|
||||
res_x_ = x;
|
||||
res_y_ = y;
|
||||
|
||||
// Calc virtual res. In vr mode our virtual res is independent of our
|
||||
// screen size (since it gets drawn to an overlay).
|
||||
if (g_core->IsVRMode()) {
|
||||
res_x_virtual_ = kBaseVirtualResX;
|
||||
res_y_virtual_ = kBaseVirtualResY;
|
||||
} else {
|
||||
res_x_virtual_ = res_x_;
|
||||
res_y_virtual_ = res_y_;
|
||||
CalcVirtualRes_(&res_x_virtual_, &res_y_virtual_);
|
||||
}
|
||||
|
||||
// Need to rebuild internal components (some are sized to the screen).
|
||||
internal_components_inited_ = false;
|
||||
|
||||
// This will inform all applicable logic thread subsystems.
|
||||
g_base->logic->OnScreenSizeChange(virtual_width, virtual_height, pixel_width,
|
||||
pixel_height);
|
||||
// Inform all our logic thread buddies of this change.
|
||||
g_base->logic->OnScreenSizeChange(res_x_virtual_, res_y_virtual_, res_x_,
|
||||
res_y_);
|
||||
|
||||
// This may trigger us sending initial graphics settings to the
|
||||
// graphics-server to kick off drawing.
|
||||
got_screen_resolution_ = true;
|
||||
UpdateInitialGraphicsSettingsSend_();
|
||||
}
|
||||
|
||||
void Graphics::ScreenMessageEntry::UpdateTranslation() {
|
||||
@ -2030,4 +2116,61 @@ void Graphics::LanguageChanged() {
|
||||
ClearScreenMessageTranslations();
|
||||
}
|
||||
|
||||
auto Graphics::GraphicsQualityFromRequest(GraphicsQualityRequest request,
|
||||
GraphicsQuality auto_val)
|
||||
-> GraphicsQuality {
|
||||
switch (request) {
|
||||
case GraphicsQualityRequest::kLow:
|
||||
return GraphicsQuality::kLow;
|
||||
case GraphicsQualityRequest::kMedium:
|
||||
return GraphicsQuality::kMedium;
|
||||
case GraphicsQualityRequest::kHigh:
|
||||
return GraphicsQuality::kHigh;
|
||||
case GraphicsQualityRequest::kHigher:
|
||||
return GraphicsQuality::kHigher;
|
||||
case GraphicsQualityRequest::kAuto:
|
||||
return auto_val;
|
||||
default:
|
||||
Log(LogLevel::kError, "Unhandled GraphicsQualityRequest value: "
|
||||
+ std::to_string(static_cast<int>(request)));
|
||||
return GraphicsQuality::kLow;
|
||||
}
|
||||
}
|
||||
auto Graphics::TextureQualityFromRequest(TextureQualityRequest request,
|
||||
TextureQuality auto_val)
|
||||
-> TextureQuality {
|
||||
switch (request) {
|
||||
case TextureQualityRequest::kLow:
|
||||
return TextureQuality::kLow;
|
||||
case TextureQualityRequest::kMedium:
|
||||
return TextureQuality::kMedium;
|
||||
case TextureQualityRequest::kHigh:
|
||||
return TextureQuality::kHigh;
|
||||
case TextureQualityRequest::kAuto:
|
||||
return auto_val;
|
||||
default:
|
||||
Log(LogLevel::kError, "Unhandled TextureQualityRequest value: "
|
||||
+ std::to_string(static_cast<int>(request)));
|
||||
return TextureQuality::kLow;
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::set_client_context(Snapshot<GraphicsClientContext>* context) {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// Currently we only expect this to be set once. That will change
|
||||
// once we support renderer swapping/etc.
|
||||
assert(!g_base->logic->graphics_ready());
|
||||
assert(!client_context_snapshot_.Exists());
|
||||
client_context_snapshot_ = context;
|
||||
|
||||
// Update our static placeholder value (we don't want to calc it dynamically
|
||||
// since it can be accessed from other threads).
|
||||
texture_quality_placeholder_ = TextureQualityFromRequest(
|
||||
settings()->texture_quality, client_context()->auto_texture_quality);
|
||||
|
||||
// Let the logic system know its free to proceed beyond bootstrapping.
|
||||
g_base->logic->OnGraphicsReady();
|
||||
}
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -6,13 +6,15 @@
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
#include "ballistica/base/graphics/support/graphics_client_context.h"
|
||||
#include "ballistica/base/graphics/support/graphics_settings.h"
|
||||
#include "ballistica/shared/foundation/object.h"
|
||||
#include "ballistica/shared/foundation/types.h"
|
||||
#include "ballistica/shared/generic/snapshot.h"
|
||||
#include "ballistica/shared/math/matrix44f.h"
|
||||
#include "ballistica/shared/math/rect.h"
|
||||
#include "ballistica/shared/math/vector2f.h"
|
||||
@ -62,10 +64,10 @@ class Graphics {
|
||||
void OnScreenSizeChange();
|
||||
void DoApplyAppConfig();
|
||||
|
||||
/// Called by the graphics server to keep us up to date in the logic
|
||||
/// thread. Dispatches the news to all logic subsystems that care.
|
||||
void SetScreenSize(float virtual_width, float virtual_height,
|
||||
float physical_width, float physical_height);
|
||||
/// Should be called by the app-adapter to keep the engine informed
|
||||
/// on the drawable area it has to work with (in pixels).
|
||||
void SetScreenResolution(float x, float y);
|
||||
|
||||
void StepDisplayTime();
|
||||
|
||||
auto TextureQualityFromAppConfig() -> TextureQualityRequest;
|
||||
@ -97,13 +99,25 @@ class Graphics {
|
||||
// Called when the GraphicsServer has sent us a frame-def for deletion.
|
||||
void ReturnCompletedFrameDef(FrameDef* frame_def);
|
||||
|
||||
auto screen_pixel_width() const { return res_x_; }
|
||||
auto screen_pixel_height() const { return res_y_; }
|
||||
auto screen_pixel_width() const {
|
||||
assert(g_base->InLogicThread());
|
||||
return res_x_;
|
||||
}
|
||||
auto screen_pixel_height() const {
|
||||
assert(g_base->InLogicThread());
|
||||
return res_y_;
|
||||
}
|
||||
|
||||
// Return the size of the virtual screen. This value should always
|
||||
// Return the current size of the virtual screen. This value should always
|
||||
// be used for interface positioning, etc.
|
||||
auto screen_virtual_width() const { return res_x_virtual_; }
|
||||
auto screen_virtual_height() const { return res_y_virtual_; }
|
||||
auto screen_virtual_width() const {
|
||||
assert(g_base->InLogicThread());
|
||||
return res_x_virtual_;
|
||||
}
|
||||
auto screen_virtual_height() const {
|
||||
assert(g_base->InLogicThread());
|
||||
return res_y_virtual_;
|
||||
}
|
||||
|
||||
void ClearScreenMessageTranslations();
|
||||
|
||||
@ -226,10 +240,10 @@ class Graphics {
|
||||
float upper_top);
|
||||
void ReleaseFadeEndCommand();
|
||||
|
||||
auto tv_border() const {
|
||||
assert(g_base->InLogicThread());
|
||||
return tv_border_;
|
||||
}
|
||||
// auto tv_border() const {
|
||||
// assert(g_base->InLogicThread());
|
||||
// return tv_border_;
|
||||
// }
|
||||
|
||||
// Nodes that draw flat stuff into the overlay pass should query this z value
|
||||
// for where to draw in z.
|
||||
@ -270,17 +284,6 @@ class Graphics {
|
||||
return y * (res_y_virtual_ / res_y_);
|
||||
}
|
||||
|
||||
// FIXME: This should probably move to Renderer or AppAdapter once we
|
||||
// support switching renderers.
|
||||
auto supports_high_quality_graphics() const {
|
||||
assert(has_supports_high_quality_graphics_value_);
|
||||
return supports_high_quality_graphics_;
|
||||
}
|
||||
void SetSupportsHighQualityGraphics(bool s);
|
||||
auto has_supports_high_quality_graphics_value() const {
|
||||
return has_supports_high_quality_graphics_value_;
|
||||
}
|
||||
|
||||
void set_internal_components_inited(bool val) {
|
||||
internal_components_inited_ = val;
|
||||
}
|
||||
@ -322,19 +325,65 @@ class Graphics {
|
||||
camera_gyro_explicitly_disabled_ = disabled;
|
||||
}
|
||||
|
||||
auto* settings() const {
|
||||
assert(g_base->InLogicThread());
|
||||
assert(settings_snapshot_.Exists());
|
||||
return settings_snapshot_.Get()->Get();
|
||||
}
|
||||
|
||||
auto GetGraphicsSettingsSnapshot() -> Snapshot<GraphicsSettings>*;
|
||||
|
||||
/// Called by the graphics-server when a new client context is ready.
|
||||
void set_client_context(Snapshot<GraphicsClientContext>* context);
|
||||
|
||||
auto has_client_context() -> bool {
|
||||
return client_context_snapshot_.Exists();
|
||||
}
|
||||
|
||||
auto client_context() const -> const GraphicsClientContext* {
|
||||
assert(g_base->InLogicThread());
|
||||
assert(client_context_snapshot_.Exists());
|
||||
return client_context_snapshot_.Get()->Get();
|
||||
}
|
||||
|
||||
static auto GraphicsQualityFromRequest(GraphicsQualityRequest request,
|
||||
GraphicsQuality auto_val)
|
||||
-> GraphicsQuality;
|
||||
static auto TextureQualityFromRequest(TextureQualityRequest request,
|
||||
TextureQuality auto_val)
|
||||
-> TextureQuality;
|
||||
|
||||
/// For temporary use from arbitrary threads. This should be removed when
|
||||
/// possible and replaced with proper safe thread-specific access patterns
|
||||
/// (so we can support switching renderers/etc.).
|
||||
auto placeholder_texture_quality() const {
|
||||
assert(client_context_snapshot_.Exists());
|
||||
return texture_quality_placeholder_;
|
||||
}
|
||||
|
||||
/// For temporary use in arbitrary threads. This should be removed when
|
||||
/// possible and replaced with proper safe thread-specific access
|
||||
/// patterns (so we can support switching renderers/etc.).
|
||||
auto placeholder_client_context() const -> const GraphicsClientContext* {
|
||||
// Using this from arbitrary threads is currently ok currently since
|
||||
// context never changes once set. Will need to kill this call once that
|
||||
// can happen though.
|
||||
assert(client_context_snapshot_.Exists());
|
||||
return client_context_snapshot_.Get()->Get();
|
||||
}
|
||||
|
||||
protected:
|
||||
class ScreenMessageEntry;
|
||||
|
||||
Graphics();
|
||||
virtual ~Graphics();
|
||||
virtual void DoDrawFade(FrameDef* frame_def, float amt);
|
||||
|
||||
private:
|
||||
class ScreenMessageEntry;
|
||||
static void CalcVirtualRes_(float* x, float* y);
|
||||
void DrawBoxingGlovesTest(FrameDef* frame_def);
|
||||
void DrawBlotches(FrameDef* frame_def);
|
||||
void DrawCursor(FrameDef* frame_def);
|
||||
void DrawFades(FrameDef* frame_def);
|
||||
void DrawDebugBuffers(RenderPass* pass);
|
||||
|
||||
void UpdateAndDrawProgressBar(FrameDef* frame_def);
|
||||
void DoDrawBlotch(std::vector<uint16_t>* indices,
|
||||
std::vector<VertexSprite>* verts, const Vector3f& pos,
|
||||
@ -347,44 +396,47 @@ class Graphics {
|
||||
void DrawProgressBar(RenderPass* pass, float opacity);
|
||||
void UpdateProgressBarProgress(float target);
|
||||
void UpdateGyro(microsecs_t time, microsecs_t elapsed);
|
||||
void UpdateInitialGraphicsSettingsSend_();
|
||||
|
||||
bool drawing_transparent_only_{};
|
||||
bool drawing_opaque_only_{};
|
||||
bool has_supports_high_quality_graphics_value_{};
|
||||
bool supports_high_quality_graphics_{};
|
||||
bool internal_components_inited_{};
|
||||
bool fade_out_{true};
|
||||
bool progress_bar_{};
|
||||
bool progress_bar_fade_in_{};
|
||||
bool debug_draw_{};
|
||||
bool network_debug_display_enabled_{};
|
||||
bool hardware_cursor_visible_{};
|
||||
bool camera_shake_disabled_{};
|
||||
bool camera_gyro_explicitly_disabled_{};
|
||||
bool gyro_enabled_{true};
|
||||
bool show_fps_{};
|
||||
bool show_ping_{};
|
||||
bool show_net_info_{};
|
||||
bool tv_border_{};
|
||||
bool floor_reflection_{};
|
||||
bool building_frame_def_{};
|
||||
bool shadow_ortho_{};
|
||||
bool fetched_overlay_node_z_depth_{};
|
||||
bool gyro_broken_{};
|
||||
GraphicsQuality last_frame_def_graphics_quality_{GraphicsQuality::kUnset};
|
||||
std::list<Object::Ref<PythonContextCall>> clean_frame_commands_;
|
||||
std::vector<MeshData*> mesh_data_creates_;
|
||||
std::vector<MeshData*> mesh_data_destroys_;
|
||||
microsecs_t last_create_frame_def_time_microsecs_{};
|
||||
millisecs_t last_create_frame_def_time_millisecs_{};
|
||||
int last_total_frames_rendered_{};
|
||||
int last_fps_{};
|
||||
int progress_bar_loads_{};
|
||||
int frame_def_count_{};
|
||||
int frame_def_count_filtered_{};
|
||||
int next_settings_index_{};
|
||||
TextureQuality texture_quality_placeholder_{};
|
||||
bool drawing_transparent_only_ : 1 {};
|
||||
bool drawing_opaque_only_ : 1 {};
|
||||
bool internal_components_inited_ : 1 {};
|
||||
bool fade_out_ : 1 {true};
|
||||
bool progress_bar_ : 1 {};
|
||||
bool progress_bar_fade_in_ : 1 {};
|
||||
bool debug_draw_ : 1 {};
|
||||
bool network_debug_display_enabled_ : 1 {};
|
||||
bool hardware_cursor_visible_ : 1 {};
|
||||
bool camera_shake_disabled_ : 1 {};
|
||||
bool camera_gyro_explicitly_disabled_ : 1 {};
|
||||
bool gyro_enabled_ : 1 {true};
|
||||
bool show_fps_ : 1 {};
|
||||
bool show_ping_ : 1 {};
|
||||
bool show_net_info_ : 1 {};
|
||||
bool tv_border_ : 1 {};
|
||||
bool floor_reflection_ : 1 {};
|
||||
bool building_frame_def_ : 1 {};
|
||||
bool shadow_ortho_ : 1 {};
|
||||
bool fetched_overlay_node_z_depth_ : 1 {};
|
||||
bool gyro_broken_ : 1 {};
|
||||
bool set_fade_start_on_next_draw_ : 1 {};
|
||||
bool graphics_settings_dirty_ : 1 {true};
|
||||
bool applied_app_config_ : 1 {};
|
||||
bool sent_initial_graphics_settings_ : 1 {};
|
||||
bool got_screen_resolution_ : 1 {};
|
||||
Vector3f shadow_offset_{0.0f, 0.0f, 0.0f};
|
||||
Vector2f shadow_scale_{1.0f, 1.0f};
|
||||
Vector3f tint_{1.0f, 1.0f, 1.0f};
|
||||
Vector3f ambient_color_{1.0f, 1.0f, 1.0f};
|
||||
Vector3f vignette_outer_{0.0f, 0.0f, 0.0f};
|
||||
Vector3f vignette_inner_{1.0f, 1.0f, 1.0f};
|
||||
std::vector<FrameDef*> recycle_frame_defs_;
|
||||
millisecs_t last_jitter_update_time_{};
|
||||
Vector3f jitter_{0.0f, 0.0f, 0.0f};
|
||||
Vector3f accel_smoothed_{0.0f, 0.0f, 0.0f};
|
||||
Vector3f accel_smoothed2_{0.0f, 0.0f, 0.0f};
|
||||
@ -394,8 +446,50 @@ class Graphics {
|
||||
Vector3f tilt_smoothed_{0.0f, 0.0f, 0.0f};
|
||||
Vector3f tilt_vel_{0.0f, 0.0f, 0.0f};
|
||||
Vector3f tilt_pos_{0.0f, 0.0f, 0.0f};
|
||||
Vector3f gyro_vals_{0.0f, 0.0, 0.0f};
|
||||
std::string fps_string_;
|
||||
std::string ping_string_;
|
||||
std::string net_info_string_;
|
||||
std::map<std::string, Object::Ref<NetGraph>> debug_graphs_;
|
||||
std::mutex frame_def_delete_list_mutex_;
|
||||
std::list<Object::Ref<PythonContextCall>> clean_frame_commands_;
|
||||
std::list<ScreenMessageEntry> screen_messages_;
|
||||
std::list<ScreenMessageEntry> screen_messages_top_;
|
||||
std::vector<FrameDef*> recycle_frame_defs_;
|
||||
std::vector<uint16_t> blotch_indices_;
|
||||
std::vector<VertexSprite> blotch_verts_;
|
||||
std::vector<uint16_t> blotch_soft_indices_;
|
||||
std::vector<VertexSprite> blotch_soft_verts_;
|
||||
std::vector<uint16_t> blotch_soft_obj_indices_;
|
||||
std::vector<VertexSprite> blotch_soft_obj_verts_;
|
||||
std::vector<FrameDef*> frame_def_delete_list_;
|
||||
std::vector<MeshData*> mesh_data_creates_;
|
||||
std::vector<MeshData*> mesh_data_destroys_;
|
||||
float fade_{};
|
||||
float res_x_{256.0f};
|
||||
float res_y_{256.0f};
|
||||
float res_x_virtual_{256.0f};
|
||||
float res_y_virtual_{256.0f};
|
||||
float gyro_mag_test_{};
|
||||
float overlay_node_z_depth_{};
|
||||
float progress_bar_progress_{};
|
||||
float screen_gamma_{1.0f};
|
||||
float shadow_lower_bottom_{-4.0f};
|
||||
float shadow_lower_top_{4.0f};
|
||||
float shadow_upper_bottom_{30.0f};
|
||||
float shadow_upper_top_{40.0f};
|
||||
millisecs_t fade_start_{};
|
||||
millisecs_t fade_time_{};
|
||||
millisecs_t next_stat_update_time_{};
|
||||
millisecs_t progress_bar_end_time_{-9999};
|
||||
millisecs_t last_progress_bar_draw_time_{};
|
||||
millisecs_t last_progress_bar_start_time_{};
|
||||
microsecs_t last_suppress_gyro_time_{};
|
||||
millisecs_t last_cursor_visibility_event_time_{};
|
||||
microsecs_t next_frame_number_filtered_increment_time_{};
|
||||
microsecs_t last_create_frame_def_time_microsecs_{};
|
||||
millisecs_t last_create_frame_def_time_millisecs_{};
|
||||
millisecs_t last_jitter_update_time_{};
|
||||
Object::Ref<ImageMesh> screen_mesh_;
|
||||
Object::Ref<ImageMesh> progress_bar_bottom_mesh_;
|
||||
Object::Ref<ImageMesh> progress_bar_top_mesh_;
|
||||
@ -406,49 +500,10 @@ class Graphics {
|
||||
Object::Ref<SpriteMesh> shadow_blotch_mesh_;
|
||||
Object::Ref<SpriteMesh> shadow_blotch_soft_mesh_;
|
||||
Object::Ref<SpriteMesh> shadow_blotch_soft_obj_mesh_;
|
||||
std::string fps_string_;
|
||||
std::string ping_string_;
|
||||
std::string net_info_string_;
|
||||
std::vector<uint16_t> blotch_indices_;
|
||||
std::vector<VertexSprite> blotch_verts_;
|
||||
std::vector<uint16_t> blotch_soft_indices_;
|
||||
std::vector<VertexSprite> blotch_soft_verts_;
|
||||
std::vector<uint16_t> blotch_soft_obj_indices_;
|
||||
std::vector<VertexSprite> blotch_soft_obj_verts_;
|
||||
std::map<std::string, Object::Ref<NetGraph>> debug_graphs_;
|
||||
std::mutex frame_def_delete_list_mutex_;
|
||||
std::vector<FrameDef*> frame_def_delete_list_;
|
||||
Object::Ref<Camera> camera_;
|
||||
millisecs_t next_stat_update_time_{};
|
||||
int last_total_frames_rendered_{};
|
||||
int last_fps_{};
|
||||
std::list<ScreenMessageEntry> screen_messages_;
|
||||
std::list<ScreenMessageEntry> screen_messages_top_;
|
||||
bool set_fade_start_on_next_draw_{};
|
||||
millisecs_t fade_start_{};
|
||||
millisecs_t fade_time_{};
|
||||
float fade_{};
|
||||
Vector3f gyro_vals_{0.0f, 0.0, 0.0f};
|
||||
float res_x_{100};
|
||||
float res_y_{100};
|
||||
float res_x_virtual_{100};
|
||||
float res_y_virtual_{100};
|
||||
int progress_bar_loads_{};
|
||||
millisecs_t progress_bar_end_time_{-9999};
|
||||
millisecs_t last_progress_bar_draw_time_{};
|
||||
millisecs_t last_progress_bar_start_time_{};
|
||||
float progress_bar_progress_{};
|
||||
float screen_gamma_{1.0f};
|
||||
float shadow_lower_bottom_{-4.0f};
|
||||
float shadow_lower_top_{4.0f};
|
||||
float shadow_upper_bottom_{30.0f};
|
||||
float shadow_upper_top_{40.0f};
|
||||
millisecs_t last_cursor_visibility_event_time_{};
|
||||
microsecs_t next_frame_number_filtered_increment_time_{};
|
||||
int64_t frame_def_count_{};
|
||||
int64_t frame_def_count_filtered_{};
|
||||
microsecs_t last_suppress_gyro_time_{};
|
||||
Object::Ref<PythonContextCall> fade_end_call_;
|
||||
Object::Ref<Snapshot<GraphicsSettings>> settings_snapshot_;
|
||||
Object::Ref<Snapshot<GraphicsClientContext>> client_context_snapshot_;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -32,15 +32,88 @@ void GraphicsServer::EnqueueFrameDef(FrameDef* framedef) {
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsServer::ApplySettings(const GraphicsSettings* settings) {
|
||||
assert(g_base->InGraphicsContext());
|
||||
|
||||
// Only push each unique settings instance through once.
|
||||
if (settings->index == settings_index_) {
|
||||
return;
|
||||
}
|
||||
settings_index_ = settings->index;
|
||||
|
||||
assert(settings->resolution.x >= 0.0f && settings->resolution.y >= 0.0f
|
||||
&& settings->resolution_virtual.x >= 0.0f
|
||||
&& settings->resolution_virtual.y >= 0.0f);
|
||||
|
||||
// Pull a few things out ourself such as screen resolution.
|
||||
tv_border_ = settings->tv_border;
|
||||
if (renderer_) {
|
||||
renderer_->set_pixel_scale(settings->pixel_scale);
|
||||
}
|
||||
// Note: not checking virtual res here; assuming it only changes when
|
||||
// actual res changes.
|
||||
if (res_x_ != settings->resolution.x || res_y_ != settings->resolution.y) {
|
||||
res_x_ = settings->resolution.x;
|
||||
res_y_ = settings->resolution.y;
|
||||
res_x_virtual_ = settings->resolution_virtual.x;
|
||||
res_y_virtual_ = settings->resolution_virtual.y;
|
||||
if (renderer_) {
|
||||
renderer_->OnScreenSizeChange();
|
||||
}
|
||||
}
|
||||
|
||||
// Kick this over to the app-adapter to apply whatever settings they
|
||||
// gathered for themself.
|
||||
g_base->app_adapter->ApplyGraphicsSettings(settings);
|
||||
|
||||
// Lastly, if we've not yet sent a context to the client, do so.
|
||||
if (client_context_ == nullptr) {
|
||||
set_client_context(g_base->app_adapter->GetGraphicsClientContext());
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsServer::set_client_context(GraphicsClientContext* context) {
|
||||
assert(g_base->InGraphicsContext());
|
||||
|
||||
// We have to do a bit of a song and dance with these context pointers.
|
||||
// We wrap the context in an immutable object wrapper which is owned by
|
||||
// the logic thread and that takes care of killing it when no longer
|
||||
// used there, but we also need to keep it alive here in our thread.
|
||||
// (which may not be the logic thread). So to accomplish that, we
|
||||
// immediately ship a refcount increment over to the logic thread, and
|
||||
// once we're done with an obj we ship a decrement.
|
||||
|
||||
auto* old_wrapper = client_context_;
|
||||
auto* new_wrapper =
|
||||
Object::NewDeferred<Snapshot<GraphicsClientContext>>(context);
|
||||
|
||||
client_context_ = new_wrapper;
|
||||
|
||||
g_base->logic->event_loop()->PushCall([old_wrapper, new_wrapper] {
|
||||
// (This has to happen in logic thread).
|
||||
auto ref = Object::CompleteDeferred(new_wrapper);
|
||||
|
||||
// Free the old one which the graphics server doesn't need anymore.
|
||||
if (old_wrapper) {
|
||||
old_wrapper->ObjectDecrementStrongRefCount();
|
||||
}
|
||||
|
||||
// Keep the new one alive for the graphics server.
|
||||
ref->ObjectIncrementStrongRefCount();
|
||||
|
||||
// Plug the new one in for logic to start using.
|
||||
g_base->graphics->set_client_context(new_wrapper);
|
||||
});
|
||||
}
|
||||
|
||||
auto GraphicsServer::TryRender() -> bool {
|
||||
assert(g_base->app_adapter->InGraphicsContext());
|
||||
|
||||
bool success{};
|
||||
|
||||
if (FrameDef* frame_def = WaitForRenderFrameDef_()) {
|
||||
// Apply settings such as tv-mode that were passed along via the
|
||||
// frame-def.
|
||||
ApplyFrameDefSettings(frame_def);
|
||||
// Apply any new graphics settings passed along via the frame-def.
|
||||
ApplySettings(frame_def->settings());
|
||||
|
||||
// Note: we run mesh-updates on each frame-def that comes through even
|
||||
// if we don't actually render the frame.
|
||||
@ -58,6 +131,7 @@ auto GraphicsServer::TryRender() -> bool {
|
||||
// Send this frame_def back to the logic thread for deletion or recycling.
|
||||
g_base->graphics->ReturnCompletedFrameDef(frame_def);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@ -113,11 +187,6 @@ auto GraphicsServer::WaitForRenderFrameDef_() -> FrameDef* {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GraphicsServer::ApplyFrameDefSettings(FrameDef* frame_def) {
|
||||
assert(g_base->app_adapter->InGraphicsContext());
|
||||
tv_border_ = frame_def->tv_border();
|
||||
}
|
||||
|
||||
// Runs any mesh updates contained in the frame-def.
|
||||
void GraphicsServer::RunFrameDefMeshUpdates(FrameDef* frame_def) {
|
||||
assert(g_base->app_adapter->InGraphicsContext());
|
||||
@ -250,14 +319,15 @@ void GraphicsServer::SetNullGraphics() {
|
||||
SetTextureCompressionTypes(c_types);
|
||||
graphics_quality_requested_ = GraphicsQualityRequest::kLow;
|
||||
graphics_quality_ = GraphicsQuality::kLow;
|
||||
graphics_quality_set_ = true;
|
||||
// graphics_quality_set_ = true;
|
||||
texture_quality_requested_ = TextureQualityRequest::kLow;
|
||||
texture_quality_ = TextureQuality::kLow;
|
||||
texture_quality_set_ = true;
|
||||
// texture_quality_set_ = true;
|
||||
|
||||
FatalError("FIXME REWORK THIS");
|
||||
// Let the logic thread know screen creation is done (or lack thereof).
|
||||
g_base->logic->event_loop()->PushCall(
|
||||
[] { g_base->logic->OnGraphicsReady(); });
|
||||
// g_base->logic->event_loop()->PushCall(
|
||||
// [] { g_base->logic->OnGraphicsReady(); });
|
||||
}
|
||||
|
||||
void GraphicsServer::set_renderer(Renderer* renderer) {
|
||||
@ -279,59 +349,43 @@ void GraphicsServer::LoadRenderer() {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (graphics_quality_requested_) {
|
||||
case GraphicsQualityRequest::kLow:
|
||||
graphics_quality_ = GraphicsQuality::kLow;
|
||||
break;
|
||||
case GraphicsQualityRequest::kMedium:
|
||||
graphics_quality_ = GraphicsQuality::kMedium;
|
||||
break;
|
||||
case GraphicsQualityRequest::kHigh:
|
||||
graphics_quality_ = GraphicsQuality::kHigh;
|
||||
break;
|
||||
case GraphicsQualityRequest::kHigher:
|
||||
graphics_quality_ = GraphicsQuality::kHigher;
|
||||
break;
|
||||
case GraphicsQualityRequest::kAuto:
|
||||
graphics_quality_ = renderer_->GetAutoGraphicsQuality();
|
||||
break;
|
||||
default:
|
||||
Log(LogLevel::kError,
|
||||
"Unhandled GraphicsQualityRequest value: "
|
||||
+ std::to_string(static_cast<int>(graphics_quality_requested_)));
|
||||
graphics_quality_ = GraphicsQuality::kLow;
|
||||
}
|
||||
graphics_quality_ = Graphics::GraphicsQualityFromRequest(
|
||||
graphics_quality_requested_, renderer_->GetAutoGraphicsQuality());
|
||||
|
||||
texture_quality_ = Graphics::TextureQualityFromRequest(
|
||||
texture_quality_requested_, renderer_->GetAutoTextureQuality());
|
||||
|
||||
// If we don't support high quality graphics, make sure we're no higher than
|
||||
// medium.
|
||||
BA_PRECONDITION(g_base->graphics->has_supports_high_quality_graphics_value());
|
||||
if (!g_base->graphics->supports_high_quality_graphics()
|
||||
&& graphics_quality_ > GraphicsQuality::kMedium) {
|
||||
graphics_quality_ = GraphicsQuality::kMedium;
|
||||
}
|
||||
graphics_quality_set_ = true;
|
||||
// BA_PRECONDITION(g_base->graphics->has_supports_high_quality_graphics_value());
|
||||
// if (!g_base->graphics->supports_high_quality_graphics()
|
||||
// && graphics_quality_ > GraphicsQuality::kMedium) {
|
||||
// graphics_quality_ = GraphicsQuality::kMedium;
|
||||
// }
|
||||
// graphics_quality_set_ = true;
|
||||
|
||||
// Update texture quality based on request.
|
||||
switch (texture_quality_requested_) {
|
||||
case TextureQualityRequest::kLow:
|
||||
texture_quality_ = TextureQuality::kLow;
|
||||
break;
|
||||
case TextureQualityRequest::kMedium:
|
||||
texture_quality_ = TextureQuality::kMedium;
|
||||
break;
|
||||
case TextureQualityRequest::kHigh:
|
||||
texture_quality_ = TextureQuality::kHigh;
|
||||
break;
|
||||
case TextureQualityRequest::kAuto:
|
||||
texture_quality_ = renderer_->GetAutoTextureQuality();
|
||||
break;
|
||||
default:
|
||||
Log(LogLevel::kError,
|
||||
"Unhandled TextureQualityRequest value: "
|
||||
+ std::to_string(static_cast<int>(texture_quality_requested_)));
|
||||
texture_quality_ = TextureQuality::kLow;
|
||||
}
|
||||
texture_quality_set_ = true;
|
||||
// switch (texture_quality_requested_) {
|
||||
// case TextureQualityRequest::kLow:
|
||||
// texture_quality_ = TextureQuality::kLow;
|
||||
// break;
|
||||
// case TextureQualityRequest::kMedium:
|
||||
// texture_quality_ = TextureQuality::kMedium;
|
||||
// break;
|
||||
// case TextureQualityRequest::kHigh:
|
||||
// texture_quality_ = TextureQuality::kHigh;
|
||||
// break;
|
||||
// case TextureQualityRequest::kAuto:
|
||||
// texture_quality_ = renderer_->GetAutoTextureQuality();
|
||||
// break;
|
||||
// default:
|
||||
// Log(LogLevel::kError,
|
||||
// "Unhandled TextureQualityRequest value: "
|
||||
// +
|
||||
// std::to_string(static_cast<int>(texture_quality_requested_)));
|
||||
// texture_quality_ = TextureQuality::kLow;
|
||||
// }
|
||||
// texture_quality_set_ = true;
|
||||
|
||||
// Ok we've got our qualities figured out; now load/update the renderer.
|
||||
renderer_->Load();
|
||||
@ -389,56 +443,56 @@ void GraphicsServer::UnloadRenderer() {
|
||||
}
|
||||
|
||||
// Given physical res, calculate virtual res.
|
||||
void GraphicsServer::CalcVirtualRes_(float* x, float* y) {
|
||||
float x_in = *x;
|
||||
float y_in = *y;
|
||||
if (*x / *y > static_cast<float>(kBaseVirtualResX)
|
||||
/ static_cast<float>(kBaseVirtualResY)) {
|
||||
*y = kBaseVirtualResY;
|
||||
*x = *y * (x_in / y_in);
|
||||
} else {
|
||||
*x = kBaseVirtualResX;
|
||||
*y = *x * (y_in / x_in);
|
||||
}
|
||||
}
|
||||
// void GraphicsServer::CalcVirtualRes_(float* x, float* y) {
|
||||
// float x_in = *x;
|
||||
// float y_in = *y;
|
||||
// if (*x / *y > static_cast<float>(kBaseVirtualResX)
|
||||
// / static_cast<float>(kBaseVirtualResY)) {
|
||||
// *y = kBaseVirtualResY;
|
||||
// *x = *y * (x_in / y_in);
|
||||
// } else {
|
||||
// *x = kBaseVirtualResX;
|
||||
// *y = *x * (y_in / x_in);
|
||||
// }
|
||||
// }
|
||||
|
||||
void GraphicsServer::UpdateVirtualScreenRes_() {
|
||||
assert(g_base->app_adapter->InGraphicsContext());
|
||||
// void GraphicsServer::UpdateVirtualScreenRes_() {
|
||||
// assert(g_base->app_adapter->InGraphicsContext());
|
||||
|
||||
// In vr mode our virtual res is independent of our screen size.
|
||||
// (since it gets drawn to an overlay)
|
||||
if (g_core->IsVRMode()) {
|
||||
res_x_virtual_ = kBaseVirtualResX;
|
||||
res_y_virtual_ = kBaseVirtualResY;
|
||||
} else {
|
||||
res_x_virtual_ = res_x_;
|
||||
res_y_virtual_ = res_y_;
|
||||
CalcVirtualRes_(&res_x_virtual_, &res_y_virtual_);
|
||||
}
|
||||
}
|
||||
// // In vr mode our virtual res is independent of our screen size.
|
||||
// // (since it gets drawn to an overlay)
|
||||
// if (g_core->IsVRMode()) {
|
||||
// res_x_virtual_ = kBaseVirtualResX;
|
||||
// res_y_virtual_ = kBaseVirtualResY;
|
||||
// } else {
|
||||
// res_x_virtual_ = res_x_;
|
||||
// res_y_virtual_ = res_y_;
|
||||
// CalcVirtualRes_(&res_x_virtual_, &res_y_virtual_);
|
||||
// }
|
||||
// }
|
||||
|
||||
void GraphicsServer::SetScreenResolution(float h, float v) {
|
||||
assert(g_base->app_adapter->InGraphicsContext());
|
||||
// void GraphicsServer::SetScreenResolution(float h, float v) {
|
||||
// assert(g_base->app_adapter->InGraphicsContext());
|
||||
|
||||
// Ignore redundant sets.
|
||||
if (res_x_ == h && res_y_ == v) {
|
||||
return;
|
||||
}
|
||||
res_x_ = h;
|
||||
res_y_ = v;
|
||||
UpdateVirtualScreenRes_();
|
||||
// // Ignore redundant sets.
|
||||
// if (res_x_ == h && res_y_ == v) {
|
||||
// return;
|
||||
// }
|
||||
// res_x_ = h;
|
||||
// res_y_ = v;
|
||||
// // UpdateVirtualScreenRes_();
|
||||
|
||||
// Inform renderer of the change.
|
||||
if (renderer_) {
|
||||
renderer_->OnScreenSizeChange();
|
||||
}
|
||||
// // Inform renderer of the change.
|
||||
// if (renderer_) {
|
||||
// renderer_->OnScreenSizeChange();
|
||||
// }
|
||||
|
||||
// Inform all logic thread bits of this change.
|
||||
g_base->logic->event_loop()->PushCall(
|
||||
[vx = res_x_virtual_, vy = res_y_virtual_, x = res_x_, y = res_y_] {
|
||||
g_base->graphics->SetScreenSize(vx, vy, x, y);
|
||||
});
|
||||
}
|
||||
// // Inform all logic thread bits of this change.
|
||||
// g_base->logic->event_loop()->PushCall(
|
||||
// [vx = res_x_virtual_, vy = res_y_virtual_, x = res_x_, y = res_y_] {
|
||||
// g_base->graphics->SetScreenSize(vx, vy, x, y);
|
||||
// });
|
||||
// }
|
||||
|
||||
// FIXME: Shouldn't have android-specific code in here.
|
||||
void GraphicsServer::HandlePushAndroidRes(const std::string& android_res) {
|
||||
@ -579,15 +633,15 @@ void GraphicsServer::PushReloadMediaCall() {
|
||||
g_base->app_adapter->PushGraphicsContextCall([this] { ReloadMedia_(); });
|
||||
}
|
||||
|
||||
void GraphicsServer::PushSetScreenPixelScaleCall(float pixel_scale) {
|
||||
g_base->app_adapter->PushGraphicsContextCall([this, pixel_scale] {
|
||||
assert(g_base->app_adapter->InGraphicsContext());
|
||||
if (!renderer_) {
|
||||
return;
|
||||
}
|
||||
renderer_->set_pixel_scale(pixel_scale);
|
||||
});
|
||||
}
|
||||
// void GraphicsServer::PushSetScreenPixelScaleCall(float pixel_scale) {
|
||||
// g_base->app_adapter->PushGraphicsContextCall([this, pixel_scale] {
|
||||
// assert(g_base->app_adapter->InGraphicsContext());
|
||||
// if (!renderer_) {
|
||||
// return;
|
||||
// }
|
||||
// renderer_->set_pixel_scale(pixel_scale);
|
||||
// });
|
||||
// }
|
||||
|
||||
void GraphicsServer::PushComponentUnloadCall(
|
||||
const std::vector<Object::Ref<Asset>*>& components) {
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
#include "ballistica/shared/foundation/object.h"
|
||||
#include "ballistica/shared/generic/snapshot.h"
|
||||
#include "ballistica/shared/math/matrix44f.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
@ -51,16 +52,18 @@ class GraphicsServer {
|
||||
return renderer_loaded_;
|
||||
}
|
||||
|
||||
void ApplySettings(const GraphicsSettings* settings);
|
||||
|
||||
/// The AppAdapter should call this to inform the engine of screen size
|
||||
/// changes. Changes will be applied to the server and then sent to the
|
||||
/// logic thread to apply to various app systems (ui, etc.).
|
||||
void SetScreenResolution(float h, float v);
|
||||
// void SetScreenResolution(float h, float v);
|
||||
|
||||
/// Used by headless builds to init the graphics-server into a
|
||||
/// non-functional state.
|
||||
void SetNullGraphics();
|
||||
|
||||
void PushSetScreenPixelScaleCall(float pixel_scale);
|
||||
// void PushSetScreenPixelScaleCall(float pixel_scale);
|
||||
void PushReloadMediaCall();
|
||||
void PushRemoveRenderHoldCall();
|
||||
void PushComponentUnloadCall(
|
||||
@ -71,8 +74,6 @@ class GraphicsServer {
|
||||
/// rendering.
|
||||
void EnqueueFrameDef(FrameDef* framedef);
|
||||
|
||||
void ApplyFrameDefSettings(FrameDef* frame_def);
|
||||
|
||||
void RunFrameDefMeshUpdates(FrameDef* frame_def);
|
||||
|
||||
// Renders shadow passes and other common parts of a frame_def.
|
||||
@ -108,9 +109,7 @@ class GraphicsServer {
|
||||
projection_matrix_state_++;
|
||||
}
|
||||
|
||||
auto projection_matrix_state() -> uint32_t {
|
||||
return projection_matrix_state_;
|
||||
}
|
||||
auto projection_matrix_state() { return projection_matrix_state_; }
|
||||
|
||||
void SetLightShadowProjectionMatrix(const Matrix44f& p) {
|
||||
// This will generally get repeatedly set to the same value
|
||||
@ -121,61 +120,57 @@ class GraphicsServer {
|
||||
}
|
||||
}
|
||||
|
||||
auto light_shadow_projection_matrix_state() const -> uint32_t {
|
||||
auto light_shadow_projection_matrix_state() const {
|
||||
return light_shadow_projection_matrix_state_;
|
||||
}
|
||||
|
||||
auto light_shadow_projection_matrix() const -> const Matrix44f& {
|
||||
const auto& light_shadow_projection_matrix() const {
|
||||
return light_shadow_projection_matrix_;
|
||||
}
|
||||
|
||||
// Return the modelview * projection matrix.
|
||||
auto GetModelViewProjectionMatrix() -> const Matrix44f& {
|
||||
const auto& GetModelViewProjectionMatrix() {
|
||||
UpdateModelViewProjectionMatrix_();
|
||||
return model_view_projection_matrix_;
|
||||
}
|
||||
|
||||
auto GetModelViewProjectionMatrixState() -> uint32_t {
|
||||
auto GetModelViewProjectionMatrixState() {
|
||||
UpdateModelViewProjectionMatrix_();
|
||||
return model_view_projection_matrix_state_;
|
||||
}
|
||||
|
||||
auto GetModelWorldMatrix() -> const Matrix44f& {
|
||||
const auto& GetModelWorldMatrix() {
|
||||
UpdateModelWorldMatrix_();
|
||||
return model_world_matrix_;
|
||||
}
|
||||
|
||||
auto GetModelWorldMatrixState() -> uint32_t {
|
||||
auto GetModelWorldMatrixState() {
|
||||
UpdateModelWorldMatrix_();
|
||||
return model_world_matrix_state_;
|
||||
}
|
||||
|
||||
auto cam_pos() -> const Vector3f& { return cam_pos_; }
|
||||
const auto& cam_pos() { return cam_pos_; }
|
||||
|
||||
auto cam_pos_state() -> uint32_t { return cam_pos_state_; }
|
||||
auto cam_pos_state() { return cam_pos_state_; }
|
||||
|
||||
auto GetCamOrientMatrix() -> const Matrix44f& {
|
||||
const auto& GetCamOrientMatrix() {
|
||||
UpdateCamOrientMatrix_();
|
||||
return cam_orient_matrix_;
|
||||
}
|
||||
|
||||
auto GetCamOrientMatrixState() -> uint32_t {
|
||||
auto GetCamOrientMatrixState() {
|
||||
UpdateCamOrientMatrix_();
|
||||
return cam_orient_matrix_state_;
|
||||
}
|
||||
|
||||
auto model_view_matrix() const -> const Matrix44f& {
|
||||
return model_view_matrix_;
|
||||
}
|
||||
const auto& model_view_matrix() const { return model_view_matrix_; }
|
||||
|
||||
void SetModelViewMatrix(const Matrix44f& m) {
|
||||
model_view_matrix_ = m;
|
||||
model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true;
|
||||
}
|
||||
|
||||
auto projection_matrix() const -> const Matrix44f& {
|
||||
return projection_matrix_;
|
||||
}
|
||||
const auto& projection_matrix() const { return projection_matrix_; }
|
||||
|
||||
void PushTransform() {
|
||||
model_view_stack_.push_back(model_view_matrix_);
|
||||
@ -209,32 +204,34 @@ class GraphicsServer {
|
||||
model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true;
|
||||
}
|
||||
|
||||
auto quality() const -> GraphicsQuality {
|
||||
assert(graphics_quality_set_);
|
||||
auto quality() const {
|
||||
assert(InGraphicsContext_());
|
||||
assert(graphics_quality_ != GraphicsQuality::kUnset);
|
||||
return graphics_quality_;
|
||||
}
|
||||
|
||||
auto texture_quality() const -> TextureQuality {
|
||||
assert(texture_quality_set_);
|
||||
auto texture_quality() const {
|
||||
assert(InGraphicsContext_());
|
||||
assert(texture_quality_ != TextureQuality::kUnset);
|
||||
return texture_quality_;
|
||||
}
|
||||
|
||||
auto screen_pixel_width() const -> float {
|
||||
auto screen_pixel_width() const {
|
||||
assert(InGraphicsContext_());
|
||||
return res_x_;
|
||||
}
|
||||
|
||||
auto screen_pixel_height() const -> float {
|
||||
auto screen_pixel_height() const {
|
||||
assert(InGraphicsContext_());
|
||||
return res_y_;
|
||||
}
|
||||
|
||||
auto screen_virtual_width() const -> float {
|
||||
auto screen_virtual_width() const {
|
||||
assert(InGraphicsContext_());
|
||||
return res_x_virtual_;
|
||||
}
|
||||
|
||||
auto screen_virtual_height() const -> float {
|
||||
auto screen_virtual_height() const {
|
||||
assert(InGraphicsContext_());
|
||||
return res_y_virtual_;
|
||||
}
|
||||
@ -244,45 +241,69 @@ class GraphicsServer {
|
||||
return tv_border_;
|
||||
}
|
||||
|
||||
auto graphics_quality_set() const { return graphics_quality_set_; }
|
||||
// auto graphics_quality_set() const {
|
||||
// return graphics_quality_ != GraphicsQuality::kUnset;
|
||||
// }
|
||||
|
||||
auto texture_quality_set() const { return texture_quality_set_; }
|
||||
// auto texture_quality_set() const {
|
||||
// return texture_quality_ != TextureQuality::kUnset;
|
||||
// }
|
||||
|
||||
auto SupportsTextureCompressionType(TextureCompressionType t) const -> bool {
|
||||
assert(InGraphicsContext_());
|
||||
assert(texture_compression_types_set_);
|
||||
return ((texture_compression_types_ & (0x01u << static_cast<uint32_t>(t)))
|
||||
!= 0u);
|
||||
}
|
||||
|
||||
void SetTextureCompressionTypes(
|
||||
const std::list<TextureCompressionType>& types);
|
||||
|
||||
auto texture_compression_types_are_set() const {
|
||||
return texture_compression_types_set_;
|
||||
}
|
||||
// auto texture_compression_types_are_set() const {
|
||||
// return texture_compression_types_set_;
|
||||
// }
|
||||
|
||||
void set_renderer_context_lost(bool lost) { renderer_context_lost_ = lost; }
|
||||
|
||||
auto renderer_context_lost() const { return renderer_context_lost_; }
|
||||
|
||||
auto graphics_quality_requested() const {
|
||||
assert(InGraphicsContext_());
|
||||
return graphics_quality_requested_;
|
||||
}
|
||||
|
||||
void set_graphics_quality_requested(GraphicsQualityRequest val) {
|
||||
assert(InGraphicsContext_());
|
||||
graphics_quality_requested_ = val;
|
||||
}
|
||||
|
||||
void set_texture_quality_requested(TextureQualityRequest val) {
|
||||
assert(InGraphicsContext_());
|
||||
texture_quality_requested_ = val;
|
||||
}
|
||||
|
||||
auto graphics_quality() const { return graphics_quality_; }
|
||||
auto graphics_quality() const {
|
||||
assert(InGraphicsContext_());
|
||||
return graphics_quality_;
|
||||
}
|
||||
|
||||
auto texture_quality_requested() const { return texture_quality_requested_; }
|
||||
auto texture_quality_requested() const {
|
||||
assert(InGraphicsContext_());
|
||||
return texture_quality_requested_;
|
||||
}
|
||||
|
||||
void HandlePushAndroidRes(const std::string& android_res);
|
||||
|
||||
auto texture_compression_types() const {
|
||||
assert(texture_compression_types_set_);
|
||||
return texture_compression_types_;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Pass a freshly allocated GraphicsContext instance, which the graphics
|
||||
/// system will take ownership of.
|
||||
void set_client_context(GraphicsClientContext* context);
|
||||
|
||||
// So we don't have to include app_adapter.h here for asserts.
|
||||
auto InGraphicsContext_() const -> bool;
|
||||
|
||||
@ -293,8 +314,8 @@ class GraphicsServer {
|
||||
auto WaitForRenderFrameDef_() -> FrameDef*;
|
||||
|
||||
// Update virtual screen dimensions based on the current physical ones.
|
||||
static void CalcVirtualRes_(float* x, float* y);
|
||||
void UpdateVirtualScreenRes_();
|
||||
// static void CalcVirtualRes_(float* x, float* y);
|
||||
// void UpdateVirtualScreenRes_();
|
||||
void UpdateCamOrientMatrix_();
|
||||
void ReloadMedia_();
|
||||
void UpdateModelViewProjectionMatrix_() {
|
||||
@ -314,23 +335,17 @@ class GraphicsServer {
|
||||
}
|
||||
|
||||
bool renderer_loaded_ : 1 {};
|
||||
bool v_sync_ : 1 {};
|
||||
bool auto_vsync_ : 1 {};
|
||||
bool model_view_projection_matrix_dirty_ : 1 {true};
|
||||
bool model_world_matrix_dirty_ : 1 {true};
|
||||
bool graphics_quality_set_ : 1 {};
|
||||
bool texture_quality_set_ : 1 {};
|
||||
bool tv_border_ : 1 {};
|
||||
bool renderer_context_lost_ : 1 {};
|
||||
bool texture_compression_types_set_ : 1 {};
|
||||
bool cam_orient_matrix_dirty_ : 1 {true};
|
||||
TextureQualityRequest texture_quality_requested_{
|
||||
TextureQualityRequest::kUnset};
|
||||
TextureQuality texture_quality_{TextureQuality::kLow};
|
||||
GraphicsQualityRequest graphics_quality_requested_{
|
||||
GraphicsQualityRequest::kUnset};
|
||||
GraphicsQuality graphics_quality_{GraphicsQuality::kUnset};
|
||||
int render_hold_{};
|
||||
Snapshot<GraphicsClientContext>* client_context_{};
|
||||
TextureQualityRequest texture_quality_requested_{};
|
||||
TextureQuality texture_quality_{};
|
||||
GraphicsQualityRequest graphics_quality_requested_{};
|
||||
GraphicsQuality graphics_quality_{};
|
||||
float res_x_{};
|
||||
float res_y_{};
|
||||
float res_x_virtual_{};
|
||||
@ -340,20 +355,21 @@ class GraphicsServer {
|
||||
Matrix44f projection_matrix_{kMatrix44fIdentity};
|
||||
Matrix44f model_view_projection_matrix_{kMatrix44fIdentity};
|
||||
Matrix44f model_world_matrix_{kMatrix44fIdentity};
|
||||
std::vector<Matrix44f> model_view_stack_;
|
||||
uint32_t texture_compression_types_{};
|
||||
uint32_t projection_matrix_state_{1};
|
||||
uint32_t model_view_projection_matrix_state_{1};
|
||||
uint32_t model_world_matrix_state_{1};
|
||||
uint32_t light_shadow_projection_matrix_state_{1};
|
||||
uint32_t cam_pos_state_{1};
|
||||
uint32_t cam_orient_matrix_state_{1};
|
||||
int render_hold_{};
|
||||
int projection_matrix_state_{};
|
||||
int model_view_projection_matrix_state_{};
|
||||
int model_world_matrix_state_{};
|
||||
int light_shadow_projection_matrix_state_{};
|
||||
int cam_pos_state_{};
|
||||
int cam_orient_matrix_state_{};
|
||||
int settings_index_{-1};
|
||||
Vector3f cam_pos_{0.0f, 0.0f, 0.0f};
|
||||
Vector3f cam_target_{0.0f, 0.0f, 0.0f};
|
||||
Matrix44f light_shadow_projection_matrix_{kMatrix44fIdentity};
|
||||
Matrix44f cam_orient_matrix_ = kMatrix44fIdentity;
|
||||
std::vector<Matrix44f> model_view_stack_;
|
||||
std::list<MeshData*> mesh_datas_;
|
||||
Timer* render_timer_{};
|
||||
Renderer* renderer_{};
|
||||
FrameDef* frame_def_{};
|
||||
std::mutex frame_def_mutex_{};
|
||||
|
||||
@ -487,7 +487,7 @@ void RenderPass::SetFrustum(float near_val, float far_val) {
|
||||
g_base->graphics_server->SetProjectionMatrix(projection_matrix_);
|
||||
}
|
||||
|
||||
void RenderPass::Finalize() {
|
||||
void RenderPass::Complete() {
|
||||
if (UsesWorldLists()) {
|
||||
for (auto& command : commands_) {
|
||||
command->Finalize();
|
||||
|
||||
@ -112,7 +112,7 @@ class RenderPass {
|
||||
return model_view_projection_matrix_;
|
||||
}
|
||||
auto HasDrawCommands() const -> bool;
|
||||
void Finalize();
|
||||
void Complete();
|
||||
void Reset();
|
||||
|
||||
// Whether this pass draws stuff from the per-shader command lists
|
||||
|
||||
@ -35,10 +35,12 @@ void Renderer::PreprocessFrameDef(FrameDef* frame_def) {
|
||||
|
||||
// If this frame_def was made in a different quality mode than we're
|
||||
// currently in, don't attempt to render it.
|
||||
if (frame_def->quality() != g_base->graphics_server->quality()) {
|
||||
frame_def->set_rendering(false);
|
||||
return;
|
||||
}
|
||||
// UPDATE - scratch that; we now set our quality FROM the frame def.
|
||||
// if (frame_def->quality() != g_base->graphics_server->quality()) {
|
||||
// frame_def->set_rendering(false);
|
||||
// return;
|
||||
// }
|
||||
|
||||
frame_def->set_rendering(true);
|
||||
|
||||
// Some VR environments muck with render states before/after
|
||||
|
||||
@ -82,7 +82,6 @@ class Renderer {
|
||||
auto light_pitch() const -> float { return light_pitch_; }
|
||||
auto light_heading() const -> float { return light_heading_; }
|
||||
void set_pixel_scale(float s) { pixel_scale_requested_ = s; }
|
||||
// void set_screen_gamma(float val) { screen_gamma_requested_ = val; }
|
||||
void set_debug_draw_mode(bool debugModeIn) { debug_draw_mode_ = debugModeIn; }
|
||||
auto debug_draw_mode() -> bool { return debug_draw_mode_; }
|
||||
|
||||
@ -269,7 +268,6 @@ class Renderer {
|
||||
Vector3f vignette_outer_{0.0f, 0.0f, 0.0f};
|
||||
Vector3f vignette_inner_{1.0f, 1.0f, 1.0f};
|
||||
int shadow_res_{-1};
|
||||
// float screen_gamma_requested_{1.0f};
|
||||
float screen_gamma_{1.0f};
|
||||
float pixel_scale_requested_{1.0f};
|
||||
float pixel_scale_{1.0f};
|
||||
|
||||
@ -1013,7 +1013,7 @@ void Camera::ApplyToFrameDef(FrameDef* frame_def) {
|
||||
up_, 4, 1000.0f,
|
||||
-1.0f, // Auto x fov.
|
||||
final_fov_y
|
||||
* (g_base->graphics->tv_border() ? (1.0f + kTVBorder) : 1.0f),
|
||||
* (frame_def->settings()->tv_border ? (1.0f + kTVBorder) : 1.0f),
|
||||
false, 0, 0, 0, 0, // Not using tangent fovs.
|
||||
area_of_interest_points_);
|
||||
}
|
||||
|
||||
@ -49,6 +49,13 @@ auto FrameDef::GetOverlayFlatPass() -> RenderPass* {
|
||||
|
||||
void FrameDef::Reset() {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// Update & grab the current settings.
|
||||
settings_snapshot_ = g_base->graphics->GetGraphicsSettingsSnapshot();
|
||||
|
||||
auto* settings = settings_snapshot_->Get();
|
||||
auto* client_context = g_base->graphics->client_context();
|
||||
|
||||
app_time_microsecs_ = 0;
|
||||
display_time_microsecs_ = 0;
|
||||
display_time_elapsed_microsecs_ = 0;
|
||||
@ -68,11 +75,17 @@ void FrameDef::Reset() {
|
||||
mesh_index_sizes_.clear();
|
||||
mesh_buffers_.clear();
|
||||
|
||||
quality_ = g_base->graphics_server->quality();
|
||||
quality_ = Graphics::GraphicsQualityFromRequest(
|
||||
settings->graphics_quality, client_context->auto_graphics_quality);
|
||||
|
||||
assert(g_base->graphics->has_supports_high_quality_graphics_value());
|
||||
texture_quality_ = Graphics::TextureQualityFromRequest(
|
||||
settings->texture_quality, client_context->auto_texture_quality);
|
||||
|
||||
// pixel_scale_ = g_base->graphics->settings()->pixel_scale;
|
||||
|
||||
// assert(g_base->graphics->has_supports_high_quality_graphics_value());
|
||||
orbiting_ = (g_base->graphics->camera()->mode() == CameraMode::kOrbit);
|
||||
tv_border_ = g_base->graphics->tv_border();
|
||||
// tv_border_ = g_base->graphics->tv_border();
|
||||
|
||||
shadow_offset_ = g_base->graphics->shadow_offset();
|
||||
shadow_scale_ = g_base->graphics->shadow_scale();
|
||||
@ -99,21 +112,21 @@ void FrameDef::Reset() {
|
||||
beauty_pass_->set_floor_reflection(g_base->graphics->floor_reflection());
|
||||
}
|
||||
|
||||
void FrameDef::Finalize() {
|
||||
void FrameDef::Complete() {
|
||||
assert(!defining_component_);
|
||||
light_pass_->Finalize();
|
||||
light_shadow_pass_->Finalize();
|
||||
beauty_pass_->Finalize();
|
||||
beauty_pass_bg_->Finalize();
|
||||
overlay_pass_->Finalize();
|
||||
overlay_front_pass_->Finalize();
|
||||
light_pass_->Complete();
|
||||
light_shadow_pass_->Complete();
|
||||
beauty_pass_->Complete();
|
||||
beauty_pass_bg_->Complete();
|
||||
overlay_pass_->Complete();
|
||||
overlay_front_pass_->Complete();
|
||||
if (g_core->IsVRMode()) {
|
||||
overlay_fixed_pass_->Finalize();
|
||||
overlay_flat_pass_->Finalize();
|
||||
vr_cover_pass_->Finalize();
|
||||
overlay_fixed_pass_->Complete();
|
||||
overlay_flat_pass_->Complete();
|
||||
vr_cover_pass_->Complete();
|
||||
}
|
||||
overlay_3d_pass_->Finalize();
|
||||
blit_pass_->Finalize();
|
||||
overlay_3d_pass_->Complete();
|
||||
blit_pass_->Complete();
|
||||
}
|
||||
|
||||
void FrameDef::AddMesh(Mesh* mesh) {
|
||||
|
||||
@ -7,13 +7,14 @@
|
||||
#include <vector>
|
||||
|
||||
#include "ballistica/base/assets/asset.h"
|
||||
#include "ballistica/shared/generic/snapshot.h"
|
||||
#include "ballistica/shared/math/matrix44f.h"
|
||||
#include "ballistica/shared/math/vector2f.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
/// A flattened representation of a frame; generated by the logic thread and
|
||||
/// sent to the graphics thread to render.
|
||||
/// sent to the graphics server to render.
|
||||
class FrameDef {
|
||||
public:
|
||||
auto light_pass() -> RenderPass* { return light_pass_.get(); }
|
||||
@ -49,15 +50,15 @@ class FrameDef {
|
||||
|
||||
// A number incremented for each frame renderered. Note that graphics code
|
||||
// should not plug this directly into things like flash calculations since
|
||||
// frame-rates will vary a lot these days. A 30hz flash will look a lot
|
||||
// frame-rates vary a lot these days. A 30hz flash will look a lot
|
||||
// different than a 240hz flash. Use frame_number_filtered() for such
|
||||
// purposes.
|
||||
auto frame_number() const { return frame_number_; }
|
||||
|
||||
// A number incremented for each frame rendered, but a maximum of 60 times
|
||||
// per second. Code for drawing flashes or other exact effects should use
|
||||
// this value instead of regular frame_number so that things don't turn
|
||||
// muddy at extremely high frame rates.
|
||||
// per second. Code for drawing flashes or other crisp blink-y effects
|
||||
// should use this value instead of regular frame_number so that things
|
||||
// don't turn muddy at extremely high frame rates.
|
||||
auto frame_number_filtered() const { return frame_number_filtered_; }
|
||||
|
||||
// Returns the display-time this frame-def was created at (tries to match
|
||||
@ -66,14 +67,19 @@ class FrameDef {
|
||||
auto display_time_millisecs() const -> millisecs_t {
|
||||
return display_time_microsecs_ / 1000;
|
||||
}
|
||||
|
||||
auto display_time_microsecs() const -> microsecs_t {
|
||||
return display_time_microsecs_;
|
||||
}
|
||||
auto display_time() const -> double {
|
||||
return static_cast<double>(display_time_microsecs_) / 1000000.0;
|
||||
|
||||
auto display_time() const -> seconds_t {
|
||||
return static_cast<seconds_t>(display_time_microsecs_) / 1000000.0;
|
||||
}
|
||||
|
||||
auto display_time_elapsed() const -> seconds_t {
|
||||
return static_cast<seconds_t>(display_time_elapsed_microsecs_) / 1000000.0;
|
||||
}
|
||||
|
||||
// How much display time does this frame-def represent.
|
||||
auto display_time_elapsed_millisecs() const -> millisecs_t {
|
||||
return display_time_elapsed_millisecs_;
|
||||
}
|
||||
@ -82,7 +88,9 @@ class FrameDef {
|
||||
return display_time_elapsed_microsecs_;
|
||||
}
|
||||
|
||||
auto quality() const -> GraphicsQuality { return quality_; }
|
||||
auto quality() const { return quality_; }
|
||||
auto texture_quality() const { return texture_quality_; }
|
||||
|
||||
auto orbiting() const -> bool { return orbiting_; }
|
||||
auto shadow_offset() const -> const Vector3f& { return shadow_offset_; }
|
||||
auto shadow_scale() const -> const Vector2f& { return shadow_scale_; }
|
||||
@ -115,11 +123,12 @@ class FrameDef {
|
||||
vr_overlay_screen_matrix_fixed_ = mat;
|
||||
}
|
||||
|
||||
// Effects requiring availability of a depth texture should
|
||||
// check this to determine whether they should draw.
|
||||
auto has_depth_texture() const -> bool {
|
||||
// Effects requiring availability of a depth texture should check this to
|
||||
// determine whether they should draw.
|
||||
auto HasDepthTexture() const -> bool {
|
||||
return (quality_ >= GraphicsQuality::kHigh);
|
||||
}
|
||||
|
||||
void AddComponent(const Object::Ref<Asset>& component) {
|
||||
// Add a reference to this component only if we havn't yet.
|
||||
if (component->last_frame_def_num() != frame_number_) {
|
||||
@ -134,7 +143,7 @@ class FrameDef {
|
||||
FrameDef();
|
||||
~FrameDef();
|
||||
void Reset();
|
||||
void Finalize();
|
||||
void Complete();
|
||||
|
||||
void set_display_time_elapsed_microsecs(microsecs_t val) {
|
||||
display_time_elapsed_microsecs_ = val;
|
||||
@ -187,7 +196,7 @@ class FrameDef {
|
||||
auto media_components() const -> const std::vector<Object::Ref<Asset>>& {
|
||||
return media_components_;
|
||||
}
|
||||
auto tv_border() const { return tv_border_; }
|
||||
// auto tv_border() const { return tv_border_; }
|
||||
|
||||
void set_camera_mode(CameraMode val) { camera_mode_ = val; }
|
||||
void set_rendering(bool val) { rendering_ = val; }
|
||||
@ -204,18 +213,27 @@ class FrameDef {
|
||||
}
|
||||
#endif
|
||||
|
||||
// auto pixel_scale() const { return pixel_scale_; }
|
||||
|
||||
auto* settings() const {
|
||||
assert(settings_snapshot_.Exists());
|
||||
return settings_snapshot_->Get();
|
||||
}
|
||||
|
||||
private:
|
||||
bool needs_clear_{};
|
||||
bool rendering_{};
|
||||
bool orbiting_{};
|
||||
bool tv_border_{};
|
||||
bool shadow_ortho_{};
|
||||
Object::Ref<Snapshot<GraphicsSettings>> settings_snapshot_;
|
||||
bool needs_clear_ : 1 {};
|
||||
bool rendering_ : 1 {};
|
||||
bool orbiting_ : 1 {};
|
||||
// bool tv_border_ : 1 {};
|
||||
bool shadow_ortho_ : 1 {};
|
||||
BenchmarkType benchmark_type_{BenchmarkType::kNone};
|
||||
CameraMode camera_mode_{CameraMode::kFollow};
|
||||
Vector3f cam_original_{0.0f, 0.0f, 0.0f};
|
||||
Vector3f cam_target_original_{0.0f, 0.0f, 0.0f};
|
||||
Vector3f shake_original_{0.0f, 0.0f, 0.0f};
|
||||
float vr_near_clip_{};
|
||||
// float pixel_scale_{};
|
||||
Matrix44f vr_overlay_screen_matrix_ = kMatrix44fIdentity;
|
||||
Matrix44f vr_overlay_screen_matrix_fixed_ = kMatrix44fIdentity;
|
||||
std::vector<MeshData*> mesh_data_creates_;
|
||||
@ -245,7 +263,8 @@ class FrameDef {
|
||||
std::unique_ptr<RenderPass> vr_cover_pass_;
|
||||
std::unique_ptr<RenderPass> overlay_3d_pass_;
|
||||
std::unique_ptr<RenderPass> blit_pass_;
|
||||
GraphicsQuality quality_{GraphicsQuality::kLow};
|
||||
GraphicsQuality quality_{};
|
||||
TextureQuality texture_quality_{};
|
||||
microsecs_t app_time_microsecs_{};
|
||||
microsecs_t display_time_microsecs_{};
|
||||
microsecs_t display_time_elapsed_microsecs_{};
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#include "ballistica/base/graphics/support/graphics_client_context.h"
|
||||
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
#include "ballistica/base/graphics/renderer/renderer.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
GraphicsClientContext::GraphicsClientContext()
|
||||
: auto_graphics_quality{g_base->graphics_server->renderer()
|
||||
->GetAutoGraphicsQuality()},
|
||||
auto_texture_quality{
|
||||
g_base->graphics_server->renderer()->GetAutoTextureQuality()},
|
||||
texture_compression_types{
|
||||
g_base->graphics_server->texture_compression_types()} {}
|
||||
|
||||
GraphicsClientContext::GraphicsClientContext(int dummy)
|
||||
: auto_graphics_quality{GraphicsQuality::kLow},
|
||||
auto_texture_quality{TextureQuality::kLow},
|
||||
texture_compression_types{0} {}
|
||||
|
||||
} // namespace ballistica::base
|
||||
@ -0,0 +1,31 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_SUPPORT_GRAPHICS_CLIENT_CONTEXT_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_SUPPORT_GRAPHICS_CLIENT_CONTEXT_H_
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
/// Represents a valid graphics setup delivered by the graphics server to
|
||||
/// the logic thread. It contains various info about concrete graphics
|
||||
/// settings and capabilities.
|
||||
struct GraphicsClientContext {
|
||||
GraphicsClientContext();
|
||||
|
||||
/// Special constructor to create a dummy context (used by headless builds).
|
||||
explicit GraphicsClientContext(int dummy);
|
||||
|
||||
auto SupportsTextureCompressionType(TextureCompressionType t) const -> bool {
|
||||
return ((texture_compression_types & (0x01u << static_cast<uint32_t>(t)))
|
||||
!= 0u);
|
||||
}
|
||||
|
||||
GraphicsQuality auto_graphics_quality;
|
||||
TextureQuality auto_texture_quality;
|
||||
uint32_t texture_compression_types;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_SUPPORT_GRAPHICS_CLIENT_CONTEXT_H_
|
||||
27
src/ballistica/base/graphics/support/graphics_settings.cc
Normal file
27
src/ballistica/base/graphics/support/graphics_settings.cc
Normal file
@ -0,0 +1,27 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#include "ballistica/base/graphics/support/graphics_settings.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "ballistica/base/graphics/graphics.h"
|
||||
#include "ballistica/base/support/app_config.h"
|
||||
#include "ballistica/shared/foundation/object.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
GraphicsSettings::GraphicsSettings()
|
||||
|
||||
: resolution{g_base->graphics->screen_pixel_width(),
|
||||
g_base->graphics->screen_pixel_height()},
|
||||
resolution_virtual{g_base->graphics->screen_virtual_width(),
|
||||
g_base->graphics->screen_virtual_height()},
|
||||
pixel_scale{std::clamp(
|
||||
g_base->app_config->Resolve(AppConfig::FloatID::kScreenPixelScale),
|
||||
0.1f, 1.0f)},
|
||||
graphics_quality{g_base->graphics->GraphicsQualityFromAppConfig()},
|
||||
texture_quality{g_base->graphics->TextureQualityFromAppConfig()},
|
||||
tv_border{
|
||||
g_base->app_config->Resolve(AppConfig::BoolID::kEnableTVBorder)} {}
|
||||
|
||||
} // namespace ballistica::base
|
||||
33
src/ballistica/base/graphics/support/graphics_settings.h
Normal file
33
src/ballistica/base/graphics/support/graphics_settings.h
Normal file
@ -0,0 +1,33 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_GRAPHICS_SUPPORT_GRAPHICS_SETTINGS_H_
|
||||
#define BALLISTICA_BASE_GRAPHICS_SUPPORT_GRAPHICS_SETTINGS_H_
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
#include "ballistica/shared/math/vector2f.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
/// A set of settings for graphics, covering things like screen
|
||||
/// resolution, texture quality, etc. These are filled out by the
|
||||
/// AppAdapter in the logic thread and passed up to the GraphicsServer
|
||||
/// either through standalone calls or attached to a FrameDef. Generally
|
||||
/// AppAdapters define their own subclass of this containing additional
|
||||
/// settings specific to themselves or the renderer(s) they use.
|
||||
struct GraphicsSettings {
|
||||
GraphicsSettings();
|
||||
// Each new settings instance will be assigned a unique incrementing index.
|
||||
int index{-1};
|
||||
|
||||
// Some standard settings used by most renderers.
|
||||
Vector2f resolution;
|
||||
Vector2f resolution_virtual;
|
||||
float pixel_scale;
|
||||
GraphicsQualityRequest graphics_quality;
|
||||
TextureQualityRequest texture_quality;
|
||||
bool tv_border;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BALLISTICA_BASE_GRAPHICS_SUPPORT_GRAPHICS_SETTINGS_H_
|
||||
@ -159,16 +159,16 @@ void Input::AnnounceConnects_() {
|
||||
|
||||
// For the first announcement just say "X controllers detected" and don't
|
||||
// have a sound.
|
||||
if (first_print && g_core->GetAppTimeMillisecs() < 10000) {
|
||||
if (first_print && g_core->GetAppTimeSeconds() < 5.0) {
|
||||
first_print = false;
|
||||
|
||||
// Disabling this completely for now; being more lenient with devices
|
||||
// allowed on Android means this will often come back with large
|
||||
// numbers.
|
||||
bool do_print{false};
|
||||
// Disabling this completely on Android for now; we often get large
|
||||
// numbers of devices there that aren't actually devices.
|
||||
|
||||
bool do_print_initial_counts{!g_buildconfig.ostype_android()};
|
||||
|
||||
// If there's been several connected, just give a number.
|
||||
if (explicit_bool(do_print)) {
|
||||
if (explicit_bool(do_print_initial_counts)) {
|
||||
if (newly_connected_controllers_.size() > 1) {
|
||||
std::string s =
|
||||
g_base->assets->GetResourceString("controllersDetectedText");
|
||||
|
||||
@ -76,11 +76,11 @@ void Logic::OnAppStart() {
|
||||
|
||||
void Logic::OnGraphicsReady() {
|
||||
assert(g_base->InLogicThread());
|
||||
if (on_initial_screen_creation_complete_called_) {
|
||||
if (graphics_ready_) {
|
||||
// Only want to fire this logic the first time.
|
||||
return;
|
||||
}
|
||||
on_initial_screen_creation_complete_called_ = true;
|
||||
graphics_ready_ = true;
|
||||
|
||||
// Ok; graphics-server is telling us we've got a screen (or no screen in
|
||||
// the case of headless-mode). We use this as a cue to kick off our
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#define BALLISTICA_BASE_LOGIC_LOGIC_H_
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "ballistica/shared/foundation/object.h"
|
||||
@ -118,6 +117,8 @@ class Logic {
|
||||
auto shutting_down() const { return shutting_down_; }
|
||||
auto shutdown_completed() const { return shutdown_completed_; }
|
||||
|
||||
auto graphics_ready() const { return graphics_ready_; }
|
||||
|
||||
private:
|
||||
void UpdateDisplayTimeForFrameDraw_();
|
||||
void UpdateDisplayTimeForHeadlessMode_();
|
||||
@ -127,31 +128,31 @@ class Logic {
|
||||
void UpdatePendingWorkTimer_();
|
||||
void StepDisplayTime_();
|
||||
|
||||
double display_time_{};
|
||||
double display_time_increment_{1.0 / 60.0};
|
||||
seconds_t display_time_{};
|
||||
seconds_t display_time_increment_{1.0 / 60.0};
|
||||
microsecs_t display_time_microsecs_{};
|
||||
microsecs_t display_time_increment_microsecs_{1000000 / 60};
|
||||
|
||||
// GUI scheduling.
|
||||
double last_display_time_update_app_time_{-1.0};
|
||||
double recent_display_time_increments_[kDisplayTimeSampleCount]{};
|
||||
int recent_display_time_increments_index_{-1};
|
||||
|
||||
// Headless scheduling.
|
||||
Timer* headless_display_time_step_timer_{};
|
||||
|
||||
Timer* process_pending_work_timer_{};
|
||||
Timer* asset_prune_timer_{};
|
||||
Timer* debug_timer_{};
|
||||
EventLoop* event_loop_{};
|
||||
std::unique_ptr<TimerList> display_timers_;
|
||||
// GUI scheduling.
|
||||
seconds_t last_display_time_update_app_time_{-1.0};
|
||||
seconds_t recent_display_time_increments_[kDisplayTimeSampleCount]{};
|
||||
int recent_display_time_increments_index_{-1};
|
||||
|
||||
bool app_bootstrapping_complete_ : 1 {};
|
||||
bool have_pending_loads_ : 1 {};
|
||||
bool debug_log_display_time_ : 1 {};
|
||||
bool applied_app_config_ : 1 {};
|
||||
bool shutting_down_ : 1 {};
|
||||
bool shutdown_completed_ : 1 {};
|
||||
bool on_initial_screen_creation_complete_called_ : 1 {};
|
||||
bool graphics_ready_ : 1 {};
|
||||
Timer* process_pending_work_timer_{};
|
||||
Timer* asset_prune_timer_{};
|
||||
Timer* debug_timer_{};
|
||||
EventLoop* event_loop_{};
|
||||
std::unique_ptr<TimerList> display_timers_;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "ballistica/base/platform/apple/base_platform_apple.h"
|
||||
|
||||
#if BA_XCODE_BUILD
|
||||
#include <BallisticaKit-Swift.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <uuid/uuid.h>
|
||||
@ -53,9 +54,14 @@ void BasePlatformApple::PurchaseAck(const std::string& purchase,
|
||||
|
||||
void BasePlatformApple::DoOpenURL(const std::string& url) {
|
||||
#if BA_XCODE_BUILD
|
||||
#if BA_OSTYPE_MACOS
|
||||
BallisticaKit::CocoaFromCppOpenURL(url);
|
||||
#else
|
||||
BallisticaKit::UIKitFromCppOpenURL(url);
|
||||
#endif
|
||||
// Go ahead and do this ourself. Though perhaps the default
|
||||
// Python path would be fine.
|
||||
AppleUtils::OpenURL(url.c_str());
|
||||
// AppleUtils::OpenURL(url.c_str());
|
||||
#else
|
||||
// Otherwise go with the default (Python webbrowser module).
|
||||
BasePlatform::DoOpenURL(url);
|
||||
|
||||
@ -810,9 +810,9 @@ static PyMethodDef PySetStressTestingDef = {
|
||||
"(internal)",
|
||||
};
|
||||
|
||||
// ------------------------------ display_log ----------------------------------
|
||||
// -------------------------------- emit_log -----------------------------------
|
||||
|
||||
static auto PyDisplayLog(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
static auto PyEmitLog(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
-> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
static const char* kwlist[] = {"name", "level", "message", nullptr};
|
||||
@ -839,25 +839,25 @@ static auto PyDisplayLog(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
level = LogLevel::kCritical;
|
||||
} else {
|
||||
// Assume we should avoid Log() calls here since it could infinite loop.
|
||||
fprintf(stderr, "Invalid log level to display_log(): %s\n", levelstr);
|
||||
fprintf(stderr, "Invalid log level to emit_log(): %s\n", levelstr);
|
||||
level = LogLevel::kInfo;
|
||||
}
|
||||
Logging::DisplayLog(name, level, message);
|
||||
Logging::EmitLog(name, level, message);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
static PyMethodDef PyDisplayLogDef = {
|
||||
"display_log", // name
|
||||
(PyCFunction)PyDisplayLog, // method
|
||||
static PyMethodDef PyEmitLogDef = {
|
||||
"emit_log", // name
|
||||
(PyCFunction)PyEmitLog, // method
|
||||
METH_VARARGS | METH_KEYWORDS, // flags
|
||||
|
||||
"display_log(name: str, level: str, message: str) -> None\n"
|
||||
"emit_log(name: str, level: str, message: str) -> None\n"
|
||||
"\n"
|
||||
"(internal)\n"
|
||||
"\n"
|
||||
"Sends a log message to the in-game console and any per-platform\n"
|
||||
"Sends a log message to the in-app console and any per-platform\n"
|
||||
"log destinations (Android log, etc.). This generally is not called\n"
|
||||
"directly and should instead be fed Python logging output.",
|
||||
};
|
||||
@ -1654,7 +1654,7 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
|
||||
PyAppNameUpperDef,
|
||||
PyIsXCodeBuildDef,
|
||||
PyCanDisplayFullUnicodeDef,
|
||||
PyDisplayLogDef,
|
||||
PyEmitLogDef,
|
||||
PyV1CloudLogDef,
|
||||
PySetStressTestingDef,
|
||||
PyEnvDef,
|
||||
|
||||
@ -348,13 +348,14 @@ static PyMethodDef PySafeColorDef = {
|
||||
|
||||
static auto PyGetMaxGraphicsQuality(PyObject* self) -> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
if (g_base->graphics
|
||||
&& g_base->graphics->has_supports_high_quality_graphics_value()
|
||||
&& g_base->graphics->supports_high_quality_graphics()) {
|
||||
return Py_BuildValue("s", "High");
|
||||
} else {
|
||||
return Py_BuildValue("s", "Medium");
|
||||
}
|
||||
// if (g_base->graphics
|
||||
// && g_base->graphics->has_supports_high_quality_graphics_value()
|
||||
// && g_base->graphics->supports_high_quality_graphics()) {
|
||||
// return Py_BuildValue("s", "High");
|
||||
// } else {
|
||||
// return Py_BuildValue("s", "Medium");
|
||||
// }
|
||||
return Py_BuildValue("s", "Higher");
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
|
||||
@ -147,17 +147,17 @@ auto CorePlatformApple::IsRunningOnDesktop() -> bool {
|
||||
#endif
|
||||
}
|
||||
|
||||
void CorePlatformApple::DisplayLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg) {
|
||||
void CorePlatformApple::EmitPlatformLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg) {
|
||||
#if BA_XCODE_BUILD && !BA_HEADLESS_BUILD
|
||||
|
||||
// HMM: do we want to use proper logging APIs here or simple printing?
|
||||
// base::AppleUtils::NSLogStr(msg);
|
||||
CorePlatform::DisplayLog(name, level, msg);
|
||||
CorePlatform::EmitPlatformLog(name, level, msg);
|
||||
#else
|
||||
|
||||
// Fall back to default handler...
|
||||
CorePlatform::DisplayLog(name, level, msg);
|
||||
CorePlatform::EmitPlatformLog(name, level, msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -26,8 +26,8 @@ class CorePlatformApple : public CorePlatform {
|
||||
auto DoHasTouchScreen() -> bool override;
|
||||
auto GetDefaultUIScale() -> UIScale override;
|
||||
auto IsRunningOnDesktop() -> bool override;
|
||||
void DisplayLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg) override;
|
||||
void EmitPlatformLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg) override;
|
||||
void GetTextBoundsAndWidth(const std::string& text, Rect* r,
|
||||
float* width) override;
|
||||
void FreeTextTexture(void* tex) override;
|
||||
|
||||
@ -465,12 +465,17 @@ auto CorePlatform::IsRunningOnDesktop() -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
void CorePlatform::SleepMillisecs(millisecs_t ms) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
void CorePlatform::SleepSeconds(seconds_t duration) {
|
||||
std::this_thread::sleep_for(
|
||||
std::chrono::microseconds(static_cast<microsecs_t>(duration * 1000000)));
|
||||
}
|
||||
|
||||
void CorePlatform::SleepMicrosecs(millisecs_t ms) {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(ms));
|
||||
void CorePlatform::SleepMillisecs(millisecs_t duration) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(duration));
|
||||
}
|
||||
|
||||
void CorePlatform::SleepMicrosecs(millisecs_t duration) {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(duration));
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
@ -481,8 +486,8 @@ auto CorePlatform::GetDefaultUIScale() -> UIScale {
|
||||
return UIScale::kLarge;
|
||||
}
|
||||
|
||||
void CorePlatform::DisplayLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg) {
|
||||
void CorePlatform::EmitPlatformLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg) {
|
||||
// Do nothing by default.
|
||||
}
|
||||
|
||||
|
||||
@ -99,8 +99,8 @@ class CorePlatform {
|
||||
/// Display a message to any default log for the platform (android log,
|
||||
/// etc.) Note that this can be called from any thread. Default
|
||||
/// implementation does nothing.
|
||||
virtual void DisplayLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg);
|
||||
virtual void EmitPlatformLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg);
|
||||
|
||||
#pragma mark ENVIRONMENT -------------------------------------------------------
|
||||
|
||||
@ -381,9 +381,9 @@ class CorePlatform {
|
||||
/// to not go backwards.
|
||||
static auto GetCurrentWholeSeconds() -> int64_t;
|
||||
|
||||
static void SleepMillisecs(millisecs_t ms);
|
||||
|
||||
static void SleepMicrosecs(microsecs_t ms);
|
||||
static void SleepSeconds(seconds_t duration);
|
||||
static void SleepMillisecs(millisecs_t duration);
|
||||
static void SleepMicrosecs(microsecs_t duration);
|
||||
|
||||
/// Given a C++ symbol, attempt to return a pretty one.
|
||||
virtual auto DemangleCXXSymbol(const std::string& s) -> std::string;
|
||||
|
||||
@ -827,11 +827,12 @@ std::string CorePlatformWindows::DoGetDeviceName() {
|
||||
|
||||
bool CorePlatformWindows::DoHasTouchScreen() { return false; }
|
||||
|
||||
void CorePlatformWindows::DisplayLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg) {
|
||||
void CorePlatformWindows::EmitPlatformLog(const std::string& name,
|
||||
LogLevel level,
|
||||
const std::string& msg) {
|
||||
// if (have_stdin_stdout_) {
|
||||
// // On headless builds we use default handler (simple stdout).
|
||||
// return CorePlatform::DisplayLog(msg);
|
||||
// return CorePlatform::EmitPlatformLog(msg);
|
||||
// }
|
||||
|
||||
// Also spit this out as a debug-string for when running from msvc.
|
||||
|
||||
@ -41,8 +41,8 @@ class CorePlatformWindows : public CorePlatform {
|
||||
auto GetLocale() -> std::string override;
|
||||
auto DoGetDeviceName() -> std::string override;
|
||||
auto DoHasTouchScreen() -> bool override;
|
||||
void DisplayLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg) override;
|
||||
void EmitPlatformLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg) override;
|
||||
void SetEnv(const std::string& name, const std::string& value) override;
|
||||
auto GetEnv(const std::string& name) -> std::optional<std::string> override;
|
||||
auto GetIsStdinATerminal() -> bool override;
|
||||
|
||||
@ -307,8 +307,8 @@ void CorePython::LoggingCall(LogLevel loglevel, const std::string& msg) {
|
||||
"CorePython::LoggingCall() called before Python"
|
||||
" logging available."};
|
||||
if (g_core->platform) {
|
||||
g_core->platform->DisplayLog("root", LogLevel::kError, errmsg);
|
||||
g_core->platform->DisplayLog("root", loglevel, msg);
|
||||
g_core->platform->EmitPlatformLog("root", LogLevel::kError, errmsg);
|
||||
g_core->platform->EmitPlatformLog("root", loglevel, msg);
|
||||
}
|
||||
fprintf(stderr, "%s\n%s\n", errmsg, msg.c_str());
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ class CorePython {
|
||||
|
||||
/// Calls Python logging function (logging.error, logging.warning, etc.)
|
||||
/// Can be called from any thread at any time. If called before Python
|
||||
/// logging is available, logs locally using Logging::DisplayLog()
|
||||
/// logging is available, logs locally using Logging::EmitPlatformLog()
|
||||
/// (with an added warning).
|
||||
void LoggingCall(LogLevel loglevel, const std::string& msg);
|
||||
void ImportPythonObjs();
|
||||
|
||||
@ -12,11 +12,12 @@
|
||||
|
||||
namespace ballistica::scene_v1 {
|
||||
|
||||
// Stores info about an occurring collision.
|
||||
// Note than just because a collision exists between two parts doesn't mean
|
||||
// they're physically colliding in the simulation. It is just a shortcut to
|
||||
// determine what behavior, if any, exists between two parts which are currently
|
||||
// overlapping in the simulation.
|
||||
/// Stores info about an occurring collision.
|
||||
///
|
||||
/// Note than just because a collision exists between two parts doesn't mean
|
||||
/// they're physically colliding in the simulation. It is just a shortcut to
|
||||
/// determine what behavior, if any, exists between two parts which are
|
||||
/// currently overlapping in the simulation.
|
||||
class Collision : public Object {
|
||||
public:
|
||||
explicit Collision(Scene* scene) : src_context(scene), dst_context(scene) {}
|
||||
|
||||
@ -66,77 +66,77 @@ void do_dBodyGetLocalFeedback(dBodyID b, dReal px, dReal py, dReal pz,
|
||||
|
||||
// Stores info about a collision needing a reset
|
||||
// (used when parts change materials).
|
||||
class Dynamics::CollisionReset {
|
||||
class Dynamics::CollisionReset_ {
|
||||
public:
|
||||
int node1;
|
||||
int node2;
|
||||
int part1;
|
||||
int part2;
|
||||
CollisionReset(int node1_in, int part1_in, int node2_in, int part2_in)
|
||||
CollisionReset_(int node1_in, int part1_in, int node2_in, int part2_in)
|
||||
: node1(node1_in), node2(node2_in), part1(part1_in), part2(part2_in) {}
|
||||
};
|
||||
|
||||
class Dynamics::CollisionEvent {
|
||||
class Dynamics::CollisionEvent_ {
|
||||
public:
|
||||
Object::Ref<MaterialAction> action;
|
||||
Object::Ref<Collision> collision;
|
||||
Object::WeakRef<Node> node1; // first event node
|
||||
Object::WeakRef<Node> node2; // second event node
|
||||
CollisionEvent(Node* node1_in, Node* node2_in,
|
||||
const Object::Ref<MaterialAction>& action_in,
|
||||
const Object::Ref<Collision>& collision_in)
|
||||
CollisionEvent_(Node* node1_in, Node* node2_in,
|
||||
const Object::Ref<MaterialAction>& action_in,
|
||||
const Object::Ref<Collision>& collision_in)
|
||||
: node1(node1_in),
|
||||
node2(node2_in),
|
||||
action(action_in),
|
||||
collision(collision_in) {}
|
||||
};
|
||||
|
||||
class Dynamics::SrcPartCollideMap {
|
||||
class Dynamics::SrcPartCollideMap_ {
|
||||
public:
|
||||
std::unordered_map<int, Object::Ref<Collision> > dst_part_collisions;
|
||||
};
|
||||
|
||||
class Dynamics::DstNodeCollideMap {
|
||||
class Dynamics::DstNodeCollideMap_ {
|
||||
public:
|
||||
std::unordered_map<int, SrcPartCollideMap> src_parts;
|
||||
std::unordered_map<int, SrcPartCollideMap_> src_parts;
|
||||
int collideDisabled;
|
||||
DstNodeCollideMap() : collideDisabled(0) {}
|
||||
~DstNodeCollideMap() = default;
|
||||
DstNodeCollideMap_() : collideDisabled(0) {}
|
||||
~DstNodeCollideMap_() = default;
|
||||
};
|
||||
|
||||
class Dynamics::SrcNodeCollideMap {
|
||||
class Dynamics::SrcNodeCollideMap_ {
|
||||
public:
|
||||
std::unordered_map<int64_t, DstNodeCollideMap> dst_nodes;
|
||||
std::unordered_map<int64_t, DstNodeCollideMap_> dst_nodes;
|
||||
};
|
||||
|
||||
class Dynamics::Impl {
|
||||
class Dynamics::Impl_ {
|
||||
public:
|
||||
explicit Impl(Dynamics* dynamics) : dynamics_(dynamics) {}
|
||||
explicit Impl_(Dynamics* dynamics) : dynamics_(dynamics) {}
|
||||
|
||||
// NOTE: we need to implement this here in an Impl class because
|
||||
// gcc currently chokes on unordered_maps with forward-declared types,
|
||||
// so we can't have this in our header without pushing all our map/collision
|
||||
// types there too.
|
||||
void HandleDisconnect(
|
||||
const std::unordered_map<int64_t, Dynamics::SrcNodeCollideMap>::iterator&
|
||||
const std::unordered_map<int64_t, Dynamics::SrcNodeCollideMap_>::iterator&
|
||||
i,
|
||||
const std::unordered_map<int64_t, Dynamics::DstNodeCollideMap>::iterator&
|
||||
const std::unordered_map<int64_t, Dynamics::DstNodeCollideMap_>::iterator&
|
||||
j,
|
||||
const std::unordered_map<int, SrcPartCollideMap>::iterator& k,
|
||||
const std::unordered_map<int, SrcPartCollideMap_>::iterator& k,
|
||||
const std::unordered_map<int, Object::Ref<Collision> >::iterator& l);
|
||||
|
||||
private:
|
||||
Dynamics* dynamics_{};
|
||||
// Contains in-progress collisions for current nodes.
|
||||
std::unordered_map<int64_t, SrcNodeCollideMap> node_collisions_;
|
||||
std::unordered_map<int64_t, SrcNodeCollideMap_> node_collisions_;
|
||||
friend class Dynamics;
|
||||
};
|
||||
|
||||
Dynamics::Dynamics(Scene* scene_in)
|
||||
: scene_(scene_in),
|
||||
collision_cache_(new base::CollisionCache()),
|
||||
impl_(std::make_unique<Impl>(this)) {
|
||||
ResetODE();
|
||||
impl_(std::make_unique<Impl_>(this)) {
|
||||
ResetODE_();
|
||||
}
|
||||
|
||||
Dynamics::~Dynamics() {
|
||||
@ -145,7 +145,7 @@ Dynamics::~Dynamics() {
|
||||
"Dynamics going down within Process() call;"
|
||||
" should not happen.");
|
||||
}
|
||||
ShutdownODE();
|
||||
ShutdownODE_();
|
||||
}
|
||||
|
||||
void Dynamics::Draw(base::FrameDef* frame_def) {
|
||||
@ -203,7 +203,7 @@ void Dynamics::RemoveTrimesh(dGeomID g) {
|
||||
throw Exception("trimesh not found");
|
||||
}
|
||||
|
||||
auto Dynamics::AreColliding(const Part& p1_in, const Part& p2_in) -> bool {
|
||||
auto Dynamics::AreColliding_(const Part& p1_in, const Part& p2_in) -> bool {
|
||||
const Part* p1;
|
||||
const Part* p2;
|
||||
if (IsInStoreOrder(p1_in.node()->id(), p1_in.id(), p2_in.node()->id(),
|
||||
@ -279,7 +279,7 @@ auto Dynamics::GetCollision(Part* p1_in, Part* p2_in, MaterialContext** cc1,
|
||||
p2->ApplyMaterials(*cc2, p2, p1);
|
||||
|
||||
// If either disabled collisions between these two nodes, store that.
|
||||
DstNodeCollideMap* dncm =
|
||||
DstNodeCollideMap_* dncm =
|
||||
&impl_->node_collisions_[p1->node()->id()].dst_nodes[p2->node()->id()];
|
||||
if (!(*cc1)->node_collide || !(*cc2)->node_collide) {
|
||||
dncm->collideDisabled = true;
|
||||
@ -319,10 +319,12 @@ auto Dynamics::GetCollision(Part* p1_in, Part* p2_in, MaterialContext** cc1,
|
||||
return &(*(i.first->second));
|
||||
}
|
||||
|
||||
void Dynamics::Impl::HandleDisconnect(
|
||||
const std::unordered_map<int64_t, Dynamics::SrcNodeCollideMap>::iterator& i,
|
||||
const std::unordered_map<int64_t, Dynamics::DstNodeCollideMap>::iterator& j,
|
||||
const std::unordered_map<int, SrcPartCollideMap>::iterator& k,
|
||||
void Dynamics::Impl_::HandleDisconnect(
|
||||
const std::unordered_map<int64_t, Dynamics::SrcNodeCollideMap_>::iterator&
|
||||
i,
|
||||
const std::unordered_map<int64_t, Dynamics::DstNodeCollideMap_>::iterator&
|
||||
j,
|
||||
const std::unordered_map<int, SrcPartCollideMap_>::iterator& k,
|
||||
const std::unordered_map<int, Object::Ref<Collision> >::iterator& l) {
|
||||
// Handle disconnect equivalents if they were colliding.
|
||||
if (l->second->collide) {
|
||||
@ -367,7 +369,7 @@ void Dynamics::Impl::HandleDisconnect(
|
||||
k->second.dst_part_collisions.erase(l);
|
||||
}
|
||||
|
||||
void Dynamics::ProcessCollisions() {
|
||||
void Dynamics::ProcessCollision_() {
|
||||
processing_collisions_ = true;
|
||||
|
||||
collision_count_ = 0;
|
||||
@ -441,10 +443,10 @@ void Dynamics::ProcessCollisions() {
|
||||
// Process all standard collisions. This will trigger our callback which
|
||||
// do the real work (add collisions to list, store commands to be
|
||||
// called, etc).
|
||||
dSpaceCollide(ode_space_, this, &DoCollideCallback);
|
||||
dSpaceCollide(ode_space_, this, &DoCollideCallback_);
|
||||
|
||||
// Collide our trimeshes against everything.
|
||||
collision_cache_->CollideAgainstSpace(ode_space_, this, &DoCollideCallback);
|
||||
collision_cache_->CollideAgainstSpace(ode_space_, this, &DoCollideCallback_);
|
||||
|
||||
// Do a bit of precalc each cycle.
|
||||
collision_cache_->Precalc();
|
||||
@ -453,9 +455,9 @@ void Dynamics::ProcessCollisions() {
|
||||
// setting parts' currently-colliding-with lists
|
||||
// based on current info,
|
||||
// removing unclaimed collisions and empty groups.
|
||||
std::unordered_map<int64_t, SrcNodeCollideMap>::iterator i_next;
|
||||
std::unordered_map<int64_t, DstNodeCollideMap>::iterator j_next;
|
||||
std::unordered_map<int, SrcPartCollideMap>::iterator k_next;
|
||||
std::unordered_map<int64_t, SrcNodeCollideMap_>::iterator i_next;
|
||||
std::unordered_map<int64_t, DstNodeCollideMap_>::iterator j_next;
|
||||
std::unordered_map<int, SrcPartCollideMap_>::iterator k_next;
|
||||
std::unordered_map<int, Object::Ref<Collision> >::iterator l_next;
|
||||
for (auto i = impl_->node_collisions_.begin();
|
||||
i != impl_->node_collisions_.end(); i = i_next) {
|
||||
@ -507,26 +509,26 @@ void Dynamics::ProcessCollisions() {
|
||||
collision_events_.clear();
|
||||
}
|
||||
|
||||
void Dynamics::process() {
|
||||
void Dynamics::Process() {
|
||||
in_process_ = true;
|
||||
// Update this once so we can recycle results.
|
||||
real_time_ = g_core->GetAppTimeMillisecs();
|
||||
ProcessCollisions();
|
||||
ProcessCollision_();
|
||||
dWorldQuickStep(ode_world_, kGameStepSeconds);
|
||||
dJointGroupEmpty(ode_contact_group_);
|
||||
in_process_ = false;
|
||||
}
|
||||
|
||||
void Dynamics::DoCollideCallback(void* data, dGeomID o1, dGeomID o2) {
|
||||
void Dynamics::DoCollideCallback_(void* data, dGeomID o1, dGeomID o2) {
|
||||
auto* d = static_cast<Dynamics*>(data);
|
||||
d->CollideCallback(o1, o2);
|
||||
d->CollideCallback_(o1, o2);
|
||||
}
|
||||
|
||||
// Run collisions for everything. Store any callbacks that will need to be made
|
||||
// and run them after all collision constraints are made.
|
||||
// This way we know all bodies and their associated nodes, etc are valid
|
||||
// throughout collision processing.
|
||||
void Dynamics::CollideCallback(dGeomID o1, dGeomID o2) {
|
||||
void Dynamics::CollideCallback_(dGeomID o1, dGeomID o2) {
|
||||
dBodyID b1 = dGeomGetBody(o1);
|
||||
dBodyID b2 = dGeomGetBody(o2);
|
||||
|
||||
@ -1103,7 +1105,7 @@ void Dynamics::CollideCallback(dGeomID o1, dGeomID o2) {
|
||||
}
|
||||
}
|
||||
|
||||
void Dynamics::ShutdownODE() {
|
||||
void Dynamics::ShutdownODE_() {
|
||||
if (ode_space_) {
|
||||
dSpaceDestroy(ode_space_);
|
||||
ode_space_ = nullptr;
|
||||
@ -1118,8 +1120,8 @@ void Dynamics::ShutdownODE() {
|
||||
}
|
||||
}
|
||||
|
||||
void Dynamics::ResetODE() {
|
||||
ShutdownODE();
|
||||
void Dynamics::ResetODE_() {
|
||||
ShutdownODE_();
|
||||
ode_world_ = dWorldCreate();
|
||||
assert(ode_world_);
|
||||
dWorldSetGravity(ode_world_, 0, -20, 0);
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#define BALLISTICA_SCENE_V1_DYNAMICS_DYNAMICS_H_
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "ballistica/base/base.h"
|
||||
@ -16,12 +15,12 @@ namespace ballistica::scene_v1 {
|
||||
|
||||
class Dynamics : public Object {
|
||||
public:
|
||||
explicit Dynamics(Scene* scene_in);
|
||||
explicit Dynamics(Scene* scene);
|
||||
~Dynamics() override;
|
||||
void Draw(base::FrameDef* frame_def); // Draw any debug stuff, etc.
|
||||
auto ode_world() -> dWorldID { return ode_world_; }
|
||||
auto getContactGroup() -> dJointGroupID { return ode_contact_group_; }
|
||||
auto space() -> dSpaceID { return ode_space_; }
|
||||
auto ode_contact_group() -> dJointGroupID { return ode_contact_group_; }
|
||||
auto ode_space() -> dSpaceID { return ode_space_; }
|
||||
|
||||
// Discontinues a collision. Used by parts when changing materials
|
||||
// so that new collisions may enter effect.
|
||||
@ -37,6 +36,7 @@ class Dynamics : public Object {
|
||||
: active_collide_src_node_)
|
||||
.Get();
|
||||
}
|
||||
|
||||
// Used by collision callbacks - internal.
|
||||
auto GetActiveCollideDstNode() -> Node* {
|
||||
assert(active_collision_);
|
||||
@ -49,19 +49,19 @@ class Dynamics : public Object {
|
||||
}
|
||||
|
||||
// Used by collide message handlers.
|
||||
void set_collide_message_state(bool inCollideMessageIn,
|
||||
bool target_other_in = false) {
|
||||
in_collide_message_ = inCollideMessageIn;
|
||||
collide_message_reverse_order_ = target_other_in;
|
||||
void set_collide_message_state(bool in_collide_message,
|
||||
bool target_other = false) {
|
||||
in_collide_message_ = in_collide_message;
|
||||
collide_message_reverse_order_ = target_other;
|
||||
}
|
||||
auto in_collide_message() const -> bool { return in_collide_message_; }
|
||||
void process();
|
||||
void increment_skid_sound_count() { skid_sound_count_++; }
|
||||
void decrement_skid_sound_count() { skid_sound_count_--; }
|
||||
auto skid_sound_count() const -> int { return skid_sound_count_; }
|
||||
void incrementRollSoundCount() { roll_sound_count_++; }
|
||||
void decrement_roll_sound_count() { roll_sound_count_--; }
|
||||
auto getRollSoundCount() const -> int { return roll_sound_count_; }
|
||||
auto in_collide_message() const { return in_collide_message_; }
|
||||
void Process();
|
||||
void IncrementSkidSoundCount() { skid_sound_count_++; }
|
||||
void DecrementSkidSoundCount() { skid_sound_count_--; }
|
||||
auto skid_sound_count() const { return skid_sound_count_; }
|
||||
void IncrementRollSoundCount() { roll_sound_count_++; }
|
||||
void DecrementRollSoundCount() { roll_sound_count_--; }
|
||||
auto roll_sound_count() const { return roll_sound_count_; }
|
||||
|
||||
// We do some fancy collision testing stuff for trimeshes instead
|
||||
// of going through regular ODE space collision testing.. so we have
|
||||
@ -69,55 +69,52 @@ class Dynamics : public Object {
|
||||
void AddTrimesh(dGeomID g);
|
||||
void RemoveTrimesh(dGeomID g);
|
||||
|
||||
auto collision_count() const -> int { return collision_count_; }
|
||||
auto process_real_time() const -> millisecs_t { return real_time_; }
|
||||
auto last_impact_sound_time() const -> millisecs_t {
|
||||
return last_impact_sound_time_;
|
||||
}
|
||||
auto in_process() const -> bool { return in_process_; }
|
||||
auto collision_count() const { return collision_count_; }
|
||||
auto process_real_time() const { return real_time_; }
|
||||
auto last_impact_sound_time() const { return last_impact_sound_time_; }
|
||||
auto in_process() const { return in_process_; }
|
||||
|
||||
private:
|
||||
auto AreColliding(const Part& p1, const Part& p2) -> bool;
|
||||
class SrcNodeCollideMap;
|
||||
class DstNodeCollideMap;
|
||||
class SrcPartCollideMap;
|
||||
class CollisionEvent;
|
||||
class CollisionReset;
|
||||
class Impl;
|
||||
std::vector<CollisionReset> collision_resets_;
|
||||
auto AreColliding_(const Part& p1, const Part& p2) -> bool;
|
||||
class SrcNodeCollideMap_;
|
||||
class DstNodeCollideMap_;
|
||||
class SrcPartCollideMap_;
|
||||
class CollisionEvent_;
|
||||
class CollisionReset_;
|
||||
class Impl_;
|
||||
std::vector<CollisionReset_> collision_resets_;
|
||||
|
||||
// Return a collision object between these two parts,
|
||||
// creating a new one if need be.
|
||||
auto GetCollision(Part* p1, Part* p2, MaterialContext** cc1,
|
||||
MaterialContext** cc2) -> Collision*;
|
||||
|
||||
std::vector<CollisionEvent> collision_events_;
|
||||
void ResetODE();
|
||||
void ShutdownODE();
|
||||
static void DoCollideCallback(void* data, dGeomID o1, dGeomID o2);
|
||||
void CollideCallback(dGeomID o1, dGeomID o2);
|
||||
void ProcessCollisions();
|
||||
std::vector<CollisionEvent_> collision_events_;
|
||||
void ResetODE_();
|
||||
void ShutdownODE_();
|
||||
static void DoCollideCallback_(void* data, dGeomID o1, dGeomID o2);
|
||||
void CollideCallback_(dGeomID o1, dGeomID o2);
|
||||
void ProcessCollision_();
|
||||
|
||||
std::unique_ptr<Impl> impl_;
|
||||
bool processing_collisions_{};
|
||||
int skid_sound_count_{};
|
||||
int roll_sound_count_{};
|
||||
int collision_count_{};
|
||||
bool in_process_ : 1 {};
|
||||
bool in_collide_message_ : 1 {};
|
||||
bool collide_message_reverse_order_ : 1 {};
|
||||
bool processing_collisions_ : 1 {};
|
||||
dWorldID ode_world_{};
|
||||
dJointGroupID ode_contact_group_{};
|
||||
dSpaceID ode_space_{};
|
||||
millisecs_t real_time_{};
|
||||
bool in_process_{};
|
||||
std::vector<dGeomID> trimeshes_;
|
||||
millisecs_t last_impact_sound_time_{};
|
||||
int skid_sound_count_{};
|
||||
int roll_sound_count_{};
|
||||
int collision_count_{};
|
||||
Scene* scene_{};
|
||||
bool in_collide_message_{};
|
||||
bool collide_message_reverse_order_{};
|
||||
Collision* active_collision_{};
|
||||
Object::WeakRef<Node> active_collide_src_node_;
|
||||
Object::WeakRef<Node> active_collide_dst_node_;
|
||||
std::vector<dGeomID> trimeshes_;
|
||||
std::unique_ptr<Impl_> impl_;
|
||||
std::unique_ptr<base::CollisionCache> collision_cache_;
|
||||
friend class Impl;
|
||||
};
|
||||
|
||||
} // namespace ballistica::scene_v1
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
#include "ballistica/scene_v1/dynamics/material/impact_sound_material_action.h"
|
||||
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
#include "ballistica/base/audio/audio.h"
|
||||
#include "ballistica/scene_v1/dynamics/dynamics.h"
|
||||
#include "ballistica/scene_v1/dynamics/material/material_context.h"
|
||||
#include "ballistica/scene_v1/support/client_session.h"
|
||||
@ -50,10 +50,8 @@ void ImpactSoundMaterialAction::Apply(MaterialContext* context,
|
||||
assert(context->dynamics.Exists());
|
||||
assert(context->dynamics->in_process());
|
||||
|
||||
// For now lets avoid this in low-quality graphics mode (should we make
|
||||
// a low-quality sound mode?)
|
||||
if (g_base->graphics_server
|
||||
&& g_base->graphics_server->quality() < base::GraphicsQuality::kMedium) {
|
||||
// Avoid this if we're cutting corners.
|
||||
if (g_base->audio->UseLowQualityAudio()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ MaterialContext::SkidSoundEntry::SkidSoundEntry(
|
||||
assert(context->dynamics.Exists());
|
||||
#endif
|
||||
assert(context->dynamics->in_process());
|
||||
context->dynamics->increment_skid_sound_count();
|
||||
context->dynamics->IncrementSkidSoundCount();
|
||||
}
|
||||
|
||||
MaterialContext::SkidSoundEntry::SkidSoundEntry(MaterialContext* context_in,
|
||||
@ -57,13 +57,13 @@ MaterialContext::SkidSoundEntry::SkidSoundEntry(MaterialContext* context_in,
|
||||
assert(context);
|
||||
assert(context->dynamics.Exists());
|
||||
assert(context->dynamics->in_process());
|
||||
context->dynamics->increment_skid_sound_count();
|
||||
context->dynamics->IncrementSkidSoundCount();
|
||||
}
|
||||
|
||||
MaterialContext::SkidSoundEntry::~SkidSoundEntry() {
|
||||
assert(context);
|
||||
assert(context->dynamics.Exists());
|
||||
context->dynamics->decrement_skid_sound_count();
|
||||
context->dynamics->DecrementSkidSoundCount();
|
||||
if (playing) {
|
||||
g_base->audio->PushSourceFadeOutCall(play_id, 200);
|
||||
}
|
||||
@ -81,7 +81,7 @@ MaterialContext::RollSoundEntry::RollSoundEntry(MaterialContext* context_in,
|
||||
assert(context);
|
||||
assert(context->dynamics.Exists());
|
||||
assert(context->dynamics->in_process());
|
||||
context->dynamics->incrementRollSoundCount();
|
||||
context->dynamics->IncrementRollSoundCount();
|
||||
}
|
||||
|
||||
MaterialContext::RollSoundEntry::RollSoundEntry(
|
||||
@ -90,13 +90,13 @@ MaterialContext::RollSoundEntry::RollSoundEntry(
|
||||
assert(context);
|
||||
assert(context->dynamics.Exists());
|
||||
assert(context->dynamics->in_process());
|
||||
context->dynamics->incrementRollSoundCount();
|
||||
context->dynamics->IncrementRollSoundCount();
|
||||
}
|
||||
|
||||
MaterialContext::RollSoundEntry::~RollSoundEntry() {
|
||||
assert(context);
|
||||
assert(context->dynamics.Exists());
|
||||
context->dynamics->decrement_roll_sound_count();
|
||||
context->dynamics->DecrementRollSoundCount();
|
||||
if (playing) {
|
||||
g_base->audio->PushSourceFadeOutCall(play_id, 200);
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
#include "ballistica/scene_v1/dynamics/material/roll_sound_material_action.h"
|
||||
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
#include "ballistica/base/audio/audio.h"
|
||||
#include "ballistica/scene_v1/dynamics/dynamics.h"
|
||||
#include "ballistica/scene_v1/dynamics/material/material_context.h"
|
||||
#include "ballistica/scene_v1/support/client_session.h"
|
||||
@ -34,16 +34,14 @@ void RollSoundMaterialAction::Apply(MaterialContext* context,
|
||||
assert(context->dynamics.Exists());
|
||||
assert(context->dynamics->in_process());
|
||||
|
||||
// For now lets avoid this in low-quality graphics mode
|
||||
// (should we make a low-quality sound mode?)
|
||||
if (g_base->graphics
|
||||
&& g_base->graphics_server->quality() < base::GraphicsQuality::kMedium) {
|
||||
// Avoid this if we're cutting corners.
|
||||
if (g_base->audio->UseLowQualityAudio()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's limit the amount of skid-sounds we spawn, otherwise we'll
|
||||
// start using up all our sound resources on skids when things get messy
|
||||
if (context->dynamics->getRollSoundCount() < 2) {
|
||||
if (context->dynamics->roll_sound_count() < 2) {
|
||||
context->roll_sounds.emplace_back(context, sound.Get(), target_impulse,
|
||||
volume);
|
||||
context->complex_sound = true;
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
#include "ballistica/scene_v1/dynamics/material/skid_sound_material_action.h"
|
||||
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
#include "ballistica/base/audio/audio.h"
|
||||
#include "ballistica/scene_v1/dynamics/dynamics.h"
|
||||
#include "ballistica/scene_v1/dynamics/material/material_context.h"
|
||||
#include "ballistica/scene_v1/support/client_session.h"
|
||||
@ -34,10 +34,8 @@ void SkidSoundMaterialAction::Apply(MaterialContext* context,
|
||||
assert(context->dynamics.Exists());
|
||||
assert(context->dynamics->in_process());
|
||||
|
||||
// For now lets avoid this in low-quality graphics mode
|
||||
// (should we make a low-quality sound mode?).
|
||||
if (g_base->graphics_server
|
||||
&& g_base->graphics_server->quality() < base::GraphicsQuality::kMedium) {
|
||||
// Avoid this if we're cutting corners.
|
||||
if (g_base->audio->UseLowQualityAudio()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -65,23 +65,23 @@ RigidBody::RigidBody(int id_in, Part* part_in, Type type_in, Shape shape_in,
|
||||
case Shape::kSphere: {
|
||||
dimensions_[0] = dimensions_[1] = dimensions_[2] = 0.3f;
|
||||
geoms_.resize(1);
|
||||
geoms_[0] = dCreateSphere(dynamics_->space(), dimensions_[0]);
|
||||
geoms_[0] = dCreateSphere(dynamics_->ode_space(), dimensions_[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
case Shape::kBox: {
|
||||
dimensions_[0] = dimensions_[1] = dimensions_[2] = 0.6f;
|
||||
geoms_.resize(1);
|
||||
geoms_[0] = dCreateBox(dynamics_->space(), dimensions_[0], dimensions_[1],
|
||||
dimensions_[2]);
|
||||
geoms_[0] = dCreateBox(dynamics_->ode_space(), dimensions_[0],
|
||||
dimensions_[1], dimensions_[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
case Shape::kCapsule: {
|
||||
dimensions_[0] = dimensions_[1] = 0.3f;
|
||||
geoms_.resize(1);
|
||||
geoms_[0] =
|
||||
dCreateCCylinder(dynamics_->space(), dimensions_[0], dimensions_[1]);
|
||||
geoms_[0] = dCreateCCylinder(dynamics_->ode_space(), dimensions_[0],
|
||||
dimensions_[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -98,14 +98,15 @@ RigidBody::RigidBody(int id_in, Part* part_in, Type type_in, Shape shape_in,
|
||||
Vector3f p =
|
||||
Matrix44fRotate(Vector3f(0, 1, 0), static_cast<float>(i) * inc)
|
||||
* Vector3f(offset, 0, 0);
|
||||
geoms_[i * 2] = dCreateGeomTransform(dynamics_->space());
|
||||
geoms_[i * 2] = dCreateGeomTransform(dynamics_->ode_space());
|
||||
geoms_[i * 2 + 1] = dCreateSphere(nullptr, sub_rad);
|
||||
dGeomTransformSetGeom(geoms_[i * 2], geoms_[i * 2 + 1]);
|
||||
dGeomSetPosition(geoms_[i * 2 + 1], p.v[0], p.v[1], p.v[2]);
|
||||
}
|
||||
|
||||
// One last center sphere to keep stuff from getting stuck in our middle.
|
||||
geoms_[geoms_.size() - 1] = dCreateSphere(dynamics_->space(), sub_rad);
|
||||
geoms_[geoms_.size() - 1] =
|
||||
dCreateSphere(dynamics_->ode_space(), sub_rad);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -129,9 +129,6 @@ FlagNode::FlagNode(Scene* scene) : Node(scene, node_type), part_(this) {
|
||||
|
||||
mesh_.SetIndexData(indices);
|
||||
mesh_.SetStaticData(v_static);
|
||||
|
||||
// Create our shadow set.
|
||||
UpdateForGraphicsQuality(g_base->graphics_server->quality());
|
||||
}
|
||||
|
||||
auto FlagNode::getPosition() const -> std::vector<float> {
|
||||
@ -257,6 +254,11 @@ void FlagNode::HandleMessage(const char* data_in) {
|
||||
}
|
||||
|
||||
void FlagNode::Draw(base::FrameDef* frame_def) {
|
||||
if (graphics_quality_ != frame_def->quality()) {
|
||||
graphics_quality_ = frame_def->quality();
|
||||
UpdateForGraphicsQuality(graphics_quality_);
|
||||
}
|
||||
|
||||
// Flag cloth.
|
||||
{
|
||||
// Update the dynamic portion of our mesh data.
|
||||
@ -311,45 +313,60 @@ void FlagNode::Draw(base::FrameDef* frame_def) {
|
||||
|
||||
FullShadowSet* full_shadows = full_shadow_set_.Get();
|
||||
|
||||
if (full_shadows) {
|
||||
// Pole bottom.
|
||||
{
|
||||
full_shadows->shadow_pole_bottom_.GetValues(&s_scale, &s_density);
|
||||
const Vector3f& p(full_shadows->shadow_pole_bottom_.GetPosition());
|
||||
g_base->graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0,
|
||||
s_density * 0.25f);
|
||||
}
|
||||
// Update our shadow objects.
|
||||
if (!g_core->HeadlessMode()) {
|
||||
dBodyID b = body_->body();
|
||||
assert(b);
|
||||
dVector3 p;
|
||||
if (FullShadowSet* full_shadows = full_shadow_set_.Get()) {
|
||||
full_shadows->shadow_flag_.SetPosition(
|
||||
flag_points_[kFlagSizeX * (kFlagSizeY / 2) + (kFlagSizeX / 2)]);
|
||||
dBodyGetRelPointPos(b, 0, 0, kFlagHeight * -0.4f, p);
|
||||
full_shadows->shadow_pole_bottom_.SetPosition(Vector3f(p));
|
||||
full_shadows->shadow_pole_middle_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(b)));
|
||||
dBodyGetRelPointPos(b, 0, 0, kFlagHeight * 0.4f, p);
|
||||
full_shadows->shadow_pole_top_.SetPosition(Vector3f(p));
|
||||
// Pole bottom.
|
||||
{
|
||||
full_shadows->shadow_pole_bottom_.GetValues(&s_scale, &s_density);
|
||||
const Vector3f& p(full_shadows->shadow_pole_bottom_.GetPosition());
|
||||
g_base->graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0,
|
||||
s_density * 0.25f);
|
||||
}
|
||||
|
||||
// Pole middle.
|
||||
{
|
||||
full_shadows->shadow_pole_middle_.GetValues(&s_scale, &s_density);
|
||||
const Vector3f& p(full_shadows->shadow_pole_middle_.GetPosition());
|
||||
g_base->graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0,
|
||||
s_density * 0.25f);
|
||||
}
|
||||
// Pole middle.
|
||||
{
|
||||
full_shadows->shadow_pole_middle_.GetValues(&s_scale, &s_density);
|
||||
const Vector3f& p(full_shadows->shadow_pole_middle_.GetPosition());
|
||||
g_base->graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0,
|
||||
s_density * 0.25f);
|
||||
}
|
||||
|
||||
// Pole top.
|
||||
{
|
||||
full_shadows->shadow_pole_middle_.GetValues(&s_scale, &s_density);
|
||||
const Vector3f& p(full_shadows->shadow_pole_top_.GetPosition());
|
||||
g_base->graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0,
|
||||
s_density * 0.25f);
|
||||
}
|
||||
// Pole top.
|
||||
{
|
||||
full_shadows->shadow_pole_middle_.GetValues(&s_scale, &s_density);
|
||||
const Vector3f& p(full_shadows->shadow_pole_top_.GetPosition());
|
||||
g_base->graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0,
|
||||
s_density * 0.25f);
|
||||
}
|
||||
|
||||
// Flag center.
|
||||
{
|
||||
full_shadows->shadow_flag_.GetValues(&s_scale, &s_density);
|
||||
const Vector3f& p(full_shadows->shadow_flag_.GetPosition());
|
||||
// Flag center.
|
||||
{
|
||||
full_shadows->shadow_flag_.GetValues(&s_scale, &s_density);
|
||||
const Vector3f& p(full_shadows->shadow_flag_.GetPosition());
|
||||
g_base->graphics->DrawBlotch(p, 0.8f * s_scale, 0, 0, 0,
|
||||
s_density * 0.3f);
|
||||
}
|
||||
|
||||
} else if (SimpleShadowSet* simple_shadows = simple_shadow_set_.Get()) {
|
||||
dBodyGetRelPointPos(b, 0, 0, kFlagHeight * -0.3f, p);
|
||||
simple_shadows->shadow_.SetPosition(Vector3f(p));
|
||||
simple_shadows->shadow_.GetValues(&s_scale, &s_density);
|
||||
const Vector3f& p(simple_shadows->shadow_.GetPosition());
|
||||
g_base->graphics->DrawBlotch(p, 0.8f * s_scale, 0, 0, 0,
|
||||
s_density * 0.3f);
|
||||
s_density * 0.5f);
|
||||
}
|
||||
} else {
|
||||
SimpleShadowSet* simple_shadows = simple_shadow_set_.Get();
|
||||
assert(simple_shadows);
|
||||
simple_shadows->shadow_.GetValues(&s_scale, &s_density);
|
||||
const Vector3f& p(simple_shadows->shadow_.GetPosition());
|
||||
g_base->graphics->DrawBlotch(p, 0.8f * s_scale, 0, 0, 0,
|
||||
s_density * 0.5f);
|
||||
}
|
||||
c.Submit();
|
||||
}
|
||||
@ -398,30 +415,6 @@ void FlagNode::Step() {
|
||||
// FIXME: This should probably happen for RBDs automatically?
|
||||
body_->UpdateBlending();
|
||||
|
||||
// Update our shadow objects.
|
||||
dBodyID b = body_->body();
|
||||
assert(b);
|
||||
|
||||
if (!g_core->HeadlessMode()) {
|
||||
dVector3 p;
|
||||
FullShadowSet* full_shadows = full_shadow_set_.Get();
|
||||
if (full_shadows) {
|
||||
full_shadows->shadow_flag_.SetPosition(
|
||||
flag_points_[kFlagSizeX * (kFlagSizeY / 2) + (kFlagSizeX / 2)]);
|
||||
dBodyGetRelPointPos(b, 0, 0, kFlagHeight * -0.4f, p);
|
||||
full_shadows->shadow_pole_bottom_.SetPosition(Vector3f(p));
|
||||
full_shadows->shadow_pole_middle_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(b)));
|
||||
dBodyGetRelPointPos(b, 0, 0, kFlagHeight * 0.4f, p);
|
||||
full_shadows->shadow_pole_top_.SetPosition(Vector3f(p));
|
||||
} else {
|
||||
SimpleShadowSet* simple_shadows = simple_shadow_set_.Get();
|
||||
assert(simple_shadows);
|
||||
dBodyGetRelPointPos(b, 0, 0, kFlagHeight * -0.3f, p);
|
||||
simple_shadows->shadow_.SetPosition(Vector3f(p));
|
||||
}
|
||||
}
|
||||
|
||||
if (dBodyIsEnabled(body_->body())) {
|
||||
// Try to keep upright by pushing the top of the
|
||||
// flag to be above the bottom.
|
||||
@ -675,10 +668,6 @@ void FlagNode::GetRigidBodyPickupLocations(int id, float* obj, float* character,
|
||||
hand1[2] = -0.05f;
|
||||
}
|
||||
|
||||
void FlagNode::OnGraphicsQualityChanged(base::GraphicsQuality q) {
|
||||
UpdateForGraphicsQuality(q);
|
||||
}
|
||||
|
||||
void FlagNode::UpdateForGraphicsQuality(base::GraphicsQuality quality) {
|
||||
if (!g_core->HeadlessMode()) {
|
||||
if (quality >= base::GraphicsQuality::kMedium) {
|
||||
|
||||
@ -44,10 +44,13 @@ class FlagNode : public Node {
|
||||
void UpdateDimensions();
|
||||
void ResetFlagMesh();
|
||||
void UpdateFlagMesh();
|
||||
void OnGraphicsQualityChanged(base::GraphicsQuality q) override;
|
||||
void UpdateForGraphicsQuality(base::GraphicsQuality q);
|
||||
void UpdateSpringPoint(int p1, int p2, float rest_length);
|
||||
base::AreaOfInterest* area_of_interest_ = nullptr;
|
||||
|
||||
base::GraphicsQuality graphics_quality_{};
|
||||
bool light_weight_ : 1 {};
|
||||
bool have_flag_impulse_ : 1 {};
|
||||
base::AreaOfInterest* area_of_interest_{};
|
||||
Part part_;
|
||||
std::vector<float> color_ = {1.0f, 1.0f, 1.0f};
|
||||
Object::Ref<RigidBody> body_;
|
||||
@ -56,15 +59,13 @@ class FlagNode : public Node {
|
||||
Object::Ref<FullShadowSet> full_shadow_set_;
|
||||
Object::Ref<SimpleShadowSet> simple_shadow_set_;
|
||||
int wind_rand_{};
|
||||
int footing_{};
|
||||
float wind_rand_x_{};
|
||||
float wind_rand_y_{};
|
||||
float wind_rand_z_{};
|
||||
float flag_impulse_add_x_{};
|
||||
float flag_impulse_add_y_{};
|
||||
float flag_impulse_add_z_{};
|
||||
bool have_flag_impulse_{};
|
||||
int footing_{};
|
||||
bool light_weight_{};
|
||||
Vector3f flag_points_[25]{};
|
||||
Vector3f flag_normals_[25]{};
|
||||
Vector3f flag_velocities_[25]{};
|
||||
|
||||
@ -40,7 +40,6 @@ class Node : public Object {
|
||||
|
||||
/// Called when the language changes.
|
||||
virtual void OnLanguageChange() {}
|
||||
virtual void OnGraphicsQualityChanged(base::GraphicsQuality q) {}
|
||||
|
||||
/// The node can rule out collisions between particular bodies using this.
|
||||
virtual auto PreFilterCollision(RigidBody* b1, RigidBody* r2) -> bool {
|
||||
|
||||
@ -576,7 +576,7 @@ auto PropNode::CollideCallback(dContact* c, int count,
|
||||
dBodyGetMass(b2, &m);
|
||||
dJointID j =
|
||||
dJointCreateFixed(scene()->dynamics()->ode_world(),
|
||||
scene()->dynamics()->getContactGroup());
|
||||
scene()->dynamics()->ode_contact_group());
|
||||
dJointAttach(j, b1, b2);
|
||||
dJointSetFixed(j);
|
||||
dJointSetFixedSpringMode(j, 1, 1, false);
|
||||
|
||||
@ -260,7 +260,7 @@ void ShieldNode::Draw(base::FrameDef* frame_def) {
|
||||
c.Submit();
|
||||
|
||||
// Nifty intersection effects in fancy graphics mode.
|
||||
if (frame_def->has_depth_texture()) {
|
||||
if (frame_def->HasDepthTexture()) {
|
||||
base::ShieldComponent c2(frame_def->overlay_3d_pass());
|
||||
{
|
||||
auto xf = c2.ScopedTransform();
|
||||
@ -273,7 +273,7 @@ void ShieldNode::Draw(base::FrameDef* frame_def) {
|
||||
}
|
||||
c2.Submit();
|
||||
}
|
||||
if (frame_def->has_depth_texture()) {
|
||||
if (frame_def->HasDepthTexture()) {
|
||||
base::PostProcessComponent c2(frame_def->blit_pass());
|
||||
c2.SetNormalDistort(distort);
|
||||
{
|
||||
|
||||
@ -916,9 +916,6 @@ SpazNode::SpazNode(Scene* scene)
|
||||
// Give joints initial vals.
|
||||
UpdateJoints();
|
||||
|
||||
// FIXME: should do this on draw.
|
||||
UpdateForGraphicsQuality(g_base->graphics_server->quality());
|
||||
|
||||
// We want to have an area of interest by default.
|
||||
SetIsAreaOfInterest(true);
|
||||
|
||||
@ -2079,40 +2076,6 @@ void SpazNode::Step() {
|
||||
}
|
||||
}
|
||||
|
||||
// Update shadows.
|
||||
#if !BA_HEADLESS_BUILD
|
||||
FullShadowSet* full_shadows = full_shadow_set_.Get();
|
||||
if (full_shadows) {
|
||||
full_shadows->torso_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(body_torso_->body())));
|
||||
full_shadows->head_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(body_head_->body())));
|
||||
full_shadows->pelvis_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(body_pelvis_->body())));
|
||||
full_shadows->lower_left_leg_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(lower_left_leg_body_->body())));
|
||||
full_shadows->lower_right_leg_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(lower_right_leg_body_->body())));
|
||||
full_shadows->upper_left_leg_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(upper_left_leg_body_->body())));
|
||||
full_shadows->upper_right_leg_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(upper_right_leg_body_->body())));
|
||||
full_shadows->lower_right_arm_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(lower_right_arm_body_->body())));
|
||||
full_shadows->upper_right_arm_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(upper_right_arm_body_->body())));
|
||||
full_shadows->lower_left_arm_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(lower_left_arm_body_->body())));
|
||||
full_shadows->upper_left_arm_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(upper_left_arm_body_->body())));
|
||||
} else {
|
||||
SimpleShadowSet* simple_shadows = simple_shadow_set_.Get();
|
||||
assert(simple_shadows);
|
||||
simple_shadows->shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(body_pelvis_->body())));
|
||||
}
|
||||
#endif // !BA_HEADLESS_BUILD
|
||||
|
||||
// Update wings if we've got 'em.
|
||||
if (wings_) {
|
||||
float maxDist = 0.8f;
|
||||
@ -4547,6 +4510,11 @@ static void DrawRadialMeter(base::MeshIndexedSimpleFull* m,
|
||||
void SpazNode::Draw(base::FrameDef* frame_def) {
|
||||
#if !BA_HEADLESS_BUILD
|
||||
|
||||
if (graphics_quality_ != frame_def->quality()) {
|
||||
graphics_quality_ = frame_def->quality();
|
||||
UpdateForGraphicsQuality(graphics_quality_);
|
||||
}
|
||||
|
||||
#if BA_OSTYPE_MACOS
|
||||
if (g_base->graphics_server->renderer()->debug_draw_mode()) {
|
||||
base::SimpleComponent c(frame_def->overlay_3d_pass());
|
||||
@ -5356,49 +5324,68 @@ void SpazNode::Draw(base::FrameDef* frame_def) {
|
||||
sc[2] = weight * freeze_color[2] + (1.0f - weight) * sc[2];
|
||||
}
|
||||
|
||||
FullShadowSet* full_shadows = full_shadow_set_.Get();
|
||||
if (full_shadows) {
|
||||
DrawBrightSpot(full_shadows->lower_left_leg_shadow_, 0.3f * death_scale,
|
||||
death_fade * (frozen_ ? 0.3f : 0.2f), sc);
|
||||
DrawBrightSpot(full_shadows->lower_right_leg_shadow_, 0.3f * death_scale,
|
||||
death_fade * (frozen_ ? 0.3f : 0.2f), sc);
|
||||
DrawBrightSpot(full_shadows->head_shadow_, 0.45f * death_scale,
|
||||
death_fade * (frozen_ ? 0.8f : 0.14f), sc);
|
||||
}
|
||||
// Update and draw shadows.
|
||||
if (!g_core->HeadlessMode()) {
|
||||
if (FullShadowSet* full_shadows = full_shadow_set_.Get()) {
|
||||
full_shadows->torso_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(body_torso_->body())));
|
||||
full_shadows->head_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(body_head_->body())));
|
||||
full_shadows->pelvis_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(body_pelvis_->body())));
|
||||
full_shadows->lower_left_leg_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(lower_left_leg_body_->body())));
|
||||
full_shadows->lower_right_leg_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(lower_right_leg_body_->body())));
|
||||
full_shadows->upper_left_leg_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(upper_left_leg_body_->body())));
|
||||
full_shadows->upper_right_leg_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(upper_right_leg_body_->body())));
|
||||
full_shadows->lower_right_arm_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(lower_right_arm_body_->body())));
|
||||
full_shadows->upper_right_arm_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(upper_right_arm_body_->body())));
|
||||
full_shadows->lower_left_arm_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(lower_left_arm_body_->body())));
|
||||
full_shadows->upper_left_arm_shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(upper_left_arm_body_->body())));
|
||||
|
||||
if (full_shadows) {
|
||||
DrawShadow(full_shadows->torso_shadow_, 0.19f * death_scale, 0.9f, sc);
|
||||
DrawShadow(full_shadows->head_shadow_, 0.15f * death_scale, 0.7f, sc);
|
||||
DrawShadow(full_shadows->pelvis_shadow_, 0.15f * death_scale, 0.7f, sc);
|
||||
DrawShadow(full_shadows->lower_left_leg_shadow_, 0.08f * death_scale,
|
||||
1.0f, sc);
|
||||
DrawShadow(full_shadows->lower_right_leg_shadow_, 0.08f * death_scale,
|
||||
1.0f, sc);
|
||||
DrawShadow(full_shadows->upper_left_leg_shadow_, 0.08f * death_scale,
|
||||
1.0f, sc);
|
||||
DrawShadow(full_shadows->upper_right_leg_shadow_, 0.08f * death_scale,
|
||||
1.0f, sc);
|
||||
DrawShadow(full_shadows->upper_left_arm_shadow_, 0.08f * death_scale,
|
||||
0.5f, sc);
|
||||
DrawShadow(full_shadows->lower_left_arm_shadow_, 0.08f * death_scale,
|
||||
0.3f, sc);
|
||||
DrawShadow(full_shadows->lower_right_arm_shadow_, 0.08f * death_scale,
|
||||
0.3f, sc);
|
||||
DrawShadow(full_shadows->upper_right_arm_shadow_, 0.08f * death_scale,
|
||||
0.5f, sc);
|
||||
} else {
|
||||
SimpleShadowSet* simple_shadows = simple_shadow_set_.Get();
|
||||
assert(simple_shadows);
|
||||
DrawShadow(simple_shadows->shadow_, 0.2f * death_scale, 2.0f, sc);
|
||||
DrawBrightSpot(full_shadows->lower_left_leg_shadow_, 0.3f * death_scale,
|
||||
death_fade * (frozen_ ? 0.3f : 0.2f), sc);
|
||||
DrawBrightSpot(full_shadows->lower_right_leg_shadow_,
|
||||
0.3f * death_scale, death_fade * (frozen_ ? 0.3f : 0.2f),
|
||||
sc);
|
||||
DrawBrightSpot(full_shadows->head_shadow_, 0.45f * death_scale,
|
||||
death_fade * (frozen_ ? 0.8f : 0.14f), sc);
|
||||
DrawShadow(full_shadows->torso_shadow_, 0.19f * death_scale, 0.9f, sc);
|
||||
DrawShadow(full_shadows->head_shadow_, 0.15f * death_scale, 0.7f, sc);
|
||||
DrawShadow(full_shadows->pelvis_shadow_, 0.15f * death_scale, 0.7f, sc);
|
||||
DrawShadow(full_shadows->lower_left_leg_shadow_, 0.08f * death_scale,
|
||||
1.0f, sc);
|
||||
DrawShadow(full_shadows->lower_right_leg_shadow_, 0.08f * death_scale,
|
||||
1.0f, sc);
|
||||
DrawShadow(full_shadows->upper_left_leg_shadow_, 0.08f * death_scale,
|
||||
1.0f, sc);
|
||||
DrawShadow(full_shadows->upper_right_leg_shadow_, 0.08f * death_scale,
|
||||
1.0f, sc);
|
||||
DrawShadow(full_shadows->upper_left_arm_shadow_, 0.08f * death_scale,
|
||||
0.5f, sc);
|
||||
DrawShadow(full_shadows->lower_left_arm_shadow_, 0.08f * death_scale,
|
||||
0.3f, sc);
|
||||
DrawShadow(full_shadows->lower_right_arm_shadow_, 0.08f * death_scale,
|
||||
0.3f, sc);
|
||||
DrawShadow(full_shadows->upper_right_arm_shadow_, 0.08f * death_scale,
|
||||
0.5f, sc);
|
||||
} else if (SimpleShadowSet* simple_shadows = simple_shadow_set_.Get()) {
|
||||
simple_shadows->shadow_.SetPosition(
|
||||
Vector3f(dBodyGetPosition(body_pelvis_->body())));
|
||||
DrawShadow(simple_shadows->shadow_, 0.2f * death_scale, 2.0f, sc);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // !BA_HEADLESS_BUILD
|
||||
} // NOLINT (yes i know this is too big)
|
||||
|
||||
void SpazNode::OnGraphicsQualityChanged(base::GraphicsQuality q) {
|
||||
UpdateForGraphicsQuality(q);
|
||||
}
|
||||
|
||||
void SpazNode::UpdateForGraphicsQuality(base::GraphicsQuality quality) {
|
||||
#if !BA_HEADLESS_BUILD
|
||||
if (quality >= base::GraphicsQuality::kMedium) {
|
||||
|
||||
@ -277,7 +277,6 @@ class SpazNode : public Node {
|
||||
|
||||
// Reset to a standing, non-moving state at the given point.
|
||||
void Stand(float x, float y, float z, float angle);
|
||||
void OnGraphicsQualityChanged(base::GraphicsQuality q) override;
|
||||
void UpdateForGraphicsQuality(base::GraphicsQuality q);
|
||||
void UpdateAreaOfInterest();
|
||||
auto CollideCallback(dContact* c, int count, RigidBody* colliding_body,
|
||||
@ -515,6 +514,7 @@ class SpazNode : public Node {
|
||||
bool has_eyelids_{true};
|
||||
bool running_{};
|
||||
bool billboard_cross_out_{};
|
||||
base::GraphicsQuality graphics_quality_{};
|
||||
Object::Ref<RigidBody> hair_front_right_body_;
|
||||
JointFixedEF* hair_front_right_joint_{};
|
||||
Object::Ref<RigidBody> hair_front_left_body_;
|
||||
|
||||
@ -483,9 +483,6 @@ void HostActivity::PruneSessionBaseTimers() {
|
||||
void HostActivity::OnScreenSizeChange() { scene()->OnScreenSizeChange(); }
|
||||
void HostActivity::LanguageChanged() { scene()->LanguageChanged(); }
|
||||
void HostActivity::DebugSpeedMultChanged() { UpdateStepTimerLength(); }
|
||||
void HostActivity::GraphicsQualityChanged(base::GraphicsQuality q) {
|
||||
scene()->GraphicsQualityChanged(q);
|
||||
}
|
||||
|
||||
void HostActivity::Draw(base::FrameDef* frame_def) {
|
||||
if (!started_) {
|
||||
|
||||
@ -57,7 +57,6 @@ class HostActivity : public SceneV1Context {
|
||||
void OnScreenSizeChange();
|
||||
void LanguageChanged();
|
||||
void DebugSpeedMultChanged();
|
||||
void GraphicsQualityChanged(base::GraphicsQuality q);
|
||||
|
||||
// Used to register python calls created in this context so we can make sure
|
||||
// they got properly cleaned up.
|
||||
|
||||
@ -154,16 +154,6 @@ void HostSession::LanguageChanged() {
|
||||
}
|
||||
}
|
||||
|
||||
void HostSession::GraphicsQualityChanged(base::GraphicsQuality q) {
|
||||
// Let our internal scene know.
|
||||
scene()->GraphicsQualityChanged(q);
|
||||
|
||||
// Let all our activities know.
|
||||
for (auto&& i : host_activities_) {
|
||||
i->GraphicsQualityChanged(q);
|
||||
}
|
||||
}
|
||||
|
||||
auto HostSession::DoesFillScreen() const -> bool {
|
||||
// FIXME not necessarily the case.
|
||||
return true;
|
||||
|
||||
@ -70,7 +70,6 @@ class HostSession : public Session {
|
||||
void Draw(base::FrameDef* f) override;
|
||||
void OnScreenSizeChange() override;
|
||||
void LanguageChanged() override;
|
||||
void GraphicsQualityChanged(base::GraphicsQuality q) override;
|
||||
void DebugSpeedMultChanged() override;
|
||||
auto GetHostSession() -> HostSession* override;
|
||||
auto GetMutableScene() -> Scene* override;
|
||||
|
||||
@ -166,7 +166,7 @@ void Scene::Step() {
|
||||
}
|
||||
|
||||
// Lastly step our sim.
|
||||
dynamics_->process();
|
||||
dynamics_->Process();
|
||||
|
||||
time_ += kGameStepMilliseconds;
|
||||
stepnum_++;
|
||||
@ -227,13 +227,6 @@ void Scene::DeleteNode(Node* node) {
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::GraphicsQualityChanged(base::GraphicsQuality q) {
|
||||
assert(g_base->InLogicThread());
|
||||
for (auto&& i : nodes_) {
|
||||
i->OnGraphicsQualityChanged(q);
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::OnScreenSizeChange() {
|
||||
assert(g_base->InLogicThread());
|
||||
for (auto&& i : nodes_) {
|
||||
|
||||
@ -43,7 +43,6 @@ class Scene : public Object {
|
||||
void SetMapBounds(float x, float y, float z, float X, float Y, float Z);
|
||||
void OnScreenSizeChange();
|
||||
void LanguageChanged();
|
||||
void GraphicsQualityChanged(base::GraphicsQuality q);
|
||||
auto out_of_bounds_nodes() -> const std::vector<Object::WeakRef<Node> >& {
|
||||
return out_of_bounds_nodes_;
|
||||
}
|
||||
|
||||
@ -1312,15 +1312,6 @@ void SceneV1AppMode::SetPublicPartyStatsURL(const std::string& url) {
|
||||
}
|
||||
}
|
||||
|
||||
void SceneV1AppMode::GraphicsQualityChanged(base::GraphicsQuality quality) {
|
||||
for (auto&& i : sessions_) {
|
||||
if (!i.Exists()) {
|
||||
continue;
|
||||
}
|
||||
i->GraphicsQualityChanged(quality);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneV1AppMode::SetPublicPartyPlayerCount(int count) {
|
||||
assert(g_base->InLogicThread());
|
||||
if (count == public_party_player_count_) {
|
||||
|
||||
@ -172,7 +172,6 @@ class SceneV1AppMode : public base::AppMode {
|
||||
sockaddr_storage* from) override;
|
||||
void DrawWorld(base::FrameDef* frame_def) override;
|
||||
auto DoesWorldFillScreen() -> bool override;
|
||||
void GraphicsQualityChanged(base::GraphicsQuality quality) override;
|
||||
void RunMainMenu();
|
||||
|
||||
auto dynamics_sync_time() const { return dynamics_sync_time_; }
|
||||
|
||||
@ -33,8 +33,6 @@ void Session::OnScreenSizeChange() {}
|
||||
|
||||
void Session::LanguageChanged() {}
|
||||
|
||||
void Session::GraphicsQualityChanged(base::GraphicsQuality q) {}
|
||||
|
||||
void Session::DebugSpeedMultChanged() {}
|
||||
|
||||
void Session::DumpFullState(SessionStream* out) {
|
||||
|
||||
@ -34,7 +34,6 @@ class Session : public SceneV1Context {
|
||||
virtual auto GetForegroundContext() -> base::ContextRef;
|
||||
virtual void OnScreenSizeChange();
|
||||
virtual void LanguageChanged();
|
||||
virtual void GraphicsQualityChanged(base::GraphicsQuality q);
|
||||
virtual void DebugSpeedMultChanged();
|
||||
auto benchmark_type() const -> base::BenchmarkType { return benchmark_type_; }
|
||||
void set_benchmark_type(base::BenchmarkType val) { benchmark_type_ = val; }
|
||||
|
||||
@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
|
||||
namespace ballistica {
|
||||
|
||||
// These are set automatically via script; don't modify them here.
|
||||
const int kEngineBuildNumber = 21479;
|
||||
const int kEngineBuildNumber = 21486;
|
||||
const char* kEngineVersion = "1.7.28";
|
||||
const int kEngineApiVersion = 8;
|
||||
|
||||
|
||||
@ -92,7 +92,7 @@ void FatalError::ReportFatalError(const std::string& message,
|
||||
// momentarily, and also go to platform-specific logging and good ol'
|
||||
// stderr.
|
||||
Logging::V1CloudLog(logmsg);
|
||||
Logging::DisplayLog("root", LogLevel::kCritical, logmsg);
|
||||
Logging::EmitLog("root", LogLevel::kCritical, logmsg);
|
||||
fprintf(stderr, "%s\n", logmsg.c_str());
|
||||
|
||||
std::string prefix = "FATAL-ERROR-LOG:";
|
||||
@ -175,10 +175,10 @@ auto FatalError::HandleFatalError(bool exit_cleanly,
|
||||
// bring the app down ourself.
|
||||
if (!in_top_level_exception_handler) {
|
||||
if (exit_cleanly) {
|
||||
Logging::DisplayLog("root", LogLevel::kCritical, "Calling exit(1)...");
|
||||
Logging::EmitLog("root", LogLevel::kCritical, "Calling exit(1)...");
|
||||
exit(1);
|
||||
} else {
|
||||
Logging::DisplayLog("root", LogLevel::kCritical, "Calling abort()...");
|
||||
Logging::EmitLog("root", LogLevel::kCritical, "Calling abort()...");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,16 +20,16 @@ void Logging::Log(LogLevel level, const std::string& msg) {
|
||||
g_core->python->LoggingCall(level, msg);
|
||||
}
|
||||
|
||||
void Logging::DisplayLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg) {
|
||||
// Print to the in-app console (with a newline added).
|
||||
void Logging::EmitLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg) {
|
||||
// Print to the dev console.
|
||||
if (g_base_soft) {
|
||||
g_base_soft->PushDevConsolePrintCall(msg + "\n");
|
||||
}
|
||||
|
||||
// Ship to platform-specific display mechanisms (android log, etc).
|
||||
if (g_core) {
|
||||
g_core->platform->DisplayLog(name, level, msg);
|
||||
g_core->platform->EmitPlatformLog(name, level, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -29,12 +29,11 @@ class Logging {
|
||||
/// babase is imported may not be visible in the app for that same reason.
|
||||
static void Log(LogLevel level, const std::string& msg);
|
||||
|
||||
/// Immediately display a log message in the in-app console,
|
||||
/// platform-specific logs, etc. This generally should not be called
|
||||
/// directly but instead wired up to display messages coming from the
|
||||
/// Python logging system.
|
||||
static void DisplayLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg);
|
||||
/// Send a log message to the in-app console, platform-specific logs, etc.
|
||||
/// This generally should not be called directly but instead wired up to
|
||||
/// log messages coming through the Python logging system.
|
||||
static void EmitLog(const std::string& name, LogLevel level,
|
||||
const std::string& msg);
|
||||
|
||||
/// Write a message to the v1 cloud log. This is considered legacy and
|
||||
/// will be phased out eventually.
|
||||
|
||||
@ -20,7 +20,6 @@ using core::g_core;
|
||||
Object::Object() {
|
||||
#if BA_DEBUG_BUILD
|
||||
// Mark when we were born.
|
||||
// NOTE: Using core's internal globals here; don't do this normally.
|
||||
assert(g_core);
|
||||
object_birth_time_ = g_core->GetAppTimeMillisecs();
|
||||
|
||||
@ -41,7 +40,6 @@ Object::Object() {
|
||||
Object::~Object() {
|
||||
#if BA_DEBUG_BUILD
|
||||
{
|
||||
// NOTE: using core's internal globals here; don't do this normally!
|
||||
assert(g_core);
|
||||
// Pull ourself from the global obj list.
|
||||
std::scoped_lock lock(g_core->object_list_mutex);
|
||||
@ -70,6 +68,7 @@ Object::~Object() {
|
||||
#endif // BA_DEBUG_BUILD
|
||||
|
||||
// Invalidate all our weak refs.
|
||||
//
|
||||
// We could call Release() on each but we'd have to deactivate the
|
||||
// thread-check since virtual functions won't work as expected in a
|
||||
// destructor. Also we can take a few shortcuts here since we know
|
||||
@ -85,7 +84,6 @@ Object::~Object() {
|
||||
|
||||
auto Object::GetObjectTypeName() const -> std::string {
|
||||
// Default implementation just returns type name.
|
||||
// Note: using core's globals directly; don't normally do this!
|
||||
if (g_core) {
|
||||
return g_core->platform->DemangleCXXSymbol(typeid(*this).name());
|
||||
}
|
||||
@ -112,7 +110,6 @@ auto Object::GetThreadOwnership() const -> Object::ThreadOwnership {
|
||||
|
||||
void Object::LsObjects() {
|
||||
#if BA_DEBUG_BUILD
|
||||
// Note: using core's internal globals here; don't normally do this.
|
||||
assert(g_core);
|
||||
std::string s;
|
||||
{
|
||||
@ -192,12 +189,12 @@ void Object::ObjectUpdateForAcquire() {
|
||||
}
|
||||
}
|
||||
|
||||
void Object::ObjectThreadCheck() {
|
||||
void Object::ObjectThreadCheck() const {
|
||||
if (!thread_checks_enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadOwnership thread_ownership = GetThreadOwnership();
|
||||
auto thread_ownership = GetThreadOwnership();
|
||||
|
||||
// Special case; graphics context (not simply a thread so have to handle
|
||||
// specially).
|
||||
|
||||
@ -12,23 +12,26 @@
|
||||
namespace ballistica {
|
||||
|
||||
/// Objects supporting strong and weak referencing and thread enforcement.
|
||||
/// A rule or two for for Objects:
|
||||
/// Don't throw exceptions out of object destructors;
|
||||
/// This will break references to that object and lead to crashes if/when they
|
||||
/// are used.
|
||||
class Object {
|
||||
public:
|
||||
protected:
|
||||
/// Our base constructor is marked protected because we *require* Objects
|
||||
/// to be dynamically allocated. This allows us extra measures of control
|
||||
/// over their construction and destruction, and it does not seem that
|
||||
/// there is a pressing use case for a statically allocated Object that
|
||||
/// would justify diluting that control.
|
||||
Object();
|
||||
|
||||
public:
|
||||
virtual ~Object();
|
||||
|
||||
// Object classes can provide descriptive names for themselves;
|
||||
// these are used for debugging and other purposes.
|
||||
// The default is to use the C++ symbol name, demangling it when possible.
|
||||
// IMPORTANT: Do not rely on this being consistent across builds/platforms.
|
||||
// Object classes can provide descriptive names for themselves; these are
|
||||
// used for debugging and other purposes. The default is to use the C++
|
||||
// symbol name, demangling it when possible. IMPORTANT: Do not rely on
|
||||
// this being consistent across builds/platforms.
|
||||
virtual auto GetObjectTypeName() const -> std::string;
|
||||
|
||||
// Provide a brief description of this particular object; by default returns
|
||||
// type-name plus address.
|
||||
// Provide a brief description of this particular object; by default
|
||||
// returns type-name plus address.
|
||||
virtual auto GetObjectDescription() const -> std::string;
|
||||
|
||||
enum class ThreadOwnership {
|
||||
@ -42,25 +45,26 @@ class Object {
|
||||
|
||||
#if BA_DEBUG_BUILD
|
||||
|
||||
/// This is called when adding or removing a reference to an Object;
|
||||
/// it can perform sanity-tests to make sure references are not being
|
||||
/// added at incorrect times or from incorrect threads.
|
||||
/// The default implementation uses the per-object
|
||||
/// ThreadOwnership/EventLoopID values accessible below. NOTE: this
|
||||
/// check runs only in the debug build so don't add any logical side-effects!
|
||||
virtual void ObjectThreadCheck();
|
||||
/// This is called when adding or removing a reference to an Object; it
|
||||
/// can perform sanity-tests to make sure references are not being added
|
||||
/// at incorrect times or from incorrect threads. The default
|
||||
/// implementation uses the per-object ThreadOwnership/EventLoopID values
|
||||
/// accessible below.
|
||||
///
|
||||
/// NOTE: This check runs *only* in the debug build so don't include any
|
||||
/// logical side-effects in these checks!
|
||||
void ObjectThreadCheck() const;
|
||||
|
||||
#endif
|
||||
|
||||
/// Called by the default ObjectThreadCheck() to determine ThreadOwnership
|
||||
/// for an Object. The default uses the object's individual value
|
||||
/// (which defaults to ThreadOwnership::kClassDefault and can be set via
|
||||
/// SetThreadOwnership())
|
||||
/// Called by the default ObjectThreadCheck() to determine ownership for
|
||||
/// an Object. By default, an object is owned by a specific thread,
|
||||
/// defaulting to the logic thread.
|
||||
virtual auto GetThreadOwnership() const -> ThreadOwnership;
|
||||
|
||||
/// Return the exact thread to check for with ThreadOwnership::kClassDefault
|
||||
/// (in the default ObjectThreadCheck implementation at least).
|
||||
/// Default returns EventLoopID::kLogic
|
||||
/// Return the exact thread to check for with
|
||||
/// ThreadOwnership::kClassDefault (in the default ObjectThreadCheck
|
||||
/// implementation at least). Default returns EventLoopID::kLogic
|
||||
virtual auto GetDefaultOwnerThread() const -> EventLoopID;
|
||||
|
||||
/// Set thread ownership for an individual object.
|
||||
@ -73,12 +77,12 @@ class Object {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Return true if the provided obj ptr is not null, is ref-counted, and has at
|
||||
// least 1 strong ref. This is generally a good thing for calls accepting
|
||||
// object ptrs to check. It is considered bad practice to perform operations
|
||||
// with not-yet-reffed objects. Note that in some cases this may return
|
||||
// false positives, so only use this as a sanity check and only take action
|
||||
// for a negative result.
|
||||
// Return true if the provided obj ptr is not null, is ref-counted, and
|
||||
// has at least 1 strong ref. This is generally a good thing for calls
|
||||
// accepting object ptrs to check. It is considered bad practice to
|
||||
// perform operations with not-yet-reffed objects. Note that in some cases
|
||||
// this may return false positives, so only use this as a sanity check and
|
||||
// only take action for a negative result.
|
||||
static auto IsValidManagedObject(Object* obj) -> bool {
|
||||
if (!obj) {
|
||||
return false;
|
||||
@ -91,11 +95,11 @@ class Object {
|
||||
return (obj->object_strong_ref_count_ > 0);
|
||||
}
|
||||
|
||||
// Return true if the object seems to be valid and was allocated as unmanaged.
|
||||
// Code that plans to explicitly delete raw passed pointers can check this
|
||||
// for peace of mind. Note that for some build types this will return false
|
||||
// positives, so only use this as a sanity check and only take action for
|
||||
// negative results.
|
||||
// Return true if the object seems to be valid and was allocated as
|
||||
// unmanaged. Code that plans to explicitly delete raw passed pointers can
|
||||
// check this for peace of mind. Note that for some build types this will
|
||||
// return false positives, so only use this as a sanity check and only
|
||||
// take action for negative results.
|
||||
static auto IsValidUnmanagedObject(Object* obj) -> bool {
|
||||
if (!obj) {
|
||||
return false;
|
||||
@ -108,12 +112,53 @@ class Object {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
// We don't store specifics in release builds; assume everything is peachy.
|
||||
// We don't store specifics in release builds; assume everything is
|
||||
// peachy.
|
||||
return true;
|
||||
}
|
||||
|
||||
auto object_strong_ref_count() const -> int {
|
||||
return object_strong_ref_count_;
|
||||
}
|
||||
|
||||
/// Increment the strong reference count for an Object. In most cases you
|
||||
/// should let Ref objects handle this for you and not call this directly.
|
||||
void ObjectIncrementStrongRefCount() {
|
||||
#if BA_DEBUG_BUILD
|
||||
ObjectUpdateForAcquire();
|
||||
ObjectThreadCheck();
|
||||
|
||||
// Obvs shouldn't be referencing dead stuff.
|
||||
assert(!object_is_dead_);
|
||||
|
||||
// Complain if trying ot create a ref to a non-ref-counted obj.
|
||||
if (!object_is_ref_counted_) {
|
||||
FatalError("Attempting to create a strong-ref to non-refcounted obj: "
|
||||
+ GetObjectDescription());
|
||||
}
|
||||
object_has_been_strong_reffed_ = true;
|
||||
#endif // BA_DEBUG_BUILD
|
||||
|
||||
object_strong_ref_count_++;
|
||||
}
|
||||
|
||||
/// Decrement the strong reference count for the Object, deleting it if it
|
||||
/// hits zero. In most cases you should let Ref objects handle this for
|
||||
/// you and not call this directly.
|
||||
void ObjectDecrementStrongRefCount() {
|
||||
#if BA_DEBUG_BUILD
|
||||
ObjectThreadCheck();
|
||||
#endif
|
||||
assert(object_strong_ref_count_ > 0);
|
||||
object_strong_ref_count_--;
|
||||
if (object_strong_ref_count_ == 0) {
|
||||
#if BA_DEBUG_BUILD
|
||||
object_is_dead_ = true;
|
||||
#endif
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T = Object>
|
||||
class Ref;
|
||||
template <typename T = Object>
|
||||
@ -193,9 +238,8 @@ class Object {
|
||||
PyExcType::kReference);
|
||||
}
|
||||
|
||||
// Yes, reinterpret_cast is evil, but we make sure
|
||||
// we only operate on cases where this is valid
|
||||
// (see Acquire()).
|
||||
// Yes, reinterpret_cast is evil, but we make sure we only operate on
|
||||
// cases where this is valid (see Acquire()).
|
||||
return *reinterpret_cast<T*>(obj_);
|
||||
}
|
||||
|
||||
@ -207,8 +251,8 @@ class Object {
|
||||
PyExcType::kReference);
|
||||
}
|
||||
|
||||
// Yes, reinterpret_cast is evil, but we make sure we only operate
|
||||
// on cases where this is valid (see Acquire()).
|
||||
// Yes, reinterpret_cast is evil, but we make sure we only operate on
|
||||
// cases where this is valid (see Acquire()).
|
||||
return reinterpret_cast<T*>(obj_);
|
||||
}
|
||||
|
||||
@ -263,8 +307,8 @@ class Object {
|
||||
auto operator=(U* ptr) -> WeakRef<T>& {
|
||||
Release();
|
||||
|
||||
// Go through our template type instead of assigning directly
|
||||
// to our Object* so we catch invalid assigns at compile-time.
|
||||
// Go through our template type instead of assigning directly to our
|
||||
// Object* so we catch invalid assigns at compile-time.
|
||||
T* tmp = ptr;
|
||||
if (tmp) Acquire(tmp);
|
||||
|
||||
@ -295,13 +339,13 @@ class Object {
|
||||
// Default constructor.
|
||||
WeakRef() = default;
|
||||
|
||||
/// Copy constructor. Note that, by making this explicit, we require code
|
||||
/// to be a bit more verbose. For example, we can't just do 'return
|
||||
/// some_ref;' from a function and instead have to do 'return
|
||||
/// Object::WeakRef<SomeType>(some_ref)'. However I feel this extra
|
||||
/// verbosity is good; we're tossing around a mix of pointers and
|
||||
/// strong-refs and weak-refs so it's good to be aware exactly where refs
|
||||
/// are being added/etc.
|
||||
/// Copy constructor. Note that, by making this explicit, we require
|
||||
/// code to be a bit more verbose. For example, we can't just do 'return
|
||||
/// some_ref;' from a function that returns a WeakRef and instead have
|
||||
/// to do 'return Object::WeakRef<SomeType>(some_ref)'. However I feel
|
||||
/// this extra verbosity is good; we're tossing around a mix of pointers
|
||||
/// and strong-refs and weak-refs so it's good to be aware exactly where
|
||||
/// refs are being added/etc.
|
||||
explicit WeakRef(const WeakRef<T>& ref) { *this = ref.Get(); }
|
||||
|
||||
/// Create from a pointer of any compatible type.
|
||||
@ -469,13 +513,13 @@ class Object {
|
||||
/// Default constructor.
|
||||
Ref() = default;
|
||||
|
||||
/// Copy constructor. Note that, by making this explicit, we require code
|
||||
/// to be a bit more verbose. For example, we can't just do 'return
|
||||
/// some_ref;' from a function and instead have to do 'return
|
||||
/// Object::Ref<SomeType>(some_ref)'. However I feel this extra verbosity
|
||||
/// is good; we're tossing around a mix of pointers and strong-refs and
|
||||
/// weak-refs so it's good to be aware exactly where refs are being
|
||||
/// added/etc.
|
||||
/// Copy constructor. Note that, by making this explicit, we require
|
||||
/// code to be a bit more verbose. For example, we can't just do 'return
|
||||
/// some_ref;' from a function that returns a Ref and instead have to do
|
||||
/// 'return Object::Ref<SomeType>(some_ref)'. However I feel this extra
|
||||
/// verbosity is good; we're tossing around a mix of pointers and
|
||||
/// strong-refs and weak-refs so it's good to be aware exactly where
|
||||
/// refs are being added/etc.
|
||||
explicit Ref(const Ref<T>& ref) { *this = ref.Get(); }
|
||||
|
||||
/// Create from a compatible pointer.
|
||||
@ -505,42 +549,16 @@ class Object {
|
||||
PyExcType::kReference);
|
||||
}
|
||||
|
||||
#if BA_DEBUG_BUILD
|
||||
obj->ObjectUpdateForAcquire();
|
||||
obj->ObjectThreadCheck();
|
||||
|
||||
// Obvs shouldn't be referencing dead stuff.
|
||||
assert(!obj->object_is_dead_);
|
||||
|
||||
// Complain if trying ot create a ref to a non-ref-counted obj.
|
||||
if (!obj->object_is_ref_counted_) {
|
||||
FatalError("Attempting to create a strong-ref to non-refcounted obj: "
|
||||
+ obj->GetObjectDescription());
|
||||
}
|
||||
obj->object_has_been_strong_reffed_ = true;
|
||||
#endif // BA_DEBUG_BUILD
|
||||
|
||||
obj->object_strong_ref_count_++;
|
||||
obj->ObjectIncrementStrongRefCount();
|
||||
obj_ = obj;
|
||||
}
|
||||
|
||||
void Release() {
|
||||
if (obj_ != nullptr) {
|
||||
#if BA_DEBUG_BUILD
|
||||
obj_->ObjectThreadCheck();
|
||||
#endif
|
||||
assert(obj_->object_strong_ref_count_ > 0);
|
||||
obj_->object_strong_ref_count_--;
|
||||
T* tmp = obj_;
|
||||
|
||||
// Invalidate ref *before* delete to avoid potential double-release.
|
||||
auto* obj = obj_;
|
||||
// Invalidate ref *before* to avoid potential recursive-release.
|
||||
obj_ = nullptr;
|
||||
if (tmp->object_strong_ref_count_ == 0) {
|
||||
#if BA_DEBUG_BUILD
|
||||
tmp->object_is_dead_ = true;
|
||||
#endif
|
||||
delete tmp;
|
||||
}
|
||||
obj->ObjectDecrementStrongRefCount();
|
||||
}
|
||||
}
|
||||
T* obj_{};
|
||||
@ -549,10 +567,10 @@ class Object {
|
||||
/// Object::New<Type>(): The preferred way to create ref-counted Objects.
|
||||
/// Allocates a new Object with the provided args and returns a strong
|
||||
/// reference to it.
|
||||
/// Generally you pass a single type to be instantiated and returned,
|
||||
/// but you can optionally specify the two separately.
|
||||
/// (for instance you may want to create a Button but return
|
||||
/// a Ref to a Widget)
|
||||
///
|
||||
/// Generally you pass a single type to be instantiated and returned, but
|
||||
/// you can optionally specify the two separately. For example, you may
|
||||
/// want to create a Button but return a Ref to a Widget.
|
||||
template <typename TRETURN, typename TALLOC = TRETURN, typename... ARGS>
|
||||
[[nodiscard]] static auto New(ARGS&&... args) -> Object::Ref<TRETURN> {
|
||||
auto* ptr = new TALLOC(std::forward<ARGS>(args)...);
|
||||
@ -642,17 +660,19 @@ class Object {
|
||||
|
||||
private:
|
||||
#if BA_DEBUG_BUILD
|
||||
// Making operator new private here to help ensure all of our dynamic
|
||||
// allocation/deallocation goes through our special functions (New(),
|
||||
// NewDeferred(), etc.). However, sticking with original new for release
|
||||
// builds since it may handle corner cases that this does not.
|
||||
// Making operator new private here purely to help enforce all of our
|
||||
// dynamic allocation/deallocation going through our special functions
|
||||
// (New(), NewDeferred(), etc.). However, sticking with original new for
|
||||
// release builds since we don't actually intend to muck with its runtime
|
||||
// behavior and the default might be somehow smarter than ours here.
|
||||
auto operator new(size_t size) -> void* { return new char[size]; }
|
||||
void ObjectUpdateForAcquire();
|
||||
bool object_has_been_strong_reffed_{};
|
||||
bool object_is_ref_counted_{};
|
||||
bool object_is_pending_deferred_{};
|
||||
bool object_is_unmanaged_{};
|
||||
bool object_is_dead_{};
|
||||
|
||||
bool object_has_been_strong_reffed_ : 1 {};
|
||||
bool object_is_ref_counted_ : 1 {};
|
||||
bool object_is_pending_deferred_ : 1 {};
|
||||
bool object_is_unmanaged_ : 1 {};
|
||||
bool object_is_dead_ : 1 {};
|
||||
Object* object_next_{};
|
||||
Object* object_prev_{};
|
||||
ThreadOwnership thread_ownership_{ThreadOwnership::kClassDefault};
|
||||
@ -661,8 +681,8 @@ class Object {
|
||||
millisecs_t object_birth_time_{};
|
||||
bool object_printed_warning_{};
|
||||
#endif
|
||||
int object_strong_ref_count_{};
|
||||
WeakRefBase* object_weak_refs_{};
|
||||
int object_strong_ref_count_{};
|
||||
BA_DISALLOW_CLASS_COPIES(Object);
|
||||
}; // Object
|
||||
|
||||
|
||||
26
src/ballistica/shared/generic/snapshot.h
Normal file
26
src/ballistica/shared/generic/snapshot.h
Normal file
@ -0,0 +1,26 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_SHARED_GENERIC_SNAPSHOT_H_
|
||||
#define BALLISTICA_SHARED_GENERIC_SNAPSHOT_H_
|
||||
|
||||
#include "ballistica/shared/foundation/object.h"
|
||||
|
||||
namespace ballistica {
|
||||
|
||||
/// Wraps a const instance of some type in a logic-thread-owned Object. To
|
||||
/// use this, allocate some object using new(), fill it out, and pass it to
|
||||
/// this which will take ownership and expose it as a const.
|
||||
template <typename T>
|
||||
class Snapshot : public Object {
|
||||
public:
|
||||
explicit Snapshot(T* data) : data_{data} { assert(data); }
|
||||
~Snapshot() { delete data_; }
|
||||
auto* Get() const { return data_; }
|
||||
|
||||
private:
|
||||
const T* data_;
|
||||
};
|
||||
|
||||
} // namespace ballistica
|
||||
|
||||
#endif // BALLISTICA_SHARED_GENERIC_SNAPSHOT_H_
|
||||
@ -307,7 +307,7 @@ int establish_connection_(const struct Context_* ctx) {
|
||||
retry_attempt + 1);
|
||||
}
|
||||
} else if (errno == ECONNREFUSED) {
|
||||
// Am seeing this very rarely on random one-off commands. I'm
|
||||
// Am seeing these very rarely on random one-off commands. I'm
|
||||
// guessing there's some race condition at the OS level where the
|
||||
// port-file write goes through before the socket is actually truly
|
||||
// accepting connections. A retry should succeed.
|
||||
@ -318,6 +318,15 @@ int establish_connection_(const struct Context_* ctx) {
|
||||
ctx->instance_prefix, ctx->instance_num, ctx->pid,
|
||||
retry_attempt + 1);
|
||||
}
|
||||
} else if (errno == EINVAL) {
|
||||
// Saw this randomly once on Mac. Not sure what could have led to it.
|
||||
if (ctx->verbose) {
|
||||
fprintf(stderr,
|
||||
"pcommandbatch client %s_%d (pid %d): got EINVAL"
|
||||
" on connect attempt %d.\n",
|
||||
ctx->instance_prefix, ctx->instance_num, ctx->pid,
|
||||
retry_attempt + 1);
|
||||
}
|
||||
} else {
|
||||
// Currently not retrying on other errors.
|
||||
fprintf(stderr,
|
||||
|
||||
@ -983,8 +983,8 @@ class XCodeBuild:
|
||||
# on to clarify in that case (unless requested not to).
|
||||
assert self._section is not None
|
||||
sys.stdout.write(
|
||||
f'{Clr.YLW}Unexpected {self._section.value}'
|
||||
f' Output:{Clr.RST} {line}'
|
||||
f'{Clr.YLW}Unfiltered Output (Section {self._section.value}):'
|
||||
f'{Clr.RST} {line}'
|
||||
)
|
||||
else:
|
||||
sys.stdout.write(line)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user