QTfrontend/util/SDLInteraction.cpp
branchhedgeroid
changeset 15515 7030706266df
parent 14872 8bba7492558d
equal deleted inserted replaced
7861:bc7b6aa5d67a 15515:7030706266df
     1 /*
     1 /*
     2  * Hedgewars, a free turn based strategy game
     2  * Hedgewars, a free turn based strategy game
     3  * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
     3  * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
     4  *
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; version 2 of the License
     7  * the Free Software Foundation; version 2 of the License
     8  *
     8  *
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    12  * GNU General Public License for more details.
    13  *
    13  *
    14  * You should have received a copy of the GNU General Public License
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program; if not, write to the Free Software
    15  * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
    16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    17  */
    17  */
    18 
    18 
    19 /**
    19 /**
    20  * @file
    20  * @file
    21  * @brief SDLInteraction class implementation
    21  * @brief SDLInteraction class implementation
    23 
    23 
    24 #include "SDL.h"
    24 #include "SDL.h"
    25 #include "SDL_mixer.h"
    25 #include "SDL_mixer.h"
    26 
    26 
    27 #include "HWApplication.h"
    27 #include "HWApplication.h"
       
    28 #include "sdlkeys.h"
       
    29 #include "hwform.h" /* you know, we could just put a config singleton lookup function in gameuiconfig or something... */
       
    30 #include "gameuiconfig.h"
    28 
    31 
    29 #include "SDLInteraction.h"
    32 #include "SDLInteraction.h"
    30 
    33 
    31 extern char sdlkeys[1024][2][128];
    34 #include "physfsrwops.h"
    32 extern char xb360buttons[][128];
       
    33 extern char xb360dpad[128];
       
    34 extern char xbox360axes[][128];
       
    35 
       
    36 
    35 
    37 SDLInteraction & SDLInteraction::instance()
    36 SDLInteraction & SDLInteraction::instance()
    38 {
    37 {
    39     static SDLInteraction instance;
    38     static SDLInteraction instance;
    40     return instance;
    39     return instance;
    48 
    47 
    49     m_audioInitialized = false;
    48     m_audioInitialized = false;
    50     m_music = NULL;
    49     m_music = NULL;
    51     m_musicTrack = "";
    50     m_musicTrack = "";
    52     m_isPlayingMusic = false;
    51     m_isPlayingMusic = false;
       
    52     lastchannel = 0;
       
    53     int i;
       
    54     // Initialize sdlkeys_iskeyboard
       
    55     for (i=0; i<1024; i++) {
       
    56         // First 7 entries are mouse buttons (see sdlkeys.cpp)
       
    57         if ((i > 6) && (sdlkeys[i][0][0] != '\0'))
       
    58             sdlkeys_iskeyboard[i] = true;
       
    59         else
       
    60             sdlkeys_iskeyboard[i] = false;
       
    61     }
       
    62 
    53     if(SDL_NumJoysticks())
    63     if(SDL_NumJoysticks())
    54         addGameControllerKeys();
    64         addGameControllerKeys();
       
    65 
       
    66     // Add special "none" key at the end of list
       
    67     i = 0;
       
    68     while(i < 1024 && sdlkeys[i][1][0] != '\0')
       
    69         i++;
       
    70     sprintf(sdlkeys[i][0], "none");
       
    71     sprintf(sdlkeys[i][1], "%s", HWApplication::translate("binds (keys)", unboundcontrol).toUtf8().constData());
       
    72 
    55     SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
    73     SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
    56 
    74 
    57     m_soundMap = new QMap<QString,Mix_Chunk*>();
    75     m_soundMap = new QMap<QString,Mix_Chunk*>();
    58 }
    76 }
    59 
    77 
    78 
    96 
    79 QStringList SDLInteraction::getResolutions() const
    97 QStringList SDLInteraction::getResolutions() const
    80 {
    98 {
    81     QStringList result;
    99     QStringList result;
    82 
   100 
    83     SDL_Rect **modes;
   101     int modesNumber = SDL_GetNumDisplayModes(0);
    84 
   102     SDL_DisplayMode mode;
    85     modes = SDL_ListModes(NULL, SDL_FULLSCREEN);
   103 
    86 
   104     for(int i = 0; i < modesNumber; ++i)
    87     if((modes == (SDL_Rect **)0) || (modes == (SDL_Rect **)-1))
   105     {
    88     {
   106         SDL_GetDisplayMode(0, i, &mode);
    89         result << "640x480";
   107 
    90     }
   108         if ((mode.w >= 640) && (mode.h >= 480))
    91     else
   109             result << QString("%1x%2").arg(mode.w).arg(mode.h);
    92     {
       
    93         for(int i = 0; modes[i]; ++i)
       
    94             if ((modes[i]->w >= 640) && (modes[i]->h >= 480))
       
    95                 result << QString("%1x%2").arg(modes[i]->w).arg(modes[i]->h);
       
    96     }
   110     }
    97 
   111 
    98     return result;
   112     return result;
    99 }
   113 }
   100 
   114 
   101 
   115 
   102 void SDLInteraction::addGameControllerKeys() const
   116 void SDLInteraction::addGameControllerKeys() const
   103 {
   117 {
   104     QStringList result;
   118     QStringList result;
   105 
   119 
       
   120 #if SDL_VERSION_ATLEAST(2, 0, 0)
   106     int i = 0;
   121     int i = 0;
   107     while(i < 1024 && sdlkeys[i][1][0] != '\0')
   122     while(i < 1024 && sdlkeys[i][1][0] != '\0')
   108         i++;
   123         i++;
   109 
   124 
   110     // Iterate through all game controllers
   125     // Iterate through all game controllers
       
   126     qDebug("Detecting controllers ...");
   111     for(int jid = 0; jid < SDL_NumJoysticks(); jid++)
   127     for(int jid = 0; jid < SDL_NumJoysticks(); jid++)
   112     {
   128     {
   113         SDL_Joystick* joy = SDL_JoystickOpen(jid);
   129         SDL_Joystick* joy = SDL_JoystickOpen(jid);
   114 
   130 
   115         // Retrieve the game controller's name and strip "Controller (...)" that's added by some drivers (English only)
   131         // Retrieve the game controller's name
   116         QString joyname = QString(SDL_JoystickName(jid)).replace(QRegExp("^Controller \\((.*)\\)$"), "\\1");
   132         QString joyname = QString(SDL_JoystickNameForIndex(jid));
       
   133 
       
   134         // Strip "Controller (...)" that's added by some drivers (English only)
       
   135         joyname.replace(QRegExp("^Controller \\((.*)\\)$"), "\\1");
       
   136 
       
   137         qDebug("- Controller no. %d: %s", jid, qPrintable(joyname));
   117 
   138 
   118         // Connected Xbox 360 controller? Use specific button names then
   139         // Connected Xbox 360 controller? Use specific button names then
   119         // Might be interesting to add 'named' buttons for the most often used gamepads
   140         // Might be interesting to add 'named' buttons for the most often used gamepads
   120         bool isxb = joyname.contains("Xbox 360");
   141         bool isxb = joyname.contains("Xbox 360");
   121 
   142 
   123         QString prefix = QString("%1 (%2): ").arg(joyname).arg(jid + 1);
   144         QString prefix = QString("%1 (%2): ").arg(joyname).arg(jid + 1);
   124 
   145 
   125         // Register entries for missing axes not assigned to sticks of this joystick/gamepad
   146         // Register entries for missing axes not assigned to sticks of this joystick/gamepad
   126         for(int aid = 0; aid < SDL_JoystickNumAxes(joy) && i < 1021; aid++)
   147         for(int aid = 0; aid < SDL_JoystickNumAxes(joy) && i < 1021; aid++)
   127         {
   148         {
   128             // Again store the part of the string not changing for multiple uses
   149             QString axis = prefix + HWApplication::translate("binds (keys)", controlleraxis).arg(aid + 1);
   129             QString axis = prefix + HWApplication::translate("binds (keys)", "Axis") + QString(" %1 ").arg(aid + 1);
       
   130 
   150 
   131             // Entry for "Axis Up"
   151             // Entry for "Axis Up"
   132             sprintf(sdlkeys[i][0], "j%da%du", jid, aid);
   152             sprintf(sdlkeys[i][0], "j%da%du", jid, aid);
   133             sprintf(sdlkeys[i++][1], "%s", ((isxb && aid < 5) ? (prefix + HWApplication::translate("binds (keys)", xbox360axes[aid * 2])) : axis + HWApplication::translate("binds (keys)", "(Up)")).toUtf8().constData());
   153             sprintf(sdlkeys[i++][1], "%s", ((isxb && aid < 5) ? (prefix + HWApplication::translate("binds (keys)", xbox360axes[aid * 2])) : (axis.arg(HWApplication::translate("binds (keys)", controllerup)))).toUtf8().constData());
   134 
   154 
   135             // Entry for "Axis Down"
   155             // Entry for "Axis Down"
   136             sprintf(sdlkeys[i][0], "j%da%dd", jid, aid);
   156             sprintf(sdlkeys[i][0], "j%da%dd", jid, aid);
   137             sprintf(sdlkeys[i++][1], "%s", ((isxb && aid < 5) ? (prefix + HWApplication::translate("binds (keys)", xbox360axes[aid * 2 + 1])) : axis + HWApplication::translate("binds (keys)", "(Down)")).toUtf8().constData());
   157             sprintf(sdlkeys[i++][1], "%s", ((isxb && aid < 5) ? (prefix + HWApplication::translate("binds (keys)", xbox360axes[aid * 2 + 1])) : (axis.arg(HWApplication::translate("binds (keys)", controllerdown)))).toUtf8().constData());
   138         }
   158         }
   139 
   159 
   140         // Register entries for all coolie hats of this joystick/gamepad
   160         // Register entries for all coolie hats of this joystick/gamepad
   141         for(int hid = 0; hid < SDL_JoystickNumHats(joy) && i < 1019; hid++)
   161         for(int hid = 0; hid < SDL_JoystickNumHats(joy) && i < 1019; hid++)
   142         {
   162         {
   143             // Again store the part of the string not changing for multiple uses
   163             // Again store the part of the string not changing for multiple uses
   144             QString hat = prefix + (isxb ? (HWApplication::translate("binds (keys)", xb360dpad) + QString(" ")) : HWApplication::translate("binds (keys)", "Hat") + QString(" %1 ").arg(hid + 1));
   164             QString hat = prefix + (isxb ? (HWApplication::translate("binds (keys)", xb360dpad) + QString(" ")) : HWApplication::translate("binds (keys)", controllerhat).arg(hid + 1));
   145 
   165 
   146             // Entry for "Hat Up"
   166             // Entry for "Hat Up"
   147             sprintf(sdlkeys[i][0], "j%dh%du", jid, hid);
   167             sprintf(sdlkeys[i][0], "j%dh%du", jid, hid);
   148             sprintf(sdlkeys[i++][1], "%s", (hat + HWApplication::translate("binds (keys)", "(Up)")).toUtf8().constData());
   168             sprintf(sdlkeys[i++][1], "%s", hat.arg(HWApplication::translate("binds (keys)", controllerup)).toUtf8().constData());
   149 
   169 
   150             // Entry for "Hat Down"
   170             // Entry for "Hat Down"
   151             sprintf(sdlkeys[i][0], "j%dh%dd", jid, hid);
   171             sprintf(sdlkeys[i][0], "j%dh%dd", jid, hid);
   152             sprintf(sdlkeys[i++][1], "%s", (hat + HWApplication::translate("binds (keys)", "(Down)")).toUtf8().constData());
   172             sprintf(sdlkeys[i++][1], "%s", hat.arg(HWApplication::translate("binds (keys)", controllerdown)).toUtf8().constData());
   153 
   173 
   154             // Entry for "Hat Left"
   174             // Entry for "Hat Left"
   155             sprintf(sdlkeys[i][0], "j%dh%dl", jid, hid);
   175             sprintf(sdlkeys[i][0], "j%dh%dl", jid, hid);
   156             sprintf(sdlkeys[i++][1], "%s", (hat + HWApplication::translate("binds (keys)", "(Left)")).toUtf8().constData());
   176             sprintf(sdlkeys[i++][1], "%s", hat.arg(HWApplication::translate("binds (keys)", controllerleft)).toUtf8().constData());
   157 
   177 
   158             // Entry for "Hat Right"
   178             // Entry for "Hat Right"
   159             sprintf(sdlkeys[i][0], "j%dh%dr", jid, hid);
   179             sprintf(sdlkeys[i][0], "j%dh%dr", jid, hid);
   160             sprintf(sdlkeys[i++][1], "%s", (hat + HWApplication::translate("binds (keys)", "(Right)")).toUtf8().constData());
   180             sprintf(sdlkeys[i++][1], "%s", hat.arg(HWApplication::translate("binds (keys)", controllerright)).toUtf8().constData());
   161         }
   181         }
   162 
   182 
   163         // Register entries for all buttons of this joystick/gamepad
   183         // Register entries for all buttons of this joystick/gamepad
   164         for(int bid = 0; bid < SDL_JoystickNumButtons(joy) && i < 1022; bid++)
   184         for(int bid = 0; bid < SDL_JoystickNumButtons(joy) && i < 1022; bid++)
   165         {
   185         {
   166             // Buttons
   186             // Buttons
   167             sprintf(sdlkeys[i][0], "j%db%d", jid, bid);
   187             sprintf(sdlkeys[i][0], "j%db%d", jid, bid);
   168             sprintf(sdlkeys[i++][1], "%s", (prefix + ((isxb && bid < 10) ? (HWApplication::translate("binds (keys)", xb360buttons[bid]) + QString(" ")) : HWApplication::translate("binds (keys)", "Button") + QString(" %1").arg(bid + 1))).toUtf8().constData());
   188             sprintf(sdlkeys[i++][1], "%s", (prefix + ((isxb && bid < 10) ? (HWApplication::translate("binds (keys)", xb360buttons[bid]) + QString(" ")) : HWApplication::translate("binds (keys)", controllerbutton).arg(bid + 1))).toUtf8().constData());
   169         }
   189         }
   170         // Close the game controller as we no longer need it
   190         // Close the game controller as we no longer need it
   171         SDL_JoystickClose(joy);
   191         SDL_JoystickClose(joy);
   172     }
   192     }
   173 
   193 
       
   194     if(i >= 1024)
       
   195         i = 1023;
       
   196 
   174     // Terminate the list
   197     // Terminate the list
   175     sdlkeys[i][0][0] = '\0';
   198     sdlkeys[i][0][0] = '\0';
   176     sdlkeys[i][1][0] = '\0';
   199     sdlkeys[i][1][0] = '\0';   
       
   200 #endif
   177 }
   201 }
   178 
   202 
   179 
   203 
   180 void SDLInteraction::SDLAudioInit()
   204 void SDLInteraction::SDLAudioInit()
   181 {
   205 {
   182     // don't init again
   206     // don't init again
   183     if (m_audioInitialized)
   207     if (m_audioInitialized)
   184         return;
   208         return;
   185 
   209 
   186     SDL_Init(SDL_INIT_AUDIO);
   210     SDL_Init(SDL_INIT_AUDIO);
   187     Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024);
   211     if(!Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024)) /* should we keep trying, or just turn off permanently? */
   188     m_audioInitialized = true;
   212         m_audioInitialized = true;
   189 }
   213 }
   190 
   214 
   191 
   215 
   192 void SDLInteraction::playSoundFile(const QString & soundFile)
   216 void SDLInteraction::playSoundFile(const QString & soundFile)
   193 {
   217 {
       
   218     if (!HWForm::config || !HWForm::config->isFrontendSoundEnabled()) return;
   194     SDLAudioInit();
   219     SDLAudioInit();
       
   220     if (!m_audioInitialized) return;
   195     if (!m_soundMap->contains(soundFile))
   221     if (!m_soundMap->contains(soundFile))
   196         m_soundMap->insert(soundFile, Mix_LoadWAV(soundFile.toLocal8Bit().constData()));
   222         m_soundMap->insert(soundFile, Mix_LoadWAV_RW(PHYSFSRWOPS_openRead(soundFile.toLocal8Bit().constData()), 1));
   197 
   223 
   198     //FIXME: this is a hack, but works as long as we have few concurrent playing sounds
   224     //FIXME: this is a hack, but works as long as we have few concurrent playing sounds
   199     if (Mix_Playing(lastchannel) == false)
   225     if (Mix_Playing(lastchannel) == false)
   200         lastchannel = Mix_PlayChannel(-1, m_soundMap->value(soundFile), 0);
   226         lastchannel = Mix_PlayChannel(-1, m_soundMap->value(soundFile), 0);
   201 }
   227 }
   228 
   254 
   229     if (m_musicTrack.isEmpty())
   255     if (m_musicTrack.isEmpty())
   230         return;
   256         return;
   231 
   257 
   232     SDLAudioInit();
   258     SDLAudioInit();
       
   259     if (!m_audioInitialized) return;
   233 
   260 
   234     if (m_music == NULL)
   261     if (m_music == NULL)
   235         m_music = Mix_LoadMUS(m_musicTrack.toLocal8Bit().constData());
   262         m_music = Mix_LoadMUS_RW(PHYSFSRWOPS_openRead(m_musicTrack.toLocal8Bit().constData()), 0);
   236 
   263 
   237     Mix_VolumeMusic(MIX_MAX_VOLUME - 28);
   264     Mix_VolumeMusic(MIX_MAX_VOLUME/4);
   238     Mix_FadeInMusic(m_music, -1, 1750);
   265     Mix_FadeInMusic(m_music, -1, 1750);
   239 }
   266 }
   240 
   267 
   241 
   268 
   242 void SDLInteraction::stopMusic()
   269 void SDLInteraction::stopMusic()
   251     }
   278     }
   252 
   279 
   253     m_isPlayingMusic = false;
   280     m_isPlayingMusic = false;
   254 }
   281 }
   255 
   282 
       
   283 
       
   284 QSize SDLInteraction::getCurrentResolution()
       
   285 {
       
   286     SDL_DisplayMode mode;
       
   287 
       
   288     SDL_GetDesktopDisplayMode(0, &mode);
       
   289 
       
   290     return QSize(mode.w, mode.h);
       
   291 }