Merge remote-tracking branch 'origin/master' into hq_mipmap_generator

This commit is contained in:
Benau
2017-03-14 13:06:27 +08:00
21 changed files with 638 additions and 199 deletions

View File

@@ -20,13 +20,16 @@ out vec2 uv;
void main()
{
vec3 test = sin(windDir * (Position.y* 0.5)) * 0.5;
test += cos(windDir) * 0.7;
mat4 new_model_matrix = ModelMatrix;
mat4 new_inverse_model_matrix = InverseModelMatrix;
new_model_matrix[3].xyz += windDir * Color.r;
new_model_matrix[3].xyz += test * Color.r;
// FIXME doesn't seem to make too much difference in pass 2, because this
// affects "nor" which is later only * 0.1 by scattering
new_inverse_model_matrix[3].xyz -= windDir * Color.r;
new_inverse_model_matrix[3].xyz -= test * Color.r;
mat4 ModelViewProjectionMatrix = ProjectionViewMatrix * new_model_matrix;
mat4 TransposeInverseModelView = transpose(InverseViewMatrix * new_inverse_model_matrix);

View File

@@ -41,8 +41,10 @@ flat out sampler2D thirdhandle;
void main()
{
mat4 ModelMatrix = getWorldMatrix(Origin + windDir * Color.r, Orientation, Scale);
mat4 TransposeInverseModelView = transpose(getInverseWorldMatrix(Origin + windDir * Color.r, Orientation, Scale) * InverseViewMatrix);
vec3 test = sin(windDir * (Position.y* 0.5)) * 0.5;
test += cos(windDir) * 0.7;
mat4 ModelMatrix = getWorldMatrix(Origin + test * Color.r, Orientation, Scale);
mat4 TransposeInverseModelView = transpose(getInverseWorldMatrix(Origin + test * Color.r, Orientation, Scale) * InverseViewMatrix);
gl_Position = ProjectionViewMatrix * ModelMatrix * vec4(Position, 1.);
nor = (TransposeInverseModelView * vec4(Normal, 0.)).xyz;
uv = Texcoord;

View File

@@ -40,17 +40,20 @@ flat out uvec2 hdle;
void main(void)
{
vec3 test = sin(windDir * (Position.y* 0.5)) * 0.5;
test += cos(windDir) * 0.7;
mat4 ModelMatrix = getWorldMatrix(Origin, Orientation, Scale);
#ifdef VSLayer
gl_Layer = layer;
gl_Position = ShadowViewProjMatrixes[gl_Layer] * ModelMatrix * vec4(Position + windDir * Color.r, 1.);
gl_Position = ShadowViewProjMatrixes[gl_Layer] * ModelMatrix * vec4(Position + test * Color.r, 1.);
uv = Texcoord;
#ifdef Use_Bindless_Texture
handle = Handle;
#endif
#else
layerId = layer;
gl_Position = ShadowViewProjMatrixes[layerId] * ModelMatrix * vec4(Position + windDir * Color.r, 1.);
gl_Position = ShadowViewProjMatrixes[layerId] * ModelMatrix * vec4(Position + test * Color.r, 1.);
tc = Texcoord;
#ifdef Use_Bindless_Texture
hdle = Handle;

View File

@@ -21,13 +21,17 @@ out int layerId;
void main(void)
{
vec3 test = sin(windDir * (Position.y* 0.5)) * 0.5;
test += cos(windDir) * 0.7;
#ifdef VSLayer
gl_Layer = layer;
uv = Texcoord;
gl_Position = ShadowViewProjMatrixes[gl_Layer] * ModelMatrix * vec4(Position + windDir * Color.r, 1.);
gl_Position = ShadowViewProjMatrixes[gl_Layer] * ModelMatrix * vec4(Position + test * Color.r, 1.);
#else
layerId = layer;
tc = Texcoord;
gl_Position = ShadowViewProjMatrixes[layerId] * ModelMatrix * vec4(Position + windDir * Color.r, 1.);
gl_Position = ShadowViewProjMatrixes[layerId] * ModelMatrix * vec4(Position + test * Color.r, 1.);
#endif
}

View File

@@ -107,3 +107,36 @@ void AnimationBase::update(float dt, Vec3 *xyz, Vec3 *hpr, Vec3 *scale)
}
} // update
// ----------------------------------------------------------------------------
/** Return the time, position and rotation at the specified time. It does not
* update the internal timer as update() does.
* \param dt Time since last call.
* \param xyz Position to be updated.
* \param hpr Rotation to be updated.
*/
void AnimationBase::getAt(float time, Vec3 *xyz, Vec3 *hpr, Vec3 *scale)
{
assert(!std::isnan(time));
// Don't do anything if the animation is disabled
if (!m_playing) return;
for_var_in(Ipo*, curr, m_all_ipos)
{
curr->update(time, xyz, hpr, scale);
}
} // getAt
// ----------------------------------------------------------------------------
/** Returns the derivative at the specified point.
* \param time The time for which to determine the derivative.
* \param xyz Float pointer to store the result.
*/
void AnimationBase::getDerivativeAt(float time, Vec3 *xyz)
{
for_var_in(Ipo*, curr, m_all_ipos)
{
curr->getDerivative(time, xyz);
}
xyz->normalize();
}

View File

@@ -67,8 +67,11 @@ public:
AnimationBase(const XMLNode &node);
AnimationBase(Ipo *ipo);
virtual ~AnimationBase() {}
virtual void update(float dt, Vec3 *xyz=NULL, Vec3 *hpr=NULL,
Vec3 *scale=NULL);
virtual void update(float dt, Vec3 *xyz=NULL, Vec3 *hpr=NULL,
Vec3 *scale=NULL);
virtual void getAt(float time, Vec3 *xyz = NULL, Vec3 *hpr = NULL,
Vec3 *scale = NULL);
virtual void getDerivativeAt(float time, Vec3 *xyz);
/** This needs to be implemented by the inheriting classes. It is called
* once per frame from the track. It has a dummy implementation that
* just asserts so that this class can be instantiated in

View File

@@ -228,7 +228,7 @@ void Ipo::IpoData::approximateBezier(float t0, float t1,
// A more sophisticated estimation might be useful (e.g. taking the
// difference between a linear approximation and the actual bezier
// curve into accound.
if(distance<=2.0f)
if(distance<=0.2f)
return;
// Insert one point at (t0+t1)/2. First split the left part of
@@ -346,7 +346,7 @@ float Ipo::IpoData::get(float time, unsigned int index, unsigned int n)
} // switch
// Keep the compiler happy:
return 0;
} // get
} // IpoData::get
// ----------------------------------------------------------------------------
/** Computes a cubic bezier curve for a given t in [0,1] and four control
@@ -361,6 +361,64 @@ float Ipo::IpoData::getCubicBezier(float t, float p0, float p1,
float b = 3.0f*(p2-p1)-c;
float a = p3 - p0 - c - b;
return ((a*t+b)*t+c)*t+p0;
} // getCubicBezier
// ----------------------------------------------------------------------------
/** Determines the derivative of a IPO at a given point.
* \param time At what time value the derivative is to be computed.
* \param index IpoData is based on 3d data. The index specified which
* value to use (0=x, 1=y, 2=z).
* \param n Curve segment to be used for the computation. It must be correct
* for the specified time value.
*/
float Ipo::IpoData::getDerivative(float time, unsigned int index,
unsigned int n)
{
switch (m_interpolation)
{
case IP_CONST: return 0; // Const --> Derivative is 0
case IP_LINEAR: {
return (m_points[n + 1][index] - m_points[n][index]) /
(m_points[n + 1].getW() - m_points[n].getW());
}
case IP_BEZIER: {
if (n == m_points.size() - 1)
{
// Only const, so derivative is 0
return 0;
}
float t = (time - m_points[n].getW())
/ (m_points[n + 1].getW() - m_points[n].getW());
return getCubicBezierDerivative(t,
m_points [n ][index],
m_handle2[n ][index],
m_handle1[n + 1][index],
m_points [n + 1][index] );
} // case IPBEZIER
default:
Log::warn("Ipo::IpoData", "Incorrect interpolation %d",
m_interpolation);
} // switch
return 0;
} // IpoData::getDerivative
// ----------------------------------------------------------------------------
/** Returns the derivative of a cubic bezier curve for a given t in [0,1] and
* four control points. The curve will go through p0 (t=0).
* \param t The parameter for the bezier curve, must be in [0,1].
* \param p0, p1, p2, p3 The four control points.
*/
float Ipo::IpoData::getCubicBezierDerivative(float t, float p0, float p1,
float p2, float p3) const
{
float c = 3.0f*(p1 - p0);
float b = 3.0f*(p2 - p1) - c;
float a = p3 - p0 - c - b;
// f(t) = ((a*t + b)*t + c)*t + p0;
// = a*t^3 +b*t^2 + c*t + p0
// --> f'(t) = 3*a*t^2 + 2*b*t + c
return (3*a * t + 2*b) * t + c;
} // bezier
// ============================================================================
@@ -471,6 +529,28 @@ void Ipo::update(float time, Vec3 *xyz, Vec3 *hpr,Vec3 *scale)
} // update
// ----------------------------------------------------------------------------
/** Updates the value of m_next_n to point to the right ipo segment based on
* the time.
* \param t Time for which m_next_n needs to be updated.
*/
void Ipo::updateNextN(float time) const
{
time = m_ipo_data->adjustTime(time);
// Time was reset since the last cached value for n,
// reset n to start from the beginning again.
if (time < m_ipo_data->m_points[m_next_n - 1].getW())
m_next_n = 1;
// Search for the first point in the (sorted) array which is greater or equal
// to the current time.
while (m_next_n < m_ipo_data->m_points.size() - 1 &&
time >= m_ipo_data->m_points[m_next_n].getW())
{
m_next_n++;
} // while
} // updateNextN
// ----------------------------------------------------------------------------
/** Returns the interpolated value at the current time (which this objects
* keeps track of).
@@ -484,18 +564,50 @@ float Ipo::get(float time, unsigned int index) const
if(m_next_n==0)
return m_ipo_data->m_points[0][index];
time = m_ipo_data->adjustTime(time);
updateNextN(time);
// Time was reset since the last cached value for n,
// reset n to start from the beginning again.
if(time < m_ipo_data->m_points[m_next_n-1].getW())
m_next_n = 1;
// Search for the first point in the (sorted) array which is greater or equal
// to the current time.
while(m_next_n<m_ipo_data->m_points.size()-1 &&
time >=m_ipo_data->m_points[m_next_n].getW())
m_next_n++;
float rval = m_ipo_data->get(time, index, m_next_n-1);
assert(!std::isnan(rval));
return rval;
} // get
// ----------------------------------------------------------------------------
/** Returns the derivative for any location based curves.
* \param time Time for which the derivative is being computed.
* \param xyz Pointer where the results should be stored.
*/
void Ipo::getDerivative(float time, Vec3 *xyz)
{
// Avoid crash in case that only one point is given for this IPO.
if (m_next_n == 0)
{
// Derivative has no real meaning in case of a single point.
// So just return a dummy value.
xyz->setValue(1, 0, 0);
return;
}
updateNextN(time);
switch (m_ipo_data->m_channel)
{
case Ipo::IPO_LOCX: xyz->setX(m_ipo_data->getDerivative(time, m_next_n, 0)); break;
case Ipo::IPO_LOCY: xyz->setY(m_ipo_data->getDerivative(time, m_next_n, 0)); break;
case Ipo::IPO_LOCZ: xyz->setZ(m_ipo_data->getDerivative(time, m_next_n, 0)); break;
case Ipo::IPO_LOCXYZ:
{
if (xyz)
{
for (unsigned int j = 0; j < 3; j++)
(*xyz)[j] = m_ipo_data->getDerivative(time, j, m_next_n-1);
}
break;
}
default: Log::warn("IPO", "Unexpected channel %d for derivate.",
m_ipo_data->m_channel );
xyz->setValue(1, 0, 0);
break;
} // switch
} // getDerivative

