From 11212bfb521d753a7201c30cbb2b910493596f9d Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 26 Oct 2023 19:50:46 -0700 Subject: [PATCH] lots of dev console terminal improvements --- .efrocachemap | 88 ++-- CHANGELOG.md | 5 +- ballisticakit-cmake/CMakeLists.txt | 2 + .../Generic/BallisticaKitGeneric.vcxproj | 2 + .../BallisticaKitGeneric.vcxproj.filters | 6 + .../Headless/BallisticaKitHeadless.vcxproj | 2 + .../BallisticaKitHeadless.vcxproj.filters | 6 + src/assets/ba_data/python/baenv.py | 2 +- .../base/app_adapter/app_adapter.cc | 47 -- src/ballistica/base/app_adapter/app_adapter.h | 4 +- .../base/app_adapter/app_adapter_apple.cc | 16 +- .../base/app_adapter/app_adapter_sdl.cc | 20 +- src/ballistica/base/assets/assets_server.cc | 1 - src/ballistica/base/base.cc | 8 +- src/ballistica/base/graphics/graphics.cc | 122 ++--- src/ballistica/base/graphics/graphics.h | 4 +- .../base/graphics/mesh/nine_patch_mesh.h | 2 +- .../graphics/support/graphics_settings.cc | 1 - src/ballistica/base/input/input.cc | 41 +- src/ballistica/base/platform/base_platform.cc | 65 --- src/ballistica/base/platform/base_platform.h | 16 +- .../base/support/base_build_switches.cc | 120 +++++ .../base/support/base_build_switches.h | 20 + src/ballistica/base/support/repeater.cc | 1 - src/ballistica/base/ui/dev_console.cc | 434 ++++++++++++++---- src/ballistica/base/ui/dev_console.h | 22 +- src/ballistica/scene_v1/node/flag_node.cc | 1 - .../scene_v1/support/scene_v1_app_mode.cc | 1 - src/ballistica/shared/ballistica.cc | 2 +- src/ballistica/shared/foundation/object.h | 21 +- src/ballistica/ui_v1/python/ui_v1_python.cc | 1 - src/ballistica/ui_v1/ui_v1.cc | 2 - 32 files changed, 710 insertions(+), 375 deletions(-) create mode 100644 src/ballistica/base/support/base_build_switches.cc create mode 100644 src/ballistica/base/support/base_build_switches.h diff --git a/.efrocachemap b/.efrocachemap index 374386c9..5d375637 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -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": "671499f10be5561b64b7c1e8551f71bc", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "8834461aaef9d915828b460426bb16b6", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "9be5746f3cdb8fdbeb01c3fba0f3cd04", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "1a4e1fb4230ffe937bc11890943bab67", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "809fd63da80c54076100f18c8cde6ba8", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "bb3574370f0d601abb9443dc2285689b", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "2b1d99684649040257bfe95b0c5a21d9", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "3a4eaac355dc1ed691aa946f9470fd80", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "0cdebb143458f5248efb0227e875d5d4", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "a4eae535e631ac6d0aaa3fa9203656cf", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "d2dcb9d5f1201e98ba83b547fb7a317e", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "6cf3c416280b71e5b16516cfb063b198", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "a01e3ef9ec790c0bc385995e598c18dd", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "427e518fd557950c4f8fec0b8fca3c86", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "b6a2f1c128e3b1c035eff76f38100566", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "deb872ab495ab8e713ba564b7bc4f169", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "c647c1e19b2c3a2bee028ef8215945d5", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "ce133f1e838b8b6d3b9b4fd7c516d5d8", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "f41eb8f74e5cf7a36cc8bbda1eef1933", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "00ae0c9d9351140edc42ed18b719a2bf", - "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "becf7a70c7c0d7bb5bfe731dde5e0249", - "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "c9ef036408f0832cd068a34365485e0b", - "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "becf7a70c7c0d7bb5bfe731dde5e0249", - "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "c9ef036408f0832cd068a34365485e0b", - "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "5bd8bcd68e03939501d192b7cda55d64", - "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "a8545c0c985eef9219c351773c5c6127", - "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "5bd8bcd68e03939501d192b7cda55d64", - "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "a8545c0c985eef9219c351773c5c6127", - "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "1e2c088713c47ff47d9aa312ebb0bd1a", - "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "e6bbe6c564c65cb498edc58daec1e084", - "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "1e2c088713c47ff47d9aa312ebb0bd1a", - "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "e6bbe6c564c65cb498edc58daec1e084", - "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "98df65aba607e74eb5c0c7305903ac29", - "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "2b57cf28eeadf43d09b1d780a5db1423", - "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "3314d791a9ab37ea81be824460c63d14", - "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "2b57cf28eeadf43d09b1d780a5db1423", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "eda80e0bcb2332fb400e4487aa821fda", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "ae70908e8821b275a7c62541288761c3", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "4dcc80f1087a342df7f0e13225c6a0d8", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "e83c284f0ee5c9bf9e02bdd5e83de604", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "92bbe105f7bbff92ebe621710bb13629", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "f3c9b10ab0dbc35214b20c3323255ea1", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "df9efe46d688a585157edfe5d3b9e912", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "3c76a27db96c7c277682430ec980d9ce", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "6e54cc75974a155e910b1095f8f559a8", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "d097531acccd231becb2a2b5bb1d2f23", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "35b551aae90a7d75f75237db93544279", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "d6081f21ed1100f44aeb4c36f7d28680", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "1d181331c45918c6d7e71630430aa011", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "1b7671e483412e63304755961e328d3f", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "8ee7a3b0674e89d286e6c28b5992da30", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "a2dd4ce5321e0127bdc9e7a1c4354aa6", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "d16e4cb4509fa427772c1894cc2db29d", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "7e5deafeec61b8520a4d22a5eef80f03", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "370fb623fa824ffad97750de5d1ff844", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "cf34e338f3c7d58afc70dc6742671584", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "6a075263de9be1db381eeb5ea8874ba9", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "0eef1925d2cf63eecad74e6932f624b1", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "de533e42f98a6081e96d1f7e96306fcd", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "91640f1b899fadf077d6844efdf6d37c", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "c29e6e391970ede95bd90b9dec830ecc", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "2c1391f2da73fe58a2e1a815106eebf5", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "90532e99fc87ef4a8a9b1f5d9737d008", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "a7bd331931da44fe268f4adda5cddb9b", + "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "476e9cf1fb229a023babd799a6e535f1", + "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "cf2a61fae8e8cd757864202a09e71255", + "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "476e9cf1fb229a023babd799a6e535f1", + "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "cf2a61fae8e8cd757864202a09e71255", + "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "b46b30262b58e96e994211631b470efb", + "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "6cc41e3401daf2e72b884fbfe0fe92b3", + "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "b46b30262b58e96e994211631b470efb", + "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "6cc41e3401daf2e72b884fbfe0fe92b3", + "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "b915f8a091643d99fd28e8d636063185", + "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "cb5de031162e4ff0cb5f030adf331a12", + "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "b915f8a091643d99fd28e8d636063185", + "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "cb5de031162e4ff0cb5f030adf331a12", + "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "be2a7322e1ddbb38ba0d22dd94a565e3", + "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "1920c5412307a78aa658c3366c86b7fc", + "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "b257bbc06d82fc912653806c01a42c15", + "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "1920c5412307a78aa658c3366c86b7fc", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "611631809a455737d7d9c0b04c89aa6b", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "bfe702cdf9cd260ab8cb4593afc6a3af", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "4a367d3b2354d60259cc68fa25004eb0", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "fc5d98c16dbb42846ef653dc860f4508", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "683fafa75e39f0b33ef22cff53b124e6", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "1f9099d422aaed13d038e64b629e7827", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "76ee096dfbb8993cbb05a3425e429e0a", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "719478dd5e71b7096801f6bd0b701b4f", "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": "6df0f34207346d89a72924249ddd4706", diff --git a/CHANGELOG.md b/CHANGELOG.md index c69fd5fd..65543034 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.28 (build 21516, api 8, 2023-10-26) +### 1.7.28 (build 21522, api 8, 2023-10-26) - 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 @@ -164,6 +164,9 @@ - Dev console no longer claims key events unless the Python tab is showing and there is a hardware keyboard attached. This allows showing dev console tabs above gameplay without interfering with it. +- Added clipboard paste support to the dev console python terminal. +- Added various text editing functionality to the dev console python terminal + (cursor movement, deleting chars and words, etc.) ### 1.7.27 (build 21282, api 8, 2023-08-30) diff --git a/ballisticakit-cmake/CMakeLists.txt b/ballisticakit-cmake/CMakeLists.txt index 13214011..443a6adc 100644 --- a/ballisticakit-cmake/CMakeLists.txt +++ b/ballisticakit-cmake/CMakeLists.txt @@ -436,6 +436,8 @@ set(BALLISTICA_SOURCES ${BA_SRC_ROOT}/ballistica/base/support/app_config.cc ${BA_SRC_ROOT}/ballistica/base/support/app_config.h ${BA_SRC_ROOT}/ballistica/base/support/app_timer.h + ${BA_SRC_ROOT}/ballistica/base/support/base_build_switches.cc + ${BA_SRC_ROOT}/ballistica/base/support/base_build_switches.h ${BA_SRC_ROOT}/ballistica/base/support/classic_soft.h ${BA_SRC_ROOT}/ballistica/base/support/context.cc ${BA_SRC_ROOT}/ballistica/base/support/context.h diff --git a/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj b/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj index 68e39f6f..3a4e6a25 100644 --- a/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj +++ b/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj @@ -428,6 +428,8 @@ + + diff --git a/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.filters b/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.filters index 761cf81f..90ed3d40 100644 --- a/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.filters +++ b/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.filters @@ -718,6 +718,12 @@ ballistica\base\support + + ballistica\base\support + + + ballistica\base\support + ballistica\base\support diff --git a/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj b/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj index 02f49c4b..7b5fa892 100644 --- a/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj +++ b/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj @@ -423,6 +423,8 @@ + + diff --git a/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.filters b/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.filters index 761cf81f..90ed3d40 100644 --- a/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.filters +++ b/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.filters @@ -718,6 +718,12 @@ ballistica\base\support + + ballistica\base\support + + + ballistica\base\support + ballistica\base\support diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index e58e986c..653ff56d 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -52,7 +52,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 21516 +TARGET_BALLISTICA_BUILD = 21522 TARGET_BALLISTICA_VERSION = '1.7.28' diff --git a/src/ballistica/base/app_adapter/app_adapter.cc b/src/ballistica/base/app_adapter/app_adapter.cc index bb89794f..b781b04b 100644 --- a/src/ballistica/base/app_adapter/app_adapter.cc +++ b/src/ballistica/base/app_adapter/app_adapter.cc @@ -2,64 +2,17 @@ #include "ballistica/base/app_adapter/app_adapter.h" -#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" -#include "ballistica/base/app_adapter/app_adapter_headless.h" -#include "ballistica/base/app_adapter/app_adapter_sdl.h" -#include "ballistica/base/app_adapter/app_adapter_vr.h" -#include "ballistica/base/graphics/graphics_server.h" #include "ballistica/base/graphics/renderer/renderer.h" #include "ballistica/base/input/input.h" #include "ballistica/base/networking/network_reader.h" #include "ballistica/base/networking/networking.h" -#include "ballistica/base/platform/base_platform.h" #include "ballistica/base/python/base_python.h" #include "ballistica/base/support/app_config.h" -#include "ballistica/base/support/stress_test.h" #include "ballistica/base/ui/ui.h" #include "ballistica/shared/foundation/event_loop.h" -#include "ballistica/shared/python/python.h" namespace ballistica::base { -auto AppAdapter::Create() -> AppAdapter* { - assert(g_core); - -// TEMP - need to init sdl on our legacy mac build even though its not -// technically an SDL app. Kill this once the old mac build is gone. -#if BA_LEGACY_MACOS_BUILD - AppAdapterSDL::InitSDL(); -#endif - - AppAdapter* app_adapter{}; - -#if BA_HEADLESS_BUILD - app_adapter = new AppAdapterHeadless(); -#elif BA_OSTYPE_ANDROID - app_adapter = new AppAdapterAndroid(); -#elif BA_XCODE_BUILD - app_adapter = new AppAdapterApple(); -#elif BA_RIFT_BUILD - // Rift build can spin up in either VR or regular mode. - if (g_core->vr_mode) { - app_adapter = new AppAdapterVR(); - } else { - app_adapter = new AppAdapterSDL(); - } -#elif BA_CARDBOARD_BUILD - app_adapter = new AppAdapterVR(); -#elif BA_SDL_BUILD - app_adapter = new AppAdapterSDL(); -#else -#error No app adapter defined for this build. -#endif - - assert(app_adapter); - return app_adapter; -} - AppAdapter::AppAdapter() = default; AppAdapter::~AppAdapter() = default; diff --git a/src/ballistica/base/app_adapter/app_adapter.h b/src/ballistica/base/app_adapter/app_adapter.h index e32864bb..6570d8a4 100644 --- a/src/ballistica/base/app_adapter/app_adapter.h +++ b/src/ballistica/base/app_adapter/app_adapter.h @@ -15,8 +15,7 @@ namespace ballistica::base { /// all might share the same CorePlatform and BasePlatform classes. class AppAdapter { public: - /// Instantiate the AppAdapter subclass for the current build. - static auto Create() -> AppAdapter*; + AppAdapter(); /// Called in the main thread when the app is being started. virtual void OnMainThreadStartApp(); @@ -224,7 +223,6 @@ class AppAdapter { auto ClipboardGetText() -> std::string; protected: - AppAdapter(); virtual ~AppAdapter(); /// Push a raw pointer Runnable to the platform's 'main' thread. The main diff --git a/src/ballistica/base/app_adapter/app_adapter_apple.cc b/src/ballistica/base/app_adapter/app_adapter_apple.cc index 17ac5c8a..0e5ae5f7 100644 --- a/src/ballistica/base/app_adapter/app_adapter_apple.cc +++ b/src/ballistica/base/app_adapter/app_adapter_apple.cc @@ -247,38 +247,38 @@ auto AppAdapterApple::GetKeyRepeatInterval() -> float { } auto AppAdapterApple::DoClipboardIsSupported() -> bool { -#if BA_XCODE_BUILD +#if BA_OSTYPE_MACOS return BallisticaKit::CocoaFromCpp::ClipboardIsSupported(); #else - return CorePlatform::DoClipboardIsSupported(); + return AppAdapter::DoClipboardIsSupported(); #endif } auto AppAdapterApple::DoClipboardHasText() -> bool { -#if BA_XCODE_BUILD +#if BA_OSTYPE_MACOS return BallisticaKit::CocoaFromCpp::ClipboardHasText(); #else - return CorePlatform::DoClipboardHasText(); + return AppAdapter::DoClipboardHasText(); #endif } void AppAdapterApple::DoClipboardSetText(const std::string& text) { -#if BA_XCODE_BUILD +#if BA_OSTYPE_MACOS BallisticaKit::CocoaFromCpp::ClipboardSetText(text); #else - CorePlatform::DoClipboardSetText(text); + AppAdapter::DoClipboardSetText(text); #endif } auto AppAdapterApple::DoClipboardGetText() -> std::string { -#if BA_XCODE_BUILD +#if BA_OSTYPE_MACOS auto contents = BallisticaKit::CocoaFromCpp::ClipboardGetText(); if (contents) { return std::string(contents.get()); } throw Exception("No text on clipboard."); #else - return CorePlatform::DoClipboardGetText(); + return AppAdapter::DoClipboardGetText(); #endif } diff --git a/src/ballistica/base/app_adapter/app_adapter_sdl.cc b/src/ballistica/base/app_adapter/app_adapter_sdl.cc index 3d7e8ca0..5c432800 100644 --- a/src/ballistica/base/app_adapter/app_adapter_sdl.cc +++ b/src/ballistica/base/app_adapter/app_adapter_sdl.cc @@ -807,23 +807,9 @@ void AppAdapterSDL::CursorPositionForDraw(float* x, float* y) { auto AppAdapterSDL::FullscreenControlAvailable() const -> bool { return true; } auto AppAdapterSDL::FullscreenControlKeyShortcut() const -> std::optional { - if (g_buildconfig.ostype_windows()) { - // On Windows we support F11 and Alt+Enter to toggle fullscreen. Let's - // mention Alt+Enter which seems like it might be more commonly used - return "Alt+Enter"; - } - if (g_buildconfig.ostype_macos()) { - // The Mac+SDL situation is a bit of a mess. By default, there is 'Enter - // Full Screen' in the window menu which is mapped to fn-F, but that - // will only work if a window was created in SDL as windowed. If we - // fullscreen that window and restart the app, we'll then have a *real* - // fullscreen sdl window and that shortcut won't work anymore. So to - // keep things consistent we advertise ctrl-f which we always handle - // ourselves. Maybe this situation will be cleaned up in SDL 3, but its - // not a huge deal anyway since our Cocoa Mac version behaves cleanly. - return "Ctrl+F"; - } - return {}; + // On our SDL build we support F11 and Alt+Enter to toggle fullscreen. + // Let's mention Alt+Enter which seems like it might be more commonly used + return "Alt+Enter"; }; auto AppAdapterSDL::SupportsVSync() -> bool const { return true; } diff --git a/src/ballistica/base/assets/assets_server.cc b/src/ballistica/base/assets/assets_server.cc index 102c6027..9c89f00e 100644 --- a/src/ballistica/base/assets/assets_server.cc +++ b/src/ballistica/base/assets/assets_server.cc @@ -5,7 +5,6 @@ #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" diff --git a/src/ballistica/base/base.cc b/src/ballistica/base/base.cc index b7e4abb3..2871e6ac 100644 --- a/src/ballistica/base/base.cc +++ b/src/ballistica/base/base.cc @@ -20,12 +20,12 @@ #include "ballistica/base/python/class/python_class_feature_set_data.h" #include "ballistica/base/python/support/python_context_call.h" #include "ballistica/base/support/app_config.h" +#include "ballistica/base/support/base_build_switches.h" #include "ballistica/base/support/huffman.h" #include "ballistica/base/support/plus_soft.h" #include "ballistica/base/support/stdio_console.h" #include "ballistica/base/support/stress_test.h" #include "ballistica/base/ui/dev_console.h" -#include "ballistica/base/ui/ui.h" #include "ballistica/base/ui/ui_delegate.h" #include "ballistica/core/python/core_python.h" #include "ballistica/shared/foundation/event_loop.h" @@ -39,7 +39,7 @@ core::CoreFeatureSet* g_core{}; BaseFeatureSet* g_base{}; BaseFeatureSet::BaseFeatureSet() - : app_adapter{AppAdapter::Create()}, + : app_adapter{BaseBuildSwitches::CreateAppAdapter()}, app_config{new AppConfig()}, app_mode_{AppModeEmpty::GetSingleton()}, assets{new Assets()}, @@ -51,7 +51,7 @@ BaseFeatureSet::BaseFeatureSet() bg_dynamics_server{g_core->HeadlessMode() ? nullptr : new BGDynamicsServer}, context_ref{new ContextRef(nullptr)}, - graphics{Graphics::Create()}, + graphics{BaseBuildSwitches::CreateGraphics()}, graphics_server{new GraphicsServer()}, huffman{new Huffman()}, input{new Input()}, @@ -59,7 +59,7 @@ BaseFeatureSet::BaseFeatureSet() network_reader{new NetworkReader()}, network_writer{new NetworkWriter()}, networking{new Networking()}, - platform{BasePlatform::Create()}, + platform{BaseBuildSwitches::CreatePlatform()}, python{new BasePython()}, stdio_console{g_buildconfig.enable_stdio_console() ? new StdioConsole() : nullptr}, diff --git a/src/ballistica/base/graphics/graphics.cc b/src/ballistica/base/graphics/graphics.cc index 7f405a9d..7bc51e39 100644 --- a/src/ballistica/base/graphics/graphics.cc +++ b/src/ballistica/base/graphics/graphics.cc @@ -5,28 +5,23 @@ #include "ballistica/base/app_adapter/app_adapter.h" #include "ballistica/base/app_mode/app_mode.h" #include "ballistica/base/dynamics/bg/bg_dynamics.h" -#include "ballistica/base/graphics/component/empty_component.h" #include "ballistica/base/graphics/component/object_component.h" #include "ballistica/base/graphics/component/post_process_component.h" #include "ballistica/base/graphics/component/simple_component.h" #include "ballistica/base/graphics/component/special_component.h" #include "ballistica/base/graphics/component/sprite_component.h" #include "ballistica/base/graphics/graphics_server.h" -#include "ballistica/base/graphics/graphics_vr.h" +#include "ballistica/base/graphics/mesh/nine_patch_mesh.h" #include "ballistica/base/graphics/support/camera.h" #include "ballistica/base/graphics/support/net_graph.h" #include "ballistica/base/graphics/text/text_graphics.h" #include "ballistica/base/input/input.h" #include "ballistica/base/logic/logic.h" -#include "ballistica/base/platform/base_platform.h" #include "ballistica/base/python/support/python_context_call.h" #include "ballistica/base/support/app_config.h" -#include "ballistica/base/ui/dev_console.h" #include "ballistica/base/ui/ui.h" -#include "ballistica/core/core.h" #include "ballistica/shared/foundation/event_loop.h" #include "ballistica/shared/generic/utils.h" -#include "ballistica/shared/python/python.h" namespace ballistica::base { @@ -36,14 +31,6 @@ const float kProgressBarZDepth{0.0f}; const int kProgressBarFadeTime{500}; const float kDebugImgZDepth{-0.04f}; -auto Graphics::Create() -> Graphics* { -#if BA_VR_BUILD - return new GraphicsVR(); -#else - return new Graphics(); -#endif -} - auto Graphics::IsShaderTransparent(ShadingType c) -> bool { switch (c) { case ShadingType::kSimpleColorTransparent: @@ -231,11 +218,9 @@ auto Graphics::VSyncFromAppConfig() -> VSyncRequest { } auto Graphics::GraphicsQualityFromAppConfig() -> GraphicsQualityRequest { - // Graphics quality. std::string gqualstr = g_base->app_config->Resolve(AppConfig::StringID::kGraphicsQuality); GraphicsQualityRequest graphics_quality_requested; - if (gqualstr == "Auto") { graphics_quality_requested = GraphicsQualityRequest::kAuto; } else if (gqualstr == "Higher") { @@ -361,33 +346,36 @@ auto Graphics::GetShadowDensity(float x, float y, float z) -> float { class Graphics::ScreenMessageEntry { public: - ScreenMessageEntry(std::string s_in, bool align_left_in, uint32_t c, - const Vector3f& color_in, TextureAsset* texture_in, - TextureAsset* tint_texture_in, const Vector3f& tint_in, - const Vector3f& tint2_in) - : align_left(align_left_in), + ScreenMessageEntry(std::string text, bool top_style, uint32_t c, + const Vector3f& color, TextureAsset* texture, + TextureAsset* tint_texture, const Vector3f& tint, + const Vector3f& tint2) + : top_style(top_style), creation_time(c), - s_raw(std::move(s_in)), - color(color_in), - texture(texture_in), - tint_texture(tint_texture_in), - tint(tint_in), - tint2(tint2_in) {} + s_raw(std::move(text)), + color(color), + texture(texture), + tint_texture(tint_texture), + tint(tint), + tint2(tint2) {} auto GetText() -> TextGroup&; void UpdateTranslation(); - bool align_left; + bool top_style; uint32_t creation_time; Vector3f color; Vector3f tint; Vector3f tint2; std::string s_raw; std::string s_translated; + float str_width{}; + float str_height{}; Object::Ref texture; Object::Ref tint_texture; float v_smoothed{}; bool translation_dirty{true}; bool mesh_dirty{true}; millisecs_t smooth_time{}; + Object::Ref shadow_mesh_; private: Object::Ref s_mesh_; @@ -578,7 +566,8 @@ void Graphics::DrawMiscOverlays(FrameDef* frame_def) { SimpleComponent c(pass); c.SetTransparent(true); c.SetTexture( - g_base->assets->SysTexture(SysTextureID::kSoftRectVertical)); + // g_base->assets->SysTexture(SysTextureID::kSoftRectVertical)); + g_base->assets->SysTexture(SysTextureID::kShadowSharp)); float screen_width = g_base->graphics->screen_virtual_width(); @@ -591,6 +580,10 @@ void Graphics::DrawMiscOverlays(FrameDef* frame_def) { // Update the translation if need be. i->UpdateTranslation(); + // Don't actually need the text just yet but need shadow mesh + // which is calculated as part of it. + i->GetText(); + millisecs_t age = g_core->GetAppTimeMillisecs() - i->creation_time; youngest_age = std::min(youngest_age, age); float s_extra = 1.0f; @@ -609,9 +602,9 @@ void Graphics::DrawMiscOverlays(FrameDef* frame_def) { } a *= 0.8f; - if (vr) { - a *= 0.8f; - } + // if (vr) { + // a *= 0.8f; + // } if (i->translation_dirty) { BA_LOG_ONCE( @@ -619,10 +612,9 @@ void Graphics::DrawMiscOverlays(FrameDef* frame_def) { "Found dirty translation on screenmessage draw pass 1; raw=" + i->s_raw); } - float str_height = - g_base->text_graphics->GetStringHeight(i->s_translated.c_str()); - float str_width = - g_base->text_graphics->GetStringWidth(i->s_translated.c_str()); + + float str_height = i->str_height; + float str_width = i->str_width; if ((str_width * scale) > (screen_width - 40)) { s_extra *= ((screen_width - 40) / (str_width * scale)); @@ -639,7 +631,7 @@ void Graphics::DrawMiscOverlays(FrameDef* frame_def) { if (age < 100) { fade = 1.0f; } else { - fade = std::max(0.0f, (200.0f - static_cast(age)) / 100.0f); + fade = std::max(0.07f, (200.0f - static_cast(age)) / 100.0f); } c.SetColor(r * fade, g * fade, b * fade, a); @@ -663,22 +655,28 @@ void Graphics::DrawMiscOverlays(FrameDef* frame_def) { c.Translate(screen_width * 0.5f, i->v_smoothed, vr ? 60 : kScreenMessageZDepth); - if (vr) { - // Let's drop down a bit in vr mode. - c.Translate(0, -10.0f, 0); - c.Scale((str_width + 60) * scale * s_extra, - (str_height + 20) * scale * s_extra); - // Align our bottom with where we just scaled from. - c.Translate(0, 0.5f, 0); - } else { - c.Scale((str_width + 110) * scale * s_extra, - (str_height + 40) * scale * s_extra); + // if (vr) { + // // Let's drop down a bit in vr mode. + // // c.Translate(0, -10.0f, 0); + // // c.Scale((str_width + 60) * scale * s_extra, + // // (str_height + 20) * scale * s_extra); + // c.Scale(scale * s_extra, scale * s_extra); + + // // Align our bottom with where we just scaled from. + // c.Translate(0, 0.5f, 0); + { + // c.Scale((str_width + 110) * scale * s_extra, + // (str_height + 40) * scale * s_extra); + c.Scale(scale * s_extra, scale * s_extra); + c.Translate(0, 20); // Align our bottom with where we just scaled from. c.Translate(0, 0.5f, 0); } - c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kImage1x1)); + // c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kImage1x1)); + assert(i->shadow_mesh_.Exists()); + c.DrawMesh(i->shadow_mesh_.Get()); } v += scale * (36 + str_height); @@ -721,10 +719,8 @@ void Graphics::DrawMiscOverlays(FrameDef* frame_def) { "Found dirty translation on screenmessage draw pass 2; raw=" + i->s_raw); } - float str_height = - g_base->text_graphics->GetStringHeight(i->s_translated.c_str()); - float str_width = - g_base->text_graphics->GetStringWidth(i->s_translated.c_str()); + float str_height = i->str_height; + float str_width = i->str_width; if ((str_width * scale) > (screen_width - 40)) { s_extra *= ((screen_width - 40) / (str_width * scale)); @@ -1964,8 +1960,28 @@ auto Graphics::ScreenMessageEntry::GetText() -> TextGroup& { if (mesh_dirty) { s_mesh_->SetText( s_translated, - align_left ? TextMesh::HAlign::kLeft : TextMesh::HAlign::kCenter, + top_style ? TextMesh::HAlign::kLeft : TextMesh::HAlign::kCenter, TextMesh::VAlign::kBottom); + + str_width = g_base->text_graphics->GetStringWidth(s_translated.c_str()); + str_height = g_base->text_graphics->GetStringHeight(s_translated.c_str()); + + if (!top_style) { + float x_extend = 40.0f; + float y_extend = 40.0f; + float y_offset = -10.0f; + float corner_radius = 60.0f; + float width_fin = str_width + x_extend * 2.0f; + float height_fin = str_height + y_extend * 2.0f; + float x_border = + NinePatchMesh::BorderForRadius(corner_radius, width_fin, height_fin); + float y_border = + NinePatchMesh::BorderForRadius(corner_radius, height_fin, width_fin); + shadow_mesh_ = Object::New( + -0.5f * width_fin, -y_extend + y_offset, 0.0f, width_fin, height_fin, + x_border, y_border, x_border, y_border); + } + mesh_dirty = false; } return *s_mesh_; diff --git a/src/ballistica/base/graphics/graphics.h b/src/ballistica/base/graphics/graphics.h index 4c244dd3..1e9736ed 100644 --- a/src/ballistica/base/graphics/graphics.h +++ b/src/ballistica/base/graphics/graphics.h @@ -53,8 +53,7 @@ const float kCursorZDepth{0.9f}; // Client class for graphics operations (used from the logic thread). class Graphics { public: - /// Instantiate the Graphics subclass for the current build. - static auto Create() -> Graphics*; + Graphics(); void OnAppStart(); void OnAppPause(); @@ -370,7 +369,6 @@ class Graphics { protected: class ScreenMessageEntry; - Graphics(); virtual ~Graphics(); virtual void DoDrawFade(FrameDef* frame_def, float amt); static void CalcVirtualRes_(float* x, float* y); diff --git a/src/ballistica/base/graphics/mesh/nine_patch_mesh.h b/src/ballistica/base/graphics/mesh/nine_patch_mesh.h index fad02593..64b6638d 100644 --- a/src/ballistica/base/graphics/mesh/nine_patch_mesh.h +++ b/src/ballistica/base/graphics/mesh/nine_patch_mesh.h @@ -18,7 +18,7 @@ class NinePatchMesh : public MeshIndexedSimpleFull { /// Calculate a border value for a NinePatchMesh based on dimensions and a /// desired max corner radius. For calculating left or right borders, - /// matching_dimension should be width and other_dimension should be + /// `matching_dimension` should be width and `other_dimension` should be /// height. For top or bottom borders it is the opposite. static auto BorderForRadius(float corner_radius, float matching_dimension, float other_dimension) -> float { diff --git a/src/ballistica/base/graphics/support/graphics_settings.cc b/src/ballistica/base/graphics/support/graphics_settings.cc index a132fe88..fd2a5ed0 100644 --- a/src/ballistica/base/graphics/support/graphics_settings.cc +++ b/src/ballistica/base/graphics/support/graphics_settings.cc @@ -6,7 +6,6 @@ #include "ballistica/base/graphics/graphics.h" #include "ballistica/base/support/app_config.h" -#include "ballistica/shared/foundation/object.h" namespace ballistica::base { diff --git a/src/ballistica/base/input/input.cc b/src/ballistica/base/input/input.cc index bbde01f1..4a983659 100644 --- a/src/ballistica/base/input/input.cc +++ b/src/ballistica/base/input/input.cc @@ -12,10 +12,8 @@ #include "ballistica/base/input/device/touch_input.h" #include "ballistica/base/logic/logic.h" #include "ballistica/base/python/base_python.h" -#include "ballistica/base/support/app_config.h" #include "ballistica/base/ui/dev_console.h" #include "ballistica/base/ui/ui.h" -#include "ballistica/shared/buildconfig/buildconfig_common.h" #include "ballistica/shared/foundation/event_loop.h" #include "ballistica/shared/generic/utils.h" @@ -838,6 +836,13 @@ void Input::PushTextInputEvent(const std::string& text) { return; } + // Ignore back-tick and tilde because we use that key to toggle the console. + // FIXME: Perhaps should allow typing it if some control-character is + // held? + if (text == "`" || text == "~") { + return; + } + // We try to handle char filtering here (to keep it consistent across // platforms) but make a stink if they sent us something that we can't // at least translate to unicode. @@ -1065,17 +1070,9 @@ void Input::HandleKeyPress_(const SDL_Keysym& keysym) { // Explicitly handle fullscreen-toggles in some cases. if (g_base->app_adapter->FullscreenControlAvailable()) { bool do_toggle{}; - // On our Mac SDL builds we support ctrl+F for toggling fullscreen. - // On our nice Cocoa build, fullscreening happens magically through the - // view menu fullscreen control's shortcut. - if (g_buildconfig.ostype_macos() && !g_buildconfig.xcode_build()) { - if (keysym.sym == SDLK_f && ((keysym.mod & KMOD_CTRL))) { - do_toggle = true; - } - } - // On Windows and Linux we support both F11 and Alt+Enter for toggling + // On our SDL builds we support both F11 and Alt+Enter for toggling // fullscreen. - if (g_buildconfig.ostype_windows() || g_buildconfig.ostype_linux()) { + if (g_buildconfig.sdl_build()) { if ((keysym.sym == SDLK_F11 || (keysym.sym == SDLK_RETURN && ((keysym.mod & KMOD_ALT))))) { do_toggle = true; @@ -1089,6 +1086,19 @@ void Input::HandleKeyPress_(const SDL_Keysym& keysym) { } } + // Ctrl-V or Cmd-V sends paste commands to the console or any interested + // text fields. + if (keysym.sym == SDLK_v + && ((keysym.mod & KMOD_CTRL) || (keysym.mod & KMOD_GUI))) { + if (auto* console = g_base->ui->dev_console()) { + if (console->PasteFromClipboard()) { + return; + } + } + g_base->ui->SendWidgetMessage(WidgetMessage(WidgetMessage::Type::kPaste)); + return; + } + // Dev Console. if (auto* console = g_base->ui->dev_console()) { if (keysym.sym == SDLK_BACKQUOTE || keysym.sym == SDLK_F2) { @@ -1102,13 +1112,6 @@ void Input::HandleKeyPress_(const SDL_Keysym& keysym) { } } - // Ctrl-V or Cmd-V sends paste commands to any interested text fields. - if (keysym.sym == SDLK_v - && ((keysym.mod & KMOD_CTRL) || (keysym.mod & KMOD_GUI))) { - g_base->ui->SendWidgetMessage(WidgetMessage(WidgetMessage::Type::kPaste)); - return; - } - bool handled = false; switch (keysym.sym) { diff --git a/src/ballistica/base/platform/base_platform.cc b/src/ballistica/base/platform/base_platform.cc index 9be958c2..75eb59c8 100644 --- a/src/ballistica/base/platform/base_platform.cc +++ b/src/ballistica/base/platform/base_platform.cc @@ -16,73 +16,8 @@ #include "ballistica/shared/python/python.h" #include "ballistica/shared/python/python_sys.h" -// ------------------------- PLATFORM SELECTION -------------------------------- - -// This ugly chunk of macros simply pulls in the correct platform class header -// for each platform and defines the actual class g_base->platform will be. - -// Android --------------------------------------------------------------------- - -#if BA_OSTYPE_ANDROID -#if BA_GOOGLE_BUILD -#include "ballistica/base/platform/android/google/base_plat_andr_google.h" -#define BA_PLATFORM_CLASS BasePlatformAndroidGoogle -#elif BA_AMAZON_BUILD -#include "ballistica/base/platform/android/amazon/base_plat_andr_amazon.h" -#define BA_PLATFORM_CLASS BasePlatformAndroidAmazon -#elif BA_CARDBOARD_BUILD -#include "ballistica/base/platform/android/cardboard/base_pl_an_cardboard.h" -#define BA_PLATFORM_CLASS BasePlatformAndroidCardboard -#else // Generic android. -#include "ballistica/base/platform/android/base_platform_android.h" -#define BA_PLATFORM_CLASS BasePlatformAndroid -#endif // (Android subplatform) - -// Apple ----------------------------------------------------------------------- - -#elif BA_OSTYPE_MACOS || BA_OSTYPE_IOS_TVOS -#include "ballistica/base/platform/apple/base_platform_apple.h" -#define BA_PLATFORM_CLASS BasePlatformApple - -// Windows --------------------------------------------------------------------- - -#elif BA_OSTYPE_WINDOWS -#if BA_RIFT_BUILD -#include "ballistica/base/platform/windows/base_platform_windows_oculus.h" -#define BA_PLATFORM_CLASS BasePlatformWindowsOculus -#else // generic windows -#include "ballistica/base/platform/windows/base_platform_windows.h" -#define BA_PLATFORM_CLASS BasePlatformWindows -#endif // windows subtype - -// Linux ----------------------------------------------------------------------- - -#elif BA_OSTYPE_LINUX -#include "ballistica/base/platform/linux/base_platform_linux.h" -#define BA_PLATFORM_CLASS BasePlatformLinux -#else - -// Generic --------------------------------------------------------------------- - -#define BA_PLATFORM_CLASS BasePlatform - -#endif - -// ----------------------- END PLATFORM SELECTION ------------------------------ - -#ifndef BA_PLATFORM_CLASS -#error no BA_PLATFORM_CLASS defined for this platform -#endif - namespace ballistica::base { -auto BasePlatform::Create() -> BasePlatform* { - auto platform = new BA_PLATFORM_CLASS(); - platform->PostInit(); - assert(platform->ran_base_post_init_); - return platform; -} - BasePlatform::BasePlatform() = default; void BasePlatform::PostInit() { diff --git a/src/ballistica/base/platform/base_platform.h b/src/ballistica/base/platform/base_platform.h index 85d19b39..63e1b043 100644 --- a/src/ballistica/base/platform/base_platform.h +++ b/src/ballistica/base/platform/base_platform.h @@ -15,8 +15,12 @@ namespace ballistica::base { /// with a single platform (Windows, Mac, etc.). class BasePlatform { public: - /// Instantiate the CorePlatform subclass for the current build. - static auto Create() -> BasePlatform*; + BasePlatform(); + + /// Called after our singleton has been instantiated. Any construction + /// functionality requiring virtual functions resolving to their final + /// class versions can go here. + virtual void PostInit(); #pragma mark APP EVENTS / LIFECYCLE -------------------------------------------- @@ -95,6 +99,8 @@ class BasePlatform { /// Must be called in the logic thread. void StringEditorCancel(); + auto ran_base_post_init() const { return ran_base_post_init_; } + protected: /// Pop up a text edit dialog. virtual void DoInvokeStringEditor(const std::string& title, @@ -107,15 +113,9 @@ class BasePlatform { /// Make a purchase. virtual void DoPurchase(const std::string& item); - BasePlatform(); virtual ~BasePlatform(); private: - /// Called after our singleton has been instantiated. Any construction - /// functionality requiring virtual functions resolving to their final - /// class versions can go here. - virtual void PostInit(); - bool ran_base_post_init_ : 1 {}; PythonRef string_edit_adapter_{}; std::string public_device_uuid_; diff --git a/src/ballistica/base/support/base_build_switches.cc b/src/ballistica/base/support/base_build_switches.cc new file mode 100644 index 00000000..96abc907 --- /dev/null +++ b/src/ballistica/base/support/base_build_switches.cc @@ -0,0 +1,120 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/base/support/base_build_switches.h" + +#if BA_OSTYPE_ANDROID +#include "ballistica/base/app_adapter/app_adapter_android.h" +#endif +#include "ballistica/base/app_adapter/app_adapter_apple.h" +#include "ballistica/base/app_adapter/app_adapter_headless.h" +#include "ballistica/base/app_adapter/app_adapter_sdl.h" +#include "ballistica/base/app_adapter/app_adapter_vr.h" +#include "ballistica/base/graphics/graphics.h" +#include "ballistica/base/graphics/graphics_vr.h" + +// ------------------------- PLATFORM SELECTION -------------------------------- + +// This ugly chunk of macros simply pulls in the correct platform class header +// for each platform and defines the actual class g_base->platform will be. + +// Android --------------------------------------------------------------------- + +#if BA_OSTYPE_ANDROID +#if BA_GOOGLE_BUILD +#include "ballistica/base/platform/android/google/base_plat_andr_google.h" +#define BA_PLATFORM_CLASS BasePlatformAndroidGoogle +#elif BA_AMAZON_BUILD +#include "ballistica/base/platform/android/amazon/base_plat_andr_amazon.h" +#define BA_PLATFORM_CLASS BasePlatformAndroidAmazon +#elif BA_CARDBOARD_BUILD +#include "ballistica/base/platform/android/cardboard/base_pl_an_cardboard.h" +#define BA_PLATFORM_CLASS BasePlatformAndroidCardboard +#else // Generic android. +#include "ballistica/base/platform/android/base_platform_android.h" +#define BA_PLATFORM_CLASS BasePlatformAndroid +#endif // (Android subplatform) + +// Apple ----------------------------------------------------------------------- + +#elif BA_OSTYPE_MACOS || BA_OSTYPE_IOS_TVOS +#include "ballistica/base/platform/apple/base_platform_apple.h" +#define BA_PLATFORM_CLASS BasePlatformApple + +// Windows --------------------------------------------------------------------- + +#elif BA_OSTYPE_WINDOWS +#if BA_RIFT_BUILD +#include "ballistica/base/platform/windows/base_platform_windows_oculus.h" +#define BA_PLATFORM_CLASS BasePlatformWindowsOculus +#else // generic windows +#include "ballistica/base/platform/windows/base_platform_windows.h" +#define BA_PLATFORM_CLASS BasePlatformWindows +#endif // windows subtype + +// Linux ----------------------------------------------------------------------- + +#elif BA_OSTYPE_LINUX +#include "ballistica/base/platform/linux/base_platform_linux.h" +#define BA_PLATFORM_CLASS BasePlatformLinux +#else + +// Generic --------------------------------------------------------------------- + +#define BA_PLATFORM_CLASS BasePlatform + +#endif + +// ----------------------- END PLATFORM SELECTION ------------------------------ + +#ifndef BA_PLATFORM_CLASS +#error no BA_PLATFORM_CLASS defined for this platform +#endif + +namespace ballistica::base { + +auto BaseBuildSwitches::CreatePlatform() -> BasePlatform* { + auto platform = new BA_PLATFORM_CLASS(); + platform->PostInit(); + assert(platform->ran_base_post_init()); + return platform; +} + +auto BaseBuildSwitches::CreateGraphics() -> Graphics* { +#if BA_VR_BUILD + return new GraphicsVR(); +#else + return new Graphics(); +#endif +} + +auto BaseBuildSwitches::CreateAppAdapter() -> AppAdapter* { + assert(g_core); + + AppAdapter* app_adapter{}; + +#if BA_HEADLESS_BUILD + app_adapter = new AppAdapterHeadless(); +#elif BA_OSTYPE_ANDROID + app_adapter = new AppAdapterAndroid(); +#elif BA_XCODE_BUILD + app_adapter = new AppAdapterApple(); +#elif BA_RIFT_BUILD + // Rift build can spin up in either VR or regular mode. + if (g_core->vr_mode) { + app_adapter = new AppAdapterVR(); + } else { + app_adapter = new AppAdapterSDL(); + } +#elif BA_CARDBOARD_BUILD + app_adapter = new AppAdapterVR(); +#elif BA_SDL_BUILD + app_adapter = new AppAdapterSDL(); +#else +#error No app adapter defined for this build. +#endif + + assert(app_adapter); + return app_adapter; +} + +} // namespace ballistica::base diff --git a/src/ballistica/base/support/base_build_switches.h b/src/ballistica/base/support/base_build_switches.h new file mode 100644 index 00000000..ea5b4ba4 --- /dev/null +++ b/src/ballistica/base/support/base_build_switches.h @@ -0,0 +1,20 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_BASE_SUPPORT_BASE_BUILD_SWITCHES_H_ +#define BALLISTICA_BASE_SUPPORT_BASE_BUILD_SWITCHES_H_ + +#include "ballistica/base/base.h" + +namespace ballistica::base { + +/// Constructs various app components based on the current build config. +class BaseBuildSwitches { + public: + static auto CreateGraphics() -> Graphics*; + static auto CreatePlatform() -> BasePlatform*; + static auto CreateAppAdapter() -> AppAdapter*; +}; + +} // namespace ballistica::base + +#endif // BALLISTICA_BASE_SUPPORT_BASE_BUILD_SWITCHES_H_ diff --git a/src/ballistica/base/support/repeater.cc b/src/ballistica/base/support/repeater.cc index 1593da15..c7d58d5e 100644 --- a/src/ballistica/base/support/repeater.cc +++ b/src/ballistica/base/support/repeater.cc @@ -2,7 +2,6 @@ #include "ballistica/base/support/repeater.h" -#include "ballistica/base/app_adapter/app_adapter.h" #include "ballistica/base/support/app_timer.h" #include "ballistica/shared/foundation/event_loop.h" diff --git a/src/ballistica/base/ui/dev_console.cc b/src/ballistica/base/ui/dev_console.cc index f0ac5365..6940c271 100644 --- a/src/ballistica/base/ui/dev_console.cc +++ b/src/ballistica/base/ui/dev_console.cc @@ -8,7 +8,6 @@ #include "ballistica/base/graphics/component/simple_component.h" #include "ballistica/base/graphics/mesh/nine_patch_mesh.h" #include "ballistica/base/graphics/text/text_graphics.h" -#include "ballistica/base/input/input.h" #include "ballistica/base/logic/logic.h" #include "ballistica/base/platform/base_platform.h" #include "ballistica/base/python/base_python.h" @@ -85,6 +84,11 @@ static auto XOffs(DevConsoleHAnchor_ attach) -> float { return 0.0f; } +static auto IsValidHungryChar_(uint32_t this_char) -> bool { + return ((this_char >= 65 && this_char <= 90) + || (this_char >= 97 && this_char <= 122)); +} + static void DrawRect(RenderPass* pass, Mesh* mesh, float bottom, float x, float y, float width, float height, const Vector3f& bgcolor) { @@ -677,6 +681,11 @@ void DevConsole::set_input_string(const std::string& val) { assert(g_base->InLogicThread()); input_string_ = val; input_text_dirty_ = true; + // Move carat to end. + carat_char_ = + static_cast(Utils::UnicodeFromUTF8(input_string_, "fj43t").size()); + assert(CaratCharValid_()); + carat_dirty_ = true; } void DevConsole::InputAdapterFinish() { @@ -690,28 +699,11 @@ auto DevConsole::HandleKeyPress(const SDL_Keysym* keysym) -> bool { // Any presses or releases cancels repeat actions. key_repeater_.Clear(); - // Handle our toggle buttons no matter whether we're active. - // switch (keysym->sym) { - // case kDevConsoleActivateKey1: - // case kDevConsoleActivateKey2: { - // if (!g_buildconfig.demo_build() && !g_buildconfig.arcade_build()) { - // // (reset input so characters don't continue walking and stuff) - // g_base->input->ResetHoldStates(); - // if (auto console = g_base->ui->dev_console()) { - // console->ToggleState(); - // } - // } - // return true; - // } - // default: - // break; - // } - if (state_ == State_::kInactive) { return false; } - // Handle some stuff only while active. + // Stuff we always look for. switch (keysym->sym) { case SDLK_ESCAPE: Dismiss(); @@ -720,56 +712,228 @@ auto DevConsole::HandleKeyPress(const SDL_Keysym* keysym) -> bool { break; } - // If we support direct keyboard input, and python terminal is showing, - // handle some keys directly. + // Stuff we look for only when direct keyboard input is enabled and our + // Python terminal is up. if (python_terminal_visible_ && g_base->ui->UIHasDirectKeyboardInput()) { + bool do_carat_right{}; + bool do_hungry_carat_right{}; + bool do_carat_left{}; + bool do_hungry_carat_left{}; + bool do_history_up{}; + bool do_history_down{}; + bool do_backspace{}; + bool do_hungry_backspace{}; + bool do_move_to_end{}; + bool do_move_to_beginning{}; + bool do_kill_line{}; switch (keysym->sym) { case SDLK_BACKSPACE: { - key_repeater_ = Repeater::New( - g_base->app_adapter->GetKeyRepeatDelay(), - g_base->app_adapter->GetKeyRepeatInterval(), [this] { - auto unichars = Utils::UnicodeFromUTF8(input_string_, "fjco38"); - if (!unichars.empty()) { - unichars.resize(unichars.size() - 1); - input_string_ = Utils::UTF8FromUnicode(unichars); - input_text_dirty_ = true; - } - }); + if (keysym->mod & KMOD_ALT) { + do_hungry_backspace = true; + } else { + do_backspace = true; + } break; } case SDLK_UP: - case SDLK_DOWN: { - if (input_history_.empty()) { - break; - } - if (keysym->sym == SDLK_UP) { - input_history_position_++; + do_history_up = true; + break; + case SDLK_DOWN: + do_history_down = true; + break; + case SDLK_RIGHT: + if (keysym->mod & KMOD_ALT) { + do_hungry_carat_right = true; } else { - input_history_position_--; - } - int input_history_position_used = - (input_history_position_ - 1) - % static_cast(input_history_.size()); - int j = 0; - for (auto& i : input_history_) { - if (j == input_history_position_used) { - input_string_ = i; - input_text_dirty_ = true; - break; - } - j++; + do_carat_right = true; + } + break; + case SDLK_LEFT: + if (keysym->mod & KMOD_ALT) { + do_hungry_carat_left = true; + } else { + do_carat_left = true; } break; - } case SDLK_KP_ENTER: case SDLK_RETURN: { Exec(); break; } + + // Wheeee emacs key shortcuts!! + case SDLK_n: + if (keysym->mod & KMOD_CTRL) { + do_history_down = true; + } + break; + case SDLK_f: + if (keysym->mod & KMOD_CTRL) { + do_carat_right = true; + } else if (keysym->mod & KMOD_ALT) { + do_hungry_carat_right = true; + } + break; + case SDLK_b: + if (keysym->mod & KMOD_CTRL) { + do_carat_left = true; + } else if (keysym->mod & KMOD_ALT) { + do_hungry_carat_left = true; + } + break; + case SDLK_p: + if (keysym->mod & KMOD_CTRL) { + do_history_up = true; + } + break; + case SDLK_a: + if (keysym->mod & KMOD_CTRL) { + do_move_to_beginning = true; + } + break; + case SDLK_e: + if (keysym->mod & KMOD_CTRL) { + do_move_to_end = true; + } + break; + case SDLK_k: + if (keysym->mod & KMOD_CTRL) { + do_kill_line = true; + } + default: { break; } } + if (do_kill_line) { + auto unichars = Utils::UnicodeFromUTF8(input_string_, "fjco38"); + assert(CaratCharValid_()); + unichars.resize(carat_char_); + assert(CaratCharValid_()); + input_string_ = Utils::UTF8FromUnicode(unichars); + input_text_dirty_ = true; + carat_dirty_ = true; + } + if (do_move_to_beginning) { + carat_char_ = 0; + assert(CaratCharValid_()); + carat_dirty_ = true; + } + if (do_move_to_end) { + // Move carat to end. + carat_char_ = static_cast( + Utils::UnicodeFromUTF8(input_string_, "fj43t").size()); + assert(CaratCharValid_()); + carat_dirty_ = true; + } + if (do_hungry_backspace || do_hungry_carat_left) { + auto do_delete = do_hungry_backspace; + key_repeater_ = Repeater::New( + g_base->app_adapter->GetKeyRepeatDelay(), + g_base->app_adapter->GetKeyRepeatInterval(), [this, do_delete] { + auto unichars = Utils::UnicodeFromUTF8(input_string_, "fjco38"); + bool found_valid{}; + // Delete/move until we've found at least one valid char and the + // stop at the first invalid one. + while (carat_char_ > 0) { + assert(CaratCharValid_()); + auto this_char = unichars[carat_char_ - 1]; + auto is_valid = IsValidHungryChar_(this_char); + if (found_valid && !is_valid) { + break; + } + if (is_valid) { + found_valid = true; + } + if (do_delete) { + unichars.erase(unichars.begin() + carat_char_ - 1); + } + carat_char_ -= 1; + assert(CaratCharValid_()); + } + input_string_ = Utils::UTF8FromUnicode(unichars); + input_text_dirty_ = true; + carat_dirty_ = true; + }); + } + if (do_hungry_carat_right) { + key_repeater_ = Repeater::New( + g_base->app_adapter->GetKeyRepeatDelay(), + g_base->app_adapter->GetKeyRepeatInterval(), [this] { + auto unichars = Utils::UnicodeFromUTF8(input_string_, "fjco38"); + bool found_valid{}; + // Move until we've found at least one valid char and the + // stop at the first invalid one. + while (carat_char_ < unichars.size()) { + assert(CaratCharValid_()); + auto this_char = unichars[carat_char_]; + auto is_valid = IsValidHungryChar_(this_char); + if (found_valid && !is_valid) { + break; + } + if (is_valid) { + found_valid = true; + } + carat_char_ += 1; + assert(CaratCharValid_()); + } + carat_dirty_ = true; + }); + } + if (do_backspace) { + key_repeater_ = Repeater::New( + g_base->app_adapter->GetKeyRepeatDelay(), + g_base->app_adapter->GetKeyRepeatInterval(), [this] { + auto unichars = Utils::UnicodeFromUTF8(input_string_, "fjco38"); + if (!unichars.empty() && carat_char_ > 0) { + assert(CaratCharValid_()); + unichars.erase(unichars.begin() + carat_char_ - 1); + input_string_ = Utils::UTF8FromUnicode(unichars); + input_text_dirty_ = true; + carat_char_ -= 1; + assert(CaratCharValid_()); + carat_dirty_ = true; + } + }); + } + if (do_carat_left || do_carat_right) { + key_repeater_ = Repeater::New( + g_base->app_adapter->GetKeyRepeatDelay(), + g_base->app_adapter->GetKeyRepeatInterval(), + [do_carat_left, do_carat_right, this] { + int offset = do_carat_right ? 1 : -1; + carat_char_ = std::clamp( + carat_char_ + offset, 0, + static_cast( + Utils::UnicodeFromUTF8(input_string_, "fffwe").size())); + assert(CaratCharValid_()); + carat_dirty_ = true; + }); + } + + if ((do_history_up || do_history_down) && !input_history_.empty()) { + if (do_history_up) { + input_history_position_++; + } else { + input_history_position_--; + } + int input_history_position_used = + (input_history_position_ - 1) + % static_cast(input_history_.size()); + int j = 0; + for (auto& i : input_history_) { + if (j == input_history_position_used) { + input_string_ = i; + carat_char_ = static_cast( + Utils::UnicodeFromUTF8(input_string_, "fffwe").size()); + assert(CaratCharValid_()); + input_text_dirty_ = true; + carat_dirty_ = true; + break; + } + j++; + } + } return true; } @@ -778,6 +942,24 @@ auto DevConsole::HandleKeyPress(const SDL_Keysym* keysym) -> bool { return false; } +auto DevConsole::HandleTextEditing(const std::string& text) -> bool { + assert(g_base->InLogicThread()); + if (state_ == State_::kInactive) { + return false; + } + assert(CaratCharValid_()); + auto unichars = Utils::UnicodeFromUTF8(input_string_, "jfof8"); + auto addunichars = Utils::UnicodeFromUTF8(text, "jfoef8"); + unichars.insert(unichars.begin() + carat_char_, addunichars.begin(), + addunichars.end()); + input_string_ = Utils::UTF8FromUnicode(unichars); + input_text_dirty_ = true; + carat_char_ += addunichars.size(); + assert(CaratCharValid_()); + carat_dirty_ = true; + return true; +} + auto DevConsole::HandleKeyRelease(const SDL_Keysym* keysym) -> bool { // Any presses or releases cancels repeat actions. key_repeater_.Clear(); @@ -804,7 +986,17 @@ void DevConsole::Exec() { input_history_.pop_back(); } input_string_.resize(0); + carat_char_ = 0; + assert(CaratCharValid_()); input_text_dirty_ = true; + carat_dirty_ = true; +} + +// Just for sanity testing. +auto DevConsole::CaratCharValid_() -> bool { + return carat_char_ >= 0 + && carat_char_ + <= Utils::UnicodeFromUTF8(input_string_, "fwewffe").size(); } void DevConsole::SubmitPythonCommand_(const std::string& command) { @@ -871,24 +1063,6 @@ void DevConsole::ToggleState() { transition_start_ = g_base->logic->display_time(); } -auto DevConsole::HandleTextEditing(const std::string& text) -> bool { - assert(g_base->InLogicThread()); - if (state_ == State_::kInactive) { - return false; - } - - // Ignore back-tick because we use that key to toggle the console. - // - // FIXME: Perhaps should allow typing it if some control-character is - // held? - if (text == "`") { - return false; - } - input_string_ += text; - input_text_dirty_ = true; - return true; -} - void DevConsole::Print(const std::string& s_in) { assert(g_base->InLogicThread()); std::string s = Utils::GetValidUTF8(s_in.c_str(), "cspr"); @@ -1013,13 +1187,14 @@ void DevConsole::Draw(FrameDef* frame_def) { if (input_text_dirty_) { input_text_group_.SetText(input_string_); input_text_dirty_ = false; - last_input_text_change_time_ = pass->frame_def()->app_time_millisecs(); } { SimpleComponent c(pass); c.SetFlatness(1.0f); c.SetTransparent(true); c.SetColor(0.4f, 0.33f, 0.45f, 0.8f); + + // Build. int elem_count = built_text_group_.GetElementCount(); for (int e = 0; e < elem_count; e++) { c.SetTexture(built_text_group_.GetElementTexture(e)); @@ -1031,6 +1206,8 @@ void DevConsole::Draw(FrameDef* frame_def) { c.DrawMesh(built_text_group_.GetElementMesh(e)); } } + + // Title. elem_count = title_text_group_.GetElementCount(); for (int e = 0; e < elem_count; e++) { c.SetTexture(title_text_group_.GetElementTexture(e)); @@ -1041,6 +1218,8 @@ void DevConsole::Draw(FrameDef* frame_def) { c.DrawMesh(title_text_group_.GetElementMesh(e)); } } + + // Prompt. elem_count = prompt_text_group_.GetElementCount(); for (int e = 0; e < elem_count; e++) { c.SetTexture(prompt_text_group_.GetElementTexture(e)); @@ -1052,6 +1231,8 @@ void DevConsole::Draw(FrameDef* frame_def) { c.DrawMesh(prompt_text_group_.GetElementMesh(e)); } } + + // Input line. elem_count = input_text_group_.GetElementCount(); for (int e = 0; e < elem_count; e++) { c.SetTexture(input_text_group_.GetElementTexture(e)); @@ -1065,21 +1246,34 @@ void DevConsole::Draw(FrameDef* frame_def) { } // Carat. + if (!carat_mesh_.Exists()) { + UpdateCarat_(); + } millisecs_t real_time = pass->frame_def()->app_time_millisecs(); if (real_time % 200 < 100 - || (real_time - last_input_text_change_time_ < 100)) { + || (real_time - last_carat_x_change_time_ < 100)) { SimpleComponent c(pass); c.SetTransparent(true); - c.SetColor(1, 1, 1, 0.7f); + c.SetTexture(g_base->assets->SysTexture(SysTextureID::kShadow)); + c.SetColor(0.8, 0.0, 1.0, 0.3f); + // c.SetPremultiplied(true); { auto xf = c.ScopedTransform(); - c.Translate( - (19.0f - + g_base->text_graphics->GetStringWidth(input_string_) * 0.5f) - * bs, - bottom + 22.5f * bs, kDevConsoleZDepth); - c.Scale(6.0f * bs, 12.0f * bs, 1.0f); - c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kImage1x1)); + auto carat_x = GetCaratX_(); + c.Translate(15.0f * bs, bottom + 14.5f * bs, kDevConsoleZDepth); + c.Scale(0.5f * bs, 0.5f * bs, 1.0f); + c.Translate(carat_x, 0.0f, 0.0f); + c.DrawMesh(carat_glow_mesh_.Get()); + } + c.SetTexture(g_base->assets->SysTexture(SysTextureID::kShadowSharp)); + c.SetColor(1.0, 1.0, 1.0, 1.0f); + { + auto xf = c.ScopedTransform(); + auto carat_x = GetCaratX_(); + c.Translate(15.0f * bs, bottom + 14.5f * bs, kDevConsoleZDepth); + c.Scale(0.5f * bs, 0.5f * bs, 1.0f); + c.Translate(carat_x, 0.0f, 0.0f); + c.DrawMesh(carat_mesh_.Get()); } } @@ -1191,4 +1385,86 @@ void DevConsole::StepDisplayTime() { } } +auto DevConsole::PasteFromClipboard() -> bool { + if (state_ != State_::kInactive) { + if (python_terminal_visible_) { + if (g_base->app_adapter->ClipboardIsSupported()) { + if (g_base->app_adapter->ClipboardHasText()) { + auto text = g_base->app_adapter->ClipboardGetText(); + if (strstr(text.c_str(), "\n") || strstr(text.c_str(), "\r")) { + g_base->audio->PlaySound( + g_base->assets->SysSound(SysSoundID::kErrorBeep)); + ScreenMessage("Can only paste single lines of text.", + Vector3f(1.0f, 0.0f, 0.0f)); + } else { + HandleTextEditing(text); + } + // Ok, we either pasted or complained, so consider it handled. + return true; + } + } + } + } + return false; +} + +void DevConsole::UpdateCarat_() { + auto unichars = Utils::UnicodeFromUTF8(input_string_, "fjfwef"); + auto unichars_clamped = unichars; + + unichars_clamped.resize(carat_char_); + auto clamped_str = Utils::UTF8FromUnicode(unichars_clamped); + carat_x_ = g_base->text_graphics->GetStringWidth(clamped_str); + + // Use a base width if we're not covering a char, and use the char's width + // if we are. + float width = 14.0f; + if (carat_char_ < unichars.size()) { + std::vector covered_char{unichars[carat_char_]}; + auto covered_char_str = Utils::UTF8FromUnicode(covered_char); + width = + std::max(3.0f, g_base->text_graphics->GetStringWidth(covered_char_str)); + } + + float height = 32.0f; + float x_extend = 15.0f; + float y_extend = 20.0f; + float x_offset = 2.0f; + float y_offset = -0.0f; + float corner_radius = 20.0f; + float width_fin = width + x_extend * 2.0f; + float height_fin = height + y_extend * 2.0f; + float x_border = + NinePatchMesh::BorderForRadius(corner_radius, width_fin, height_fin); + float y_border = + NinePatchMesh::BorderForRadius(corner_radius, height_fin, width_fin); + carat_glow_mesh_ = Object::New( + -x_extend + x_offset, -y_extend + y_offset, 0.0f, width_fin, height_fin, + x_border, y_border, x_border, y_border); + + corner_radius = 3.0f; + x_extend = 0.0f; + y_extend = -3.0f; + x_offset = 1.0f; + y_offset = 0.0f; + width_fin = width + x_extend * 2.0f; + height_fin = height + y_extend * 2.0f; + x_border = + NinePatchMesh::BorderForRadius(corner_radius, width_fin, height_fin); + y_border = + NinePatchMesh::BorderForRadius(corner_radius, height_fin, width_fin); + carat_mesh_ = Object::New( + -x_extend + x_offset, -y_extend + y_offset, 0.0f, width_fin, height_fin, + x_border, y_border, x_border, y_border); +} + +auto DevConsole::GetCaratX_() -> float { + if (carat_dirty_) { + last_carat_x_change_time_ = g_core->GetAppTimeMillisecs(); + UpdateCarat_(); + carat_dirty_ = false; + } + return carat_x_; +} + } // namespace ballistica::base diff --git a/src/ballistica/base/ui/dev_console.h b/src/ballistica/base/ui/dev_console.h index e7134c70..7e080ace 100644 --- a/src/ballistica/base/ui/dev_console.h +++ b/src/ballistica/base/ui/dev_console.h @@ -8,6 +8,7 @@ #include #include +#include "ballistica/base/graphics/mesh/nine_patch_mesh.h" #include "ballistica/base/graphics/renderer/renderer.h" #include "ballistica/shared/foundation/object.h" #include "ballistica/shared/python/python_ref.h" @@ -32,6 +33,9 @@ class DevConsole { /// Tell the console to quietly go away no matter what state it is in. void Dismiss(); + /// Attempt to Paste. Returns true if it happened. + auto PasteFromClipboard() -> bool; + /// Print text to the console. void Print(const std::string& s_in); void Draw(FrameDef* frame_def); @@ -75,6 +79,9 @@ class DevConsole { class OutputLine_; enum class State_ : uint8_t { kInactive, kMini, kFull }; + auto CaratCharValid_() -> bool; + auto GetCaratX_() -> float; + void UpdateCarat_(); auto Bottom_() const -> float; void SubmitPythonCommand_(const std::string& command); void InvokeStringEditor_(); @@ -82,17 +89,20 @@ class DevConsole { void RefreshTabContents_(); int input_history_position_{}; - int ui_lock_count_ : 1 {}; + int ui_lock_count_{}; + int carat_char_{0}; + State_ state_{State_::kInactive}; + State_ state_prev_{State_::kInactive}; bool input_text_dirty_ : 1 {true}; bool input_enabled_ : 1 {}; bool last_line_mesh_dirty_ : 1 {true}; bool python_terminal_visible_ : 1 {}; bool python_terminal_pressed_ : 1 {}; bool refresh_pending_ : 1 {}; - double transition_start_{}; - State_ state_{State_::kInactive}; - State_ state_prev_{State_::kInactive}; - millisecs_t last_input_text_change_time_{}; + bool carat_dirty_ : 1 {true}; + float carat_x_{}; + seconds_t transition_start_{}; + millisecs_t last_carat_x_change_time_{}; ImageMesh bg_mesh_; ImageMesh stripe_mesh_; ImageMesh border_mesh_; @@ -111,6 +121,8 @@ class DevConsole { std::vector > tab_buttons_; Object::Ref last_line_mesh_group_; Object::Ref key_repeater_; + Object::Ref carat_mesh_; + Object::Ref carat_glow_mesh_; }; } // namespace ballistica::base diff --git a/src/ballistica/scene_v1/node/flag_node.cc b/src/ballistica/scene_v1/node/flag_node.cc index 05b26746..ede8eb98 100644 --- a/src/ballistica/scene_v1/node/flag_node.cc +++ b/src/ballistica/scene_v1/node/flag_node.cc @@ -5,7 +5,6 @@ #include "ballistica/base/dynamics/bg/bg_dynamics_shadow.h" #include "ballistica/base/graphics/component/object_component.h" #include "ballistica/base/graphics/component/simple_component.h" -#include "ballistica/base/graphics/graphics_server.h" #include "ballistica/base/graphics/support/area_of_interest.h" #include "ballistica/base/graphics/support/camera.h" #include "ballistica/scene_v1/assets/scene_texture.h" diff --git a/src/ballistica/scene_v1/support/scene_v1_app_mode.cc b/src/ballistica/scene_v1/support/scene_v1_app_mode.cc index 9fec9239..59b25ae8 100644 --- a/src/ballistica/scene_v1/support/scene_v1_app_mode.cc +++ b/src/ballistica/scene_v1/support/scene_v1_app_mode.cc @@ -11,7 +11,6 @@ #include "ballistica/base/python/base_python.h" #include "ballistica/base/support/app_config.h" #include "ballistica/base/support/plus_soft.h" -#include "ballistica/base/ui/ui.h" #include "ballistica/scene_v1/connection/connection_set.h" #include "ballistica/scene_v1/connection/connection_to_client_udp.h" #include "ballistica/scene_v1/connection/connection_to_host.h" diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index 047ad453..8046fdc8 100644 --- a/src/ballistica/shared/ballistica.cc +++ b/src/ballistica/shared/ballistica.cc @@ -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 = 21516; +const int kEngineBuildNumber = 21522; const char* kEngineVersion = "1.7.28"; const int kEngineApiVersion = 8; diff --git a/src/ballistica/shared/foundation/object.h b/src/ballistica/shared/foundation/object.h index c4f39b5d..53b9eeea 100644 --- a/src/ballistica/shared/foundation/object.h +++ b/src/ballistica/shared/foundation/object.h @@ -13,15 +13,8 @@ namespace ballistica { /// Objects supporting strong and weak referencing and thread enforcement. class Object { - 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: + Object(); virtual ~Object(); // Object classes can provide descriptive names for themselves; these are @@ -575,6 +568,10 @@ class Object { [[nodiscard]] static auto New(ARGS&&... args) -> Object::Ref { auto* ptr = new TALLOC(std::forward(args)...); #if BA_DEBUG_BUILD + /// Objects assume they are statically allocated by default; it's up + /// to us to tell them when they're not. + ptr->object_is_static_allocated_ = false; + /// Make sure things aren't creating strong refs to themselves in their /// constructors. if (ptr->object_has_been_strong_reffed_) { @@ -599,6 +596,10 @@ class Object { [[nodiscard]] static auto NewDeferred(ARGS&&... args) -> T* { T* ptr = new T(std::forward(args)...); #if BA_DEBUG_BUILD + /// Objects assume they are statically allocated by default; it's up + /// to us to tell them when they're not. + ptr->object_is_static_allocated_ = false; + /// Make sure things aren't creating strong refs to themselves in their /// constructors. if (ptr->object_has_been_strong_reffed_) { @@ -650,6 +651,9 @@ class Object { [[nodiscard]] static auto NewUnmanaged(ARGS&&... args) -> T* { T* ptr = new T(std::forward(args)...); #if BA_DEBUG_BUILD + /// Objects assume they are statically allocated by default; it's up + /// to us to tell them when they're not. + ptr->object_is_static_allocated_ = false; ptr->object_is_unmanaged_ = true; #endif return ptr; @@ -668,6 +672,7 @@ class Object { auto operator new(size_t size) -> void* { return new char[size]; } void ObjectUpdateForAcquire(); + bool object_is_static_allocated_ : 1 {true}; bool object_has_been_strong_reffed_ : 1 {}; bool object_is_ref_counted_ : 1 {}; bool object_is_pending_deferred_ : 1 {}; diff --git a/src/ballistica/ui_v1/python/ui_v1_python.cc b/src/ballistica/ui_v1/python/ui_v1_python.cc index d76ecd34..f12321b0 100644 --- a/src/ballistica/ui_v1/python/ui_v1_python.cc +++ b/src/ballistica/ui_v1/python/ui_v1_python.cc @@ -2,7 +2,6 @@ #include "ballistica/ui_v1/python/ui_v1_python.h" -#include "ballistica/base/assets/assets.h" #include "ballistica/base/audio/audio.h" #include "ballistica/base/input/device/keyboard_input.h" #include "ballistica/base/input/input.h" diff --git a/src/ballistica/ui_v1/ui_v1.cc b/src/ballistica/ui_v1/ui_v1.cc index 30083701..cf8ffc9d 100644 --- a/src/ballistica/ui_v1/ui_v1.cc +++ b/src/ballistica/ui_v1/ui_v1.cc @@ -3,10 +3,8 @@ #include "ballistica/ui_v1/ui_v1.h" #include "ballistica/base/app_mode/app_mode.h" -#include "ballistica/base/audio/audio.h" #include "ballistica/base/graphics/component/empty_component.h" #include "ballistica/base/input/input.h" -#include "ballistica/base/python/base_python.h" #include "ballistica/base/support/app_config.h" #include "ballistica/ui_v1/python/ui_v1_python.h" #include "ballistica/ui_v1/support/root_ui.h"