Restore the ImGui stack after a lua error throw
parent
ec789570ec
commit
491ab1f37f
|
@ -93,6 +93,9 @@ endif (MINGW)
|
|||
|
||||
option(WITH_OBJECTVIEWER "Include the object viewer in the build" ON)
|
||||
option(WITH_DEVKEYS "Include various extra keybindings for dev functions" ON)
|
||||
option(USE_SYSTEM_LIBGLEW "Use the system's libglew" OFF)
|
||||
option(USE_SYSTEM_LIBLUA "Use the system's liblua" OFF)
|
||||
option(PROFILER_ENABLED "Build pioneer with profiling support built-in." OFF)
|
||||
|
||||
list(APPEND SRC_FOLDERS
|
||||
src/
|
||||
|
@ -103,8 +106,6 @@ list(APPEND SRC_FOLDERS
|
|||
src/graphics/dummy
|
||||
src/graphics/opengl
|
||||
src/gui
|
||||
src/lua
|
||||
src/lua/core
|
||||
src/pigui
|
||||
src/scenegraph
|
||||
src/ship
|
||||
|
@ -114,14 +115,18 @@ list(APPEND SRC_FOLDERS
|
|||
src/ui
|
||||
)
|
||||
|
||||
foreach (each IN LISTS SRC_FOLDERS)
|
||||
macro(add_source_folders TARGET SRC_FOLDERS)
|
||||
foreach (each IN LISTS ${SRC_FOLDERS})
|
||||
file(GLOB header_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${each}/*.h)
|
||||
list(APPEND HXX_FILES ${header_files})
|
||||
list(APPEND ${TARGET}_HXX_FILES ${header_files})
|
||||
file(GLOB src_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${each}/*.cpp)
|
||||
list(APPEND CXX_FILES ${src_files})
|
||||
endforeach (each IN LISTS SRC_FOLDERS)
|
||||
list(APPEND ${TARGET}_CXX_FILES ${src_files})
|
||||
endforeach ()
|
||||
endmacro()
|
||||
|
||||
list(REMOVE_ITEM CXX_FILES
|
||||
add_source_folders(PIONEER SRC_FOLDERS)
|
||||
|
||||
list(REMOVE_ITEM PIONEER_CXX_FILES
|
||||
src/main.cpp
|
||||
src/modelcompiler.cpp
|
||||
src/savegamedump.cpp
|
||||
|
@ -147,7 +152,7 @@ endif (WIN32)
|
|||
|
||||
configure_file(buildopts.h.cmakein buildopts.h @ONLY)
|
||||
|
||||
LIST(APPEND CXX_FILES ${FILESYSTEM_CXX_FILES})
|
||||
LIST(APPEND PIONEER_CXX_FILES ${FILESYSTEM_CXX_FILES})
|
||||
if (MSVC)
|
||||
option(USE_PIONEER_THIRDPARTY "Use pioneer's thirdparty library repository." ON)
|
||||
if (USE_PIONEER_THIRDPARTY)
|
||||
|
@ -158,13 +163,11 @@ if (MSVC)
|
|||
endif()
|
||||
endif (MSVC)
|
||||
|
||||
option(USE_SYSTEM_LIBGLEW "Use the system's libglew" OFF)
|
||||
if (USE_SYSTEM_LIBGLEW)
|
||||
add_library(GLEW::GLEW INTERFACE IMPORTED)
|
||||
find_package(GLEW REQUIRED)
|
||||
endif (USE_SYSTEM_LIBGLEW)
|
||||
|
||||
option(USE_SYSTEM_LIBLUA "Use the system's liblua" OFF)
|
||||
if (USE_SYSTEM_LIBLUA)
|
||||
find_package(Lua 5.2 EXACT REQUIRED)
|
||||
include_directories(${LUA_INCLUDE_DIR})
|
||||
|
@ -173,11 +176,23 @@ if (USE_SYSTEM_LIBLUA)
|
|||
endif (WIN32)
|
||||
endif (USE_SYSTEM_LIBLUA)
|
||||
|
||||
option(PROFILER_ENABLED "Build pioneer with profiling support built-in." OFF)
|
||||
if (PROFILER_ENABLED)
|
||||
add_definitions(-DPIONEER_PROFILER=1)
|
||||
endif(PROFILER_ENABLED)
|
||||
|
||||
macro(set_cxx11_properties)
|
||||
set_target_properties(${ARGN} PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
CXX_EXTENSIONS ON
|
||||
)
|
||||
endmacro()
|
||||
|
||||
macro(define_pioneer_library library_name _src _header)
|
||||
add_library(${library_name} STATIC ${${_src}} ${${_header}})
|
||||
set_cxx11_properties(${library_name})
|
||||
endmacro()
|
||||
|
||||
if (MSVC)
|
||||
include(msvc-defaults.cmake)
|
||||
else (MSVC)
|
||||
|
@ -228,7 +243,9 @@ if (NOT USE_SYSTEM_LIBLUA)
|
|||
include_directories(contrib/lua)
|
||||
endif (NOT USE_SYSTEM_LIBLUA)
|
||||
|
||||
add_library(pioneerLib STATIC ${CXX_FILES} ${HXX_FILES})
|
||||
define_pioneer_library(pioneer-lib PIONEER_CXX_FILES PIONEER_HXX_FILES)
|
||||
|
||||
add_subdirectory(src/lua)
|
||||
|
||||
if (WIN32)
|
||||
string(TIMESTAMP BUILD_YEAR "%Y")
|
||||
|
@ -260,8 +277,11 @@ add_executable(savegamedump WIN32
|
|||
src/PngWriter.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(pioneer-lib PUBLIC lz4)
|
||||
|
||||
list(APPEND pioneerLibs
|
||||
pioneerLib
|
||||
pioneer-lib
|
||||
pioneer-lua
|
||||
${ASSIMP_LIBRARIES}
|
||||
${FREETYPE_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
|
@ -270,7 +290,6 @@ list(APPEND pioneerLibs
|
|||
${SIGCPP_LIBRARIES}
|
||||
${VORBISFILE_LIBRARIES}
|
||||
${LUA_LIBRARIES}
|
||||
lz4
|
||||
GLEW::GLEW
|
||||
imgui
|
||||
jenkins
|
||||
|
@ -290,11 +309,7 @@ target_link_libraries(${PROJECT_NAME} LINK_PRIVATE ${pioneerLibs} ${winLibs})
|
|||
target_link_libraries(modelcompiler LINK_PRIVATE ${pioneerLibs} ${winLibs})
|
||||
target_link_libraries(savegamedump LINK_PRIVATE ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES} profiler lz4 ${winLibs})
|
||||
|
||||
set_target_properties(${PROJECT_NAME} modelcompiler savegamedump pioneerLib PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
CXX_EXTENSIONS ON
|
||||
)
|
||||
set_cxx11_properties(${PROJECT_NAME} modelcompiler savegamedump)
|
||||
|
||||
if(MSVC)
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
|
|
|
@ -92,6 +92,14 @@ local textBackgroundMarginPixels = 2
|
|||
|
||||
ui.icons_texture = pigui:LoadTextureFromSVG(pigui.DataDirPath({"icons", "icons.svg"}), 16 * 64, 16 * 64)
|
||||
|
||||
-- Clean up the ImGui stack in case of an error
|
||||
function ui.pcall(fun, ...)
|
||||
local stack = pigui.GetImguiStack()
|
||||
return xpcall(fun, function(msg)
|
||||
return msg .. pigui.CleanupImguiStack(stack)
|
||||
end, ...)
|
||||
end
|
||||
|
||||
function ui.window(name, params, fun)
|
||||
local ok = pigui.Begin(name, params)
|
||||
if ok then fun() end
|
||||
|
|
|
@ -241,6 +241,19 @@ local function displayScreenshotInfo()
|
|||
end
|
||||
end
|
||||
|
||||
local function drawGameModules()
|
||||
for i, module in ipairs(gameView.modules) do
|
||||
local shouldDraw = not Game.InHyperspace() or module.showInHyperspace
|
||||
if (not module.disabled) and shouldDraw then
|
||||
local ok, err = ui.pcall(module.draw, module, delta_t)
|
||||
if not ok then
|
||||
module.disabled = true
|
||||
print(err)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local gameViewWindowFlags = ui.WindowFlags {"NoTitleBar", "NoResize", "NoMove", "NoInputs", "NoSavedSettings", "NoFocusOnAppearing", "NoBringToFrontOnFocus"}
|
||||
ui.registerHandler('game', function(delta_t)
|
||||
-- delta_t is ignored for now
|
||||
|
@ -255,11 +268,7 @@ ui.registerHandler('game', function(delta_t)
|
|||
gameView.center = Vector2(ui.screenWidth / 2, ui.screenHeight / 2)
|
||||
if ui.shouldDrawUI() then
|
||||
if Game.CurrentView() == "world" then
|
||||
for i, module in ipairs(gameView.modules) do
|
||||
if not Game.InHyperspace() or module.showInHyperspace then
|
||||
module:draw(delta_t)
|
||||
end
|
||||
end
|
||||
drawGameModules(gameView.modules)
|
||||
ui.radialMenu("worldloopworld")
|
||||
else
|
||||
ui.radialMenu("worldloopnotworld")
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
list(APPEND LUA_SRC_FOLDERS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
core
|
||||
)
|
||||
|
||||
# Creates variables LUA_CXX_FILES and LUA_HXX_FILES
|
||||
add_source_folders(LUA LUA_SRC_FOLDERS)
|
||||
|
||||
# Creates a library, adds it to the build, and sets C++ target properties on it
|
||||
define_pioneer_library(pioneer-lua LUA_CXX_FILES LUA_HXX_FILES)
|
||||
target_include_directories(pioneer-lua PRIVATE ${CMAKE_BINARY_DIR})
|
||||
target_link_libraries(pioneer-lua pioneer-lib)
|
|
@ -14,6 +14,7 @@ namespace PiGUI {
|
|||
LuaObject<PiGUI::Image>::RegisterClass();
|
||||
LuaObject<PiGUI::Face>::RegisterClass();
|
||||
LuaObject<PiGUI::ModelSpinner>::RegisterClass();
|
||||
RegisterSandbox();
|
||||
}
|
||||
|
||||
} // namespace Lua
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "lua/LuaObject.h"
|
||||
|
||||
namespace PiGUI {
|
||||
void RegisterSandbox();
|
||||
|
||||
namespace Lua {
|
||||
|
||||
void Init();
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
|
||||
#include <lua.hpp>
|
||||
|
||||
#include "PiGui.h"
|
||||
#include "PiGuiLua.h"
|
||||
|
||||
#include "lua/LuaPiGui.h"
|
||||
#include "lua/LuaUtils.h"
|
||||
|
||||
#include "imgui/imgui_internal.h"
|
||||
|
||||
struct SavedImguiStackInfo {
|
||||
static const char *meta_name;
|
||||
|
||||
uint32_t windowStackSize;
|
||||
uint32_t styleColorStack;
|
||||
uint32_t styleVarStack;
|
||||
uint32_t fontStackSize;
|
||||
};
|
||||
|
||||
const char *SavedImguiStackInfo::meta_name = "PiGui.SavedImguiStackInfo";
|
||||
|
||||
static int CleanupWindowStack(SavedImguiStackInfo *stackInfo)
|
||||
{
|
||||
auto &windowStack = ImGui::GetCurrentContext()->CurrentWindowStack;
|
||||
int numUnfinishedWindows = windowStack.size() - stackInfo->windowStackSize;
|
||||
|
||||
// While it shouldn't be possible to get a window stack of less than the last time it was updated,
|
||||
// we want to check for it anyways to avoid causing issues down the line.
|
||||
if (numUnfinishedWindows <= 1 || !stackInfo->windowStackSize)
|
||||
return 0;
|
||||
|
||||
for (int n = numUnfinishedWindows; n > 0; n--) {
|
||||
auto &wnd = windowStack.back();
|
||||
|
||||
// Finish all calls to BeginGroup() just to be courteous.
|
||||
// We don't unwind the ID stack because that's per-window and doesn't affect the geometry output.
|
||||
for (size_t gS = wnd->DC.GroupStack.size(); gS > 0; gS--) {
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
// Need to call EndChild() instead of End() here
|
||||
if (windowStack.back()->Flags & ImGuiWindowFlags_ChildWindow)
|
||||
ImGui::EndChild();
|
||||
|
||||
// Just a regular window, close it
|
||||
else
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
return numUnfinishedWindows;
|
||||
}
|
||||
|
||||
static int CleanupStyleStack(SavedImguiStackInfo *stackInfo)
|
||||
{
|
||||
auto &colorStack = ImGui::GetCurrentContext()->ColorModifiers;
|
||||
int numResetStyles = colorStack.size() - stackInfo->styleColorStack;
|
||||
if (colorStack.size() > stackInfo->styleColorStack)
|
||||
ImGui::PopStyleColor(colorStack.size() - stackInfo->styleColorStack);
|
||||
|
||||
auto &varStack = ImGui::GetCurrentContext()->StyleModifiers;
|
||||
numResetStyles += varStack.size() - stackInfo->styleVarStack;
|
||||
if (varStack.size() > stackInfo->styleVarStack)
|
||||
ImGui::PopStyleVar(varStack.size() - stackInfo->styleVarStack);
|
||||
|
||||
return numResetStyles;
|
||||
}
|
||||
|
||||
static int CleanupFontStack(SavedImguiStackInfo *stackInfo)
|
||||
{
|
||||
auto &fontStack = ImGui::GetCurrentContext()->FontStack;
|
||||
int numResetFonts = fontStack.size() - stackInfo->fontStackSize;
|
||||
|
||||
if (numResetFonts <= 0)
|
||||
return 0;
|
||||
|
||||
for (int n = numResetFonts; n > 0; n--)
|
||||
ImGui::PopFont();
|
||||
|
||||
return numResetFonts;
|
||||
}
|
||||
|
||||
void UpdateStackInfo(SavedImguiStackInfo *stackInfo)
|
||||
{
|
||||
stackInfo->windowStackSize = ImGui::GetCurrentContext()->CurrentWindowStack.size();
|
||||
stackInfo->styleColorStack = ImGui::GetCurrentContext()->ColorModifiers.size();
|
||||
stackInfo->styleVarStack = ImGui::GetCurrentContext()->StyleModifiers.size();
|
||||
stackInfo->fontStackSize = ImGui::GetCurrentContext()->FontStack.size();
|
||||
}
|
||||
|
||||
static int l_new_stack_info(lua_State *L)
|
||||
{
|
||||
auto *savedStackInfo = static_cast<SavedImguiStackInfo *>(lua_newuserdata(L, sizeof(SavedImguiStackInfo)));
|
||||
|
||||
// placement new to initialize this new userdata
|
||||
new (savedStackInfo) SavedImguiStackInfo;
|
||||
luaL_setmetatable(L, SavedImguiStackInfo::meta_name);
|
||||
|
||||
UpdateStackInfo(savedStackInfo);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_stack_cleanup(lua_State *L)
|
||||
{
|
||||
using std::to_string;
|
||||
auto *stackInfo = static_cast<SavedImguiStackInfo *>(luaL_checkudata(L, 1, SavedImguiStackInfo::meta_name));
|
||||
std::array<int, 3> resetNum = {
|
||||
CleanupWindowStack(stackInfo),
|
||||
CleanupStyleStack(stackInfo),
|
||||
CleanupFontStack(stackInfo)
|
||||
};
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (resetNum[0] || resetNum[1] || resetNum[2]) {
|
||||
std::string errormsg =
|
||||
"Cleaned up " + to_string(resetNum[0]) + " windows, " + to_string(resetNum[1]) + " styles, and " + to_string(resetNum[2]) + " fonts.\n";
|
||||
|
||||
lua_pushstring(L, errormsg.c_str());
|
||||
} else {
|
||||
lua_pushstring(L, "No imgui stack cleanup necessary.\n");
|
||||
}
|
||||
|
||||
// return the new message
|
||||
return 1;
|
||||
}
|
||||
|
||||
luaL_Reg l_stack_functions[] = {
|
||||
{ "GetImguiStack", l_new_stack_info },
|
||||
{ "CleanupImguiStack", l_stack_cleanup },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
void PiGUI::RegisterSandbox()
|
||||
{
|
||||
lua_State *L = ::Lua::manager->GetLuaState();
|
||||
LUA_DEBUG_START(L);
|
||||
|
||||
// Create the new metatable and the
|
||||
luaL_newmetatable(L, SavedImguiStackInfo::meta_name);
|
||||
lua_pop(L, 1);
|
||||
|
||||
// We use this instead of lua_getglobal because PiGui is in the CoreImports table instead
|
||||
pi_lua_split_table_path(L, "PiGui");
|
||||
lua_gettable(L, -2);
|
||||
luaL_setfuncs(L, l_stack_functions, 0);
|
||||
lua_pop(L, 1);
|
||||
|
||||
LUA_DEBUG_END(L, 0);
|
||||
}
|
Loading…
Reference in New Issue