view engine/core/video/devicecaps.cpp @ 653:01acc9fc35ea

* Moved getCurrentScreenMode() to the renderbackend as renderbackend is what initializes the screen. * Updated the Color masks to follow the integer standards * Added some new SDL modes (HW Surface and double buffer) to check for in DeviceCaps. * RenderBackend now saves the actual flags used to initialize the screen.
author prock@33b003aa-7bff-0310-803a-e67f0ece8222
date Fri, 15 Oct 2010 18:54:34 +0000
parents b9c132cb6ea4
children 5d6b1820b953
line wrap: on
line source

/***************************************************************************
 *   Copyright (C) 2005-2010 by the FIFE team                              *
 *   http://www.fifengine.net                                               *
 *   This file is part of FIFE.                                            *
 *                                                                         *
 *   FIFE is free software; you can redistribute it and/or                 *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library 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     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
 ***************************************************************************/

// Standard C++ library includes
#include <iostream>
#include <algorithm>

// 3rd party library includes
#include <SDL.h>
#include <SDL_video.h>

// FIFE includes
// These includes are split up in two parts, separated by one empty line
// First block: files included from the FIFE root src directory
// Second block: files included from the same folder
#include "util/base/exception.h"

#include "devicecaps.h"

namespace FIFE {

	ScreenMode::ScreenMode() :
		           m_width(0), m_height(0), m_bpp(0), m_SDLFlags(0){
	}

	ScreenMode::ScreenMode(uint16_t width, uint16_t height, uint16_t bpp, uint32_t SDLFlags) :
		           m_width(width), m_height(height), m_bpp(bpp), m_SDLFlags(SDLFlags){
	}

	ScreenMode::ScreenMode(const ScreenMode& rhs){
		m_width = rhs.getWidth();
		m_height = rhs.getHeight();
		m_bpp = rhs.getBPP();
		m_SDLFlags = rhs.getSDLFlags();
	}

	bool ScreenMode::operator <(const ScreenMode& rhs) const {
		if (m_bpp < rhs.getBPP() ) {
			return true;
		}

		else if (m_bpp == rhs.getBPP()) {
			if (m_width == rhs.getWidth() && m_height == rhs.getHeight()){
				if (!(m_SDLFlags & SDL_HWSURFACE) && (rhs.getSDLFlags() & SDL_HWSURFACE)) {
					//I would like return true so that we prefer hardware surfaces but
					//it really slows the engine down in fullscreen.  See the SDL FAQ for an
					//explanation.
					return false;
				}
			}

			else if (m_width < rhs.getWidth() || m_height < rhs.getHeight()) {
				return true;
			}
		}
		return false;
	}

	DeviceCaps::DeviceCaps() :
	    m_driverName("Invalid"),
		m_hwAvailable(false),
		m_wmAvailable(false),
		m_hwBlitAccel(false),
		m_hwCCBlitAccel(false),
		m_hwToHwAlphaBlitAccel(false),
		m_swToHwBlitAccel(false),
		m_swToHwCCBlistAccel(false),
		m_swToHwAlphaBlitAccel(false),
		m_BlitFillAccel(false),
		m_videoMem(0) {

		fillAvailableDrivers();
	}


	DeviceCaps::~DeviceCaps() {
	}

	void DeviceCaps::reset() {
		m_screenModes.clear();
		m_driverName = "Invalid";
		m_hwAvailable = false;
		m_wmAvailable = false;
		m_hwBlitAccel = false;
		m_hwCCBlitAccel = false;
		m_hwToHwAlphaBlitAccel = false;
		m_swToHwBlitAccel = false;
		m_swToHwCCBlistAccel = false;
		m_swToHwAlphaBlitAccel = false;
		m_BlitFillAccel = false;
		m_videoMem = 0;
	}


	void DeviceCaps::fillAvailableDrivers() {
		m_availableDrivers.clear();
#if defined( __unix__ )
		m_availableDrivers.push_back("x11");
		m_availableDrivers.push_back("nanox");
		m_availableDrivers.push_back("qtopia");
		m_availableDrivers.push_back("fbcon");
		m_availableDrivers.push_back("directfb");
		m_availableDrivers.push_back("svgalib");
#endif

// Win32
#if defined( WIN32 )
		m_availableDrivers.push_back("directx");
		m_availableDrivers.push_back("windib");
#endif

// Macintosh
#if defined( __APPLE_CC__ )
		m_availableDrivers.push_back("Quartz");
		m_availableDrivers.push_back("x11");
#endif
	}

