From 7c5a3514dd6e907866bddcbb09b4d9cbd958dd8e Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Sun, 29 Jul 2012 15:09:53 +0200 Subject: [PATCH] Video mode changing - added video mode querying & changing - added joystick querying & changing - cleaned up CApplication interface --- src/app/app.cpp | 410 +++++++++++++++++++------------ src/app/app.h | 129 +++++++--- src/common/event.h | 33 ++- src/graphics/core/device.h | 10 +- src/graphics/core/texture.h | 10 +- src/graphics/engine/engine.cpp | 20 +- src/graphics/engine/engine.h | 21 +- src/graphics/opengl/gldevice.cpp | 44 +++- src/graphics/opengl/gldevice.h | 6 +- src/math/intsize.h | 61 +++++ src/math/size.h | 66 +++++ 11 files changed, 584 insertions(+), 226 deletions(-) create mode 100644 src/math/intsize.h create mode 100644 src/math/size.h diff --git a/src/app/app.cpp b/src/app/app.cpp index c778a63c..5c6ef49e 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -56,19 +56,14 @@ struct ApplicationPrivate SDL_Event currentEvent; //! Joystick SDL_Joystick *joystick; - //! Index of joystick device - int joystickIndex; //! Id of joystick timer SDL_TimerID joystickTimer; - //! Current configuration of OpenGL display device - Gfx::GLDeviceConfig deviceConfig; ApplicationPrivate() { memset(¤tEvent, 0, sizeof(SDL_Event)); surface = NULL; joystick = NULL; - joystickIndex = 0; joystickTimer = 0; } }; @@ -77,11 +72,8 @@ struct ApplicationPrivate CApplication::CApplication() { - m_private = new ApplicationPrivate(); - m_exitCode = 0; - - m_iMan = new CInstanceManager(); - + m_private = new ApplicationPrivate(); + m_iMan = new CInstanceManager(); m_eventQueue = new CEventQueue(m_iMan); m_engine = NULL; @@ -90,22 +82,17 @@ CApplication::CApplication() m_sound = NULL; m_keyState = 0; - m_axeKey = Math::Vector(0.0f, 0.0f, 0.0f); - m_axeJoy = Math::Vector(0.0f, 0.0f, 0.0f); + m_axeKey = Math::Vector(0.0f, 0.0f, 0.0f); + m_axeJoy = Math::Vector(0.0f, 0.0f, 0.0f); + + m_exitCode = 0; + m_active = false; + m_debugMode = false; + + m_windowTitle = "COLOBOT"; - m_active = false; - m_activateApp = false; - m_ready = false; m_joystickEnabled = false; - m_time = 0.0f; - - m_windowTitle = "COLOBOT"; - - m_showStats = false; - m_debugMode = false; - m_setupMode = true; - m_dataPath = "./data"; ResetKey(); @@ -139,7 +126,6 @@ bool CApplication::ParseArguments(int argc, char *argv[]) if (arg == "-debug") { - m_showStats = true; SetDebugMode(true); } else if (arg == "-datadir") @@ -165,7 +151,7 @@ bool CApplication::Create() // TODO: verify that data directory exists // Temporarily -- only in windowed mode - m_private->deviceConfig.fullScreen = false; + m_deviceConfig.fullScreen = false; // Create the 3D engine m_engine = new Gfx::CEngine(m_iMan, this); @@ -186,71 +172,30 @@ bool CApplication::Create() if (SDL_Init(initFlags) < 0) { - SystemDialog( SDT_ERROR, "COLOBOT - Error", "SDL initialization error:\n" + - std::string(SDL_GetError()) ); + SystemDialog( SDT_ERROR, "COLOBOT - Fatal Error", + "SDL initialization error:\n" + + std::string(SDL_GetError()) ); m_exitCode = 2; return false; } if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) == 0) { - SystemDialog( SDT_ERROR, "COLOBOT - Error", std::string("SDL_Image initialization error:\n") + - std::string(IMG_GetError()) ); + SystemDialog( SDT_ERROR, "COLOBOT - Fatal Error", + std::string("SDL_Image initialization error:\n") + + std::string(IMG_GetError()) ); m_exitCode = 3; return false; } - const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo(); - if (videoInfo == NULL) - { - SystemDialog( SDT_ERROR, "COLOBOT - Error", "SDL error while getting video info:\n " + - std::string(SDL_GetError()) ); - m_exitCode = 2; - return false; - } - - Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE; - - if (m_private->deviceConfig.resizeable) - videoFlags |= SDL_RESIZABLE; - - // Use hardware surface if available - if (videoInfo->hw_available) - videoFlags |= SDL_HWSURFACE; - else - videoFlags |= SDL_SWSURFACE; - - // Enable hardware blit if available - if (videoInfo->blit_hw) - videoFlags |= SDL_HWACCEL; - - if (m_private->deviceConfig.fullScreen) - videoFlags |= SDL_FULLSCREEN; - - // Set OpenGL attributes - - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, m_private->deviceConfig.redSize); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, m_private->deviceConfig.greenSize); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, m_private->deviceConfig.blueSize); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, m_private->deviceConfig.alphaSize); - - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, m_private->deviceConfig.depthSize); - - if (m_private->deviceConfig.doubleBuf) - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - - /* If hardware acceleration specifically requested, this will force the hw accel - and fail with error if not available */ - if (m_private->deviceConfig.hardwareAccel) - SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); - - m_private->surface = SDL_SetVideoMode(m_private->deviceConfig.width, m_private->deviceConfig.height, - m_private->deviceConfig.bpp, videoFlags); + if (! CreateVideoSurface()) + return false; // dialog is in function if (m_private->surface == NULL) { - SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("SDL error while setting video mode:\n") + - std::string(SDL_GetError()) ); + SystemDialog( SDT_ERROR, "COLOBT - Fatal Error", + std::string("SDL error while setting video mode:\n") + + std::string(SDL_GetError()) ); m_exitCode = 2; return false; } @@ -269,11 +214,12 @@ bool CApplication::Create() // The video is ready, we can create and initalize the graphics device - m_device = new Gfx::CGLDevice(); + m_device = new Gfx::CGLDevice(m_deviceConfig); if (! m_device->Create() ) { - SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("Error in CDevice::Create() :\n") + - std::string(m_device->GetError()) ); + SystemDialog( SDT_ERROR, "COLOBT - Fatal Error", + std::string("Error in CDevice::Create() :\n") + + std::string(m_device->GetError()) ); m_exitCode = 1; return false; } @@ -281,23 +227,74 @@ bool CApplication::Create() m_engine->SetDevice(m_device); if (! m_engine->Create() ) { - SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("Error in CEngine::Create() :\n") + - std::string(m_engine->GetError()) ); + SystemDialog( SDT_ERROR, "COLOBT - Fatal Error", + std::string("Error in CEngine::Create() :\n") + + std::string(m_engine->GetError()) ); m_exitCode = 1; return false; } if (! m_engine->AfterDeviceSetInit() ) { - SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("Error in CEngine::AfterDeviceSetInit() :\n") + - std::string(m_engine->GetError()) ); + SystemDialog( SDT_ERROR, "COLOBT - Fatal Error", + std::string("Error in CEngine::AfterDeviceSetInit() :\n") + + std::string(m_engine->GetError()) ); m_exitCode = 1; return false; } + return true; +} - // The app is ready to go - m_ready = true; +bool CApplication::CreateVideoSurface() +{ + const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo(); + if (videoInfo == NULL) + { + SystemDialog( SDT_ERROR, "COLOBOT - Fatal Error", + std::string("SDL error while getting video info:\n ") + + std::string(SDL_GetError()) ); + m_exitCode = 2; + return false; + } + + Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE; + + // Use hardware surface if available + if (videoInfo->hw_available) + videoFlags |= SDL_HWSURFACE; + else + videoFlags |= SDL_SWSURFACE; + + // Enable hardware blit if available + if (videoInfo->blit_hw) + videoFlags |= SDL_HWACCEL; + + if (m_deviceConfig.fullScreen) + videoFlags |= SDL_FULLSCREEN; + + if (m_deviceConfig.resizeable) + videoFlags |= SDL_RESIZABLE; + + // Set OpenGL attributes + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, m_deviceConfig.redSize); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, m_deviceConfig.greenSize); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, m_deviceConfig.blueSize); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, m_deviceConfig.alphaSize); + + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, m_deviceConfig.depthSize); + + if (m_deviceConfig.doubleBuf) + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + /* If hardware acceleration specifically requested, this will force the hw accel + and fail with error if not available */ + if (m_deviceConfig.hardwareAccel) + SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); + + m_private->surface = SDL_SetVideoMode(m_deviceConfig.size.w, m_deviceConfig.size.h, + m_deviceConfig.bpp, videoFlags); return true; } @@ -351,15 +348,73 @@ void CApplication::Destroy() SDL_Quit(); } +bool CApplication::ChangeVideoConfig(const Gfx::GLDeviceConfig &newConfig) +{ + static bool restore = false; + + m_lastDeviceConfig = m_deviceConfig; + m_deviceConfig = newConfig; + + + SDL_FreeSurface(m_private->surface); + + if (! CreateVideoSurface()) + { + // Fatal error, so post the quit event + m_eventQueue->AddEvent(Event(EVENT_QUIT)); + return false; + } + + if (m_private->surface == NULL) + { + if (! restore) + { + SystemDialog( SDT_ERROR, "COLOBT - Error", + std::string("SDL error while setting video mode:\n") + + std::string(SDL_GetError()) + std::string("\n") + + std::string("Previous mode will be restored") ); + + restore = true; + ChangeVideoConfig(m_lastDeviceConfig); + return false; + } + else + { + restore = false; + + SystemDialog( SDT_ERROR, "COLOBT - Fatal Error", + std::string("SDL error while restoring previous video mode:\n") + + std::string(SDL_GetError()) ); + + + // Fatal error, so post the quit event + m_eventQueue->AddEvent(Event(EVENT_QUIT)); + return false; + } + } + + ( static_cast(m_device) )->ConfigChanged(m_deviceConfig); + + m_engine->ResetAfterDeviceChanged(); + + return true; +} + bool CApplication::OpenJoystick() { - m_private->joystick = SDL_JoystickOpen(m_private->joystickIndex); + if ( (m_joystick.index < 0) || (m_joystick.index >= SDL_NumJoysticks()) ) + return false; + + m_private->joystick = SDL_JoystickOpen(m_joystick.index); if (m_private->joystick == NULL) return false; + m_joystick.axisCount = SDL_JoystickNumAxes(m_private->joystick); + m_joystick.buttonCount = SDL_JoystickNumButtons(m_private->joystick); + // Create the vectors with joystick axis & button states to exactly the required size - m_joyAxeState = std::vector(SDL_JoystickNumAxes(m_private->joystick), 0); - m_joyButtonState = std::vector(SDL_JoystickNumButtons(m_private->joystick), false); + m_joyAxeState = std::vector(m_joystick.axisCount, 0); + m_joyButtonState = std::vector(m_joystick.buttonCount, false); // Create a timer for polling joystick state m_private->joystickTimer = SDL_AddTimer(JOYSTICK_TIMER_INTERVAL, JoystickTimerCallback, NULL); @@ -367,7 +422,6 @@ bool CApplication::OpenJoystick() return true; } - void CApplication::CloseJoystick() { // Timer will remove itself automatically @@ -376,6 +430,17 @@ void CApplication::CloseJoystick() m_private->joystick = NULL; } +bool CApplication::ChangeJoystick(const JoystickDevice &newJoystick) +{ + if ( (newJoystick.index < 0) || (newJoystick.index >= SDL_NumJoysticks()) ) + return false; + + if (m_private->joystick != NULL) + CloseJoystick(); + + return OpenJoystick(); +} + Uint32 JoystickTimerCallback(Uint32 interval, void *) { CApplication *app = CApplication::GetInstancePointer(); @@ -452,6 +517,8 @@ int CApplication::Run() // To be sure no old event remains m_private->currentEvent.type = SDL_NOEVENT; + // Call SDL_PumpEvents() only once here + // (SDL_PeepEvents() doesn't call it) if (m_active) SDL_PumpEvents(); @@ -462,11 +529,11 @@ int CApplication::Run() int count = 0; // 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. + // render the scene. Else, use SDL_WaitEvent() to avoid eating CPU time. if (m_active) count = SDL_PeepEvents(&m_private->currentEvent, 1, SDL_GETEVENT, SDL_ALLEVENTS); else - count = SDL_PollEvent(&m_private->currentEvent); + count = SDL_WaitEvent(&m_private->currentEvent); // If received an event if (count > 0) @@ -492,7 +559,7 @@ int CApplication::Run() } // Enter game update & frame rendering only if active - if (m_active && m_ready) + if (m_active) { Event event; while (m_eventQueue->GetEvent(event)) @@ -554,14 +621,14 @@ PressState TranslatePressState(unsigned char state) - 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); + return Math::Point( (float)pos.x / (float)m_deviceConfig.size.w, + 1.0f - (float)pos.y / (float)m_deviceConfig.size.h); } Math::IntPoint CApplication::InterfaceToWindowCoords(Math::Point pos) { - return Math::IntPoint((int)(pos.x * m_private->deviceConfig.width), - (int)((1.0f - pos.y) * m_private->deviceConfig.height)); + return Math::IntPoint((int)(pos.x * m_deviceConfig.size.w), + (int)((1.0f - pos.y) * m_deviceConfig.size.h)); } /** The SDL event parsed is stored internally. @@ -626,6 +693,19 @@ Event CApplication::ParseEvent() event.joyButton.button = m_private->currentEvent.jbutton.button; event.joyButton.state = TranslatePressState(m_private->currentEvent.jbutton.state); } + else if (m_private->currentEvent.type == SDL_ACTIVEEVENT) + { + event.type = EVENT_ACTIVE; + + if (m_private->currentEvent.active.type & SDL_APPINPUTFOCUS) + event.active.flags |= ACTIVE_INPUT; + if (m_private->currentEvent.active.type & SDL_APPMOUSEFOCUS) + event.active.flags |= ACTIVE_MOUSE; + if (m_private->currentEvent.active.type & SDL_APPACTIVE) + event.active.flags |= ACTIVE_APP; + + event.active.gain = m_private->currentEvent.active.gain == 1; + } return event; } @@ -636,6 +716,14 @@ Event CApplication::ParseEvent() bool CApplication::ProcessEvent(const Event &event) { CLogger *l = GetLogger(); + + if (event.type == EVENT_ACTIVE) + { + m_active = event.active.gain; + if (m_debugMode) + l->Info("Focus change: active = %s\n", m_active ? "true" : "false"); + } + // Print the events in debug mode to test the code if (m_debugMode) { @@ -672,6 +760,11 @@ bool CApplication::ProcessEvent(const Event &event) l->Info(" button = %d\n", event.joyButton.button); l->Info(" state = %s\n", (event.joyButton.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED"); break; + case EVENT_ACTIVE: + l->Info("EVENT_ACTIVE:\n"); + l->Info(" flags = 0x%x\n", event.active.flags); + l->Info(" gain = %s\n", event.active.gain ? "true" : "false"); + break; default: break; } @@ -688,48 +781,58 @@ bool CApplication::Render() if (! result) return false; - if (m_private->deviceConfig.doubleBuf) + if (m_deviceConfig.doubleBuf) SDL_GL_SwapBuffers(); return true; } -/** Called in to toggle the pause state of the app. */ -void CApplication::Pause(bool pause) -{ - static long appPausedCount = 0L; - - appPausedCount += ( pause ? +1 : -1 ); - m_ready = appPausedCount == 0; - - // Handle the first pause request (of many, nestable pause requests) - if( pause && ( 1 == appPausedCount ) ) - { - // Stop the scene from animating - //m_engine->TimeEnterGel(); - } - - // Final pause request done - if (appPausedCount == 0) - { - // Restart the scene - //m_engine->TimeExitGel(); - } -} - void CApplication::StepSimulation(float rTime) { // TODO } -void CApplication::SetShowStat(bool show) +VideoQueryResult CApplication::GetVideoResolutionList(std::vector &resolutions, + bool fullScreen, bool resizeable) { - m_showStats = show; -} + resolutions.clear(); -bool CApplication::GetShowStat() -{ - return m_showStats; + const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo(); + if (videoInfo == NULL) + return VIDEO_QUERY_ERROR; + + Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE; + + // Use hardware surface if available + if (videoInfo->hw_available) + videoFlags |= SDL_HWSURFACE; + else + videoFlags |= SDL_SWSURFACE; + + // Enable hardware blit if available + if (videoInfo->blit_hw) + videoFlags |= SDL_HWACCEL; + + if (resizeable) + videoFlags |= SDL_RESIZABLE; + + if (fullScreen) + videoFlags |= SDL_FULLSCREEN; + + + SDL_Rect **modes = SDL_ListModes(NULL, videoFlags); + + if (modes == (SDL_Rect **)0) + return VIDEO_QUERY_NONE; // no modes available + + if (modes == (SDL_Rect **)-1) + return VIDEO_QUERY_ALL; // all resolutions are possible + + + for (int i = 0; modes[i] != NULL; ++i) + resolutions.push_back(Math::IntSize(modes[i]->w, modes[i]->h)); + + return VIDEO_QUERY_OK; } void CApplication::SetDebugMode(bool mode) @@ -742,11 +845,6 @@ bool CApplication::GetDebugMode() return m_debugMode; } -bool CApplication::GetSetupMode() -{ - return m_setupMode; -} - void CApplication::FlushPressKey() { // TODO @@ -803,6 +901,28 @@ Math::Point CApplication::GetSystemMousePos() return m_systemMousePos; } +std::vector CApplication::GetJoystickList() +{ + std::vector result; + + int count = SDL_NumJoysticks(); + + for (int index = 0; index < count; ++index) + { + JoystickDevice device; + device.index = index; + device.name = SDL_JoystickName(index); + result.push_back(device); + } + + return result; +} + +JoystickDevice CApplication::GetJoystick() +{ + return m_joystick; +} + void CApplication::SetJoystickEnabled(bool enable) { m_joystickEnabled = enable; @@ -825,32 +945,6 @@ bool CApplication::GetJoystickEnabled() return m_joystickEnabled; } -bool CApplication::WriteScreenShot(char *filename, int width, int height) -{ - // TODO - return false; -} - -void CApplication::InitText() -{ - // TODO -} - -void CApplication::DrawSuppl() -{ - // TODO -} - -void CApplication::ShowStats() -{ - // TODO -} - -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 956eab83..483aa55c 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -24,6 +24,8 @@ #include "common/singleton.h" #include "graphics/core/device.h" #include "graphics/engine/engine.h" +#include "graphics/opengl/gldevice.h" +#include "math/intsize.h" #include #include @@ -34,6 +36,35 @@ class CEvent; class CRobotMain; class CSound; +/** + \struct JoystickDevice + \brief Information about a joystick device */ +struct JoystickDevice +{ + //! Device index (-1 = invalid device) + int index; + //! Device name + std::string name; + //! Number of axes (only available after joystick opened) + int axisCount; + //! Number of buttons (only available after joystick opened) + int buttonCount; + + JoystickDevice() + : index(-1), axisCount(0), buttonCount(0) {} +}; + +/** + \enum VideoQueryResult + \brief Result of querying for available video resolutions */ +enum VideoQueryResult +{ + VIDEO_QUERY_ERROR, + VIDEO_QUERY_NONE, + VIDEO_QUERY_ALL, + VIDEO_QUERY_OK +}; + struct ApplicationPrivate; @@ -46,26 +77,38 @@ struct ApplicationPrivate; * * It is a singleton class with only one instance that can be created. * - * Creation of other main objects + * \section Creation Creation of other main objects * * The class creates the only instance of CInstanceManager, CEventQueue, CEngine, * CRobotMain and CSound classes. * - * Window management + * \section Window 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. + * joystick management, grabbing input and changing the system mouse cursor + * position and visibility. + * ("System mouse cursor" means the cursor displayed by the OS in constrast to the cursor + * displayed by CEngine). * - * Events + * \section Events Events + * + * Events are taken from SDL event queue, translated to common events from src/common.h + * and pushed to global event queue CEventQueue. * - * 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. + * The events are passed to ProcessEvent() of classes in this order: CApplication, CEngine + * and CRobotMain. CApplication and CEngine's ProcessEvent() functions return bool, which + * means whether to pass the event on, or stop the chain. This is to enable handling some + * events which are internal to CApplication or CEngine. + * + * \section Portability Portability + * + * Currently, the class only handles OpenGL devices. SDL can be used with DirectX, but + * for that to work, video initialization and video setting must be done differently. * */ class CApplication : public CSingleton @@ -89,26 +132,36 @@ public: //! Cleans up before exit void Destroy(); - //! Enters the pause mode - void Pause(bool pause); + //! Returns a list of possible video modes + VideoQueryResult GetVideoResolutionList(std::vector &resolutions, + bool fullScreen, bool resizeable); + + //! Returns the current video mode + Gfx::GLDeviceConfig GetVideoConfig(); + + //! Change the video mode to given mode + bool ChangeVideoConfig(const Gfx::GLDeviceConfig &newConfig); //! Updates the simulation state void StepSimulation(float rTime); + //! Returns a list of available joystick devices + std::vector GetJoystickList(); + + //! Returns info about the current joystick + JoystickDevice GetJoystick(); + + //! Change the current joystick device + bool ChangeJoystick(const JoystickDevice &newJoystick); + + //! Enables/disables joystick + void SetJoystickEnabled(bool enable); + //! Returns whether joystick is enabled + bool GetJoystickEnabled(); + //! Polls the state of joystick axes and buttons void UpdateJoystick(); - void SetShowStat(bool show); - bool GetShowStat(); - - void SetDebugMode(bool mode); - bool GetDebugMode(); - - bool GetSetupMode(); - - void SetJoystickEnabled(bool enable); - bool GetJoystickEnabled(); - void FlushPressKey(); void ResetKey(); void SetKey(int keyRank, int option, int key); @@ -129,12 +182,18 @@ public: //! Returns the position of system mouse cursor (in interface coords) Math::Point GetSystemMousePos(); - bool WriteScreenShot(char *filename, int width, int height); + //! Enables/disables debug mode (prints more info in logger) + void SetDebugMode(bool mode); + //! Returns whether debug mode is enabled + bool GetDebugMode(); //! Returns the full path to a file in data directory std::string GetDataFilePath(const std::string &dirName, const std::string &fileName); protected: + //! Creates the window's SDL_Surface + bool CreateVideoSurface(); + //! Processes the captured SDL event to Event struct Event ParseEvent(); //! Handles some incoming events @@ -152,11 +211,6 @@ protected: //! Converts the interface coords to window coords Math::IntPoint InterfaceToWindowCoords(Math::Point pos); - void InitText(); - void DrawSuppl(); - void ShowStats(); - void OutputText(long x, long y, char* str); - protected: //! Instance manager CInstanceManager* m_iMan; @@ -175,17 +229,15 @@ protected: //! Code to return at exit int m_exitCode; - + //! Whether application window is active bool m_active; - bool m_activateApp; - bool m_ready; - - bool m_showStats; + //! Whether debug mode is enabled bool m_debugMode; - bool m_setupMode; - //! Whether joystick is enabled - bool m_joystickEnabled; + //! Current configuration of OpenGL display device + Gfx::GLDeviceConfig m_deviceConfig; + //! Previous configuration of OpenGL display device + Gfx::GLDeviceConfig m_lastDeviceConfig; //! Text set as window title std::string m_windowTitle; @@ -196,14 +248,17 @@ protected: Math::Point m_systemMousePos; long m_mouseWheel; + long m_key[50][2]; + + //! Info about current joystick device + JoystickDevice m_joystick; + //! Whether joystick is enabled + bool m_joystickEnabled; //! Current state of joystick axes; may be updated from another thread std::vector m_joyAxeState; //! Current state of joystick buttons; may be updated from another thread std::vector m_joyButtonState; - float m_time; - long m_key[50][2]; - //! Path to directory with data files std::string m_dataPath; }; diff --git a/src/common/event.h b/src/common/event.h index 6ce1a792..0d9aa7c9 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -55,6 +55,9 @@ enum EventType //! Event sent after releasing a key EVENT_KEY_UP = 9, + //! Event sent when application window loses/gains focus + EVENT_ACTIVE = 10, + //? EVENT_CHAR = 10, //? EVENT_FOCUS = 11, @@ -608,7 +611,7 @@ struct JoyAxisEventData }; /** \struct JoyButtonEventData - \brief Joystick button event structure */ + \brief Additional data for joystick button event */ struct JoyButtonEventData { //! The joystick button index @@ -620,7 +623,31 @@ struct JoyButtonEventData : button(0), state(STATE_PRESSED) {} }; -// TODO: JoyHatEventData? JoyBallEventData? +/** \enum ActiveEventFlags + \brief Type of focus gained/lost */ +enum ActiveEventFlags +{ + //! Application window focus + ACTIVE_APP = 0x01, + //! Input focus + ACTIVE_INPUT = 0x02, + //! Mouse focus + ACTIVE_MOUSE = 0x04 + +}; + +/** \struct ActiveEventData + \brief Additional data for active event */ +struct ActiveEventData +{ + //! Flags (bitmask of enum values ActiveEventFlags) + unsigned char flags = 0; + //! True if the focus was gained; false otherwise + bool gain; + + ActiveEventData() + : flags(0), gain(false) {} +}; /** @@ -652,6 +679,8 @@ struct Event JoyAxisEventData joyAxis; //! Additional data for EVENT_JOY_AXIS JoyButtonEventData joyButton; + //! Additional data for EVENT_ACTIVE + ActiveEventData active; //? long param; // parameter //? Math::Point pos; // mouse position (0 .. 1) diff --git a/src/graphics/core/device.h b/src/graphics/core/device.h index ae612b72..1f6cacff 100644 --- a/src/graphics/core/device.h +++ b/src/graphics/core/device.h @@ -25,6 +25,7 @@ #include "graphics/core/material.h" #include "graphics/core/texture.h" #include "graphics/core/vertex.h" +#include "math/intsize.h" #include "math/matrix.h" #include @@ -43,10 +44,8 @@ namespace Gfx { */ struct DeviceConfig { - //! Screen width - int width; - //! Screen height - int height; + //! Screen size + Math::IntSize size; //! Bits per pixel int bpp; //! Full screen @@ -64,8 +63,7 @@ struct DeviceConfig //! Loads the default values inline void LoadDefault() { - width = 800; - height = 600; + size = Math::IntSize(800, 600); bpp = 32; fullScreen = false; resizeable = false; diff --git a/src/graphics/core/texture.h b/src/graphics/core/texture.h index 787c2bf2..8d6b0821 100644 --- a/src/graphics/core/texture.h +++ b/src/graphics/core/texture.h @@ -18,6 +18,9 @@ #pragma once +#include "math/intsize.h" + + namespace Gfx { /** @@ -190,10 +193,8 @@ struct Texture bool valid; //! ID of the texture in graphics engine unsigned int id; - //! Width of texture - int width; - //! Height of texture - int height; + //! Size of texture + Math::IntSize size; //! Whether the texture has alpha channel bool alpha; @@ -201,7 +202,6 @@ struct Texture { valid = false; id = 0; - width = height = 0; alpha = false; } diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 0914f9e2..e544ee31 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -62,9 +62,6 @@ Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app) m_sound = NULL; m_terrain = NULL; - m_dim.x = 640; - m_dim.y = 480; - m_lastDim = m_dim; m_focus = 0.75f; m_baseTime = 0; m_lastTime = 0; @@ -272,6 +269,12 @@ bool Gfx::CEngine::AfterDeviceSetInit() return true; } +void Gfx::CEngine::ResetAfterDeviceChanged() +{ + // TODO +} + + Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName, const Gfx::TextureCreateParams ¶ms) { CImage img; @@ -727,3 +730,14 @@ void Gfx::CEngine::AddStatisticTriangle(int count) { m_statisticTriangle += count; } + +void Gfx::CEngine::SetShowStat(bool show) +{ + m_showStats = show; +} + +bool Gfx::CEngine::GetShowStat() +{ + return m_showStats; +} + diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index 1348cddf..25c5e5d3 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -26,6 +26,7 @@ #include "graphics/core/texture.h" #include "graphics/core/vertex.h" #include "math/intpoint.h" +#include "math/intsize.h" #include "math/matrix.h" #include "math/point.h" #include "math/vector.h" @@ -513,21 +514,33 @@ public: CEngine(CInstanceManager *iMan, CApplication *app); ~CEngine(); + //! Returns whether the device was initialized bool GetWasInit(); + //! Returns the last error encountered std::string GetError(); + //! Performs the first initialization, before a device was set bool Create(); + //! Frees all resources before exit void Destroy(); + //! Sets the device to be used void SetDevice(Gfx::CDevice *device); + //! Returns the current device Gfx::CDevice* GetDevice(); + //! Performs initialization after a device was created and set bool AfterDeviceSetInit(); + //! Resets some states and flushes textures after device was changed (e.g. resoulution changed) + void ResetAfterDeviceChanged(); + void SetTerrain(Gfx::CTerrain* terrain); + //! Processes incoming event bool ProcessEvent(const Event &event); + //! Renders a single frame bool Render(); @@ -859,6 +872,9 @@ protected: bool m_wasInit; std::string m_error; + //! Whether to show stats (FPS, etc) + bool m_showStats; + int m_blackSrcBlend[2]; int m_blackDestBlend[2]; int m_whiteSrcBlend[2]; @@ -887,8 +903,9 @@ protected: bool m_render; bool m_movieLock; - Math::IntPoint m_dim; - Math::IntPoint m_lastDim; + //! Current size of window + Math::IntSize m_size; + Math::IntSize m_lastSize; std::vector m_objectTree; std::vector m_objects; diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp index bfe7fd75..1fd6a181 100644 --- a/src/graphics/opengl/gldevice.cpp +++ b/src/graphics/opengl/gldevice.cpp @@ -61,8 +61,9 @@ void Gfx::GLDeviceConfig::LoadDefault() -Gfx::CGLDevice::CGLDevice() +Gfx::CGLDevice::CGLDevice(const Gfx::GLDeviceConfig &config) { + m_config = config; m_wasInit = false; m_lighting = false; m_texturing = false; @@ -86,18 +87,24 @@ std::string Gfx::CGLDevice::GetError() bool Gfx::CGLDevice::Create() { #if defined(USE_GLEW) - if (glewInit() != GLEW_OK) - { - m_error = "GLEW initialization failed"; - return false; - } + static bool glewInited = false; - if ( (! GLEW_ARB_multitexture) || (! GLEW_EXT_texture_env_combine) || (! GLEW_EXT_secondary_color) ) + if (!glewInited) { - m_error = "GLEW reports required extensions not supported"; - return false; - } + glewInited = true; + if (glewInit() != GLEW_OK) + { + m_error = "GLEW initialization failed"; + return false; + } + + if ( (! GLEW_ARB_multitexture) || (! GLEW_EXT_texture_env_combine) || (! GLEW_EXT_secondary_color) ) + { + m_error = "GLEW reports required extensions not supported"; + return false; + } + } #endif /* NOTE: when not using GLEW, extension testing is not performed, as it is assumed that @@ -123,6 +130,8 @@ bool Gfx::CGLDevice::Create() glMatrixMode(GL_MODELVIEW); glLoadIdentity(); + glViewport(0, 0, m_config.size.w, m_config.size.h); + m_lights = std::vector(GL_MAX_LIGHTS, Gfx::Light()); m_lightsEnabled = std::vector (GL_MAX_LIGHTS, false); @@ -153,6 +162,17 @@ void Gfx::CGLDevice::Destroy() m_wasInit = false; } +void Gfx::CGLDevice::ConfigChanged(const Gfx::GLDeviceConfig& newConfig) +{ + m_config = newConfig; + + // Reset state + m_lighting = false; + m_texturing = false; + Destroy(); + Create(); +} + void Gfx::CGLDevice::BeginScene() { Clear(); @@ -375,8 +395,8 @@ Gfx::Texture Gfx::CGLDevice::CreateTexture(CImage *image, const Gfx::TextureCrea } result.valid = true; - result.width = data->surface->w; - result.height = data->surface->h; + result.size.w = data->surface->w; + result.size.h = data->surface->h; // Use & enable 1st texture stage glActiveTexture(GL_TEXTURE0); diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gldevice.h index 313ea02b..18640004 100644 --- a/src/graphics/opengl/gldevice.h +++ b/src/graphics/opengl/gldevice.h @@ -70,7 +70,7 @@ struct GLDevicePrivate; class CGLDevice : public Gfx::CDevice { public: - CGLDevice(); + CGLDevice(const Gfx::GLDeviceConfig &config); virtual ~CGLDevice(); virtual bool GetWasInit(); @@ -79,6 +79,8 @@ public: virtual bool Create(); virtual void Destroy(); + void ConfigChanged(const Gfx::GLDeviceConfig &newConfig); + virtual void BeginScene(); virtual void EndScene(); @@ -159,6 +161,8 @@ private: void UpdateLightPosition(int index); private: + //! Current config + Gfx::GLDeviceConfig m_config; //! Was initialized? bool m_wasInit; //! Last encountered error diff --git a/src/math/intsize.h b/src/math/intsize.h new file mode 100644 index 00000000..f4b2431f --- /dev/null +++ b/src/math/intsize.h @@ -0,0 +1,61 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * This program 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. +// * +// * This program 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 this program. If not, see http://www.gnu.org/licenses/. + +/** @defgroup MathIntSizeModule math/intsize.h + Contains the IntSize struct. + */ + +#pragma once + +// Math module namespace +namespace Math +{ + +/* @{ */ // start of group + +/** \struct IntSize math/size.h + \brief 2D size with integer dimensions */ +struct IntSize +{ + //! Width + int w; + //! Height + int h; + + //! Constructs a zero size: (0,0) + inline IntSize() + { + LoadZero(); + } + + //! Constructs a size from given dimensions: (w,h) + inline explicit IntSize(int w, int h) + { + this->w = w; + this->h = h; + } + + //! Sets the zero size: (0,0) + inline void LoadZero() + { + w = h = 0; + } +}; // struct Size + + +/* @} */ // end of group + +}; // namespace Math diff --git a/src/math/size.h b/src/math/size.h new file mode 100644 index 00000000..781b9a4a --- /dev/null +++ b/src/math/size.h @@ -0,0 +1,66 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * This program 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. +// * +// * This program 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 this program. If not, see http://www.gnu.org/licenses/. + +/** @defgroup MathSizeModule math/size.h + Contains the Size struct. + */ + +#pragma once + +// Math module namespace +namespace Math +{ + +/* @{ */ // start of group + +/** \struct Size math/size.h + \brief 2D size + + Represents a 2D size (w, h). + Is separate from Math::Point to avoid confusion. + + */ +struct Size +{ + //! Width + float w; + //! Height + float h; + + //! Constructs a zero size: (0,0) + inline Size() + { + LoadZero(); + } + + //! Constructs a size from given dimensions: (w,h) + inline explicit Size(float w, float h) + { + this->w = w; + this->h = h; + } + + //! Sets the zero size: (0,0) + inline void LoadZero() + { + w = h = 0.0f; + } +}; // struct Size + + +/* @} */ // end of group + +}; // namespace Math