Merge branch 'master' into kart-properties

Conflicts:
	src/karts/kart.cpp
This commit is contained in:
Flakebi 2015-08-19 12:03:43 +02:00
commit 586724c855
22 changed files with 212 additions and 275 deletions

View File

@ -1088,16 +1088,29 @@ scene::IMeshSceneNode *IrrDriver::addOctTree(scene::IMesh *mesh)
scene::IMeshSceneNode *IrrDriver::addSphere(float radius,
const video::SColor &color)
{
scene::IMeshSceneNode *node = m_scene_manager->addSphereSceneNode(radius);
node->setMaterialType(video::EMT_SOLID);
scene::IMesh *mesh = node->getMesh();
scene::IMesh *mesh = m_scene_manager->getGeometryCreator()
->createSphereMesh(radius);
mesh->setMaterialFlag(video::EMF_COLOR_MATERIAL, true);
video::SMaterial m;
video::SMaterial &m = mesh->getMeshBuffer(0)->getMaterial();
m.AmbientColor = color;
m.DiffuseColor = color;
m.EmissiveColor = color;
m.BackfaceCulling = false;
mesh->getMeshBuffer(0)->getMaterial() = m;
m.MaterialType = video::EMT_SOLID;
m.setTexture(0, getUnicolorTexture(video::SColor(128, 255, 105, 180)));
m.setTexture(1, getUnicolorTexture(video::SColor(0, 0, 0, 0)));
if (CVS->isGLSL())
{
STKMeshSceneNode *node =
new STKMeshSceneNode(mesh,
m_scene_manager->getRootSceneNode(),
NULL, -1, "sphere");
return node;
}
scene::IMeshSceneNode *node = m_scene_manager->addMeshSceneNode(mesh);
return node;
} // addSphere

View File

@ -18,6 +18,7 @@
#include "graphics/show_curve.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "utils/vec3.hpp"
@ -64,6 +65,9 @@ void ShowCurve::addEmptyMesh()
m_mesh = irr_driver->createQuadMesh(&m,
/*create_one_quad*/ false);
m_buffer = m_mesh->getMeshBuffer(0);
m_buffer->getMaterial().setTexture(0, getUnicolorTexture(video::SColor(128, 255, 105, 180)));
m_buffer->getMaterial().setTexture(1, getUnicolorTexture(video::SColor(0, 0, 0, 0)));
assert(m_buffer->getVertexType()==video::EVT_STANDARD);
} // addEmptyMesh

View File

@ -252,13 +252,16 @@ void fillLocalBuffer(GLMesh &mesh, scene::IMeshBuffer* mb)
glGenBuffers(1, &(mesh.index_buffer));
glBindBuffer(GL_ARRAY_BUFFER, mesh.vertex_buffer);
const void* vertices = mb->getVertices();
const u32 vertexCount = mb->getVertexCount();
// This can happen for certain debug structures, e.g. ShowCurve
if (vertexCount == 0)
return;
const c8* vbuf = static_cast<const c8*>(vertices);
glBufferData(GL_ARRAY_BUFFER, vertexCount * mesh.Stride, vbuf,
GL_STREAM_DRAW);
assert(vertexCount);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.index_buffer);
const void* indices = mb->getIndices();

View File

@ -417,10 +417,8 @@ void PlayerKartWidget::markAsReady()
// 'playerNameString' is already fribidize, so we need to use
// 'insertValues' and not _("...", a) so it's not flipped again
m_ready_text =
GUIEngine::getGUIEnv()->addStaticText(
StringUtils::insertValues(_("%s is ready"),
playerNameString).c_str(),
rect );
GUIEngine::getGUIEnv()->addStaticText(_("%s is ready", playerNameString),
rect);
m_ready_text->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER );
m_children.remove(m_player_ident_spinner);

View File

