FIFE  2008.0
devicecaps.cpp
00001 /***************************************************************************
00002  *   Copyright (C) 2005-2010 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_tnumFlags = 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 = 15;
00200         uint16_t resolutions[numRes][2] = {
00201             {640, 480},
00202             {800, 600},
00203             {1024, 768},
00204             {1152, 864},
00205             {1280, 768},
00206             {1280, 800},
00207             {1280, 960},
00208             {1280, 1024},
00209             {1366, 768},
00210             {1440, 900},
00211             {1600, 900},
00212             {1600, 1200},
00213             {1680, 1050},
00214             {1920, 1080},
00215             {1920, 1200}
00216         };
00217 
00218 
00219         for (uint32_t i = 0; i < numBPP; ++i){
00220             for (uint32_t j = 0; j < numFlags; ++j) {
00221                 for ( uint32_t k = 0; k < numRes; ++k) {
00222                     uint16_t bpp;
00223                     if (flags[j] & SDL_FULLSCREEN) {
00224                         bpp = SDL_VideoModeOK(resolutions[k][0],resolutions[k][1], bpps[i], flags[j]);
00225 
00226                         if (bpp > 0) {
00227                             m_screenModes.push_back(ScreenMode(resolutions[k][0],resolutions[k][1], bpps[i], flags[j]));
00228                         }
00229                     }
00230                     else {  //windowed mode
00231                         //check an arbitrary value as we know all resolutions are supported in windowed mode.
00232                         //we are checking to make sure the bpp is supported here.
00233                         bpp = SDL_VideoModeOK(resolutions[k][0],resolutions[k][1], bpps[i], flags[j]);
00234                         if (bpp > 0) {
00235                             m_screenModes.push_back(ScreenMode(0,0, bpps[i], flags[j]));
00236                             break; //insert windowed mode once as all resolutions are supported.
00237                         }
00238                     }
00239 
00240                 }
00241             }
00242         }
00243 
00244         //sort the list to keep the most preferred modes at the top of the selection process
00245         //in getNearestScreenMode()
00246         std::sort(m_screenModes.begin(), m_screenModes.end());
00247         std::reverse(m_screenModes.begin(), m_screenModes.end());
00248 
00249         if(SDL_VideoDriverName(buffer, bufferSize) != NULL) {
00250             m_driverName = std::string(buffer);
00251         }
00252         else {
00253             m_driverName = "Unknown";
00254         }
00255 
00256         const SDL_VideoInfo* vInfo = SDL_GetVideoInfo();
00257 
00258         m_hwAvailable = vInfo->hw_available;
00259         m_wmAvailable = vInfo->wm_available;
00260         m_hwBlitAccel = vInfo->blit_hw;
00261         m_hwCCBlitAccel = vInfo->blit_hw_CC;
00262         m_hwToHwAlphaBlitAccel = vInfo->blit_hw_A;
00263         m_swToHwBlitAccel = vInfo->blit_sw;
00264         m_swToHwCCBlistAccel = vInfo->blit_sw_CC;
00265         m_swToHwAlphaBlitAccel = vInfo->blit_sw_A;
00266         m_BlitFillAccel = vInfo->blit_fill;
00267         m_videoMem = vInfo->video_mem;
00268     }
00269 
00270     ScreenMode DeviceCaps::getNearestScreenMode(uint16_t width, uint16_t height, uint16_t bpp, const std::string& renderer, bool fs) const {
00271         ScreenMode mode;
00272         bool foundMode = false;
00273 
00274         bool widthCheck = false;
00275         bool heightCheck = false;
00276         bool bppCheck = false;
00277         bool rendCheck = false;
00278         bool fsCheck = false;
00279 
00280 
00281         for (uint32_t i = 0; i < m_screenModes.size(); i++) {
00282             if (m_screenModes[i].getWidth() == width) {
00283                 widthCheck = true;
00284             }
00285             if (m_screenModes[i].getHeight() == height) {
00286                 heightCheck = true;
00287             }
00288             if (m_screenModes[i].getBPP() == bpp) {
00289                 bppCheck = true;
00290             }
00291             if (m_screenModes[i].isFullScreen() == fs) {
00292                 fsCheck = true;
00293             }
00294 
00295             if ((m_screenModes[i].isOpenGL() && renderer == "OpenGL") || (!m_screenModes[i].isOpenGL() && renderer == "SDL")){
00296                 rendCheck = true;
00297             }
00298 
00299             //check for exact match
00300             if (widthCheck && heightCheck && bppCheck && fsCheck && rendCheck) {
00301                 mode = m_screenModes[i];
00302                 foundMode = true;
00303                 break;
00304             }
00305 
00306             //@note When the width and height to 0 that means that all
00307             //resolutions are supported
00308             if (m_screenModes[i].getWidth() == 0 && m_screenModes[i].getHeight() == 0 && bppCheck && fsCheck && rendCheck) {
00309                 mode = ScreenMode(width, height, bpp, m_screenModes[i].getSDLFlags());
00310                 foundMode = true;
00311                 break;
00312             }
00313 
00314             //current screen bpp selected
00315             if (widthCheck && heightCheck && bpp == 0 && fsCheck && rendCheck) {
00316                 mode = ScreenMode(width, height, bpp, m_screenModes[i].getSDLFlags());
00317                 foundMode = true;
00318                 break;
00319             }
00320 
00321             if (m_screenModes[i].getWidth() == 0 && m_screenModes[i].getHeight() == 0  && bpp == 0 && fsCheck && rendCheck) {
00322                 mode = ScreenMode(width, height, bpp, m_screenModes[i].getSDLFlags());
00323                 foundMode = true;
00324                 break;
00325             }
00326 
00327 
00328             widthCheck = false;
00329             heightCheck = false;
00330             bppCheck = false;
00331             rendCheck = false;
00332             fsCheck = false;
00333         }
00334 
00335         if (!foundMode) {
00336             throw NotSupported("Could not find a maching screen mode for the values given!");
00337         }
00338 
00339         return mode;
00340     }
00341 
00342 } //FIFE