Back to index

supertuxkart  0.5+dfsg1
race_gui.cpp
Go to the documentation of this file.
00001 //  $Id: race_gui.cpp 2111 2008-05-31 07:04:30Z cosmosninja $
00002 //
00003 //  SuperTuxKart - a fun racing game with go-kart
00004 //  Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
00005 //  Copyright (C) 2006 Joerg Henrichs, SuperTuxKart-Team, Steve Baker
00006 //
00007 //  This program is free software; you can redistribute it and/or
00008 //  modify it under the terms of the GNU General Public License
00009 //  as published by the Free Software Foundation; either version 2
00010 //  of the License, or (at your option) any later version.
00011 //
00012 //  This program is distributed in the hope that it will be useful,
00013 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //  GNU General Public License for more details.
00016 //
00017 //  You should have received a copy of the GNU General Public License
00018 //  along with this program; if not, write to the Free Software
00019 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00020 
00021 #include "race_gui.hpp"
00022 
00023 #include "input.hpp"
00024 #include "sdldrv.hpp"
00025 
00026 #include "user_config.hpp"
00027 #include "history.hpp"
00028 #include "track.hpp"
00029 #include "material_manager.hpp"
00030 #include "menu_manager.hpp"
00031 #include "sound_manager.hpp"
00032 #include "race_manager.hpp"
00033 
00034 #undef USE_WIDGET_MANAGER
00035 #ifdef USE_WIDGET_MANAGER
00036 #include "widget_manager.hpp"
00037 #endif
00038 
00039 #include "translation.hpp"
00040 #include "font.hpp"
00041 
00042 #ifdef USE_WIDGET_MANAGER
00043 //MAX_TOP_POS is the maximum number of racers to be shown in the bar to the
00044 //left where the positions are drawn.
00045 static const int MAX_TOP_POS = 10;
00046 
00047 static const int MAX_HUMANS = 4;
00048 
00049 enum WidgetTokens
00050 {
00051     WTOK_FPS,
00052     WTOK_EMPTY1,
00053     WTOK_CLOCK,
00054 
00055     WTOK_EMPTY2,
00056 
00057     WTOK_FIRST_TOP_IMG,
00058     WTOK_LAST_TOP_IMG = WTOK_FIRST_TOP_IMG + MAX_TOP_POS,
00059 
00060     WTOK_FIRST_TOP_TEXT,
00061     WTOK_LAST_TOP_TEXT = WTOK_FIRST_TOP_TEXT + MAX_TOP_POS,
00062 
00063     WTOK_FIRST_MESSAGE,
00064     WTOK_LAST_MESSAGE = WTOK_FIRST_MESSAGE + MAX_HUMANS,
00065 
00066     WTOK_FIRST_POWERBAR,
00067     WTOK_LAST_POWERBAR = WTOK_FIRST_POWERBAR + MAX_HUMANS,
00068 
00069     WTOK_FIRST_POSITION,
00070     WTOK_LAST_POSITION = WTOK_FIRST_POSITION + MAX_HUMANS,
00071 
00072     WTOK_MAP,
00073 
00074     WTOK_FIRST_LAP,
00075     WTOK_LAST_LAP = WTOK_FIRST_LAP + MAX_HUMANS,
00076 
00077     WTOK_FIRST_WHEEL,
00078     WTOK_LAST_WHEEL = WTOK_FIRST_WHEEL + MAX_HUMANS,
00079 
00080     WTOK_FIRST_SPEED,
00081     WTOK_LAST_SPEED = WTOK_FIRST_SPEED + MAX_HUMANS
00082 };
00083 #endif
00084 
00085 RaceGUI::RaceGUI()
00086 {
00087     // FIXME: translation problem
00088     m_pos_string[0] = "?!?";
00089     m_pos_string[1] = "1st";
00090     m_pos_string[2] = "2nd";
00091     m_pos_string[3] = "3rd";
00092     m_pos_string[4] = "4th";
00093     m_pos_string[5] = "5th";
00094     m_pos_string[6] = "6th";
00095     m_pos_string[7] = "7th";
00096     m_pos_string[8] = "8th";
00097     m_pos_string[9] = "9th";
00098     m_pos_string[10] = "10th";
00099 
00100     //FIXME: Temporary, we need a better icon here
00101     m_steering_wheel_icon = material_manager->getMaterial("wheel.rgb");
00102     m_steering_wheel_icon->getState()->disable(GL_CULL_FACE);
00103     m_speed_back_icon = material_manager->getMaterial("speedback.rgb");
00104     m_speed_back_icon->getState()->disable(GL_CULL_FACE);
00105     m_speed_fore_icon = material_manager->getMaterial("speedfore.rgb");
00106     m_speed_fore_icon->getState()->disable(GL_CULL_FACE);
00107 
00108     m_fps_counter = 0;
00109     m_fps_string[0]=0;
00110     m_fps_timer.reset();
00111     m_fps_timer.update();
00112     m_fps_timer.setMaxDelta(1000);
00113 
00114 #ifdef USE_WIDGET_MANAGER
00115     const bool HIDE_TEXT = false;
00116     widget_manager->setInitialTextState(HIDE_TEXT, "", WGT_FNT_LRG,
00117         WGT_FONT_RACE, WGT_WHITE );
00118 
00119     widget_manager->addWgt( WTOK_FPS, 30, 10 );
00120     widget_manager->addWgt( WTOK_EMPTY1, 40, 10 );
00121     widget_manager->addWgt( WTOK_CLOCK, 30, 10 );
00122     widget_manager->breakLine();
00123 
00124     widget_manager->layout( WGT_AREA_TOP );
00125 #endif
00126 }   // RaceGUI
00127 
00128 //-----------------------------------------------------------------------------
00129 RaceGUI::~RaceGUI()
00130 {
00131 #ifdef USE_WIDGET_MANAGER
00132     widget_manager->reset();
00133 #endif
00134 
00135     //FIXME: does all that material stuff need freeing somehow?
00136 }   // ~Racegui
00137 
00138 //-----------------------------------------------------------------------------
00139 void
00140 RaceGUI::handle(GameAction ga, int value)
00141 {
00142        static int isWireframe = false;
00143        
00144        // The next lines find out the player and kartaction that belongs
00145        // to a certain gameaction value (GameAction -> Player number, Kartaction).
00146        // Since the numbers are fixed this can be done through computation
00147        // (instead of using e.g. a separate data structure).
00148        // Note that the kartaction enum value and their representatives in
00149        // gameaction enum have the same order (Otherwise the stuff below would
00150        // not work ...)!
00151        if (ga >= GA_FIRST_KARTACTION && ga <= GA_LAST_KARTACTION)
00152        {
00153               // 'Pulls down' the gameaction value to make them multiples of the
00154               // kartaction values.
00155               int ka = ga - GA_FIRST_KARTACTION;
00156               
00157               int playerNo = ka / KC_COUNT;
00158               ka = ka % KC_COUNT;
00159               
00160               world->getPlayerKart(playerNo)->action((KartAction) ka, value);
00161               
00162               return;
00163        }
00164        
00165        if (value)
00166               return;
00167        
00168        switch (ga)
00169        {
00170               case GA_DEBUG_ADD_SPARK:
00171                      if (race_manager->getNumPlayers() ==1 )
00172                      {
00173                             Kart* kart = world->getPlayerKart(0);
00174                             kart->setCollectable(COLLECT_SPARK, 10000);
00175                      }
00176                      break;
00177               case GA_DEBUG_ADD_MISSILE:
00178                      if (race_manager->getNumPlayers() ==1 )
00179                      {
00180                             Kart* kart = world->getPlayerKart(0);
00181                             kart->setCollectable(COLLECT_MISSILE, 10000);
00182                      }
00183                      break;
00184               case GA_DEBUG_ADD_HOMING:
00185                      if (race_manager->getNumPlayers() ==1 )
00186                      {
00187                             Kart* kart = world->getPlayerKart(0);
00188                             kart->setCollectable(COLLECT_HOMING, 10000);
00189                      }
00190                      break;
00191               case GA_DEBUG_TOGGLE_FPS:
00192                      user_config->m_display_fps = !user_config->m_display_fps;
00193                      if(user_config->m_display_fps)
00194                      {
00195                             m_fps_timer.reset();
00196                             m_fps_timer.setMaxDelta(1000);
00197                             m_fps_counter=0;
00198 #ifdef USE_WIDGET_MANAGER
00199                 widget_manager->showWgtText( WTOK_FPS );
00200                      }
00201             else
00202             {
00203                 widget_manager->hideWgtText( WTOK_FPS );
00204 #endif
00205             }
00206                      break;
00207               case GA_DEBUG_TOGGLE_WIREFRAME:
00208                      glPolygonMode(GL_FRONT_AND_BACK, isWireframe ? GL_FILL : GL_LINE);
00209                      isWireframe = ! isWireframe;
00210                      break;
00211 #ifndef WIN32
00212               // For now disable F9 toggling fullscreen, since windows requires
00213               // to reload all textures, display lists etc. Fullscreen can
00214               // be toggled from the main menu (options->display).
00215               case GA_TOGGLE_FULLSCREEN:
00216                      inputDriver->toggleFullscreen(false);   // 0: do not reset textures
00217                      // Fall through to put the game into pause mode.
00218 #endif
00219               case GA_LEAVE_RACE:
00220                      world->pause();
00221                      menu_manager->pushMenu(MENUID_RACEMENU);
00222               break;
00223               case GA_DEBUG_HISTORY:
00224                      history->Save();
00225                      break;
00226               default:
00227                      break;
00228        } // switch
00229 
00230 }
00231 
00232 //-----------------------------------------------------------------------------
00233 void RaceGUI::update(float dt)
00234 {
00235     assert(world != NULL);
00236     drawStatusText(dt);
00237     cleanupMessages();
00238 
00239     BaseGUI::update( dt );
00240 }   // update
00241 
00242 //-----------------------------------------------------------------------------
00243 void RaceGUI::drawFPS ()
00244 {
00245     if (++m_fps_counter>=50)
00246     {
00247         m_fps_timer.update();
00248         sprintf(m_fps_string, "%d",
00249                 (int)(m_fps_counter/m_fps_timer.getDeltaTime()));
00250         m_fps_counter = 0;
00251         m_fps_timer.setMaxDelta(1000);
00252     }
00253 #ifdef USE_WIDGET_MANAGER
00254     widget_manager->setWgtText( WTOK_FPS, m_fps_string );
00255 #else
00256     font_race->PrintShadow(m_fps_string,48, 0, user_config->m_height-50);
00257 #endif
00258 }   // drawFPS
00259 
00260 //-----------------------------------------------------------------------------
00261 void RaceGUI::drawTimer ()
00262 {
00263     if(world->getPhase()!=World::RACE_PHASE         &&
00264        world->getPhase()!=World::DELAY_FINISH_PHASE   ) return;
00265     char str[256];
00266 
00267     assert(world != NULL);
00268 
00269     TimeToString(world->getTime(), str);
00270 #ifdef USE_WIDGET_MANAGER
00271     widget_manager->showWgtText( WTOK_CLOCK );
00272     widget_manager->setWgtText( WTOK_CLOCK, str );
00273 #else
00274     font_race->PrintShadow(str, 60, user_config->m_width-260,
00275         user_config->m_height-64);
00276 #endif
00277 }   // drawTimer
00278 
00279 //-----------------------------------------------------------------------------
00280 #define TRACKVIEW_SIZE 100
00281 
00282 void RaceGUI::drawMap ()
00283 {
00284     glDisable ( GL_TEXTURE_2D ) ;
00285     assert(world != NULL);
00286     int xLeft = 10;
00287     int yTop   =  10;
00288 
00289     world -> m_track -> draw2Dview ( (float)xLeft,   (float)yTop   );
00290 
00291     glBegin ( GL_QUADS ) ;
00292 
00293     for ( unsigned int i = 0 ; i < race_manager->getNumKarts() ; i++ )
00294     {
00295         sgCoord *c ;
00296 
00297         Kart* kart = world->getKart(i);
00298         if(kart->isEliminated()) continue;   // don't draw eliminated kart
00299         glColor3fv ( *kart->getColor());
00300         c          = kart->getCoord () ;
00301 
00302         /* If it's a player, draw a bigger sign */
00303         if (kart -> isPlayerKart ())
00304         {
00305             world -> m_track->glVtx ( c->xyz, (float)xLeft+3, (float)yTop+3);
00306             world -> m_track->glVtx ( c->xyz, (float)xLeft-2, (float)yTop+3);
00307             world -> m_track->glVtx ( c->xyz, (float)xLeft-2, (float)yTop-2);
00308             world -> m_track->glVtx ( c->xyz, (float)xLeft+3, (float)yTop-2);
00309         }
00310         else
00311         {
00312             world -> m_track->glVtx ( c->xyz, (float)xLeft+2, (float)yTop+2);
00313             world -> m_track->glVtx ( c->xyz, (float)xLeft-1, (float)yTop+2);
00314             world -> m_track->glVtx ( c->xyz, (float)xLeft-1, (float)yTop-1);
00315             world -> m_track->glVtx ( c->xyz, (float)xLeft+2, (float)yTop-1);
00316         }
00317     }
00318 
00319     glEnd () ;
00320     glEnable ( GL_TEXTURE_2D ) ;
00321 }   // drawMap
00322 
00323 //-----------------------------------------------------------------------------
00324 // Draw players position on the race
00325 void RaceGUI::drawPlayerIcons ()
00326 {
00327     assert(world != NULL);
00328 
00329     int x = 5;
00330     int y;
00331 #define ICON_WIDTH 40
00332 #define ICON_PLAYER_WIDHT 50
00333 
00334     //glEnable(GL_TEXTURE_2D);
00335     Material *last_players_gst = 0;
00336     int   laps_of_leader       = -1;
00337     float time_of_leader       = -1;
00338     // Find the best time for the lap. We can't simply use
00339     // the time of the kart at position 1, since the kart
00340     // might have been overtaken by now
00341     for(unsigned int i = 0; i < race_manager->getNumKarts() ; i++)
00342     {
00343         Kart* kart     = world->getKart(i);
00344         if(kart->isEliminated()) continue;
00345         float lap_time = kart->getTimeAtLap();
00346         int laps       = kart->getLap();
00347 
00348         if(laps > laps_of_leader)
00349         {
00350             // more laps than current leader --> new leader and new time computation
00351             laps_of_leader = laps;
00352             time_of_leader = lap_time;
00353         } else if(laps == laps_of_leader)
00354         {
00355             // Same number of laps as leader: use fastest time
00356             time_of_leader=std::min(time_of_leader,lap_time);
00357         }
00358     }   // for i<getNumKarts
00359 
00360     int bFirst                 = 1;
00361     for(unsigned int i = 0; i < race_manager->getNumKarts() ; i++)
00362     {
00363         Kart* kart   = world->getKart(i);
00364         if(kart->isEliminated()) continue;
00365         int position = kart->getPosition();
00366         int lap      = kart->getLap();
00367 
00368         y = user_config->m_height*3/4-20 - ((position-1)*(ICON_PLAYER_WIDHT+2));
00369 
00370         // draw text
00371         GLfloat COLORS[] = {1.0f, 1.0f, 1.0f, 1.0f};
00372         int numLaps = race_manager->getNumLaps();
00373 
00374         if(lap>=numLaps)
00375         {  // kart is finished, display in green
00376             COLORS[1] = COLORS[2] = 0;
00377         }
00378         else if(lap>=0 && numLaps>1)
00379         {
00380             COLORS[1] = COLORS[2] = 1.0f-(float)lap/((float)numLaps-1.0f);
00381         }
00382 
00383         glDisable(GL_CULL_FACE);
00384 
00385         if(laps_of_leader>0 &&    // Display position during first lap
00386            (world->getTime() - kart->getTimeAtLap()<5.0f || lap!=laps_of_leader) &&
00387            race_manager->raceHasLaps())
00388         {  // Display for 5 seconds
00389             char str[256];
00390             if(position==1)
00391             {
00392                 str[0]=' '; str[1]=0;
00393                 TimeToString(kart->getTimeAtLap(), str+1);
00394             }
00395             else
00396             {
00397                 float timeBehind;
00398                 timeBehind = (lap==laps_of_leader ? kart->getTimeAtLap() : world->getTime())
00399                     - time_of_leader;
00400                 str[0]='+'; str[1]=0;
00401                 TimeToString(timeBehind, str+1);
00402             }
00403             font_race->PrintShadow(str, 30, ICON_PLAYER_WIDHT+x, y+5,
00404                                    COLORS);
00405         }
00406         if(race_manager->getRaceMode()==RaceManager::RM_FOLLOW_LEADER && i==0)
00407         {
00408             GLfloat const RED[] = { 1.0f, 0, 0, 1.0f};
00409             font_race->PrintShadow(_("Leader"), 30, ICON_PLAYER_WIDHT+x, y+5,
00410                                    RED );
00411         }
00412 
00413         glEnable(GL_CULL_FACE);
00414 
00415         bFirst = 0;
00416         // draw icon
00417         Material* players_gst = kart->getKartProperties()->getIconMaterial();
00418         // Hmm - if the same icon is displayed more than once in a row,
00419         // plib does only do the first setTexture, therefore nothing is
00420         // displayed for the remaining icons. So we have to call force() if
00421         // the same icon is displayed more than once in a row.
00422         if(last_players_gst==players_gst)
00423         {
00424             players_gst->getState()->force();
00425         }
00426         //The material of the icons should not have a non-zero alpha_ref value,
00427         //because if so the next call can make the text look aliased.
00428         players_gst -> apply ();
00429         last_players_gst = players_gst;
00430         glBegin ( GL_QUADS ) ;
00431         glColor4f    ( 1, 1, 1, 1 ) ;
00432         if (kart -> isPlayerKart ())
00433         {
00434             glTexCoord2f ( 0, 0 ) ; glVertex2i ( x                  , y                   ) ;
00435             glTexCoord2f ( 1, 0 ) ; glVertex2i ( x+ICON_PLAYER_WIDHT, y                   ) ;
00436             glTexCoord2f ( 1, 1 ) ; glVertex2i ( x+ICON_PLAYER_WIDHT, y+ICON_PLAYER_WIDHT ) ;
00437             glTexCoord2f ( 0, 1 ) ; glVertex2i ( x                  , y+ICON_PLAYER_WIDHT ) ;
00438         }
00439         else
00440         {
00441             glTexCoord2f ( 0, 0 ) ; glVertex2i ( x           , y            ) ;
00442             glTexCoord2f ( 1, 0 ) ; glVertex2i ( x+ICON_WIDTH, y            ) ;
00443             glTexCoord2f ( 1, 1 ) ; glVertex2i ( x+ICON_WIDTH, y+ICON_WIDTH ) ;
00444             glTexCoord2f ( 0, 1 ) ; glVertex2i ( x           , y+ICON_WIDTH ) ;
00445         }
00446         glEnd () ;
00447 
00448         // draw position (1st, 2nd...)
00449         glDisable(GL_CULL_FACE);
00450         char str[256];
00451 
00452         sprintf(str, "%d", kart->getPosition());
00453         font_race->PrintShadow(str, 33, x-7, y-4);
00454 
00455         // FIXME: translation
00456         if (kart->getPosition() == 1)
00457             font_race->PrintShadow("st", 13, x-7+17, y-4+17);
00458         else if (kart->getPosition() == 2)
00459             font_race->PrintShadow("nd", 13, x-7+17, y-4+17);
00460         else if (kart->getPosition() == 3)
00461             font_race->PrintShadow("rd", 13, x-7+17, y-4+17);
00462         else
00463             font_race->PrintShadow("th", 13, x-7+17, y-4+17);
00464 
00465         glEnable(GL_CULL_FACE);
00466     }
00467 }   // drawPlayerIcons
00468 
00469 //-----------------------------------------------------------------------------
00470 void RaceGUI::drawCollectableIcons ( Kart* player_kart, int offset_x,
00471                                      int offset_y, float ratio_x,
00472                                      float ratio_y                    )
00473 {
00474     // If player doesn't have anything, do nothing.
00475     Collectable* collectable=player_kart->getCollectable();
00476     if(collectable->getType() == COLLECT_NOTHING) return;
00477 
00478     // Originally the hardcoded sizes were 320-32 and 400
00479     int x1 = (int)((user_config->m_width/2-32) * ratio_x) + offset_x ;
00480     int y1 = (int)(user_config->m_height*5/6 * ratio_y)      + offset_y;
00481 
00482     int nSize=(int)(64.0f*std::min(ratio_x, ratio_y));
00483     collectable->getIcon()->apply();
00484 
00485     int n  = player_kart->getNumCollectables() ;
00486 
00487     if ( n > 5 ) n = 5 ;
00488     if ( n < 1 ) n = 1 ;
00489 
00490     glBegin(GL_QUADS) ;
00491     glColor4f(1, 1, 1, 1 );
00492 
00493     for ( int i = 0 ; i < n ; i++ )
00494     {
00495         glTexCoord2f(0, 0); glVertex2i( i*30 + x1      , y1      );
00496         glTexCoord2f(1, 0); glVertex2i( i*30 + x1+nSize, y1      );
00497         glTexCoord2f(1, 1); glVertex2i( i*30 + x1+nSize, y1+nSize);
00498         glTexCoord2f(0, 1); glVertex2i( i*30 + x1      , y1+nSize);
00499     }   // for i
00500     glEnd () ;
00501 
00502 }   // drawCollectableIcons
00503 
00504 //-----------------------------------------------------------------------------
00505 /* Energy meter that gets filled with coins */
00506 
00507 // Meter fluid color (0 - 255)
00508 #define METER_TOP_COLOR    240, 0, 0, 255
00509 #define METER_BOTTOM_COLOR    240, 200, 0, 160
00510 // Meter border color (0.0 - 1.0)
00511 #define METER_BORDER_BLACK 0.0, 0.0, 0.0
00512 #define METER_BORDER_WHITE 1.0, 1.0, 1.0
00513 #define METER_TARGET_RED   1.0, 0.0, 0.0
00514 
00515 //-----------------------------------------------------------------------------
00516 void RaceGUI::drawEnergyMeter ( Kart *player_kart, int offset_x, int offset_y,
00517                                 float ratio_x, float ratio_y             )
00518 {
00519     float state = (float)(player_kart->getNumHerring()) /
00520                   MAX_HERRING_EATEN;
00521     int x = (int)((user_config->m_width-24) * ratio_x) + offset_x;
00522     int y = (int)(250 * ratio_y) + offset_y;
00523     int w = (int)(16 * ratio_x);
00524     int h = (int)(user_config->m_height/4 * ratio_y);
00525     int wl = (int)(ratio_x);
00526     if(wl < 1)
00527         wl = 1;
00528     const int GRADS = (int)(MAX_HERRING_EATEN/5);  // each graduation equals 5 herring
00529     int gh = (int)(h/GRADS);  //graduation height
00530     float coin_target = (float)race_manager->getCoinTarget();
00531     int th = (int)(h*(coin_target/MAX_HERRING_EATEN));
00532 
00533     glDisable(GL_TEXTURE_2D);
00534     // Draw a Meter border
00535     x-=1;
00536     y-=1;
00537     // left side
00538     glBegin ( GL_QUADS ) ;
00539     glColor3f ( METER_BORDER_BLACK ) ;
00540     glVertex2i ( x-wl, y-wl ) ;
00541     glVertex2i ( x,    y-wl ) ;
00542     glVertex2i ( x,    y + h+1) ;
00543     glVertex2i ( x-wl, y + h+1) ;
00544     glEnd () ;
00545 
00546     // right side
00547     glBegin ( GL_QUADS ) ;
00548     glColor3f ( METER_BORDER_BLACK ) ;
00549     glVertex2i ( x+w,    y-wl ) ;
00550     glVertex2i ( x+w+wl, y-wl ) ;
00551     glVertex2i ( x+w+wl, y + h+1) ;
00552     glVertex2i ( x+w,    y + h+1) ;
00553     glEnd () ;
00554 
00555     // down side
00556     glBegin ( GL_QUADS ) ;
00557     glColor3f ( METER_BORDER_BLACK ) ;
00558     glVertex2i ( x,   y-wl ) ;
00559     glVertex2i ( x+w, y-wl ) ;
00560     glVertex2i ( x+w, y ) ;
00561     glVertex2i ( x,   y ) ;
00562     glEnd () ;
00563 
00564     // up side
00565     glBegin ( GL_QUADS ) ;
00566     glColor3f ( METER_BORDER_BLACK ) ;
00567     glVertex2i ( x,   y+h ) ;
00568     glVertex2i ( x+w, y+h ) ;
00569     glVertex2i ( x+w, y+h+wl ) ;
00570     glVertex2i ( x,   y+h+wl ) ;
00571     glEnd () ;
00572 
00573     x+=1;
00574     y+=1;
00575 
00576     // left side
00577     glBegin ( GL_QUADS ) ;
00578     glColor3f ( METER_BORDER_WHITE ) ;
00579     glVertex2i ( x-wl, y-wl ) ;
00580     glVertex2i ( x,    y-wl ) ;
00581     glVertex2i ( x,    y + h+1) ;
00582     glVertex2i ( x-wl, y + h+1) ;
00583     glEnd () ;
00584 
00585     // right side
00586     glBegin ( GL_QUADS ) ;
00587     glColor3f ( METER_BORDER_WHITE ) ;
00588     glVertex2i ( x+w,    y-wl ) ;
00589     glVertex2i ( x+w+wl, y-wl ) ;
00590     glVertex2i ( x+w+wl, y + h+1) ;
00591     glVertex2i ( x+w,    y + h+1) ;
00592     glEnd () ;
00593 
00594     // down side
00595     glBegin ( GL_QUADS ) ;
00596     glColor3f ( METER_BORDER_WHITE ) ;
00597     glVertex2i ( x,   y-wl ) ;
00598     glVertex2i ( x+w, y-wl ) ;
00599     glVertex2i ( x+w, y ) ;
00600     glVertex2i ( x,   y ) ;
00601     glEnd () ;
00602 
00603     //Graduations
00604     int gh_incr = gh;
00605     for (int i=0; i<GRADS-1; i++)
00606     {
00607         glBegin( GL_QUADS );
00608         glColor3f(METER_BORDER_WHITE);
00609         glVertex2i(x,   y+gh);
00610         glVertex2i(x+w, y+gh);
00611         glVertex2i(x+w, y+gh+wl);
00612         glVertex2i(x,   y+gh+wl);
00613         glEnd();
00614         gh+=gh_incr;
00615     }
00616     
00617     //Target line
00618     if (coin_target > 0)
00619     {
00620         glBegin ( GL_QUADS );
00621         glColor3f(METER_TARGET_RED);
00622         glVertex2i(x,   y+th);
00623         glVertex2i(x+w, y+th);
00624         glVertex2i(x+w, y+th+wl);
00625         glVertex2i(x,   y+th+wl);
00626         glEnd();
00627     }
00628     
00629     // up side
00630     glBegin ( GL_QUADS ) ;
00631     glColor3f ( METER_BORDER_WHITE ) ;
00632     glVertex2i ( x,   y+h ) ;
00633     glVertex2i ( x+w, y+h ) ;
00634     glVertex2i ( x+w, y+h+wl ) ;
00635     glVertex2i ( x,   y+h+wl ) ;
00636     glEnd () ;
00637 
00638     // Draw the Meter fluid
00639     glBegin ( GL_QUADS ) ;
00640     glColor4ub ( METER_BOTTOM_COLOR ) ;
00641     glVertex2i ( x,   y ) ;
00642     glVertex2i ( x+w, y ) ;
00643 
00644     glColor4ub ( METER_TOP_COLOR ) ;
00645     glVertex2i ( x+w, y + (int)(state * h));
00646     glVertex2i ( x,   y + (int)(state * h) ) ;
00647     glEnd () ;
00648     glEnable(GL_TEXTURE_2D);
00649 }   // drawEnergyMeter
00650 
00651 
00652 //-----------------------------------------------------------------------------
00653 void RaceGUI::drawSteering(Kart* kart, int offset_x, int offset_y,
00654                            float ratio_x, float ratio_y           )
00655 {
00656 
00657     float minRatio = std::min(ratio_x, ratio_y);
00658 #define WHEELWIDTH 64
00659     int width  = (int)(WHEELWIDTH*minRatio);
00660     int height = (int)(WHEELWIDTH*minRatio);
00661     offset_x += (int)((user_config->m_width-160)*ratio_x) - width;
00662     offset_y += (int)(6*ratio_y);
00663 
00664     glMatrixMode(GL_MODELVIEW);
00665     glPushMatrix();
00666     glLoadIdentity();
00667     // for now we display the maximum steering as a 45 degree angle.
00668     // One the steering angle for all karts are fixed, this should be
00669     // changed, so that the user gets feedback about how much steering
00670     // is currently done, since it will vary from kart to kart.
00671     float displayedAngle = 45.0f * kart->getSteerPercent();
00672 
00673     int tw = width/2; int th = height/2;
00674     glTranslatef( (float)(offset_x+tw), (float)(offset_y+th), 0.0f);
00675     glRotatef(displayedAngle, 0.0f, 0.0f, 1.0f);
00676     glTranslatef((float)(-offset_x-tw), (float)(-offset_y-th), 0.0f);
00677 
00678     m_steering_wheel_icon->getState()->force();
00679     glBegin ( GL_QUADS ) ;
00680     glColor4f    ( 1, 1, 1, 1 ) ;
00681     glTexCoord2f(0, 0);glVertex2i(offset_x      , offset_y       );
00682     glTexCoord2f(1, 0);glVertex2i(offset_x+width, offset_y       );
00683     glTexCoord2f(1, 1);glVertex2i(offset_x+width, offset_y+height);
00684     glTexCoord2f(0, 1);glVertex2i(offset_x      , offset_y+height);
00685     glEnd () ;
00686 
00687     glPopMatrix();
00688 } // drawSteering
00689 
00690 //-----------------------------------------------------------------------------
00691 void RaceGUI::drawPosition(Kart* kart, int offset_x, int offset_y,
00692                            float ratio_x, float ratio_y           )
00693 {
00694 
00695     char str[256];
00696     offset_x += (int)((user_config->m_width-110)*ratio_x);
00697     offset_y += (int)(140*ratio_y);
00698 
00699     sprintf(str, "%d", kart->getPosition());
00700     font_race->PrintShadow(str, (int)(100*ratio_y), offset_x, offset_y);
00701 
00702     offset_x += (int)(50*ratio_x);
00703     offset_y += (int)(50*ratio_y);
00704 
00705     // FIXME: translation
00706     if (kart->getPosition() == 1)
00707         font_race->PrintShadow("st", (int)(40*ratio_y), offset_x, offset_y);
00708     else if (kart->getPosition() == 2)
00709         font_race->PrintShadow("nd", (int)(40*ratio_y), offset_x, offset_y);
00710     else if (kart->getPosition() == 3)
00711         font_race->PrintShadow("rd", (int)(40*ratio_y), offset_x, offset_y);
00712     else
00713         font_race->PrintShadow("th", (int)(40*ratio_y), offset_x, offset_y);
00714 } // drawPosition
00715 
00716 //-----------------------------------------------------------------------------
00717 void RaceGUI::drawSpeed(Kart* kart, int offset_x, int offset_y,
00718                         float ratio_x, float ratio_y           )
00719 {
00720 
00721     float minRatio = std::min(ratio_x, ratio_y);
00722 #define SPEEDWIDTH 128
00723     int width  = (int)(SPEEDWIDTH*minRatio);
00724     int height = (int)(SPEEDWIDTH*minRatio);
00725     offset_x += (int)((user_config->m_width-10)*ratio_x) - width;
00726     offset_y += (int)(10*ratio_y);
00727 
00728     glMatrixMode(GL_MODELVIEW);
00729     m_speed_back_icon->getState()->force();
00730     glBegin ( GL_QUADS ) ;
00731     glTexCoord2f(0, 0);glVertex2i(offset_x      , offset_y       );
00732     glTexCoord2f(1, 0);glVertex2i(offset_x+width, offset_y       );
00733     glTexCoord2f(1, 1);glVertex2i(offset_x+width, offset_y+height);
00734     glTexCoord2f(0, 1);glVertex2i(offset_x      , offset_y+height);
00735     glEnd () ;
00736 
00737     //convention taken from btRaycastVehicle::updateVehicle
00738     const float speed =  kart->getSpeed();
00739 
00740     if ( !kart->isOnGround() )
00741         font_race->PrintShadow("!", (int)(60*minRatio), 
00742                                offset_x-(int)(30*minRatio), 
00743                                offset_y-(int)(10*minRatio));
00744     /* Show speed */
00745     if ( speed < 0 )
00746         font_race->PrintShadow(_("REV"), (int)(40*minRatio), 
00747                                offset_x+(int)(40*minRatio), 
00748                                offset_y+(int)(10*minRatio));
00749     else
00750     {
00751         if ( speed >= kart->getMaxSpeed()*kart->getWheelieMaxSpeedRatio() )
00752         {
00753             font_race->PrintShadow("l", (int)(60*minRatio), 
00754                                    offset_x+(int)(70*minRatio), offset_y);
00755             font_race->PrintShadow("^", (int)(60*minRatio), 
00756                                    offset_x+(int)(65*minRatio), 
00757                                    offset_y+(int)(7*minRatio));
00758         }
00759 
00760         float speedRatio = speed/KILOMETERS_PER_HOUR/110.0f;
00761         // The following does not work with wheelie or Zipper
00762         //float speedRatio = kart->getVelocity()->xyz[1]/(kart->getMaxSpeed();
00763 
00764         if ( speedRatio > 1 )
00765             speedRatio = 1;
00766 
00767         m_speed_fore_icon->getState()->force();
00768         glBegin ( GL_POLYGON ) ;
00769         glTexCoord2f(1, 0);glVertex2i(offset_x+width, offset_y);
00770         glTexCoord2f(0, 0);glVertex2i(offset_x, offset_y);
00771         if (speedRatio < 0.5)
00772         {
00773             glTexCoord2f(0, speedRatio*2);glVertex2i(offset_x, (int)(offset_y+width*speedRatio*2));
00774         }
00775         else
00776         {
00777             glTexCoord2f(0, 1);glVertex2i(offset_x, offset_y+width);
00778             glTexCoord2f((speedRatio-0.5f)*2, 1);glVertex2i((int)(offset_x+height*(speedRatio-0.5f)*2), offset_y+height);
00779         }
00780 
00781         glEnd () ;
00782     }   // speed<0
00783 
00784 } // drawSpeed
00785 
00786 //-----------------------------------------------------------------------------
00787 void RaceGUI::drawLap(Kart* kart, int offset_x, int offset_y,
00788                       float ratio_x, float ratio_y           )
00789 {
00790     // Don't display laps in follow the leader mode
00791     if(!race_manager->raceHasLaps()) return;
00792 
00793     float maxRatio = std::max(ratio_x, ratio_y);
00794     char str[256];
00795     offset_x += (int)(120*ratio_x);
00796     offset_y += (int)(70*maxRatio);
00797 
00798     if ( kart->getLap() >= race_manager->getNumLaps())
00799     {
00800         sprintf(str, _("Finished"));
00801         font_race->PrintShadow(str, (int)(48*maxRatio), offset_x, offset_y);
00802     }
00803     else
00804     {
00805         font_race->PrintShadow( _("Lap"), (int)(48*maxRatio), offset_x, offset_y);
00806 
00807         offset_y -= (int)(50*ratio_y);
00808 
00809         sprintf(str, "%d/%d", kart->getLap()<0?0:kart->getLap()+1, 
00810                 race_manager->getNumLaps());
00811         font_race->PrintShadow(str, (int)(48*maxRatio), offset_x, offset_y);
00812     }
00813 } // drawLap
00814 
00815 //-----------------------------------------------------------------------------
00821 void RaceGUI::cleanupMessages()
00822 {
00823     AllMessageType::iterator p =m_messages.begin(); 
00824     while(p!=m_messages.end())
00825     {
00826         if((*p).done())
00827         {
00828             p = m_messages.erase(p);
00829         }
00830         else
00831         {
00832             ++p;
00833         }
00834     }
00835 }   // cleanupMessages
00836 
00837 //-----------------------------------------------------------------------------
00840 void RaceGUI::drawAllMessages(Kart* player_kart, int offset_x, int offset_y,
00841                               float ratio_x,  float ratio_y  )
00842 {
00843     int y;
00844     // First line of text somewhat under the top of the screen. For now
00845     // start just under the timer display
00846     y = (int)(ratio_y*(user_config->m_height -164)+offset_y);
00847     // The message are displayed in reverse order, so that a multi-line
00848     // message (addMessage("1", ...); addMessage("2",...) is displayed
00849     // in the right order: "1" on top of "2"
00850     for(AllMessageType::const_iterator i=m_messages.begin();i!=m_messages.end(); ++i)
00851     {
00852         TimedMessage const &msg = *i;
00853 
00854         // Display only messages for all karts, or messages for this kart
00855         if( msg.m_kart && msg.m_kart!=player_kart) continue;
00856 
00857         //FIXME: instead of the next line, in msg there should be a GLfloat that acts as the colors.
00858         GLfloat const COLORS[] = {msg.m_red/255.0f, msg.m_green/255.0f, msg.m_blue/255.0f, 255.0f};
00859         font_race->Print( msg.m_message.c_str(), msg.m_font_size, 
00860                           Font::CENTER_OF_SCREEN, y,
00861                           COLORS,
00862                           ratio_x, ratio_y,
00863                           offset_x, offset_x+(int)(user_config->m_width*ratio_x));
00864         // Add 20% of font size as space between the lines
00865         y-=msg.m_font_size*12/10;
00866         
00867         
00868     }   // for i in all messages
00869 }   // drawAllMessages
00870 
00871 //-----------------------------------------------------------------------------
00876 void RaceGUI::addMessage(const char *msg, Kart *kart, float time, 
00877                          int font_size, int red, int green, int blue)
00878 {
00879     m_messages.push_back(TimedMessage(msg, kart, time, font_size, red, green, blue));
00880 }   // addMessage
00881 
00882 //-----------------------------------------------------------------------------
00883 // Displays the description given for the music currently being played -
00884 // usually the title and composer.
00885 void RaceGUI::drawMusicDescription()
00886 {
00887     const MusicInformation* mi=sound_manager->getCurrentMusic();
00888     if(!mi) return;
00889     int y=0;
00890     if(mi->getComposer()!="")
00891     {
00892         std::string s="by "+mi->getComposer();
00893         font_race->Print( s.c_str(), 25, 
00894                           Font::CENTER_OF_SCREEN, y );
00895         y+=20;
00896     }
00897     std::string s="\""+mi->getTitle()+"\"";
00898     font_race->Print( s.c_str(), 25, 
00899                       Font::CENTER_OF_SCREEN, y );
00900 }   // drawMusicDescription
00901 
00902 //-----------------------------------------------------------------------------
00903 void RaceGUI::drawStatusText(const float dt)
00904 {
00905     assert(world != NULL);
00906 
00907     glMatrixMode   ( GL_MODELVIEW ) ;
00908     glPushMatrix   () ;
00909     glLoadIdentity () ;
00910 
00911     glMatrixMode   ( GL_PROJECTION ) ;
00912     glPushMatrix   () ;
00913     glLoadIdentity () ;
00914 
00915     glPushAttrib   ( GL_ENABLE_BIT | GL_LIGHTING_BIT ) ;
00916     glDisable      ( GL_DEPTH_TEST   );
00917     glDisable      ( GL_LIGHTING     );
00918     glDisable      ( GL_FOG          );
00919     glDisable      ( GL_CULL_FACE    );
00920     glEnable       ( GL_ALPHA_TEST   );
00921     glAlphaFunc    ( GL_GREATER, 0.1f);
00922     glEnable       ( GL_BLEND        );
00923 
00924     glOrtho        ( 0, user_config->m_width, 0, user_config->m_height, 0, 100 ) ;
00925     switch (world->getPhase())
00926     {
00927     case World::READY_PHASE:
00928         {
00929             GLfloat const COLORS[] = { 0.9f, 0.66f, 0.62f, 1.0f };
00930             font_race->PrintShadow( _("Ready!"), 90,
00931                                    Font::CENTER_OF_SCREEN,
00932                                    Font::CENTER_OF_SCREEN,
00933                                    COLORS );
00934         }
00935         break;
00936     case World::SET_PHASE:
00937         {
00938             GLfloat const COLORS[] = { 0.9f, 0.9f, 0.62f, 1.0f };
00939             font_race->PrintShadow( _("Set!"), 90,
00940                                    Font::CENTER_OF_SCREEN,
00941                                    Font::CENTER_OF_SCREEN,
00942                                    COLORS );
00943         }
00944         break;
00945     case World::GO_PHASE:
00946         {
00947             GLfloat const COLORS[] = { 0.39f, 0.82f, 0.39f, 1.0f };
00948             font_race->PrintShadow( _("Go!"), 90, 
00949                                    Font::CENTER_OF_SCREEN,
00950                                    Font::CENTER_OF_SCREEN,
00951                                    COLORS );
00952         }
00953         break;
00954     default: 
00955          break;
00956     }   // switch
00957 
00958     for(int i = 0; i < 10; ++i)
00959     {
00960         if(world->m_debug_text[i] != "")
00961         {
00962             GLfloat const COLORS[] = { 0.39f, 0.82f, 0.39f, 1.0f };
00963             font_race->Print( world->m_debug_text[i].c_str(),
00964                              20, 20, 200 -i*20, COLORS );
00965         }
00966     }
00967     // The penalty message needs to be displayed for up to one second
00968     // after the start of the race, otherwise it disappears if 
00969     // "Go" is displayed and the race starts
00970     if(world->isStartPhase() || world->getTime()<1.0f)
00971     {
00972         for(unsigned int i=0; i<race_manager->getNumPlayers(); i++)
00973         {
00974             if(world->getPlayerKart(i)->earlyStartPenalty())
00975             {
00976                 GLfloat const COLORS[] = { 0.78f, 0.025f, 0.025f, 1.0f };
00977                 font_race->PrintShadow( _("Penalty time!!"), 80,
00978                                        Font::CENTER_OF_SCREEN, 200,
00979                                         COLORS );
00980             }   // if penalty
00981         }  // for i < getNumPlayers
00982     }  // if not RACE_PHASE
00983 
00984     float split_screen_ratio_x, split_screen_ratio_y;
00985     split_screen_ratio_x = split_screen_ratio_y = 1.0;
00986     if(race_manager->getNumPlayers() >= 2)
00987         split_screen_ratio_y = 0.5;
00988     if(race_manager->getNumPlayers() >= 3)
00989         split_screen_ratio_x = 0.5;
00990 
00991     if ( world->isRacePhase() )
00992     {
00993         const int numPlayers = race_manager->getNumPlayers();
00994 
00995         for(int pla = 0; pla < numPlayers; pla++)
00996         {
00997             int offset_x, offset_y;
00998             offset_x = offset_y = 0;
00999 
01000             if(numPlayers == 2)
01001             {
01002               if(pla == 0) offset_y = user_config->m_height/2;
01003             }
01004             else if (numPlayers == 3)
01005             {
01006               if (pla == 0  || pla == 1)
01007                 offset_y = user_config->m_height/2;
01008               else
01009               {
01010                 // Fixes width for player 3
01011                 split_screen_ratio_x = 1.0;
01012               }
01013 
01014               if (pla == 1)
01015                 offset_x = user_config->m_width/2;
01016 
01017             }
01018             else if(numPlayers == 4)
01019             {
01020               if(pla == 0  || pla == 1)
01021                 offset_y = user_config->m_height/2;
01022 
01023               if((pla == 1) || pla == 3)
01024                 offset_x = user_config->m_width/2;
01025             }
01026 
01027             Kart* player_kart=world->getPlayerKart(pla);
01028             drawCollectableIcons(player_kart, offset_x, offset_y,
01029                                  split_screen_ratio_x, split_screen_ratio_y );
01030             drawEnergyMeter     (player_kart, offset_x, offset_y,
01031                                  split_screen_ratio_x, split_screen_ratio_y );
01032             drawSteering        (player_kart, offset_x, offset_y,
01033                                  split_screen_ratio_x, split_screen_ratio_y );
01034             drawPosition        (player_kart, offset_x, offset_y,
01035                                  split_screen_ratio_x, split_screen_ratio_y );
01036             drawSpeed           (player_kart, offset_x, offset_y,
01037                                  split_screen_ratio_x, split_screen_ratio_y );
01038             drawLap             (player_kart, offset_x, offset_y,
01039                                  split_screen_ratio_x, split_screen_ratio_y );
01040             drawAllMessages     (player_kart, offset_x, offset_y,
01041                                  split_screen_ratio_x, split_screen_ratio_y );
01042         }   // for pla
01043         drawTimer           ();
01044         if(world->getTime()<TIME_MUSIC_DESCRIPTION 
01045           && race_manager->getRaceMode() != RaceManager::RM_FOLLOW_LEADER)
01046         {
01047             drawMusicDescription();
01048         }
01049         else if (world->getTime()>stk_config->m_leader_intervals[0]-TIME_MUSIC_DESCRIPTION 
01050           && race_manager->getRaceMode()== RaceManager::RM_FOLLOW_LEADER)
01051             drawMusicDescription();
01052             
01053         drawMap             ();
01054         if ( user_config->m_display_fps ) drawFPS ();
01055         drawPlayerIcons     ();
01056     }   // if RACE_PHASE
01057 
01058     glPopAttrib  () ;
01059     glPopMatrix  () ;
01060     glMatrixMode ( GL_MODELVIEW ) ;
01061     glPopMatrix  () ;
01062 }   // drawStatusText
01063 
01064 /* EOF */