Merged master

This commit is contained in:
Sachith Hasaranga Seneviratne 2014-07-08 18:18:56 +05:30
commit be9e9a326d
37 changed files with 723 additions and 635 deletions

View File

@ -25,20 +25,17 @@ uniform float boost_amount;
// The color buffer to use.
uniform sampler2D color_buffer;
uniform sampler2D dtex;
// Center (in texture coordinates) at which the kart is. A small circle
// around this center is not blurred (see mask_radius below)
uniform vec2 center;
// The direction to which the blurring aims at
uniform vec2 direction;
// Radius of mask around the character in which no blurring happens
// so that the kart doesn't get blurred.
uniform float mask_radius;
// Maximum height of texture used
uniform float max_tex_height;
uniform mat4 previous_viewproj;
layout (std140) uniform MatrixesData
{
@ -55,42 +52,44 @@ out vec4 FragColor;
// Number of samples used for blurring
#define NB_SAMPLES 8
vec4 getPosFromUVDepth(vec3 uvDepth, mat4 InverseProjectionMatrix);
void main()
{
vec2 texcoords = gl_FragCoord.xy / screen;
vec2 texcoords = gl_FragCoord.xy / screen;
// Sample the color buffer
vec3 color = texture(color_buffer, texcoords).rgb;
// Sample the color buffer
vec3 color = texture(color_buffer, texcoords).rgb;
// Compute the blur direction.
// IMPORTANT: we don't normalize it so that it avoids a glitch around 'center',
// plus it naturally scales the motion blur in a cool way :)
vec2 blur_dir = direction - texcoords;
float z = texture(dtex, texcoords).x;
vec4 ViewPos = getPosFromUVDepth(vec3(texcoords, z), InverseProjectionMatrix);
vec4 OldScreenPos = previous_viewproj * InverseViewMatrix * ViewPos;
OldScreenPos /= OldScreenPos.w;
OldScreenPos = .5 * OldScreenPos + .5;
// Compute the blurring factor:
// - apply the mask, i.e. no blurring in a small circle around the kart
float blur_factor = max(0.0, length(texcoords - center) - mask_radius);
// Compute the blur direction.
// IMPORTANT: we don't normalize it so that it avoids a glitch around 'center',
// plus it naturally scales the motion blur in a cool way :)
vec2 blur_dir = texcoords - OldScreenPos.xy;
// - avoid blurring the top of the screen
blur_factor *= (max_tex_height - texcoords.t);
// Compute the blurring factor:
// - apply the mask, i.e. no blurring in a small circle around the kart
float blur_factor = max(0.0, length(texcoords - center) - mask_radius);
// - apply the boost amount
blur_factor *= boost_amount;
// - apply the boost amount
blur_factor *= boost_amount;
// Scale the blur direction
blur_dir *= blur_factor;
// Scale the blur direction
blur_dir *= boost_amount;
// Compute the blur
vec2 inc_vec = blur_dir / vec2(NB_SAMPLES);
vec2 blur_texcoords = texcoords + inc_vec;
for(int i=1 ; i < NB_SAMPLES ; i++)
{
color += texture(color_buffer, blur_texcoords).rgb;
blur_texcoords += inc_vec;
}
color /= vec3(NB_SAMPLES);
FragColor = vec4(color, 1.0);
// Keep this commented line for debugging:
//FragColor = vec4(blur_factor, blur_factor, blur_factor, 0.0);
// Compute the blur
vec2 inc_vec = blur_dir / vec2(NB_SAMPLES);
vec2 blur_texcoords = texcoords - inc_vec * NB_SAMPLES / 2;
for(int i=1 ; i < NB_SAMPLES ; i++)
{
color += texture(color_buffer, blur_texcoords).rgb;
blur_texcoords += inc_vec;
}
color /= vec3(NB_SAMPLES);
FragColor = vec4(color, 1.0);
}

View File

@ -8,7 +8,8 @@ vec3 getLightFactor(float specMapValue);
void main(void)
{
vec4 col = texture(Albedo, uv) * color;
vec4 col = texture(Albedo, uv);
col.xyz *= pow(color.xyz, vec3(2.2));
vec3 LightFactor = getLightFactor(1.);
FragColor = vec4(col.xyz * LightFactor, 1.);
}

View File

@ -380,9 +380,6 @@
downward-impulse-factor="0"
track-connection-accel="2"/>
<!-- Parameters for the upright constraint, which keeps karts upright. -->
<upright tolerance="0.2" max-force="30"/>
<!-- collision
impulse-type: STK can apply an additional impulse in case of
kart-track collision:

View File

@ -1,5 +1,5 @@
# Modify this file to change the last-modified date when you add/remove a file.
# This will then trigger a new cmake run automatically.
# This will then trigger a new cmake run automatically.
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")

View File

@ -376,8 +376,7 @@ void ChallengeData::setRace(RaceManager::Difficulty d) const
else if(m_mode==CM_GRAND_PRIX)
{
race_manager->setMinorMode(m_minor);
const GrandPrixData *gp = grand_prix_manager->getGrandPrix(m_gp_id);
race_manager->setGrandPrix(*gp);
race_manager->setGrandPrix(grand_prix_manager->getGrandPrix(m_gp_id));
race_manager->setDifficulty(d);
race_manager->setNumKarts(m_num_karts[d]);
race_manager->setNumLocalPlayers(1);
@ -459,7 +458,7 @@ bool ChallengeData::isGPFulfilled() const
// is no world objects to query at this stage.
if (race_manager->getMajorMode() != RaceManager::MAJOR_MODE_GRAND_PRIX ||
race_manager->getMinorMode() != m_minor ||
race_manager->getGrandPrix()->getId() != m_gp_id ||
race_manager->getGrandPrix().getId() != m_gp_id ||
race_manager->getNumberOfKarts() < (unsigned int)m_num_karts[d] ||
race_manager->getNumPlayers() > 1) return false;

View File

@ -99,7 +99,7 @@ const int MIN_SUPPORTED_WIDTH = 800;
* So we create a dummy device here to begin with, which is then later (once
* the real device exists) changed in initDevice().
*/
IrrDriver::IrrDriver() : object_count{}
IrrDriver::IrrDriver()
{
m_resolution_changing = RES_CHANGE_NONE;
m_phase = SOLID_NORMAL_AND_DEPTH_PASS;
@ -112,6 +112,7 @@ IrrDriver::IrrDriver() : object_count{}
m_mipviz = m_wireframe = m_normals = m_ssaoviz = \
m_lightviz = m_shadowviz = m_distortviz = m_rsm = m_rh = m_gi = false;
SkyboxCubeMap = m_last_light_bucket_distance = 0;
memset(object_count, 0, sizeof(object_count));
} // IrrDriver
// ----------------------------------------------------------------------------

View File

@ -230,7 +230,7 @@ private:
core::array<video::IRenderTarget> m_mrt;
/** Matrixes used in several places stored here to avoid recomputation. */
core::matrix4 m_ViewMatrix, m_InvViewMatrix, m_ProjMatrix, m_InvProjMatrix, m_ProjViewMatrix, m_InvProjViewMatrix;
core::matrix4 m_ViewMatrix, m_InvViewMatrix, m_ProjMatrix, m_InvProjMatrix, m_ProjViewMatrix, m_previousProjViewMatrix, m_InvProjViewMatrix;
std::vector<video::ITexture *> SkyboxTextures;
std::vector<video::ITexture *> SphericalHarmonicsTextures;
@ -694,7 +694,8 @@ public:
void setProjMatrix(core::matrix4 matrix) { m_ProjMatrix = matrix; matrix.getInverse(m_InvProjMatrix); }
const core::matrix4 &getProjMatrix() const { return m_ProjMatrix; }
const core::matrix4 &getInvProjMatrix() const { return m_InvProjMatrix; }
void genProjViewMatrix() { m_ProjViewMatrix = m_ProjMatrix * m_ViewMatrix; m_InvProjViewMatrix = m_ProjViewMatrix; m_InvProjViewMatrix.makeInverse(); }
void genProjViewMatrix() { m_previousProjViewMatrix = m_ProjViewMatrix; m_ProjViewMatrix = m_ProjMatrix * m_ViewMatrix; m_InvProjViewMatrix = m_ProjViewMatrix; m_InvProjViewMatrix.makeInverse(); }
const core::matrix4 & getPreviousPVMatrix() { return m_previousProjViewMatrix; }
const core::matrix4 &getProjViewMatrix() const { return m_ProjViewMatrix; }
const core::matrix4 &getInvProjViewMatrix() const { return m_InvProjViewMatrix; }
#ifdef DEBUG

View File

@ -607,13 +607,17 @@ void PostProcessing::renderMotionBlur(unsigned cam, FrameBuffer &in_fbo, FrameBu
glUseProgram(FullScreenShader::MotionBlurShader::Program);
glBindVertexArray(FullScreenShader::MotionBlurShader::vao);
setTexture(0, in_fbo.getRTT()[0], GL_NEAREST, GL_NEAREST);
setTexture(0, in_fbo.getRTT()[0], GL_LINEAR, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
setTexture(1, irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST);
FullScreenShader::MotionBlurShader
::setUniforms(cb->getBoostTime(cam), cb->getCenter(cam),
cb->getDirection(cam), 0.15f,
cb->getMaxHeight(cam) * 0.7f, 0);
::setUniforms(.1, // Todo : should be framerate dependent
// Todo : use a previousPVMatrix per cam, not global
irr_driver->getPreviousPVMatrix(),
cb->getCenter(cam),
0.15f,
0, 1);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
@ -868,7 +872,7 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, boo
{
PROFILER_PUSH_CPU_MARKER("- Motion blur", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_MOTIONBLUR));
if (isRace && UserConfigParams::m_motionblur && m_any_boost && World::getWorld() != NULL) // motion blur
if (isRace && UserConfigParams::m_motionblur && World::getWorld() != NULL) // motion blur
{
renderMotionBlur(0, *in_fbo, *out_fbo);
std::swap(in_fbo, out_fbo);

View File

@ -204,9 +204,6 @@ void IrrDriver::renderGLSL(float dt)
else
fbo->BlitToDefault(viewport.UpperLeftCorner.X, viewport.UpperLeftCorner.Y, viewport.LowerRightCorner.X, viewport.LowerRightCorner.Y);
}
else
glDisable(GL_FRAMEBUFFER_SRGB);
PROFILER_POP_CPU_MARKER();
} // for i<world->getNumKarts()
@ -372,7 +369,10 @@ void IrrDriver::renderScene(scene::ICameraSceneNode * const camnode, unsigned po
PROFILER_POP_CPU_MARKER();
}
if (!UserConfigParams::m_dynamic_lights && !forceRTT)
{
glDisable(GL_FRAMEBUFFER_SRGB);
return;
}
// Render displacement
{

View File

@ -2663,33 +2663,34 @@ namespace FullScreenShader
GLuint MotionBlurShader::uniform_boost_amount;
GLuint MotionBlurShader::uniform_center;
GLuint MotionBlurShader::uniform_color_buffer;
GLuint MotionBlurShader::uniform_direction;
GLuint MotionBlurShader::uniform_dtex;
GLuint MotionBlurShader::uniform_previous_viewproj;
GLuint MotionBlurShader::uniform_mask_radius;
GLuint MotionBlurShader::uniform_max_tex_height;
GLuint MotionBlurShader::vao;
void MotionBlurShader::init()
{
Program = LoadProgram(
GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getPosFromUVDepth.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/motion_blur.frag").c_str());
uniform_boost_amount = glGetUniformLocation(Program, "boost_amount");
uniform_center = glGetUniformLocation(Program, "center");
uniform_color_buffer = glGetUniformLocation(Program, "color_buffer");
uniform_direction = glGetUniformLocation(Program, "direction");
uniform_mask_radius = glGetUniformLocation(Program, "mask_radius");
uniform_max_tex_height = glGetUniformLocation(Program, "max_tex_height");
uniform_dtex = glGetUniformLocation(Program, "dtex");
uniform_previous_viewproj = glGetUniformLocation(Program, "previous_viewproj");
vao = createFullScreenVAO(Program);
}
void MotionBlurShader::setUniforms(float boost_amount, const core::vector2df &center, const core::vector2df &direction, float mask_radius, float max_tex_height, unsigned TU_cb)
void MotionBlurShader::setUniforms(float boost_amount, const core::matrix4 &previousVP, const core::vector2df &center, float mask_radius, unsigned TU_cb, unsigned TU_dtex)
{
glUniformMatrix4fv(uniform_previous_viewproj, 1, GL_FALSE, previousVP.pointer());
glUniform1f(uniform_boost_amount, boost_amount);
glUniform2f(uniform_center, center.X, center.Y);
glUniform2f(uniform_direction, direction.X, direction.Y);
glUniform1f(uniform_mask_radius, mask_radius);
glUniform1f(uniform_max_tex_height, max_tex_height);
glUniform1i(uniform_color_buffer, TU_cb);
glUniform1i(uniform_dtex, TU_dtex);
}
GLuint GodFadeShader::Program;

View File

@ -759,11 +759,11 @@ class MotionBlurShader
{
public:
static GLuint Program;
static GLuint uniform_boost_amount, uniform_color_buffer, uniform_center, uniform_direction, uniform_mask_radius, uniform_max_tex_height;
static GLuint uniform_boost_amount, uniform_color_buffer, uniform_dtex, uniform_previous_viewproj, uniform_center, uniform_mask_radius;
static GLuint vao;
static void init();
static void setUniforms(float boost_amount, const core::vector2df &center, const core::vector2df &direction, float mask_radius, float max_tex_height, unsigned TU_cb);
static void setUniforms(float boost_amount, const core::matrix4 &previousVP, const core::vector2df &center, float mask_radius, unsigned TU_cb, unsigned TU_dtex);
};
class GodFadeShader

View File

@ -160,7 +160,7 @@ void SpinnerWidget::add()
{
label->setText(m_labels[m_value].c_str() );
}
}
@ -174,7 +174,7 @@ void SpinnerWidget::add()
m_children[2].m_id = m_children[2].m_element->getID();
// refresh display
setValue(m_value);
}
@ -333,7 +333,7 @@ void SpinnerWidget::setValue(const int new_value)
assert(new_value >= 0);
assert(new_value < (int)m_labels.size());
m_children[1].m_element->setText(m_labels[new_value].c_str() );
m_children[1].m_element->setText(m_labels[new_value].c_str());
}
else if (m_text.size() > 0 && m_children.size() > 0)
{

View File

@ -28,7 +28,6 @@ class AbstractKartAnimation;
class Attachment;
class btKart;
class btQuaternion;
class btUprightConstraint;
class Controller;
class Item;
class KartModel;
@ -342,9 +341,6 @@ public:
/** Returns the bullet vehicle which represents this kart. */
virtual btKart* getVehicle() const = 0;
// ------------------------------------------------------------------------
/** Returns the upright constraint for this kart. */
virtual btUprightConstraint* getUprightConstraint() const = 0;
// ------------------------------------------------------------------------
virtual btQuaternion getVisualRotation() const = 0;
// ------------------------------------------------------------------------
/** Returns true if the kart is 'resting', i.e. (nearly) not moving. */

View File

@ -58,7 +58,6 @@
#include "network/network_manager.hpp"
#include "physics/btKart.hpp"
#include "physics/btKartRaycast.hpp"
#include "physics/btUprightConstraint.hpp"
#include "physics/physics.hpp"
#include "race/history.hpp"
#include "tracks/track.hpp"
@ -269,7 +268,6 @@ Kart::~Kart()
World::getWorld()->getPhysics()->removeKart(this);
delete m_vehicle;
delete m_vehicle_raycaster;
delete m_uprightConstraint;
}
for(int i=0; i<m_kart_chassis.getNumChildShapes(); i++)
@ -682,13 +680,6 @@ void Kart::createPhysics()
// Obviously these allocs have to be properly managed/freed
btTransform t;
t.setIdentity();
m_uprightConstraint=new btUprightConstraint(this, t);
m_uprightConstraint->setLimit(m_kart_properties->getUprightTolerance());
m_uprightConstraint->setBounce(0.0f);
m_uprightConstraint->setMaxLimitForce(m_kart_properties->getUprightMaxForce());
m_uprightConstraint->setErp(1.0f);
m_uprightConstraint->setLimitSoftness(1.0f);
m_uprightConstraint->setDamping(0.0f);
World::getWorld()->getPhysics()->addKart(this);
} // createPhysics
@ -699,8 +690,9 @@ void Kart::flyUp()
{
m_flying = true;
Moveable::flyUp();
}
} // flyUp
// ----------------------------------------------------------------------------
void Kart::flyDown()
{
if (isNearGround())
@ -712,7 +704,7 @@ void Kart::flyDown()
{
Moveable::flyDown();
}
} // flyUp
} // flyDown
// ----------------------------------------------------------------------------
/** Starts the engine sound effect. Called once the track intro phase is over.
@ -957,8 +949,7 @@ bool Kart::isOnGround() const
//-----------------------------------------------------------------------------
/** The kart is near the ground, but not necessarily on it (small jumps). This
* is used to determine when to switch off the upright constraint, so that
* explosions can be more violent, while still
* is used to determine when to stop flying.
*/
bool Kart::isNearGround() const
{
@ -1102,21 +1093,6 @@ void Kart::update(float dt)
m_slipstream->update(dt);
if (!m_flying)
{
// When really on air, free fly, when near ground, try to glide /
// adjust for landing. If zipped, be stable, so ramp+zipper can
// allow nice jumps without scripting the fly
// Also disable he upright constraint when gravity is changed by
// the terrain
if( (!isNearGround() &&
m_max_speed->getSpeedIncreaseTimeLeft(MaxSpeed::MS_INCREASE_ZIPPER)<=0.0f ) ||
(getMaterial() && getMaterial()->hasGravity()) )
m_uprightConstraint->setLimit(M_PI);
else
m_uprightConstraint->setLimit(m_kart_properties->getUprightTolerance());
}
// TODO: hiker said this probably will be moved to btKart or so when updating bullet engine.
// Neutralize any yaw change if the kart leaves the ground, so the kart falls more or less
// straight after jumping, but still allowing some "boat shake" (roll and pitch).
@ -2041,6 +2017,30 @@ void Kart::updatePhysics(float dt)
m_max_speed->setMinSpeed(min_speed);
m_max_speed->update(dt);
// If the kart is flying, keep its up-axis aligned to gravity (which in
// turn typically means the kart is parallel to the ground). This avoids
// that the kart rotates in mid-air and lands on its side.
if(m_vehicle->getNumWheelsOnGround()==0)
{
btVector3 kart_up = getTrans().getBasis().getColumn(1); // up vector
btVector3 terrain_up = m_body->getGravity();
float g = World::getWorld()->getTrack()->getGravity();
// Normalize the gravity, g is the length of the vector
btVector3 new_up = 0.9f * kart_up + 0.1f * terrain_up/-g;
// Get the rotation (hpr) based on current heading.
Vec3 rotation(getHeading(), new_up);
btMatrix3x3 m;
m.setEulerZYX(rotation.getX(), rotation.getY(), rotation.getZ());
// We can't use getXYZ() for the position here, since the position is
// based on interpolation, while the actual center-of-mass-transform
// is based on the actual value every 1/60 of a second (using getXYZ()
// would result in the kart being pushed ahead a bit, making it jump
// much further, depending on fps)
btTransform new_trans(m, m_body->getCenterOfMassTransform().getOrigin());
//setTrans(new_trans);
m_body->setCenterOfMassTransform(new_trans);
}
// To avoid tunneling (which can happen on long falls), clamp the
// velocity in Y direction. Tunneling can happen if the Y velocity
// is larger than the maximum suspension travel (per frame), since then
@ -2048,6 +2048,7 @@ void Kart::updatePhysics(float dt)
// not sure if this is enough in all cases!). So the speed is limited
// to suspensionTravel / dt with dt = 1/60 (since this is the dt
// bullet is using).
// Only apply if near ground instead of purely based on speed avoiding
// the "parachute on top" look.
const Vec3 &v = m_body->getLinearVelocity();
@ -2056,7 +2057,7 @@ void Kart::updatePhysics(float dt)
Vec3 v_clamped = v;
// clamp the speed to 99% of the maxium falling speed.
v_clamped.setY(-m_kart_properties->getSuspensionTravelCM()*0.01f*60 * 0.99f);
m_body->setLinearVelocity(v_clamped);
//m_body->setLinearVelocity(v_clamped);
}
//at low velocity, forces on kart push it back and forth so we ignore this

