Merged master
This commit is contained in:
commit
be9e9a326d
@ -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);
|
||||
}
|
||||
|
@ -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.);
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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/*")
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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 ¢er, 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 ¢er, 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;
|
||||
|
@ -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 ¢er, 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 ¢er, float mask_radius, unsigned TU_cb, unsigned TU_dtex);
|
||||
};
|
||||
|
||||
class GodFadeShader
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
@ -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" );
|
||||
|
@ -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;}
|
||||
|
@ -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))
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -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++)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
195
src/states_screens/dialogs/random_gp_dialog.cpp
Normal file
195
src/states_screens/dialogs/random_gp_dialog.cpp
Normal 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;
|
||||
}
|
||||
|
53
src/states_screens/dialogs/random_gp_dialog.hpp
Normal file
53
src/states_screens/dialogs/random_gp_dialog.hpp
Normal 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
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user