work on user-defined dev-console tabs

This commit is contained in:
Eric 2023-10-02 16:14:47 -07:00
parent 50f91361f4
commit f25f31cce4
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
32 changed files with 703 additions and 367 deletions

60
.efrocachemap generated
View File

@ -4056,26 +4056,26 @@
"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": "fdcef1a7c77ad3cb23d7339fb1be2bf0",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "da17b5cc5f83bed3a0df7d238ba52d62",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "f550cb252d584f5ad7a100d9bb65d07a",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "6ce0af256949280a4820b96388e9d33c",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "65d75cd5909aa24e5c554c39d8aa7425",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "7e2267b47b1075da9737005d3d6821a3",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "6429f3fbddc8f71a29588486c9e0135f",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "48e5146f5a93e62d0c42d902d928f123",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "497c7b622b63b47268a4e55f439b00b1",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "2d54d79c942f48f6de4f07496b5c7d9c",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "0959c5af017a58f487d353d56cfb3fc5",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "ce4e095b7f36cf0f1c5d39bd196087a6",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "3afafa7c2b660d60c740bc152898f1b8",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "db0e1929b4fcfc55295fd401a8c19e3a",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "78c06393fc28e1d5ba8dac8ab97ba07e",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "fbada26a44865ad20b621641d4f1bf47",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "63d57d508d8f9ae21e05ceda181e1a2d",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "2c4f7247938de3d3fbb65b5766263866",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "85ef605dc94c4be74aac5b15a8931da5",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "a39d6180a89b83463fc44f1b006ebc7d",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "06130b0dfceeb424ba1b66414cf6d930",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "9ea9b12078443053eee0e0be5137492d",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "31f82f74a30d97d6bc66b2fa8d3abbcd",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "7ba3fa11b4e22b42aa16b8f0f904ea70",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "230141db6263d696c28ad00c011f0f9e",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "1e0a508a1fbd20f7e8a1ed79e361ecc6",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "ad6f15fdb1b3956b08d73abb4a0b240d",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "49edc04b213fd8bb10d3227e27921fe8",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "169375157927ea3a826d06a2f3339ccc",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "ed4a2bf5ef5c9e90c4a34a94e82e1752",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "4a8df3bd047824c139d271cb82db06d5",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "a4b0933ce9220822302d660865766891",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "a22db827c37da85d73d248be95f07523",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "49bb13ad22a1f5a75246a21830689998",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "98aa51efb0554fadd446f48b8cb6f31e",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "4450820bb5a73e7b83004a3fe78a50d6",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "cff958f088a5bea303a846dbd0d96e14",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "b2cbf2eee4db47d8d4e1ce0df1c80214",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "3aa845292833b423a7b96263b368bb13",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "2b2a64c6fb1d73d6ddfc19dc597a0947",
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "6ce4983e76e1cc2d2803fe306d08ad58",
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "4ea0cf78901f994215f215aebb0af1dc",
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "6ce4983e76e1cc2d2803fe306d08ad58",
@ -4092,18 +4092,18 @@
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "de83e1b384abb333f457f2c9646f810f",
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "0149ef8dae7720330416846919a834e7",
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "de83e1b384abb333f457f2c9646f810f",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "e3ad15ecc9656a1a268582b14336bed7",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "fce3fd45ed78f84592ef914450817778",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "feeb14560de0fa18d8b7654aa43534ea",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "7896041f53b6f076d032388d661413b0",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "a5b84aaf028c8b13d55d2d99f3853f5d",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "4a8387851909f5cedabb5972b397a7b1",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "53fa53d605a009a6ab592e30d45629a8",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "2988d1791814f0ec0d64914d691a100e",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "163fbb4576a5218685919cf04de63cc6",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "66bbf458c1778685d38d6a2a537f6012",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "1ff129f72dc2dddc24d4dcdfb9b2826a",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "12d9566016a1bbd2aeb873d598d9ceed",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "ba99295cfbcbb3f6da27e4fad8227d74",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "8d53587d097910667fcb7f4958e55384",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "4f3e5d9578c0b0c3bd1203755fe8d464",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "ab834d0257bec7c972a2587a0b34eeff",
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
"src/assets/ba_data/python/babase/_mgen/enums.py": "f8cd3af311ac63147882590123b78318",
"src/ballistica/base/mgen/pyembed/binding_base.inc": "c81b2b1f3a14b4cd20a7b93416fe893a",
"src/ballistica/base/mgen/pyembed/binding_base_app.inc": "b67add3e1346f63491bf3450148e60d4",
"src/ballistica/base/mgen/pyembed/binding_base.inc": "9f71f171464dc004dbaab87e9bb4b03b",
"src/ballistica/base/mgen/pyembed/binding_base_app.inc": "a521bc86a7e98e56fec14cea029996f8",
"src/ballistica/classic/mgen/pyembed/binding_classic.inc": "3ceb412513963f0818ab39c58bf292e3",
"src/ballistica/core/mgen/pyembed/binding_core.inc": "9d0a3c9636138e35284923e0c8311c69",
"src/ballistica/core/mgen/pyembed/env.inc": "8be46e5818f360d10b7b0224a9e91d07",

View File

@ -2923,6 +2923,8 @@
<w>syslogmodule</w>
<w>sysresponse</w>
<w>tabdefs</w>
<w>tabentry</w>
<w>tabname</w>
<w>tabtype</w>
<w>tabtypes</w>
<w>tabval</w>
@ -3351,6 +3353,7 @@
<w>xcworkspacedata</w>
<w>xdrlib</w>
<w>xhdpi</w>
<w>xhost</w>
<w>xinput</w>
<w>xjtp</w>
<w>xmlbuilder</w>

View File

@ -1,4 +1,4 @@
### 1.7.28 (build 21401, api 8, 2023-09-29)
### 1.7.28 (build 21405, api 8, 2023-10-02)
- 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

View File

@ -135,6 +135,7 @@ resources-clean:
cd src/resources && $(MAKE) clean
# Build our generated sources.
#
# Meta builds can affect sources used by asset builds, resource builds, and
# compiles, so it should be listed as a dependency of any of those.
meta: prereqs
@ -146,8 +147,8 @@ meta-clean:
rm -f $(LAZYBUILDDIR)/meta
cd src/meta && $(MAKE) clean
# Remove ALL files and directories that aren't managed by git
# (except for a few things such as localconfig.json).
# Remove ALL files and directories that aren't managed by git (except for a
# few things such as localconfig.json).
clean:
$(CHECK_CLEAN_SAFETY)
rm -rf build # Handle this part ourself; can confuse git.
@ -160,9 +161,10 @@ clean-list:
git clean -dnx $(ROOT_CLEAN_IGNORES)
# Build/update dummy python modules.
# IMPORTANT - building this target can kick off full builds/cleans and so
# it should not be built in parallel with other targets.
# See py_check_prereqs target for more info.
#
# IMPORTANT - building this target can kick off full builds/cleans and so it
# should not be built in parallel with other targets. See py_check_prereqs
# target for more info.
dummymodules: prereqs meta
@$(PCOMMAND) lazybuild dummymodules_src $(LAZYBUILDDIR)/$@ \
rm -rf build/dummymodules \&\& $(PCOMMAND) gen_dummy_modules

View File

@ -1733,6 +1733,8 @@
<w>syscalls</w>
<w>sysresponse</w>
<w>tabdefs</w>
<w>tabentry</w>
<w>tabname</w>
<w>tabtype</w>
<w>tabtypes</w>
<w>talloc</w>
@ -1972,6 +1974,7 @@
<w>xcrun</w>
<w>xdiff</w>
<w>xdist</w>
<w>xhost</w>
<w>xinput</w>
<w>xmax</w>
<w>xmin</w>

View File

@ -51,11 +51,6 @@ if (HEADLESS)
endif ()
find_package(OpenGL REQUIRED)
find_package(OpenAL REQUIRED)
if (APPLE)
# On mac this sets an include path that we don't need since
# we're using the system framework... should clean this up.
set(OPENAL_INCLUDE_DIR "")
endif ()
find_library(OGG_LIBRARY ogg)
find_library(VORBISFILE_LIBRARY vorbisfile)
if (NOT OGG_LIBRARY)
@ -77,8 +72,7 @@ endif ()
# on Raspberry Pi builds. We never need to care about C++ abi compatibility
# so just silencing them for now. Can maybe remove this later if they stop.
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -Wno-psabi")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-psabi")
endif()
set(BA_SRC_ROOT ../src)
@ -800,11 +794,6 @@ target_link_libraries(ballisticakitbin PRIVATE
${CMAKE_CURRENT_BINARY_DIR}/prefablib/libballisticaplus.a ode pthread ${Python_LIBRARIES}
${SDL2_LIBRARIES} ${EXTRA_LIBRARIES} dl)
# Hack for building on rpi; need to update my pi so I can remove this.
if(EXISTS "/home/pi")
target_link_libraries(ballisticakitbin PRIVATE dl util stdc++fs)
endif()
# BallisticaKit modular shared library
# (for use with vanilla Python interpreters).