View File

@ -35,7 +35,6 @@
#include "utils/no_copy.hpp"
class btKart;
class btUprightConstraint;
class Attachment;
class Controller;
@ -146,7 +145,6 @@ private:
btCompoundShape m_kart_chassis;
btVehicleRaycaster *m_vehicle_raycaster;
btKart *m_vehicle;
btUprightConstraint *m_uprightConstraint;
/** The amount of energy collected by hitting coins. Note that it
* must be float, since dt is subtraced in each timestep. */
@ -342,11 +340,7 @@ public:
virtual Skidding *getSkidding() { return m_skidding; }
// ------------------------------------------------------------------------
/** Returns the bullet vehicle which represents this kart. */
virtual btKart *getVehicle () const {return m_vehicle; }
// ------------------------------------------------------------------------
/** Returns the upright constraint for this kart. */
virtual btUprightConstraint *getUprightConstraint() const
{return m_uprightConstraint;}
virtual btKart *getVehicle() const {return m_vehicle; }
// ------------------------------------------------------------------------
/** Returns the speed of the kart in meters/second. */
virtual float getSpeed() const {return m_speed; }

View File

@ -72,9 +72,8 @@ KartProperties::KartProperties(const std::string &filename)
m_wheel_radius = m_chassis_linear_damping = m_max_suspension_force =
m_chassis_angular_damping = m_suspension_rest =
m_max_speed_reverse_ratio = m_rescue_vert_offset =
m_upright_tolerance = m_collision_terrain_impulse =
m_collision_impulse = m_restitution = m_collision_impulse_time =
m_upright_max_force = m_suspension_travel_cm =
m_collision_terrain_impulse = m_collision_impulse = m_restitution =
m_collision_impulse_time = m_suspension_travel_cm =
m_track_connection_accel = m_rubber_band_max_length =
m_rubber_band_force = m_rubber_band_duration =
m_rubber_band_speed_increase = m_rubber_band_fade_out_time =
@ -367,12 +366,6 @@ void KartProperties::getAllData(const XMLNode * root)
&m_track_connection_accel );
}
if(const XMLNode *upright_node = root->getNode("upright"))
{
upright_node->get("tolerance", &m_upright_tolerance);
upright_node->get("max-force", &m_upright_max_force);
}
if(const XMLNode *collision_node = root->getNode("collision"))
{
collision_node->get("impulse", &m_collision_impulse );
@ -673,8 +666,6 @@ void KartProperties::checkAllSet(const std::string &filename)
CHECK_NEG(m_bevel_factor.getX(), "collision bevel-factor" );
CHECK_NEG(m_bevel_factor.getY(), "collision bevel-factor" );
CHECK_NEG(m_bevel_factor.getZ(), "collision bevel-factor" );
CHECK_NEG(m_upright_tolerance, "upright tolerance" );
CHECK_NEG(m_upright_max_force, "upright max-force" );
CHECK_NEG(m_rubber_band_max_length, "plunger band-max-length" );
CHECK_NEG(m_rubber_band_force, "plunger band-force" );
CHECK_NEG(m_rubber_band_duration, "plunger band-duration" );

View File

@ -328,9 +328,6 @@ private:
/** The restitution factor to be used in collsions for this kart. */
float m_restitution;
float m_upright_tolerance;
float m_upright_max_force;
/** How far behind a kart slipstreaming is effective. */
float m_slipstream_length;
/** How wide the slipstream area is at the end. */
@ -699,15 +696,6 @@ public:
float getExplosionInvulnerabilityTime() const
{ return m_explosion_invulnerability_time; }
// ------------------------------------------------------------------------
/** Returns how much a kart can roll/pitch before the upright constraint
* counteracts. */
float getUprightTolerance () const {return m_upright_tolerance; }
// ------------------------------------------------------------------------
/** Returns the maximum value of the upright counteracting force. */
float getUprightMaxForce () const {return m_upright_max_force; }
// ------------------------------------------------------------------------
/** Returns the maximum length of a rubber band before it breaks. */
float getRubberBandMaxLength () const {return m_rubber_band_max_length;}

View File

@ -854,7 +854,7 @@ int handleCmdLine()
Log::warn("main", "There is no GP named '%s'.", s.c_str());
return 0;
}
race_manager->setGrandPrix(*gp);
race_manager->setGrandPrix(gp);
} // --gp
if(CommandLine::has("--numkarts", &n) ||CommandLine::has("-k", &n))

