devicecaps.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005-2011 by the FIFE team                              *
00003  *   http://www.fifengine.net                                               *
00004  *   This file is part of FIFE.                                            *
00005  *                                                                         *
00006  *   FIFE is free software; you can redistribute it and/or                 *
00007  *   modify it under the terms of the GNU Lesser General Public            *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2.1 of the License, or (at your option) any later version.    *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the                 *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
00020  ***************************************************************************/
00021 
00022 // Standard C++ library includes
00023 #include <iostream>
00024 #include <algorithm>
00025 
00026 // 3rd party library includes
00027 #include <SDL.h>
00028 #include <SDL_video.h>
00029 
00030 // FIFE includes
00031 // These includes are split up in two parts, separated by one empty line
00032 // First block: files included from the FIFE root src directory
00033 // Second block: files included from the same folder
00034 #include "util/base/exception.h"
00035 
00036 #include "devicecaps.h"
00037 
00038 namespace FIFE {
00039 
00040     ScreenMode::ScreenMode() :
00041                    m_width(0), m_height(0), m_bpp(0), m_SDLFlags(0){
00042     }
00043 
00044     ScreenMode::ScreenMode(uint16_t width, uint16_t height, uint16_t bpp, uint32_t SDLFlags) :
00045                    m_width(width), m_height(height), m_bpp(bpp), m_SDLFlags(SDLFlags){
00046     }
00047 
00048     ScreenMode::ScreenMode(const ScreenMode& rhs){
00049         m_width = rhs.getWidth();
00050         m_height = rhs.getHeight();
00051         m_bpp = rhs.getBPP();
00052         m_SDLFlags = rhs.getSDLFlags();
00053     }
00054 
00055     bool ScreenMode::operator <(const ScreenMode& rhs) const {
00056 
00057         //sort by fullscreen first
00058         if (!isFullScreen() && rhs.isFullScreen()){
00059             return true;
00060         }
00061         else if (isFullScreen() && !rhs.isFullScreen()){
00062             return false;
00063         }
00064 
00065         //next by bpp
00066         if (m_bpp < rhs.getBPP()){
00067             return true;
00068         }
00069         else if (m_bpp > rhs.getBPP()){
00070             return false;
00071         }
00072 
00073         //then by screen dimentions
00074         if (m_width == rhs.getWidth() && m_height == rhs.getHeight()){
00075             if (!(m_SDLFlags & SDL_HWSURFACE) && (rhs.getSDLFlags() & SDL_HWSURFACE)) {
00076                 //I would like return true so that we prefer hardware surfaces but
00077                 //it really slows the engine down in fullscreen.  See the SDL FAQ for an
00078                 //explanation.
00079                 return false;
00080             }
00081         }
00082 
00083         else if (m_width < rhs.getWidth() || m_height < rhs.getHeight()) {
00084             return true;
00085         }
00086 
00087         return false;
00088     }
00089 
00090     DeviceCaps::DeviceCaps() :
00091         m_driverName("Invalid"),
00092         m_hwAvailable(false),
00093         m_wmAvailable(false),
00094         m_hwBlitAccel(false),
00095         m_hwCCBlitAccel(false),
00096         m_hwToHwAlphaBlitAccel(false),
00097         m_swToHwBlitAccel(false),
00098         m_swToHwCCBlistAccel(false),
00099         m_swToHwAlphaBlitAccel(false),
00100         m_BlitFillAccel(false),
00101         m_videoMem(0) {
00102 
00103         fillAvailableDrivers();
00104     }
00105 
00106 
00107     DeviceCaps::~DeviceCaps() {
00108     }
00109 
00110     void DeviceCaps::reset() {
00111         m_screenModes.clear();
00112         m_driverName = "Invalid";
00113         m_hwAvailable = false;
00114         m_wmAvailable = false;
00115         m_hwBlitAccel = false;
00116         m_hwCCBlitAccel = false;
00117         m_hwToHwAlphaBlitAccel = false;
00118         m_swToHwBlitAccel = false;
00119         m_swToHwCCBlistAccel = false;
00120         m_swToHwAlphaBlitAccel = false;
00121         m_BlitFillAccel = false;
00122         m_videoMem = 0;
00123     }
00124 
00125 
00126     void DeviceCaps::fillAvailableDrivers() {
00127         m_availableDrivers.clear();
00128 #if defined( __unix__ )
00129         m_availableDrivers.push_back("x11");
00130         m_availableDrivers.push_back("nanox");
00131         m_availableDrivers.push_back("qtopia");
00132         m_availableDrivers.push_back("fbcon");
00133         m_availableDrivers.push_back("directfb");
00134         m_availableDrivers.push_back("svgalib");
00135 #endif
00136 
00137 // Win32
00138 #if defined( WIN32 )
00139         m_availableDrivers.push_back("directx");
00140         m_availableDrivers.push_back("windib");
00141 #endif
00142 
00143 // Macintosh
00144 #if defined( __APPLE_CC__ )
00145         m_availableDrivers.push_back("Quartz");
00146         m_availableDrivers.push_back("x11");
00147 #endif
00148     }
00149 
00150     void DeviceCaps::fillDeviceCaps() {
00151         //buffer to store driver name
00152         const uint32_t bufferSize = 256;
00153         char buffer[bufferSize];
00154 
00155         //clear in case this is called twice
00156         reset();
00157 
00158         //FLAGS
00159 #ifdef HAVE_OPENGL
00160         const uint32_t numFlags = 6;
00161         uint32_t flags[numFlags];
00162 
00163         //OpenGL, windowed, hw accel
00164         flags[0] = ScreenMode::HW_WINDOWED_OPENGL;
00165         //OpenGL, fullscree, hw accel
00166         flags[1] = ScreenMode::HW_FULLSCREEN_OPENGL;
00167         //SDL, windowed
00168         flags[2] = ScreenMode::WINDOWED_SDL;
00169         //SDL, windowed, hw surface, double buffer
00170         flags[3] = ScreenMode::WINDOWED_SDL_DB_HW;
00171         //SDL, fullscreen
00172         flags[4] = ScreenMode::FULLSCREEN_SDL;
00173         //SDL, fullscreen, hw surface, double buffer
00174         flags[5] = ScreenMode::FULLSCREEN_SDL_DB_HW;
00175 
00176 #else
00177         const uint32_t numFlags = 4;
00178         uint32_t flags[numFlags];
00179 
00180         //SDL, windowed
00181         flags[0] = ScreenMode::WINDOWED_SDL;
00182         //SDL, windowed, hw surface, double buffer
00183         flags[1] = ScreenMode::WINDOWED_SDL_DB_HW;
00184         //SDL, fullscreen
00185         flags[2] = ScreenMode::FULLSCREEN_SDL;
00186         //SDL, fullscreen, hw surface, double buffer
00187         flags[3] = ScreenMode::FULLSCREEN_SDL_DB_HW;
00188 #endif
00189 
00190         //BITS PER PIXEL
00191         const uint32_t numBPP = 3;
00192         uint16_t bpps[numBPP];
00193 
00194         bpps[0] = 16;
00195         bpps[1] = 24;
00196         bpps[2] = 32;
00197 
00198         //COMMON FS RESOLUTIONS
00199         const uint32_t numRes = 16;
00200         uint16_t resolutions[numRes][2] = {
00201             {640, 480},
00202             {800, 600},
00203             {1024, 600},
00204             {1024, 768},
00205             {1152, 864},
00206             {1280, 768},
00207             {1280, 800},
00208             {1280, 960},
00209             {1280, 1024},
00210             {1366, 768},
00211             {1440, 900},
00212             {1600, 900},
00213             {1600, 1200},
00214             {1680, 1050},
00215             {1920, 1080},
00216             {1920, 1200}
00217         };
00218 
00219 
00220         for (uint32_t i = 0; i < numBPP; ++i){
00221             for (uint32_t j = 0; j < numFlags; ++j) {
00222                 for ( uint32_t k = 0; k < numRes; ++k) {
00223                     uint16_t bpp;
00224                     if (flags[j] & SDL_FULLSCREEN) {
00225                         bpp = SDL_VideoModeOK(resolutions[k][0],resolutions[k][1], bpps[i], flags[j]);
00226 
00227                         if (bpp > 0) {
00228                             m_screenModes.push_back(ScreenMode(resolutions[k][0],resolutions[k][1], bpps[i], flags[j]));
00229                         }
00230                     }
00231                     else {  //windowed mode
00232                         //check an arbitrary value as we know all resolutions are supported in windowed mode.
00233                         //we are checking to make sure the bpp is supported here.
00234                         bpp = SDL_VideoModeOK(resolutions[k][0],resolutions[k][1], bpps[i], flags[j]);
00235                         if (bpp > 0) {
00236                             m_screenModes.push_back(ScreenMode(0,0, bpps[i], flags[j]));
00237                             break; //insert windowed mode once as all resolutions are supported.
00238                         }
00239                     }
00240 
00241                 }
00242             }
00243         }
00244 
00245         //sort the list to keep the most preferred modes at the top of the selection process
00246         //in getNearestScreenMode()
00247         std::sort(m_screenModes.begin(), m_screenModes.end());
00248         std::reverse(m_screenModes.begin(), m_screenModes.end());
00249 
00250         if(SDL_VideoDriverName(buffer, bufferSize) != NULL) {
00251             m_driverName = std::string(buffer);
00252         }
00253         else {
00254             m_driverName = "Unknown";
00255         }
00256 
00257         const SDL_VideoInfo* vInfo = SDL_GetVideoInfo();
00258 
00259         m_hwAvailable = vInfo->hw_available;
00260         m_wmAvailable = vInfo->wm_available;
00261         m_hwBlitAccel = vInfo->blit_hw;
00262         m_hwCCBlitAccel = vInfo->blit_hw_CC;
00263         m_hwToHwAlphaBlitAccel = vInfo->blit_hw_A;
00264         m_swToHwBlitAccel = vInfo->blit_sw;
00265         m_swToHwCCBlistAccel = vInfo->blit_sw_CC;
00266         m_swToHwAlphaBlitAccel = vInfo->blit_sw_A;
00267         m_BlitFillAccel = vInfo->blit_fill;
00268         m_videoMem = vInfo->video_mem;
00269     }
00270 
00271     ScreenMode DeviceCaps::getNearestScreenMode(uint16_t width, uint16_t height, uint16_t bpp, const std::string& renderer, bool fs) const {
00272         ScreenMode mode;
00273         bool foundMode = false;
00274 
00275         bool widthCheck = false;
00276         bool heightCheck = false;
00277         bool bppCheck = false;
00278         bool rendCheck = false;
00279         bool fsCheck = false;
00280 
00281 
00282         for (uint32_t i = 0; i < m_screenModes.size(); i++) {
00283             if (m_screenModes[i].getWidth() == width) {
00284                 widthCheck = true;
00285             }
00286             if (m_screenModes[i].getHeight() == height) {
00287                 heightCheck = true;
00288             }
00289             if (m_screenModes[i].getBPP() == bpp) {
00290                 bppCheck = true;
00291             }
00292             if (m_screenModes[i].isFullScreen() == fs) {
00293                 fsCheck = true;
00294             }
00295 
00296             if ((m_screenModes[i].isOpenGL() && (renderer == "OpenGL" || renderer == "OpenGLe")) || (!m_screenModes[i].isOpenGL() && renderer == "SDL")){
00297                 rendCheck = true;
00298             }
00299 
00300             //check for exact match
00301             if (widthCheck && heightCheck && bppCheck && fsCheck && rendCheck) {
00302                 mode = m_screenModes[i];
00303                 foundMode = true;
00304                 break;
00305             }
00306 
00307             //@note When the width and height to 0 that means that all
00308             //resolutions are supported
00309             if (m_screenModes[i].getWidth() == 0 && m_screenModes[i].getHeight() == 0 && bppCheck && fsCheck && rendCheck) {
00310                 mode = ScreenMode(width, height, bpp, m_screenModes[i].getSDLFlags());
00311                 foundMode = true;
00312                 break;
00313             }
00314 
00315             //current screen bpp selected
00316             if (widthCheck && heightCheck && bpp == 0 && fsCheck && rendCheck) {
00317                 mode = ScreenMode(width, height, bpp, m_screenModes[i].getSDLFlags());
00318                 foundMode = true;
00319                 break;
00320             }
00321 
00322             if (m_screenModes[i].getWidth() == 0 && m_screenModes[i].getHeight() == 0  && bpp == 0 && fsCheck && rendCheck) {
00323                 mode = ScreenMode(width, height, bpp, m_screenModes[i].getSDLFlags());
00324                 foundMode = true;
00325                 break;
00326             }
00327 
00328 
00329             widthCheck = false;
00330             heightCheck = false;
00331             bppCheck = false;
00332             rendCheck = false;
00333             fsCheck = false;
00334         }
00335 
00336         if (!foundMode) {
00337             throw NotSupported("Could not find a maching screen mode for the values given!");
00338         }
00339 
00340         return mode;
00341     }
00342 
00343 } //FIFE