Moved more functions and variables common to the two
race guis into a common base class. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@8292 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
@@ -23,7 +23,6 @@
|
||||
#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"
|
||||
@@ -91,11 +90,6 @@ MinimalRaceGUI::MinimalRaceGUI()
|
||||
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;
|
||||
|
||||
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" );
|
||||
@@ -107,11 +101,6 @@ MinimalRaceGUI::MinimalRaceGUI()
|
||||
//I18N: Shown at the end of a race
|
||||
m_string_lap = _("Lap");
|
||||
m_string_rank = _("Rank");
|
||||
|
||||
//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!");
|
||||
|
||||
// Scaled fonts don't look good atm.
|
||||
m_font_scale = 1.0f; //race_manager->getNumLocalPlayers()==1 ? 1.2f : 1.0f;
|
||||
@@ -127,9 +116,9 @@ MinimalRaceGUI::MinimalRaceGUI()
|
||||
m_lap_width = font->getDimension(m_string_lap.c_str()).Width;
|
||||
m_timer_width = font->getDimension(L"99:99:99").Width;
|
||||
if(race_manager->getNumberOfKarts()>9)
|
||||
m_rank_width = font->getDimension(L"99/99").Width;
|
||||
m_rank_width = font->getDimension(L"99/99").Width;
|
||||
else
|
||||
m_rank_width = font->getDimension(L"9/9").Width;
|
||||
m_rank_width = font->getDimension(L"9/9").Width;
|
||||
|
||||
int w;
|
||||
if (race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER ||
|
||||
@@ -146,124 +135,8 @@ MinimalRaceGUI::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 ¢er,
|
||||
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.
|
||||
@@ -468,41 +341,6 @@ void MinimalRaceGUI::drawGlobalMiniMap()
|
||||
} // for only_draw_player_kart
|
||||
} // 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
|
||||
@@ -666,240 +504,3 @@ void MinimalRaceGUI::drawRankLap(const KartIconDisplayInfo* info,
|
||||
} // 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);
|
||||
|
||||
// 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 are not displayed in minimal mode
|
||||
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
|
||||
|
||||
@@ -42,49 +42,6 @@ class RaceSetup;
|
||||
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_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;
|
||||
@@ -104,21 +61,11 @@ private:
|
||||
/** A scaling factor for the font for time, rank, and lap display. */
|
||||
float m_font_scale;
|
||||
|
||||
/** 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;
|
||||
@@ -147,36 +94,20 @@ private:
|
||||
|
||||
/** Used to display messages without overlapping */
|
||||
int m_max_font_height;
|
||||
int m_small_font_max_height;
|
||||
|
||||
/** 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 ¢er,
|
||||
const video::SColor &color,
|
||||
video::S3DVertex *v, unsigned short int *index);
|
||||
|
||||
/* Display informat for one player on the screen. */
|
||||
void drawEnergyMeter (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 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:
|
||||
|
||||
@@ -184,15 +115,7 @@ public:
|
||||
~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); }
|
||||
|
||||
@@ -25,7 +25,6 @@ using namespace irr;
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "audio/music_manager.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/camera.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
@@ -73,8 +72,6 @@ RaceGUI::RaceGUI()
|
||||
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)
|
||||
@@ -84,14 +81,8 @@ RaceGUI::RaceGUI()
|
||||
|
||||
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
|
||||
@@ -100,10 +91,6 @@ RaceGUI::RaceGUI()
|
||||
|
||||
//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!");
|
||||
|
||||
m_dist_show_overlap=2;
|
||||
m_icons_inertia=2;
|
||||
@@ -142,124 +129,8 @@ RaceGUI::RaceGUI()
|
||||
//-----------------------------------------------------------------------------
|
||||
RaceGUI::~RaceGUI()
|
||||
{
|
||||
irr_driver->removeTexture(m_marker);
|
||||
} // ~Racegui
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** 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 RaceGUI::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),
|
||||
"RaceGUI::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 RaceGUI::createRegularPolygon(unsigned int n, float radius,
|
||||
const core::vector2df ¢er,
|
||||
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.
|
||||
@@ -700,41 +571,6 @@ void RaceGUI::drawGlobalPlayerIcons(const KartIconDisplayInfo* info)
|
||||
} //next position
|
||||
} // drawGlobalPlayerIcons
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void RaceGUI::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
|
||||
@@ -980,264 +816,3 @@ void RaceGUI::drawRankLap(const KartIconDisplayInfo* info, const Kart* kart,
|
||||
}
|
||||
|
||||
} // 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 RaceGUI::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 RaceGUI::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 RaceGUI::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 RaceGUI::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 RaceGUI::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
|
||||
|
||||
@@ -42,51 +42,9 @@ class RaceSetup;
|
||||
class RaceGUI : 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;
|
||||
@@ -96,22 +54,12 @@ private:
|
||||
|
||||
/** 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;
|
||||
@@ -137,10 +85,6 @@ private:
|
||||
|
||||
/** 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. */
|
||||
@@ -157,22 +101,10 @@ private:
|
||||
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 ¢er,
|
||||
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,
|
||||
@@ -181,9 +113,6 @@ private:
|
||||
/** Display items that are shown once only (for all karts). */
|
||||
void drawGlobalMiniMap ();
|
||||
void drawGlobalTimer ();
|
||||
void drawGlobalMusicDescription();
|
||||
void cleanupMessages (const float dt);
|
||||
void drawGlobalReadySetGo ();
|
||||
|
||||
public:
|
||||
|
||||
@@ -191,15 +120,7 @@ public:
|
||||
~RaceGUI();
|
||||
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); }
|
||||
|
||||
@@ -31,14 +31,281 @@
|
||||
# include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
#include "audio/music_manager.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/material_manager.hpp"
|
||||
#include "guiengine/scalable_font.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "modes/follow_the_leader.hpp"
|
||||
#include "modes/world.hpp"
|
||||
|
||||
RaceGUIBase::RaceGUIBase()
|
||||
{
|
||||
m_lightning = 0.0f;
|
||||
m_max_font_height = GUIEngine::getFontHeight() + 10;
|
||||
m_small_font_max_height = GUIEngine::getSmallFontHeight() + 5;
|
||||
m_music_icon = material_manager->getMaterial("notes.png");
|
||||
//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!");
|
||||
m_plunger_face = material_manager->getMaterial("plungerface.png");
|
||||
const std::string &guidir = file_manager->getGUIDir();
|
||||
m_gauge_full = irr_driver->getTexture(guidir+"gauge_full.png" );
|
||||
m_gauge_empty = irr_driver->getTexture(guidir+"gauge_empty.png");
|
||||
m_gauge_goal = irr_driver->getTexture(guidir+"gauge_goal.png" );
|
||||
|
||||
|
||||
|
||||
} // RaceGUIBase
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
RaceGUIBase::~RaceGUIBase()
|
||||
{
|
||||
irr_driver->removeTexture(m_marker);
|
||||
} // ~RaceGUIBase
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** 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 RaceGUIBase::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),
|
||||
"RaceGUI::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 RaceGUIBase::createRegularPolygon(unsigned int n, float radius,
|
||||
const core::vector2df ¢er,
|
||||
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
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Displays all messages in the message queue
|
||||
**/
|
||||
void RaceGUIBase::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
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** 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 RaceGUIBase::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
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void RaceGUIBase::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
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Updates lightning related information.
|
||||
*/
|
||||
@@ -105,5 +372,175 @@ void RaceGUIBase::renderPlayerView(const Kart *kart)
|
||||
glEnable(GL_BLEND);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // renderPlayerView
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** 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 RaceGUIBase::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 RaceGUIBase::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 RaceGUIBase::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
|
||||
|
||||
@@ -20,10 +20,14 @@
|
||||
#ifndef HEADER_RACE_GUI_BASE_HPP
|
||||
#define HEADER_RACE_GUI_BASE_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "irrlicht.h"
|
||||
using namespace irr;
|
||||
|
||||
|
||||
class Kart;
|
||||
class Material;
|
||||
|
||||
/**
|
||||
* \brief An abstract base class for the two race guis (race_gui and
|
||||
@@ -52,29 +56,105 @@ public:
|
||||
int lap;
|
||||
}; // KartIconDisplayInfo
|
||||
|
||||
private:
|
||||
/** Delight in seconds between lightnings. */
|
||||
float m_lightning;
|
||||
|
||||
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
|
||||
// ---------------------------------------------------------
|
||||
|
||||
typedef std::vector<TimedMessage> AllMessageType;
|
||||
AllMessageType m_messages;
|
||||
int m_small_font_max_height;
|
||||
|
||||
/** Used to display messages without overlapping */
|
||||
int m_max_font_height;
|
||||
|
||||
/** Musical notes icon (for music description and credits) */
|
||||
Material *m_music_icon;
|
||||
|
||||
/** Translated strings 'ready', 'set', 'go'. */
|
||||
core::stringw m_string_ready, m_string_set, m_string_go;
|
||||
|
||||
protected:
|
||||
/** Material for the 'plunger in the face' texture. */
|
||||
Material *m_plunger_face;
|
||||
|
||||
/** The size of a single marker in pixels, must be a power of 2. */
|
||||
int m_marker_rendered_size;
|
||||
|
||||
/** A texture with all mini dots to be displayed in the minimap for all karts. */
|
||||
video::ITexture *m_marker;
|
||||
video::ITexture *m_gauge_empty;
|
||||
video::ITexture *m_gauge_full;
|
||||
video::ITexture *m_gauge_goal;
|
||||
|
||||
|
||||
|
||||
void cleanupMessages(const float dt);
|
||||
void createMarkerTexture();
|
||||
void createRegularPolygon(unsigned int n, float radius,
|
||||
const core::vector2df ¢er,
|
||||
const video::SColor &color,
|
||||
video::S3DVertex *v, unsigned short int *index);
|
||||
void drawAllMessages (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 drawGlobalMusicDescription();
|
||||
void drawGlobalReadySetGo ();
|
||||
|
||||
public:
|
||||
|
||||
bool m_enabled;
|
||||
|
||||
RaceGUIBase();
|
||||
virtual ~RaceGUIBase() {};
|
||||
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) = 0;
|
||||
|
||||
virtual void clearAllMessages() = 0;
|
||||
|
||||
virtual ~RaceGUIBase();
|
||||
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);
|
||||
/** Returns the size of the texture on which to render the minimap to. */
|
||||
virtual const core::dimension2du
|
||||
getMiniMapSize() const = 0;
|
||||
virtual void renderGlobal(float dt);
|
||||
virtual void renderPlayerView(const Kart *kart);
|
||||
virtual void clearAllMessages() { m_messages.clear(); }
|
||||
|
||||
/** Set the flag that a lightning should be shown. */
|
||||
void doLightning() { m_lightning = 1.0f; }
|
||||
|
||||
Reference in New Issue
Block a user