View File

@@ -81,10 +81,12 @@ private:
private:
float getCubicBezier(float t, float p0, float p1,
float p2, float p3) const;
void approximateBezier(float t0, float t1,
const Vec3 &p0, const Vec3 &p1,
const Vec3 &h0, const Vec3 &h2,
unsigned int rec_level = 0);
float getCubicBezierDerivative(float t, float p0, float p1,
float p2, float p3) const;
void approximateBezier(float t0, float t1,
const Vec3 &p0, const Vec3 &p1,
const Vec3 &h0, const Vec3 &h2,
unsigned int rec_level = 0);
public:
IpoData(const XMLNode &curve, float fps, bool reverse);
void readCurve(const XMLNode &node, bool reverse);
@@ -94,6 +96,7 @@ private:
const Vec3 &h1, const Vec3 &h2);
float adjustTime(float time);
float get(float time, unsigned int index, unsigned int n);
float getDerivative(float time, unsigned int index, unsigned int n);
}; // IpoData
// ------------------------------------------------------------------------
@@ -113,6 +116,8 @@ private:
* it is declared mutable). */
mutable unsigned int m_next_n;
void updateNextN(float time) const;
Ipo(const Ipo *ipo);
public:
Ipo(const XMLNode &curve, float fps=25, bool reverse=false);
@@ -120,10 +125,10 @@ public:
Ipo *clone();
void update(float time, Vec3 *xyz=NULL, Vec3 *hpr=NULL,
Vec3 *scale=NULL);
void getDerivative(float time, Vec3 *xyz);
float get(float time, unsigned int index) const;
void setInitialTransform(const Vec3 &xyz, const Vec3 &hpr);
void reset();
// ------------------------------------------------------------------------
/** Returns the raw data points for this IPO. */
const std::vector<Vec3>& getPoints() const { return m_ipo_data->m_points; }