View File

@ -98,7 +98,7 @@
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef;../../src/external/qrencode-3.4.4</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef;../../src/external/qrencode-3.4.4</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
@ -122,7 +122,7 @@
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
@ -147,7 +147,7 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<SDLCheck>false</SDLCheck>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
@ -172,7 +172,7 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<SDLCheck>false</SDLCheck>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>

View File

@ -100,7 +100,7 @@
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
@ -122,7 +122,7 @@
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
@ -144,7 +144,7 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
@ -168,7 +168,7 @@
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../src;../../src/external/windows/include/SDL2;../../src/external/windows/include/AL;../../src/external/windows/include/python;../../src/external/windows/include;../../src/external/open_dynamics_engine-ef</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>

View File

@ -14,6 +14,7 @@
"ba_data/python/babase/__pycache__/_assetmanager.cpython-311.opt-1.pyc",
"ba_data/python/babase/__pycache__/_asyncio.cpython-311.opt-1.pyc",
"ba_data/python/babase/__pycache__/_cloud.cpython-311.opt-1.pyc",
"ba_data/python/babase/__pycache__/_devconsole.cpython-311.opt-1.pyc",
"ba_data/python/babase/__pycache__/_emptyappmode.cpython-311.opt-1.pyc",
"ba_data/python/babase/__pycache__/_env.cpython-311.opt-1.pyc",
"ba_data/python/babase/__pycache__/_error.cpython-311.opt-1.pyc",
@ -43,6 +44,7 @@
"ba_data/python/babase/_assetmanager.py",
"ba_data/python/babase/_asyncio.py",
"ba_data/python/babase/_cloud.py",
"ba_data/python/babase/_devconsole.py",
"ba_data/python/babase/_emptyappmode.py",
"ba_data/python/babase/_env.py",
"ba_data/python/babase/_error.py",

View File

@ -172,6 +172,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \
$(BUILD_DIR)/ba_data/python/babase/_assetmanager.py \
$(BUILD_DIR)/ba_data/python/babase/_asyncio.py \
$(BUILD_DIR)/ba_data/python/babase/_cloud.py \
$(BUILD_DIR)/ba_data/python/babase/_devconsole.py \
$(BUILD_DIR)/ba_data/python/babase/_emptyappmode.py \
$(BUILD_DIR)/ba_data/python/babase/_env.py \
$(BUILD_DIR)/ba_data/python/babase/_error.py \
@ -445,6 +446,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_assetmanager.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_asyncio.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_cloud.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_devconsole.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_emptyappmode.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_env.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_error.cpython-311.opt-1.pyc \

View File

