Moved terrain particle effectrs from kart into kart_gfx.

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@10766 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2012-01-30 22:20:31 +00:00
parent 9e99055545
commit c7083edba3
4 changed files with 220 additions and 202 deletions

View File

@ -93,14 +93,12 @@ Kart::Kart (const std::string& ident, Track* track, int position, bool is_first_
m_race_position = position;
m_collected_energy = 0;
m_finished_race = false;
m_wheel_toggle = 1;
m_finish_time = 0.0f;
m_bubblegum_time = 0.0f;
m_invulnerable_time = 0.0f;
m_squash_time = 0.0f;
m_shadow_enabled = false;
m_shadow = NULL;
m_terrain_particles = NULL;
m_collision_particles = NULL;
m_slipstream = NULL;
m_skidmarks = NULL;
@ -430,7 +428,6 @@ Kart::~Kart()
delete m_kart_gfx;
if(m_terrain_sound) sfx_manager->deleteSFX(m_terrain_sound);
if(m_previous_terrain_sound) sfx_manager->deleteSFX(m_previous_terrain_sound);
if(m_terrain_particles) delete m_terrain_particles;
if(m_collision_particles) delete m_collision_particles;
if(m_slipstream) delete m_slipstream;
if(m_rain) delete m_rain;
@ -906,7 +903,6 @@ void Kart::update(float dt)
//smoke drawing control point
if (UserConfigParams::m_graphical_effects)
{
if (m_terrain_particles) m_terrain_particles->update(dt);
if (m_rain)
{
m_rain->setPosition( getCamera()->getCameraSceneNode()->getPosition() );
@ -1153,140 +1149,92 @@ void Kart::handleMaterialGFX()
// on top of a surface (i.e. not falling), actually touching
// something with the wheels, and the material has not the
// below surface property set.
if (material && isOnGround() && !material->isBelowSurface() && m_kart_mode != EA_RESCUE)
if (material && isOnGround() && !material->isBelowSurface() &&
m_kart_mode != EA_RESCUE && UserConfigParams::m_graphical_effects)
{
if (m_terrain_particles)
// Get the appropriate particle data depending on
// wether the kart is skidding or driving.
const ParticleKind* pk =
material->getParticlesWhen(m_skidding > 1.0f
? Material::EMIT_ON_SKID
: Material::EMIT_ON_DRIVE);
if(!pk)
{
Vec3 xyz;
m_wheel_toggle = 1 - m_wheel_toggle;
const btWheelInfo &wi =
getVehicle()->getWheelInfo(2 + m_wheel_toggle);
xyz = wi.m_raycastInfo.m_contactPointWS;
// FIXME: the X position is not yet always accurate.
xyz += Vec3(0.06f * (m_wheel_toggle ? +1 : -1),
0,
0.06f);
// Get the appropriate particle data depending on
// wether the kart is skidding or driving.
const ParticleKind* pk =
material->getParticlesWhen(m_skidding > 1.0f
? Material::EMIT_ON_SKID
: Material::EMIT_ON_DRIVE);
if(!pk)
{
// Disable potentially running particle effects
m_terrain_particles->setCreationRateAbsolute(0);
return; // no particle effect, return
}
// Now compute the particle creation rate:
float rate = 0;
const float speed = fabsf(getSpeed());
if (m_skidding > 1.0f)
{
rate = fabsf(m_controls.m_steer) > 0.8 ? m_skidding - 1 : 0;
}
else if (speed >= 0.5f)
{
rate = speed/m_kart_properties->getMaxSpeed();
}
else
{
m_terrain_particles->setCreationRateAbsolute(0);
return;
}
float create = pk->getMinRate()*(1-rate) + pk->getMaxRate()*rate;
m_terrain_particles->setParticleType(pk);
// when particle type changes, the emitter is re-created at (0,0,0) so we need to
// set the position after setParticleType
m_terrain_particles->setPosition(xyz);
m_terrain_particles->setCreationRateAbsolute(create);
// Disable potentially running particle effects
m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_TERRAIN, 0);
return; // no particle effect, return
}
m_kart_gfx->updateTerrain(pk);
return;
}
// Now the kart is either falling, or driving on a terrain which
// has the 'below surface' flag set. Detect if there is a surface
// on top of the kart.
// --------------------------------------------------------------
if (m_camera && m_camera->getMode() != Camera::CM_FINAL)
{
if (material && material->hasFallingEffect() && !m_flying)
{
m_camera->setMode(Camera::CM_FALLING);
}
else if (m_camera->getMode() != Camera::CM_NORMAL && m_camera->getMode() != Camera::CM_REVERSE)
else if (m_camera->getMode() != Camera::CM_NORMAL &&
m_camera->getMode() != Camera::CM_REVERSE)
{
m_camera->setMode(Camera::CM_NORMAL);
}
}
} // camera != final camera
if (m_terrain_particles)
{
// Use the middle of the contact points of the two rear wheels
// as the point from which to cast the ray upwards
const btWheelInfo::RaycastInfo &ri2 =
getVehicle()->getWheelInfo(2).m_raycastInfo;
const btWheelInfo::RaycastInfo &ri3 =
getVehicle()->getWheelInfo(3).m_raycastInfo;
Vec3 from = (ri2.m_contactPointWS + ri3.m_contactPointWS)*0.5f;
Vec3 xyz;
const Material *surface_material;
if(!getSurfaceInfo(from, &xyz, &surface_material))
{
m_terrain_particles->setCreationRateAbsolute(0);
return;
}
const ParticleKind *pk =
surface_material->getParticlesWhen(Material::EMIT_ON_DRIVE);
if(pk && !m_flying && m_kart_mode != EA_RESCUE)
{
const float distance = xyz.distance2(from);
m_terrain_particles->setParticleType(pk);
m_terrain_particles->setPosition(xyz.toIrrVector());
//const float speed = fabsf(getSpeed());
//float rate = (speed>=0.5f) ? speed/m_kart_properties->getMaxSpeed()
// : 0;
if (!UserConfigParams::m_graphical_effects)
return;
float create;
if (distance < 2.0f)
{
create = (float)pk->getMaxRate();
}
else if (distance < 4.0f)
{
create = pk->getMinRate() + (pk->getMaxRate() - pk->getMinRate())*(distance - 2.0f)/2.0f;
}
else
{
create = 0.0f;
}
m_terrain_particles->setCreationRateAbsolute(create);
const std::string s = surface_material->getSFXName();
if (s != "" && m_kart_mode != EA_RESCUE &&
(m_terrain_sound == NULL || m_terrain_sound->getStatus() == SFXManager::SFX_STOPPED))
{
if (m_previous_terrain_sound) sfx_manager->deleteSFX(m_previous_terrain_sound);
m_previous_terrain_sound = m_terrain_sound;
if(m_previous_terrain_sound)
m_previous_terrain_sound->setLoop(false);
m_terrain_sound = sfx_manager->createSoundSource(s);
m_terrain_sound->play();
m_terrain_sound->setLoop(false);
}
// handleMaterialSFX(surface_material);
}
// Use the middle of the contact points of the two rear wheels
// as the point from which to cast the ray upwards
const btWheelInfo::RaycastInfo &ri2 =
getVehicle()->getWheelInfo(2).m_raycastInfo;
const btWheelInfo::RaycastInfo &ri3 =
getVehicle()->getWheelInfo(3).m_raycastInfo;
Vec3 from = (ri2.m_contactPointWS + ri3.m_contactPointWS)*0.5f;
Vec3 xyz;
const Material *surface_material;
if(!getSurfaceInfo(from, &xyz, &surface_material))
{
m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_TERRAIN, 0);
return;
}
const ParticleKind *pk =
surface_material->getParticlesWhen(Material::EMIT_ON_DRIVE);
if(!pk || m_flying || m_kart_mode == EA_RESCUE)
return;
// Now the kart is under a surface, and there is a surface effect
// --------------------------------------------------------------
m_kart_gfx->setParticleKind(KartGFX::KGFX_TERRAIN, pk);
m_kart_gfx->setXYZ(KartGFX::KGFX_TERRAIN, xyz);
const float distance = xyz.distance2(from);
float ratio;
if (distance < 2.0f) ratio = 1.0f;
else if (distance < 4.0f) ratio = (4.0f-distance)*0.5f;
else ratio = -1.0f; // No more particles
m_kart_gfx->setCreationRateRelative(KartGFX::KGFX_TERRAIN, ratio);
// Play special sound effects for this terrain
// -------------------------------------------
const std::string s = surface_material->getSFXName();
if (s != "" && m_kart_mode != EA_RESCUE &&
(m_terrain_sound == NULL || m_terrain_sound->getStatus() == SFXManager::SFX_STOPPED))
{
if (m_previous_terrain_sound) sfx_manager->deleteSFX(m_previous_terrain_sound);
m_previous_terrain_sound = m_terrain_sound;
if(m_previous_terrain_sound)
m_previous_terrain_sound->setLoop(false);
m_terrain_sound = sfx_manager->createSoundSource(s);
m_terrain_sound->play();
m_terrain_sound->setLoop(false);
}
} // handleMaterialGFX
@ -2028,25 +1976,6 @@ void Kart::loadData(RaceManager::KartType type, bool is_first_kart,
createPhysics();
// Attach Particle System
if (UserConfigParams::m_graphical_effects && !isWheeless())
{
try
{
// Note: the smoke system is NOT child of the kart, since bullet
// gives the position of the wheels on the ground in world coordinates.
// So it's easier not to move the particle system with the kart, and set
// the position directly from the wheel coordinates.
Vec3 position(-getKartWidth()*0.35f, 0.06f, -getKartLength()*0.5f);
m_terrain_particles = new ParticleEmitter(ParticleKindManager::get()->getParticles("smoke.xml"),
position);
}
catch (std::runtime_error& e)
{
std::cerr << "[Kart::loadData] " << e.what() << std::endl;
}
}
if (type == RaceManager::KT_PLAYER && UserConfigParams::m_weather_effects &&
track->getSkyParticles() != NULL)

View File

@ -114,9 +114,6 @@ private:
* determine startup boost. */
bool m_has_started;
/** For skidding smoke */
int m_wheel_toggle;
/**<Maximum engine rpm's for the current gear*/
float m_max_gear_rpm;
@ -154,9 +151,6 @@ private:
* stuck to the kart, i.e. the shadow would be flying, too). */
bool m_shadow_enabled;
/** Particle emitter used for terrain-specific effects (including but not limited too skidding). */
ParticleEmitter *m_terrain_particles;
ParticleEmitter *m_sky_particles_emitter;
/** All particle effects. */