@ -19,24 +19,10 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//The AI debugging works best with just 1 AI kart, so set the number of karts
//to 2 in main.cpp with quickstart and run supertuxkart with the arg -N.
#ifdef DEBUG
// Enable AI graphical debugging
# undef AI_DEBUG
// Shows left and right lines when using new findNonCrashing function
# undef AI_DEBUG_NEW_FIND_NON_CRASHING
// Show the predicted turn circles
# undef AI_DEBUG_CIRCLES
// Show the heading of the kart
# undef AI_DEBUG_KART_HEADING
// Shows line from kart to its aim point
# undef AI_DEBUG_KART_AIM
#endif
#include "karts/controller/skidding_ai.hpp"
#ifdef AI_DEBUG
# include "graphics/glwrap.hpp"
# include "graphics/irr_driver.hpp"
#endif
#include "graphics/show_curve.hpp"
@ -111,6 +97,8 @@ SkiddingAI::SkiddingAI(AbstractKart *kart)
i==2 ? 128 : 0);
m_debug_sphere[i] = irr_driver->addSphere(1.0f, col_debug);
m_debug_sphere[i]->setVisible(false);
m_debug_sphere[i]->setMaterialTexture(0, getUnicolorTexture(video::SColor(128, 255, 105, 180)));
m_debug_sphere[i]->setMaterialTexture(1, getUnicolorTexture(video::SColor(0, 0, 0, 0)));
}
m_debug_sphere[m_point_selection_algorithm]->setVisible(true);
m_item_sphere = irr_driver->addSphere(1.0f);
@ -167,7 +155,7 @@ SkiddingAI::~SkiddingAI()
{
delete m_curve[i];
}
delete m_curve;
delete [] m_curve;
#endif
} // ~SkiddingAI
@ -1843,7 +1831,7 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
m_curve[CURVE_RIGHT]->addPoint(q[RIGHT_END_POINT]+eps1);
m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1);
#endif
#ifdef AI_DEBUG_KART_HEADING
#if defined(AI_DEBUG_KART_HEADING) || defined(AI_DEBUG_NEW_FIND_NON_CRASHING)
const Vec3 eps(0,0.5f,0);
m_curve[CURVE_KART]->clear();
m_curve[CURVE_KART]->addPoint(m_kart->getXYZ()+eps);

View File

@ -22,6 +22,27 @@
#ifndef HEADER_SKIDDING_AI_HPP
#define HEADER_SKIDDING_AI_HPP
// Some debugging features for the AI. For example you can visualise the
// point the AI is aiming at, or visualise the curve the AI is predicting.
// It works best with just 1 AI kart, so set the number of karts
// to 2 in main.cpp with quickstart and run supertuxkart with the arg -N.
// Or use --profile-laps=99 and run just one AI. Using the debug camera
// (top view) is useful, too
#ifdef DEBUG
// Enable AI graphical debugging
# undef AI_DEBUG
// Shows left and right lines when using new findNonCrashing function
# undef AI_DEBUG_NEW_FIND_NON_CRASHING
// Show the predicted turn circles
# undef AI_DEBUG_CIRCLES
// Show the heading of the kart
# undef AI_DEBUG_KART_HEADING
// Shows line from kart to its aim point
# undef AI_DEBUG_KART_AIM
#endif
#include "karts/controller/ai_base_controller.hpp"
#include "race/race_manager.hpp"
#include "tracks/graph_node.hpp"

View File

