Updated VS10 project file, and started to add minimal race gui.

This was only committed early to update the VC10 project file.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@7656 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2011-02-08 12:59:32 +00:00
parent e7a3ed4eb9
commit 8ab10035a1
7 changed files with 1096 additions and 1 deletions

View File

@ -333,6 +333,8 @@ supertuxkart_SOURCES = \
states_screens/kart_selection.hpp \
states_screens/main_menu_screen.cpp \
states_screens/main_menu_screen.hpp \
states_screens/minimal_race_gui.cpp \
states_screens/minimal_race_gui.hpp \
states_screens/options_screen_audio.cpp \
states_screens/options_screen_audio.hpp \
states_screens/options_screen_input.cpp \

View File

@ -344,6 +344,8 @@ namespace UserConfigParams
// ---- Misc
PARAM_PREFIX BoolUserConfigParam m_minimal_race_gui
PARAM_DEFAULT( BoolUserConfigParam(false, "minimal-race-gui") );
PARAM_PREFIX BoolUserConfigParam m_crashed
PARAM_DEFAULT( BoolUserConfigParam(false, "crashed") ); // TODO : is this used with new code? does it still work?
PARAM_PREFIX BoolUserConfigParam m_log_errors

View File

@ -164,6 +164,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\graphics\particle_kind_manager.cpp" />
<ClCompile Include="..\..\graphics\rain.cpp" />
<ClCompile Include="..\..\main.cpp" />
<ClCompile Include="..\..\main_loop.cpp" />
<ClCompile Include="..\..\guiengine\abstract_state_manager.cpp" />
@ -201,6 +202,7 @@
<ClCompile Include="..\..\challenges\challenge_data.cpp" />
<ClCompile Include="..\..\challenges\unlock_manager.cpp" />
<ClCompile Include="..\..\physics\btKartRaycast.cpp" />
<ClCompile Include="..\..\states_screens\minimal_race_gui.cpp" />
<ClCompile Include="..\..\utils\constants.cpp" />
<ClCompile Include="..\..\utils\random_generator.cpp" />
<ClCompile Include="..\..\utils\string_utils.cpp" />
@ -361,6 +363,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\graphics\particle_kind_manager.hpp" />
<ClInclude Include="..\..\graphics\rain.hpp" />
<ClInclude Include="..\..\main_loop.hpp" />
<ClInclude Include="..\..\guiengine\abstract_state_manager.hpp" />
<ClInclude Include="..\..\guiengine\abstract_top_level_container.hpp" />
@ -408,6 +411,7 @@
<ClInclude Include="..\..\network\remote_kart_info.hpp" />
<ClInclude Include="..\..\network\world_loaded_message.hpp" />
<ClInclude Include="..\..\physics\btKartRaycast.hpp" />
<ClInclude Include="..\..\states_screens\minimal_race_gui.hpp" />
<ClInclude Include="..\..\utils\constants.hpp" />
<ClInclude Include="..\..\utils\no_copy.hpp" />
<ClInclude Include="..\..\utils\ptr_vector.hpp" />

View File

@ -717,6 +717,12 @@
<ClCompile Include="..\..\physics\btKartRaycast.cpp">
<Filter>Quelldateien\physics</Filter>
</ClCompile>
<ClCompile Include="..\..\states_screens\minimal_race_gui.cpp">
<Filter>Quelldateien\states_screens</Filter>
</ClCompile>
<ClCompile Include="..\..\graphics\rain.cpp">
<Filter>Quelldateien\graphics</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\main_loop.hpp">
@ -1343,5 +1349,11 @@
<ClInclude Include="..\..\physics\btKartRaycast.hpp">
<Filter>Headerdateien\physics</Filter>
</ClInclude>
<ClInclude Include="..\..\states_screens\minimal_race_gui.hpp">
<Filter>Headerdateien\states_screens</Filter>
</ClInclude>
<ClInclude Include="..\..\graphics\rain.hpp">
<Filter>Headerdateien\graphics</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -47,6 +47,7 @@
#include "states_screens/state_manager.hpp"
#include "states_screens/race_gui_base.hpp"
#include "states_screens/race_gui.hpp"
#include "states_screens/minimal_race_gui.hpp"
#include "states_screens/race_result_gui.hpp"
#include "tracks/track.hpp"
#include "tracks/track_manager.hpp"
@ -107,7 +108,10 @@ void World::init()
// Create the race gui before anything else is attached to the scene node
// (which happens when the track is loaded). This allows the race gui to
// do any rendering on texture.
m_race_gui = new RaceGUI();
if(UserConfigParams::m_minimal_race_gui)
m_race_gui = new MinimalRaceGUI();
else
m_race_gui = new RaceGUI();
// Grab the track file
m_track = track_manager->getTrack(race_manager->getTrackName());

View File