View File

@ -22,45 +22,45 @@
#include "io/file_manager.hpp"
#include "graphics/particle_emitter.hpp"
#include "graphics/particle_kind.hpp"
#include "graphics/particle_kind_manager.hpp"
#include "karts/kart.hpp"
#include "physics/btKart.hpp"
#include <iostream>
KartGFX::KartGFX(const Kart *kart) : m_current_skid(KGFX_SKID1)
KartGFX::KartGFX(const Kart *kart)
{
if(!UserConfigParams::m_graphical_effects)
{
for(unsigned int i=0; i<KGFX_COUNT; i++)
{
m_all_emitters.push_back(NULL);
m_all_particle_kinds.push_back(NULL);
}
return;
}
m_kart = kart;
Vec3 position(0, kart->getKartHeight()*0.35f,
-kart->getKartLength()*0.35f);
Vec3 rear_center(0, kart->getKartHeight()*0.35f,
-kart->getKartLength()*0.35f);
// Create all effects. Note that they must be created
// in the order of KartGFXType.
addEffect(KGFX_NITRO, "nitro.xml", position);
addEffect(KGFX_ZIPPER, "zipper_fire.xml", position);
addEffect(KGFX_SKID1, "skid1.xml", position);
addEffect(KGFX_SKID2, "skid2.xml", position);
addEffect(KGFX_NITRO, "nitro.xml", rear_center);
addEffect(KGFX_ZIPPER, "zipper_fire.xml", rear_center);
addEffect(KGFX_TERRAIN, "smoke.xml", Vec3(0,0,0));
addEffect(KGFX_SKID1, "skid1.xml", rear_center);
addEffect(KGFX_SKID2, "skid2.xml", rear_center);
} // KartGFX
// ----------------------------------------------------------------------------
/** Destructor. Frees all particle effects and kinds.
*/
KartGFX::~KartGFX()
{
for(unsigned int i=0; i<KGFX_COUNT; i++)
{
if(m_all_emitters[i])
delete m_all_emitters[i];
if(m_all_particle_kinds[i])
delete m_all_particle_kinds[i];
} // for i < KGFX_COUNT
} // ~KartGFX
@ -75,17 +75,23 @@ KartGFX::~KartGFX()
void KartGFX::addEffect(KartGFXType type, const std::string &file_name,
const Vec3 &position)
{
ParticleKind *kind = NULL;
ParticleEmitter *emitter = NULL;
const ParticleKind *kind = NULL;
ParticleEmitter *emitter = NULL;
try
{
kind = new ParticleKind(file_manager->getGfxFile(file_name));
if(type==KGFX_SKID2)
emitter = NULL; // skid2 is only used to store the emitter type
kind = ParticleKindManager::get()->getParticles(file_name);
//kind = new ParticleKind(file_manager->getGfxFile(file_name));
// Skid2 is only used to store the emitter type, and a wheeless
// kart has no terrain effects.
if(type==KGFX_SKID2 || (type==KGFX_TERRAIN && m_kart->isWheeless()) )
emitter = NULL;
else if(type==KGFX_TERRAIN)
// Terrain is NOT a child of the kart, since bullet returns the
// raycast info in world coordinates
emitter = new ParticleEmitter(kind, position);
else
emitter = new ParticleEmitter(kind,
position,
m_kart->getNode());
emitter = new ParticleEmitter(kind, position, m_kart->getNode());
}
catch (std::runtime_error& e)
{
@ -99,13 +105,18 @@ void KartGFX::addEffect(KartGFXType type, const std::string &file_name,
}
assert(m_all_emitters.size()==type);
m_all_emitters.push_back(emitter);
assert(m_all_particle_kinds.size()==type);
m_all_particle_kinds.push_back(kind);
if(type==KGFX_SKID1)
m_skid_kind1 = kind;
else if (type==KGFX_SKID2)
m_skid_kind2 = kind;
} // addEffect
// ----------------------------------------------------------------------------
/** Resets all particle emitters. Used at the (re)start of a race.
*/
void KartGFX::reset()
{
m_wheel_toggle = 1;
for(unsigned int i=0; i<m_all_emitters.size(); i++)
{
if(m_all_emitters[i])
@ -121,44 +132,40 @@ void KartGFX::reset()
* \param type Must be either KGFX_SKID1 or KGFX_SKID2 - the particle type
* to use corresponding to the bonus level.
*/
void KartGFX::setSkidLevel(unsigned int level)
void KartGFX::setSkidLevel(const unsigned int level)
{
KartGFXType type = level==1 ? KGFX_SKID1 : KGFX_SKID2;
assert(type == KGFX_SKID1 || type==KGFX_SKID2);
m_current_skid = type;
assert(level >= 1);
assert(level <= 2);
const ParticleKind *pk = level==1 ? m_skid_kind1 : m_skid_kind2;
if(m_all_emitters[KGFX_SKID1])
m_all_emitters[KGFX_SKID1]->setParticleType(
m_all_particle_kinds[type]);
m_all_emitters[KGFX_SKID1]->setParticleType(pk);
} // setSkidLevel
// ----------------------------------------------------------------------------
/** Updates all gfx.
* \param dt Time step size.
/** Sets a new particle type to be used. Note that the memory of this
* kind must be managed by the caller.
* \param type The emitter type for which to set the new particle type.
* \param pk The particle kind to use.
*/
void KartGFX::update(float dt)
void KartGFX::setParticleKind(const KartGFXType type, const ParticleKind *pk)
{
if(!UserConfigParams::m_graphical_effects) return;
ParticleEmitter *pe = m_all_emitters[KGFX_TERRAIN];
if(pe) return;
for(unsigned int i=0; i<m_all_emitters.size(); i++)
{
if(m_all_emitters[i])
m_all_emitters[i]->update(dt);
}
} // update
pe->setParticleType(pk);
} // setParticleKind
// ----------------------------------------------------------------------------
/** Sets the creation rate for the specified particle type relative to the
* given minimum and maximum particle rate.
* \param type The particle effect for which to set the
* creation rate.
* \param f The new relative creation rate.
/** Defines the new position of the specified emitter.
* \param type The emitter to set a new position for.
* \param xyz The new position of the emitter.
*/
void KartGFX::setCreationRateRelative(KartGFXType type, float f)
void KartGFX::setXYZ(const KartGFXType type, const Vec3 &xyz)
{
if(m_all_emitters[type])
m_all_emitters[type]->setCreationRateRelative(f);
} // setCreationRate
ParticleEmitter *pe = m_all_emitters[KGFX_TERRAIN];
if(!pe) return;
pe->setPosition(xyz);
} // setXYZ
// ----------------------------------------------------------------------------
/** Sets the absolute creation rate for the specified particle type.
@ -170,7 +177,26 @@ void KartGFX::setCreationRateAbsolute(KartGFXType type, float f)
{
if(m_all_emitters[type])
m_all_emitters[type]->setCreationRateAbsolute(f);
} // setCreationRate
} // setCreationRateAbsolute
// ----------------------------------------------------------------------------
/** Sets the creation rate for the specified particle type relative to the
* given minimum and maximum particle rate. If a negative value is
* specified, the creation rate will be set to 0 (absolute).
* \param type The particle effect for which to set the
* creation rate (<0 means no more particles).
* \param f The new relative creation rate.
*/
void KartGFX::setCreationRateRelative(KartGFXType type, float f)
{
if(m_all_emitters[type])
{
if(f<0)
m_all_emitters[type]->setCreationRateAbsolute(0);
else
m_all_emitters[type]->setCreationRateRelative(f);
}
} // setCreationRateRelative
// ----------------------------------------------------------------------------
/** Resize the area from which the particles are emitted: the emitter box
@ -185,4 +211,63 @@ void KartGFX::resizeBox(KartGFXType type, float speed, float dt)
{
if(m_all_emitters[type])
m_all_emitters[type]->resizeBox(std::max(0.25f, speed*dt));
} // resizeBox
} // resizeBox
// ----------------------------------------------------------------------------
/** If necessary defines a new particle type for the terrain emitter. Then
* adjusts the location of the terrain emitter to be in synch with the
* current wheel position, and defines the emission rate depending on speed,
* steering, and skidding.
* \param pk Particle type to use.
*/
void KartGFX::updateTerrain(const ParticleKind *pk)
{
ParticleEmitter *pe = m_all_emitters[KGFX_TERRAIN];
if(!pe) return;
pe->setParticleType(pk);
const btWheelInfo &wi = m_kart->getVehicle()
->getWheelInfo(2+m_wheel_toggle);
Vec3 xyz = wi.m_raycastInfo.m_contactPointWS;
// FIXME: the X and Z position is not always accurate.
xyz.setX(xyz.getX()+ 0.06f * (m_wheel_toggle ? +1 : -1));
xyz.setZ(xyz.getZ()+0.06f);
pe->setPosition(xyz);
// Now compute the particle creation rate:
float rate = 0;
const float speed = fabsf(m_kart->getSpeed());
const float skidding = m_kart->getSkidding();
if (skidding > 1.0f)
rate = fabsf(m_kart->getControls().m_steer) > 0.8 ? skidding - 1 : 0;
else if (speed >= 0.5f)
rate = speed/m_kart->getKartProperties()->getMaxSpeed();
else
{
pe->setCreationRateAbsolute(0);
return;
}
// m_skidding can be > 2, and speed > maxSpeed (if powerups are used).
if(rate>1.0f) rate = 1.0f;
pe->setCreationRateRelative(rate);
} // updateTerrain
// ----------------------------------------------------------------------------
/** Updates all gfx.
* \param dt Time step size.
*/
void KartGFX::update(float dt)
{
if(!UserConfigParams::m_graphical_effects) return;
m_wheel_toggle = 1 - m_wheel_toggle;
for(unsigned int i=0; i<m_all_emitters.size(); i++)
{
if(m_all_emitters[i])
m_all_emitters[i]->update(dt);
}
} // update

View File

@ -34,18 +34,25 @@ class KartGFX
{
public:
/** All particle effects supported by this object.
* Nitro, zipper, and skidding effects. KGFX_COUNT
* Nitro, zipper, terrain, and skidding effects. Two different
* skid types are supported, but only one emitter node will be
* created. So KGFX_SKID1/2 store the two types, and KGFX_SKID
* = KGFX_SKID1 stores the actual emitter node. KGFX_COUNT
* is the number of entries and must therefore be last. */
enum KartGFXType { KGFX_NITRO=0,
KGFX_ZIPPER,
KGFX_TERRAIN,
KGFX_SKID,
KGFX_SKID1=KGFX_SKID,
KGFX_SKID2,
KGFX_COUNT};
private:
/** Vector of all particle kinde. */
std::vector<ParticleKind*> m_all_particle_kinds;
/** The particle kind for skidding bonus level 1. */
const ParticleKind *m_skid_kind1;
/** The particle kind for skidding bonus level 2. */
const ParticleKind *m_skid_kind2;
/** Vector of all particle emitters. */
std::vector<ParticleEmitter*> m_all_emitters;
@ -53,8 +60,8 @@ private:
/** Pointer to the owner of this kart. */
const Kart *m_kart;
/** Indicates the current skidding level, either skid1 or skid2. */
KartGFXType m_current_skid;
/** Used to alternate particle effects from the rear wheels. */
int m_wheel_toggle;
void addEffect(KartGFXType type, const std::string &file_name,
const Vec3 &position);
@ -63,10 +70,13 @@ public:
KartGFX(const Kart *kart);
~KartGFX();
void reset();
void setSkidLevel(const unsigned int level);
void setParticleKind(const KartGFXType type, const ParticleKind *pk);
void setXYZ(const KartGFXType type, const Vec3 &xyz);
void setCreationRateAbsolute(const KartGFXType type, float f);
void setCreationRateRelative(const KartGFXType type, float f);
void resizeBox(const KartGFXType type, float speed, float dt);
void updateTerrain(const ParticleKind *pk);
void update(float dt);
void setCreationRateAbsolute(KartGFXType type, float f);
void setCreationRateRelative(KartGFXType type, float f);
void resizeBox(KartGFXType type, float speed, float dt);
void setSkidLevel(unsigned int level);
}; // KartWGFX
#endif