Video mode changing

- added video mode querying & changing
- added joystick querying & changing
- cleaned up CApplication interface
dev-ui
Piotr Dziwinski 2012-07-29 15:09:53 +02:00
parent 72c0188ec3
commit 7c5a3514dd
11 changed files with 584 additions and 226 deletions

View File

@ -56,19 +56,14 @@ struct ApplicationPrivate
SDL_Event currentEvent; SDL_Event currentEvent;
//! Joystick //! Joystick
SDL_Joystick *joystick; SDL_Joystick *joystick;
//! Index of joystick device
int joystickIndex;
//! Id of joystick timer //! Id of joystick timer
SDL_TimerID joystickTimer; SDL_TimerID joystickTimer;
//! Current configuration of OpenGL display device
Gfx::GLDeviceConfig deviceConfig;
ApplicationPrivate() ApplicationPrivate()
{ {
memset(&currentEvent, 0, sizeof(SDL_Event)); memset(&currentEvent, 0, sizeof(SDL_Event));
surface = NULL; surface = NULL;
joystick = NULL; joystick = NULL;
joystickIndex = 0;
joystickTimer = 0; joystickTimer = 0;
} }
}; };
@ -77,11 +72,8 @@ struct ApplicationPrivate
CApplication::CApplication() CApplication::CApplication()
{ {
m_private = new ApplicationPrivate(); m_private = new ApplicationPrivate();
m_exitCode = 0; m_iMan = new CInstanceManager();
m_iMan = new CInstanceManager();
m_eventQueue = new CEventQueue(m_iMan); m_eventQueue = new CEventQueue(m_iMan);
m_engine = NULL; m_engine = NULL;
@ -90,22 +82,17 @@ CApplication::CApplication()
m_sound = NULL; m_sound = NULL;
m_keyState = 0; m_keyState = 0;
m_axeKey = 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_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_joystickEnabled = false;
m_time = 0.0f;
m_windowTitle = "COLOBOT";
m_showStats = false;
m_debugMode = false;
m_setupMode = true;
m_dataPath = "./data"; m_dataPath = "./data";
ResetKey(); ResetKey();
@ -139,7 +126,6 @@ bool CApplication::ParseArguments(int argc, char *argv[])
if (arg == "-debug") if (arg == "-debug")
{ {
m_showStats = true;
SetDebugMode(true); SetDebugMode(true);
} }
else if (arg == "-datadir") else if (arg == "-datadir")
@ -165,7 +151,7 @@ bool CApplication::Create()
// TODO: verify that data directory exists // TODO: verify that data directory exists
// Temporarily -- only in windowed mode // Temporarily -- only in windowed mode
m_private->deviceConfig.fullScreen = false; m_deviceConfig.fullScreen = false;
// Create the 3D engine // Create the 3D engine
m_engine = new Gfx::CEngine(m_iMan, this); m_engine = new Gfx::CEngine(m_iMan, this);
@ -186,71 +172,30 @@ bool CApplication::Create()
if (SDL_Init(initFlags) < 0) if (SDL_Init(initFlags) < 0)
{ {
SystemDialog( SDT_ERROR, "COLOBOT - Error", "SDL initialization error:\n" + SystemDialog( SDT_ERROR, "COLOBOT - Fatal Error",
std::string(SDL_GetError()) ); "SDL initialization error:\n" +
std::string(SDL_GetError()) );
m_exitCode = 2; m_exitCode = 2;
return false; return false;
} }
if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) == 0) if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) == 0)
{ {
SystemDialog( SDT_ERROR, "COLOBOT - Error", std::string("SDL_Image initialization error:\n") + SystemDialog( SDT_ERROR, "COLOBOT - Fatal Error",
std::string(IMG_GetError()) ); std::string("SDL_Image initialization error:\n") +
std::string(IMG_GetError()) );
m_exitCode = 3; m_exitCode = 3;
return false; return false;
} }
const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo(); if (! CreateVideoSurface())
if (videoInfo == NULL) return false; // dialog is in function
{
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 (m_private->surface == NULL) if (m_private->surface == NULL)
{ {
SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("SDL error while setting video mode:\n") + SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
std::string(SDL_GetError()) ); std::string("SDL error while setting video mode:\n") +
std::string(SDL_GetError()) );
m_exitCode = 2; m_exitCode = 2;
return false; return false;
} }
@ -269,11 +214,12 @@ bool CApplication::Create()
// The video is ready, we can create and initalize the graphics device // 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() ) if (! m_device->Create() )
{ {
SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("Error in CDevice::Create() :\n") + SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
std::string(m_device->GetError()) ); std::string("Error in CDevice::Create() :\n") +
std::string(m_device->GetError()) );
m_exitCode = 1; m_exitCode = 1;
return false; return false;
} }
@ -281,23 +227,74 @@ bool CApplication::Create()
m_engine->SetDevice(m_device); m_engine->SetDevice(m_device);
if (! m_engine->Create() ) if (! m_engine->Create() )
{ {
SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("Error in CEngine::Create() :\n") + SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
std::string(m_engine->GetError()) ); std::string("Error in CEngine::Create() :\n") +
std::string(m_engine->GetError()) );
m_exitCode = 1; m_exitCode = 1;
return false; return false;
} }
if (! m_engine->AfterDeviceSetInit() ) if (! m_engine->AfterDeviceSetInit() )
{ {
SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("Error in CEngine::AfterDeviceSetInit() :\n") + SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
std::string(m_engine->GetError()) ); std::string("Error in CEngine::AfterDeviceSetInit() :\n") +
std::string(m_engine->GetError()) );
m_exitCode = 1; m_exitCode = 1;
return false; return false;
} }
return true;
}
// The app is ready to go bool CApplication::CreateVideoSurface()
m_ready = true; {
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; return true;
} }
@ -351,15 +348,73 @@ void CApplication::Destroy()
SDL_Quit(); 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<Gfx::CGLDevice*>(m_device) )->ConfigChanged(m_deviceConfig);
m_engine->ResetAfterDeviceChanged();
return true;
}
bool CApplication::OpenJoystick() 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) if (m_private->joystick == NULL)
return false; 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 // 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_joyAxeState = std::vector<int>(m_joystick.axisCount, 0);
m_joyButtonState = std::vector<bool>(SDL_JoystickNumButtons(m_private->joystick), false); m_joyButtonState = std::vector<bool>(m_joystick.buttonCount, false);
// Create a timer for polling joystick state // Create a timer for polling joystick state
m_private->joystickTimer = SDL_AddTimer(JOYSTICK_TIMER_INTERVAL, JoystickTimerCallback, NULL); m_private->joystickTimer = SDL_AddTimer(JOYSTICK_TIMER_INTERVAL, JoystickTimerCallback, NULL);
@ -367,7 +422,6 @@ bool CApplication::OpenJoystick()
return true; return true;
} }
void CApplication::CloseJoystick() void CApplication::CloseJoystick()
{ {
// Timer will remove itself automatically // Timer will remove itself automatically
@ -376,6 +430,17 @@ void CApplication::CloseJoystick()
m_private->joystick = NULL; 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 *) Uint32 JoystickTimerCallback(Uint32 interval, void *)
{ {
CApplication *app = CApplication::GetInstancePointer(); CApplication *app = CApplication::GetInstancePointer();
@ -452,6 +517,8 @@ int CApplication::Run()
// To be sure no old event remains // To be sure no old event remains
m_private->currentEvent.type = SDL_NOEVENT; m_private->currentEvent.type = SDL_NOEVENT;
// Call SDL_PumpEvents() only once here
// (SDL_PeepEvents() doesn't call it)
if (m_active) if (m_active)
SDL_PumpEvents(); SDL_PumpEvents();
@ -462,11 +529,11 @@ int CApplication::Run()
int count = 0; int count = 0;
// Use SDL_PeepEvents() if the app is active, so we can use idle time to // 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) if (m_active)
count = SDL_PeepEvents(&m_private->currentEvent, 1, SDL_GETEVENT, SDL_ALLEVENTS); count = SDL_PeepEvents(&m_private->currentEvent, 1, SDL_GETEVENT, SDL_ALLEVENTS);
else else
count = SDL_PollEvent(&m_private->currentEvent); count = SDL_WaitEvent(&m_private->currentEvent);
// If received an event // If received an event
if (count > 0) if (count > 0)
@ -492,7 +559,7 @@ int CApplication::Run()
} }
// Enter game update & frame rendering only if active // Enter game update & frame rendering only if active
if (m_active && m_ready) if (m_active)
{ {
Event event; Event event;
while (m_eventQueue->GetEvent(event)) while (m_eventQueue->GetEvent(event))
@ -554,14 +621,14 @@ PressState TranslatePressState(unsigned char state)
- y: 0=down, 1=up */ - y: 0=down, 1=up */
Math::Point CApplication::WindowToInterfaceCoords(Math::IntPoint pos) Math::Point CApplication::WindowToInterfaceCoords(Math::IntPoint pos)
{ {
return Math::Point( (float)pos.x / (float)m_private->deviceConfig.width, return Math::Point( (float)pos.x / (float)m_deviceConfig.size.w,
1.0f - (float)pos.y / (float)m_private->deviceConfig.height); 1.0f - (float)pos.y / (float)m_deviceConfig.size.h);
} }
Math::IntPoint CApplication::InterfaceToWindowCoords(Math::Point pos) Math::IntPoint CApplication::InterfaceToWindowCoords(Math::Point pos)
{ {
return Math::IntPoint((int)(pos.x * m_private->deviceConfig.width), return Math::IntPoint((int)(pos.x * m_deviceConfig.size.w),
(int)((1.0f - pos.y) * m_private->deviceConfig.height)); (int)((1.0f - pos.y) * m_deviceConfig.size.h));
} }
/** The SDL event parsed is stored internally. /** The SDL event parsed is stored internally.
@ -626,6 +693,19 @@ Event CApplication::ParseEvent()
event.joyButton.button = m_private->currentEvent.jbutton.button; event.joyButton.button = m_private->currentEvent.jbutton.button;
event.joyButton.state = TranslatePressState(m_private->currentEvent.jbutton.state); 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; return event;
} }
@ -636,6 +716,14 @@ Event CApplication::ParseEvent()
bool CApplication::ProcessEvent(const Event &event) bool CApplication::ProcessEvent(const Event &event)
{ {
CLogger *l = GetLogger(); 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 // Print the events in debug mode to test the code
if (m_debugMode) if (m_debugMode)
{ {
@ -672,6 +760,11 @@ bool CApplication::ProcessEvent(const Event &event)
l->Info(" button = %d\n", event.joyButton.button); l->Info(" button = %d\n", event.joyButton.button);
l->Info(" state = %s\n", (event.joyButton.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED"); l->Info(" state = %s\n", (event.joyButton.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED");
break; 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: default:
break; break;
} }
@ -688,48 +781,58 @@ bool CApplication::Render()
if (! result) if (! result)
return false; return false;
if (m_private->deviceConfig.doubleBuf) if (m_deviceConfig.doubleBuf)
SDL_GL_SwapBuffers(); SDL_GL_SwapBuffers();
return true; 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) void CApplication::StepSimulation(float rTime)
{ {
// TODO // TODO
} }
void CApplication::SetShowStat(bool show) VideoQueryResult CApplication::GetVideoResolutionList(std::vector<Math::IntSize> &resolutions,
bool fullScreen, bool resizeable)
{ {
m_showStats = show; resolutions.clear();
}
bool CApplication::GetShowStat() const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
{ if (videoInfo == NULL)
return m_showStats; 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) void CApplication::SetDebugMode(bool mode)
@ -742,11 +845,6 @@ bool CApplication::GetDebugMode()
return m_debugMode; return m_debugMode;
} }
bool CApplication::GetSetupMode()
{
return m_setupMode;
}
void CApplication::FlushPressKey() void CApplication::FlushPressKey()
{ {
// TODO // TODO
@ -803,6 +901,28 @@ Math::Point CApplication::GetSystemMousePos()
return m_systemMousePos; return m_systemMousePos;
} }
std::vector<JoystickDevice> CApplication::GetJoystickList()
{
std::vector<JoystickDevice> 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) void CApplication::SetJoystickEnabled(bool enable)
{ {
m_joystickEnabled = enable; m_joystickEnabled = enable;
@ -825,32 +945,6 @@ bool CApplication::GetJoystickEnabled()
return m_joystickEnabled; 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) std::string CApplication::GetDataFilePath(const std::string& dirName, const std::string& fileName)
{ {
return m_dataPath + "/" + dirName + "/" + fileName; return m_dataPath + "/" + dirName + "/" + fileName;

View File

@ -24,6 +24,8 @@
#include "common/singleton.h" #include "common/singleton.h"
#include "graphics/core/device.h" #include "graphics/core/device.h"
#include "graphics/engine/engine.h" #include "graphics/engine/engine.h"
#include "graphics/opengl/gldevice.h"
#include "math/intsize.h"
#include <string> #include <string>
#include <vector> #include <vector>
@ -34,6 +36,35 @@ class CEvent;
class CRobotMain; class CRobotMain;
class CSound; 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; struct ApplicationPrivate;
@ -46,26 +77,38 @@ struct ApplicationPrivate;
* *
* It is a singleton class with only one instance that can be created. * 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, * The class creates the only instance of CInstanceManager, CEventQueue, CEngine,
* CRobotMain and CSound classes. * CRobotMain and CSound classes.
* *
* Window management * \section Window Window management
* *
* The class is responsible for creating app window, setting and changing the video mode, * 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, * Joystick events are generated somewhat differently, by running a separate timer,
* polling the device for changes and synthesising events on change. It avoids flooding * 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 * the event queue with too many joystick events and the granularity of the timer can be
* adjusted. * 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<CApplication> class CApplication : public CSingleton<CApplication>
@ -89,26 +132,36 @@ public:
//! Cleans up before exit //! Cleans up before exit
void Destroy(); void Destroy();
//! Enters the pause mode //! Returns a list of possible video modes
void Pause(bool pause); VideoQueryResult GetVideoResolutionList(std::vector<Math::IntSize> &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 //! Updates the simulation state
void StepSimulation(float rTime); void StepSimulation(float rTime);
//! Returns a list of available joystick devices
std::vector<JoystickDevice> 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 //! Polls the state of joystick axes and buttons
void UpdateJoystick(); 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 FlushPressKey();
void ResetKey(); void ResetKey();
void SetKey(int keyRank, int option, int key); void SetKey(int keyRank, int option, int key);
@ -129,12 +182,18 @@ public:
//! Returns the position of system mouse cursor (in interface coords) //! Returns the position of system mouse cursor (in interface coords)
Math::Point GetSystemMousePos(); 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 //! Returns the full path to a file in data directory
std::string GetDataFilePath(const std::string &dirName, const std::string &fileName); std::string GetDataFilePath(const std::string &dirName, const std::string &fileName);
protected: protected:
//! Creates the window's SDL_Surface
bool CreateVideoSurface();
//! Processes the captured SDL event to Event struct //! Processes the captured SDL event to Event struct
Event ParseEvent(); Event ParseEvent();
//! Handles some incoming events //! Handles some incoming events
@ -152,11 +211,6 @@ protected:
//! Converts the interface coords to window coords //! Converts the interface coords to window coords
Math::IntPoint InterfaceToWindowCoords(Math::Point pos); Math::IntPoint InterfaceToWindowCoords(Math::Point pos);
void InitText();
void DrawSuppl();
void ShowStats();
void OutputText(long x, long y, char* str);
protected: protected:
//! Instance manager //! Instance manager
CInstanceManager* m_iMan; CInstanceManager* m_iMan;
@ -175,17 +229,15 @@ protected:
//! Code to return at exit //! Code to return at exit
int m_exitCode; int m_exitCode;
//! Whether application window is active
bool m_active; bool m_active;
bool m_activateApp; //! Whether debug mode is enabled
bool m_ready;
bool m_showStats;
bool m_debugMode; bool m_debugMode;
bool m_setupMode;
//! Whether joystick is enabled //! Current configuration of OpenGL display device
bool m_joystickEnabled; Gfx::GLDeviceConfig m_deviceConfig;
//! Previous configuration of OpenGL display device
Gfx::GLDeviceConfig m_lastDeviceConfig;
//! Text set as window title //! Text set as window title
std::string m_windowTitle; std::string m_windowTitle;
@ -196,14 +248,17 @@ protected:
Math::Point m_systemMousePos; Math::Point m_systemMousePos;
long m_mouseWheel; 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 //! Current state of joystick axes; may be updated from another thread
std::vector<int> m_joyAxeState; std::vector<int> m_joyAxeState;
//! Current state of joystick buttons; may be updated from another thread //! Current state of joystick buttons; may be updated from another thread
std::vector<bool> m_joyButtonState; std::vector<bool> m_joyButtonState;
float m_time;
long m_key[50][2];
//! Path to directory with data files //! Path to directory with data files
std::string m_dataPath; std::string m_dataPath;
}; };

View File

@ -55,6 +55,9 @@ enum EventType
//! Event sent after releasing a key //! Event sent after releasing a key
EVENT_KEY_UP = 9, EVENT_KEY_UP = 9,
//! Event sent when application window loses/gains focus
EVENT_ACTIVE = 10,
//? EVENT_CHAR = 10, //? EVENT_CHAR = 10,
//? EVENT_FOCUS = 11, //? EVENT_FOCUS = 11,
@ -608,7 +611,7 @@ struct JoyAxisEventData
}; };
/** \struct JoyButtonEventData /** \struct JoyButtonEventData
\brief Joystick button event structure */ \brief Additional data for joystick button event */
struct JoyButtonEventData struct JoyButtonEventData
{ {
//! The joystick button index //! The joystick button index
@ -620,7 +623,31 @@ struct JoyButtonEventData
: button(0), state(STATE_PRESSED) {} : 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; JoyAxisEventData joyAxis;
//! Additional data for EVENT_JOY_AXIS //! Additional data for EVENT_JOY_AXIS
JoyButtonEventData joyButton; JoyButtonEventData joyButton;
//! Additional data for EVENT_ACTIVE
ActiveEventData active;
//? long param; // parameter //? long param; // parameter
//? Math::Point pos; // mouse position (0 .. 1) //? Math::Point pos; // mouse position (0 .. 1)

View File

@ -25,6 +25,7 @@
#include "graphics/core/material.h" #include "graphics/core/material.h"
#include "graphics/core/texture.h" #include "graphics/core/texture.h"
#include "graphics/core/vertex.h" #include "graphics/core/vertex.h"
#include "math/intsize.h"
#include "math/matrix.h" #include "math/matrix.h"
#include <string> #include <string>
@ -43,10 +44,8 @@ namespace Gfx {
*/ */
struct DeviceConfig struct DeviceConfig
{ {
//! Screen width //! Screen size
int width; Math::IntSize size;
//! Screen height
int height;
//! Bits per pixel //! Bits per pixel
int bpp; int bpp;
//! Full screen //! Full screen
@ -64,8 +63,7 @@ struct DeviceConfig
//! Loads the default values //! Loads the default values
inline void LoadDefault() inline void LoadDefault()
{ {
width = 800; size = Math::IntSize(800, 600);
height = 600;
bpp = 32; bpp = 32;
fullScreen = false; fullScreen = false;
resizeable = false; resizeable = false;

View File

@ -18,6 +18,9 @@
#pragma once #pragma once
#include "math/intsize.h"
namespace Gfx { namespace Gfx {
/** /**
@ -190,10 +193,8 @@ struct Texture
bool valid; bool valid;
//! ID of the texture in graphics engine //! ID of the texture in graphics engine
unsigned int id; unsigned int id;
//! Width of texture //! Size of texture
int width; Math::IntSize size;
//! Height of texture
int height;
//! Whether the texture has alpha channel //! Whether the texture has alpha channel
bool alpha; bool alpha;
@ -201,7 +202,6 @@ struct Texture
{ {
valid = false; valid = false;
id = 0; id = 0;
width = height = 0;
alpha = false; alpha = false;
} }

View File

@ -62,9 +62,6 @@ Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
m_sound = NULL; m_sound = NULL;
m_terrain = NULL; m_terrain = NULL;
m_dim.x = 640;
m_dim.y = 480;
m_lastDim = m_dim;
m_focus = 0.75f; m_focus = 0.75f;
m_baseTime = 0; m_baseTime = 0;
m_lastTime = 0; m_lastTime = 0;
@ -272,6 +269,12 @@ bool Gfx::CEngine::AfterDeviceSetInit()
return true; return true;
} }
void Gfx::CEngine::ResetAfterDeviceChanged()
{
// TODO
}
Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName, const Gfx::TextureCreateParams &params) Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName, const Gfx::TextureCreateParams &params)
{ {
CImage img; CImage img;
@ -727,3 +730,14 @@ void Gfx::CEngine::AddStatisticTriangle(int count)
{ {
m_statisticTriangle += count; m_statisticTriangle += count;
} }
void Gfx::CEngine::SetShowStat(bool show)
{
m_showStats = show;
}
bool Gfx::CEngine::GetShowStat()
{
return m_showStats;
}

View File

@ -26,6 +26,7 @@
#include "graphics/core/texture.h" #include "graphics/core/texture.h"
#include "graphics/core/vertex.h" #include "graphics/core/vertex.h"
#include "math/intpoint.h" #include "math/intpoint.h"
#include "math/intsize.h"
#include "math/matrix.h" #include "math/matrix.h"
#include "math/point.h" #include "math/point.h"
#include "math/vector.h" #include "math/vector.h"
@ -513,21 +514,33 @@ public:
CEngine(CInstanceManager *iMan, CApplication *app); CEngine(CInstanceManager *iMan, CApplication *app);
~CEngine(); ~CEngine();
//! Returns whether the device was initialized
bool GetWasInit(); bool GetWasInit();
//! Returns the last error encountered
std::string GetError(); std::string GetError();
//! Performs the first initialization, before a device was set
bool Create(); bool Create();
//! Frees all resources before exit
void Destroy(); void Destroy();
//! Sets the device to be used
void SetDevice(Gfx::CDevice *device); void SetDevice(Gfx::CDevice *device);
//! Returns the current device
Gfx::CDevice* GetDevice(); Gfx::CDevice* GetDevice();
//! Performs initialization after a device was created and set
bool AfterDeviceSetInit(); bool AfterDeviceSetInit();
//! Resets some states and flushes textures after device was changed (e.g. resoulution changed)
void ResetAfterDeviceChanged();
void SetTerrain(Gfx::CTerrain* terrain); void SetTerrain(Gfx::CTerrain* terrain);
//! Processes incoming event
bool ProcessEvent(const Event &event); bool ProcessEvent(const Event &event);
//! Renders a single frame
bool Render(); bool Render();
@ -859,6 +872,9 @@ protected:
bool m_wasInit; bool m_wasInit;
std::string m_error; std::string m_error;
//! Whether to show stats (FPS, etc)
bool m_showStats;
int m_blackSrcBlend[2]; int m_blackSrcBlend[2];
int m_blackDestBlend[2]; int m_blackDestBlend[2];
int m_whiteSrcBlend[2]; int m_whiteSrcBlend[2];
@ -887,8 +903,9 @@ protected:
bool m_render; bool m_render;
bool m_movieLock; bool m_movieLock;
Math::IntPoint m_dim; //! Current size of window
Math::IntPoint m_lastDim; Math::IntSize m_size;
Math::IntSize m_lastSize;
std::vector<Gfx::EngineObjLevel1> m_objectTree; std::vector<Gfx::EngineObjLevel1> m_objectTree;
std::vector<Gfx::EngineObject> m_objects; std::vector<Gfx::EngineObject> m_objects;

View File

@ -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_wasInit = false;
m_lighting = false; m_lighting = false;
m_texturing = false; m_texturing = false;
@ -86,18 +87,24 @@ std::string Gfx::CGLDevice::GetError()
bool Gfx::CGLDevice::Create() bool Gfx::CGLDevice::Create()
{ {
#if defined(USE_GLEW) #if defined(USE_GLEW)
if (glewInit() != GLEW_OK) static bool glewInited = false;
{
m_error = "GLEW initialization failed";
return false;
}
if ( (! GLEW_ARB_multitexture) || (! GLEW_EXT_texture_env_combine) || (! GLEW_EXT_secondary_color) ) if (!glewInited)
{ {
m_error = "GLEW reports required extensions not supported"; glewInited = true;
return false;
}
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 #endif
/* NOTE: when not using GLEW, extension testing is not performed, as it is assumed that /* 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); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
glViewport(0, 0, m_config.size.w, m_config.size.h);
m_lights = std::vector<Gfx::Light>(GL_MAX_LIGHTS, Gfx::Light()); m_lights = std::vector<Gfx::Light>(GL_MAX_LIGHTS, Gfx::Light());
m_lightsEnabled = std::vector<bool> (GL_MAX_LIGHTS, false); m_lightsEnabled = std::vector<bool> (GL_MAX_LIGHTS, false);
@ -153,6 +162,17 @@ void Gfx::CGLDevice::Destroy()
m_wasInit = false; 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() void Gfx::CGLDevice::BeginScene()
{ {
Clear(); Clear();
@ -375,8 +395,8 @@ Gfx::Texture Gfx::CGLDevice::CreateTexture(CImage *image, const Gfx::TextureCrea
} }
result.valid = true; result.valid = true;
result.width = data->surface->w; result.size.w = data->surface->w;
result.height = data->surface->h; result.size.h = data->surface->h;
// Use & enable 1st texture stage // Use & enable 1st texture stage
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);

View File

@ -70,7 +70,7 @@ struct GLDevicePrivate;
class CGLDevice : public Gfx::CDevice class CGLDevice : public Gfx::CDevice
{ {
public: public:
CGLDevice(); CGLDevice(const Gfx::GLDeviceConfig &config);
virtual ~CGLDevice(); virtual ~CGLDevice();
virtual bool GetWasInit(); virtual bool GetWasInit();
@ -79,6 +79,8 @@ public:
virtual bool Create(); virtual bool Create();
virtual void Destroy(); virtual void Destroy();
void ConfigChanged(const Gfx::GLDeviceConfig &newConfig);
virtual void BeginScene(); virtual void BeginScene();
virtual void EndScene(); virtual void EndScene();
@ -159,6 +161,8 @@ private:
void UpdateLightPosition(int index); void UpdateLightPosition(int index);
private: private:
//! Current config
Gfx::GLDeviceConfig m_config;
//! Was initialized? //! Was initialized?
bool m_wasInit; bool m_wasInit;
//! Last encountered error //! Last encountered error

61
src/math/intsize.h Normal file
View File

@ -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

66
src/math/size.h Normal file
View File

@ -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