From 8797569d33c4917eb8f8a1dc2341aac7b5815315 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Sun, 22 Jul 2012 22:05:12 +0200 Subject: Texture & mouse functions; refactoring & fixes - cleaned up and added documentation to engine.h - refactored CEngine interface and associated structs - added mouse handling functions in CApplication & CEngine - fixed bugs in projection matrix setting - changed texture loading & handling - added const-values in CDevice & CGLDevice - changed event management in CApplication - other minor changes & bugfixes --- src/app/app.cpp | 208 ++++++++++++++++++++++++++++++++++++++++--------------- src/app/app.h | 67 +++++++++--------- src/app/main.cpp | 4 +- 3 files changed, 188 insertions(+), 91 deletions(-) (limited to 'src/app') diff --git a/src/app/app.cpp b/src/app/app.cpp index 6a71f64..4812102 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -22,6 +22,7 @@ #include "app/system.h" #include "common/logger.h" #include "common/iman.h" +#include "common/image.h" #include "graphics/opengl/gldevice.h" @@ -31,6 +32,9 @@ #include +template<> CApplication* CSingleton::mInstance = NULL; + + //! Interval of timer called to update joystick state const int JOYSTICK_TIMER_INTERVAL = 1000/30; @@ -70,14 +74,9 @@ struct ApplicationPrivate }; -CApplication* CApplication::m_appInstance = NULL; - CApplication::CApplication() { - assert(m_appInstance == NULL); - m_appInstance = this; - m_private = new ApplicationPrivate(); m_exitCode = 0; @@ -107,6 +106,8 @@ CApplication::CApplication() m_debugMode = false; m_setupMode = true; + m_dataPath = "./data"; + ResetKey(); } @@ -120,29 +121,49 @@ CApplication::~CApplication() delete m_iMan; m_iMan = NULL; - - m_appInstance = NULL; } -Error CApplication::ParseArguments(int argc, char *argv[]) +bool CApplication::ParseArguments(int argc, char *argv[]) { + bool waitDataDir = false; + for (int i = 1; i < argc; ++i) { std::string arg = argv[i]; + if (waitDataDir) + { + waitDataDir = false; + m_dataPath = arg; + } + if (arg == "-debug") { m_showStats = true; SetDebugMode(true); } - // TODO else {} report invalid argument + else if (arg == "-datadir") + { + waitDataDir = true; + } + else + { + m_exitCode = 1; + return false; + } } - return ERR_OK; + // Data dir not given? + if (waitDataDir) + return false; + + return true; } bool CApplication::Create() { + // TODO: verify that data directory exists + // Temporarily -- only in windowed mode m_private->deviceConfig.fullScreen = false; @@ -365,7 +386,7 @@ void CApplication::CloseJoystick() Uint32 JoystickTimerCallback(Uint32 interval, void *) { - CApplication *app = CApplication::GetInstance(); + CApplication *app = CApplication::GetInstancePointer(); if ((app == NULL) || (! app->GetJoystickEnabled())) return 0; // don't run the timer again @@ -434,43 +455,82 @@ int CApplication::Run() { m_active = true; - while (m_private->currentEvent.type != SDL_QUIT) + while (true) { // Use SDL_PeepEvents() if the app is active, so we can use idle time to // render the scene. Else, use SDL_PollEvent() to avoid eating CPU time. int count = 0; - if (m_active) - { - SDL_PumpEvents(); - count = SDL_PeepEvents(&m_private->currentEvent, 1, SDL_GETEVENT, SDL_ALLEVENTS); - } - else - { - SDL_PollEvent(&m_private->currentEvent); - } - // If received an event - if ((m_active && count > 0) || (!m_active)) + // To be sure no old event remains + m_private->currentEvent.type = SDL_NOEVENT; + + bool haveEvent = true; + while (haveEvent) { - ParseEvent(); + haveEvent = false; + + if (m_active) + { + SDL_PumpEvents(); + count = SDL_PeepEvents(&m_private->currentEvent, 1, SDL_GETEVENT, SDL_ALLEVENTS); + } + else + { + count = SDL_PollEvent(&m_private->currentEvent); + } + + // If received an event + if (count > 0) + { + haveEvent = true; + + Event event = ParseEvent(); + + if (event.type == EVENT_QUIT) + goto end; // exit the loop + + if (event.type != EVENT_NULL) + { + bool passOn = ProcessEvent(event); + + if (m_engine != NULL && passOn) + passOn = m_engine->ProcessEvent(event); + + if (passOn) + m_eventQueue->AddEvent(event); + } + } } - // Render a frame during idle time (no messages are waiting) + // Enter game update & frame rendering only if active if (m_active && m_ready) { Event event; while (m_eventQueue->GetEvent(event)) { if (event.type == EVENT_QUIT) - { goto end; // exit both loops + + bool passOn = true; + + // Skip system events (they have been processed earlier) + if (! event.systemEvent) + { + passOn = ProcessEvent(event); + + if (passOn && m_engine != NULL) + passOn = m_engine->ProcessEvent(event); } - //m_robotMain->EventProcess(event); + /*if (passOn && m_robotMain != NULL) + m_robotMain->ProcessEvent(event); */ } + // Update game and render a frame during idle time (no messages are waiting) + bool ok = Render(); + // If an error occurs, push quit event to the queue - if (! Render()) + if (! ok) { SDL_Event quitEvent; memset(&quitEvent, 0, sizeof(SDL_Event)); @@ -481,7 +541,6 @@ int CApplication::Run() } end: - //m_sound->StopMusic(); Destroy(); return m_exitCode; @@ -501,23 +560,34 @@ PressState TranslatePressState(unsigned char state) return STATE_RELEASED; } -/** Conversion of the position of the mouse to the following coordinates: - -x: 0=left, 1=right +/** Conversion of the position of the mouse from window coords to interface coords: + - x: 0=left, 1=right + - y: 0=down, 1=up */ +Math::Point CApplication::WindowToInterfaceCoords(Math::IntPoint pos) +{ + return Math::Point( (float)pos.x / (float)m_private->deviceConfig.width, + 1.0f - (float)pos.y / (float)m_private->deviceConfig.height); +} -y: 0=down, 1=up -*/ -Math::Point CApplication::WindowToInterfaceCoords(int x, int y) +Math::IntPoint CApplication::InterfaceToWindowCoords(Math::Point pos) { - return Math::Point((float)x / (float)m_private->deviceConfig.width, - 1.0f - (float)y / (float)m_private->deviceConfig.height); + return Math::IntPoint((int)(pos.x * m_private->deviceConfig.width), + (int)((1.0f - pos.y) * m_private->deviceConfig.height)); } -void CApplication::ParseEvent() +/** The SDL event parsed is stored internally. + If event is not available or is not understood, returned event is of type EVENT_NULL. */ +Event CApplication::ParseEvent() { Event event; - if ( (m_private->currentEvent.type == SDL_KEYDOWN) || + event.systemEvent = true; + + if (m_private->currentEvent.type == SDL_QUIT) + { + event.type = EVENT_QUIT; + } + else if ( (m_private->currentEvent.type == SDL_KEYDOWN) || (m_private->currentEvent.type == SDL_KEYUP) ) { if (m_private->currentEvent.type == SDL_KEYDOWN) @@ -540,16 +610,15 @@ void CApplication::ParseEvent() event.mouseButton.button = m_private->currentEvent.button.button; event.mouseButton.state = TranslatePressState(m_private->currentEvent.button.state); - event.mouseButton.pos = WindowToInterfaceCoords(m_private->currentEvent.button.x, m_private->currentEvent.button.y); + event.mouseButton.pos = WindowToInterfaceCoords(Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y)); } else if (m_private->currentEvent.type == SDL_MOUSEMOTION) { event.type = EVENT_MOUSE_MOVE; event.mouseMove.state = TranslatePressState(m_private->currentEvent.button.state); - event.mouseMove.pos = WindowToInterfaceCoords(m_private->currentEvent.button.x, m_private->currentEvent.button.y); + event.mouseMove.pos = WindowToInterfaceCoords(Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y)); } - // TODO: joystick state polling instead of getting events else if (m_private->currentEvent.type == SDL_JOYAXISMOTION) { event.type = EVENT_JOY_AXIS; @@ -569,16 +638,13 @@ void CApplication::ParseEvent() event.joyButton.state = TranslatePressState(m_private->currentEvent.jbutton.state); } - - if (m_robotMain != NULL && event.type != EVENT_NULL) - { - //m_robotMain->EventProcess(event); - } - - ProcessEvent(event); + return event; } -void CApplication::ProcessEvent(Event event) +/** Processes incoming events. It is the first function called after an event is captures. + Function returns \c true if the event is to be passed on to other processing functions + or \c false if not. */ +bool CApplication::ProcessEvent(const Event &event) { CLogger *l = GetLogger(); // Print the events in debug mode to test the code @@ -621,8 +687,12 @@ void CApplication::ProcessEvent(Event event) break; } } + + // By default, pass on all events + return true; } +/** Renders the frame and swaps buffers as necessary. Returns \c false on error. */ bool CApplication::Render() { bool result = m_engine->Render(); @@ -709,14 +779,39 @@ int CApplication::GetKey(int keyRank, int option) return 0; } -void CApplication::SetMousePos(Math::Point pos) +void CApplication::SetGrabInput(bool grab) { - // TODO + SDL_WM_GrabInput(grab ? SDL_GRAB_ON : SDL_GRAB_OFF); } -void CApplication::SetMouseType(Gfx::MouseType type) +bool CApplication::GetGrabInput() { - // TODO + int result = SDL_WM_GrabInput(SDL_GRAB_QUERY); + return result == SDL_GRAB_ON; +} + +void CApplication::SetSystemMouseVisible(bool visible) +{ + SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE); +} + +bool CApplication::GetSystemMouseVisibile() +{ + int result = SDL_ShowCursor(SDL_QUERY); + return result == SDL_ENABLE; +} + + +void CApplication::SetSystemMousePos(Math::Point pos) +{ + Math::IntPoint windowPos = InterfaceToWindowCoords(pos); + SDL_WarpMouse(windowPos.x, windowPos.y); + m_systemMousePos = pos; +} + +Math::Point CApplication::GetSystemMousePos() +{ + return m_systemMousePos; } void CApplication::SetJoystickEnabled(bool enable) @@ -766,3 +861,8 @@ void CApplication::OutputText(long x, long y, char* str) { // TODO } + +std::string CApplication::GetDataFilePath(const std::string& dirName, const std::string& fileName) +{ + return m_dataPath + "/" + dirName + "/" + fileName; +} diff --git a/src/app/app.h b/src/app/app.h index ed2bd9a..576ed62 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -21,6 +21,7 @@ #include "common/misc.h" +#include "common/singleton.h" #include "graphics/common/device.h" #include "graphics/common/engine.h" @@ -33,8 +34,8 @@ class CEvent; class CRobotMain; class CSound; -struct ApplicationPrivate; +struct ApplicationPrivate; /** * \class CApplication @@ -67,7 +68,7 @@ struct ApplicationPrivate; * The events are further handled in CRobotMain class. * */ -class CApplication +class CApplication : public CSingleton { public: //! Constructor (can only be called once!) @@ -75,13 +76,9 @@ public: //! Destructor ~CApplication(); - //! Returns the only CApplication instance - static CApplication* GetInstance() - { return m_appInstance; } - public: //! Parses commandline arguments - Error ParseArguments(int argc, char *argv[]); + bool ParseArguments(int argc, char *argv[]); //! Initializes the application bool Create(); //! Main event loop @@ -117,20 +114,31 @@ public: void SetKey(int keyRank, int option, int key); int GetKey(int keyRank, int option); - void SetMouseType(Gfx::MouseType type); - void SetMousePos(Math::Point pos); + //! Sets the grab mode for input (keyboard & mouse) + void SetGrabInput(bool grab); + //! Returns the grab mode + bool GetGrabInput(); + + //! Sets the visiblity of system mouse cursor + void SetSystemMouseVisible(bool visible); + //! Returns the visiblity of system mouse cursor + bool GetSystemMouseVisibile(); - //? void SetNiceMouse(bool nice); - //? bool GetNiceMouse(); - //? bool GetNiceMouseCap(); + //! Sets the position of system mouse cursor (in interface coords) + void SetSystemMousePos(Math::Point pos); + //! Returns the position of system mouse cursor (in interface coords) + Math::Point GetSystemMousePos(); bool WriteScreenShot(char *filename, int width, int height); + //! Returns the full path to a file in data directory + std::string GetDataFilePath(const std::string &dirName, const std::string &fileName); + protected: - //! Processes an SDL event to Event struct - void ParseEvent(); + //! Processes the captured SDL event to Event struct + Event ParseEvent(); //! Handles some incoming events - void ProcessEvent(Event event); + bool ProcessEvent(const Event &event); //! Renders the image in window bool Render(); @@ -140,16 +148,9 @@ protected: void CloseJoystick(); //! Converts window coords to interface coords - Math::Point WindowToInterfaceCoords(int x, int y); - - //HRESULT ConfirmDevice( DDCAPS* pddDriverCaps, D3DDEVICEDESC7* pd3dDeviceDesc ); - //HRESULT Initialize3DEnvironment(); - //HRESULT Change3DEnvironment(); - //HRESULT CreateZBuffer(GUID* pDeviceGUID); - //HRESULT Render3DEnvironment(); - //VOID Cleanup3DEnvironment(); - //VOID DeleteDeviceObjects(); - //VOID DisplayFrameworkError( HRESULT, DWORD ); + Math::Point WindowToInterfaceCoords(Math::IntPoint pos); + //! Converts the interface coords to window coords + Math::IntPoint InterfaceToWindowCoords(Math::Point pos); void InitText(); void DrawSuppl(); @@ -157,8 +158,6 @@ 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) @@ -185,21 +184,16 @@ protected: bool m_debugMode; bool m_setupMode; + //! Whether joystick is enabled bool m_joystickEnabled; + //! Text set as window title std::string m_windowTitle; - //? long m_vidMemTotal; - //? bool m_appUseZBuffer; - //? bool m_appUseStereo; - //? bool m_audioState; - //? bool m_audioTrack; - //? bool m_niceMouse; - int m_keyState; Math::Vector m_axeKey; Math::Vector m_axeJoy; - Math::Point m_mousePos; + Math::Point m_systemMousePos; long m_mouseWheel; //! Current state of joystick axes; may be updated from another thread @@ -209,5 +203,8 @@ protected: float m_time; long m_key[50][2]; + + //! Path to directory with data files + std::string m_dataPath; }; diff --git a/src/app/main.cpp b/src/app/main.cpp index f857037..9eea6e4 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -69,10 +69,10 @@ int main(int argc, char *argv[]) CApplication app; // single instance of the application - Error err = app.ParseArguments(argc, argv); - if (err != ERR_OK) + if (! app.ParseArguments(argc, argv)) { SystemDialog(SDT_ERROR, "COLOBOT", "Invalid commandline arguments!\n"); + return app.GetExitCode(); } int code = 0; -- cgit v1.2.3-1-g7c22