@ -114,6 +114,11 @@ from babase._apputils import (
AppHealthMonitor,
)
from babase._cloud import CloudSubsystem
from babase._devconsole import (
DevConsoleTab,
DevConsoleTabEntry,
DevConsoleSubsystem,
)
from babase._emptyappmode import EmptyAppMode
from babase._error import (
print_exception,
@ -206,6 +211,9 @@ __all__ = [
'ContextError',
'ContextRef',
'DelegateNotFoundError',
'DevConsoleTab',
'DevConsoleTabEntry',
'DevConsoleSubsystem',
'DisplayTime',
'displaytime',
'displaytimer',

View File

@ -24,6 +24,7 @@ from babase._appcomponent import AppComponentSubsystem
from babase._appmodeselector import AppModeSelector
from babase._appintent import AppIntentDefault, AppIntentExec
from babase._stringedit import StringEditSubsystem
from babase._devconsole import DevConsoleSubsystem
if TYPE_CHECKING:
import asyncio
@ -164,6 +165,7 @@ class App:
self.workspaces = WorkspaceSubsystem()
self.components = AppComponentSubsystem()
self.stringedit = StringEditSubsystem()
self.devconsole = DevConsoleSubsystem()
# This is incremented any time the app is backgrounded or
# foregrounded; can be a simple way to determine if network data

View File

@ -0,0 +1,144 @@
# Released under the MIT License. See LICENSE for details.
#
"""Dev-Console functionality."""
from __future__ import annotations
from typing import TYPE_CHECKING
from dataclasses import dataclass
import logging
import _babase
if TYPE_CHECKING:
from typing import Callable, Any, Literal
class DevConsoleTab:
"""Defines behavior for a tab in the dev-console."""
def refresh(self) -> None:
"""Called when the tab should refresh itself."""
def request_refresh(self) -> None:
"""The tab can call this to request that it be refreshed."""
_babase.dev_console_request_refresh()
def button(
self,
label: str,
pos: tuple[float, float],
size: tuple[float, float],
call: Callable[[], Any] | None = None,
h_anchor: Literal['left', 'center', 'right'] = 'center',
label_scale: float = 1.0,
corner_radius: float = 8.0,
) -> None:
"""Add a button to the tab being refreshed."""
assert _babase.app.devconsole.is_refreshing
_babase.dev_console_add_button(
label,
pos[0],
pos[1],
size[0],
size[1],
call,
h_anchor,
label_scale,
corner_radius,
)
def python_terminal(self) -> None:
"""Add a Python Terminal to the tab being refreshed."""
assert _babase.app.devconsole.is_refreshing
_babase.dev_console_add_python_terminal()
@property
def width(self) -> float:
"""Return the current tab width. Only call during refreshes."""
assert _babase.app.devconsole.is_refreshing
return _babase.dev_console_tab_width()
@property
def height(self) -> float:
"""Return the current tab height. Only call during refreshes."""
assert _babase.app.devconsole.is_refreshing
return _babase.dev_console_tab_height()
@property
def base_scale(self) -> float:
"""A scale value set depending on the app's UI scale.
Dev-console tabs can incorporate this into their UI sizes and
positions if they desire. This must be done manually however.
"""
assert _babase.app.devconsole.is_refreshing
return _babase.dev_console_base_scale()
class DevConsoleTabPython(DevConsoleTab):
"""The Python dev-console tab."""
def refresh(self) -> None:
self.python_terminal()
class DevConsoleTabTest(DevConsoleTab):
"""Test dev-console tab."""
def refresh(self) -> None:
import random
self.button(
f'FLOOP-{random.randrange(200)}',
pos=(10, 10),
size=(100, 30),
h_anchor='left',
call=self.request_refresh,
)
@dataclass
class DevConsoleTabEntry:
"""Represents a distinct tab in the dev-console."""
name: str
factory: Callable[[], DevConsoleTab]
class DevConsoleSubsystem:
"""Wrangles the dev console."""
def __init__(self) -> None:
# All tabs in the dev-console. Add your own stuff here via
# plugins or whatnot.
self.tabs: list[DevConsoleTabEntry] = [
DevConsoleTabEntry('Python', DevConsoleTabPython),
DevConsoleTabEntry('Test', DevConsoleTabTest),
]
self.is_refreshing = False
def do_refresh_tab(self, tabname: str) -> None:
"""Called by the C++ layer when a tab should be filled out."""
assert _babase.in_logic_thread()
# FIXME: We currently won't handle multiple tabs with the same
# name. We should give a clean error or something in that case.
tab: DevConsoleTab | None = None
for tabentry in self.tabs:
if tabentry.name == tabname:
tab = tabentry.factory()
break
if tab is None:
logging.error(
'DevConsole got refresh request for tab'
" '%s' which does not exist.",
tabname,
)
return
self.is_refreshing = True
try:
tab.refresh()
finally:
self.is_refreshing = False

View File

@ -372,3 +372,8 @@ def string_edit_adapter_can_be_replaced(adapter: StringEditAdapter) -> bool:
assert isinstance(adapter, StringEditAdapter)
return adapter.can_be_replaced()
def get_dev_console_tab_names() -> list[str]:
"""Return the current set of dev-console tab names."""
return [t.name for t in _babase.app.devconsole.tabs]

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 = 21401
TARGET_BALLISTICA_BUILD = 21405
TARGET_BALLISTICA_VERSION = '1.7.28'

View File

@ -13,12 +13,12 @@
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#include <al.h>
#include <alc.h>
#endif
#if BA_OSTYPE_ANDROID
#include <AL/alext.h>
#include <alext.h>
#endif
#define CHECK_AL_ERROR _check_al_error(__FILE__, __LINE__)

View File

@ -1,15 +1,12 @@
// Released under the MIT License. See LICENSE for details.
#if BA_ENABLE_OPENGL
#include "ballistica/base/graphics/gl/renderer_gl.h"
#include <iterator>
#include <sstream>
#include "ballistica/base/graphics/component/special_component.h"
#include "ballistica/base/graphics/gl/framebuffer_object_gl.h"
#include "ballistica/base/graphics/gl/gl_sys.h"
#include "ballistica/base/graphics/gl/mesh/mesh_asset_data_gl.h"
#include "ballistica/base/graphics/gl/mesh/mesh_data_dual_texture_full_gl.h"
#include "ballistica/base/graphics/gl/mesh/mesh_data_gl.h"
@ -29,11 +26,6 @@
#include "ballistica/base/graphics/gl/render_target_gl.h"
#include "ballistica/base/graphics/gl/texture_data_gl.h"
#include "ballistica/base/platform/base_platform.h"
#include "ballistica/shared/buildconfig/buildconfig_common.h"
#if BA_OSTYPE_IOS_TVOS
#include "ballistica/base/platform/apple/apple_utils.h"
#endif
// Turn this off to see how much blend overdraw is occurring.
#define BA_GL_ENABLE_BLEND 1
@ -64,22 +56,6 @@ namespace ballistica::base {
bool RendererGL::funky_depth_issue_set_{};
bool RendererGL::funky_depth_issue_{};
bool RendererGL::draws_shields_funny_{};
bool RendererGL::draws_shields_funny_set_{};
// FIXME - move this stuff to the renderer class.
// GLint g_combined_texture_image_unit_count{};
// bool g_anisotropic_support{};
// bool g_vao_support{};
// float g_max_anisotropy{};
// bool g_discard_framebuffer_support{};
// bool g_invalidate_framebuffer_support{};
// bool g_blit_framebuffer_support{};
// bool g_framebuffer_multisample_support{};
// bool g_running_es3{};
// bool g_seamless_cube_maps{};
// int g_msaa_max_samples_rgb565{};
// int g_msaa_max_samples_rgb8{};
#if BA_OSTYPE_ANDROID
bool RendererGL::is_speedy_android_device_{};
@ -108,8 +84,11 @@ void RendererGL::CheckGLError(const char* file, int line) {
GLenum err = glGetError();
if (err != GL_NO_ERROR) {
const char* version = (const char*)glGetString(GL_VERSION);
BA_PRECONDITION_FATAL(version);
const char* vendor = (const char*)glGetString(GL_VENDOR);
BA_PRECONDITION_FATAL(vendor);
const char* renderer = (const char*)glGetString(GL_RENDERER);
BA_PRECONDITION_FATAL(renderer);
Log(LogLevel::kError,
"OpenGL Error at " + std::string(file) + " line " + std::to_string(line)
+ ": " + GLErrorToString(err) + "\nrenderer: " + renderer
@ -177,11 +156,27 @@ void RendererGL::CheckGLCapabilities_() {
BA_DEBUG_CHECK_GL_ERROR;
assert(g_base->app_adapter->InGraphicsContext());
draws_shields_funny_set_ = true;
const char* renderer = (const char*)glGetString(GL_RENDERER);
BA_PRECONDITION_FATAL(renderer);
const char* vendor = (const char*)glGetString(GL_VENDOR);
BA_PRECONDITION_FATAL(vendor);
const char* version_str = (const char*)glGetString(GL_VERSION);
BA_PRECONDITION_FATAL(version_str);
// Do a rough check to make sure we're running 3 or newer of GL/GLES.
// This query should be available even on older versions.
if (version_str[0] != '3' && version_str[0] != '4') {
FatalError(std::string("Invalid OpenGL version found (") + version_str
+ "). We require 3.0 or later.");
}
// Now fetch exact major/minor versions. This query requires version 3.0
// or newer which is why we checked that above.
glGetError(); // Clear any existing error so we don't die on it here.
glGetIntegerv(GL_MAJOR_VERSION, &gl_version_major_);
BA_PRECONDITION_FATAL(glGetError() == GL_NO_ERROR);
glGetIntegerv(GL_MINOR_VERSION, &gl_version_minor_);
BA_PRECONDITION_FATAL(glGetError() == GL_NO_ERROR);
const char* basestr;
if (gl_is_es()) {
@ -200,28 +195,20 @@ void RendererGL::CheckGLCapabilities_() {
std::vector<std::string> extensions;
bool used_num_extensions{};
// On the ES side we still support ES 2 which does not support the modern
// GL_NUM_EXTENSIONS route. Though I suppose we could just try it on ES
// and do the fallback if we get GL_INVALID_ENUM.
#if !BA_OPENGL_IS_ES
{
GLint num_extensions{};
glGetError(); // Clear any existing error.
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
if (glGetError() == GL_NO_ERROR) {
used_num_extensions = true;
extensions.reserve(num_extensions);
for (int i = 0; i < num_extensions; ++i) {
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
BA_PRECONDITION(extension);
extensions.push_back(extension);
}
// Do the modern gl thing of looking through a list of extensions; not a
// single string.
if (auto num_extensions = GLGetIntOptional(GL_NUM_EXTENSIONS)) {
used_num_extensions = true;
extensions.reserve(*num_extensions);
for (int i = 0; i < num_extensions; ++i) {
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
BA_PRECONDITION(extension);
extensions.push_back(extension);
}
}
#endif
// Fall back on parsing the single giant string if need be.
if (!used_num_extensions) {
} else {
Log(LogLevel::kWarning, "Falling back on legacy GL_EXTENSIONS parsing.");
// Fall back on parsing the single giant string if need be.
// (Can probably kill this).
auto* ex = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
BA_DEBUG_CHECK_GL_ERROR;
BA_PRECONDITION_FATAL(ex);
@ -349,13 +336,15 @@ void RendererGL::CheckGLCapabilities_() {
std::list<TextureCompressionType> c_types;
assert(g_base->graphics);
if (CheckGLExtension(extensions, "texture_compression_s3tc"))
if (CheckGLExtension(extensions, "texture_compression_s3tc")) {
c_types.push_back(TextureCompressionType::kS3TC);
}
// Limiting pvr support to iOS for the moment.
if (!g_buildconfig.ostype_android()) {
if (CheckGLExtension(extensions, "texture_compression_pvrtc"))
if (CheckGLExtension(extensions, "texture_compression_pvrtc")) {
c_types.push_back(TextureCompressionType::kPVR);
}
}
// All android devices should support etc1.
@ -375,33 +364,14 @@ void RendererGL::CheckGLCapabilities_() {
g_base->graphics_server->SetTextureCompressionTypes(c_types);
// Check whether we support high-quality mode (requires a few things like
// depth textures) For now lets also disallow high-quality in some VR
// environments.
// Both GL 3.2 and GL ES 3.0 support depth textures.
// if (!gl_is_es()) {
// supports_depth_textures_ = true;
// Both GL 3 and GL ES 3.0 support depth textures (and thus our high
// quality mode) as a core feature.
g_base->graphics->SetSupportsHighQualityGraphics(true);
// } else {
// if (CheckGLExtension(extensions, "depth_texture")) {
// supports_depth_textures_ = true;
// if (g_buildconfig.cardboard_build()) {
// g_base->graphics->SetSupportsHighQualityGraphics(false);
// } else {
// g_base->graphics->SetSupportsHighQualityGraphics(true);
// }
// } else {
// supports_depth_textures_ = false;
// g_base->graphics->SetSupportsHighQualityGraphics(false);
// }
// }
// Store the tex-compression type we support.
BA_DEBUG_CHECK_GL_ERROR;
// Anisotropic sampling is still an extension as of both GL 3.2 and ES 3,
// Anisotropic sampling is still an extension as of both GL 3 and ES 3,
// so we need to test for it.
anisotropic_support_ =
CheckGLExtension(extensions, "texture_filter_anisotropic");
@ -411,40 +381,6 @@ void RendererGL::CheckGLCapabilities_() {
BA_DEBUG_CHECK_GL_ERROR;
// VAO support is everywhere now.
// #if BA_OPENGL_IS_ES
// // We can run with our without VAOs but they're nice to have.
// g_vao_support =
// (glGenVertexArrays != nullptr && glDeleteVertexArrays != nullptr
// && glBindVertexArray != nullptr
// && (g_running_es3
// || CheckGLExtension(extensions, "vertex_array_object")));
// #else
// g_vao_support = true;
// #endif
// #if !BA_OPENGL_IS_ES
// Both of these are standard in GL 3.2 and GL ES 3; hooray!
// g_blit_framebuffer_support = true;
// g_framebuffer_multisample_support = true;
// #else
// #if BA_OSTYPE_IOS_TVOS
// g_blit_framebuffer_support = false;
// g_framebuffer_multisample_support = false;
// #elif BA_OSTYPE_MACOS
// g_blit_framebuffer_support = CheckGLExtension(extensions,
// "framebuffer_blit"); g_framebuffer_multisample_support = false;
// #else
// g_blit_framebuffer_support =
// (glBlitFramebuffer != nullptr
// && (g_running_es3 || CheckGLExtension(ex, "framebuffer_blit")));
// g_framebuffer_multisample_support =
// (glRenderbufferStorageMultisample != nullptr
// && (g_running_es3 || (CheckGLExtension(ex,
// "framebuffer_multisample"))));
// #endif
// #endif
if (gl_is_es()) {
// GL ES 3 has glInvalidateFramebuffer as part of the standard.
invalidate_framebuffer_support_ = true;
@ -454,68 +390,25 @@ void RendererGL::CheckGLCapabilities_() {
invalidate_framebuffer_support_ = false;
}
// #if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID
// #if BA_OSTYPE_IOS_TVOS
// g_discard_framebuffer_support = CheckGLExtension(ex,
// "discard_framebuffer");
// #else
// g_discard_framebuffer_support =
// (glDiscardFramebufferEXT != nullptr
// && CheckGLExtension(ex, "discard_framebuffer"));
// #endif
// g_invalidate_framebuffer_support =
// (g_running_es3 && glInvalidateFramebuffer != nullptr);
// #else
// g_discard_framebuffer_support = false;
// g_invalidate_framebuffer_support = false;
// #endif
// g_seamless_cube_maps = CheckGLExtension(ex, "seamless_cube_map");
// #if BA_OSTYPE_WINDOWS
// // The vmware gl driver breaks horrifically with VAOs turned on.
// const char* vendor = (const char*)glGetString(GL_VENDOR);
// if (strstr(vendor, "VMware")) {
// g_vao_support = false;
// }
// #endif
// #if BA_OSTYPE_ANDROID
// // VAOs currently break my poor kindle fire hd to the point of rebooting
// it if (!g_running_es3 && !is_tegra_4_) {
// g_vao_support = false;
// }
// // also they seem to be problematic on zenfone2's gpu.
// if (strstr(renderer, "PowerVR Rogue G6430")) {
// g_vao_support = false;
// }
// #endif
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
&combined_texture_image_unit_count_);
combined_texture_image_unit_count_ =
GLGetInt(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
// If we're running ES3, ask about our max multisample counts and whether we
// can enable MSAA.
// enable_msaa_ = false; // start pessimistic
msaa_max_samples_rgb565_ = msaa_max_samples_rgb8_ = 0; // start pessimistic
// FIXME - NEED TO CHECK DESKTOP GL VERSION TO USE THIS THERE.
#if BA_OSTYPE_ANDROID || BA_RIFT_BUILD
bool check_msaa = false;
bool have_gl_get_internal_format_iv{};
if (gl_is_es()) {
// This is available on ES 3.
have_gl_get_internal_format_iv = true;
} else {
// This is available on GL 4.2 or newer.
if (gl_version_major() == 4 && gl_version_minor() >= 2) {
have_gl_get_internal_format_iv = true;
}
}
#if BA_OSTYPE_ANDROID
// if (g_running_es3) {
check_msaa = true;
// }
#endif // BA_OSTYPE_ANDROID
#if BA_RIFT_BUILD
check_msaa = true;
#endif // BA_RIFT_BUILD
if (check_msaa) {
if (have_gl_get_internal_format_iv) {
GLint count;
glGetInternalformativ(GL_RENDERBUFFER, GL_RGB565, GL_NUM_SAMPLE_COUNTS, 1,
&count);
@ -543,10 +436,17 @@ void RendererGL::CheckGLCapabilities_() {
BA_LOG_ONCE(LogLevel::kError, "Got 0 samplecounts for RGB8");
msaa_max_samples_rgb8_ = 0;
}
} else {
// For older GL (which includes all Macs) it sounds like this is the way
// to query max samples?.. but I don't know for sure if this applies to
// renderbuffer targets or just the default drawable. Will it ever be
// different?
auto max_samples = GLGetIntOptional(GL_MAX_SAMPLES);
if (max_samples.has_value()) {
msaa_max_samples_rgb565_ = msaa_max_samples_rgb8_ = *max_samples;
}
}
#endif // BA_OSTYPE_ANDROID
BA_DEBUG_CHECK_GL_ERROR;
first_extension_check_ = false;
@ -639,7 +539,7 @@ void RendererGL::BindTextureUnit(uint32_t tex_unit) {
assert(tex_unit >= 0 && tex_unit < kMaxGLTexUnitsUsed);
if (active_tex_unit_ != -1) {
// Make sure our internal state stays correct.
assert(DebugGLGetInt(GL_ACTIVE_TEXTURE) == GL_TEXTURE0 + active_tex_unit_);
assert(GLGetInt(GL_ACTIVE_TEXTURE) == GL_TEXTURE0 + active_tex_unit_);
}
if (active_tex_unit_ != tex_unit) {
active_tex_unit_ = tex_unit;
@ -649,18 +549,39 @@ void RendererGL::BindTextureUnit(uint32_t tex_unit) {
}
}
auto RendererGL::DebugGLGetInt(GLenum name) -> int {
// This is probably inefficient so make sure we don't leave it on in
// release builds.
assert(g_buildconfig.debug_build());
auto RendererGL::GLGetInt(GLenum name) -> int {
assert(g_base->app_adapter->InGraphicsContext());
// Clear any error coming in; don't want to die for something that's not
// ours.
BA_DEBUG_CHECK_GL_ERROR;
// Clear any error coming in; don't want to fail for something that's not
// our problem.
if (g_buildconfig.debug_build()) {
BA_DEBUG_CHECK_GL_ERROR;
} else {
glGetError();
}
GLint val;
glGetIntegerv(name, &val);
assert(glGetError() == GL_NO_ERROR);
if (glGetError() != GL_NO_ERROR) {
FatalError("Unable to fetch GL int " + std::to_string(name));
}
return val;
}
auto RendererGL::GLGetIntOptional(GLenum name) -> std::optional<int> {
assert(g_base->app_adapter->InGraphicsContext());
// Clear any error coming in; don't want to fail for something that's not
// our problem.
if (g_buildconfig.debug_build()) {
BA_DEBUG_CHECK_GL_ERROR;
} else {
glGetError();
}
GLint val;
glGetIntegerv(name, &val);
if (glGetError() != GL_NO_ERROR) {
return {};
}
return val;
}
@ -669,14 +590,14 @@ void RendererGL::BindFramebuffer(GLuint fb) {
glBindFramebuffer(GL_FRAMEBUFFER, fb);
active_framebuffer_ = fb;
} else {
assert(DebugGLGetInt(GL_FRAMEBUFFER_BINDING) == fb);
assert(GLGetInt(GL_FRAMEBUFFER_BINDING) == fb);
}
}
void RendererGL::BindArrayBuffer(GLuint b) {
if (active_array_buffer_ != -1) {
// Make sure our internal state stays correct.
assert(DebugGLGetInt(GL_ARRAY_BUFFER_BINDING) == active_array_buffer_);
assert(GLGetInt(GL_ARRAY_BUFFER_BINDING) == active_array_buffer_);
}
if (active_array_buffer_ != b) {
glBindBuffer(GL_ARRAY_BUFFER, b);
@ -702,7 +623,7 @@ void RendererGL::BindTexture_(GLuint type, GLuint tex, GLuint tex_unit) {
if (g_buildconfig.debug_build()) {
if (bound_textures_2d_[tex_unit] != -1) {
BindTextureUnit(tex_unit);
assert(DebugGLGetInt(GL_TEXTURE_BINDING_2D)
assert(GLGetInt(GL_TEXTURE_BINDING_2D)
== bound_textures_2d_[tex_unit]);
}
}
@ -718,7 +639,7 @@ void RendererGL::BindTexture_(GLuint type, GLuint tex, GLuint tex_unit) {
if (g_buildconfig.debug_build()) {
if (bound_textures_cube_map_[tex_unit] != -1) {
BindTextureUnit(tex_unit);
assert(DebugGLGetInt(GL_TEXTURE_BINDING_CUBE_MAP)
assert(GLGetInt(GL_TEXTURE_BINDING_CUBE_MAP)
== bound_textures_cube_map_[tex_unit]);
}
}
@ -825,7 +746,6 @@ void RendererGL::InvalidateFramebuffer(bool color, bool depth,
// Currently this is ES only for us.
#if BA_OPENGL_IS_ES
// #if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID
if (invalidate_framebuffer_support()) {
GLenum attachments[5];
@ -834,11 +754,9 @@ void RendererGL::InvalidateFramebuffer(bool color, bool depth,
if (active_framebuffer_ == 0 && !target_read_framebuffer) {
if (color) {
attachments[count++] = GL_COLOR;
// attachments[count++] = GL_COLOR_EXT;
}
if (depth) {
attachments[count++] = GL_DEPTH;
// attachments[count++] = GL_DEPTH_EXT;
}
} else {
if (color) {
@ -848,29 +766,16 @@ void RendererGL::InvalidateFramebuffer(bool color, bool depth,
attachments[count++] = GL_DEPTH_ATTACHMENT;
}
// Apparently the oculus docs say glInvalidateFramebuffer errors on a
// mali es3 implementation so they always use glDiscard when present.
// if () {
// #if BA_OSTYPE_IOS_TVOS
// throw Exception(); // shouldnt happen
// #else
glInvalidateFramebuffer(
target_read_framebuffer ? GL_READ_FRAMEBUFFER : GL_FRAMEBUFFER, count,
attachments);
// #endif
}
// } else {
// // If we've got a read-framebuffer, we should have invalidate too.
// assert(!target_read_framebuffer);
// glDiscardFramebufferEXT(GL_FRAMEBUFFER, count, attachments);
// }
BA_DEBUG_CHECK_GL_ERROR;
}
#else
// Make noise if we should be doing this here too...
// Make noise if we should be doing this here too at some point.
assert(!invalidate_framebuffer_support());
#endif // BA_OPENGL_IS_ES
// #endif // BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID
}
RendererGL::~RendererGL() {
@ -2701,8 +2606,7 @@ void RendererGL::Load() {
// Grab the current framebuffer and consider that to be our 'screen'
// framebuffer. This can be 0 for the main framebuffer or can be
// something else.
glGetIntegerv(GL_FRAMEBUFFER_BINDING,
reinterpret_cast<GLint*>(&screen_framebuffer_));
screen_framebuffer_ = GLGetInt(GL_FRAMEBUFFER_BINDING);
}
Renderer::Load();
int high_qual_pp_flag =
@ -3340,9 +3244,7 @@ void RendererGL::VREyeRenderBegin() {
glDisable(GL_FRAMEBUFFER_SRGB);
#endif // BA_RIFT_BUILD
GLuint fb;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, reinterpret_cast<GLint*>(&fb));
screen_framebuffer_ = fb;
screen_framebuffer_ = GLGetInt(GL_FRAMEBUFFER_BINDING);
}
#if BA_VR_BUILD

View File

@ -217,7 +217,14 @@ class RendererGL : public Renderer {
#endif
}
auto DebugGLGetInt(GLenum name) -> int;
auto gl_version_minor() const { return gl_version_minor_; }
auto gl_version_major() const { return gl_version_major_; }
// Wraps glGetIntegerv(). Triggers FatalError if get fails.
auto GLGetInt(GLenum name) -> int;
// Wraps glGetIntegerv(); returns empty value if get fails.
auto GLGetIntOptional(GLenum name) -> std::optional<int>;
private:
static auto GetFunkyDepthIssue_() -> bool;
@ -251,18 +258,28 @@ class RendererGL : public Renderer {
void BindArrayBuffer(GLuint b);
void SetBlend(bool b);
void SetBlendPremult(bool b);
millisecs_t dof_update_time_{};
std::vector<Object::Ref<FramebufferObjectGL> > blur_buffers_;
// bool supports_depth_textures_{};
bool blend_{};
bool blend_premult_{};
bool first_extension_check_{true};
bool is_tegra_4_{};
bool is_tegra_k1_{};
bool is_recent_adreno_{};
bool is_adreno_{};
bool enable_msaa_{};
bool draw_at_equal_depth_{};
bool depth_writing_enabled_{};
bool depth_testing_enabled_{};
bool data_loaded_{};
bool draw_front_{};
bool got_screen_framebuffer_{};
bool double_sided_{};
bool invalidate_framebuffer_support_{};
GLint gl_version_major_{};
GLint gl_version_minor_{};
int last_blur_res_count_{};
float last_cam_buffer_width_{};
float last_cam_buffer_height_{};
int last_blur_res_count_{};
float vignette_tex_outer_r_{};
float vignette_tex_outer_g_{};
float vignette_tex_outer_b_{};
@ -271,13 +288,7 @@ class RendererGL : public Renderer {
float vignette_tex_inner_b_{};
float depth_range_min_{};
float depth_range_max_{};
bool draw_at_equal_depth_{};
bool depth_writing_enabled_{};
bool depth_testing_enabled_{};
bool data_loaded_{};
bool draw_front_{};
bool got_screen_framebuffer_{};
GLuint screen_framebuffer_{};
GLint screen_framebuffer_{};
GLuint random_tex_{};
GLuint vignette_tex_{};
GraphicsQuality vignette_quality_{};
@ -285,6 +296,8 @@ class RendererGL : public Renderer {
GLint viewport_y_{};
GLint viewport_width_{};
GLint viewport_height_{};
millisecs_t dof_update_time_{};
std::vector<Object::Ref<FramebufferObjectGL> > blur_buffers_;
std::vector<std::unique_ptr<ProgramGL> > shaders_;
ProgramSimpleGL* simple_color_prog_{};
ProgramSimpleGL* simple_tex_prog_{};
@ -326,24 +339,18 @@ class RendererGL : public Renderer {
ProgramPostProcessGL* postprocess_distort_prog_{};
static bool funky_depth_issue_set_;
static bool funky_depth_issue_;
static bool draws_shields_funny_set_;
static bool draws_shields_funny_;
#if BA_OSTYPE_ANDROID
static bool is_speedy_android_device_;
static bool is_extra_speedy_android_device_;
#endif
ProgramGL* current_program_{};
bool double_sided_{};
std::vector<Rect> scissor_rects_;
GLuint current_vertex_array_{};
bool vertex_attrib_arrays_enabled_[kVertexAttrCount]{};
int active_tex_unit_{};
int active_framebuffer_{};
int active_array_buffer_{};
int bound_textures_2d_[kMaxGLTexUnitsUsed]{};
int bound_textures_cube_map_[kMaxGLTexUnitsUsed]{};
bool blend_{};
bool blend_premult_{};
std::unique_ptr<MeshDataSimpleFullGL> screen_mesh_;
std::vector<MeshDataSimpleSplitGL*> recycle_mesh_datas_simple_split_;
std::vector<MeshDataObjectSplitGL*> recycle_mesh_datas_object_split_;
@ -355,7 +362,6 @@ class RendererGL : public Renderer {
GLint combined_texture_image_unit_count_{};
GLint anisotropic_support_{};
GLfloat max_anisotropy_{};
bool invalidate_framebuffer_support_{};
int msaa_max_samples_rgb565_{-1};
int msaa_max_samples_rgb8_{-1};
};

View File

@ -105,6 +105,8 @@ class BasePython {
kAppPushApplyAppConfigCall,
kStringEditAdapterCanBeReplacedCall,
kDevConsoleStringEditAdapterClass,
kGetDevConsoleTabNamesCall,
kAppDevConsoleDoRefreshTabCall,
kLast // Sentinel; must be at end.
};

View File

@ -12,6 +12,7 @@
#include "ballistica/base/python/base_python.h"
#include "ballistica/base/python/class/python_class_simple_sound.h"
#include "ballistica/base/support/app_config.h"
#include "ballistica/base/ui/dev_console.h"
#include "ballistica/base/ui/ui.h"
#include "ballistica/shared/generic/utils.h"
@ -1450,6 +1451,169 @@ static PyMethodDef PyFatalErrorDef = {
"however, Exceptions should be preferred.",
};
// ------------------------- dev_console_add_button ----------------------------
static auto PyDevConsoleAddButton(PyObject* self, PyObject* args) -> PyObject* {
BA_PYTHON_TRY;
BA_PRECONDITION(g_base->InLogicThread());
auto* dev_console = g_base->ui->dev_console();
BA_PRECONDITION(dev_console);
BA_PRECONDITION(dev_console->IsActive());
const char* label;
float x;
float y;
float width;
float height;
PyObject* call;
const char* h_anchor;
float label_scale;
float corner_radius;
if (!PyArg_ParseTuple(args, "sffffOsff", &label, &x, &y, &width, &height,
&call, &h_anchor, &label_scale, &corner_radius)) {
return nullptr;
}
dev_console->AddButton(label, x, y, width, height, call, h_anchor,
label_scale, corner_radius);
Py_RETURN_NONE;
BA_PYTHON_CATCH;
}
static PyMethodDef PyDevConsoleAddButtonDef = {
"dev_console_add_button", // name
(PyCFunction)PyDevConsoleAddButton, // method
METH_VARARGS, // flags
"dev_console_add_button(\n"
" label: str,\n"
" x: float,\n"
" y: float,\n"
" width: float,\n"
" height: float,\n"
" call: Callable[[], Any] | None,\n"
" h_anchor: str,\n"
" label_scale: float,\n"
" corner_radius: float,\n"
") -> None\n"
"\n"
"(internal)",
};
// -------------------- dev_console_add_python_terminal ------------------------
static auto PyDevConsoleAddPythonTerminal(PyObject* self, PyObject* args)
-> PyObject* {
BA_PYTHON_TRY;
BA_PRECONDITION(g_base->InLogicThread());
auto* dev_console = g_base->ui->dev_console();
BA_PRECONDITION(dev_console);
BA_PRECONDITION(dev_console->IsActive());
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
}
dev_console->AddPythonTerminal();
Py_RETURN_NONE;
BA_PYTHON_CATCH;
}
static PyMethodDef PyDevConsoleAddPythonTerminalDef = {
"dev_console_add_python_terminal", // name
(PyCFunction)PyDevConsoleAddPythonTerminal, // method
METH_VARARGS, // flags
"dev_console_add_python_terminal() -> None\n"
"\n"
"(internal)",
};
// ------------------------ dev_console_tab_width ------------------------------
static auto PyDevConsoleTabWidth(PyObject* self) -> PyObject* {
BA_PYTHON_TRY;
BA_PRECONDITION(g_base->InLogicThread());
auto* dev_console = g_base->ui->dev_console();
BA_PRECONDITION(dev_console);
BA_PRECONDITION(dev_console->IsActive());
return PyFloat_FromDouble(dev_console->Width());
BA_PYTHON_CATCH;
}
static PyMethodDef PyDevConsoleTabWidthDef = {
"dev_console_tab_width", // name
(PyCFunction)PyDevConsoleTabWidth, // method
METH_NOARGS, // flags
"dev_console_tab_width() -> float\n"
"\n"
"(internal)",
};
// ------------------------ dev_console_tab_height -----------------------------
static auto PyDevConsoleTabHeight(PyObject* self) -> PyObject* {
BA_PYTHON_TRY;
BA_PRECONDITION(g_base->InLogicThread());
auto* dev_console = g_base->ui->dev_console();
BA_PRECONDITION(dev_console);
BA_PRECONDITION(dev_console->IsActive());
return PyFloat_FromDouble(dev_console->Height());
BA_PYTHON_CATCH;
}
static PyMethodDef PyDevConsoleTabHeightDef = {
"dev_console_tab_height", // name
(PyCFunction)PyDevConsoleTabHeight, // method
METH_NOARGS, // flags
"dev_console_tab_height() -> float\n"
"\n"
"(internal)",
};
// ----------------------- dev_console_base_scale ------------------------------
static auto PyDevConsoleBaseScale(PyObject* self) -> PyObject* {
BA_PYTHON_TRY;
BA_PRECONDITION(g_base->InLogicThread());
auto* dev_console = g_base->ui->dev_console();
BA_PRECONDITION(dev_console);
BA_PRECONDITION(dev_console->IsActive());
return PyFloat_FromDouble(dev_console->BaseScale());
BA_PYTHON_CATCH;
}
static PyMethodDef PyDevConsoleBaseScaleDef = {
"dev_console_base_scale", // name
(PyCFunction)PyDevConsoleBaseScale, // method
METH_NOARGS, // flags
"dev_console_base_scale() -> float\n"
"\n"
"(internal)",
};
// -------------------- dev_console_request_refresh ----------------------------
static auto PyDevConsoleRequestRefresh(PyObject* self) -> PyObject* {
BA_PYTHON_TRY;
BA_PRECONDITION(g_base->InLogicThread());
auto* dev_console = g_base->ui->dev_console();
BA_PRECONDITION(dev_console);
BA_PRECONDITION(dev_console->IsActive());
dev_console->RequestRefresh();
Py_RETURN_NONE;
BA_PYTHON_CATCH;
}
static PyMethodDef PyDevConsoleRequestRefreshDef = {
"dev_console_request_refresh", // name
(PyCFunction)PyDevConsoleRequestRefresh, // method
METH_NOARGS, // flags
"dev_console_request_refresh() -> None\n"
"\n"
"(internal)",
};
// -----------------------------------------------------------------------------
auto PythonMethodsMisc::GetMethods() -> std::vector<PyMethodDef> {
@ -1505,6 +1669,12 @@ auto PythonMethodsMisc::GetMethods() -> std::vector<PyMethodDef> {
PyNativeStackTraceDef,
PyOpenDirExternallyDef,
PyFatalErrorDef,
PyDevConsoleAddButtonDef,
PyDevConsoleAddPythonTerminalDef,
PyDevConsoleTabWidthDef,
PyDevConsoleTabHeightDef,
PyDevConsoleBaseScaleDef,
PyDevConsoleRequestRefreshDef,
};
}

View File

@ -16,6 +16,7 @@
#include "ballistica/core/core.h"
#include "ballistica/core/platform/support/min_sdl.h"
#include "ballistica/shared/foundation/event_loop.h"
#include "ballistica/shared/foundation/macros.h"
#include "ballistica/shared/generic/utils.h"
#include "ballistica/shared/python/python_command.h"
#include "ballistica/shared/python/python_sys.h"
@ -103,7 +104,8 @@ class DevConsole::Button_ : public DevConsole::Widget_ {
template <typename F>
Button_(const std::string& label, float text_scale, DevButtonAttach_ attach,
float x, float y, float width, float height, const F& lambda)
float x, float y, float width, float height, float corner_radius,
const F& lambda)
: attach{attach},
x{x},
y{y},
@ -112,14 +114,10 @@ class DevConsole::Button_ : public DevConsole::Widget_ {
call{NewLambdaRunnable(lambda)},
text_scale{text_scale},
mesh(0.0f, 0.0f, 0.0f, width, height,
NinePatchMesh::BorderForRadius(kDevConsoleButtonCornerRadius,
width, height),
NinePatchMesh::BorderForRadius(kDevConsoleButtonCornerRadius,
height, width),
NinePatchMesh::BorderForRadius(kDevConsoleButtonCornerRadius,
width, height),
NinePatchMesh::BorderForRadius(kDevConsoleButtonCornerRadius,
height, width)) {
NinePatchMesh::BorderForRadius(corner_radius, width, height),
NinePatchMesh::BorderForRadius(corner_radius, height, width),
NinePatchMesh::BorderForRadius(corner_radius, width, height),
NinePatchMesh::BorderForRadius(corner_radius, height, width)) {
text_group.SetText(label, TextMesh::HAlign::kCenter,
TextMesh::VAlign::kCenter);
}
@ -309,9 +307,10 @@ class DevConsole::TabButton_ : public DevConsole::Widget_ {
}
};
class DevConsole::Line_ {
class DevConsole::OutputLine_ {
public:
Line_(std::string s_in, double c) : creation_time(c), s(std::move(s_in)) {}
OutputLine_(std::string s_in, double c)
: creation_time(c), s(std::move(s_in)) {}
double creation_time;
std::string s;
auto GetText() -> TextGroup& {
@ -340,43 +339,112 @@ DevConsole::DevConsole() {
title_text_group_.SetText(title);
built_text_group_.SetText("Built: " __DATE__ " " __TIME__);
prompt_text_group_.SetText(">");
Refresh();
}
void DevConsole::Refresh() {
BA_PRECONDITION(g_base->InLogicThread());
buttons_.clear();
tab_buttons_.clear();
RefreshTabsButtons_();
DevConsole::~DevConsole() = default;
if (active_tab_ == "Python") {
float bs = PythonConsoleBaseScale_();
buttons_.emplace_back(std::make_unique<Button_>(
"Exec", 0.75f * bs, DevButtonAttach_::kRight, -33.0f * bs, 15.95f * bs,
32.0f * bs, 13.0f * bs, [this] { Exec(); }));
void DevConsole::RefreshTabButtons_() {
// Ask the Python layer for the latest set of tabs.
tabs_ = g_base->python->objs()
.Get(BasePython::ObjID::kGetDevConsoleTabNamesCall)
.Call()
.ValueAsStringSequence();
// If we have tabs and none of them are selected, select the first.
if (!tabs_.empty()) {
bool found{};
for (auto&& tab : tabs_) {
if (active_tab_ == tab) {
found = true;
break;
}
}
if (!found) {
active_tab_ = tabs_.front();
}
}
}
void DevConsole::RefreshTabsButtons_() {
float bs = PythonConsoleBaseScale_();
// Now rebuild our buttons for them.
tab_buttons_.clear();
float bs = BaseScale();
float bwidth = 90.0f * bs;
float bheight = 26.0f * bs;
float bscale = 0.8f * bs;
float total_width = tabs_.size() * bwidth;
float x = total_width * -0.5f;
for (auto&& tab : tabs_) {
tab_buttons_.emplace_back(std::make_unique<TabButton_>(
tab, active_tab_ == tab, bscale, DevButtonAttach_::kCenter, x, -bheight,
bwidth, bheight, [this, tab] {
active_tab_ = tab;
Refresh();
RefreshTabButtons_();
RefreshTabContents_();
}));
x += bwidth;
}
}
DevConsole::~DevConsole() = default;
void DevConsole::RefreshTabContents_() {
BA_PRECONDITION(g_base->InLogicThread());
// Consider any refresh requests fulfilled. Subsequent refresh-requests
// will generate a new refresh at this point.
refresh_pending_ = false;
// Clear to an empty slate.
buttons_.clear();
python_terminal_visible_ = false;
// Now ask the Python layer to fill this tab in.
PythonRef args(Py_BuildValue("(s)", active_tab_.c_str()), PythonRef::kSteal);
g_base->python->objs()
.Get(BasePython::ObjID::kAppDevConsoleDoRefreshTabCall)
.Call(args);
}
void DevConsole::AddButton(const char* label, float x, float y, float width,
float height, PyObject* call, const char* h_anchor,
float label_scale, float corner_radius) {
assert(g_base->InLogicThread());
DevButtonAttach_ anchor;
if (!strcmp(h_anchor, "left")) {
anchor = DevButtonAttach_::kLeft;
} else if (!strcmp(h_anchor, "right")) {
anchor = DevButtonAttach_::kRight;
} else {
assert(!strcmp(h_anchor, "center"));
anchor = DevButtonAttach_::kCenter;
}
// auto call_obj = PythonRef::Acquired(call);
buttons_.emplace_back(std::make_unique<Button_>(
label, label_scale, anchor, x, y, width, height, corner_radius,
[this, call_obj = PythonRef::Acquired(call)] {
if (call_obj.Get() != Py_None) {
call_obj.Call();
}
}));
}
void DevConsole::AddPythonTerminal() {
float bs = BaseScale();
buttons_.emplace_back(std::make_unique<Button_>(
"Exec", 0.75f * bs, DevButtonAttach_::kRight, -33.0f * bs, 15.95f * bs,
32.0f * bs, 13.0f * bs, 2.0 * bs, [this] { Exec(); }));
python_terminal_visible_ = true;
}
void DevConsole::RequestRefresh() {
assert(g_base->InLogicThread());
// Schedule a refresh. If one is already scheduled but hasn't run, do
// nothing.
if (refresh_pending_) {
return;
}
refresh_pending_ = true;
g_base->logic->event_loop()->PushCall([this] { RefreshTabContents_(); });
}
auto DevConsole::HandleMouseDown(int button, float x, float y) -> bool {
assert(g_base->InLogicThread());
@ -404,13 +472,21 @@ auto DevConsole::HandleMouseDown(int button, float x, float y) -> bool {
return false;
}
if (button == 1) {
python_console_pressed_ = true;
if (button == 1 && python_terminal_visible_) {
python_terminal_pressed_ = true;
}
return true;
}
auto DevConsole::Width() -> float {
return g_base->graphics->screen_virtual_width();
}
auto DevConsole::Height() -> float {
return g_base->graphics->screen_virtual_height() - Bottom_();
}
void DevConsole::HandleMouseUp(int button, float x, float y) {
assert(g_base->InLogicThread());
float bottom{Bottom_()};
@ -424,8 +500,8 @@ void DevConsole::HandleMouseUp(int button, float x, float y) {
}
}
if (button == 1 && python_console_pressed_) {
python_console_pressed_ = false;
if (button == 1 && python_terminal_pressed_) {
python_terminal_pressed_ = false;
if (y > bottom) {
// If we're not getting fed keyboard events and have a string editor
// available, invoke it.
@ -548,19 +624,6 @@ auto DevConsole::HandleKeyPress(const SDL_Keysym* keysym) -> bool {
break;
}
default: {
// #if BA_SDL2_BUILD || BA_MINSDL_BUILD
// // (in SDL2/Non-SDL we dont' get chars from keypress events;
// // they come through as text edit events)
// #else // BA_SDL2_BUILD
// if (keysym->unicode < 0x80 && keysym->unicode > 0) {
// std::vector<uint32_t> unichars =
// Utils::UnicodeFromUTF8(input_string_, "cjofrh0");
// unichars.push_back(keysym->unicode);
// input_string_ = Utils::GetValidUTF8(
// Utils::UTF8FromUnicode(unichars).c_str(), "sdkr");
// input_text_dirty_ = true;
// }
// #endif // BA_SDL2_BUILD
break;
}
}
@ -576,9 +639,9 @@ void DevConsole::Exec() {
input_history_position_ = 0;
if (input_string_ == "clear") {
last_line_.clear();
lines_.clear();
output_lines_.clear();
} else {
SubmitCommand_(input_string_);
SubmitPythonCommand_(input_string_);
}
input_history_.push_front(input_string_);
if (input_history_.size() > 100) {
@ -588,7 +651,7 @@ void DevConsole::Exec() {
input_text_dirty_ = true;
}
void DevConsole::SubmitCommand_(const std::string& command) {
void DevConsole::SubmitPythonCommand_(const std::string& command) {
assert(g_base);
g_base->logic->event_loop()->PushCall([command, this] {
// These are always run in whichever context is 'visible'.
@ -631,9 +694,12 @@ void DevConsole::ToggleState() {
switch (state_) {
case State_::kInactive:
state_ = State_::kMini;
RefreshTabButtons_();
RefreshTabContents_();
break;
case State_::kMini:
state_ = State_::kFull;
RefreshTabContents_();
break;
case State_::kFull:
state_ = State_::kInactive;
@ -650,6 +716,9 @@ auto DevConsole::HandleTextEditing(const std::string& text) -> bool {
}
// 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;
}
@ -679,9 +748,9 @@ void DevConsole::Print(const std::string& s_in) {
// Spit out all completed lines and keep the last one as lastline.
for (size_t i = 0; i < broken_up.size() - 1; i++) {
lines_.emplace_back(broken_up[i], g_base->logic->display_time());
if (lines_.size() > kDevConsoleLineLimit) {
lines_.pop_front();
output_lines_.emplace_back(broken_up[i], g_base->logic->display_time());
if (output_lines_.size() > kDevConsoleLineLimit) {
output_lines_.pop_front();
}
}
last_line_ = broken_up[broken_up.size() - 1];
@ -689,13 +758,18 @@ void DevConsole::Print(const std::string& s_in) {
}
auto DevConsole::Bottom_() const -> float {
float bs = PythonConsoleBaseScale_();
float vh = g_base->graphics->screen_virtual_height();
float ratio =
(g_base->logic->display_time() - transition_start_) / kTransitionSeconds;
float bottom;
float mini_size = 90.0f * bs;
// NOTE: Originally I was tweaking this based on UI scale, but I decided
// that it would be a better idea to have a constant value everywhere.
// dev-consoles are not meant to be especially pretty and I think it is
// more important for them to be able to be written to a known hard-coded
// mini-size.
float mini_size = 100.0f;
if (state_ == State_::kMini) {
bottom = vh - mini_size;
} else {
@ -724,7 +798,7 @@ auto DevConsole::Bottom_() const -> float {
}
void DevConsole::Draw(FrameDef* frame_def) {
float bs = PythonConsoleBaseScale_();
float bs = BaseScale();
RenderPass* pass = frame_def->overlay_front_pass();
// If we're not yet transitioning in for the first time OR have completed
@ -753,7 +827,7 @@ void DevConsole::Draw(FrameDef* frame_def) {
c.SetColor(0, 0, 0.1f, 0.9f);
c.DrawMesh(&bg_mesh_);
c.Submit();
if (active_tab_ == "Python") {
if (python_terminal_visible_) {
c.SetColor(1.0f, 1.0f, 1.0f, 0.1f);
c.DrawMesh(&stripe_mesh_);
c.Submit();
@ -779,7 +853,7 @@ void DevConsole::Draw(FrameDef* frame_def) {
}
}
if (active_tab_ == "Python") {
if (python_terminal_visible_) {
if (input_text_dirty_) {
input_text_group_.SetText(input_string_);
input_text_dirty_ = false;
@ -887,7 +961,7 @@ void DevConsole::Draw(FrameDef* frame_def) {
}
v += v_inc;
}
for (auto i = lines_.rbegin(); i != lines_.rend(); i++) {
for (auto i = output_lines_.rbegin(); i != output_lines_.rend(); i++) {
int elem_count = i->GetText().GetElementCount();
for (int e = 0; e < elem_count; e++) {
c.SetTexture(i->GetText().GetElementTexture(e));
@ -922,7 +996,7 @@ void DevConsole::Draw(FrameDef* frame_def) {
}
}
auto DevConsole::PythonConsoleBaseScale_() const -> float {
auto DevConsole::BaseScale() const -> float {
switch (g_base->ui->scale()) {
case UIScale::kLarge:
return 1.5f;

View File

@ -51,24 +51,42 @@ class DevConsole {
auto HandleMouseDown(int button, float x, float y) -> bool;
void HandleMouseUp(int button, float x, float y);
void Exec();
void Refresh();
void AddButton(const char* label, float x, float y, float width, float height,
PyObject* call, const char* h_anchor, float label_scale,
float corner_radius);
void AddPythonTerminal();
auto Width() -> float;
auto Height() -> float;
auto BaseScale() const -> float;
void RequestRefresh();
private:
class Widget_;
class Button_;
class ToggleButton_;
class TabButton_;
class Line_;
enum class State_ { kInactive, kMini, kFull };
class OutputLine_;
enum class State_ : uint8_t { kInactive, kMini, kFull };
auto Bottom_() const -> float;
auto PythonConsoleBaseScale_() const -> float;
void SubmitCommand_(const std::string& command);
void SubmitPythonCommand_(const std::string& command);
void InvokeStringEditor_();
void RefreshTabsButtons_();
void RefreshTabButtons_();
void RefreshTabContents_();
std::list<std::string> tabs_{"Python", "AppModes", "Logging", "Graphics"};
std::string active_tab_{"Python"};
bool input_text_dirty_{true};
bool input_enabled_{};
bool last_line_mesh_dirty_{true};
bool python_terminal_visible_{};
bool python_terminal_pressed_{};
bool refresh_pending_{};
State_ state_{State_::kInactive};
State_ state_prev_{State_::kInactive};
millisecs_t last_input_text_change_time_{};
double transition_start_{};
int input_history_position_{};
ImageMesh bg_mesh_;
ImageMesh stripe_mesh_;
ImageMesh border_mesh_;
@ -76,21 +94,15 @@ class DevConsole {
TextGroup title_text_group_;
TextGroup prompt_text_group_;
TextGroup input_text_group_;
millisecs_t last_input_text_change_time_{};
bool input_text_dirty_{true};
double transition_start_{};
State_ state_{State_::kInactive};
State_ state_prev_{State_::kInactive};
bool input_enabled_{};
std::string input_string_;
std::list<std::string> input_history_;
int input_history_position_{};
std::list<Line_> lines_;
std::string last_line_;
Object::Ref<TextGroup> last_line_mesh_group_;
bool last_line_mesh_dirty_{true};
bool python_console_pressed_{};
std::string input_string_;
std::list<std::string> tabs_{"Python", "AppModes", "Logging", "Graphics",
"UI"};
std::string active_tab_{"Python"};
PythonRef string_edit_adapter_;
Object::Ref<TextGroup> last_line_mesh_group_;
std::list<std::string> input_history_;
std::list<OutputLine_> output_lines_;
std::vector<std::unique_ptr<Widget_> > buttons_;
std::vector<std::unique_ptr<Widget_> > tab_buttons_;
};

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 = 21401;
const int kEngineBuildNumber = 21405;
const char* kEngineVersion = "1.7.28";
const int kEngineApiVersion = 8;

View File

@ -21,7 +21,7 @@
#endif
#define BA_OSTYPE_MACOS 1
#define BA_HAVE_FRAMEWORK_OPENAL 1
// #define BA_HAVE_FRAMEWORK_OPENAL 1
#elif __linux__

View File

@ -225,7 +225,7 @@ auto Python::GetPyFloats(PyObject* o) -> std::vector<float> {
return vals;
}
auto Python::GetPyStrings(PyObject* o) -> std::list<std::string> {
auto Python::GetPyStringSequence(PyObject* o) -> std::list<std::string> {
assert(HaveGIL());
BA_PRECONDITION_FATAL(o != nullptr);

View File

@ -125,7 +125,7 @@ class Python {
static auto GetPyInts(PyObject* o) -> std::vector<int>;
static auto GetPyUInts64(PyObject* o) -> std::vector<uint64_t>;
static auto GetPyPoint2D(PyObject* o) -> Point2D;
static auto GetPyStrings(PyObject* o) -> std::list<std::string>;
static auto GetPyStringSequence(PyObject* o) -> std::list<std::string>;
/// Set Python exception from C++ Exception.
static void SetPythonException(const Exception& exc);

View File

@ -162,6 +162,12 @@ auto PythonRef::ValueAsString() const -> std::string {
return Python::GetPyString(obj_);
}
auto PythonRef::ValueAsStringSequence() const -> std::list<std::string> {
assert(Python::HaveGIL());
ThrowIfUnset();
return Python::GetPyStringSequence(obj_);
}
auto PythonRef::ValueAsOptionalInt() const -> std::optional<int64_t> {
assert(Python::HaveGIL());
ThrowIfUnset();
@ -193,7 +199,7 @@ auto PythonRef::ValueAsOptionalStringSequence() const
if (obj_ == Py_None) {
return {};
}
return Python::GetPyStrings(obj_);
return Python::GetPyStringSequence(obj_);
}
auto PythonRef::ValueAsInt() const -> int64_t {

View File

@ -166,6 +166,7 @@ class PythonRef {
auto ValueAsLString() const -> std::string;
auto ValueAsString() const -> std::string;
auto ValueAsStringSequence() const -> std::list<std::string>;
auto ValueAsOptionalString() const -> std::optional<std::string>;
auto ValueAsOptionalStringSequence() const
-> std::optional<std::list<std::string>>;

View File

@ -53,6 +53,7 @@ values = [
_hooks.do_quit, # kQuitCall
_hooks.show_post_purchase_message, # kShowPostPurchaseMessageCall
_hooks.string_edit_adapter_can_be_replaced, # kStringEditAdapterCanBeReplacedCall
_hooks.get_dev_console_tab_names, # kGetDevConsoleTabNamesCall
_language.Lstr, # kLStrClass
_general.Call, # kCallClass
_apputils.garbage_collect_session_end, # kGarbageCollectSessionEndCall

View File

@ -19,4 +19,5 @@ values = [
app.on_native_shutdown, # kAppOnNativeShutdownCall
app.on_native_shutdown_complete, # kAppOnNativeShutdownCompleteCall
app.read_config, # kAppReadConfigCall
app.devconsole.do_refresh_tab, # kAppDevConsoleDoRefreshTabCall
]

View File

@ -36,7 +36,6 @@ class HostConfig:
mosh_shell: str = 'sh'
workspaces_root: str = '/home/${USER}/cloudshell_workspaces'
sync_perms: bool = True
precommand: str | None = None # KILL THIS
precommand_noninteractive: str | None = None
precommand_interactive: str | None = None
managed: bool = False

View File

@ -728,16 +728,18 @@ def echo() -> None:
clrnames = {n for n in dir(clr) if n.isupper() and not n.startswith('_')}
first = True
out: list[str] = []
last_was_tag = False
for arg in pcommand.get_args():
if arg in clrnames:
out.append(getattr(clr, arg))
last_was_tag = True
else:
# Special case: a dot by itself is treated as a period for
# the previous arg. This lets us do periods following color
# tags.
if not first and arg != '.':
# Special case: punctuation by itself after a tag doesn't
# get a space before it.
if not first and not (last_was_tag and arg in ('.', '?', '!')):
out.append(' ')
first = False
last_was_tag = False
out.append(arg)
out.append(clr.RST)
pcommand.clientprint(''.join(out))