View File

@@ -92,6 +92,7 @@ public:
void setCreationRateAbsolute(float fraction);
void setCreationRateRelative(float f);
int getCreationRate();
float getCreationRateFloat() {return m_min_rate;}
void setPosition(const Vec3 &pos);
void setRotation(const Vec3 &rot);

View File

@@ -337,7 +337,7 @@ core::vector3df getWindDir()
const float time = irr_driver->getDevice()->getTimer()->getTime() / 1000.0f;
GrassShaderProvider *gsp =
(GrassShaderProvider *)Shaders::getCallback(ES_GRASS);
return (gsp->getSpeed() * cos(time)) * vector3df(1., 0., 0.);
return (gsp->getSpeed() * time * vector3df(1., 0., 0.));
} // getWindDir
// ----------------------------------------------------------------------------

View File

@@ -27,30 +27,123 @@
#include "LinearMath/btTransform.h"
CannonAnimation::CannonAnimation(AbstractKart *kart, Ipo *ipo)
: AbstractKartAnimation(kart, "CannonAnimation")
/** The constructor for the cannon animation.
* \param kart The kart to be animated.
* \param ipo The IPO (blender interpolation curve) which the kart
* should follow.
* \param start_left, start_right: Left and right end points of the line
* that the kart just crossed.
* \param end_left, end_right: Left and right end points of the line at
* which the kart finishes.
* \param skid_rot Visual rotation of the kart due to skidding (while this
* value can be queried, the AbstractkartAnimation constructor
* resets the value to 0, so it needs to be passed in.
*/
CannonAnimation::CannonAnimation(AbstractKart *kart, Ipo *ipo,
const Vec3 &start_left, const Vec3 &start_right,
const Vec3 &end_left, const Vec3 &end_right,
float skid_rot)
: AbstractKartAnimation(kart, "CannonAnimation")
{
m_curve = new AnimationBase(ipo);
m_timer = ipo->getEndTime();
// First make sure that left and right points are indeed correct
// -------------------------------------------------------------
Vec3 my_start_left = start_left;
Vec3 my_start_right = start_right;
Vec3 p0, p1;
// Define a plane that goes through the middle of the start line
// (the curve's origin must be in the middle of the line.
m_curve->getAt(0, &p0);
m_curve->getAt(0.1f, &p1);
Vec3 p2 = 0.5f*(p0 + p1) + m_kart->getNormal();
if (start_left.sideofPlane(p0, p1, p2) < 0)
{
// Left and right start line needs to be swapped
my_start_left = start_right;
my_start_right = start_left;
}
// First adjust start and end points to take on each side half the kart
// width into account:
Vec3 direction = my_start_right - my_start_left;
direction.normalize();
float kw = m_kart->getKartModel()->getWidth();
Vec3 adj_start_left = my_start_left + (0.5f*kw) * direction;
Vec3 adj_start_right = my_start_right - (0.5f*kw) * direction;
// Store the length of the start and end line, which is used
// during update() to adjust the distance to center
m_start_line_length = (adj_start_left - adj_start_right).length();
m_end_line_length = (end_left - end_right).length() - kw;
// The current kart position is divided into three components:
// kart.xyz = curve.xyz + parallel_to_start_line_component + rest
// 1) curve.xyz: The point at the curve at t=0.
// 2) parallel_to_start_line_component:
// A component parallel to the start line. This component is scaled
// depending on time and length of start- and end-line (e.g. if the
// end line is twice as long as the start line, this will make sure
// that a kart starting at the very left of the start line will end
// up at the very left of the end line). This component can also be
// adjusted by steering while in the air. This is done by modifying
// m_fraction_of_line, which is multiplied with the current width
// vector.
// 3) rest: The amoount that the kart is ahead and above the
// start line. This is stored in m_delta and will be added to the
// newly computed curve xyz coordinates.
//
// Compute the delta between the kart position and the start of the curve.
// This delta is rotated with the kart and added to the interpolated curve
// position to get the actual kart position during the animation.
m_curve->update(0, &m_previous_orig_xyz);
m_delta = kart->getXYZ() - m_previous_orig_xyz;
Vec3 curve_xyz;
m_curve->update(0, &curve_xyz);
m_delta = kart->getXYZ() - curve_xyz;
// Compute on which fraction of the start line the kart is, to get the
// second component of the kart position: distance along start line
Vec3 v = adj_start_left - adj_start_right;
float l = v.length();
v /= l;
float f = v.dot(adj_start_left - kart->getXYZ());
if (f <= 0)
f = 0;
else if (f >= l)
f = l;
else
f = f / l;
// Now f is in [0,1] - 0 in case of left side, 1 if the kart is at the
// very right. Convert this to [-1,1] assuming that the ipo for the
// cannon is in the middle of the start and end line
m_fraction_of_line = 2.0f*f - 1.0f;
Vec3 delta = 0.5f*m_fraction_of_line * (adj_start_right - adj_start_left);
// Subtract the horizontal difference, to get the constant offset the
// kart has from the curve.
m_delta = m_delta - delta;
// Compute the original heading of the kart. At the end of the cannon,
// the kart should be parallel to the curve, but at the beginning it
// the kart should be parallel to the curve and facing forwards, but
// at the beginning it might not be. The initial rotation between the
// tangent of the curce and the kart is stored as a m_delta_heading,
// which will be applied to the curve orientation in update, but reduced
// over time till it becomes 0 at the end of the curve. The effect is that
// initially (t=0) the kart will keep its (non-orhtogonal) rotation,
// but smoothly this will adjusted until at the end the kart will be
// facing forwards again.
Vec3 tangent;
m_curve->getDerivativeAt(0, &tangent);
// Get the current kart orientation
Vec3 forward = m_kart->getTrans().getBasis().getColumn(2);
Vec3 v1(tangent), v2(forward);
v1.setY(0); v2.setY(0);
m_delta_heading = shortestArcQuatNormalize2(v1, v2)
* btQuaternion(Vec3(0,1,0), skid_rot);
// Now the delta vector needs to be rotated back, so that it will point
// in the right direction when it is (in update) rotated to be the same
// as the kart's heading. To estimate the angle at the start, use the
// interpolated value at t=dt:
const float dt = 0.1f;
Vec3 xyz1;
m_curve->update(dt, &xyz1);
core::vector3df rot = (m_previous_orig_xyz-xyz1).toIrrVector()
.getHorizontalAngle();
btQuaternion q(Vec3(0,1,0),rot.Y*DEGREE_TO_RAD);
btMatrix3x3 m(q);
m_delta = m * m_delta;
// The previous call to m_curve->update will set the internal timer
// of the curve to dt. Reset it to 0 to make sure the timer is in
@@ -63,11 +156,7 @@ CannonAnimation::~CannonAnimation()
{
delete m_curve;
btTransform pos;
pos.setOrigin(m_kart->getXYZ());
pos.setRotation(btQuaternion(btVector3(0.0f, 1.0f, 0.0f),
m_kart->getHeading() ));
btTransform pos = m_kart->getTrans();
m_kart->getBody()->setCenterOfMassTransform(pos);
Vec3 v(0, 0, m_kart->getKartProperties()->getEngineMaxSpeed());
m_kart->setVelocity(pos.getBasis()*v);
@@ -86,26 +175,77 @@ void CannonAnimation::update(float dt)
return;
}
Vec3 xyz;
m_curve->update(dt, &xyz);
// First compute the current rotation
// ==================================
// Get the tangent = derivative at the current point to compute the
// new orientation of the kart
Vec3 tangent;
m_curve->getDerivativeAt(m_curve->getAnimationDuration() - m_timer,
&tangent);
// Get the current kart orientation
Vec3 forward = m_kart->getTrans().getBasis().getColumn(2);
// Heading
// -------
// I tried to also adjust pitch at the same time, but that adds a strong
// roll to the kart on some cannons while it is in the air (caused by
// the rotation axis returned shortestArc not being orthogonal to the
// up vector).
Vec3 v1(tangent), v2(forward);
v1.setY(0); v2.setY(0);
btQuaternion heading = shortestArcQuatNormalize2(v2, v1);
// It can happen that the same position is returned, e.g. if the end of
// the curve is reached, but due to floating point differences the
// end is not detected in the above test. To avoid that the kart then
// rotates to a heading of 0, do not rotate in this case at all, i.e.
// the previous rotation is kept.
if(xyz!=m_previous_orig_xyz)
{
btQuaternion prev_rot = m_kart->getRotation();
core::vector3df rot = (xyz-m_previous_orig_xyz).toIrrVector()
.getHorizontalAngle();
btQuaternion q(Vec3(0,1,0),rot.Y*DEGREE_TO_RAD);
m_kart->setRotation(prev_rot.slerp(q,0.1f));
}
m_previous_orig_xyz = xyz;
// Align to up-vector
// ------------------
// While start and end line have to have the same 'up' vector, karts can
// sometimes be not parallel to them. So slowly adjust this over time
Vec3 up = m_kart->getTrans().getBasis().getColumn(1);
up.normalize();
Vec3 gravity = -m_kart->getBody()->getGravity();
gravity.normalize();
// Adjust only 5% towards the real up vector. This will smoothly
// adjust the kart while the kart is in the air
Vec3 target_up_vector = (gravity*0.05f + up*0.95f).normalize();
btQuaternion q_up = shortestArcQuat(up, target_up_vector);
Vec3 rotated_delta = m_kart->getTrans().getBasis()*m_delta;
m_kart->setXYZ(xyz + rotated_delta);
// Additional kart rotation
// ------------------------
// Apply any additional rotation the kart had when crossing the start
// line. This rotation will be reduced the closer the kart gets to
// the end line, with the result that at the start line the kart will
// be not rotated at all (so the visuals from physics to cannon will
// be smoothed), and at the end line the kart will face in the
// forward direction.
// The timer counts backwards, so the fraction goes from 1 to 0
float f = m_timer / m_curve->getAnimationDuration();
btQuaternion zero(gravity, 0);
btQuaternion current_delta_heading = zero.slerp(m_delta_heading, f);
btQuaternion all_heading = m_kart->getRotation()*current_delta_heading*heading;
m_kart->setRotation(q_up * all_heading);
// Then compute the new location of the kart
// -----------------------------------------
float f_current_width = m_start_line_length * f
+ m_end_line_length * (1.0f - f);
// Adjust the horizontal location based on steering
m_fraction_of_line += m_kart->getSteerPercent()*dt*2.0f;
btClamp(m_fraction_of_line, -1.0f, 1.0f);
// horiz_delta is in kart coordinates, the rotation by q will
// transform it to the global coordinate system
Vec3 horiz_delta = Vec3(0.5f*m_fraction_of_line * f_current_width, 0, 0);
Vec3 rotated_delta = quatRotate(all_heading, m_delta + horiz_delta);
Vec3 curve_xyz;
m_curve->update(dt, &curve_xyz);
m_kart->setXYZ(curve_xyz+rotated_delta);
AbstractKartAnimation::update(dt);
} // update