View File

@ -3,6 +3,8 @@
#include "race/race_manager.hpp"
#include "utils/log.hpp"
#include <stdexcept>
/** \brief Gets the element with the highest count in a std::map<S,int>.
* \param histogram : A pointer to the histogram.
* \return The key of type S that has the highest second value.

View File

@ -1,176 +0,0 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (C) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "physics/btUprightConstraint.hpp"
#include <new>
#include <stdio.h>
#include "BulletDynamics/Dynamics/btRigidBody.h"
#include "LinearMath/btTransformUtil.h"
#include "karts/kart.hpp"
//!
//!
//!
void btUprightConstraint::solveAngularLimit(
btUprightConstraintLimit *limit,
btScalar timeStep, btScalar jacDiagABInv,
btRigidBody * body0 )
{
// Work out if limit is violated
if(limit->m_angle>=m_loLimit && limit->m_angle<=m_hiLimit) return;
limit->m_currentLimitError = (limit->m_angle<m_loLimit)
? limit->m_angle - m_loLimit
: limit->m_angle - m_hiLimit;
btScalar targetVelocity = -m_ERP*limit->m_currentLimitError
/ (3.1415f/8.0f*timeStep);
btScalar maxMotorForce = m_maxLimitForce;
maxMotorForce *= timeStep;
// current velocity difference
btVector3 angularVelocity = body0->getAngularVelocity();
btScalar axisAngularVelocity = limit->m_axis.dot( angularVelocity );
// correction velocity
btScalar motorVelocity = m_limitSoftness*(targetVelocity
- m_damping*axisAngularVelocity);
// correction impulse
btScalar unclippedMotorImpulse = (1+m_bounce)*motorVelocity*jacDiagABInv;
// clip correction impulse
btScalar clippedMotorImpulse = unclippedMotorImpulse;
//todo: should clip against accumulated impulse
if (unclippedMotorImpulse>0.0f)
{
clippedMotorImpulse = unclippedMotorImpulse > maxMotorForce
? maxMotorForce : unclippedMotorImpulse;
}
else
{
clippedMotorImpulse = unclippedMotorImpulse < -maxMotorForce
? -maxMotorForce : unclippedMotorImpulse;
}
// sort with accumulated impulses
btScalar lo = btScalar(-1e30);
btScalar hi = btScalar(1e30);
btScalar oldaccumImpulse = limit->m_accumulatedImpulse;
btScalar sum = oldaccumImpulse + clippedMotorImpulse;
limit->m_accumulatedImpulse = sum > hi ? btScalar(0.)
: sum < lo ? btScalar(0.) : sum;
clippedMotorImpulse = limit->m_accumulatedImpulse - oldaccumImpulse;
btVector3 motorImp = clippedMotorImpulse * limit->m_axis;
body0->applyTorqueImpulse(motorImp);
} // solveAngularLimit
//!
//!
//!
btUprightConstraint::btUprightConstraint(const Kart* kart,
const btTransform& frameInA)
: btTypedConstraint(D6_CONSTRAINT_TYPE, *(kart->getBody()))
, m_frameInA(frameInA)
{
m_kart = kart;
m_ERP = 1.0f;
m_bounce = 0.0f;
m_damping = 1.0f;
m_limitSoftness = 1.0f;
m_maxLimitForce = 3000.0f;
m_disable_time = 0.0f;
m_limit[0].m_accumulatedImpulse = 0.0f;
m_limit[1].m_accumulatedImpulse = 0.0f;
m_limit[ 0 ].m_axis = btVector3( 1, 0, 0 );
m_limit[ 1 ].m_axis = btVector3( 0, 0, 1 );
setLimit( SIMD_PI * 0.4f );
} // btUprightConstraint
//!
//!
//!
void btUprightConstraint::buildJacobian()
{
m_limit[ 0 ].m_angle = m_kart->getPitch();
m_limit[ 1 ].m_angle = -m_kart->getRoll();
for ( int i = 0; i < 2; i++ )
{
new (&m_jacAng[ i ]) btJacobianEntry( m_limit[ i ].m_axis,
m_rbA.getCenterOfMassTransform().getBasis().transpose(),
m_rbB.getCenterOfMassTransform().getBasis().transpose(),
m_rbA.getInvInertiaDiagLocal(),
m_rbB.getInvInertiaDiagLocal());
}
} // buildJacobian
//!
//!
//!
void btUprightConstraint::solveConstraintObsolete(btRigidBody& /*bodyA*/,btRigidBody& /*bodyB*/,btScalar timeStep)
{
m_timeStep = timeStep;
// Update disable time and return if constraint is still disabled
if(m_disable_time>0.0f)
{
m_disable_time -= timeStep;
if(m_disable_time>0.0f) return;
}
solveAngularLimit( &m_limit[ 0 ], m_timeStep, btScalar(1.) / m_jacAng[ 0 ].getDiagonal(), &m_rbA );
solveAngularLimit( &m_limit[ 1 ], m_timeStep, btScalar(1.) / m_jacAng[ 1 ].getDiagonal(), &m_rbA );
} // solveConstraint
void btUprightConstraint::getInfo1(btConstraintInfo1* info) {
info->m_numConstraintRows = 0;
info->nub = 0;
}
void btUprightConstraint::getInfo2(btConstraintInfo2* info) {
}
btScalar btUprightConstraint::getParam(int num, int axis) const
{
return 0;
}
void btUprightConstraint::setParam(int num, btScalar value, int axis)
{
}