	void DeviceCaps::fillDeviceCaps() {
		//buffer to store driver name
		const uint32_t bufferSize = 256;
		char buffer[bufferSize];

		//clear in case this is called twice
		reset();

		//FLAGS
#ifdef HAVE_OPENGL
		const uint32_t numFlags = 6;
		uint32_t flags[numFlags];

		//OpenGL, windowed, hw accel
		flags[0] = ScreenMode::HW_WINDOWED_OPENGL;
		//OpenGL, fullscree, hw accel
		flags[1] = ScreenMode::HW_FULLSCREEN_OPENGL;
		//SDL, windowed
		flags[2] = ScreenMode::WINDOWED_SDL;
		//SDL, windowed, hw surface, double buffer
		flags[3] = ScreenMode::WINDOWED_SDL_DB_HW;
		//SDL, fullscreen
		flags[4] = ScreenMode::FULLSCREEN_SDL;
		//SDL, fullscreen, hw surface, double buffer
		flags[5] = ScreenMode::FULLSCREEN_SDL_DB_HW;

#else
		const uint32_tnumFlags = 4;
		uint32_t flags[numFlags];

		//SDL, windowed
		flags[0] = ScreenMode::WINDOWED_SDL;
		//SDL, windowed, hw surface, double buffer
		flags[1] = ScreenMode::WINDOWED_SDL_DB_HW;
		//SDL, fullscreen
		flags[2] = ScreenMode::FULLSCREEN_SDL;
		//SDL, fullscreen, hw surface, double buffer
		flags[3] = ScreenMode::FULLSCREEN_SDL_DB_HW;
#endif

		//BITS PER PIXEL
		const uint32_t numBPP = 3;
		uint16_t bpps[numBPP];

		bpps[0] = 16;
		bpps[1] = 24;
		bpps[2] = 32;

		//COMMON FS RESOLUTIONS
		const uint32_t numRes = 15;
		uint16_t resolutions[numRes][2] = {
			{640, 480},
			{800, 600},
			{1024, 768},
			{1152, 864},
			{1280, 768},
			{1280, 800},
			{1280, 960},
			{1280, 1024},
			{1366, 768},
			{1440, 900},
			{1600, 900},
			{1600, 1200},
			{1680, 1050},
			{1920, 1080},
			{1920, 1200}
		};


		for (uint32_t i = 0; i < numBPP; ++i){
			for (uint32_t j = 0; j < numFlags; ++j) {
				for ( uint32_t k = 0; k < numRes; ++k) {
					uint16_t bpp;
					if (flags[j] & SDL_FULLSCREEN) {
						bpp = SDL_VideoModeOK(resolutions[k][0],resolutions[k][1], bpps[i], flags[j]);

						if (bpp > 0) {
							m_screenModes.push_back(ScreenMode(resolutions[k][0],resolutions[k][1], bpps[i], flags[j]));
						}
					}
					else {  //windowed mode
						//check an arbitrary value as we know all resolutions are supported in windowed mode.
						//we are checking to make sure the bpp is supported here.
						bpp = SDL_VideoModeOK(resolutions[k][0],resolutions[k][1], bpps[i], flags[j]);
						if (bpp > 0) {
							m_screenModes.push_back(ScreenMode(0,0, bpps[i], flags[j]));
							break; //insert windowed mode once as all resolutions are supported.
						}
					}

				}
			}
		}

		//sort the list to keep the most preferred modes at the top of the selection process
		//in getNearestScreenMode()
		std::sort(m_screenModes.begin(), m_screenModes.end());
		std::reverse(m_screenModes.begin(), m_screenModes.end());

		if(SDL_VideoDriverName(buffer, bufferSize) != NULL) {
			m_driverName = std::string(buffer);
		}
		else {
			m_driverName = "Unknown";
		}

		const SDL_VideoInfo* vInfo = SDL_GetVideoInfo();

		m_hwAvailable = vInfo->hw_available;
		m_wmAvailable = vInfo->wm_available;
		m_hwBlitAccel = vInfo->blit_hw;
		m_hwCCBlitAccel = vInfo->blit_hw_CC;
		m_hwToHwAlphaBlitAccel = vInfo->blit_hw_A;
		m_swToHwBlitAccel = vInfo->blit_sw;
		m_swToHwCCBlistAccel = vInfo->blit_sw_CC;
		m_swToHwAlphaBlitAccel = vInfo->blit_sw_A;
		m_BlitFillAccel = vInfo->blit_fill;
		m_videoMem = vInfo->video_mem;
	}

	ScreenMode DeviceCaps::getNearestScreenMode(uint16_t width, uint16_t height, uint16_t bpp, const std::string& renderer, bool fs) const {
		ScreenMode mode;
		bool foundMode = false;

		bool widthCheck = false;
		bool heightCheck = false;
		bool bppCheck = false;
		bool rendCheck = false;
		bool fsCheck = false;


		for (uint32_t i = 0; i < m_screenModes.size(); i++) {
			if (m_screenModes[i].getWidth() == width) {
				widthCheck = true;
			}
			if (m_screenModes[i].getHeight() == height) {
				heightCheck = true;
			}
			if (m_screenModes[i].getBPP() == bpp) {
				bppCheck = true;
			}
			if (m_screenModes[i].isFullScreen() == fs) {
				fsCheck = true;
			}

			if ((m_screenModes[i].isOpenGL() && renderer == "OpenGL") || (!m_screenModes[i].isOpenGL() && renderer == "SDL")){
				rendCheck = true;
			}

			//check for exact match
			if (widthCheck && heightCheck && bppCheck && fsCheck && rendCheck) {
				mode = m_screenModes[i];
				foundMode = true;
				break;
			}

			//@note When the width and height to 0 that means that all
			//resolutions are supported
			if (m_screenModes[i].getWidth() == 0 && m_screenModes[i].getHeight() == 0 && bppCheck && fsCheck && rendCheck) {
				mode = ScreenMode(width, height, bpp, m_screenModes[i].getSDLFlags());
				foundMode = true;
				break;
			}

			//current screen bpp selected
			if (widthCheck && heightCheck && bpp == 0 && fsCheck && rendCheck) {
				mode = ScreenMode(width, height, bpp, m_screenModes[i].getSDLFlags());
				foundMode = true;
				break;
			}

			if (m_screenModes[i].getWidth() == 0 && m_screenModes[i].getHeight() == 0  && bpp == 0 && fsCheck && rendCheck) {
				mode = ScreenMode(width, height, bpp, m_screenModes[i].getSDLFlags());
				foundMode = true;
				break;
			}


			widthCheck = false;
			heightCheck = false;
			bppCheck = false;
			rendCheck = false;
			fsCheck = false;
		}

		if (!foundMode) {
			throw NotSupported("Could not find a maching screen mode for the values given!");
		}

		return mode;
	}

} //FIFE