@ -166,6 +166,7 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id,
m_boing_sound = SFXManager::get()->createSoundSource( "boing" );
m_goo_sound = SFXManager::get()->createSoundSource( "goo" );
m_skid_sound = SFXManager::get()->createSoundSource( "skid" );
m_nitro_sound = SFXManager::get()->createSoundSource( "nitro" );
m_terrain_sound = NULL;
m_previous_terrain_sound = NULL;
@ -192,6 +193,7 @@ void Kart::init(RaceManager::KartType type)
m_crash_sound->setVolume( 1.0f / factor );
m_boing_sound->setVolume( 1.0f / factor );
m_beep_sound->setVolume( 1.0f / factor );
m_nitro_sound->setVolume( 1.0f / factor );
}
else
{
@ -200,6 +202,7 @@ void Kart::init(RaceManager::KartType type)
m_crash_sound->setVolume( 1.0f / race_manager->getNumberOfKarts() );
m_beep_sound->setVolume( 1.0f / race_manager->getNumberOfKarts() );
m_boing_sound->setVolume( 1.0f / race_manager->getNumberOfKarts() );
m_nitro_sound->setVolume( 1.0f / race_manager->getNumberOfKarts() );
}
}
@ -256,6 +259,7 @@ Kart::~Kart()
m_goo_sound ->deleteSFX();
m_beep_sound ->deleteSFX();
m_boing_sound ->deleteSFX();
m_nitro_sound ->deleteSFX();
delete m_kart_gfx;
if(m_terrain_sound) m_terrain_sound->deleteSFX();
if(m_previous_terrain_sound) m_previous_terrain_sound->deleteSFX();
@ -609,7 +613,7 @@ void Kart::createPhysics()
// The y position of the wheels (i.e. the points where
// the suspension is attached to) is just at the
// bottom of the kart. That is half the kart height
// down.
// down.
wheel_pos[index].setY(- 0.5f*kart_height);
wheel_pos[index].setZ((0.5f*kart_length-0.25f)* z);
@ -1234,6 +1238,7 @@ void Kart::update(float dt)
m_crash_sound->setPosition ( getXYZ() );
m_skid_sound->setPosition ( getXYZ() );
m_boing_sound->setPosition ( getXYZ() );
m_nitro_sound->setPosition ( getXYZ() );
// Check if a kart is (nearly) upside down and not moving much -->
// automatic rescue
@ -1263,19 +1268,19 @@ void Kart::update(float dt)
m_xyz_front = getTrans()(front);
// After the physics step was done, the position of the wheels (as stored
// in wheelInfo) is actually outdated, since the chassis was moved
// in wheelInfo) is actually outdated, since the chassis was moved
// according to the force acting from the wheels. So the cnter of the
// chassis is not at the center of the wheels anymore, it is somewhat
// moved forward (depending on speed and fps). In very extreme cases
// (see bug 2246) the center of the chassis can actually be ahead of the
// front wheels. So if we do a raycast to detect the terrain from the
// current chassis, that raycast might be ahead of the wheels - which
// current chassis, that raycast might be ahead of the wheels - which
// results in incorrect rescues (the wheels are still on the ground,
// but the raycast happens ahead of the front wheels and are over
// a rescue texture).
// To avoid this problem, we do the raycast for terrain detection from
// the center of the 4 wheel positions (in world coordinates).
Vec3 from(0, 0, 0);
for (unsigned int i = 0; i < 4; i++)
from += m_vehicle->getWheelInfo(i).m_raycastInfo.m_hardPointWS;
@ -1747,23 +1752,35 @@ void Kart::updateNitro(float dt)
bool increase_speed = (m_controls.m_nitro && isOnGround());
if (!increase_speed && m_min_nitro_time <= 0.0f)
{
if(m_nitro_sound->getStatus() == SFXBase::SFX_PLAYING)
m_nitro_sound->stop();
return;
}
m_collected_energy -= dt * m_characteristic->getNitroConsumption();
if (m_collected_energy < 0)
{
if(m_nitro_sound->getStatus() == SFXBase::SFX_PLAYING)
m_nitro_sound->stop();
m_collected_energy = 0;
return;
}
if (increase_speed)
{
if(m_nitro_sound->getStatus() != SFXBase::SFX_PLAYING)
m_nitro_sound->play();
m_max_speed->increaseMaxSpeed(MaxSpeed::MS_INCREASE_NITRO,
m_characteristic->getNitroMaxSpeedIncrease(),
m_characteristic->getNitroEngineForce(),
m_characteristic->getNitroDuration(),
m_characteristic->getNitroFadeOutTime());
}
else
{
if(m_nitro_sound->getStatus() == SFXBase::SFX_PLAYING)
m_nitro_sound->stop();
}
} // updateNitro
// -----------------------------------------------------------------------------
@ -2503,7 +2520,7 @@ void Kart::kartIsInRestNow()
* physics-only simulation steps so that karts come to a rest). Then at
* race time, only the difference between the current suspension length and
* this default suspension length is used. The graphical kart chassis will be
* offset so that when the kart is in rest, i.e. suspension length ==
* offset so that when the kart is in rest, i.e. suspension length ==
* default suspension length, the kart will look the way it was modelled in
* blender. To explain the various offsets used, here a view from the side
* focusing on the Y axis only (X/Z position of the graphical chassis is
@ -2561,7 +2578,7 @@ void Kart::kartIsInRestNow()
* and so not easily visible), so if the suspension is compressed by more than
* that, the chassiswill appear to be in the ground. Testing on the sand track
* shows that the suspension is compressed by 0.12 (and up to 0.16 in some
* extreme points), which means that the chassis will appear to be in the
* extreme points), which means that the chassis will appear to be in the
* ground quite easily. Therefore the chassis is actually moved up a bit to
* avoid this problem. Historically (due to never sorting out that formula
* properly) the chassis was moved twice as high as its lowest point, e.g.
@ -2571,7 +2588,7 @@ void Kart::kartIsInRestNow()
* same amount higher.
*
* Of course this means that the Y position of the wheels (relative to the
* visual kart chassis) needs to be adjusted: if the kart is in rest, the
* visual kart chassis) needs to be adjusted: if the kart is in rest, the
* wheels are exactly on the ground. If the suspension is shorter, that wheel
* would appear to be partly in the ground, and if the suspension is longer,
* the wheel would not touch the ground.
@ -2579,7 +2596,7 @@ void Kart::kartIsInRestNow()
* The wheels must be offset by how much the current suspension length is
* longer or shorter than the default (i.e. at rest) suspension length.
* This is done in KartModel (pos is the position of the wheel relative
* to the visual kart chassis):
* to the visual kart chassis):
* pos.Y += m_default_physics_suspension[i]
* - wi.m_raycastInfo.m_suspensionLength
* But since the chassis is raised an additional 'getLowestPoint' (see
@ -2692,7 +2709,7 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz,
if (m_shadow)
{
const bool emergency = getKartAnimation() != NULL;
m_shadow->update(isOnGround() && !emergency,
m_shadow->update(isOnGround() && !emergency,
m_terrain_info->getHoT() - getXYZ().getY()
- m_skidding->getGraphicalJumpOffset()
- m_graphical_y_offset
@ -2750,7 +2767,7 @@ void Kart::setOnScreenText(const wchar_t *text)
if (CVS->isGLSL())
{
gui::ScalableFont* font = GUIEngine::getFont() ? GUIEngine::getFont()
gui::ScalableFont* font = GUIEngine::getFont() ? GUIEngine::getFont()
: GUIEngine::getTitleFont();
new STKTextBillboard(text, font,
video::SColor(255, 255, 225, 0),

View File

@ -148,7 +148,7 @@ private:
/** True if fire button was pushed and not released */
bool m_fire_clicked;
/** Counter which is used for displaying wrong way message after a delay */
float m_wrongway_counter;
@ -199,6 +199,7 @@ private:
SFXBase *m_engine_sound;
SFXBase *m_crash_sound;
SFXBase *m_terrain_sound;
SFXBase *m_nitro_sound;
/** A pointer to the previous terrain sound needs to be saved so that an
* 'older' sfx can be finished and an abrupt end of the sfx is avoided. */
SFXBase *m_previous_terrain_sound;

View File

@ -267,7 +267,7 @@ public:
*/
core::stringw getName() const
{
return core::stringw(translations->w_gettext(m_name.c_str()));
return _LTR(m_name.c_str());
}
// ------------------------------------------------------------------------

View File

@ -199,9 +199,8 @@ void EasterEggHunt::getKartsDisplayInfo(
{
RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
//I18n: number of collected eggs / overall number of eggs
rank_info.m_text = StringUtils::insertValues(_("Eggs: %d / %d"),
m_eggs_collected[i],
m_number_of_eggs);
rank_info.m_text = _("Eggs: %d / %d", m_eggs_collected[i],
m_number_of_eggs);
rank_info.m_color = video::SColor(255, 255, 255, 255);
}
} // getKartDisplayInfo

View File

@ -173,7 +173,14 @@ void LinearWorld::update(float dt)
// Nothing to do for karts that are currently being
// rescued or eliminated
if(kart->getKartAnimation()) continue;
// If the kart is off road, and 'flying' over a reset plane
// don't adjust the distance of the kart, to avoid a jump
// in the position of the kart (e.g. while falling the kart
// might get too close to another part of the track, shortly
// jump to position one, then on reset fall back to last)
if (!kart_info.getTrackSector()->isOnRoad() &&
kart->getMaterial()->isDriveReset())
continue;
kart_info.getTrackSector()->update(kart->getFrontXYZ());
kart_info.m_overall_distance = kart_info.m_race_lap
* m_track->getTrackLength()

View File

@ -167,8 +167,8 @@ public:
// -------------------------------------------------------------------------
enum GPReverseType getReverseType()
const { return m_reverse_type; }
static const char* getRandomGPID() { return "random"; }
static const wchar_t* getRandomGPName() { return _LTR("Random Grand Prix");}
static const char* getRandomGPID() { return "random"; }
static irr::core::stringw getRandomGPName() { return _LTR("Random Grand Prix"); }
}; // GrandPrixData
#endif

View File

@ -168,7 +168,7 @@ public:
/** Returns a (translated) name of a minor race mode.
* \param mode Minor race mode.
*/
static const wchar_t* getNameOf(const MinorRaceModeType mode)
static const core::stringw getNameOf(const MinorRaceModeType mode)
{
switch (mode)
{
@ -184,7 +184,7 @@ public:
case MINOR_MODE_EASTER_EGG: return _("Egg Hunt");
//I18N: Game mode
case MINOR_MODE_SOCCER: return _("Soccer");
default: assert(false); return NULL;
default: assert(false); return L"";
}
} // getNameOf

View File

@ -356,9 +356,8 @@ void AddonsLoading::doInstall()
bool error = !addons_manager->install(m_addon);
if(error)
{
core::stringw msg = StringUtils::insertValues(
_("Problems installing the addon '%s'."),
core::stringw(m_addon.getName().c_str()));
const core::stringw &name = m_addon.getName();
core::stringw msg = _("Problems installing the addon '%s'.", name);
getWidget<BubbleWidget>("description")->setText(msg.c_str());
}
@ -394,8 +393,8 @@ void AddonsLoading::doUninstall()
Log::warn("Addons", "Directory '%s' can not be removed.",
m_addon.getDataDir().c_str());
Log::warn("Addons", "Please remove this directory manually.");
core::stringw msg = StringUtils::insertValues(_("Problems removing the addon '%s'."),
core::stringw(m_addon.getName().c_str()));
const core::stringw &name = m_addon.getName();
core::stringw msg = _("Problems removing the addon '%s'.", name);
getWidget<BubbleWidget>("description")->setText(msg.c_str());
}

View File

@ -98,10 +98,6 @@ RaceGUIBase::RaceGUIBase()
m_dist_show_overlap = 2;
m_icons_inertia = 2;
//I18N: When some GlobalPlayerIcons are hidden, write "Top 10" to show it
m_string_top = _("Top %i");
m_referee = NULL;
} // RaceGUIBase
@ -812,7 +808,8 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
static video::SColor color = video::SColor(255, 255, 255, 255);
pos_top.LowerRightCorner = pos_top.UpperLeftCorner;
font->draw(StringUtils::insertValues( m_string_top, position-1 ), pos_top, color);
//I18N: When some GlobalPlayerIcons are hidden, write "Top 10" to show it
font->draw(_("Top %i", position-1 ), pos_top, color);
break;
}

View File

@ -129,9 +129,6 @@ private:
/** Translated strings 'ready', 'set', 'go'. */
core::stringw m_string_ready, m_string_set, m_string_go, m_string_goal;
/** Translated string 'Top %d' displayed every frame. */
core::stringw m_string_top;
/** The position of the referee for all karts. */
std::vector<Vec3> m_referee_pos;

View File

@ -20,6 +20,7 @@
#include "config/user_config.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/glwrap.hpp"
#include "io/xml_node.hpp"
#include "karts/abstract_kart.hpp"
#include "modes/linear_world.hpp"
@ -77,6 +78,7 @@ CheckLine::CheckLine(const XMLNode &node, unsigned int index)
scene::IMesh *mesh = irr_driver->createQuadMesh(&material,
/*create mesh*/true);
scene::IMeshBuffer *buffer = mesh->getMeshBuffer(0);
assert(buffer->getVertexType()==video::EVT_STANDARD);
irr::video::S3DVertex* vertices
= (video::S3DVertex*)buffer->getVertices();
@ -95,11 +97,14 @@ CheckLine::CheckLine(const XMLNode &node, unsigned int index)
for(unsigned int i=0; i<4; i++)
{
vertices[i].Color = m_active_at_reset
? video::SColor(0, 255, 0, 0)
: video::SColor(0, 128, 128, 128);
? video::SColor(128, 255, 0, 0)
: video::SColor(128, 128, 128, 128);
}
buffer->recalculateBoundingBox();
mesh->setBoundingBox(buffer->getBoundingBox());
buffer->getMaterial().setTexture(0, getUnicolorTexture(video::SColor(128, 255, 105, 180)));
buffer->getMaterial().setTexture(1, getUnicolorTexture(video::SColor(0, 0, 0, 0)));
buffer->getMaterial().BackfaceCulling = false;
//mesh->setBoundingBox(buffer->getBoundingBox());
m_debug_node = irr_driver->addMesh(mesh, "checkdebug");
mesh->drop();
}
@ -137,11 +142,14 @@ void CheckLine::changeDebugColor(bool is_active)
scene::IMeshBuffer *buffer = mesh->getMeshBuffer(0);
irr::video::S3DVertex* vertices
= (video::S3DVertex*)buffer->getVertices();
video::SColor color = is_active ? video::SColor(192, 255, 0, 0)
: video::SColor(192, 128, 128, 128);
for(unsigned int i=0; i<4; i++)
{
vertices[i].Color = is_active ? video::SColor(0, 255, 0, 0)
: video::SColor(0, 128, 128, 128);
vertices[i].Color = color;
}
buffer->getMaterial().setTexture(0, getUnicolorTexture(color));
} // changeDebugColor
// ----------------------------------------------------------------------------