View File

@ -1,122 +0,0 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (C) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef HEADER_UPRIGHT_CONSTRAINT_HPP
#define HEADER_UPRIGHT_CONSTRAINT_HPP
#include "LinearMath/btVector3.h"
#include "BulletDynamics/ConstraintSolver/btJacobianEntry.h"
#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h"
class btRigidBody;
class Kart;
/**
* \ingroup physics
*/
class btUprightConstraint : public btTypedConstraint
{
private:
class btUprightConstraintLimit
{
public:
btVector3 m_axis;
btScalar m_angle;
btScalar m_accumulatedImpulse;
btScalar m_currentLimitError;
};
//! relative_frames
//!@{
btTransform m_frameInA;//!< the constraint space w.r.t body A
//!@}
//! Jacobians
//!@{
btJacobianEntry m_jacAng[ 2 ];//!< angular constraint
//!@}
const Kart *m_kart;
protected:
//! temporal variables
//!@{
btScalar m_timeStep;
btScalar m_ERP;
btScalar m_bounce;
btScalar m_damping;
btScalar m_maxLimitForce;
btScalar m_limitSoftness;
btScalar m_hiLimit;
btScalar m_loLimit;
btScalar m_disable_time;
btUprightConstraintLimit m_limit[ 2 ];
//!@}
btUprightConstraint& operator=(btUprightConstraint& other)
{
btAssert(0);
(void) other;
return *this;
}
void buildAngularJacobian(btJacobianEntry & jacAngular,
const btVector3 & jointAxisW);
void solveAngularLimit(btUprightConstraintLimit *limit,
btScalar timeStep, btScalar jacDiagABInv,
btRigidBody * body0 );
public:
btUprightConstraint(const Kart* kart, const btTransform& frameInA);
// -PI,+PI is the full range
// 0,0 is no rotation around x or z
// -PI*0.2,+PI*0.2 is a nice bit of tilt
void setLimit( btScalar range ) { m_loLimit = -range;
m_hiLimit = +range; }
// Error correction scaling
// 0 - 1
void setErp( btScalar erp ) { m_ERP = erp; }
void setBounce( btScalar bounce ) { m_bounce = bounce; }
void setMaxLimitForce( btScalar force ) { m_maxLimitForce = force; }
void setLimitSoftness( btScalar softness ) { m_limitSoftness = softness; }
void setDamping( btScalar damping ) { m_damping = damping; }
void setDisableTime( btScalar t ) { m_disable_time = t; }
virtual void buildJacobian();
virtual void solveConstraintObsolete(btRigidBody& /*bodyA*/,
btRigidBody& /*bodyB*/, btScalar
timeStep);
virtual void getInfo1 (btConstraintInfo1* info);
virtual void getInfo2 (btConstraintInfo2* info);
virtual void setParam(int num, btScalar value, int axis = -1);
virtual btScalar getParam(int num, int axis) const;
};
#endif //UPRIGHT_CONSTRAINT_H

View File

@ -33,7 +33,6 @@
#include "modes/world.hpp"
#include "karts/explosion_animation.hpp"
#include "physics/btKart.hpp"
#include "physics/btUprightConstraint.hpp"
#include "physics/irr_debug_drawer.hpp"
#include "physics/physical_object.hpp"
#include "physics/stk_dynamics_world.hpp"
@ -86,8 +85,8 @@ Physics::~Physics()
// ----------------------------------------------------------------------------
/** Adds a kart to the physics engine.
* This adds the rigid body, the vehicle, and the upright constraint, but only
* if the kart is not already in the physics world.
* This adds the rigid body and the vehicle but only if the kart is not
* already in the physics world.
* \param kart The kart to add.
* \param vehicle The raycast vehicle object.
*/
@ -102,7 +101,6 @@ void Physics::addKart(const AbstractKart *kart)
}
m_dynamics_world->addRigidBody(kart->getBody());
m_dynamics_world->addVehicle(kart->getVehicle());
m_dynamics_world->addConstraint(kart->getUprightConstraint());
} // addKart
//-----------------------------------------------------------------------------
@ -130,7 +128,6 @@ void Physics::removeKart(const AbstractKart *kart)
{
m_dynamics_world->removeRigidBody(kart->getBody());
m_dynamics_world->removeVehicle(kart->getVehicle());
m_dynamics_world->removeConstraint(kart->getUprightConstraint());
}
} // removeKart

View File

@ -24,13 +24,15 @@
#include "config/player_manager.hpp"
#include "io/file_manager.hpp"
#include "io/utf_writer.hpp"
#include "states_screens/dialogs/random_gp_dialog.hpp"
#include "tracks/track_manager.hpp"
#include "tracks/track.hpp"
#include "utils/string_utils.hpp"
#include <iostream>
#include <memory>
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <memory>
#include <stdexcept>
@ -44,6 +46,94 @@ GrandPrixData::GrandPrixData(const std::string& filename)
reload();
}
// ----------------------------------------------------------------------------
GrandPrixData::GrandPrixData(const unsigned int number_of_tracks,
const std::string& track_group,
const RandomGPInfoDialog::REVERSED use_reverse)
{
m_filename = "Random GP - Not loaded from a file!";
m_id = "random";
m_name = "Random Grand Prix";
m_editable = false;
m_tracks.reserve(number_of_tracks);
m_laps.reserve(number_of_tracks);
m_reversed.reserve(number_of_tracks);
changeTrackNumber(number_of_tracks, track_group);
changeReverse(use_reverse);
}
// ----------------------------------------------------------------------------
void GrandPrixData::changeTrackNumber(const unsigned int number_of_tracks,
const std::string& track_group)
{
// The problem with the track groups is that "all" isn't a track group
// TODO: Add "all" to the track groups and rewrite this more elegant
std::vector<int> track_indices;
size_t available_tracks;
if (track_group == "all")
{
available_tracks = track_manager->getNumberOfTracks();
}
else
{
track_indices = track_manager->getTracksInGroup(track_group);
available_tracks = track_indices.size();
}
assert(number_of_tracks <= available_tracks);
// add or remove the right number of tracks
if (m_tracks.size() < number_of_tracks)
{
while (m_tracks.size() < number_of_tracks)
{
int index = (track_group == "all") ?
rand() % available_tracks :
track_indices[rand() % available_tracks];
std::string id = track_manager->getTrack(index)->getIdent();
// Avoid duplicate tracks
if (std::find(m_tracks.begin(), m_tracks.end(), id) != m_tracks.end())
continue;
m_tracks.push_back(id);
m_laps.push_back(3); // TODO: Take the default number from the track
m_reversed.push_back(false); // This will be changed later
}
}
else if (m_tracks.size() > number_of_tracks)
{
while (m_tracks.size() > number_of_tracks)
{
m_tracks.pop_back();
m_laps.pop_back();
m_reversed.pop_back();
}
}
assert(m_tracks.size() == m_laps.size() );
assert(m_laps.size() == m_reversed.size());
}
// ----------------------------------------------------------------------------
void GrandPrixData::changeReverse(const RandomGPInfoDialog::REVERSED use_reverse)
{
for (unsigned int i = 0; i < m_tracks.size(); i++)
{
if (use_reverse == RandomGPInfoDialog::NO_REVERSE)
m_reversed[i] = false;
else if (use_reverse == RandomGPInfoDialog::MIXED)
if (track_manager->getTrack(m_tracks[i])->reverseAvailable())
m_reversed[i] = (rand() % 2!=0);
else
m_reversed[i] = false;
else // all reversed
m_reversed[i] = true;
}
}
// ----------------------------------------------------------------------------
void GrandPrixData::setId(const std::string& id)
{

View File

@ -20,14 +20,15 @@
#ifndef HEADER_GRAND_PRIX_DATA_HPP
#define HEADER_GRAND_PRIX_DATA_HPP
#include <irrString.h>
#include <string>
#include <vector>
#include <cassert>
#include <irrString.h>
#include <stdexcept>
#include "states_screens/dialogs/random_gp_dialog.hpp"
#include "utils/translation.hpp"
using irr::core::stringw;
class Track;
/** Simple class that hold the data relevant to a 'grand_prix', aka. a number
@ -76,6 +77,13 @@ public:
GrandPrixData(const std::string& filename);
/** Needed for simple creation of an instance of GrandPrixData */
GrandPrixData() {};
/** Creates a new random GP */
GrandPrixData(const unsigned int number_of_tracks,
const std::string& track_group,
const RandomGPInfoDialog::REVERSED use_reverse);
void changeTrackNumber(const unsigned int number_of_tracks,
const std::string& track_group);
void changeReverse(const RandomGPInfoDialog::REVERSED use_reverse);
// Methods for the GP editor
void setId(const std::string& id);
@ -117,7 +125,6 @@ public:
// ------------------------------------------------------------------------
/** Returns the filename of the grand prix xml file. */
const std::string& getFilename() const { return m_filename; }
}; // GrandPrixData
#endif

