Show window and allow user to close it to quit.

This commit is contained in:
King_DuckZ 2016-10-26 01:20:01 +02:00
parent 6afa1a4cd4
commit 92a1069324
10 changed files with 375 additions and 11 deletions

View file

@ -55,6 +55,7 @@ add_executable(${PROJECT_NAME}
src/sizenotifiable.cpp
src/sizeratio.cpp
src/gamescenebase.cpp
src/inputbag.cpp
)
target_include_directories(${PROJECT_NAME} SYSTEM

View file

@ -1,11 +1,55 @@
#include "gamescenebase.hpp"
#include "inputbag.hpp"
#include "sdlmain.hpp"
#include <cassert>
#include <SDL2/SDL.h>
namespace curry {
GameSceneBase::GameSceneBase() :
namespace {
///---------------------------------------------------------------------
///---------------------------------------------------------------------
bool DoEvents (cloonel::InputBag& parInput, cloonel::SDLMain* parSdlMain) {
using cloonel::InputDevice_Keyboard;
SDL_Event eve;
while (SDL_PollEvent(&eve)) {
switch (eve.type) {
case SDL_KEYDOWN:
//eve.key.keysym.sym
parInput.NotifyKeyAction(InputDevice_Keyboard, eve.key.keysym.scancode, true);
break;
case SDL_KEYUP:
parInput.NotifyKeyAction(InputDevice_Keyboard, eve.key.keysym.scancode, false);
break;
case SDL_QUIT:
return true;
case SDL_WINDOWEVENT:
if (SDL_WINDOWEVENT_RESIZED == eve.window.event) {
parSdlMain->SetResolution(vec2us(static_cast<uint16_t>(eve.window.data1), static_cast<uint16_t>(eve.window.data2)));
}
else if (SDL_WINDOWEVENT_CLOSE == eve.window.event) {
return true;
}
break;
}
}
return false;
}
} //unnamed namespace
GameSceneBase::GameSceneBase (cloonel::SDLMain* parSdlMain) :
m_input(std::make_unique<cloonel::InputBag>()),
m_sdlmain(parSdlMain),
m_wants_to_quit(false)
{
assert(m_sdlmain);
}
GameSceneBase::~GameSceneBase() noexcept = default;
void GameSceneBase::prepare() {
m_wants_to_quit = false;
this->on_prepare();
@ -23,4 +67,15 @@ namespace curry {
void GameSceneBase::set_wants_to_quit() {
m_wants_to_quit = true;
}
void GameSceneBase::exec() {
if (DoEvents(*m_input, m_sdlmain))
set_wants_to_quit();
this->on_update();
}
cloonel::SDLMain* GameSceneBase::sdl_main() {
return m_sdlmain;
}
} //namespace curry

View file

@ -1,15 +1,22 @@
#pragma once
#include <memory>
namespace cloonel {
class InputBag;
class SDLMain;
} //namespace cloonel
namespace curry {
class GameSceneBase {
public:
GameSceneBase();
virtual ~GameSceneBase() noexcept = default;
explicit GameSceneBase (cloonel::SDLMain* parSdlMain);
virtual ~GameSceneBase() noexcept;
void prepare();
void destroy() noexcept;
virtual void exec() = 0;
void exec();
bool wants_to_quit() const;
void set_wants_to_quit();
@ -17,8 +24,12 @@ namespace curry {
protected:
virtual void on_prepare() = 0;
virtual void on_destroy() noexcept = 0;
virtual void on_update() = 0;
cloonel::SDLMain* sdl_main();
private:
std::unique_ptr<cloonel::InputBag> m_input;
cloonel::SDLMain* m_sdlmain;
bool m_wants_to_quit;
};
} //namespace curry

View file

@ -3,7 +3,7 @@
namespace curry {
IngameScene::IngameScene (cloonel::SDLMain* parSDLMain) :
m_sdlmain(parSDLMain)
GameSceneBase(parSDLMain)
{
}
@ -13,7 +13,7 @@ namespace curry {
std::cout << "game prepare\n";
}
void IngameScene::exec() {
void IngameScene::on_update() {
std::cout << "game exec\n";
}

View file

@ -12,13 +12,9 @@ namespace curry {
explicit IngameScene (cloonel::SDLMain* parSDLMain);
virtual ~IngameScene() noexcept;
virtual void exec() override;
protected:
virtual void on_prepare() override;
virtual void on_destroy() noexcept override;
private:
cloonel::SDLMain* m_sdlmain;
virtual void on_update() override;
};
} //namespace curry

150
src/inputbag.cpp Normal file
View file

@ -0,0 +1,150 @@
/*
Copyright 2014 Michele "King_DuckZ" Santullo
This file is part of CloonelJump.
CloonelJump is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CloonelJump is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CloonelJump. If not, see <http://www.gnu.org/licenses/>.
*/
#include "inputbag.hpp"
#include "key.hpp"
#include <vector>
#include <map>
#include <cassert>
#include <algorithm>
#include <ciso646>
namespace cloonel {
struct Action {
Key key;
const std::string name;
InputBag::ActionStateType state;
bool newStatePressed;
bool operator== ( const Key& parKey ) const { return key == parKey; }
};
struct InputBag::LocalData {
std::vector<Action> actions;
std::map<int, Action*> mappings;
};
namespace {
// | rl | pr
// -----------------
// rel | rel | jpr
// prs | jrl | prs
// jrl | rel | jpr
// jpr | jrl | prs
const InputBag::ActionStateType g_stateTruthTable[] = {
InputBag::ActionState_Released,
InputBag::ActionState_JustReleased,
InputBag::ActionState_Released,
InputBag::ActionState_JustReleased,
InputBag::ActionState_JustPressed,
InputBag::ActionState_Pressed,
InputBag::ActionState_JustPressed,
InputBag::ActionState_Pressed
};
///----------------------------------------------------------------------
///When actions vector is reallocated, update pointers in mappings.
///----------------------------------------------------------------------
void UpdatePointers (Action* parOldAddrStart, Action* parNewAddress, std::map<int, Action*>& parUpdate, int parOffset) {
for (auto& itMap : parUpdate) {
if (itMap.second >= parOldAddrStart) {
itMap.second = parNewAddress + (itMap.second - parOldAddrStart) + parOffset;
}
}
}
} //unnamed namespace
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
InputBag::InputBag() :
m_localdata(new LocalData)
{
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
InputBag::~InputBag() noexcept {
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void InputBag::AddAction (int parAction, const Key& parKey, std::string&& parName) {
Action* const oldBuff = m_localdata->actions.data();
m_localdata->actions.push_back(Action({parKey, parName, ActionState_Released, false}));
Action* const newBuff = m_localdata->actions.data();
if (oldBuff != newBuff) {
UpdatePointers(oldBuff, newBuff, m_localdata->mappings, 0);
}
m_localdata->mappings[parAction] = &m_localdata->actions.back();
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
InputBag::ActionStateType InputBag::ActionState (int parAction) const {
assert(m_localdata->mappings.find(parAction) != m_localdata->mappings.end());
return m_localdata->mappings[parAction]->state;
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void InputBag::Clear() {
m_localdata->actions.clear();
m_localdata->mappings.clear();
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void InputBag::NotifyKeyAction (InputDeviceType parDev, int parScancode, bool parPressed) {
const Key searchKey(parDev, parScancode);
auto itFound = std::find(m_localdata->actions.begin(), m_localdata->actions.end(), searchKey);
//This method gets called every time a keypress or keyrelease is
//produced, but if the key is of any use is decided here. So it possible
//that a keystroke is not bound to any action and therefore no
//corresponding element is present in the actions list.
if (m_localdata->actions.end() != itFound)
itFound->newStatePressed = parPressed;
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void InputBag::KeyStateUpdateFinished() noexcept {
for (auto& currAction : m_localdata->actions) {
const int numericState = static_cast<int>(currAction.state);
assert(numericState < 4);
const int index = (currAction.newStatePressed ? 4 : 0) + numericState;
currAction.state = g_stateTruthTable[index];
}
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void InputBag::ClearState() {
for (auto& currAction : m_localdata->actions) {
currAction.newStatePressed = false;
currAction.state = ActionState_Released;
}
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
bool IsPressed (const InputBag& parInput, int parAction) {
const InputBag::ActionStateType state = parInput.ActionState(parAction);
return InputBag::ActionState_Pressed == state or InputBag::ActionState_JustPressed == state;
}
} //namespace cloonel

59
src/inputbag.hpp Normal file
View file

@ -0,0 +1,59 @@
/*
Copyright 2014 Michele "King_DuckZ" Santullo
This file is part of CloonelJump.
CloonelJump is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CloonelJump is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CloonelJump. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef idF4E67FC292A5480DA4305B806170F520
#define idF4E67FC292A5480DA4305B806170F520
#include "inputdevicetype.hpp"
#include <memory>
#include <ciso646>
namespace cloonel {
struct Key;
class InputBag {
public:
enum ActionStateType {
ActionState_Released,
ActionState_Pressed,
ActionState_JustReleased,
ActionState_JustPressed
};
InputBag ( void );
~InputBag ( void ) noexcept;
void AddAction ( int parAction, const Key& parKey, std::string&& parName );
ActionStateType ActionState ( int parAction ) const;
void Clear ( void );
void NotifyKeyAction ( InputDeviceType parDev, int parScancode, bool parPressed );
void KeyStateUpdateFinished ( void ) noexcept;
void ClearState ( void );
private:
struct LocalData;
const std::unique_ptr<LocalData> m_localdata;
};
bool IsPressed ( const InputBag& parInput, int parAction );
inline bool IsReleased ( const InputBag& parInput, int parAction ) { return not IsPressed(parInput, parAction); }
} //namespace cloonel
#endif

29
src/inputdevicetype.hpp Normal file
View file

@ -0,0 +1,29 @@
/*
Copyright 2014 Michele "King_DuckZ" Santullo
This file is part of CloonelJump.
CloonelJump is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CloonelJump is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CloonelJump. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef idED0C5C9767B64910A2998ACDAE14A509
#define idED0C5C9767B64910A2998ACDAE14A509
namespace cloonel {
enum InputDeviceType {
InputDevice_Keyboard
};
} //namespace cloonel
#endif

62
src/key.hpp Normal file
View file

@ -0,0 +1,62 @@
/*
Copyright 2014 Michele "King_DuckZ" Santullo
This file is part of CloonelJump.
CloonelJump is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CloonelJump is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CloonelJump. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef id8F6145D6CFBA40338C5804DEC032CE16
#define id8F6145D6CFBA40338C5804DEC032CE16
#include "inputdevicetype.hpp"
#include <ciso646>
namespace cloonel {
struct Key {
Key ( void ) = default;
Key ( InputDeviceType parDev, int parScancode, const char parLabel[4] ) :
srcdevice(parDev),
scancode(parScancode)
{
label[0] = parLabel[0];
label[1] = parLabel[1];
label[2] = parLabel[2];
label[3] = parLabel[3];
}
Key ( InputDeviceType parDev, int parScancode ) :
srcdevice(parDev),
scancode(parScancode),
label {0, 0, 0, 0}
{
}
~Key ( void ) noexcept = default;
bool operator== ( const Key& parOther ) const {
return srcdevice == parOther.srcdevice and scancode == parOther.scancode;
}
bool operator!= ( const Key& parOther ) const {
return not this->operator==(parOther);
}
bool operator< ( const Key& parOther ) const {
return (srcdevice == parOther.srcdevice and scancode < parOther.scancode) or (srcdevice < parOther.srcdevice);
}
InputDeviceType srcdevice;
int scancode;
char label[4];
};
} //namespace cloonel
#endif

View file

@ -36,6 +36,7 @@ namespace vwr {
namespace curry {
using vec2f = vwr::Vec<std::array<float, 2>>;
using vec2us = vwr::Vec<std::array<uint16_t, 2>>;
} //namespace curry
//make stuff from CloonelJump compile happily