View File

@ -310,7 +310,7 @@ void TrackObject::onWorldReady()
fn_signature << "bool " << fn_name << "(";
for (int i = 0; i < arguments.size(); i++)
for (unsigned int i = 0; i < arguments.size(); i++)
{
if (i > 0)
fn_signature << ",";
@ -328,7 +328,7 @@ void TrackObject::onWorldReady()
script_engine->runFunction(true, fn_signature.str(),
[&](asIScriptContext* ctx)
{
for (int i = 0; i < arguments.size(); i++)
for (unsigned int i = 0; i < arguments.size(); i++)
{
ctx->SetArgObject(i, &arguments[i]);
}

View File

@ -25,12 +25,13 @@
#include "utils/utf8.h"
#include "coreutil.h"
#include <math.h>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <stdio.h>
#include <cwchar>
#include <exception>
#include <assert.h>
namespace StringUtils
{
@ -167,7 +168,7 @@ namespace StringUtils
try
{
std::string::size_type start=0;
while(start!=std::string::npos && start<(unsigned int)s.size())
while(start < (unsigned int) s.size())
{
std::string::size_type i=s.find(c, start);
if (i!=std::string::npos)
@ -185,11 +186,11 @@ namespace StringUtils
}
else // end of string reached
{
if (keepSplitChar)
if (keepSplitChar && start != 0)
result.push_back(std::string(s,start-1));
else
result.push_back(std::string(s,start));
start = i;
return result;
}
}
return result;
@ -243,14 +244,13 @@ namespace StringUtils
}
else
{
if (keepSplitChar)
if (keepSplitChar && start != 0)
result.push_back( s.subString(start - 1,
s.size()-start + 1) );
else
result.push_back( s.subString(start, s.size()-start) );
return result;
//start = i+1;
}
}
return result;

View File

@ -136,210 +136,71 @@ namespace StringUtils
std::string insertValues(const std::string &s,
std::vector<std::string>& all_vals);
/** This no-op is useful when using variadic arguments, so that we may
* support the case with 0 variadic arguments */
template <class T1>
T1 insertValues(const T1& s) { return s; }
// ------------------------------------------------------------------------
/** Same as above but for wide-strings */
irr::core::stringw insertValues(const irr::core::stringw &s,
std::vector<irr::core::stringw>& all_vals);
// ------------------------------------------------------------------------
// Note: the order in which the templates are specified is important, since
// otherwise some compilers will not find the right template to use.
template <class T1, class T2, class T3, class T4, class T5, class T6>
std::string insertValues(const std::string &s, const T1 &v1,
const T2 &v2, const T3 &v3, const T4 &v4,
const T5 &v5,const T6 &v6)
{
std::vector<std::string> all_vals;
std::ostringstream dummy;
dummy << v1; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v2; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v3; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v4; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v5; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v6; all_vals.push_back(dummy.str());
return insertValues(s, all_vals);
} // insertValues(s, v1, ..., v6)
// ------------------------------------------------------------------------
template <class T1, class T2, class T3, class T4, class T5>
std::string insertValues(const std::string &s, const T1 &v1,
const T2 &v2, const T3 &v3, const T4 &v4,
const T5 &v5)
{
std::vector<std::string> all_vals;
std::ostringstream dummy;
dummy << v1; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v2; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v3; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v4; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v5; all_vals.push_back(dummy.str());
return insertValues(s, all_vals);
} // insertValues(s, v1, ..., v5)
// ------------------------------------------------------------------------
template <class T1, class T2, class T3, class T4>
std::string insertValues(const std::string &s, const T1 &v1,
const T2 &v2, const T3 &v3, const T4 &v4)
{
std::vector<std::string> all_vals;
std::ostringstream dummy;
dummy << v1; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v2; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v3; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v4; all_vals.push_back(dummy.str());
return insertValues(s, all_vals);
} // insertValues(s, v1, ..., v4)
// ------------------------------------------------------------------------
/** Shortcut insert_values taking three values, see above for
* full docs.
* \param s String in which all %s or %d are replaced.
* \param v1,v2, v3 Value(s) to replace all %s or %d with.
*/
template <class T1, class T2, class T3>
std::string insertValues(const std::string &s, const T1 &v1,
const T2 &v2, const T3 &v3)
{
std::vector<std::string> all_vals;
std::ostringstream dummy;
dummy << v1; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v2; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v3; all_vals.push_back(dummy.str());
return insertValues(s, all_vals);
} // insertValues(s, v1, ..., v3)
// ------------------------------------------------------------------------
// Note: the order in which the templates are specified is important, since
// otherwise some compilers will not find the right template to use.
/** Shortcut insert_values taking three values, see above for
* full docs.
* \param s String in which all %s or %d are replaced.
* \param v1,v2 Value(s) to replace all %s or %d with.
*/
template <class T1, class T2>
std::string insertValues(const std::string &s, const T1 &v1,
const T2 &v2)
{
std::vector<std::string> all_vals;
std::ostringstream dummy;
dummy << v1; all_vals.push_back(dummy.str()); dummy.str("");
dummy << v2; all_vals.push_back(dummy.str()); dummy.str("");
return insertValues(s, all_vals);
} // insertValues(s, v1, v2)
// ------------------------------------------------------------------------
/** Shortcut insert_values taking three values, see above for
* full docs.
* \param s String in which all %s, %d are replaced.
* \param v1 Value to replace.
*/
template <class T1>
std::string insertValues(const std::string &s, const T1 &v1)
{
std::vector<std::string> all_vals;
std::ostringstream dummy;
dummy << v1; all_vals.push_back(dummy.str()); dummy.str("");
return insertValues(s, all_vals);
} // insertValues(s, v1)
// ------------------------------------------------------------------------
/** Intermediate struct to fill a vector using variadic templates */
struct __FillStringwVector
struct FillStringVector
{
/** FillS takes a vector as the first argument and a variadic list of
* arguments. The arguments are recursively inserted into the vector
* which will contain all the arguments converted to strings in the end.
*/
template<typename T, typename...Args>
static void __Fill(std::vector<irr::core::stringw> &all_vals, T&& v, Args &&...args)
static void FillS(std::vector<std::string> &all_vals, T&& v, Args &&...args)
{
std::ostringstream oss;
oss << v;
all_vals.push_back(oss.str());
FillS(all_vals, std::forward<Args>(args)...);
}
static void FillS(std::vector<std::string>&) {}
/** This functions does the same as FillS but for wide strings. */
template<typename T, typename...Args>
static void FillW(std::vector<irr::core::stringw> &all_vals, T&& v, Args &&...args)
{
all_vals.push_back(irr::core::stringw(std::forward<T>(v)));
__Fill(all_vals, std::forward<Args>(args)...);
FillW(all_vals, std::forward<Args>(args)...);
}
static void __Fill(std::vector<irr::core::stringw>&) {}
static void FillW(std::vector<irr::core::stringw>&) {}
};
template <typename...Args>
std::string insertValues(const std::string &s, Args ...args)
{
std::vector<std::string> all_vals;
all_vals.reserve(sizeof...(args));
FillStringVector::FillS(all_vals, std::forward<Args>(args)...);
return insertValues(s, all_vals);
}
template <typename...Args>
std::string insertValues(const char *s, Args ...args)
{
return insertValues(std::string(s), std::forward<Args>(args)...);
}
/** Like the other ones above but for wide strings */
template <typename...Args>
irr::core::stringw insertValues(const irr::core::stringw &s, Args ...args)
{
std::vector<irr::core::stringw> all_vals;
__FillStringwVector::__Fill(all_vals, std::forward<Args>(args)...);
all_vals.reserve(sizeof...(args));
FillStringVector::FillW(all_vals, std::forward<Args>(args)...);
return insertValues(s, all_vals);
}
// ------------------------------------------------------------------------
/** Like the other ones above but for wide strings */
template <class T1, class T2, class T3, class T4, class T5>
irr::core::stringw insertValues(const wchar_t* chars, const T1 &v1,
const T2 &v2, const T3 &v3, const T4 &v4,
const T5 &v5)
template <typename...Args>
irr::core::stringw insertValues(const wchar_t *s, Args ...args)
{
irr::core::stringw s(chars);
return insertValues(s, v1, v2, v3, v4, v5);
} // insertValues(s, v1, ..., v5)
// ------------------------------------------------------------------------
/** Like the other ones above but for wide strings */
template <class T1, class T2, class T3>
irr::core::stringw insertValues(const wchar_t* chars, const T1 &v1,
const T2 &v2, const T3 &v3)
{
irr::core::stringw s(chars);
return insertValues(s, v1, v2, v3);
} // insertValues(s, v1, ..., v3)
// ------------------------------------------------------------------------
/** Like the other ones above but for wide strings */
template <class T1, class T2>
irr::core::stringw insertValues(const wchar_t* chars, const T1 &v1,
const T2 &v2)
{
irr::core::stringw s(chars);
return insertValues(s, v1, v2);
} // insertValues(s, v1, v2)
// ------------------------------------------------------------------------
/** Like the other ones above but for wide strings */
template <class T1>
irr::core::stringw insertValues(const wchar_t* chars, const T1 &v1)
{
irr::core::stringw s(chars);
return insertValues(s, v1);
} // insertValues(s, v1)
// ------------------------------------------------------------------------
/** Like the other ones above but for C strings */
template <class T1, class T2, class T3>
std::string insertValues(const char* chars, const T1 &v1,
const T2 &v2, const T3 &v3)
{
std::string s(chars);
return insertValues(s, v1, v2, v3);
} // insertValues(s, v1, ..., v3)
// ------------------------------------------------------------------------
/** Like the other ones above but for C strings */
template <class T1, class T2>
std::string insertValues(const char* chars, const T1 &v1,
const T2 &v2)
{
std::string s(chars);
return insertValues(s, v1, v2);
} // insertValues(s, v1, v2)
// ------------------------------------------------------------------------
/** Like the other ones above but for C strings */
template <class T1>
std::string insertValues(const char* chars, const T1 &v1)
{
std::string s(chars);
return insertValues(s, v1);
} // insertValues(s, v1)
return insertValues(irr::core::stringw(s), std::forward<Args>(args)...);
}
// ------------------------------------------------------------------------
template<typename T>
@ -371,5 +232,3 @@ namespace StringUtils
} // namespace StringUtils
#endif
/* EOF */