View File

@ -31,6 +31,23 @@ GrandPrixManager *grand_prix_manager = NULL;
const char* GrandPrixManager::SUFFIX = ".grandprix";
// ----------------------------------------------------------------------------
GrandPrixManager::GrandPrixManager()
{
m_random_gp = NULL; // better do it explicitly and avoid weird stuff
loadFiles();
} // GrandPrixManager
// ----------------------------------------------------------------------------
GrandPrixManager::~GrandPrixManager()
{
for(unsigned int i=0; i<m_gp_data.size(); i++)
{
delete m_gp_data[i];
}
delete m_random_gp;
} // ~GrandPrixManager
// ----------------------------------------------------------------------------
void GrandPrixManager::loadFiles()
{
@ -48,7 +65,7 @@ void GrandPrixManager::loadFiles()
if (!dir.empty() && dir[dir.size() - 1] == '/')
loadDir(dir);
}
}
} // loadFiles
// ----------------------------------------------------------------------------
void GrandPrixManager::loadDir(const std::string& dir)
@ -64,7 +81,7 @@ void GrandPrixManager::loadDir(const std::string& dir)
i != result.end(); i++)
if (StringUtils::hasSuffix(*i, SUFFIX))
load(dir + *i);
}
} // loadDir
// ----------------------------------------------------------------------------
void GrandPrixManager::load(const std::string& filename)
@ -92,7 +109,7 @@ void GrandPrixManager::reload()
m_gp_data.clear();
loadFiles();
}
} // reload
// ----------------------------------------------------------------------------
std::string GrandPrixManager::generateId()
@ -118,7 +135,7 @@ std::string GrandPrixManager::generateId()
}
return s.str();
}
} // generateId
// ----------------------------------------------------------------------------
bool GrandPrixManager::existsName(const irr::core::stringw& name) const
@ -128,32 +145,20 @@ bool GrandPrixManager::existsName(const irr::core::stringw& name) const
return true;
return false;
}
// ----------------------------------------------------------------------------
GrandPrixManager::GrandPrixManager()
{
loadFiles();
}
// ----------------------------------------------------------------------------
GrandPrixManager::~GrandPrixManager()
{
for(unsigned int i=0; i<m_gp_data.size(); i++)
{
delete m_gp_data[i];
}
}
} // existsName
// ----------------------------------------------------------------------------
GrandPrixData* GrandPrixManager::getGrandPrix(const std::string& s) const
{
return editGrandPrix(s);
}
} // getGrandPrix
// ----------------------------------------------------------------------------
GrandPrixData* GrandPrixManager::editGrandPrix(const std::string& s) const
{
if (s == "random")
return m_random_gp;
for(unsigned int i=0; i<m_gp_data.size(); i++)
{
if(m_gp_data[i]->getId() == s)
@ -161,7 +166,7 @@ GrandPrixData* GrandPrixManager::editGrandPrix(const std::string& s) const
} // for i in m_gp_data
return NULL;
}
} // editGrandPrix
// ----------------------------------------------------------------------------
void GrandPrixManager::checkConsistency()
@ -194,7 +199,7 @@ GrandPrixData* GrandPrixManager::createNewGP(const irr::core::stringw& newName)
m_gp_data.push_back(gp);
return gp;
}
} // createNewGP
// ----------------------------------------------------------------------------
GrandPrixData* GrandPrixManager::copy(const std::string& id,
@ -214,7 +219,7 @@ GrandPrixData* GrandPrixManager::copy(const std::string& id,
m_gp_data.push_back(gp);
return gp;
}
} // copy
// ----------------------------------------------------------------------------
void GrandPrixManager::remove(const std::string& id)
@ -232,4 +237,4 @@ void GrandPrixManager::remove(const std::string& id)
Log::warn("GrandPrixManager",
"Grand Prix '%s' can not be removed", gp->getId().c_str());
}
}
} // remove

View File

@ -47,6 +47,10 @@ private:
bool existsName(const irr::core::stringw& name) const;
public:
/** saved here by a random GP dialog to avoid dangling pinters or
* memory leaks */
GrandPrixData* m_random_gp;
GrandPrixManager();
~GrandPrixManager();
void reload();

View File