@ -0,0 +1,868 @@
// $Id$
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
// Copyright (C) 2006 Joerg Henrichs, SuperTuxKart-Team, Steve Baker
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "states_screens/minimal_race_gui.hpp"
#include "irrlicht.h"
using namespace irr;
#include "audio/music_manager.hpp"
#include "config/user_config.hpp"
#include "graphics/camera.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material_manager.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/modaldialog.hpp"
#include "guiengine/scalable_font.hpp"
#include "io/file_manager.hpp"
#include "input/input.hpp"
#include "input/input_manager.hpp"
#include "items/attachment.hpp"
#include "items/attachment_manager.hpp"
#include "items/powerup_manager.hpp"
#include "karts/kart_properties_manager.hpp"
#include "modes/follow_the_leader.hpp"
#include "modes/linear_world.hpp"
#include "modes/world.hpp"
#include "race/race_manager.hpp"
#include "tracks/track.hpp"
#include "utils/constants.hpp"
#include "utils/string_utils.hpp"
#include "utils/translation.hpp"
/** The constructor is called before anything is attached to the scene node.
* So rendering to a texture can be done here. But world is not yet fully
* created, so only the race manager can be accessed safely.
*/
MinimalRaceGUI::MinimalRaceGUI()
{
m_enabled = true;
// Originally m_map_height was 100, and we take 480 as minimum res
const float scaling = irr_driver->getFrameSize().Height / 480.0f;
// Marker texture has to be power-of-two for (old) OpenGL compliance
m_marker_rendered_size = 2 << ((int) ceil(1.0 + log(32.0 * scaling)));
m_marker_ai_size = (int)( 28.0f * scaling);
m_marker_player_size = (int)( 24.0f * scaling);
m_map_width = (int)(200.0f * scaling);
m_map_height = (int)(200.0f * scaling);
m_map_left = (int)( 10.0f * scaling);
m_map_bottom = (int)( 10.0f * scaling);
// Minimap is also rendered bigger via OpenGL, so find power-of-two again
const int map_texture = 2 << ((int) ceil(1.0 + log(128.0 * scaling)));
m_map_rendered_width = map_texture;
m_map_rendered_height = map_texture;
m_max_font_height = GUIEngine::getFontHeight() + 10;
m_small_font_max_height = GUIEngine::getSmallFontHeight() + 5;
// special case : when 3 players play, use available 4th space for such things
if (race_manager->getNumLocalPlayers() == 3)
{
m_map_left = UserConfigParams::m_width - m_map_width;
}
m_speed_meter_icon = material_manager->getMaterial("speedback.png");
m_speed_bar_icon = material_manager->getMaterial("speedfore.png");
m_plunger_face = material_manager->getMaterial("plungerface.png");
m_music_icon = material_manager->getMaterial("notes.png");
createMarkerTexture();
m_gauge_full = irr_driver->getTexture( file_manager->getGUIDir() + "gauge_full.png" );
m_gauge_empty = irr_driver->getTexture( file_manager->getGUIDir() + "gauge_empty.png" );
m_gauge_goal = irr_driver->getTexture( file_manager->getGUIDir() + "gauge_goal.png" );
// Translate strings only one in constructor to avoid calling
// gettext in each frame.
//I18N: Shown at the end of a race
m_string_lap = _("Lap");
m_string_rank = _("Rank");
//I18N: When some GlobalPlayerIcons are hidden, write "Top 10" to show it
m_string_top = _("Top %i");
//I18N: as in "ready, set, go", shown at the beginning of the race
m_string_ready = _("Ready!");
m_string_set = _("Set!");
m_string_go = _("Go!");
//read icon frame picture
m_icons_frame=material_manager->getMaterial("icons-frame.png");
// Determine maximum length of the rank/lap text, in order to
// align those texts properly on the right side of the viewport.
gui::ScalableFont* font = GUIEngine::getFont();
m_rank_lap_width = font->getDimension(m_string_lap.c_str()).Width;
m_timer_width = font->getDimension(L"99:99:99").Width;
font = (race_manager->getNumLocalPlayers() > 2 ? GUIEngine::getSmallFont() : GUIEngine::getFont());
int w;
if (race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER ||
race_manager->getMinorMode()==RaceManager::MINOR_MODE_3_STRIKES ||
race_manager->getNumLaps() > 9)
w = font->getDimension(L"99/99").Width;
else
w = font->getDimension(L"9/9").Width;
// In some split screen configuration the energy bar might be next
// to the lap display - so make the lap X/Y display large enough to
// leave space for the energy bar (16 pixels) and 10 pixels of space
// to the right (see drawEnergyMeter for details).
w += 16 + 10;
if(m_rank_lap_width < w) m_rank_lap_width = w;
w = font->getDimension(m_string_rank.c_str()).Width;
if(m_rank_lap_width < w) m_rank_lap_width = w;
} // MinimalRaceGUI
//-----------------------------------------------------------------------------
MinimalRaceGUI::~MinimalRaceGUI()
{
irr_driver->removeTexture(m_marker);
} // ~MinimalRaceGUI
//-----------------------------------------------------------------------------
/** Creates a texture with the markers for all karts in the current race
* on it. This assumes that nothing is attached to the scene node at
* this stage.
*/
void MinimalRaceGUI::createMarkerTexture()
{
unsigned int num_karts = race_manager->getNumberOfKarts();
unsigned int npower2 = 1;
// Textures must be power of 2, so
while(npower2<num_karts) npower2*=2;
int radius = (m_marker_rendered_size>>1)-1;
IrrDriver::RTTProvider rttProvider(core::dimension2du(m_marker_rendered_size
*npower2,
m_marker_rendered_size),
"MinimalRaceGUI::markers");
scene::ICameraSceneNode *camera = irr_driver->addCameraSceneNode();
core::matrix4 projection;
projection.buildProjectionMatrixOrthoLH((float)(m_marker_rendered_size*npower2),
(float)(m_marker_rendered_size),
-1.0f, 1.0f);
camera->setProjectionMatrix(projection, true);
core::vector3df center( (float)(m_marker_rendered_size*npower2>>1),
(float)(m_marker_rendered_size>>1), 0.0f);
camera->setPosition(center);
camera->setUpVector(core::vector3df(0,1,0));
camera->setTarget(center + core::vector3df(0,0,4));
// The call to render sets the projection matrix etc. So we have to call
// this now before doing the direct OpenGL calls.
// FIXME: perhaps we should use three calls to irr_driver: begin(),
// render(), end() - so we could do the rendering by calling to
// draw2DPolygon() between render() and end(), avoiding the
// call to camera->render()
camera->render();
// We have to reset the material here, since otherwise the last
// set material (i.e from the kart selection screen) will be used
// when rednering to the texture.
video::SMaterial m;
m.setTexture(0, NULL);
irr_driver->getVideoDriver()->setMaterial(m);
for(unsigned int i=0; i<num_karts; i++)
{
const std::string& kart_ident = race_manager->getKartIdent(i);
assert(kart_ident.size() > 0);
const KartProperties *kp=kart_properties_manager->getKart(kart_ident);
assert(kp != NULL);
core::vector2df center((float)((m_marker_rendered_size>>1)
+i*m_marker_rendered_size),
(float)(m_marker_rendered_size>>1) );
int count = kp->getShape();
video::ITexture *t = kp->getMinimapIcon();
if(t)
{
video::ITexture *t = kp->getIconMaterial()->getTexture();
core::recti dest_rect(i*m_marker_rendered_size,
0,
(i+1)*m_marker_rendered_size,
m_marker_rendered_size);
core::recti source_rect(core::vector2di(0,0), t->getSize());
irr_driver->getVideoDriver()->draw2DImage(t, dest_rect,
source_rect,
/*clipRect*/0,
/*color*/ 0,
/*useAlpha*/true);
}
else // no special minimap icon defined
{
video::S3DVertex *vertices = new video::S3DVertex[count+1];
unsigned short int *index = new unsigned short int[count+1];
video::SColor color = kp->getColor();
createRegularPolygon(count, (float)radius, center, color,
vertices, index);
irr_driver->getVideoDriver()->draw2DVertexPrimitiveList(vertices,
count, index, count-2,
video::EVT_STANDARD,
scene::EPT_TRIANGLE_FAN);
delete [] vertices;
delete [] index;
} // if special minimap icon defined
}
m_marker = rttProvider.renderToTexture(-1, /*is_2d_render*/true);
irr_driver->removeCameraSceneNode(camera);
} // createMarkerTexture
//-----------------------------------------------------------------------------
/** Creates the 2D vertices for a regular polygon. Adopted from Irrlicht.
* \param n Number of vertices to use.
* \param radius Radius of the polygon.
* \param center The center point of the polygon.
* \param v Pointer to the array of vertices.
*/
void MinimalRaceGUI::createRegularPolygon(unsigned int n, float radius,
const core::vector2df &center,
const video::SColor &color,
video::S3DVertex *v,
unsigned short int *index)
{
float f = 2*M_PI/(float)n;
for (unsigned int i=0; i<n; i++)
{
float p = i*f;
core::vector2df X = center + core::vector2df( sin(p)*radius,
-cos(p)*radius);
v[i].Pos.X = X.X;
v[i].Pos.Y = X.Y;
v[i].Color = color;
index[i] = i;
}
} // createRegularPolygon
//-----------------------------------------------------------------------------
/** Render all global parts of the race gui, i.e. things that are only
* displayed once even in splitscreen.
* \param dt Timestep sized.
*/
void MinimalRaceGUI::renderGlobal(float dt)
{
cleanupMessages(dt);
// Special case : when 3 players play, use 4th window to display such
// stuff (but we must clear it)
if (race_manager->getNumLocalPlayers() == 3 &&
!GUIEngine::ModalDialog::isADialogActive())
{
static video::SColor black = video::SColor(255,0,0,0);
irr_driver->getVideoDriver()
->draw2DRectangle(black,
core::rect<s32>(UserConfigParams::m_width/2,
UserConfigParams::m_height/2,
UserConfigParams::m_width,
UserConfigParams::m_height));
}
World *world = World::getWorld();
assert(world != NULL);
if(world->getPhase() >= WorldStatus::READY_PHASE &&
world->getPhase() <= WorldStatus::GO_PHASE )
{
drawGlobalReadySetGo();
}
// Timer etc. are not displayed unless the game is actually started.
if(!world->isRacePhase()) return;
if (!m_enabled) return;
drawGlobalTimer();
if(world->getPhase() == WorldStatus::GO_PHASE ||
world->getPhase() == WorldStatus::MUSIC_PHASE)
{
drawGlobalMusicDescription();
}
drawGlobalMiniMap();
KartIconDisplayInfo* info = world->getKartsDisplayInfo();
} // renderGlobal
//-----------------------------------------------------------------------------
/** Render the details for a single player, i.e. speed, energy,
* collectibles, ...
* \param kart Pointer to the kart for which to render the view.
*/
void MinimalRaceGUI::renderPlayerView(const Kart *kart)
{
if (!m_enabled) return;
const core::recti &viewport = kart->getCamera()->getViewport();
core::vector2df scaling = kart->getCamera()->getScaling();
//std::cout << "Applied ratio : " << viewport.getWidth()/800.0f << std::endl;
scaling *= viewport.getWidth()/800.0f; // scale race GUI along screen size
//std::cout << "Scale : " << scaling.X << ", " << scaling.Y << std::endl;
if (kart->hasViewBlockedByPlunger())
{
int offset_y = viewport.UpperLeftCorner.Y;
const int screen_width = viewport.LowerRightCorner.X
- viewport.UpperLeftCorner.X;
const int plunger_size = viewport.LowerRightCorner.Y
- viewport.UpperLeftCorner.Y;
int plunger_x = viewport.UpperLeftCorner.X + screen_width/2
- plunger_size/2;
video::ITexture *t=m_plunger_face->getTexture();
core::rect<s32> dest(plunger_x, offset_y,
plunger_x+plunger_size, offset_y+plunger_size);
const core::rect<s32> source(core::position2d<s32>(0,0),
t->getOriginalSize());
//static const video::SColor white = video::SColor(255, 255, 255, 255);
irr_driver->getVideoDriver()->draw2DImage(t, dest, source,
NULL /* clip */,
NULL /* color */,
true /* alpha */);
}
drawAllMessages (kart, viewport, scaling);
if(!World::getWorld()->isRacePhase()) return;
MinimalRaceGUI::KartIconDisplayInfo* info = World::getWorld()->getKartsDisplayInfo();
drawPowerupIcons (kart, viewport, scaling);
drawSpeedAndEnergy (kart, viewport, scaling);
drawRankLap (info, kart, viewport);
} // renderPlayerView
//-----------------------------------------------------------------------------
/** Displays the racing time on the screen.s
*/
void MinimalRaceGUI::drawGlobalTimer()
{
assert(World::getWorld() != NULL);
if(!World::getWorld()->shouldDrawTimer()) return;
std::string s = StringUtils::timeToString(World::getWorld()->getTime());
core::stringw sw(s.c_str());
static video::SColor time_color = video::SColor(255, 255, 255, 255);
core::rect<s32> pos(UserConfigParams::m_width - m_timer_width - 10, 10,
UserConfigParams::m_width, 50);
// special case : when 3 players play, use available 4th space for such things
if (race_manager->getNumLocalPlayers() == 3)
{
pos += core::vector2d<s32>(0, UserConfigParams::m_height/2);
}
gui::ScalableFont* font = GUIEngine::getFont();
font->draw(sw.c_str(), pos, time_color, false, false, NULL, true /* ignore RTL */);
} // drawGlobalTimer
//-----------------------------------------------------------------------------
/** Draws the mini map and the position of all karts on it.
*/
void MinimalRaceGUI::drawGlobalMiniMap()
{
World *world = World::getWorld();
// arenas currently don't have a map.
if(world->getTrack()->isArena()) return;
const video::ITexture *mini_map=world->getTrack()->getMiniMap();
int upper_y = UserConfigParams::m_height-m_map_bottom-m_map_height;
int lower_y = UserConfigParams::m_height-m_map_bottom;
core::rect<s32> dest(m_map_left, upper_y,
m_map_left + m_map_width, lower_y);
core::rect<s32> source(core::position2di(0, 0), mini_map->getOriginalSize());
irr_driver->getVideoDriver()->draw2DImage(mini_map, dest, source, 0, 0, true);
for(unsigned int i=0; i<world->getNumKarts(); i++)
{
const Kart *kart = world->getKart(i);
if(kart->isEliminated()) continue; // don't draw eliminated kart
const Vec3& xyz = kart->getXYZ();
Vec3 draw_at;
world->getTrack()->mapPoint2MiniMap(xyz, &draw_at);
// int marker_height = m_marker->getOriginalSize().Height;
core::rect<s32> source(i *m_marker_rendered_size,
0,
(i+1)*m_marker_rendered_size,
m_marker_rendered_size);
int marker_half_size = (kart->getController()->isPlayerController()
? m_marker_player_size
: m_marker_ai_size )>>1;
core::rect<s32> position(m_map_left+(int)(draw_at.getX()-marker_half_size),
lower_y -(int)(draw_at.getY()+marker_half_size),
m_map_left+(int)(draw_at.getX()+marker_half_size),
lower_y -(int)(draw_at.getY()-marker_half_size));
irr_driver->getVideoDriver()->draw2DImage(m_marker, position, source,
NULL, NULL, true);
} // for i<getNumKarts
} // drawGlobalMiniMap
//-----------------------------------------------------------------------------
void MinimalRaceGUI::drawPowerupIcons(const Kart* kart,
const core::recti &viewport,
const core::vector2df &scaling)
{
// If player doesn't have anything, do nothing.
const Powerup* powerup = kart->getPowerup();
if(powerup->getType() == PowerupManager::POWERUP_NOTHING) return;
int n = kart->getNumPowerup() ;
if(n<1) return; // shouldn't happen, but just in case
if(n>5) n=5; // Display at most 5 items
int nSize=(int)(64.0f*std::min(scaling.X, scaling.Y));
int itemSpacing = (int)(std::min(scaling.X, scaling.Y)*30);
int x1 = viewport.UpperLeftCorner.X + viewport.getWidth()/2
- (n * itemSpacing)/2;
int y1 = viewport.UpperLeftCorner.Y + (int)(20 * scaling.Y);
assert(powerup != NULL);
assert(powerup->getIcon() != NULL);
video::ITexture *t=powerup->getIcon()->getTexture();
assert(t != NULL);
core::rect<s32> rect(core::position2di(0, 0), t->getOriginalSize());
for ( int i = 0 ; i < n ; i++ )
{
int x2=(int)(x1+i*itemSpacing);
core::rect<s32> pos(x2, y1, x2+nSize, y1+nSize);
irr_driver->getVideoDriver()->draw2DImage(t, pos, rect, NULL,
NULL, true);
} // for i
} // drawPowerupIcons
//-----------------------------------------------------------------------------
/** Energy meter that gets filled with nitro. This function is called from
* drawSpeedAndEnergy, which defines the correct position of the energy
* meter.
* \param x X position of the meter.
* \param y Y position of the meter.
* \param kart Kart to display the data for.
* \param scaling Scaling applied (in case of split screen)
*/
void MinimalRaceGUI::drawEnergyMeter(int x, int y, const Kart *kart,
const core::recti &viewport,
const core::vector2df &scaling)
{
float state = (float)(kart->getEnergy()) / MAX_NITRO;
if (state < 0.0f) state = 0.0f;
else if (state > 1.0f) state = 1.0f;
int h = (int)(viewport.getHeight()/3);
int w = h/4; // gauge image is so 1:4
y -= h;
x -= w;
// Background
irr_driver->getVideoDriver()->draw2DImage(m_gauge_empty, core::rect<s32>(x, y, x+w, y+h) /* dest rect */,
core::rect<s32>(0, 0, 64, 256) /* source rect */,
NULL /* clip rect */, NULL /* colors */,
true /* alpha */);
// Target
if (race_manager->getCoinTarget() > 0)
{
float coin_target = (float)race_manager->getCoinTarget() / MAX_NITRO;
const int EMPTY_TOP_PIXELS = 4;
const int EMPTY_BOTTOM_PIXELS = 3;
int y1 = y + (int)(EMPTY_TOP_PIXELS +
(h - EMPTY_TOP_PIXELS - EMPTY_BOTTOM_PIXELS)
*(1.0f - coin_target) );
if (state >= 1.0f) y1 = y;
core::rect<s32> clip(x, y1, x + w, y + h);
irr_driver->getVideoDriver()->draw2DImage(m_gauge_goal, core::rect<s32>(x, y, x+w, y+h) /* dest rect */,
core::rect<s32>(0, 0, 64, 256) /* source rect */,
&clip, NULL /* colors */, true /* alpha */);
}
// Filling (current state)
if (state > 0.0f)
{
const int EMPTY_TOP_PIXELS = 4;
const int EMPTY_BOTTOM_PIXELS = 3;
int y1 = y + (int)(EMPTY_TOP_PIXELS
+ (h - EMPTY_TOP_PIXELS - EMPTY_BOTTOM_PIXELS)
*(1.0f - state) );
if (state >= 1.0f) y1 = y;
core::rect<s32> clip(x, y1, x + w, y + h);
irr_driver->getVideoDriver()->draw2DImage(m_gauge_full, core::rect<s32>(x, y, x+w, y+h) /* dest rect */,
core::rect<s32>(0, 0, 64, 256) /* source rect */,
&clip, NULL /* colors */, true /* alpha */);
}
} // drawEnergyMeter
//-----------------------------------------------------------------------------
void MinimalRaceGUI::drawSpeedAndEnergy(const Kart* kart, const core::recti &viewport,
const core::vector2df &scaling)
{
float minRatio = std::min(scaling.X, scaling.Y);
const int SPEEDWIDTH = 128;
int meter_height = (int)(SPEEDWIDTH*minRatio);
drawEnergyMeter(viewport.LowerRightCorner.X,
(int)(viewport.LowerRightCorner.Y - meter_height*0.75f),
kart, viewport, scaling);
} // drawSpeedAndEnergy
//-----------------------------------------------------------------------------
/** Displays the rank and the lap of the kart.
* \param info Info object c
*/
void MinimalRaceGUI::drawRankLap(const KartIconDisplayInfo* info, const Kart* kart,
const core::recti &viewport)
{
// Don't display laps or ranks if the kart has already finished the race.
if (kart->hasFinishedRace()) return;
core::recti pos;
pos.UpperLeftCorner.Y = viewport.UpperLeftCorner.Y;
// If the time display in the top right is in this viewport,
// move the lap/rank display down a little bit so that it is
// displayed under the time.
if(viewport.UpperLeftCorner.Y==0 &&
viewport.LowerRightCorner.X==UserConfigParams::m_width &&
race_manager->getNumPlayers()!=3)
pos.UpperLeftCorner.Y += 40;
pos.LowerRightCorner.Y = viewport.LowerRightCorner.Y;
pos.UpperLeftCorner.X = viewport.LowerRightCorner.X
- m_rank_lap_width - 10;
pos.LowerRightCorner.X = viewport.LowerRightCorner.X;
gui::ScalableFont* font = (race_manager->getNumLocalPlayers() > 2 ? GUIEngine::getSmallFont() : GUIEngine::getFont());
int font_height = (int)(font->getDimension(L"X").Height);
static video::SColor color = video::SColor(255, 255, 255, 255);
WorldWithRank *world = (WorldWithRank*)(World::getWorld());
if (world->displayRank())
{
const int rank = kart->getPosition();
font->draw(m_string_rank.c_str(), pos, color);
pos.UpperLeftCorner.Y += font_height;
pos.LowerRightCorner.Y += font_height;
char str[256];
const unsigned int kart_amount = world->getCurrentNumKarts();
sprintf(str, "%d/%d", rank, kart_amount);
font->draw(core::stringw(str).c_str(), pos, color);
pos.UpperLeftCorner.Y += font_height;
pos.LowerRightCorner.Y += font_height;
}
// Don't display laps in follow the leader mode
if(world->raceHasLaps())
{
const int lap = info[kart->getWorldKartId()].lap;
// don't display 'lap 0/...'
if(lap>=0)
{
font->draw(m_string_lap.c_str(), pos, color);
char str[256];
sprintf(str, "%d/%d", lap+1, race_manager->getNumLaps());
pos.UpperLeftCorner.Y += font_height;
pos.LowerRightCorner.Y += font_height;
font->draw(core::stringw(str).c_str(), pos, color);
pos.UpperLeftCorner.Y += font_height;
pos.LowerRightCorner.Y += font_height;
}
}
} // drawRankLap
//-----------------------------------------------------------------------------
/** Removes messages which have been displayed long enough. This function
* must be called after drawAllMessages, otherwise messages which are only
* displayed once will not be drawn!
**/
void MinimalRaceGUI::cleanupMessages(const float dt)
{
AllMessageType::iterator p =m_messages.begin();
while(p!=m_messages.end())
{
if((*p).done(dt))
{
p = m_messages.erase(p);
}
else
{
++p;
}
}
} // cleanupMessages
//-----------------------------------------------------------------------------
/** Displays all messages in the message queue
**/
void MinimalRaceGUI::drawAllMessages(const Kart* kart,
const core::recti &viewport,
const core::vector2df &scaling)
{
int y = viewport.LowerRightCorner.Y - m_small_font_max_height - 10;
const int x = (viewport.LowerRightCorner.X + viewport.UpperLeftCorner.X)/2;
const int w = (viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X);
// draw less important first, at the very bottom of the screen
// unimportant messages are skipped in multiplayer, they take too much screen space
if (race_manager->getNumLocalPlayers() < 2)
{
for (AllMessageType::const_iterator i = m_messages.begin();
i != m_messages.end(); ++i)
{
TimedMessage const &msg = *i;
if (!msg.m_important)
{
// Display only messages for all karts, or messages for this kart
if (msg.m_kart && msg.m_kart!=kart) continue;
core::rect<s32> pos(x - w/2, y, x + w/2, y + m_max_font_height);
GUIEngine::getSmallFont()->draw(
core::stringw(msg.m_message.c_str()).c_str(),
pos, msg.m_color, true /* hcenter */, true /* vcenter */);
y -= m_small_font_max_height;
}
}
}
// First line of text somewhat under the top of the viewport.
y = (int)(viewport.UpperLeftCorner.Y + 164*scaling.Y);
gui::ScalableFont* font = GUIEngine::getFont();
int font_height = m_max_font_height;
if (race_manager->getNumLocalPlayers() > 2)
{
font = GUIEngine::getSmallFont();
font_height = m_small_font_max_height;
}
// The message are displayed in reverse order, so that a multi-line
// message (addMessage("1", ...); addMessage("2",...) is displayed
// in the right order: "1" on top of "2"
for (AllMessageType::const_iterator i = m_messages.begin();
i != m_messages.end(); ++i)
{
TimedMessage const &msg = *i;
// less important messages were already displayed
if (!msg.m_important) continue;
// Display only messages for all karts, or messages for this kart
if (msg.m_kart && msg.m_kart!=kart) continue;
core::rect<s32> pos(x - w/2, y, x + w/2, y + font_height);
font->draw(core::stringw(msg.m_message.c_str()).c_str(),
pos, msg.m_color, true /* hcenter */,
true /* vcenter */);
y += font_height;
} // for i in all messages
} // drawAllMessages
//-----------------------------------------------------------------------------
/** Adds a message to the message queue. The message is displayed for a
* certain amount of time (unless time<0, then the message is displayed
* once).
**/
void MinimalRaceGUI::addMessage(const core::stringw &msg, const Kart *kart,
float time, int font_size,
const video::SColor &color, bool important)
{
m_messages.push_back(TimedMessage(msg, kart, time, font_size, color,
important));
} // addMessage
//-----------------------------------------------------------------------------
// Displays the description given for the music currently being played -
// usually the title and composer.
void MinimalRaceGUI::drawGlobalMusicDescription()
{
// show no music description when it's off
if (!UserConfigParams::m_music) return;
gui::IGUIFont* font = GUIEngine::getFont();
float race_time = World::getWorld()->getTime();
// In follow the leader the clock counts backwards, so convert the
// countdown time to time since start:
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER)
race_time = ((FollowTheLeaderRace*)World::getWorld())->getClockStartTime()
- race_time;
// ---- Manage pulsing effect
// 3.0 is the duration of ready/set (TODO: don't hardcode)
float timeProgression = (float)(race_time) /
(float)(stk_config->m_music_credit_time - 2.0f);
const int x_pulse = (int)(sin(race_time*9.0f)*10.0f);
const int y_pulse = (int)(cos(race_time*9.0f)*10.0f);
float resize = 1.0f;
if (timeProgression < 0.1)
{
resize = timeProgression/0.1f;
}
else if (timeProgression > 0.9)
{
resize = 1.0f - (timeProgression - 0.9f)/0.1f;
}
const float resize3 = resize*resize*resize;
// Get song name, and calculate its size, allowing us to position stuff
const MusicInformation* mi = music_manager->getCurrentMusic();
if (!mi) return;
std::string s="\""+mi->getTitle()+"\"";
core::stringw thetext(s.c_str());
core::dimension2d< u32 > textSize = font->getDimension(thetext.c_str());
int textWidth = textSize.Width;
int textWidth2 = 0;
core::stringw thetext_composer;
if (mi->getComposer()!="")
{
// I18N: string used to show the author of the music. (e.g. "Sunny Song" by "John Doe")
thetext_composer = _("by");
thetext_composer += " ";
thetext_composer += mi->getComposer().c_str();
textWidth2 = font->getDimension(thetext_composer.c_str()).Width;
}
const int max_text_size = (int)(UserConfigParams::m_width*2.0f/3.0f);
if (textWidth > max_text_size) textWidth = max_text_size;
if (textWidth2 > max_text_size) textWidth2 = max_text_size;
const int ICON_SIZE = 64;
const int y = UserConfigParams::m_height - 80;
// the 20 is an arbitrary space left between the note icon and the text
const int noteX = (UserConfigParams::m_width / 2)
- std::max(textWidth, textWidth2)/2 - ICON_SIZE/2 - 20;
const int noteY = y;
// the 20 is an arbitrary space left between the note icon and the text
const int textXFrom = (UserConfigParams::m_width / 2)
- std::max(textWidth, textWidth2)/2 + 20;
const int textXTo = (UserConfigParams::m_width / 2)
+ std::max(textWidth, textWidth2)/2 + 20;
// ---- Draw "by" text
const int text_y = (int)(UserConfigParams::m_height - 80*(resize3)
+ 40*(1-resize));
static const video::SColor white = video::SColor(255, 255, 255, 255);
if(mi->getComposer()!="")
{
core::rect<s32> pos_by(textXFrom, text_y+40,
textXTo, text_y+40);
std::string s="by "+mi->getComposer();
font->draw(core::stringw(s.c_str()).c_str(), pos_by, white,
true, true);
}
// ---- Draw "song name" text
core::rect<s32> pos(textXFrom, text_y,
textXTo, text_y);
font->draw(thetext.c_str(), pos, white, true /* hcenter */,
true /* vcenter */);
// Draw music icon
int iconSizeX = (int)(ICON_SIZE*resize + x_pulse*resize*resize);
int iconSizeY = (int)(ICON_SIZE*resize + y_pulse*resize*resize);
video::ITexture *t = m_music_icon->getTexture();
core::rect<s32> dest(noteX-iconSizeX/2+20,
noteY-iconSizeY/2+ICON_SIZE/2,
noteX+iconSizeX/2+20,
noteY+iconSizeY/2+ICON_SIZE/2);
const core::rect<s32> source(core::position2d<s32>(0,0),
t->getOriginalSize());
irr_driver->getVideoDriver()->draw2DImage(t, dest, source,
NULL, NULL, true);
} // drawGlobalMusicDescription
// ----------------------------------------------------------------------------
/** Draws the ready-set-go message on the screen.
*/
void MinimalRaceGUI::drawGlobalReadySetGo()
{
switch (World::getWorld()->getPhase())
{
case WorldStatus::READY_PHASE:
{
static video::SColor color = video::SColor(255, 255, 255, 255);
core::rect<s32> pos(UserConfigParams::m_width>>1,
UserConfigParams::m_height>>1,
UserConfigParams::m_width>>1,
UserConfigParams::m_height>>1);
gui::IGUIFont* font = GUIEngine::getTitleFont();
font->draw(m_string_ready.c_str(), pos, color, true, true);
}
break;
case WorldStatus::SET_PHASE:
{
static video::SColor color = video::SColor(255, 255, 255, 255);
core::rect<s32> pos(UserConfigParams::m_width>>1,
UserConfigParams::m_height>>1,
UserConfigParams::m_width>>1,
UserConfigParams::m_height>>1);
gui::IGUIFont* font = GUIEngine::getTitleFont();
//I18N: as in "ready, set, go", shown at the beginning of the race
font->draw(m_string_set.c_str(), pos, color, true, true);
}
break;
case WorldStatus::GO_PHASE:
{
static video::SColor color = video::SColor(255, 255, 255, 255);
core::rect<s32> pos(UserConfigParams::m_width>>1,
UserConfigParams::m_height>>1,
UserConfigParams::m_width>>1,
UserConfigParams::m_height>>1);
//gui::IGUIFont* font = irr_driver->getRaceFont();
gui::IGUIFont* font = GUIEngine::getTitleFont();
//I18N: as in "ready, set, go", shown at the beginning of the race
font->draw(m_string_go.c_str(), pos, color, true, true);
}
break;
default:
break;
} // switch
} // drawGlobalReadySetGo

