summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPiotr Dziwinski <piotrdz@gmail.com>2012-06-30 12:26:40 +0200
committerPiotr Dziwinski <piotrdz@gmail.com>2012-06-30 12:26:40 +0200
commit00c737b880865e874391af5681d8247f1cd6d4ad (patch)
tree1d121ae8a7660d6278c684a0df63f74ecd4de10d /src
parent9a268f553869ee59288873e059ca938d404378c4 (diff)
downloadcolobot-00c737b880865e874391af5681d8247f1cd6d4ad.tar.gz
colobot-00c737b880865e874391af5681d8247f1cd6d4ad.tar.bz2
colobot-00c737b880865e874391af5681d8247f1cd6d4ad.zip
Joystick polling with timer
- added joystick polling through timer - updated documentation on CApplication class
Diffstat (limited to 'src')
-rw-r--r--src/app/app.cpp106
-rw-r--r--src/app/app.h46
2 files changed, 138 insertions, 14 deletions
diff --git a/src/app/app.cpp b/src/app/app.cpp
index 5612c17..2be58ff 100644
--- a/src/app/app.cpp
+++ b/src/app/app.cpp
@@ -29,6 +29,13 @@
#include <stdio.h>
+//! Interval of timer called to update joystick state
+const int JOYSTICK_TIMER_INTERVAL = 1000/30;
+
+//! Function called by the timer
+Uint32 JoystickTimerCallback(Uint32 interval, void *);
+
+
/**
* \struct ApplicationPrivate
* \brief Private data of CApplication class
@@ -45,6 +52,8 @@ struct ApplicationPrivate
SDL_Joystick *joystick;
//! Index of joystick device
int joystickIndex;
+ //! Id of joystick timer
+ SDL_TimerID joystickTimer;
ApplicationPrivate()
{
@@ -52,12 +61,19 @@ struct ApplicationPrivate
surface = NULL;
joystick = NULL;
joystickIndex = 0;
+ joystickTimer = 0;
}
};
+CApplication* CApplication::m_appInstance = NULL;
+
+
CApplication::CApplication()
{
+ assert(m_appInstance == NULL);
+ m_appInstance = this;
+
m_private = new ApplicationPrivate();
m_exitCode = 0;
@@ -80,11 +96,6 @@ CApplication::CApplication()
m_time = 0.0f;
- for (int i = 0; i < 32; i++)
- {
- m_joyButton[i] = false;
- }
-
m_windowTitle = "COLOBOT";
m_showStats = false;
@@ -150,7 +161,7 @@ bool CApplication::Create()
/* SDL initialization sequence */
- Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_JOYSTICK;
+ Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_TIMER;
if (SDL_Init(initFlags) < 0)
{
@@ -213,8 +224,8 @@ bool CApplication::Create()
// Enable translating key codes of key press events to unicode chars
SDL_EnableUNICODE(1);
- // Enable joystick event generation
- SDL_JoystickEventState(SDL_ENABLE);
+ // Don't generate joystick events
+ SDL_JoystickEventState(SDL_IGNORE);
// For now, enable joystick for testing
@@ -255,13 +266,90 @@ bool CApplication::OpenJoystick()
if (m_private->joystick == NULL)
return false;
+ // Create the vectors with joystick axis & button states to exactly the required size
+ m_joyAxeState = std::vector<int>(SDL_JoystickNumAxes(m_private->joystick), 0);
+ m_joyButtonState = std::vector<bool>(SDL_JoystickNumButtons(m_private->joystick), false);
+
+ // Create a timer for polling joystick state
+ m_private->joystickTimer = SDL_AddTimer(JOYSTICK_TIMER_INTERVAL, JoystickTimerCallback, NULL);
+
return true;
}
void CApplication::CloseJoystick()
{
+ // Timer will remove itself automatically
+
SDL_JoystickClose(m_private->joystick);
+ m_private->joystick = NULL;
+}
+
+Uint32 JoystickTimerCallback(Uint32 interval, void *)
+{
+ CApplication *app = CApplication::RetInstance();
+ if ((app == NULL) || (! app->RetJoystickEnabled()))
+ return 0; // don't run the timer again
+
+ app->UpdateJoystick();
+
+ return interval; // run for the same interval again
+}
+
+/** Updates the state info in CApplication and on change, creates SDL events and pushes them to SDL event queue.
+ This way, the events get handled properly in the main event loop and besides, SDL_PushEvent() ensures thread-safety. */
+void CApplication::UpdateJoystick()
+{
+ if (! m_joystickEnabled)
+ return;
+
+ SDL_JoystickUpdate();
+
+ for (int axis = 0; axis < (int) m_joyAxeState.size(); ++axis)
+ {
+ int newValue = SDL_JoystickGetAxis(m_private->joystick, axis);
+
+ if (m_joyAxeState[axis] != newValue)
+ {
+ m_joyAxeState[axis] = newValue;
+
+ SDL_Event joyAxisEvent;
+
+ joyAxisEvent.jaxis.type = SDL_JOYAXISMOTION;
+ joyAxisEvent.jaxis.which = 0;
+ joyAxisEvent.jaxis.axis = axis;
+ joyAxisEvent.jaxis.value = newValue;
+
+ SDL_PushEvent(&joyAxisEvent);
+ }
+ }
+
+ for (int button = 0; button < (int) m_joyButtonState.size(); ++button)
+ {
+ bool newValue = SDL_JoystickGetButton(m_private->joystick, button) == 1;
+
+ if (m_joyButtonState[button] != newValue)
+ {
+ m_joyButtonState[button] = newValue;
+
+ SDL_Event joyButtonEvent;
+
+ if (newValue)
+ {
+ joyButtonEvent.jbutton.type = SDL_JOYBUTTONDOWN;
+ joyButtonEvent.jbutton.state = SDL_PRESSED;
+ }
+ else
+ {
+ joyButtonEvent.jbutton.type = SDL_JOYBUTTONUP;
+ joyButtonEvent.jbutton.state = SDL_RELEASED;
+ }
+ joyButtonEvent.jbutton.which = 0;
+ joyButtonEvent.jbutton.button = button;
+
+ SDL_PushEvent(&joyButtonEvent);
+ }
+ }
}
int CApplication::Run()
@@ -444,7 +532,7 @@ void CApplication::ProcessEvent(Event event)
case EVENT_JOY_BUTTON_UP:
printf("EVENT_JOY_BUTTON_%s:\n", (event.type == EVENT_JOY_BUTTON_DOWN) ? "DOWN" : "UP");
printf(" button = %d\n", event.joyButton.button);
- printf(" state = %s\n", (event.mouseButton.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED");
+ printf(" state = %s\n", (event.joyButton.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED");
break;
default:
break;
diff --git a/src/app/app.h b/src/app/app.h
index 9d689e2..b2d9135 100644
--- a/src/app/app.h
+++ b/src/app/app.h
@@ -25,6 +25,7 @@
#include "graphics/common/engine.h"
#include <string>
+#include <vector>
class CInstanceManager;
@@ -39,10 +40,32 @@ struct ApplicationPrivate;
* \class CApplication
* \brief Main application
*
- * This class is responsible for creating and handling main application window,
- * receiving events, etc.
+ * This class is responsible for main application execution, including creating
+ * and handling main application window, receiving events, etc.
+ *
+ * It is a singleton class with only one instance that can be created.
+ *
+ * Creation of other main objects
+ *
+ * The class creates the only instance of CInstanceManager, CEventQueue, CEngine,
+ * CRobotMain and CSound classes.
+ *
+ * Window management
+ *
+ * The class is responsible for creating app window, setting and changing the video mode,
+ * setting the position of mouse and changing the cursor, grabbing and writing screenshots.
+ *
+ * Events
+ *
+ * Events are taken from SDL event queue and either handled by CApplication or translated
+ * to common events from src/common.h and pushed to global event queue CEventQueue.
+ * Joystick events are generated somewhat differently, by running a separate timer,
+ * polling the device for changes and synthesising events on change. It avoids flooding
+ * the event queue with too many joystick events and the granularity of the timer can be
+ * adjusted.
+ *
+ * The events are further handled in CRobotMain class.
*
- * ...
*/
class CApplication
{
@@ -52,6 +75,10 @@ public:
//! Destructor
~CApplication();
+ //! Returns the only CApplication instance
+ static CApplication* RetInstance()
+ { return m_appInstance; }
+
public:
//! Parses commandline arguments
Error ParseArguments(int argc, char *argv[]);
@@ -66,6 +93,9 @@ public:
//! Updates the simulation state
void StepSimulation(float rTime);
+ //! Polls the state of joystick axes and buttons
+ void UpdateJoystick();
+
void SetShowStat(bool show);
bool RetShowStat();
@@ -124,6 +154,9 @@ protected:
void OutputText(long x, long y, char* str);
protected:
+ //! The only instance of CApplication
+ static CApplication* m_appInstance;
+ //! Instance manager
CInstanceManager* m_iMan;
//! Private (SDL-dependent data)
ApplicationPrivate* m_private;
@@ -138,7 +171,6 @@ protected:
//! Main class of the proper game engine
CRobotMain* m_robotMain;
-
//! Code to return at exit
int m_exitCode;
@@ -164,10 +196,14 @@ protected:
int m_keyState;
Math::Vector m_axeKey;
Math::Vector m_axeJoy;
- bool m_joyButton[32];
Math::Point m_mousePos;
long m_mouseWheel;
+ //! Current state of joystick axes; may be updated from another thread
+ std::vector<int> m_joyAxeState;
+ //! Current state of joystick buttons; may be updated from another thread
+ std::vector<bool> m_joyButtonState;
+
float m_time;
long m_key[50][2];
};