@ -771,9 +771,10 @@ void RaceManager::startGP(const GrandPrixData* gp, bool from_overworld,
bool continue_saved_gp)
{
assert(gp != NULL);
//std::cout << gp->getId();
StateManager::get()->enterGameState();
setGrandPrix(*gp);
setGrandPrix(gp);
setCoinTarget( 0 ); // Might still be set from a previous challenge
race_manager->setupPlayerKartInfo();
m_continue_saved_gp = continue_saved_gp;

View File

@ -331,7 +331,7 @@ private:
int m_coin_target;
bool m_has_time_target;
float m_time_target;
int m_goal_target;
int m_goal_target;
void startNextRace(); // start a next race
@ -344,7 +344,7 @@ private:
bool m_have_kart_last_position_on_overworld;
Vec3 m_kart_last_position_on_overworld;
/** Determines if saved GP should be continued or not*/
bool m_continue_saved_gp;
@ -410,9 +410,9 @@ public:
void setDifficulty(Difficulty diff);
// ------------------------------------------------------------------------
void setGrandPrix(const GrandPrixData &gp)
void setGrandPrix(const GrandPrixData *gp)
{
m_grand_prix = gp;
m_grand_prix = *gp;
m_coin_target = 0;
}
// ------------------------------------------------------------------------
@ -525,7 +525,7 @@ public:
// ------------------------------------------------------------------------
const std::string& getTrackName() const { return m_tracks[m_track_number];}
// ------------------------------------------------------------------------
const GrandPrixData *getGrandPrix() const { return &m_grand_prix; }
const GrandPrixData& getGrandPrix() const { return m_grand_prix; }
// ------------------------------------------------------------------------
unsigned int getFinishedKarts() const { return m_num_finished_karts; }
// ------------------------------------------------------------------------

View File

@ -81,7 +81,7 @@ void EnterGPNameDialog::onEnterPressedInternal()
TextBoxWidget* textCtrl = getWidget<TextBoxWidget>("textfield");
assert(textCtrl != NULL);
stringw name = textCtrl->getText().trim();
if (name.size() > 0)
if (name.size() > 0 && name != "Random Grand Prix")
{
// check for duplicate names
for (unsigned int i = 0; i < grand_prix_manager->getNumberOfGrandPrix(); i++)

View File

@ -28,6 +28,7 @@
#include "guiengine/widgets/label_widget.hpp"
#include "io/file_manager.hpp"
#include "race/grand_prix_manager.hpp"
#include "race/grand_prix_data.hpp"
#include "race/race_manager.hpp"
#include "states_screens/state_manager.hpp"
#include "states_screens/tracks_screen.hpp"
@ -35,143 +36,190 @@
#include "tracks/track_manager.hpp"
#include "utils/translation.hpp"
#include <iostream>
#include <IGUIEnvironment.h>
#include <IGUIStaticText.h>
using namespace irr::gui;
using namespace irr::video;
using namespace irr::core;
using namespace GUIEngine;
using irr::gui::IGUIStaticText;
using GUIEngine::PROP_ID;
// ------------------------------------------------------------------------------------------------------
typedef GUIEngine::LabelWidget Label;
GPInfoDialog::GPInfoDialog(const std::string& gpIdent, const float w, const float h) : ModalDialog(w, h)
const float GPInfoDialog::PERCENT_WIDTH = 0.8f;
const float GPInfoDialog::PERCENT_HEIGHT = 0.7f;
GPInfoDialog::GPInfoDialog(const std::string& gp_ident)
: ModalDialog(PERCENT_WIDTH, PERCENT_HEIGHT)
{
doInit();
m_curr_time = 0.0f;
const int y1 = m_area.getHeight()/7;
const int y2 = m_area.getHeight()*6/7;
m_gp = grand_prix_manager->getGrandPrix(gp_ident);
m_gp->checkConsistency();
m_gp_ident = gpIdent;
m_under_title = m_area.getHeight()/7;
m_over_body = m_area.getHeight()/7;
m_lower_bound = m_area.getHeight()*6/7;
const GrandPrixData* gp = grand_prix_manager->getGrandPrix(gpIdent);
assert (gp != NULL);
addTitle();
addTracks();
addScreenshot();
addButtons();
}
// ---- GP Name
core::rect< s32 > area_top(0, 0, m_area.getWidth(), y1);
IGUIStaticText* title = GUIEngine::getGUIEnv()->addStaticText( translations->fribidize(gp->getName()),
area_top, false, true, // border, word wrap
m_irrlicht_window);
// ----------------------------------------------------------------------------
GPInfoDialog::~GPInfoDialog()
{
GUIEngine::Screen* curr_screen = GUIEngine::getCurrentScreen();
if (curr_screen->getName() == "tracks.stkgui")
static_cast<TracksScreen*>(curr_screen)->setFocusOnGP(m_gp->getId());
}
// ----------------------------------------------------------------------------
void GPInfoDialog::addTitle()
{
core::rect< s32 > area_top(0, 0, m_area.getWidth(), m_under_title);
IGUIStaticText* title = GUIEngine::getGUIEnv()->addStaticText(
translations->fribidize(m_gp->getName()),
area_top, false, true, // border, word wrap
m_irrlicht_window);
title->setTabStop(false);
title->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
title->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
}
// ----------------------------------------------------------------------------
// ---- Track listings
const std::vector<std::string> tracks = gp->getTrackNames();
const int trackAmount = tracks.size();
void GPInfoDialog::addTracks()
{
const std::vector<std::string> tracks = m_gp->getTrackNames();
const unsigned int track_amount = tracks.size();
int height_of_one_line = (y2 - y1)/(trackAmount+1);
const int textHeight = GUIEngine::getFontHeight();
if (height_of_one_line > (int)(textHeight*1.5f)) height_of_one_line = (int)(textHeight*1.5f);
int height_of_one_line = std::min((m_lower_bound - m_over_body)/(track_amount+1),
(unsigned int)(GUIEngine::getFontHeight()*1.5f));
bool gp_ok = true;
for (int t=0; t<trackAmount; t++)
// Count the number of label already existing labels representing a track
unsigned int existing = 0;
for (unsigned int i = 0; i < m_widgets.size(); i++)
{
const int from_y = y1 + height_of_one_line*(t+1);
Track* track = track_manager->getTrack(tracks[t]);
stringw lineText;
if (track == NULL)
{
lineText = L"MISSING : ";
lineText.append( stringw(tracks[t].c_str()) );
gp_ok = false;
}
else
{
lineText = track->getName();
}
LabelWidget* widget = new LabelWidget();
widget->setText(translations->fribidize(lineText), false);
widget->m_x = 20;
widget->m_y = from_y;
widget->m_w = m_area.getWidth()/2 - 20;
widget->m_h = height_of_one_line;
widget->setParent(m_irrlicht_window);
m_widgets.push_back(widget);
widget->add();
// IGUIStaticText* line = GUIEngine::getGUIEnv()->addStaticText( lineText.c_str(),
// entry_area, false , true , // border, word wrap
// m_irrlicht_window);
if (m_widgets.get(i)->m_properties[PROP_ID] == "Track label")
existing++;
}
// ---- Track screenshot
unsigned int reuse = std::min(existing, track_amount);
// m_widgets has the type PtrVector<Widget, HOLD>
unsigned int widgets_iter = 0;
for (unsigned int i = 0; i < reuse; i++)
{
Track* track = track_manager->getTrack(tracks[i]);
m_screenshot_widget = new IconButtonWidget(IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO,
false /* tab stop */, false /* focusable */,
IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE /* Track gives us absolute paths */);
// Find the next widget that is a track label
while (m_widgets.get(widgets_iter)->m_properties[PROP_ID] != "Track label")
widgets_iter++;
Label* widget = dynamic_cast<Label*>(m_widgets.get(widgets_iter));
widget->setText(translations->fribidize(track->getName()), false);
widget->move(20, m_over_body + height_of_one_line*(i+1),
m_area.getWidth()/2 - 20, height_of_one_line);
widgets_iter++;
}
if (existing < track_amount)
{
// There are not enough labels for all the track names, so we have to
// add some more
for (unsigned int i = reuse; i < track_amount; i++)
{
Track* track = track_manager->getTrack(tracks[i]);
assert(track != NULL);
Label* widget = new Label();
widget->m_properties[PROP_ID] = "Track label";
widget->setText(translations->fribidize(track->getName()), false);
widget->setParent(m_irrlicht_window);
m_widgets.push_back(widget);
widget->add();
widget->move(20, m_over_body + height_of_one_line*(i+1),
m_area.getWidth()/2 - 20, height_of_one_line);
}
}
else if (existing > track_amount)
{
// There are label which are not necessary anymore so they're deleted
for (unsigned int i = widgets_iter; i < m_widgets.size(); i++)
{
if (m_widgets.get(i)->m_properties[PROP_ID] == "Track label")
{
m_irrlicht_window->removeChild(m_widgets.get(i)->getIrrlichtElement());
m_widgets.remove(i);
i--;
}
}
}
}
// ----------------------------------------------------------------------------
void GPInfoDialog::addScreenshot()
{
m_screenshot_widget = new GUIEngine::IconButtonWidget(
GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO,
false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE);
// images are saved squared, but must be stretched to 4:3
m_screenshot_widget->setCustomAspectRatio(4.0f / 3.0f);
m_screenshot_widget->m_x = m_area.getWidth()/2;
m_screenshot_widget->m_y = y1;
m_screenshot_widget->m_w = m_area.getWidth()/2;
m_screenshot_widget->m_h = y2 - y1 - 10;
m_screenshot_widget->m_x = m_area.getWidth()/2-20;
m_screenshot_widget->m_y = m_over_body + 10;
Track* track = (tracks.size() == 0 ? NULL : track_manager->getTrack(tracks[0]));
// Scale the picture to the biggest possible size without an overflow
if (m_lower_bound - m_over_body - 20 < m_area.getWidth()/2*3/4)
{
m_screenshot_widget->m_w = (m_lower_bound - m_over_body - 30)*4/3;
m_screenshot_widget->m_h = m_lower_bound - m_over_body - 30;
}
else
{
m_screenshot_widget->m_w = m_area.getWidth()/2;
m_screenshot_widget->m_h = m_area.getWidth()*3/8; // *(3/4)*(1/2)
}
m_screenshot_widget->m_properties[PROP_ICON] = (track != NULL ?
track->getScreenshotFile().c_str() :
file_manager->getAsset(FileManager::GUI,"main_help.png"));
Track* track = track_manager->getTrack(m_gp->getTrackNames()[0]);
m_screenshot_widget->m_properties[GUIEngine::PROP_ICON] = (track->getScreenshotFile().c_str());
m_screenshot_widget->setParent(m_irrlicht_window);
m_screenshot_widget->add();
m_widgets.push_back(m_screenshot_widget);
}
// ----------------------------------------------------------------------------
void GPInfoDialog::addButtons()
{
// ---- Start button
ButtonWidget* okBtn = new ButtonWidget();
ButtonWidget* continueBtn = new ButtonWidget();
GUIEngine::ButtonWidget* okBtn = new GUIEngine::ButtonWidget();
GUIEngine::ButtonWidget* continueBtn = new GUIEngine::ButtonWidget();
SavedGrandPrix* saved_gp = SavedGrandPrix::getSavedGP( StateManager::get()
->getActivePlayerProfile(0)
->getUniqueID(),
gpIdent,
m_gp->getId(),
race_manager->getDifficulty(),
race_manager->getNumberOfKarts(),
race_manager->getNumLocalPlayers());
if (tracks.size() == 0)
{
okBtn->m_properties[PROP_ID] = "cannot_start";
okBtn->setText(_("Sorry, no tracks available"));
}
else if (gp_ok)
{
okBtn->m_properties[PROP_ID] = "start";
okBtn->setText(_("Start Grand Prix"));
okBtn->m_properties[PROP_ID] = "start";
okBtn->setText(_("Start Grand Prix"));
continueBtn->m_properties[PROP_ID] = "continue";
continueBtn->setText(_("Continue"));
}
else
{
okBtn->m_properties[PROP_ID] = "cannot_start";
okBtn->setText(_("This Grand Prix is broken!"));
okBtn->setBadge(BAD_BADGE);
}
continueBtn->m_properties[PROP_ID] = "continue";
continueBtn->setText(_("Continue"));
if (saved_gp && gp_ok)
if (saved_gp)
{
continueBtn->m_x = m_area.getWidth()/2 + 110;
continueBtn->m_y = y2;
continueBtn->m_y = m_lower_bound;
continueBtn->m_w = 200;
continueBtn->m_h = m_area.getHeight() - y2 - 15;
continueBtn->m_h = m_area.getHeight() - m_lower_bound - 15;
continueBtn->setParent(m_irrlicht_window);
m_widgets.push_back(continueBtn);
continueBtn->add();
@ -185,9 +233,9 @@ GPInfoDialog::GPInfoDialog(const std::string& gpIdent, const float w, const floa
okBtn->m_x = m_area.getWidth()/2 - 200;
}
okBtn->m_y = y2;
okBtn->m_y = m_lower_bound;
okBtn->m_w = 400;
okBtn->m_h = m_area.getHeight() - y2 - 15;
okBtn->m_h = m_area.getHeight() - m_lower_bound - 15;
okBtn->setParent(m_irrlicht_window);
m_widgets.push_back(okBtn);
okBtn->add();
@ -195,87 +243,57 @@ GPInfoDialog::GPInfoDialog(const std::string& gpIdent, const float w, const floa
okBtn->getIrrlichtElement()->setTabGroup(false);
okBtn->setFocusForPlayer( PLAYER_ID_GAME_MASTER );
}
// ------------------------------------------------------------------------------------------------------
GPInfoDialog::~GPInfoDialog()
{
// Place focus back on selected GP, in case the dialog was cancelled and we're back to
// the track selection screen after
Screen* curr_screen = GUIEngine::getCurrentScreen();
if (curr_screen->getName() == "tracks.stkgui")
{
((TracksScreen*)curr_screen)->setFocusOnGP(m_gp_ident);
}
}
// ------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void GPInfoDialog::onEnterPressedInternal()
{
// Save the gp identifier, since dismiss will delete this object.
std::string gp_id = m_gp_ident;
// Save the GP id because dismiss() will destroy this instance
std::string gp_id = m_gp->getId();
ModalDialog::dismiss();
// Disable accidentally unlocking of a challenge
PlayerManager::getCurrentPlayer()->setCurrentChallenge("");
race_manager->startGP(grand_prix_manager->getGrandPrix(gp_id), false, false);
}
// ------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------
GUIEngine::EventPropagation GPInfoDialog::processEvent(const std::string& eventSource)
{
if (eventSource == "start")
if (eventSource == "start" || eventSource == "continue")
{
// Save GP identifier, since dismiss will delete this object.
std::string gp_id = m_gp_ident;
std::string gp_id = m_gp->getId();
ModalDialog::dismiss();
race_manager->startGP(grand_prix_manager->getGrandPrix(gp_id), false, false);
race_manager->startGP(grand_prix_manager->getGrandPrix(gp_id), false,
(eventSource == "continue"));
return GUIEngine::EVENT_BLOCK;
}
if (eventSource == "continue")
{
// Save GP identifier, since dismiss will delete this object.
std::string gp_id = m_gp_ident;
ModalDialog::dismiss();
race_manager->startGP(grand_prix_manager->getGrandPrix(gp_id), false, true);
return GUIEngine::EVENT_BLOCK;
}
else if (eventSource == "cannot_start")
{
sfx_manager->quickSound( "anvil" );
}
return GUIEngine::EVENT_LET;
}
// ------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void GPInfoDialog::onUpdate(float dt)
{
const int frameBefore = (int)(m_curr_time / 1.5f);
if (dt == 0)
return; // if nothing changed, return right now
m_curr_time += dt;
int frameAfter = (int)(m_curr_time / 1.5f);
if (frameAfter == frameBefore) return; // if nothing changed, return right now
const GrandPrixData* gp = grand_prix_manager->getGrandPrix(m_gp_ident);
assert(gp != NULL);
const std::vector<std::string> tracks = gp->getTrackNames();
const std::vector<std::string> tracks = m_gp->getTrackNames();
if (frameAfter >= (int)tracks.size())
{
frameAfter = 0;
m_curr_time = 0;
}
Track* track = (tracks.size() == 0 ? NULL :
track_manager->getTrack(tracks[frameAfter]));
std::string fn = track ? track->getScreenshotFile()
: file_manager->getAsset(FileManager::GUI, "main_help.png");
m_screenshot_widget->setImage(fn.c_str(), IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE);
Track* track = track_manager->getTrack(tracks[frameAfter]);
std::string file = track->getScreenshotFile();
typedef GUIEngine::IconButtonWidget Icon;
m_screenshot_widget->setImage(file.c_str(), Icon::ICON_PATH_TYPE_ABSOLUTE);
}
// ------------------------------------------------------------------------------------------------------

View File

@ -20,6 +20,10 @@
#define HEADER_GP_INFO_DIALOG_HPP
#include "guiengine/modaldialog.hpp"
// Don't include grand_prix_data.hpp here or the compilation will fail
class GrandPrixData;
namespace GUIEngine
{
@ -32,23 +36,46 @@ namespace GUIEngine
*/
class GPInfoDialog : public GUIEngine::ModalDialog
{
std::string m_gp_ident;
protected: // Necessary for RandomGPInfoDialog
GUIEngine::IconButtonWidget* m_screenshot_widget;
float m_curr_time;
GrandPrixData* m_gp;
/** height of the separator over the body */
int m_over_body;
/** height of the separator under the titlebar, which is equal to
* m_over_body in a normal GPInfoDialo and lower in RandomGPInfoDialog. */
int m_under_title;
/** height of the seperator over the buttons */
int m_lower_bound;
void addTitle();
/** \brief display all the tracks according to the current gp
* For a normal gp info dialog, it just creates a label for every track.
* But with a random gp info dialog, it tries to reuse as many
* labels as possible by just changing their text. */
void addTracks();
void addScreenshot();
/** display a ok-button and eventually a continue-button */
void addButtons();
/** only used for track_screen.cpp */
GPInfoDialog() : ModalDialog(PERCENT_WIDTH, PERCENT_HEIGHT) {}
private:
static const float PERCENT_WIDTH;
static const float PERCENT_HEIGHT;
public:
/**
* Creates a modal dialog with given percentage of screen width and height
*/
GPInfoDialog(const std::string& gpIdent, const float percentWidth, const float percentHeight);
GPInfoDialog(const std::string& gpIdent);
/** Places the focus back on the selected GP, in the case that the dialog
* was cancelled and we're returning to the track selection screen */
virtual ~GPInfoDialog();
void onEnterPressedInternal();
GUIEngine::EventPropagation processEvent(const std::string& eventSource);
virtual void onUpdate(float dt);
virtual void onUpdate(float dt);
};
#endif

View File

@ -0,0 +1,195 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2014 konstin
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "guiengine/engine.hpp"
#include "guiengine/widgets/icon_button_widget.hpp"
#include "guiengine/widgets/spinner_widget.hpp"
#include "race/grand_prix_manager.hpp"
#include "race/race_manager.hpp"
#include "states_screens/dialogs/random_gp_dialog.hpp"
#include "tracks/track_manager.hpp"
#include <IGUIEnvironment.h>
#include <IGUIStaticText.h>
using irr::core::stringc;
using irr::core::stringw;
using irr::gui::IGUIStaticText;
typedef GUIEngine::SpinnerWidget Spinner;
RandomGPInfoDialog::RandomGPInfoDialog()
{
// Defaults - loading selection from last time frrom a file would be better
m_number_of_tracks = 2; // We can assume that there are at least 2 standard tracks
m_trackgroup = "standard";
m_use_reverse = NO_REVERSE;
doInit();
m_curr_time = 0.0f;
m_under_title = m_area.getHeight()/7;
m_over_body = m_area.getHeight()/7 + SPINNER_HEIGHT + 10; // 10px space
m_lower_bound = m_area.getHeight()*6/7;
// The GP manager is be used to make the GP live longer than this dialog
if (grand_prix_manager->m_random_gp)
{
delete grand_prix_manager->m_random_gp;
grand_prix_manager->m_random_gp = NULL;
}
m_gp = new GrandPrixData(m_number_of_tracks, m_trackgroup, m_use_reverse);
grand_prix_manager->m_random_gp = m_gp;
addTitle();
addSpinners();
addTracks();
addScreenshot();
addButtons();
addRestartButton();
}
// ----------------------------------------------------------------------------
void RandomGPInfoDialog::addSpinners()
{
const int trackgroup_width = 200, laps_with = 150, reverse_width = 200;
const int left = (m_area.getWidth() - trackgroup_width - 150 - 250)/2;
// Trackgroup chooser
Spinner* spinner = new Spinner(false);
spinner->m_properties[GUIEngine::PROP_ID] = "Trackgroup";
spinner->m_properties[GUIEngine::PROP_WRAP_AROUND] = "true";
spinner->setParent(m_irrlicht_window);
m_widgets.push_back(spinner);
spinner->add();
spinner->move(left, m_under_title, trackgroup_width, SPINNER_HEIGHT);
// Fill it with all the track group names
spinner->addLabel("all");
int index_standard;
const std::vector<std::string>& groups = track_manager->getAllTrackGroups();
for (unsigned int i = 0; i < groups.size(); i++)
{
// FIXME: The NULL check is necessary until #1348 on github is fixed
if (groups[i].c_str() != NULL)
{
spinner->addLabel(stringw(groups[i].c_str()));
if(groups[i] == "standard")
index_standard = i+1;
}
}
// The value can only be set here because SpinnerWidget resets the value
// every time a label is added
spinner->setValue(index_standard);
// Number of laps chooser
spinner = new Spinner(false);
spinner->setValue(m_number_of_tracks);
spinner->setMin(1);
spinner->setMax(track_manager->getTracksInGroup("standard").size());
spinner->setParent(m_irrlicht_window);
spinner->m_properties[GUIEngine::PROP_ID] = "Number of tracks";
spinner->m_properties[GUIEngine::PROP_WRAP_AROUND] = "true";
m_widgets.push_back(spinner);
spinner->add();
spinner->move(left + trackgroup_width + 10, m_under_title, laps_with, SPINNER_HEIGHT);
// reverse choose
spinner = new Spinner(false);
spinner->setParent(m_irrlicht_window);
spinner->m_properties[GUIEngine::PROP_ID] = "reverse";
spinner->m_properties[GUIEngine::PROP_WRAP_AROUND] = "true";
m_widgets.push_back(spinner);
spinner->add();
spinner->move(left + trackgroup_width + laps_with + 10, m_under_title, reverse_width, SPINNER_HEIGHT);
spinner->addLabel("no reverse");
spinner->addLabel("all reverse");
spinner->addLabel("mixed");
}
// ----------------------------------------------------------------------------
void RandomGPInfoDialog::addRestartButton()
{
GUIEngine::IconButtonWidget* button = new GUIEngine::IconButtonWidget();
button->setImage("gui/restart.png");
button->setParent(m_irrlicht_window);
button->m_properties[GUIEngine::PROP_ID] = "reload";
m_widgets.push_back(button);
button->add();
button->move(m_area.getWidth() - 20 - 32, 20, 32, 32);
}
// ----------------------------------------------------------------------------
GUIEngine::EventPropagation RandomGPInfoDialog::processEvent(
const std::string& eventSource)
{
if (eventSource == "start")
{
ModalDialog::dismiss();
race_manager->startGP(grand_prix_manager->m_random_gp, false, false);
return GUIEngine::EVENT_BLOCK;
}
else if (eventSource == "Number of tracks")
{
// The old gp can be reused because there's only track deletion/adding
m_number_of_tracks = getWidget<Spinner>("Number of tracks")->getValue();
m_gp->changeTrackNumber(m_number_of_tracks, m_trackgroup);
addTracks();
}
else if (eventSource == "Trackgroup")
{
Spinner* t = getWidget<Spinner>("Trackgroup");
Spinner* s = getWidget<Spinner>("Number of tracks");
m_trackgroup = stringc(t->getStringValue()).c_str();
// Update the maximum for the number of tracks since it's depending on
// the current track. The current value in the Number-of-tracks-spinner
// has to be updated, since otherwise the displayed (and used) value
// can be bigger than the maximum. (Might be a TODO to fix this)
unsigned int max = (m_trackgroup == "all") ?
track_manager->getNumberOfTracks() :
track_manager->getTracksInGroup(m_trackgroup).size();
m_number_of_tracks = std::min(max, m_number_of_tracks);
s->setMax(max);
if (s->getValue() > (signed)max)
s->setValue(max);
delete m_gp;
m_gp = new GrandPrixData(m_number_of_tracks, m_trackgroup, m_use_reverse);
grand_prix_manager->m_random_gp = m_gp;
addTracks();
}
else if (eventSource == "reverse")
{
Spinner* r = getWidget<Spinner>("reverse");
m_use_reverse = static_cast<REVERSED>(r->getValue());
m_gp->changeReverse(m_use_reverse);
}
else if (eventSource == "reload")
{
delete m_gp;
m_gp = new GrandPrixData(m_number_of_tracks, m_trackgroup, m_use_reverse);
grand_prix_manager->m_random_gp = m_gp;
addTracks();
}
return GUIEngine::EVENT_LET;
}

View File

@ -0,0 +1,53 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2014 konstin
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_RANDOM_GP_INFO_DIALOG_HPP
#define HEADER_RANDOM_GP_INFO_DIALOG_HPP
#include "states_screens/dialogs/gp_info_dialog.hpp"
#include <string>
class RandomGPInfoDialog : public GPInfoDialog
{
public:
enum REVERSED
{
NO_REVERSE = 0,
ALL_REVERSE = 1,
MIXED = 2
};
private:
unsigned int m_number_of_tracks;
std::string m_trackgroup;
REVERSED m_use_reverse;
public:
static const int SPINNER_HEIGHT = 40;
RandomGPInfoDialog();
/** Adds a SpinnerWidgets to choose the track groups, one to choose the
* number of tracks and one to choose if the tracks should be raced in
* reverse. The Spinners are centered. */
void addSpinners();
void addRestartButton();
GUIEngine::EventPropagation processEvent(const std::string& eventSource);
};
#endif

View File

@ -1602,6 +1602,11 @@ void KartSelectionScreen::updateKartWidgetModel(uint8_t widget_id,
kart_model.getWheelGraphicsPosition(2) );
w3->addModel( kart_model.getWheelModel(3),
kart_model.getWheelGraphicsPosition(3) );
for (size_t i = 0; i < kart_model.getSpeedWeightedObjectsCount(); i++)
{
const SpeedWeightedObject& obj = kart_model.getSpeedWeightedObject(i);
w3->addModel(obj.m_model, obj.m_position);
}
w3->update(0);
m_kart_widgets[widget_id].m_kart_name

View File

@ -92,7 +92,7 @@ void RaceResultGUI::init()
// Calculate screenshot scrolling parameters
const std::vector<std::string> tracks =
race_manager->getGrandPrix()->getTrackNames();
race_manager->getGrandPrix().getTrackNames();
int n_tracks = tracks.size();
int currentTrack = race_manager->getTrackNumber();
m_start_track = currentTrack;
@ -208,7 +208,7 @@ void RaceResultGUI::enableAllButtons()
void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
const std::string& name, const int playerID)
{
int n_tracks = race_manager->getGrandPrix()->getNumberOfTracks();
int n_tracks = race_manager->getGrandPrix().getNumberOfTracks();
if (name == "up_button" && n_tracks > m_max_tracks && m_start_track > 0)
{
m_start_track--;
@ -1121,7 +1121,7 @@ void RaceResultGUI::enableGPProgress()
status_label->m_h = font_height;
status_label->add();
status_label->setText(_("Track %i/%i", currentTrack + 1,
race_manager->getGrandPrix()->getNumberOfTracks()), true);
race_manager->getGrandPrix().getNumberOfTracks()), true);
addGPProgressWidget(status_label);
y = (status_label->m_y + status_label->m_h + 5);
@ -1316,7 +1316,7 @@ void RaceResultGUI::displayHighScores()
void RaceResultGUI::displayScreenShots()
{
const std::vector<std::string> tracks =
race_manager->getGrandPrix()->getTrackNames();
race_manager->getGrandPrix().getTrackNames();
int currentTrack = race_manager->getTrackNumber();
int n_sshot = 1;

View File

@ -29,6 +29,7 @@
#include "race/grand_prix_manager.hpp"
#include "states_screens/state_manager.hpp"
#include "states_screens/dialogs/gp_info_dialog.hpp"
#include "states_screens/dialogs/random_gp_dialog.hpp"
#include "states_screens/dialogs/track_info_dialog.hpp"
#include "tracks/track.hpp"
#include "tracks/track_manager.hpp"
@ -121,9 +122,16 @@ void TracksScreen::eventCallback(Widget* widget, const std::string& name,
gps_widget->getSelectionIDString(PLAYER_ID_GAME_MASTER);
if (selection == "locked")
{
unlock_manager->playLockSound();
}
else
new GPInfoDialog(selection, 0.8f, 0.7f);
{
if (selection == "Random Grand Prix")
new RandomGPInfoDialog();
else
new GPInfoDialog(selection);
}
}
else if (name == "trackgroups")
{
@ -214,12 +222,13 @@ void TracksScreen::init()
}
}
/*// Random GP - not finished yet
// Random GP
std::vector<std::string> screenshots;
screenshots.push_back("gui/main_help.png");
gps_widget->addAnimatedItem(translations->fribidize("Random"), "Random",
screenshots.push_back(file_manager->getAsset(FileManager::GUI, "main_help.png"));
gps_widget->addAnimatedItem(translations->fribidize("Random Grand Prix"),
"Random Grand Prix",
screenshots, 1.5f, 0,
IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE);*/
IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE);
gps_widget->updateItemDisplay();

View File

@ -523,10 +523,10 @@ void Track::loadTrackInfo()
delete root;
std::string dir = StringUtils::getPath(m_filename);
std::string easter_name = dir+"/easter_eggs.xml";
std::string easter_name = dir + "/easter_eggs.xml";
XMLNode *easter = file_manager->createXMLTree(easter_name);
if(easter)
{
for(unsigned int i=0; i<easter->getNumNodes(); i++)
@ -934,7 +934,7 @@ bool Track::loadMainTrack(const XMLNode &root)
{
mesh = irr_driver->getMesh(full_path);
}
if(!mesh)
{
Log::fatal("track",
@ -1969,7 +1969,7 @@ void Track::loadObjects(const XMLNode* root, const std::string& path, ModelDefin
libroot = library_nodes[name];
create_lod_definitions = false; // LOD definitions are already created, don't create them again
}
scene::ISceneNode* parent = irr_driver->getSceneManager()->addEmptySceneNode();
parent->setPosition(xyz);
parent->setRotation(hpr);