View File

@ -0,0 +1,203 @@
// $Id$
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
// Copyright (C) 2006 Joerg Henrichs, SuperTuxKart-Team, Steve Baker
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_MINIMAL_RACE_GUI_HPP
#define HEADER_MINIMAL_RACE_GUI_HPP
#include <string>
#include <vector>
#include "irrlicht.h"
using namespace irr;
#include "config/player.hpp"
#include "states_screens/race_gui_base.hpp"
class InputMap;
class Kart;
class Material;
class RaceSetup;
/**
* \brief Handles the in-race GUI (messages, mini-map, rankings, timer, etc...)
* \ingroup states_screens
*/
class MinimalRaceGUI : public RaceGUIBase
{
private:
class TimedMessage
{
public:
irr::core::stringw m_message; //!< message to display
float m_remaining_time; //!< time remaining before removing this message from screen
video::SColor m_color; //!< color of message
int m_font_size; //!< size
const Kart *m_kart;
bool m_important; //!< Important msgs are displayed in the middle of the screen
// -----------------------------------------------------
// std::vector needs standard copy-ctor and std-assignment op.
// let compiler create defaults .. they'll do the job, no
// deep copies here ..
TimedMessage(const irr::core::stringw &message,
const Kart *kart, float time, int size,
const video::SColor &color, const bool important)
{
m_message = message;
m_font_size = size;
m_kart = kart;
m_remaining_time = ( time < 0.0f ) ? -1.0f : time;
m_color = color;
m_important = important;
} // TimedMessage
// -----------------------------------------------------
// in follow leader the clock counts backwards
bool done(const float dt)
{
m_remaining_time -= dt;
return m_remaining_time < 0;
} // done
}; // TimedMessage
// ---------------------------------------------------------
Material *m_speed_meter_icon;
Material *m_speed_bar_icon;
Material *m_plunger_face;
typedef std::vector<TimedMessage> AllMessageType;
AllMessageType m_messages;
/** A texture with all mini dots to be displayed in the minimap for all karts. */
video::ITexture *m_marker;
/** Musical notes icon (for music description and credits) */
Material *m_music_icon;
/** Translated string 'lap' displayed every frame. */
core::stringw m_string_lap;
/** Translated string 'rank' displayed every frame. */
core::stringw m_string_rank;
/** Translated string 'Top %d' displayed every frame. */
core::stringw m_string_top;
/** Translated strings 'ready', 'set', 'go'. */
core::stringw m_string_ready, m_string_set, m_string_go;
video::ITexture *m_gauge_empty;
video::ITexture *m_gauge_full;
video::ITexture *m_gauge_goal;
// Minimap related variables
// -------------------------
/** The mini map of the track. */
video::ITexture *m_mini_map;
/** The size of a single marker in pixels, must be a power of 2. */
int m_marker_rendered_size;
/** The size of a single marker on the screen for AI karts,
* need not be a power of 2. */
int m_marker_ai_size;
/** The size of a single marker on the screen or player karts,
* need not be a power of 2. */
int m_marker_player_size;
/** The width of the rendered mini map in pixels, must be a power of 2. */
int m_map_rendered_width;
/** The height of the rendered mini map in pixels, must be a power of 2. */
int m_map_rendered_height;
/** Width of the map in pixels on the screen, need not be a power of 2. */
int m_map_width;
/** Height of the map in pixels on the screen, need not be a power of 2. */
int m_map_height;
/** Distance of map from left side of screen. */
int m_map_left;
/** Distance of map from bottom of screen. */
int m_map_bottom;
/** Used to display messages without overlapping */
int m_max_font_height;
int m_small_font_max_height;
/** Maximum string length of 'rank', 'lap', '99/99'. Used to position
* the rank/lap text correctly close to the right border. */
int m_rank_lap_width;
/** Maximum string length for the timer */
int m_timer_width;
/** previous position of icons */
std::vector< core::vector2d<s32> > m_previous_icons_position;
Material *m_icons_frame;
void createMarkerTexture();
void createRegularPolygon(unsigned int n, float radius,
const core::vector2df &center,
const video::SColor &color,
video::S3DVertex *v, unsigned short int *index);
/* Display informat for one player on the screen. */
void drawEnergyMeter (int x, int y, const Kart *kart,
const core::recti &viewport,
const core::vector2df &scaling);
void drawPowerupIcons (const Kart* kart,
const core::recti &viewport,
const core::vector2df &scaling);
void drawAllMessages (const Kart* kart,
const core::recti &viewport,
const core::vector2df &scaling);
void drawSpeedAndEnergy (const Kart* kart, const core::recti &viewport,
const core::vector2df &scaling);
void drawRankLap (const KartIconDisplayInfo* info, const Kart* kart,
const core::recti &viewport);
/** Display items that are shown once only (for all karts). */
void drawGlobalMiniMap ();
void drawGlobalTimer ();
void drawGlobalMusicDescription();
void cleanupMessages (const float dt);
void drawGlobalReadySetGo ();
public:
MinimalRaceGUI();
~MinimalRaceGUI();
virtual void renderGlobal(float dt);
virtual void renderPlayerView(const Kart *kart);
virtual void addMessage(const irr::core::stringw &m, const Kart *kart,
float time, int fonst_size,
const video::SColor &color=
video::SColor(255, 255, 0, 255),
bool important=true);
virtual void clearAllMessages() { m_messages.clear(); }
/** Returns the size of the texture on which to render the minimap to. */
virtual const core::dimension2du getMiniMapSize() const
{ return core::dimension2du(m_map_width, m_map_height); }
}; // MinimalRaceGUI
#endif