View File

@@ -22,15 +22,18 @@
#include "karts/abstract_kart_animation.hpp"
#include "utils/vec3.hpp"
/** This animation shoots the kart to a specified point on the track.
*
* \ingroup karts
*/
#include "LinearMath/btQuaternion.h"
class AbstractKart;
class AnimationBase;
class Ipo;
/** This animation shoots the kart to a specified point on the track.
*
* \ingroup karts
*/
class CannonAnimation: public AbstractKartAnimation
{
protected:
@@ -43,12 +46,26 @@ protected:
/** Stores the curve interpolation for the cannon. */
AnimationBase *m_curve;
/** This stores the original (unmodified) interpolated curve value. THis
* is used to determine the orientation of the kart. */
Vec3 m_previous_orig_xyz;
/** Length of the (adjusted, i.e. taking kart width into account)
* start line. */
float m_start_line_length;
/** Length of the (adjusted, i.e. taking kart width into account)
* end line. */
float m_end_line_length;
/** Stores the position of the kart relative to the line width
* at the current location. */
float m_fraction_of_line;
/** The initial heading of the kart when crossing the line. This is
* used to smoothly orient the kart towards the normal of the cuve. */
btQuaternion m_delta_heading;
public:
CannonAnimation(AbstractKart *kart, Ipo *ipo);
CannonAnimation(AbstractKart *kart, Ipo *ipo,
const Vec3 &start_left, const Vec3 &start_right,
const Vec3 &end_left, const Vec3 &end_right,
float skid_rot);
virtual ~CannonAnimation();
virtual void update(float dt);

View File

@@ -153,6 +153,7 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id,
m_reset_transform = init_transform;
m_speed = 0.0f;
m_smoothed_speed = 0.0f;
m_last_factor_engine_sound = 0.0f;
m_kart_model->setKart(this);
@@ -1225,7 +1226,19 @@ void Kart::update(float dt)
}
}
// Update the position and other data taken from the physics
// This is to avoid a rescue immediately after an explosion
const bool has_animation_before = m_kart_animation != NULL;
// A kart animation can change the xyz position. This needs to be done
// before updating the graphical position (which is done in
// Moveable::update() ), otherwise 'stuttering' can happen (caused by
// graphical and physical position not being the same).
if (has_animation_before)
{
m_kart_animation->update(dt);
}
// Update the position and other data taken from the physics (or
// an animation which calls setXYZ(), which also updates the kart
// physical position).
Moveable::update(dt);
Vec3 front(0, 0, getKartLength()*0.5f);
@@ -1309,9 +1322,6 @@ void Kart::update(float dt)
// Used to prevent creating a rescue animation after an explosion animation
// got deleted
const bool has_animation_before = m_kart_animation!= NULL;
if(has_animation_before)
m_kart_animation->update(dt);
m_attachment->update(dt);
@@ -1375,6 +1385,7 @@ void Kart::update(float dt)
fabs(getSpeed()) < 3.0f)
{
new RescueAnimation(this, /*is_auto_rescue*/true);
m_last_factor_engine_sound = 0.0f;
}
}
@@ -1439,7 +1450,10 @@ void Kart::update(float dt)
if((min->getY() - getXYZ().getY() > 17 || dist_to_sector > 25) && !m_flying &&
!getKartAnimation())
{
new RescueAnimation(this);
m_last_factor_engine_sound = 0.0f;
}
}
else
{
@@ -1458,7 +1472,10 @@ void Kart::update(float dt)
} // if !flying
handleMaterialSFX(material);
if (material->isDriveReset() && isOnGround())
{
new RescueAnimation(this);
m_last_factor_engine_sound = 0.0f;
}
else if(material->isZipper() && isOnGround())
{
handleZipper(material);
@@ -2094,6 +2111,7 @@ void Kart::crashed(const Material *m, const Vec3 &normal)
if (m->getCollisionReaction() == Material::RESCUE)
{
new RescueAnimation(this);
m_last_factor_engine_sound = 0.0f;
}
else if (m->getCollisionReaction() == Material::PUSH_BACK)
{
@@ -2285,7 +2303,7 @@ void Kart::updatePhysics(float dt)
m_max_speed->update(dt);
updateEngineSFX();
updateEngineSFX(dt);
#ifdef XX
Log::info("Kart","angVel %f %f %f heading %f suspension %f %f %f %f"
,m_body->getAngularVelocity().getX()
@@ -2304,7 +2322,7 @@ void Kart::updatePhysics(float dt)
//-----------------------------------------------------------------------------
/** Adjust the engine sound effect depending on the speed of the kart.
*/
void Kart::updateEngineSFX()
void Kart::updateEngineSFX(float dt)
{
// when going faster, use higher pitch for engine
if(!m_engine_sound || !SFXManager::get()->sfxAllowed())
@@ -2312,7 +2330,7 @@ void Kart::updateEngineSFX()
if(isOnGround())
{
float max_speed = m_max_speed->getCurrentMaxSpeed();
float max_speed = m_kart_properties->getEngineMaxSpeed();
// Engine noise is based half in total speed, half in fake gears:
// With a sawtooth graph like /|/|/| we get 3 even spaced gears,
@@ -2320,20 +2338,23 @@ void Kart::updateEngineSFX()
// good enough brrrBRRRbrrrBRRR sound effect. Speed factor makes
// it a "staired sawtooth", so more acoustically rich.
float f = max_speed > 0 ? m_speed/max_speed : 1.0f;
// Speed at this stage is not yet capped, so it can be > 1, which
// results in odd engine sfx.
if (f>1.0f) f=1.0f;
// Speed at this stage is not yet capped, reduce the amount beyond 1
if (f> 1.0f) f = 1.0f + (1.0f-1.0f/f);
float gears = 3.0f * fmod(f, 0.333334f);
float fc = f;
if (fc>1.0f) fc = 1.0f;
float gears = 3.0f * fmod(fc, 0.333334f);
assert(!std::isnan(f));
m_engine_sound->setSpeedPosition(0.6f + (f + gears) * 0.35f, getXYZ());
m_last_factor_engine_sound = (0.9*f + gears) * 0.35f;
m_engine_sound->setSpeedPosition(0.6f + m_last_factor_engine_sound, getXYZ());
}
else
{
// When flying, fixed value but not too high pitch
// This gives some variation (vs previous "on wheels" one)
m_engine_sound->setSpeedPosition(0.9f, getXYZ());
}
{
// When flying, reduce progressively the sound engine (since we can't accelerate)
m_last_factor_engine_sound *= (1.0f-0.1*dt);
m_engine_sound->setSpeedPosition(0.6f + m_last_factor_engine_sound, getXYZ());
if (m_speed < 0.1f) m_last_factor_engine_sound = 0.0f;
}
} // updateEngineSFX
//-----------------------------------------------------------------------------

View File

@@ -201,6 +201,9 @@ protected:
/** For camera handling an exponentially smoothened value is used, which
* reduces stuttering of the camera. */
float m_smoothed_speed;
/** For smoothing engine sound**/
float m_last_factor_engine_sound;
std::vector<SFXBase*> m_custom_sounds;
SFXBase *m_beep_sound;
@@ -226,7 +229,7 @@ protected:
void updateFlying();
void updateSliding();
void updateEnginePowerAndBrakes(float dt);
void updateEngineSFX();
void updateEngineSFX(float dt);
void updateSpeed();
void updateNitro(float dt);
float getActualWheelForce();

View File

@@ -38,6 +38,14 @@
KartGFX::KartGFX(const AbstractKart *kart, RaceManager::KartType type, bool is_day)
{
m_nitro_light = NULL;
m_skidding_light_1 = NULL;
m_skidding_light_2 = NULL;
m_head_light = NULL;
m_kart = kart;
m_wheel_toggle = 0;
m_skid_level = 0;
//if(!UserConfigParams::m_graphical_effects)
//{
// for(unsigned int i=0; i<KGFX_COUNT; i++)
@@ -45,69 +53,52 @@ KartGFX::KartGFX(const AbstractKart *kart, RaceManager::KartType type, bool is_d
// return;
//}
m_kart = kart;
const KartModel *km = m_kart->getKartModel();
const float length = km->getLength();
scene::ISceneNode *node = m_kart->getNode();
// Create nitro light
core::vector3df location(0.0f, 0.5f, -0.5f*length - 0.05f);
#ifndef SERVER_ONLY
m_nitro_light = irr_driver->addLight(location, /*force*/ 0.4f,
/*radius*/CVS->isGLSL() ? 5.0f : 1.0f,
0.0f, 0.4f, 1.0f,
false, node);
m_nitro_light->setVisible(false);
#ifdef DEBUG
m_nitro_light->setName( ("nitro emitter (" + m_kart->getIdent()
+ ")").c_str() );
#endif
// Create skidding lights
// For the first skidding level
m_skidding_light_1 =
irr_driver->addLight(core::vector3df(0.0f, 0.1f, -0.5f*length - 0.05f),
/* force */ 0.3f,
/*radius*/CVS->isGLSL() ? 3.0f : 1.0f,
1.0f, 0.6f, 0.0f, false, node);
m_skidding_light_1->setVisible(false);
m_skidding_light_1->setName( ("skidding emitter 1 (" + m_kart->getIdent()
+ ")").c_str() );
// For the second skidding level
m_skidding_light_2 =
irr_driver->addLight(core::vector3df(0.0f, 0.1f, -0.5f*length - 0.05f),
/* force */0.4f,
/*radius*/CVS->isGLSL() ? 4.0f : 1.0f,
1.0f, 0.0f, 0.0f, false, node);
m_skidding_light_2->setVisible(false);
m_skidding_light_2->setName( ("skidding emitter 2 (" + m_kart->getIdent()
+ ")").c_str() );
m_head_light =
irr_driver->addLight(core::vector3df(0.0f, 0.2f, 1.5f*length),
/* force */ 0.5f,
/*radius*/CVS->isGLSL() ? 5.0f : 1.0f,
1.0f, 1.0f, 1.0f, false, node);
m_head_light->setName( ("head light " + m_kart->getIdent()
+ ")").c_str() );
if (type == RaceManager::KT_PLAYER && !is_day)
{
m_head_light->setVisible(true);
}
else
{
m_head_light->setVisible(false);
}
#endif
#ifndef SERVER_ONLY
if (CVS->isGLSL())
{
m_nitro_light = irr_driver->addLight(location, /*force*/ 0.4f,
/*radius*/ 5.0f, 0.0f, 0.4f, 1.0f,
false, node);
m_nitro_light->setVisible(false);
#ifdef DEBUG
m_nitro_light->setName( ("nitro emitter (" + m_kart->getIdent()
+ ")").c_str() );
#endif
// Create skidding lights
// For the first skidding level
m_skidding_light_1 =
irr_driver->addLight(core::vector3df(0.0f, 0.1f, -0.5f * length -
0.05f), /* force */ 0.3f, /*radius*/ 3.0f,
1.0f, 0.6f, 0.0f, false, node);
m_skidding_light_1->setVisible(false);
m_skidding_light_1->setName(("skidding emitter 1 (" + m_kart->getIdent()
+ ")").c_str() );
// For the second skidding level
m_skidding_light_2 =
irr_driver->addLight(core::vector3df(0.0f, 0.1f, -0.5f * length -
0.05f), /* force */0.4f, /*radius*/4.0f,
1.0f, 0.0f, 0.0f, false, node);
m_skidding_light_2->setVisible(false);
m_skidding_light_2->setName(("skidding emitter 2 (" + m_kart->getIdent()
+ ")").c_str() );
m_head_light =
irr_driver->addLight(core::vector3df(0.0f, 0.2f, 1.5f * length),
/* force */ 0.5f, /*radius*/5.0f, 1.0f, 1.0f,
1.0f, false, node);
m_head_light->setName( ("head light " + m_kart->getIdent()
+ ")").c_str() );
m_head_light->setVisible(type == RaceManager::KT_PLAYER && !is_day);
m_nitro_light->grab();
m_skidding_light_1->grab();
m_skidding_light_2->grab();
@@ -182,7 +173,7 @@ void KartGFX::addEffect(KartGFXType type, const std::string &file_name,
const Vec3 &position, bool important)
{
#ifndef SERVER_ONLY
if (!UserConfigParams::m_graphical_effects &&
if ((!UserConfigParams::m_graphical_effects || !CVS->isGLSL()) &&
(!important || m_kart->getType() == RaceManager::KT_AI ||
m_kart->getType() == RaceManager::KT_SPARE_TIRE))
{
@@ -257,6 +248,7 @@ void KartGFX::setSkidLevel(const unsigned int level)
{
assert(level >= 1);
assert(level <= 2);
m_skid_level = level;
const ParticleKind *pk = level==1 ? m_skid_kind1 : m_skid_kind2;
#ifndef SERVER_ONLY
if(m_all_emitters[KGFX_SKID1L])
@@ -309,8 +301,13 @@ void KartGFX::setXYZ(const KartGFXType type, const Vec3 &xyz)
void KartGFX::setCreationRateAbsolute(KartGFXType type, float f)
{
#ifndef SERVER_ONLY
if(m_all_emitters[type])
m_all_emitters[type]->setCreationRateAbsolute(f);
if (!m_all_emitters[type])
return;
if (m_all_emitters[type]->getCreationRateFloat() == f)
return;
m_all_emitters[type]->setCreationRateAbsolute(f);
#endif
} // setCreationRateAbsolute
@@ -428,7 +425,9 @@ void KartGFX::updateNitroGraphics(float nitro_frac)
setCreationRateRelative(KartGFX::KGFX_NITRO2, nitro_frac);
setCreationRateRelative(KartGFX::KGFX_NITROSMOKE1, nitro_frac);
setCreationRateRelative(KartGFX::KGFX_NITROSMOKE2, nitro_frac);
m_nitro_light->setVisible(true);
if (CVS->isGLSL())
m_nitro_light->setVisible(true);
}
else
{
@@ -436,15 +435,14 @@ void KartGFX::updateNitroGraphics(float nitro_frac)
setCreationRateAbsolute(KartGFX::KGFX_NITRO2, 0);
setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE1, 0);
setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE2, 0);
m_nitro_light->setVisible(false);
if (CVS->isGLSL())
m_nitro_light->setVisible(false);
}
if (CVS->isGLSL())
{
// Exhaust is always emitting
setCreationRateRelative(KartGFX::KGFX_EXHAUST1, 1.0);
setCreationRateRelative(KartGFX::KGFX_EXHAUST2, 1.0);
}
// Exhaust is always emitting
setCreationRateRelative(KartGFX::KGFX_EXHAUST1, 1.0);
setCreationRateRelative(KartGFX::KGFX_EXHAUST2, 1.0);
#endif
} // updateGraphics
@@ -456,8 +454,11 @@ void KartGFX::updateNitroGraphics(float nitro_frac)
void KartGFX::updateSkidLight(unsigned int level)
{
#ifndef SERVER_ONLY
m_skidding_light_1->setVisible(level == 1);
m_skidding_light_2->setVisible(level > 1);
if (CVS->isGLSL())
{
m_skidding_light_1->setVisible(level == 1);
m_skidding_light_2->setVisible(level > 1);
}
#endif
} // updateSkidLight
@@ -484,7 +485,7 @@ void KartGFX::getGFXStatus(int* nitro, bool* zipper,
if (m_all_emitters[KGFX_SKIDL])
{
s = m_all_emitters[KGFX_SKIDL]->getCreationRate();
r = m_skidding_light_2->isVisible();
r = m_skid_level == 2;
}
*nitro = n;
@@ -505,15 +506,19 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper,
setCreationRateAbsolute(KartGFX::KGFX_NITRO2, (float)nitro);
setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE1, (float)nitro);
setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE2, (float)nitro);
m_nitro_light->setVisible(true);
if (CVS->isGLSL())
m_nitro_light->setVisible(true);
}
else if (m_nitro_light->isVisible() && nitro == 0)
else
{
setCreationRateAbsolute(KartGFX::KGFX_NITRO1, 0.0f);
setCreationRateAbsolute(KartGFX::KGFX_NITRO2, 0.0f);
setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE1, 0.0f);
setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE2, 0.0f);
m_nitro_light->setVisible(false);
if (CVS->isGLSL())
m_nitro_light->setVisible(false);
}
if (zipper)
@@ -521,36 +526,33 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper,
if (skidding > 0)
{
if (!m_skidding_light_1->isVisible() && !red_skidding)
{
if (m_all_emitters[KGFX_SKID1L])
m_all_emitters[KGFX_SKID1L]->setParticleType(m_skid_kind1);
if (m_all_emitters[KGFX_SKID1R])
m_all_emitters[KGFX_SKID1R]->setParticleType(m_skid_kind1);
const ParticleKind* skid_kind = red_skidding ? m_skid_kind2
: m_skid_kind1;
m_skidding_light_1->setVisible(true);
m_skidding_light_2->setVisible(false);
}
if (!m_skidding_light_2->isVisible() && red_skidding)
{
if (m_all_emitters[KGFX_SKID1L])
m_all_emitters[KGFX_SKID1L]->setParticleType(m_skid_kind2);
if (m_all_emitters[KGFX_SKID1R])
m_all_emitters[KGFX_SKID1R]->setParticleType(m_skid_kind2);
if (m_all_emitters[KGFX_SKID1L])
m_all_emitters[KGFX_SKID1L]->setParticleType(skid_kind);
if (m_all_emitters[KGFX_SKID1R])
m_all_emitters[KGFX_SKID1R]->setParticleType(skid_kind);
m_skidding_light_1->setVisible(false);
m_skidding_light_2->setVisible(true);
if (CVS->isGLSL())
{
m_skidding_light_1->setVisible(!red_skidding);
m_skidding_light_2->setVisible(red_skidding);
}
setCreationRateAbsolute(KartGFX::KGFX_SKIDL, (float)skidding);
setCreationRateAbsolute(KartGFX::KGFX_SKIDR, (float)skidding);
}
else if ((m_skidding_light_1->isVisible() ||
m_skidding_light_2->isVisible()) && skidding == 0)
else
{
setCreationRateAbsolute(KartGFX::KGFX_SKIDL, 0.0f);
setCreationRateAbsolute(KartGFX::KGFX_SKIDR, 0.0f);
m_skidding_light_1->setVisible(false);
m_skidding_light_2->setVisible(false);
if (CVS->isGLSL())
{
m_skidding_light_1->setVisible(false);
m_skidding_light_2->setVisible(false);
}
}
#endif
} // setGFXFromReplay
@@ -559,9 +561,12 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper,
void KartGFX::setGFXInvisible()
{
#ifndef SERVER_ONLY
m_nitro_light->setVisible(false);
m_skidding_light_1->setVisible(false);
m_skidding_light_2->setVisible(false);
m_head_light->setVisible(false);
if (CVS->isGLSL())
{
m_nitro_light->setVisible(false);
m_skidding_light_1->setVisible(false);
m_skidding_light_2->setVisible(false);
m_head_light->setVisible(false);
}
#endif
} // setGFXInvisible

View File

@@ -77,6 +77,9 @@ private:
/** Used to alternate particle effects from the rear wheels. */
int m_wheel_toggle;
/** A skid level that is currently in use */
int m_skid_level;
/** A light that's shown when the kart uses nitro. */
irr::scene::ISceneNode* m_nitro_light;

View File

@@ -152,7 +152,7 @@ void Physics::update(float dt)
// Maximum of three substeps. This will work for framerate down to
// 20 FPS (bullet default frequency is 60 HZ).
m_dynamics_world->stepSimulation(dt, 3);
m_dynamics_world->stepSimulation(dt, 6, 1.0f/120.0f);
// Now handle the actual collision. Note: flyables can not be removed
// inside of this loop, since the same flyables might hit more than one

View File

@@ -21,10 +21,13 @@
#include "animations/animation_base.hpp"
#include "animations/ipo.hpp"
#include "config/user_config.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/show_curve.hpp"
#include "graphics/stk_tex_manager.hpp"
#include "io/xml_node.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/cannon_animation.hpp"
#include "karts/skidding.hpp"
#include "modes/world.hpp"
@@ -35,13 +38,23 @@
CheckCannon::CheckCannon(const XMLNode &node, unsigned int index)
: CheckLine(node, index)
{
core::vector3df p1, p2;
if(!node.get("target-p1", &p1) || !node.get("target-p2", &p2))
std::string p1("target-p1");
std::string p2("target-p2");
if (race_manager->getReverseTrack())
{
p1 = "p1";
p2 = "p2";
}
if( !node.get(p1, &m_target_left ) ||
!node.get(p2, &m_target_right) )
Log::fatal("CheckCannon", "No target line specified.");
m_target.setLine(p1, p2);
m_curve = new Ipo(*(node.getNode("curve")),
/*fps*/25,
/*reverse*/race_manager->getReverseTrack());
#if defined(DEBUG) && !defined(SERVER_ONLY)
if(UserConfigParams::m_track_debug)
{
@@ -50,7 +63,41 @@ CheckCannon::CheckCannon(const XMLNode &node, unsigned int index)
for(unsigned int i=0; i<p.size(); i++)
m_show_curve->addPoint(p[i]);
}
if (UserConfigParams::m_check_debug)
{
video::SMaterial material;
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
material.setFlag(video::EMF_LIGHTING, false);
material.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
scene::IMesh *mesh = irr_driver->createQuadMesh(&material,
/*create mesh*/true);
scene::IMeshBuffer *buffer = mesh->getMeshBuffer(0);
assert(buffer->getVertexType() == video::EVT_STANDARD);
irr::video::S3DVertex* vertices
= (video::S3DVertex*)buffer->getVertices();
Vec3 height(0, 3, 0);
vertices[0].Pos = m_target_left.toIrrVector();
vertices[1].Pos = m_target_right.toIrrVector();
vertices[2].Pos = Vec3(m_target_right + height).toIrrVector();
vertices[3].Pos = Vec3(m_target_left + height).toIrrVector();
for (unsigned int i = 0; i<4; i++)
{
vertices[i].Color = m_active_at_reset
? video::SColor(128, 255, 0, 0)
: video::SColor(128, 128, 128, 128);
}
buffer->recalculateBoundingBox();
buffer->getMaterial().setTexture(0, STKTexManager::getInstance()->getUnicolorTexture(video::SColor(128, 255, 105, 180)));
buffer->getMaterial().setTexture(1, STKTexManager::getInstance()->getUnicolorTexture(video::SColor(0, 0, 0, 0)));
buffer->getMaterial().setTexture(2, STKTexManager::getInstance()->getUnicolorTexture(video::SColor(0, 0, 0, 0)));
buffer->getMaterial().BackfaceCulling = false;
//mesh->setBoundingBox(buffer->getBoundingBox());
m_debug_target_node = irr_driver->addMesh(mesh, "checkdebug");
mesh->drop();
}
#endif // DEBUG AND !SERVER_ONLY
} // CheckCannon
// ----------------------------------------------------------------------------
@@ -66,6 +113,26 @@ CheckCannon::~CheckCannon()
#endif
} // ~CheckCannon
// ----------------------------------------------------------------------------
void CheckCannon::changeDebugColor(bool is_active)
{
#if defined(DEBUG) && !defined(SERVER_ONLY)
CheckLine::changeDebugColor(is_active);
scene::IMesh *mesh = m_debug_target_node->getMesh();
scene::IMeshBuffer *buffer = mesh->getMeshBuffer(0);
irr::video::S3DVertex* vertices
= (video::S3DVertex*)buffer->getVertices();
video::SColor color = is_active ? video::SColor(192, 255, 0, 0)
: video::SColor(192, 128, 128, 128);
for (unsigned int i = 0; i<4; i++)
{
vertices[i].Color = color;
}
buffer->getMaterial().setTexture(0, STKTexManager::getInstance()->getUnicolorTexture(color));
#endif
} // changeDebugColor
// ----------------------------------------------------------------------------
/** Called when the check line is triggered. This function creates a cannon
* animation object and attaches it to the kart.
@@ -73,9 +140,13 @@ CheckCannon::~CheckCannon()
*/
void CheckCannon::trigger(unsigned int kart_index)
{
Vec3 target(m_target.getMiddle());
AbstractKart *kart = World::getWorld()->getKart(kart_index);
if(kart->getKartAnimation()) return;
new CannonAnimation(kart, m_curve->clone());
// The constructor AbstractKartAnimation resets the skidding to 0. So in
// order to smooth rotate the kart, we need to keep the current visual
// rotation and pass it to the CannonAnimation.
float skid_rot = kart->getSkidding()->getVisualSkidRotation();
new CannonAnimation(kart, m_curve->clone(), getLeftPoint(), getRightPoint(),
m_target_left, m_target_right, skid_rot);
} // CheckCannon

View File

@@ -37,7 +37,8 @@ class CheckCannon : public CheckLine
{
private:
/** The target point the kart will fly to. */
core::line3df m_target;
Vec3 m_target_left;
Vec3 m_target_right;
/** Stores the cannon curve data. */
Ipo *m_curve;
@@ -46,12 +47,16 @@ private:
/** If track debugging is enabled, this will show the the curve of
* the cannon in the race. */
ShowCurve * m_show_curve;
/** Used to display debug information about checklines. */
scene::IMeshSceneNode *m_debug_target_node;
#endif
public:
CheckCannon(const XMLNode &node, unsigned int index);
virtual ~CheckCannon();
virtual void trigger(unsigned int kart_index);
virtual void changeDebugColor(bool is_active);
}; // CheckLine
#endif

View File

@@ -71,6 +71,10 @@ private:
/** How much a kart is allowed to be over the minimum height of a
* quad and still considered to be able to cross it. */
static const int m_over_min_height = 4;
protected:
const Vec3 &getLeftPoint() const { return m_left_point; }
const Vec3 &getRightPoint() const { return m_right_point; }
public:
CheckLine(const XMLNode &node, unsigned int index);
virtual ~CheckLine();

View File

@@ -723,11 +723,15 @@ bool onEvent(const SEvent &event)
if(!UserConfigParams::m_artist_debug_mode)
return true; // keep handling the events
if(event.EventType == EET_MOUSE_INPUT_EVENT)
if (event.EventType == EET_MOUSE_INPUT_EVENT)
{
// Create the menu (only one menu at a time)
if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN &&
!g_debug_menu_visible)
#ifdef ANDROID
if (event.MouseInput.X < 30 && event.MouseInput.Y < 30 &&
#else
if (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN &&
#endif
!g_debug_menu_visible)
{
irr_driver->getDevice()->getCursorControl()->setVisible(true);