Merge remote-tracking branch 'origin/master' into hq_mipmap_generator
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user