#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); }