Skip to content
Snippets Groups Projects
Select Git revision
  • master default
  • mingw_gcc44
  • release_ABP1_012
  • release_ABP1_008
  • release_ABP1_006
  • release_ABP1_007
  • release_ABP1_005
  • release_ABP1_004
  • release_ABP1_003
  • pre_release_0.15
  • release_ABP1_001
  • release_ABP1_002
  • pre_release_0.13
  • pre_release_0.14
  • pre_release_0.11
  • pre_release_0.12
  • pre_release_0.10
  • pre_release_0.09
  • pre_release_0.08
19 results

WindowManager.cpp

Blame
  • Forked from einsteinathome / graphicsframework
    259 commits behind the upstream repository.
    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);
    }