Select Git revision
WindowManager.cpp
Forked from
einsteinathome / graphicsframework
259 commits behind the upstream repository.
-
Oliver Bock authoredOliver Bock authored
WindowManager.cpp 10.21 KiB
#include "WindowManager.h"
WindowManager::WindowManager()
{
}
WindowManager::~WindowManager()
{
}
bool WindowManager::initialize(const int width, const int height)
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
cerr << "Window system could not be initalized: " << SDL_GetError() << endl;
return false;
}
atexit(SDL_Quit);
// retrieve current video settings
const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
if (videoInfo->current_w != 0) {
m_DesktopWidth = videoInfo->current_w;
}
if (videoInfo->current_h != 0) {
m_DesktopHeight = videoInfo->current_h;
}
if (videoInfo->vfmt->BitsPerPixel != 0) {
m_DesktopBitsPerPixel = videoInfo->vfmt->BitsPerPixel;
}
// set initial non-fullscreen resolution
m_WindowedWidth = width;
m_WindowedHeight = height;
/*
* SDL_ASYNCBLIT - Surface benutzt asynchrone Blits, wenn möglich
* SDL_ANYFORMAT - Erlaubt jedes Pixel-Format (nur beim display-surface)
* SDL_FULLSCREEN - Surface im Full-Screen-Mode initialisieren (nur display-surface)
* SDL_OPENGL - Surface nutzt OpenGL (nur display-surface)
* SDL_RESIZABLE - Surfacefenster ist veränderbar (nur display-Surface)
* SDL_HWACCEL- Surface blit nutzt Hardwarebeschleunigung
* SDL_SRCCOLORKEY - Surface nutzt colorkey blitting
* SDL_RLEACCEL - Colorkey blitting ist durch RLE beschleunigt
* SDL_SRCALPHA - Surface blit nutzt alpha blending
* SDL_PREALLOC - Surface nutzt vorher allokierten Speicher
*/
// set common video flags
m_VideoModeFlags = SDL_OPENGL;
// check fullscreen video mode
m_FullscreenModeAvailable = true;
Uint32 bitPerPixel = SDL_VideoModeOK(
m_DesktopWidth,
m_DesktopHeight,
m_DesktopBitsPerPixel,
m_VideoModeFlags | SDL_FULLSCREEN);
if(!bitPerPixel) {
cerr << "Fullscreen video mode not supported: " << SDL_GetError() << endl;
m_FullscreenModeAvailable = false;
}
// check initial windowed video mode
m_WindowedModeAvailable = true;
bitPerPixel = SDL_VideoModeOK(
m_WindowedWidth,
m_WindowedHeight,
m_DesktopBitsPerPixel,
m_VideoModeFlags | SDL_RESIZABLE);
if(!bitPerPixel) {
cerr << "Windowed video mode not supported: " << SDL_GetError() << endl;
m_WindowedModeAvailable = false;
}
// both checks failed
if(!(m_FullscreenModeAvailable || m_WindowedModeAvailable)) {
cerr << "No suitable video mode available!"<< endl;
return false;
}
// minimum requirements
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 1);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 1);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 1);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
// unused requirements
//SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
//SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
//SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
//SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
// 4x FSAA, might be too heavy for some machines :-)
// TODO: should be controlled with config values (coupled to disabling text rendering?)
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
// we always start in windowed mode
// (starting in fullscreen fails with high CPU load!)
m_CurrentWidth = m_WindowedWidth;
m_CurrentHeight = m_WindowedHeight;
m_VideoModeFlags |= SDL_RESIZABLE;
m_DisplaySurface = SDL_SetVideoMode(
m_CurrentWidth,
m_CurrentHeight,
m_DesktopBitsPerPixel,
m_VideoModeFlags);
if (m_DisplaySurface == NULL) {
cerr << "Could not acquire rendering surface: " << SDL_GetError() << endl;
return false;
}
return true;
}
void WindowManager::eventLoop()
{
// be sure there's at least one observer!
assert(eventObservers.size() > 0);
// set two main timers (interval in ms)
SDL_AddTimer(40, &timerCallbackRenderEvent, NULL);
SDL_AddTimer(1000, &timerCallbackBOINCUpdateEvent, NULL);
// events we don't ignore, hence use
//SDL_EventState( SDL_QUIT, SDL_IGNORE);
//SDL_EventState( SDL_KEYDOWN, SDL_IGNORE);
//SDL_EventState( SDL_MOUSEMOTION, SDL_IGNORE);
//SDL_EventState( SDL_VIDEORESIZE, SDL_IGNORE);
//SDL_EventState( SDL_USEREVENT, SDL_IGNORE);
// events we ignore
SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
SDL_EventState(SDL_KEYUP, SDL_IGNORE);
SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_IGNORE);
SDL_EventState(SDL_JOYAXISMOTION, SDL_IGNORE);
SDL_EventState(SDL_JOYBALLMOTION, SDL_IGNORE);
SDL_EventState(SDL_JOYHATMOTION, SDL_IGNORE);
SDL_EventState(SDL_JOYBUTTONDOWN, SDL_IGNORE);
SDL_EventState(SDL_JOYBUTTONUP, SDL_IGNORE);
SDL_EventState(SDL_VIDEOEXPOSE, SDL_IGNORE);
SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
SDL_Event event;
while (SDL_WaitEvent(&event) ) {
if (event.type == SDL_USEREVENT &&
event.user.code == RenderEvent) {
#ifdef DEBUG_VALGRIND
// stop after i iterations when running valgrinded
static int i = 0;
if(i < 500) {
i++;
#endif
// notify our observers (currently exactly one)
eventObservers.front()->render(dtime());
#ifdef DEBUG_VALGRIND
}
else {
if (m_DisplaySurface) SDL_FreeSurface(m_DisplaySurface);
break;
}
#endif
}
else if (event.type == SDL_USEREVENT &&
event.user.code == BOINCUpdateEvent) {
// notify observers to fetch a BOINC update
eventObservers.front()->refreshBOINCInformation();
}
else if (event.motion.state & (SDL_BUTTON(1) | SDL_BUTTON(3)) &&
event.type == SDL_MOUSEMOTION) {
if (event.motion.state & SDL_BUTTON(1)) {
// notify our observers (currently exactly one)
eventObservers.front()->mouseMoveEvent(
event.motion.xrel,
event.motion.yrel,
AbstractGraphicsEngine::MouseButtonLeft);
}
else if (event.motion.state & SDL_BUTTON(3)) {
// notify our observers (currently exactly one)
eventObservers.front()->mouseMoveEvent(
event.motion.xrel,
event.motion.yrel,
AbstractGraphicsEngine::MouseButtonRight);
}
}
else if (event.type == SDL_VIDEORESIZE) {
m_CurrentWidth = m_WindowedWidth = event.resize.w;
m_CurrentHeight = m_WindowedHeight = event.resize.h;
// update video mode
m_DisplaySurface = SDL_SetVideoMode(
m_CurrentWidth,
m_CurrentHeight,
m_DesktopBitsPerPixel,
m_VideoModeFlags);
// notify our observers (currently exactly one)
eventObservers.front()->resize(m_CurrentWidth, m_CurrentHeight);
}
else if (event.type == SDL_QUIT ||
(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)) {
if (m_DisplaySurface) {
SDL_FreeSurface(m_DisplaySurface);
}
break;
}
else if (event.type == SDL_KEYDOWN) {
switch (event.key.keysym.sym) {
// notify our observers (currently exactly one)
case SDLK_s:
eventObservers.front()->keyboardPressEvent(AbstractGraphicsEngine::KeyS);
break;
case SDLK_c:
eventObservers.front()->keyboardPressEvent(AbstractGraphicsEngine::KeyC);
break;
case SDLK_o:
eventObservers.front()->keyboardPressEvent(AbstractGraphicsEngine::KeyO);
break;
case SDLK_x:
eventObservers.front()->keyboardPressEvent(AbstractGraphicsEngine::KeyX);
break;
case SDLK_p:
eventObservers.front()->keyboardPressEvent(AbstractGraphicsEngine::KeyP);
break;
case SDLK_r:
eventObservers.front()->keyboardPressEvent(AbstractGraphicsEngine::KeyR);
break;
case SDLK_g:
eventObservers.front()->keyboardPressEvent(AbstractGraphicsEngine::KeyG);
break;
case SDLK_a:
eventObservers.front()->keyboardPressEvent(AbstractGraphicsEngine::KeyA);
break;
case SDLK_i:
eventObservers.front()->keyboardPressEvent(AbstractGraphicsEngine::KeyI);
break;
case SDLK_l:
eventObservers.front()->keyboardPressEvent(AbstractGraphicsEngine::KeyL);
break;
case SDLK_m:
eventObservers.front()->keyboardPressEvent(AbstractGraphicsEngine::KeyM);
break;
case SDLK_RETURN:
toggleFullscreen();
default:
break;
}
}
}
}
void WindowManager::registerEventObserver(AbstractGraphicsEngine *engine)
{
// right now we're only accepting/using ONE observer
eventObservers.assign(1, engine);
}
void WindowManager::unregisterEventObserver(AbstractGraphicsEngine *engine)
{
eventObservers.remove(engine);
}
Uint32 WindowManager::timerCallbackRenderEvent(Uint32 interval, void *param)
{
SDL_Event event;
SDL_UserEvent userevent;
userevent.type = SDL_USEREVENT;
userevent.code = RenderEvent;
userevent.data1 = NULL;
userevent.data2 = NULL;
event.type = SDL_USEREVENT;
event.user = userevent;
SDL_PushEvent(&event);
return interval;
}
Uint32 WindowManager::timerCallbackBOINCUpdateEvent(Uint32 interval,
void *param)
{
SDL_Event event;
SDL_UserEvent userevent;
userevent.type = SDL_USEREVENT;
userevent.code = BOINCUpdateEvent;
userevent.data1 = NULL;
userevent.data2 = NULL;
event.type = SDL_USEREVENT;
event.user = userevent;
SDL_PushEvent(&event);
return interval;
}
int WindowManager::windowWidth() const
{
return m_CurrentWidth;
}
int WindowManager::windowHeight() const
{
return m_CurrentHeight;
}
void WindowManager::setWindowCaption(const string caption) const
{
SDL_WM_SetCaption(caption.c_str(), NULL);
}
void WindowManager::setWindowIcon(const string filename) const
{
if (filename.length() > 0) {
SDL_WM_SetIcon(SDL_LoadBMP(filename.c_str()), NULL);
}
}
void WindowManager::toggleFullscreen()
{
// toggle fullscreen bit and reset video mode
if(m_WindowedModeAvailable && (m_VideoModeFlags & SDL_FULLSCREEN)) {
// set new dimensions
m_CurrentWidth = m_WindowedWidth;
m_CurrentHeight = m_WindowedHeight;
// (un)set video mode flags
m_VideoModeFlags &= ~SDL_FULLSCREEN;
m_VideoModeFlags |= SDL_RESIZABLE;
// show cursor in fullscreen mode
SDL_ShowCursor(SDL_ENABLE);
}
else if(m_FullscreenModeAvailable && !(m_VideoModeFlags & SDL_FULLSCREEN)) {
// set new dimensions
m_CurrentWidth = m_DesktopWidth;
m_CurrentHeight = m_DesktopHeight;
// (un)set video mode flags
m_VideoModeFlags |= SDL_FULLSCREEN;
m_VideoModeFlags &= ~SDL_RESIZABLE;
// hide cursor
SDL_ShowCursor(SDL_DISABLE);
}
// reset video mode
m_DisplaySurface = SDL_SetVideoMode(
m_CurrentWidth,
m_CurrentHeight,
m_DesktopBitsPerPixel,
m_VideoModeFlags);
// notify our observers (currently exactly one)
eventObservers.front()->resize(m_CurrentWidth, m_CurrentHeight);
}