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"