lots of dev console terminal improvements

This commit is contained in:
Eric 2023-10-26 19:50:46 -07:00
parent f0ebe2bce8
commit 11212bfb52
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
32 changed files with 710 additions and 375 deletions

88
.efrocachemap generated
View File

@ -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",

View File

@ -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)

View File

@ -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

View File

@ -428,6 +428,8 @@
<ClCompile Include="..\..\src\ballistica\base\support\app_config.cc" />
<ClInclude Include="..\..\src\ballistica\base\support\app_config.h" />
<ClInclude Include="..\..\src\ballistica\base\support\app_timer.h" />
<ClCompile Include="..\..\src\ballistica\base\support\base_build_switches.cc" />
<ClInclude Include="..\..\src\ballistica\base\support\base_build_switches.h" />
<ClInclude Include="..\..\src\ballistica\base\support\classic_soft.h" />
<ClCompile Include="..\..\src\ballistica\base\support\context.cc" />
<ClInclude Include="..\..\src\ballistica\base\support\context.h" />

View File

@ -718,6 +718,12 @@
<ClInclude Include="..\..\src\ballistica\base\support\app_timer.h">
<Filter>ballistica\base\support</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ballistica\base\support\base_build_switches.cc">
<Filter>ballistica\base\support</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ballistica\base\support\base_build_switches.h">
<Filter>ballistica\base\support</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ballistica\base\support\classic_soft.h">
<Filter>ballistica\base\support</Filter>
</ClInclude>

View File

@ -423,6 +423,8 @@
<ClCompile Include="..\..\src\ballistica\base\support\app_config.cc" />
<ClInclude Include="..\..\src\ballistica\base\support\app_config.h" />
<ClInclude Include="..\..\src\ballistica\base\support\app_timer.h" />
<ClCompile Include="..\..\src\ballistica\base\support\base_build_switches.cc" />
<ClInclude Include="..\..\src\ballistica\base\support\base_build_switches.h" />
<ClInclude Include="..\..\src\ballistica\base\support\classic_soft.h" />
<ClCompile Include="..\..\src\ballistica\base\support\context.cc" />
<ClInclude Include="..\..\src\ballistica\base\support\context.h" />

View File

@ -718,6 +718,12 @@
<ClInclude Include="..\..\src\ballistica\base\support\app_timer.h">
<Filter>ballistica\base\support</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ballistica\base\support\base_build_switches.cc">
<Filter>ballistica\base\support</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ballistica\base\support\base_build_switches.h">
<Filter>ballistica\base\support</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ballistica\base\support\classic_soft.h">
<Filter>ballistica\base\support</Filter>
</ClInclude>

View File

@ -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'

View File

@ -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;

View File

@ -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

View File

@ -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
}

View File

@ -807,23 +807,9 @@ void AppAdapterSDL::CursorPositionForDraw(float* x, float* y) {
auto AppAdapterSDL::FullscreenControlAvailable() const -> bool { return true; }
auto AppAdapterSDL::FullscreenControlKeyShortcut() const
-> std::optional<std::string> {
if (g_buildconfig.ostype_windows()) {
// On Windows we support F11 and Alt+Enter to toggle fullscreen. Let's
// mention Alt+Enter which seems like it might be more commonly used
return "Alt+Enter";
}
if (g_buildconfig.ostype_macos()) {
// The Mac+SDL situation is a bit of a mess. By default, there is 'Enter
// Full Screen' in the window menu which is mapped to fn-F, but that
// will only work if a window was created in SDL as windowed. If we
// fullscreen that window and restart the app, we'll then have a *real*
// fullscreen sdl window and that shortcut won't work anymore. So to
// keep things consistent we advertise ctrl-f which we always handle
// ourselves. Maybe this situation will be cleaned up in SDL 3, but its
// not a huge deal anyway since our Cocoa Mac version behaves cleanly.
return "Ctrl+F";
}
return {};
// 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; }

View File

@ -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"

View File

@ -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},

View File

@ -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<TextureAsset> texture;
Object::Ref<TextureAsset> tint_texture;
float v_smoothed{};
bool translation_dirty{true};
bool mesh_dirty{true};
millisecs_t smooth_time{};
Object::Ref<NinePatchMesh> shadow_mesh_;
private:
Object::Ref<TextGroup> 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<float>(age)) / 100.0f);
fade = std::max(0.07f, (200.0f - static_cast<float>(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<NinePatchMesh>(
-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_;

View File

@ -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);

View File

@ -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 {

View File

@ -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 {

View File

@ -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) {

View File

@ -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() {

View File

@ -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_;

View File

@ -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

View File

@ -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_

View File

@ -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"

View File

@ -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<int>(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<int>(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<int>(
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<int>(
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<int>(input_history_.size());
int j = 0;
for (auto& i : input_history_) {
if (j == input_history_position_used) {
input_string_ = i;
carat_char_ = static_cast<int>(
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<uint32_t> 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<NinePatchMesh>(
-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<NinePatchMesh>(
-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

View File

@ -8,6 +8,7 @@
#include <utility>
#include <vector>
#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<std::unique_ptr<Widget_> > tab_buttons_;
Object::Ref<TextGroup> last_line_mesh_group_;
Object::Ref<Repeater> key_repeater_;
Object::Ref<NinePatchMesh> carat_mesh_;
Object::Ref<NinePatchMesh> carat_glow_mesh_;
};
} // namespace ballistica::base

View File

@ -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"

View File

@ -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"

View File

@ -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;

View File

@ -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<TRETURN> {
auto* ptr = new TALLOC(std::forward<ARGS>(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>(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>(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 {};

View File

@ -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"

View File

@ -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"