Move Input and PiGui handling to GuiApplication
At the moment, the lifecycle is responsible for calling HandleEvents and rendering PiGui. This can change once legacy code no longer depends on HandleEvents running after View::Draw3D(). Added virtual HandleEvent() call to dispatch to legacy UI code. This is suboptimal; we need a better way that doesn't involve virtual function calls. Use std::function or a better, lower-overhead delegate librarymaster
parent
a1745867ff
commit
e584780ce9
|
@ -9,7 +9,13 @@
|
|||
|
||||
#include <array>
|
||||
|
||||
void Input::Init(GameConfig *config)
|
||||
Input::Input(const GameConfig *config) :
|
||||
m_capturingMouse(false),
|
||||
mouseYInvert(false),
|
||||
joystickEnabled(true),
|
||||
keyModState(0),
|
||||
mouseButton(),
|
||||
mouseMotion()
|
||||
{
|
||||
joystickEnabled = (config->Int("EnableJoystick")) ? true : false;
|
||||
mouseYInvert = (config->Int("InvertMouseY")) ? true : false;
|
||||
|
@ -22,8 +28,8 @@ void Input::InitGame()
|
|||
//reset input states
|
||||
keyState.clear();
|
||||
keyModState = 0;
|
||||
std::fill(mouseButton, mouseButton + COUNTOF(mouseButton), 0);
|
||||
std::fill(mouseMotion, mouseMotion + COUNTOF(mouseMotion), 0);
|
||||
mouseButton.fill(0);
|
||||
mouseMotion.fill(0);
|
||||
for (std::map<SDL_JoystickID, JoystickState>::iterator stick = joysticks.begin(); stick != joysticks.end(); ++stick) {
|
||||
JoystickState &state = stick->second;
|
||||
std::fill(state.buttons.begin(), state.buttons.end(), false);
|
||||
|
@ -32,6 +38,11 @@ void Input::InitGame()
|
|||
}
|
||||
}
|
||||
|
||||
void Input::NewFrame()
|
||||
{
|
||||
mouseMotion.fill(0);
|
||||
}
|
||||
|
||||
InputResponse Input::InputFrame::ProcessSDLEvent(SDL_Event &event)
|
||||
{
|
||||
bool matched = false;
|
||||
|
@ -130,14 +141,14 @@ void Input::HandleSDLEvent(SDL_Event &event)
|
|||
onKeyRelease.emit(&event.key.keysym);
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (event.button.button < COUNTOF(mouseButton)) {
|
||||
if (event.button.button < mouseButton.size()) {
|
||||
mouseButton[event.button.button] = 1;
|
||||
onMouseButtonDown.emit(event.button.button,
|
||||
event.button.x, event.button.y);
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (event.button.button < COUNTOF(mouseButton)) {
|
||||
if (event.button.button < mouseButton.size()) {
|
||||
mouseButton[event.button.button] = 0;
|
||||
onMouseButtonUp.emit(event.button.button,
|
||||
event.button.x, event.button.y);
|
||||
|
|
10
src/Input.h
10
src/Input.h
|
@ -16,10 +16,10 @@ class Input {
|
|||
friend class Pi;
|
||||
|
||||
public:
|
||||
Input() = default;
|
||||
void Init(GameConfig *config);
|
||||
Input(const GameConfig *config);
|
||||
void InitGame();
|
||||
void HandleSDLEvent(SDL_Event &ev);
|
||||
void NewFrame();
|
||||
|
||||
// The Page->Group->Binding system serves as a thin veneer for the UI to make
|
||||
// sane reasonings about how to structure the Options dialog.
|
||||
|
@ -132,7 +132,7 @@ public:
|
|||
|
||||
void GetMouseMotion(int motion[2])
|
||||
{
|
||||
memcpy(motion, mouseMotion, sizeof(int) * 2);
|
||||
std::copy_n(mouseMotion.data(), mouseMotion.size(), motion);
|
||||
}
|
||||
|
||||
// Capturing the mouse hides the cursor, puts the mouse into relative mode,
|
||||
|
@ -156,8 +156,8 @@ private:
|
|||
|
||||
std::map<SDL_Keycode, bool> keyState;
|
||||
int keyModState;
|
||||
char mouseButton[6];
|
||||
int mouseMotion[2];
|
||||
std::array<char, 6> mouseButton;
|
||||
std::array<int, 2> mouseMotion;
|
||||
bool m_capturingMouse;
|
||||
|
||||
bool joystickEnabled;
|
||||
|
|
142
src/Pi.cpp
142
src/Pi.cpp
|
@ -134,7 +134,7 @@ float Pi::amountOfBackgroundStarsDisplayed = 1.0f;
|
|||
bool Pi::DrawGUI = true;
|
||||
Graphics::Renderer *Pi::renderer;
|
||||
RefCountedPtr<UI::Context> Pi::ui;
|
||||
RefCountedPtr<PiGui> Pi::pigui;
|
||||
PiGui *Pi::pigui = nullptr;
|
||||
ModelCache *Pi::modelCache;
|
||||
Intro *Pi::intro;
|
||||
SDLGraphics *Pi::sdl;
|
||||
|
@ -362,8 +362,7 @@ void Pi::App::Startup()
|
|||
Pi::rng.IncRefCount(); // so nothing tries to free it
|
||||
Pi::rng.seed(time(0));
|
||||
|
||||
Pi::input = new Input();
|
||||
Pi::input->Init(Pi::config);
|
||||
Pi::input = StartupInput(config);
|
||||
Pi::input->onKeyPress.connect(sigc::ptr_fun(&Pi::HandleKeyDown));
|
||||
|
||||
// we can only do bindings once joysticks are initialised.
|
||||
|
@ -372,6 +371,8 @@ void Pi::App::Startup()
|
|||
|
||||
RegisterInputBindings();
|
||||
|
||||
Pi::pigui = StartupPiGui();
|
||||
|
||||
// FIXME: move these into the appropriate class!
|
||||
navTunnelDisplayed = (config->Int("DisplayNavTunnel")) ? true : false;
|
||||
speedLinesDisplayed = (config->Int("SpeedLines")) ? true : false;
|
||||
|
@ -439,9 +440,10 @@ void Pi::App::Shutdown()
|
|||
BaseSphere::Uninit();
|
||||
FaceParts::Uninit();
|
||||
Graphics::Uninit();
|
||||
Pi::pigui->Uninit();
|
||||
|
||||
ShutdownPiGui();
|
||||
Pi::pigui = nullptr;
|
||||
Pi::ui.Reset(0);
|
||||
Pi::pigui.Reset(0);
|
||||
Lua::UninitModules();
|
||||
Lua::Uninit();
|
||||
Gui::Uninit();
|
||||
|
@ -453,6 +455,9 @@ void Pi::App::Shutdown()
|
|||
ShutdownRenderer();
|
||||
Pi::renderer = nullptr;
|
||||
|
||||
ShutdownInput();
|
||||
Pi::input = nullptr;
|
||||
|
||||
delete Pi::config;
|
||||
delete Pi::planner;
|
||||
asyncJobQueue.reset();
|
||||
|
@ -492,8 +497,6 @@ void LoadStep::Start()
|
|||
// normal init flow, or drawing the init screen in C++ instead?
|
||||
// Ideally we can initialize the ImGui related parts of pigui as soon as the renderer is online,
|
||||
// and then load all the lua-related state once Lua's registered and online...
|
||||
Pi::pigui.Reset(new PiGui);
|
||||
Pi::pigui->Init(Pi::renderer->GetSDLWindow());
|
||||
LuaObject<PiGui>::RegisterClass();
|
||||
|
||||
// Don't render the first frame, just make sure all of our fonts are loaded
|
||||
|
@ -645,38 +648,7 @@ void MainMenu::Start()
|
|||
|
||||
void MainMenu::Update(float deltaTime)
|
||||
{
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (event.type == SDL_QUIT)
|
||||
Pi::RequestQuit();
|
||||
else {
|
||||
Pi::pigui->ProcessEvent(&event);
|
||||
|
||||
if (Pi::pigui->WantCaptureMouse()) {
|
||||
// don't process mouse event any further, imgui already handled it
|
||||
switch (event.type) {
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
case SDL_MOUSEWHEEL:
|
||||
case SDL_MOUSEMOTION:
|
||||
continue;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (Pi::pigui->WantCaptureKeyboard()) {
|
||||
// don't process keyboard event any further, imgui already handled it
|
||||
switch (event.type) {
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
case SDL_TEXTINPUT:
|
||||
continue;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
Pi::input->HandleSDLEvent(event);
|
||||
}
|
||||
}
|
||||
Pi::GetApp()->HandleEvents();
|
||||
|
||||
Pi::intro->Draw(deltaTime);
|
||||
|
||||
|
@ -849,12 +821,13 @@ void Pi::HandleEscKey()
|
|||
}
|
||||
}
|
||||
|
||||
void Pi::App::HandleEvents()
|
||||
// Return true if the event has been handled and shouldn't be passed through
|
||||
// to the normal input system.
|
||||
bool Pi::App::HandleEvent(SDL_Event &event)
|
||||
{
|
||||
PROFILE_SCOPED()
|
||||
SDL_Event event;
|
||||
|
||||
// XXX for most keypresses SDL will generate KEYUP/KEYDOWN and TEXTINPUT
|
||||
// HACK for most keypresses SDL will generate KEYUP/KEYDOWN and TEXTINPUT
|
||||
// events. keybindings run off KEYUP/KEYDOWN. the console is opened/closed
|
||||
// via keybinding. the console TextInput widget uses TEXTINPUT events. thus
|
||||
// after switching the console, the stray TEXTINPUT event causes the
|
||||
|
@ -862,64 +835,37 @@ void Pi::App::HandleEvents()
|
|||
// this by setting this flag if the console was switched. if its set, we
|
||||
// swallow the TEXTINPUT event this hack must remain until we have a
|
||||
// unified input system
|
||||
bool skipTextInput = false;
|
||||
// This is safely able to be removed once GUI and newUI are gone
|
||||
static bool skipTextInput = false;
|
||||
|
||||
Pi::input->mouseMotion[0] = Pi::input->mouseMotion[1] = 0;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (event.type == SDL_QUIT) {
|
||||
Pi::RequestQuit();
|
||||
}
|
||||
|
||||
Pi::pigui->ProcessEvent(&event);
|
||||
|
||||
// Input system takes priority over mouse events when capturing the mouse
|
||||
if (Pi::pigui->WantCaptureMouse() && !Pi::input->IsCapturingMouse()) {
|
||||
// don't process mouse event any further, imgui already handled it
|
||||
switch (event.type) {
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
case SDL_MOUSEWHEEL:
|
||||
case SDL_MOUSEMOTION:
|
||||
continue;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (Pi::pigui->WantCaptureKeyboard()) {
|
||||
// don't process keyboard event any further, imgui already handled it
|
||||
switch (event.type) {
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
case SDL_TEXTINPUT:
|
||||
continue;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skipTextInput && event.type == SDL_TEXTINPUT) {
|
||||
skipTextInput = false;
|
||||
continue;
|
||||
}
|
||||
if (ui->DispatchSDLEvent(event))
|
||||
continue;
|
||||
|
||||
bool consoleActive = Pi::IsConsoleActive();
|
||||
if (!consoleActive) {
|
||||
KeyBindings::DispatchSDLEvent(&event);
|
||||
if (currentView)
|
||||
currentView->HandleSDLEvent(event);
|
||||
} else
|
||||
KeyBindings::toggleLuaConsole.CheckSDLEventAndDispatch(&event);
|
||||
if (consoleActive != Pi::IsConsoleActive()) {
|
||||
skipTextInput = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Pi::IsConsoleActive())
|
||||
continue;
|
||||
|
||||
Gui::HandleSDLEvent(&event);
|
||||
input->HandleSDLEvent(event);
|
||||
if (skipTextInput && event.type == SDL_TEXTINPUT) {
|
||||
skipTextInput = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ui->DispatchSDLEvent(event))
|
||||
return true;
|
||||
|
||||
bool consoleActive = Pi::IsConsoleActive();
|
||||
if (!consoleActive) {
|
||||
KeyBindings::DispatchSDLEvent(&event);
|
||||
if (currentView)
|
||||
currentView->HandleSDLEvent(event);
|
||||
} else {
|
||||
KeyBindings::toggleLuaConsole.CheckSDLEventAndDispatch(&event);
|
||||
}
|
||||
|
||||
if (consoleActive != Pi::IsConsoleActive()) {
|
||||
skipTextInput = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Pi::IsConsoleActive())
|
||||
return true;
|
||||
|
||||
Gui::HandleSDLEvent(&event);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Pi::App::HandleRequests()
|
||||
|
|
4
src/Pi.h
4
src/Pi.h
|
@ -101,7 +101,7 @@ public:
|
|||
void RunJobs();
|
||||
|
||||
void HandleRequests();
|
||||
void HandleEvents();
|
||||
bool HandleEvent(SDL_Event &ev) override;
|
||||
|
||||
private:
|
||||
// msgs/requests that can be posted which the game processes at the end of a game loop in HandleRequests
|
||||
|
@ -170,7 +170,7 @@ public:
|
|||
#endif
|
||||
|
||||
static RefCountedPtr<UI::Context> ui;
|
||||
static RefCountedPtr<PiGui> pigui;
|
||||
static PiGui *pigui;
|
||||
|
||||
static Random rng;
|
||||
static int statSceneTris;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "Application.h"
|
||||
#include "FileSystem.h"
|
||||
#include "OS.h"
|
||||
#include "SDL.h"
|
||||
#include "profiler/Profiler.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
@ -33,11 +34,14 @@ void Application::Startup()
|
|||
#ifdef PIONEER_PROFILER
|
||||
FileSystem::userFiles.MakeDirectory("profiler");
|
||||
#endif
|
||||
|
||||
SDL_Init(SDL_INIT_EVENTS);
|
||||
}
|
||||
|
||||
void Application::Shutdown()
|
||||
{
|
||||
FileSystem::Uninit();
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
bool Application::StartLifecycle()
|
||||
|
|
|
@ -40,8 +40,6 @@ public:
|
|||
m_nextLifecycle = l;
|
||||
}
|
||||
|
||||
Application *GetApp();
|
||||
|
||||
private:
|
||||
// set to true when you want to accumulate all updates in a lifecycle into a single profile frame
|
||||
bool m_profilerAccumulate = false;
|
||||
|
|
|
@ -100,6 +100,54 @@ Graphics::RenderTarget *GuiApplication::CreateRenderTarget(const Graphics::Setti
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void GuiApplication::HandleEvents()
|
||||
{
|
||||
PROFILE_SCOPED()
|
||||
SDL_Event event;
|
||||
|
||||
// FIXME: input state is right before handling updates because
|
||||
// legacy UI code needs to run before input does.
|
||||
// When HandleEvents() is moved to BeginFrame / PreUpdate, this call should go with it
|
||||
m_input->NewFrame();
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (event.type == SDL_QUIT) {
|
||||
RequestQuit();
|
||||
}
|
||||
|
||||
m_pigui->ProcessEvent(&event);
|
||||
|
||||
// Input system takes priority over mouse events when capturing the mouse
|
||||
if (m_pigui->WantCaptureMouse() && !m_input->IsCapturingMouse()) {
|
||||
// don't process mouse event any further, imgui already handled it
|
||||
switch (event.type) {
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
case SDL_MOUSEWHEEL:
|
||||
case SDL_MOUSEMOTION:
|
||||
continue;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (m_pigui->WantCaptureKeyboard()) {
|
||||
// don't process keyboard event any further, imgui already handled it
|
||||
switch (event.type) {
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
case SDL_TEXTINPUT:
|
||||
continue;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: virtual method dispatch for each event isn't great. Let's find a better solution
|
||||
if (HandleEvent(event))
|
||||
continue;
|
||||
|
||||
m_input->HandleSDLEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
Graphics::Renderer *GuiApplication::StartupRenderer(const GameConfig *config, bool hidden)
|
||||
{
|
||||
PROFILE_SCOPED()
|
||||
|
@ -145,3 +193,28 @@ void GuiApplication::ShutdownRenderer()
|
|||
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
}
|
||||
|
||||
Input *GuiApplication::StartupInput(const GameConfig *config)
|
||||
{
|
||||
m_input.reset(new Input(config));
|
||||
|
||||
return m_input.get();
|
||||
}
|
||||
|
||||
void GuiApplication::ShutdownInput()
|
||||
{
|
||||
m_input.reset();
|
||||
}
|
||||
|
||||
PiGui *GuiApplication::StartupPiGui()
|
||||
{
|
||||
m_pigui.Reset(new PiGui());
|
||||
m_pigui->Init(m_renderer->GetSDLWindow());
|
||||
return m_pigui.Get();
|
||||
}
|
||||
|
||||
void GuiApplication::ShutdownPiGui()
|
||||
{
|
||||
m_pigui->Uninit();
|
||||
m_pigui.Reset();
|
||||
}
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
|
||||
#include "Application.h"
|
||||
#include "GameConfig.h"
|
||||
#include "Input.h"
|
||||
#include "RefCounted.h"
|
||||
#include "SDL_events.h"
|
||||
#include "pigui/PiGui.h"
|
||||
|
||||
#include "graphics/RenderState.h"
|
||||
#include "graphics/RenderTarget.h"
|
||||
|
@ -17,9 +20,11 @@ public:
|
|||
Application(), m_applicationTitle(title)
|
||||
{}
|
||||
|
||||
protected:
|
||||
Graphics::Renderer *GetRenderer() { return m_renderer.get(); }
|
||||
Input *GetInput() { return m_input.get(); }
|
||||
PiGui *GetPiGui() { return m_pigui.Get(); }
|
||||
|
||||
protected:
|
||||
// Called at the end of the frame automatically, blits the RT onto the application
|
||||
// framebuffer
|
||||
void DrawRenderTarget();
|
||||
|
@ -27,9 +32,21 @@ protected:
|
|||
// Call this from your Startup() method
|
||||
Graphics::Renderer *StartupRenderer(const GameConfig *config, bool hidden = false);
|
||||
|
||||
// Call this from your Startup() method
|
||||
Input *StartupInput(const GameConfig *config);
|
||||
|
||||
// Call this from your Startup() method
|
||||
PiGui *StartupPiGui();
|
||||
|
||||
// Call this from your Shutdown() method
|
||||
void ShutdownRenderer();
|
||||
|
||||
// Call this from your Shutdown() method
|
||||
void ShutdownInput();
|
||||
|
||||
// Call this from your shutdown() method
|
||||
void ShutdownPiGui();
|
||||
|
||||
// Hook to bind the RT and clear the screen.
|
||||
// If you override BeginFrame, make sure you call this.
|
||||
void BeginFrame() override;
|
||||
|
@ -38,9 +55,21 @@ protected:
|
|||
// If you override EndFrame, make sure you call this.
|
||||
void EndFrame() override;
|
||||
|
||||
// Consume events from SDL and dispatch to pigui / input
|
||||
void HandleEvents();
|
||||
|
||||
// Override point for classes to add custom event handling
|
||||
virtual bool HandleEvent(SDL_Event &ev) { return false; }
|
||||
|
||||
// Override point to handle an application quit notification
|
||||
virtual void HandleQuit(SDL_QuitEvent &ev) { RequestQuit(); }
|
||||
|
||||
private:
|
||||
Graphics::RenderTarget *CreateRenderTarget(const Graphics::Settings &settings);
|
||||
|
||||
RefCountedPtr<PiGui> m_pigui;
|
||||
std::unique_ptr<Input> m_input;
|
||||
|
||||
std::string m_applicationTitle;
|
||||
|
||||
std::unique_ptr<Graphics::Renderer> m_renderer;
|
||||
|
|
|
@ -116,7 +116,7 @@ static int l_engine_attr_ui(lua_State *l)
|
|||
*/
|
||||
static int l_engine_attr_pigui(lua_State *l)
|
||||
{
|
||||
LuaObject<PiGui>::PushToLua(Pi::pigui.Get());
|
||||
LuaObject<PiGui>::PushToLua(Pi::pigui);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue