Restore the ImGui stack after a lua error throw

master
Webster Sheets 2020-01-26 08:57:39 -05:00
parent ec789570ec
commit 491ab1f37f
7 changed files with 221 additions and 24 deletions

View File

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

View File

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

View File

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

13
src/lua/CMakeLists.txt Normal file
View File

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

View File

@ -14,6 +14,7 @@ namespace PiGUI {
LuaObject<PiGUI::Image>::RegisterClass();
LuaObject<PiGUI::Face>::RegisterClass();
LuaObject<PiGUI::ModelSpinner>::RegisterClass();
RegisterSandbox();
}
} // namespace Lua

View File

@ -7,6 +7,8 @@
#include "lua/LuaObject.h"
namespace PiGUI {
void RegisterSandbox();
namespace Lua {
void Init();

149
src/pigui/PiGuiSandbox.cpp Normal file
View File

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