View File

@ -26,12 +26,13 @@
#include "utils/translation.hpp"
#include <algorithm>
#include <assert.h>
#include <locale.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <cassert>
#include <cerrno>
#include <clocale>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cwchar>
#include <iostream>
#include <vector>
@ -359,10 +360,23 @@ Translations::Translations() //: m_dictionary_manager("UTF-16")
// ----------------------------------------------------------------------------
Translations::~Translations()
{
} // ~Translations
// ----------------------------------------------------------------------------
const wchar_t* Translations::fribidize(const wchar_t* in_ptr)
{
if (isRTLText(in_ptr))
{
// Test if this string was already fribidized
std::map<const irr::core::stringw, const irr::core::stringw>::const_iterator
found = m_fribidized_strings.find(in_ptr);
if (found != m_fribidized_strings.cend())
return found->second.c_str();
// Use fribidi to fribidize the string
// Split text into lines
std::vector<core::stringw> input_lines = StringUtils::split(in_ptr, '\n');
// Reverse lines for RTL strings, irrlicht will reverse them back
@ -371,18 +385,25 @@ const wchar_t* Translations::fribidize(const wchar_t* in_ptr)
std::reverse(input_lines.begin(), input_lines.end());
// Fribidize and concat lines
core::stringw converted_string;
for (std::vector<core::stringw>::iterator it = input_lines.begin();
it != input_lines.end(); it++)
{
if (it == input_lines.begin())
m_converted_string = fribidizeLine(*it);
converted_string = fribidizeLine(*it);
else
{
m_converted_string += "\n";
m_converted_string += fribidizeLine(*it);
converted_string += "\n";
converted_string += fribidizeLine(*it);
}
}
return m_converted_string.c_str();
// Save it in the map
m_fribidized_strings.insert(std::pair<const irr::core::stringw, const irr::core::stringw>(
in_ptr, converted_string));
found = m_fribidized_strings.find(in_ptr);
return found->second.c_str();
}
else
return in_ptr;
@ -448,12 +469,13 @@ const wchar_t* Translations::w_gettext(const char* original, const char* context
if (original_t == original)
{
m_converted_string = StringUtils::utf8_to_wide(original);
static irr::core::stringw converted_string;
converted_string = StringUtils::utf8_to_wide(original);
#if TRANSLATE_VERBOSE
std::wcout << L" translation : " << m_converted_string << std::endl;
std::wcout << L" translation : " << converted_string << std::endl;
#endif
return m_converted_string.c_str();
return converted_string.c_str();
}
// print
@ -572,4 +594,3 @@ core::stringw Translations::fribidizeLine(const core::stringw &str)
return core::stringw(str);
#endif // ENABLE_BIDI
}

View File

@ -20,11 +20,14 @@
#define TRANSLATION_HPP
#include <irrString.h>
#include <vector>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "utils/string_utils.hpp"
# include "tinygettext/tinygettext.hpp"
#include "tinygettext/tinygettext.hpp"
# define _(String, ...) (translations->fribidize(StringUtils::insertValues(translations->w_gettext(String), ##__VA_ARGS__)))
#undef _C
@ -46,13 +49,15 @@ private:
tinygettext::DictionaryManager m_dictionary_manager;
tinygettext::Dictionary m_dictionary;
irr::core::stringw m_converted_string;
/** A map that saves all fribidized strings: Original string, fribidized string */
std::map<const irr::core::stringw, const irr::core::stringw> m_fribidized_strings;
bool m_rtl;
std::string m_current_language_name;
public:
Translations();
~Translations();
const wchar_t *w_gettext(const wchar_t* original, const char* context=NULL);
const wchar_t *w_gettext(const char* original, const char* context=NULL);