First part of track object refactor

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@12596 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
auria 2013-04-04 01:15:37 +00:00
parent cc6446cd1c
commit bc1d1e7d31
21 changed files with 1316 additions and 1112 deletions

View File

@ -27,7 +27,6 @@
#include <algorithm>
AnimationBase::AnimationBase(const XMLNode &node)
: TrackObject(node)
{
float fps=25;
node.get("fps", &fps);
@ -43,12 +42,12 @@ AnimationBase::AnimationBase(const XMLNode &node)
{
m_playing = false;
}
reset();
} // AnimationBase
// ----------------------------------------------------------------------------
/** Special constructor which takes one IPO (or curve). This is used by the
*/
AnimationBase::AnimationBase(Ipo *ipo) : TrackObject()
AnimationBase::AnimationBase(Ipo *ipo)
{
m_anim_type = ATT_CYCLIC_ONCE;
m_playing = true;
@ -83,8 +82,6 @@ void AnimationBase::reset()
{
curr->reset();
}
TrackObject::reset();
} // reset
// ----------------------------------------------------------------------------
@ -95,12 +92,14 @@ void AnimationBase::reset()
*/
void AnimationBase::update(float dt, Vec3 *xyz, Vec3 *hpr, Vec3 *scale)
{
TrackObject::update(dt);
assert(!isnan(m_current_time));
// Don't do anything if the animation is disabled
if(!m_playing) return;
m_current_time += dt;
assert(!isnan(m_current_time));
Ipo* curr;
for_in (curr, m_all_ipos)
{

View File

@ -30,7 +30,6 @@
// Note that ipo.hpp is included here in order that PtrVector<Ipo> can call
// the proper destructor!
#include "animations/ipo.hpp"
#include "tracks/track_object.hpp"
#include "utils/ptr_vector.hpp"
#include <algorithm>
@ -41,7 +40,7 @@ class XMLNode;
* \brief A base class for all animations.
* \ingroup animations
*/
class AnimationBase : public TrackObject
class AnimationBase
{
private:
/** Two types of animations: cyclic ones that play all the time, and

View File

@ -1,102 +0,0 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "animations/billboard_animation.hpp"
#include "config/user_config.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material.hpp"
#include "graphics/material_manager.hpp"
#include "io/file_manager.hpp"
#include <ISceneManager.h>
#include <ICameraSceneNode.h>
#include <SColor.h>
#include <IBillboardSceneNode.h>
class XMLNode;
/** A 2d billboard animation. */
BillboardAnimation::BillboardAnimation(const XMLNode &xml_node)
: AnimationBase(xml_node)
{
std::string texture_name;
float width, height;
xml_node.get("texture", &texture_name);
xml_node.get("width", &width );
xml_node.get("height", &height );
m_fade_out_when_close = false;
xml_node.get("fadeout", &m_fade_out_when_close);
if (m_fade_out_when_close)
{
xml_node.get("start", &m_fade_out_start);
xml_node.get("end", &m_fade_out_end );
}
video::ITexture *texture =
irr_driver->getTexture(file_manager->getTextureFile(texture_name));
m_node = irr_driver->addBillboard(core::dimension2df(width, height),
texture);
Material *stk_material = material_manager->getMaterial(texture_name);
stk_material->setMaterialProperties(&(m_node->getMaterial(0)), NULL);
m_node->setPosition(m_init_xyz);
} // BillboardAnimation
// ----------------------------------------------------------------------------
/** Update the animation, called one per time step.
* \param dt Time since last call. */
void BillboardAnimation::update(float dt)
{
//if ( UserConfigParams::m_graphical_effects )
{
Vec3 xyz(m_node->getPosition());
// Rotation doesn't make too much sense for a billboard,
// so just set it to 0
Vec3 hpr(0, 0, 0);
Vec3 scale = m_node->getScale();
AnimationBase::update(dt, &xyz, &hpr, &scale);
m_node->setPosition(xyz.toIrrVector());
m_node->setScale(scale.toIrrVector());
// Setting rotation doesn't make sense
}
if (m_fade_out_when_close)
{
scene::ICameraSceneNode* curr_cam = irr_driver->getSceneManager()->getActiveCamera();
const float dist = m_node->getPosition().getDistanceFrom( curr_cam->getPosition() );
scene::IBillboardSceneNode* node = (scene::IBillboardSceneNode*)m_node;
if (dist < m_fade_out_start)
{
node->setColor(video::SColor(0, 255, 255, 255));
}
else if (dist > m_fade_out_end)
{
node->setColor(video::SColor(255, 255, 255, 255));
}
else
{
int a = (int)(255*(dist - m_fade_out_start) / (m_fade_out_end - m_fade_out_start));
node->setColor(video::SColor(a, 255, 255, 255));
}
}
} // update

View File

@ -1,48 +0,0 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_BILLBOARD_ANIMATION_HPP
#define HEADER_BILLBOARD_ANIMATION_HPP
#include <string>
#include "animations/animation_base.hpp"
class XMLNode;
/**
* \brief A 2d billboard animation.
* \ingroup animations
*/
class BillboardAnimation : public AnimationBase
{
/** To create halo-like effects where the halo disapears when you get
close to it. Requested by samuncle */
bool m_fade_out_when_close;
float m_fade_out_start;
float m_fade_out_end;
public:
BillboardAnimation(const XMLNode &node);
virtual ~BillboardAnimation() {};
virtual void update(float dt);
}; // BillboardAnimation
#endif

View File

@ -440,7 +440,8 @@ void Ipo::reset()
* \param scale The scale that needs to be updated (can be NULL)
*/
void Ipo::update(float time, Vec3 *xyz, Vec3 *hpr,Vec3 *scale)
{
{
assert(!isnan(time));
switch(m_ipo_data->m_channel)
{
case Ipo::IPO_LOCX : if(xyz) xyz ->setX(get(time, 0)); break;
@ -474,6 +475,8 @@ void Ipo::update(float time, Vec3 *xyz, Vec3 *hpr,Vec3 *scale)
*/
float Ipo::get(float time, unsigned int index) const
{
assert(!isnan(time));
// Avoid crash in case that only one point is given for this IPO.
if(m_next_n==0)
return m_ipo_data->m_points[0][index];
@ -489,5 +492,7 @@ float Ipo::get(float time, unsigned int index) const
while(m_next_n<m_ipo_data->m_points.size()-1 &&
time >=m_ipo_data->m_points[m_next_n].getW())
m_next_n++;
return m_ipo_data->get(time, index, m_next_n-1);
float rval = m_ipo_data->get(time, index, m_next_n-1);
assert(!isnan(rval));
return rval;
} // get

View File

@ -29,15 +29,17 @@
#include "modes/world.hpp"
#include "physics/kart_motion_state.hpp"
#include "physics/physics.hpp"
#include "physics/physical_object.hpp"
#include "physics/triangle_mesh.hpp"
#include "tracks/bezier_curve.hpp"
#include "utils/constants.hpp"
#include <ISceneManager.h>
#include <IMeshSceneNode.h>
ThreeDAnimation::ThreeDAnimation(const XMLNode &node)
: AnimationBase(node)
ThreeDAnimation::ThreeDAnimation(const XMLNode &node, TrackObject* object) : AnimationBase(node)
{
m_object = object;
m_crash_reset = false;
m_explode_kart = false;
node.get("reset", &m_crash_reset);
@ -45,259 +47,21 @@ ThreeDAnimation::ThreeDAnimation(const XMLNode &node)
m_important_animation = (World::getWorld()->getIdent() == IDENT_CUSTSCENE);
node.get("important", &m_important_animation);
m_triangle_mesh = NULL;
if (AnimationBase::m_node)
{
/** Save the initial position and rotation in the base animation object. */
setInitialTransform(AnimationBase::m_node->getPosition(),
AnimationBase::m_node->getRotation() );
m_hpr = AnimationBase::m_node->getRotation();
}
else
m_hpr = m_init_hpr;
m_body = NULL;
m_motion_state = NULL;
m_collision_shape = NULL;
std::string shape;
node.get("shape", &shape);
if(shape!="")
{
createPhysicsBody(shape);
}
if (m_node == NULL)
{
m_node = irr_driver->getSceneManager()->addEmptySceneNode();
}
/** Save the initial position and rotation in the base animation object. */
setInitialTransform(object->getInitXYZ(),
object->getInitRotation() );
m_hpr = object->getInitRotation();
assert(!isnan(m_hpr.getX()));
assert(!isnan(m_hpr.getY()));
assert(!isnan(m_hpr.getZ()));
} // ThreeDAnimation
// ----------------------------------------------------------------------------
/** Creates a bullet rigid body for this animated model. */
void ThreeDAnimation::createPhysicsBody(const std::string &shape)
{
if (m_interaction == "ghost" || m_node == NULL) return;
// 1. Determine size of the object
// -------------------------------
Vec3 extend = Vec3(1.0f, 1.0f, 1.0f);
if (m_mesh != NULL)
{
Vec3 min, max;
MeshTools::minMax3D(m_mesh, &min, &max);
extend = max - min;
}
if(shape=="box")
{
m_collision_shape = new btBoxShape(0.5*extend);
}
else if(shape=="coneX")
{
float radius = 0.5f*std::max(extend.getY(), extend.getZ());
m_collision_shape = new btConeShapeX(radius, extend.getX());
}
else if(shape=="coneY" || shape=="cone")
{
float radius = 0.5f*std::max(extend.getX(), extend.getZ());
m_collision_shape = new btConeShape(radius, extend.getY());
}
else if(shape=="coneZ")
{
// Note that the b3d model and therefore the extend has the
// irrlicht axis, i.e. Y and Z swapped. Also we need to
// convert
float radius = 0.5f*std::max(extend.getX(), extend.getY());
m_collision_shape = new btConeShapeZ(radius, extend.getZ());
}
else if(shape=="cylinderX")
{
m_collision_shape = new btCylinderShapeX(0.5f*extend);
}
else if(shape=="cylinderY")
{
m_collision_shape = new btCylinderShape(0.5f*extend);
}
else if(shape=="cylinderZ")
{
m_collision_shape = new btCylinderShapeZ(0.5f*extend);
}
else if(shape=="sphere")
{
float radius = std::max(extend.getX(), extend.getY());
radius = 0.5f*std::max(radius, extend.getZ());
m_collision_shape = new btSphereShape(radius);
}
else if(shape=="exact")
{
TriangleMesh* triangle_mesh = new TriangleMesh();
// In case of readonly materials we have to get the material from
// the mesh, otherwise from the node. This is esp. important for
// water nodes, which only have the material defined in the node,
// but not in the mesh at all!
bool is_readonly_material = false;
scene::IMesh* mesh = NULL;
switch (m_node->getType())
{
case scene::ESNT_MESH :
case scene::ESNT_WATER_SURFACE :
case scene::ESNT_OCTREE :
mesh = ((scene::IMeshSceneNode*)m_node)->getMesh();
is_readonly_material =
((scene::IMeshSceneNode*)m_node)->isReadOnlyMaterials();
break;
case scene::ESNT_ANIMATED_MESH :
// for now just use frame 0
mesh = ((scene::IAnimatedMeshSceneNode*)m_node)->getMesh()->getMesh(0);
is_readonly_material =
((scene::IAnimatedMeshSceneNode*)m_node)->isReadOnlyMaterials();
break;
default:
fprintf(stderr, "[3DAnimation] Unknown object type, cannot create exact collision body!\n");
return;
} // switch node->getType()
//core::matrix4 mat;
//mat.setRotationDegrees(hpr);
//mat.setTranslation(pos);
//core::matrix4 mat_scale;
// Note that we can't simply call mat.setScale, since this would
// overwrite the elements on the diagonal, making any rotation incorrect.
//mat_scale.setScale(scale);
//mat *= mat_scale;
for(unsigned int i=0; i<mesh->getMeshBufferCount(); i++)
{
scene::IMeshBuffer *mb = mesh->getMeshBuffer(i);
// FIXME: take translation/rotation into account
if (mb->getVertexType() != video::EVT_STANDARD &&
mb->getVertexType() != video::EVT_2TCOORDS)
{
fprintf(stderr, "WARNING: ThreeDAnimation::createPhysicsBody: Ignoring type '%d'!\n",
mb->getVertexType());
continue;
}
// Handle readonly materials correctly: mb->getMaterial can return
// NULL if the node is not using readonly materials. E.g. in case
// of a water scene node, the mesh (which is the animated copy of
// the original mesh) does not contain any material information,
// the material is only available in the node.
const video::SMaterial &irrMaterial =
is_readonly_material ? mb->getMaterial()
: m_node->getMaterial(i);
video::ITexture* t=irrMaterial.getTexture(0);
const Material* material=0;
TriangleMesh *tmesh = triangle_mesh;
if(t)
{
std::string image = std::string(core::stringc(t->getName()).c_str());
material=material_manager->getMaterial(StringUtils::getBasename(image));
if(material->isIgnore())
continue;
}
u16 *mbIndices = mb->getIndices();
Vec3 vertices[3];
Vec3 normals[3];
if (mb->getVertexType() == video::EVT_STANDARD)
{
irr::video::S3DVertex* mbVertices=(video::S3DVertex*)mb->getVertices();
for(unsigned int j=0; j<mb->getIndexCount(); j+=3)
{
for(unsigned int k=0; k<3; k++)
{
int indx=mbIndices[j+k];
core::vector3df v = mbVertices[indx].Pos;
//mat.transformVect(v);
vertices[k]=v;
normals[k]=mbVertices[indx].Normal;
} // for k
if(tmesh) tmesh->addTriangle(vertices[0], vertices[1],
vertices[2], normals[0],
normals[1], normals[2],
material );
} // for j
}
else
{
if (mb->getVertexType() == video::EVT_2TCOORDS)
{
irr::video::S3DVertex2TCoords* mbVertices = (video::S3DVertex2TCoords*)mb->getVertices();
for(unsigned int j=0; j<mb->getIndexCount(); j+=3)
{
for(unsigned int k=0; k<3; k++)
{
int indx=mbIndices[j+k];
core::vector3df v = mbVertices[indx].Pos;
//mat.transformVect(v);
vertices[k]=v;
normals[k]=mbVertices[indx].Normal;
} // for k
if(tmesh) tmesh->addTriangle(vertices[0], vertices[1],
vertices[2], normals[0],
normals[1], normals[2],
material );
} // for j
}
}
} // for i<getMeshBufferCount
triangle_mesh->createCollisionShape();
m_collision_shape = &triangle_mesh->getCollisionShape();
m_triangle_mesh = triangle_mesh;
}
else
{
fprintf(stderr, "[3DAnimation] WARNING: Shape '%s' is not supported, ignored.\n", shape.c_str());
return;
}
const core::vector3df &hpr = m_node->getRotation()*DEGREE_TO_RAD;
btQuaternion q(hpr.X, hpr.Y, hpr.Z);
const core::vector3df &xyz=m_node->getPosition();
Vec3 p(xyz);
btTransform trans(q,p);
m_motion_state = new KartMotionState(trans);
btRigidBody::btRigidBodyConstructionInfo info(0, m_motion_state,
m_collision_shape);
m_body = new btRigidBody(info);
m_user_pointer.set(this);
m_body->setUserPointer(&m_user_pointer);
World::getWorld()->getPhysics()->addBody(m_body);
m_body->setCollisionFlags( m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
m_body->setActivationState(DISABLE_DEACTIVATION);
} // createPhysicsBody
// ----------------------------------------------------------------------------
/** Destructor. */
ThreeDAnimation::~ThreeDAnimation()
{
if(m_body)
{
World::getWorld()->getPhysics()->removeBody(m_body);
delete m_body;
delete m_motion_state;
// If an exact shape was used, the collision shape pointer
// here is a copy of the collision shape pointer in the
// triangle mesh. In order to avoid double-freeing this
// pointer, we don't free the pointer in this case.
if(!m_triangle_mesh)
delete m_collision_shape;
}
if (m_triangle_mesh)
{
delete m_triangle_mesh;
}
} // ~ThreeDAnimation
// ----------------------------------------------------------------------------
@ -308,12 +72,13 @@ void ThreeDAnimation::update(float dt)
{
//if ( UserConfigParams::m_graphical_effects || m_important_animation )
{
Vec3 xyz = m_node->getPosition();
Vec3 scale = m_node->getScale();
Vec3 xyz = m_object->getPosition();
Vec3 scale = m_object->getScale();
AnimationBase::update(dt, &xyz, &m_hpr, &scale); //updates all IPOs
m_node->setPosition(xyz.toIrrVector());
m_node->setScale(scale.toIrrVector());
//m_node->setPosition(xyz.toIrrVector());
//m_node->setScale(scale.toIrrVector());
// Note that the rotation order of irrlicht is different from the one
// in blender. So in order to reproduce the blender IPO rotations
// correctly, we have to get the rotations around each axis and combine
@ -321,6 +86,9 @@ void ThreeDAnimation::update(float dt)
core::matrix4 m;
m.makeIdentity();
core::matrix4 mx;
assert(!isnan(m_hpr.getX()));
assert(!isnan(m_hpr.getY()));
assert(!isnan(m_hpr.getZ()));
mx.setRotationDegrees(core::vector3df(m_hpr.getX(), 0, 0));
core::matrix4 my;
my.setRotationDegrees(core::vector3df(0, m_hpr.getY(), 0));
@ -328,30 +96,11 @@ void ThreeDAnimation::update(float dt)
mz.setRotationDegrees(core::vector3df(0, 0, m_hpr.getZ()));
m = my*mz*mx;
core::vector3df hpr = m.getRotationDegrees();
m_node->setRotation(hpr);
//m_node->setRotation(hpr);
// Now update the position of the bullet body if there is one:
if(m_body)
if (m_object)
{
Vec3 hpr2(hpr);
hpr2.degreeToRad();
btQuaternion q;
core::matrix4 mat;
mat.setRotationDegrees(hpr);
irr::core::quaternion tempQuat(mat);
q = btQuaternion(-tempQuat.X, -tempQuat.Y, -tempQuat.Z, tempQuat.W);
Vec3 p(xyz);
btTransform trans(q,p);
m_motion_state->setWorldTransform(trans);
}
if (m_sound != NULL)
{
m_sound->position(xyz);
m_object->move(xyz.toIrrVector(), hpr, scale.toIrrVector());
}
}
} // update

View File

@ -29,6 +29,12 @@ using namespace irr;
#include "animations/animation_base.hpp"
#include "physics/user_pointer.hpp"
namespace irr
{
namespace scene { class IAnimatedMesh; class ISceneNode; class IMesh; }
}
class TrackObject;
class BezierCurve;
class XMLNode;
@ -38,21 +44,8 @@ class XMLNode;
class ThreeDAnimation : public AnimationBase
{
private:
/** The bullet collision shape for the physics. */
btCollisionShape *m_collision_shape;
/** The bullet rigid body. */
btRigidBody *m_body;
/** Motion state of the physical object. */
btMotionState *m_motion_state;
/** A user pointer to connect a bullet body with this object. */
UserPointer m_user_pointer;
/** Non-null only if the shape is exact */
TriangleMesh *m_triangle_mesh;
TrackObject *m_object;
/** True if a collision with this object should trigger
* rescuing a kart. */
bool m_crash_reset;
@ -71,10 +64,10 @@ private:
*/
bool m_important_animation;
void createPhysicsBody(const std::string &shape);
//scene::ISceneNode* m_node;
public:
ThreeDAnimation(const XMLNode &node);
ThreeDAnimation(const XMLNode &node, TrackObject* object);
virtual ~ThreeDAnimation();
virtual void update(float dt);
// ------------------------------------------------------------------------

View File

@ -589,3 +589,12 @@ int XMLNode::getHPR(Vec3 *value) const
} // getHPR Vec3
// ----------------------------------------------------------------------------
bool XMLNode::hasChildNamed(const char* name) const
{
for (unsigned int i = 0; i < m_nodes.size(); i++)
{
if (m_nodes[i]->getName() == name) return true;
}
return false;
}

View File

@ -100,6 +100,9 @@ public:
int getXYZ(Vec3 *vaslue) const;
int getHPR(core::vector3df *value) const;
int getHPR(Vec3 *value) const;
bool hasChildNamed(const char* name) const;
/** Handy functions to test the bit pattern returned by get(vector3df*).*/
static bool hasX(int b) { return (b&1)==1; }
static bool hasY(int b) { return (b&2)==2; }

View File

@ -22,6 +22,7 @@
#include <ISceneManager.h>
#include "animations/animation_base.hpp"
#include "animations/three_d_animation.hpp"
#include "audio/music_manager.hpp"
#include "challenges/game_slot.hpp"
#include "challenges/unlock_manager.hpp"
@ -82,9 +83,10 @@ void CutsceneWorld::init()
TrackObject* curr;
for_in(curr, objects)
{
if (curr->getType() == "particle-emitter" && !curr->getTriggerCondition().empty())
if (curr->getType() == "particle-emitter" &&
!curr->getPresentation<TrackObjectPresentationParticles>()->getTriggerCondition().empty())
{
const std::string& condition = curr->getTriggerCondition();
const std::string& condition = curr->getPresentation<TrackObjectPresentationParticles>()->getTriggerCondition();
if (StringUtils::startsWith(condition, "frame "))
{
@ -102,9 +104,9 @@ void CutsceneWorld::init()
m_particles_to_trigger[frame / FPS].push_back(curr);
}
}
else if (curr->getType() == "sfx-emitter" && !curr->getTriggerCondition().empty())
else if (curr->getType() == "sfx-emitter" && !curr->getPresentation<TrackObjectPresentationSound>()->getTriggerCondition().empty())
{
const std::string& condition = curr->getTriggerCondition();
const std::string& condition = curr->getPresentation<TrackObjectPresentationSound>()->getTriggerCondition();
if (StringUtils::startsWith(condition, "frame "))
{
@ -135,15 +137,14 @@ void CutsceneWorld::init()
float FPS = 25.0f; // for now we assume the cutscene is saved at 25 FPS
m_sounds_to_stop[frame / FPS].push_back(curr);
curr->triggerSound(true);
curr->getPresentation<TrackObjectPresentationSound>()->triggerSound(true);
}
}
if (dynamic_cast<AnimationBase*>(curr) != NULL)
if (curr->getAnimator() != NULL)
{
m_duration = std::max(m_duration,
(double)dynamic_cast<AnimationBase*>(curr)
->getAnimationDuration());
(double)curr->getAnimator()->getAnimationDuration());
}
}
@ -273,10 +274,11 @@ void CutsceneWorld::update(float dt)
{
if (curr->getType() == "cutscene_camera")
{
m_camera->setPosition(curr->getNode()->getPosition());
scene::ISceneNode* anchorNode = curr->getPresentation<TrackObjectPresentationEmpty>()->getNode();
m_camera->setPosition(anchorNode->getPosition());
m_camera->updateAbsolutePosition();
core::vector3df rot = curr->getNode()->getRotation();
core::vector3df rot = anchorNode->getRotation();
Vec3 rot2(rot);
rot2.setPitch(rot2.getPitch() + 90.0f);
m_camera->setRotation(rot2.toIrrVector());
@ -299,7 +301,7 @@ void CutsceneWorld::update(float dt)
std::vector<TrackObject*> objects = it->second;
for (unsigned int i = 0; i < objects.size(); i++)
{
objects[i]->triggerSound();
objects[i]->getPresentation<TrackObjectPresentationSound>()->triggerSound(false);
}
m_sounds_to_trigger.erase(it++);
}
@ -317,7 +319,7 @@ void CutsceneWorld::update(float dt)
std::vector<TrackObject*> objects = it->second;
for (unsigned int i = 0; i < objects.size(); i++)
{
objects[i]->triggerParticles();
objects[i]->getPresentation<TrackObjectPresentationParticles>()->triggerParticles();
}
m_particles_to_trigger.erase(it++);
}
@ -334,7 +336,7 @@ void CutsceneWorld::update(float dt)
std::vector<TrackObject*> objects = it->second;
for (unsigned int i = 0; i < objects.size(); i++)
{
objects[i]->stopSound();
objects[i]->getPresentation<TrackObjectPresentationSound>()->stopSound();
}
m_sounds_to_stop.erase(it++);
}

View File

@ -123,7 +123,7 @@ void ThreeStrikesBattle::reset()
evt.m_kart_info = m_kart_info;
m_battle_events.push_back(evt);
PhysicalObject *obj;
TrackObject *obj;
for_in(obj, m_tires)
{
m_track->getTrackObjectManager()->removeObject(obj);
@ -330,6 +330,8 @@ void ThreeStrikesBattle::update(float dt)
tire = m_tire_dir+"/wheel-rear-right.b3d";
}
// TODO: add back tires
#if 0
TrackObjectManager* tom = m_track->getTrackObjectManager();
PhysicalObject* obj =
tom->insertObject(tire,
@ -349,6 +351,7 @@ void ThreeStrikesBattle::update(float dt)
m_insert_tire = 0;
m_tires.push_back(obj);
#endif
}
} // update

View File

@ -19,7 +19,9 @@
#ifndef THREE_STRIKES_HPP
#define THREE_STRIKES_HPP
#include "modes/world_with_rank.hpp"
#include "tracks/track_object.hpp"
#include "states_screens/race_gui_base.hpp"
#include <IMesh.h>
@ -68,7 +70,7 @@ private:
/** A rotation to apply to the tires when inserting them. */
float m_tire_rotation;
PtrVector<PhysicalObject, REF> m_tires;
PtrVector<TrackObject, REF> m_tires;
public:

View File

@ -746,6 +746,14 @@ void World::updateWorld(float dt)
#define MEASURE_FPS 0
//-----------------------------------------------------------------------------
void World::scheduleTutorial()
{
m_schedule_exit_race = true;
m_schedule_tutorial = true;
}
//-----------------------------------------------------------------------------
/** Updates the physics, all karts, the track, and projectile manager.
* \param dt Time step size.

View File

@ -252,8 +252,7 @@ public:
void schedulePause(Phase phase);
void scheduleUnpause();
void scheduleExitRace() { m_schedule_exit_race = true; }
void scheduleTutorial() { m_schedule_exit_race = true;
m_schedule_tutorial = true; }
void scheduleTutorial();
void updateWorld(float dt);
void handleExplosion(const Vec3 &xyz, AbstractKart *kart_hit,
PhysicalObject *object);

View File

@ -24,11 +24,13 @@
using namespace irr;
#include "graphics/irr_driver.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/mesh_tools.hpp"
#include "io/file_manager.hpp"
#include "io/xml_node.hpp"
#include "modes/world.hpp"
#include "physics/physics.hpp"
#include "physics/triangle_mesh.hpp"
#include "tracks/track.hpp"
#include "utils/constants.hpp"
#include "utils/string_utils.hpp"
@ -37,8 +39,9 @@ using namespace irr;
#include <IMeshSceneNode.h>
// ----------------------------------------------------------------------------
PhysicalObject::PhysicalObject(const XMLNode &xml_node)
: TrackObject(xml_node)
PhysicalObject::PhysicalObject(bool kinetic, const XMLNode &xml_node,
scene::ISceneNode* scenenode)
{
m_shape = NULL;
m_body = NULL;
@ -50,6 +53,12 @@ PhysicalObject::PhysicalObject(const XMLNode &xml_node)
m_crash_reset = false;
m_explode_kart = false;
m_node = scenenode;
m_init_xyz = scenenode->getPosition();
m_init_hpr = scenenode->getRotation();
m_init_scale = scenenode->getScale();
std::string shape;
xml_node.get("mass", &m_mass );
xml_node.get("radius", &m_radius );
@ -71,36 +80,31 @@ PhysicalObject::PhysicalObject(const XMLNode &xml_node)
else if(shape=="box" ) m_body_type = MP_BOX;
else if(shape=="sphere" ) m_body_type = MP_SPHERE;
else if(shape=="exact") m_body_type = MP_EXACT;
else fprintf(stderr, "Unknown shape type : %s\n", shape.c_str());
m_init_pos.setIdentity();
Vec3 hpr(m_init_hpr);
hpr.degreeToRad();
Vec3 radHpr(m_init_hpr);
radHpr.degreeToRad();
btQuaternion q;
q.setEuler(hpr.getY(), hpr.getX(), hpr.getZ());
q.setEuler(radHpr.getY(),radHpr.getX(), radHpr.getZ());
m_init_pos.setRotation(q);
Vec3 init_xyz(m_init_xyz);
m_init_pos.setOrigin(init_xyz);
if (m_node == NULL)
{
std::string model_name;
xml_node.get("model", &model_name );
fprintf(stderr,
"[PhysicalObject] WARNING, could not locate model '%s'\n",
model_name.c_str());
}
m_kinetic = kinetic;
init();
} // PhysicalObject
// ----------------------------------------------------------------------------
/*
PhysicalObject::PhysicalObject(const std::string& model,
bodyTypes shape, float mass, float radius,
const core::vector3df& hpr,
const core::vector3df& pos,
const core::vector3df& scale)
: TrackObject(pos, hpr, scale, model)
{
m_body_type = shape;
m_mass = mass;
@ -114,16 +118,48 @@ PhysicalObject::PhysicalObject(const std::string& model,
m_init_pos.setRotation(q);
m_init_pos.setOrigin(btVector3(pos.X, pos.Y, pos.Z));
}
*/
// ----------------------------------------------------------------------------
PhysicalObject::~PhysicalObject()
{
World::getWorld()->getPhysics()->removeBody(m_body);
delete m_body;
delete m_motion_state;
delete m_shape;
// If an exact shape was used, the collision shape pointer
// here is a copy of the collision shape pointer in the
// triangle mesh. In order to avoid double-freeing this
// pointer, we don't free the pointer in this case.
if (!m_triangle_mesh)
delete m_shape;
if (m_triangle_mesh)
{
delete m_triangle_mesh;
}
} // ~PhysicalObject
// ----------------------------------------------------------------------------
void PhysicalObject::move(const Vec3& xyz, const core::vector3df& hpr)
{
Vec3 hpr2(hpr);
hpr2.degreeToRad();
btQuaternion q;
core::matrix4 mat;
mat.setRotationDegrees(hpr);
irr::core::quaternion tempQuat(mat);
q = btQuaternion(-tempQuat.X, -tempQuat.Y, -tempQuat.Z, tempQuat.W);
Vec3 p(xyz);
btTransform trans(q,p);
m_motion_state->setWorldTransform(trans);
}
// ----------------------------------------------------------------------------
/** Additional initialisation after loading of the model is finished.
*/
@ -187,57 +223,197 @@ void PhysicalObject::init()
m_graphical_offset = -0.5f*(max+min);
switch (m_body_type)
{
case MP_CONE_Y: {
if(m_radius<0) m_radius = 0.5f*extend.length_2d();
m_shape = new btConeShape(m_radius, extend.getY());
break;
}
case MP_CONE_X: {
if(m_radius<0)
m_radius = 0.5f*sqrt(extend.getY()*extend.getY() +
extend.getZ()*extend.getZ());
m_shape = new btConeShapeX(m_radius, extend.getY());
break;
}
case MP_CONE_Z: {
if(m_radius<0)
m_radius = 0.5f*sqrt(extend.getX()*extend.getX() +
extend.getY()*extend.getY());
m_shape = new btConeShapeZ(m_radius, extend.getY());
break;
}
case MP_CYLINDER_Y: {
if(m_radius<0) m_radius = 0.5f*extend.length_2d();
m_shape = new btCylinderShape(0.5f*extend);
break;
}
case MP_CYLINDER_X: {
if(m_radius<0)
m_radius = 0.5f*sqrt(extend.getY()*extend.getY() +
extend.getZ()*extend.getZ());
m_shape = new btCylinderShapeX(0.5f*extend);
break;
}
case MP_CYLINDER_Z: {
if(m_radius<0)
m_radius = 0.5f*sqrt(extend.getX()*extend.getX() +
extend.getY()*extend.getY());
m_shape = new btCylinderShapeZ(0.5f*extend);
break;
}
case MP_BOX: m_shape = new btBoxShape(0.5*extend);
break;
case MP_SPHERE: {
if(m_radius<0)
case MP_CONE_Y:
{
if (m_radius < 0) m_radius = 0.5f*extend.length_2d();
m_shape = new btConeShape(m_radius, extend.getY());
break;
}
case MP_CONE_X:
{
if (m_radius < 0)
m_radius = 0.5f*sqrt(extend.getY()*extend.getY() +
extend.getZ()*extend.getZ());
m_shape = new btConeShapeX(m_radius, extend.getY());
break;
}
case MP_CONE_Z:
{
if (m_radius < 0)
m_radius = 0.5f*sqrt(extend.getX()*extend.getX() +
extend.getY()*extend.getY());
m_shape = new btConeShapeZ(m_radius, extend.getY());
break;
}
case MP_CYLINDER_Y:
{
if (m_radius < 0) m_radius = 0.5f*extend.length_2d();
m_shape = new btCylinderShape(0.5f*extend);
break;
}
case MP_CYLINDER_X:
{
if (m_radius < 0)
m_radius = 0.5f*sqrt(extend.getY()*extend.getY() +
extend.getZ()*extend.getZ());
m_shape = new btCylinderShapeX(0.5f*extend);
break;
}
case MP_CYLINDER_Z:
{
if (m_radius < 0)
m_radius = 0.5f*sqrt(extend.getX()*extend.getX() +
extend.getY()*extend.getY());
m_shape = new btCylinderShapeZ(0.5f*extend);
break;
}
case MP_SPHERE:
{
if(m_radius<0)
{
m_radius = std::max(extend.getX(), extend.getY());
m_radius = 0.5f*std::max(m_radius, extend.getZ());
}
m_shape = new btSphereShape(m_radius);
break;
}
case MP_EXACT:
{
TriangleMesh* triangle_mesh = new TriangleMesh();
// In case of readonly materials we have to get the material from
// the mesh, otherwise from the node. This is esp. important for
// water nodes, which only have the material defined in the node,
// but not in the mesh at all!
bool is_readonly_material = false;
scene::IMesh* mesh = NULL;
switch (m_node->getType())
{
case scene::ESNT_MESH :
case scene::ESNT_WATER_SURFACE :
case scene::ESNT_OCTREE :
mesh = ((scene::IMeshSceneNode*)m_node)->getMesh();
is_readonly_material =
((scene::IMeshSceneNode*)m_node)->isReadOnlyMaterials();
break;
case scene::ESNT_ANIMATED_MESH :
// for now just use frame 0
mesh = ((scene::IAnimatedMeshSceneNode*)m_node)->getMesh()->getMesh(0);
is_readonly_material =
((scene::IAnimatedMeshSceneNode*)m_node)->isReadOnlyMaterials();
break;
default:
fprintf(stderr, "[3DAnimation] Unknown object type, cannot create exact collision body!\n");
return;
} // switch node->getType()
//core::matrix4 mat;
//mat.setRotationDegrees(hpr);
//mat.setTranslation(pos);
//core::matrix4 mat_scale;
// Note that we can't simply call mat.setScale, since this would
// overwrite the elements on the diagonal, making any rotation incorrect.
//mat_scale.setScale(scale);
//mat *= mat_scale;
for(unsigned int i=0; i<mesh->getMeshBufferCount(); i++)
{
scene::IMeshBuffer *mb = mesh->getMeshBuffer(i);
// FIXME: take translation/rotation into account
if (mb->getVertexType() != video::EVT_STANDARD &&
mb->getVertexType() != video::EVT_2TCOORDS)
{
fprintf(stderr, "WARNING: ThreeDAnimation::createPhysicsBody: Ignoring type '%d'!\n",
mb->getVertexType());
continue;
}
// Handle readonly materials correctly: mb->getMaterial can return
// NULL if the node is not using readonly materials. E.g. in case
// of a water scene node, the mesh (which is the animated copy of
// the original mesh) does not contain any material information,
// the material is only available in the node.
const video::SMaterial &irrMaterial =
is_readonly_material ? mb->getMaterial()
: m_node->getMaterial(i);
video::ITexture* t=irrMaterial.getTexture(0);
const Material* material=0;
TriangleMesh *tmesh = triangle_mesh;
if(t)
{
std::string image = std::string(core::stringc(t->getName()).c_str());
material=material_manager->getMaterial(StringUtils::getBasename(image));
if(material->isIgnore())
continue;
}
u16 *mbIndices = mb->getIndices();
Vec3 vertices[3];
Vec3 normals[3];
if (mb->getVertexType() == video::EVT_STANDARD)
{
irr::video::S3DVertex* mbVertices=(video::S3DVertex*)mb->getVertices();
for(unsigned int j=0; j<mb->getIndexCount(); j+=3)
{
for(unsigned int k=0; k<3; k++)
{
m_radius = std::max(extend.getX(), extend.getY());
m_radius = 0.5f*std::max(m_radius, extend.getZ());
}
m_shape = new btSphereShape(m_radius);
break;
}
case MP_NONE: fprintf(stderr, "WARNING: Uninitialised moving shape\n");
break;
int indx=mbIndices[j+k];
core::vector3df v = mbVertices[indx].Pos;
//mat.transformVect(v);
vertices[k]=v;
normals[k]=mbVertices[indx].Normal;
} // for k
if(tmesh) tmesh->addTriangle(vertices[0], vertices[1],
vertices[2], normals[0],
normals[1], normals[2],
material );
} // for j
}
else
{
if (mb->getVertexType() == video::EVT_2TCOORDS)
{
irr::video::S3DVertex2TCoords* mbVertices = (video::S3DVertex2TCoords*)mb->getVertices();
for(unsigned int j=0; j<mb->getIndexCount(); j+=3)
{
for(unsigned int k=0; k<3; k++)
{
int indx=mbIndices[j+k];
core::vector3df v = mbVertices[indx].Pos;
//mat.transformVect(v);
vertices[k]=v;
normals[k]=mbVertices[indx].Normal;
} // for k
if(tmesh) tmesh->addTriangle(vertices[0], vertices[1],
vertices[2], normals[0],
normals[1], normals[2],
material );
} // for j
}
}
} // for i<getMeshBufferCount
triangle_mesh->createCollisionShape();
m_shape = &triangle_mesh->getCollisionShape();
m_triangle_mesh = triangle_mesh;
break;
}
case MP_NONE:
default:
fprintf(stderr, "WARNING: Uninitialised moving shape\n");
// intended fall-through
case MP_BOX:
{
m_shape = new btBoxShape(0.5*extend);
break;
}
}
// 2. Create the rigid object
@ -258,11 +434,19 @@ void PhysicalObject::init()
m_body->setUserPointer(&m_user_pointer);
World::getWorld()->getPhysics()->addBody(m_body);
if (!m_kinetic)
{
m_body->setCollisionFlags( m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
m_body->setActivationState(DISABLE_DEACTIVATION);
}
} // init
// ----------------------------------------------------------------------------
void PhysicalObject::update(float dt)
{
if (!m_kinetic) return;
btTransform t;
m_motion_state->getWorldTransform(t);

View File

@ -26,22 +26,35 @@
#include "physics/user_pointer.hpp"
#include "tracks/track_object.hpp"
#include "utils/vec3.hpp"
#include "utils/leak_check.hpp"
class XMLNode;
/**
* \ingroup physics
*/
class PhysicalObject : public TrackObject
class PhysicalObject
{
public:
/** The supported collision shapes. */
enum bodyTypes {MP_NONE,
MP_CONE_Y, MP_CONE_X, MP_CONE_Z,
MP_CYLINDER_Y, MP_CYLINDER_X, MP_CYLINDER_Z,
MP_BOX, MP_SPHERE};
MP_BOX, MP_SPHERE, MP_EXACT};
private:
/** The initial XYZ position of the object. */
core::vector3df m_init_xyz;
/** The initial hpr of the object. */
core::vector3df m_init_hpr;
/** The initial scale of the object. */
core::vector3df m_init_scale;
scene::ISceneNode* m_node;
/** The shape of this object. */
bodyTypes m_body_type;
@ -90,20 +103,31 @@ private:
/** If m_reset_when_too_low this object is set back to its start
* position if its height is below this value. */
float m_reset_height;
public:
PhysicalObject (const XMLNode &node);
bool m_kinetic;
/** Non-null only if the shape is exact */
TriangleMesh *m_triangle_mesh;
public:
PhysicalObject(bool kinetic, const XMLNode &node,
scene::ISceneNode* scenenode);
/*
PhysicalObject(const std::string& model,
bodyTypes shape, float mass, float radius,
const core::vector3df& hpr,
const core::vector3df& pos,
const core::vector3df& scale);
*/
virtual ~PhysicalObject ();
virtual void reset ();
virtual void handleExplosion(const Vec3& pos, bool directHit);
void update (float dt);
void init ();
bool isKinetic () const { return m_kinetic; }
// ------------------------------------------------------------------------
/** Returns the rigid body of this physical object. */
btRigidBody *getBody () { return m_body; }
@ -112,6 +136,10 @@ public:
* hits it. */
bool isCrashReset() const { return m_crash_reset; }
bool isExplodeKartObject () const { return m_explode_kart; }
void move(const Vec3& xyz, const core::vector3df& hpr);
LEAK_CHECK()
}; // PhysicalObject
#endif

View File

@ -66,12 +66,12 @@ void CheckGoal::update(float dt)
if(!obj->isSoccerBall())
continue;
const Vec3 &xyz = obj->getNode()->getPosition();
const Vec3 &xyz = obj->getPresentation<TrackObjectPresentationMesh>()->getNode()->getPosition();
if(isTriggered(m_previous_position[ball_index], xyz, ball_index))
{
if(UserConfigParams::m_check_debug)
printf("CHECK: Goal check structure %d triggered for object %s.\n",
m_index, obj->getDebugName());
m_index, obj->getPresentation<TrackObjectPresentationMesh>()->getNode()->getDebugName());
trigger(ball_index);
}
m_previous_position[ball_index] = xyz;
@ -122,7 +122,7 @@ void CheckGoal::reset(const Track &track)
if(!obj->isSoccerBall())
continue;
const Vec3 &xyz = obj->getNode()->getPosition();
const Vec3 &xyz = obj->getPresentation<TrackObjectPresentationMesh>()->getNode()->getPosition();
m_previous_position.push_back(xyz);
}

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@ namespace irr
using namespace irr;
#include "items/item.hpp"
#include "utils/cpp2011.h"
#include "utils/no_copy.hpp"
#include "utils/vec3.hpp"
#include <string>
@ -36,50 +37,12 @@ using namespace irr;
class XMLNode;
class SFXBase;
class ParticleEmitter;
class PhysicalObject;
class ThreeDAnimation;
/**
* \ingroup tracks
* This is a base object for any separate object on the track, which
* might also have a skeletal animation. This is used by objects that
* have an IPO animation, as well as physical objects.
*/
class TrackObject : public scene::IAnimationEndCallBack, public NoCopy,
public TriggerItemListener
class TrackObjectPresentation
{
//public:
// The different type of track objects: physical objects, graphical
// objects (without a physical representation) - the latter might be
// eye candy (to reduce work for physics), ...
//enum TrackObjectType {TO_PHYSICAL, TO_GRAPHICAL};
private:
/** True if the object is currently being displayed. */
bool m_enabled;
/** True if it is a looped animation. */
bool m_is_looped;
/** Start frame of the animation to be played. */
unsigned int m_frame_start;
/** End frame of the animation to be played. */
unsigned int m_frame_end;
/** Currently used for sound effects only, in cutscenes only atm */
std::string m_trigger_condition;
virtual void OnAnimationEnd(scene::IAnimatedMeshSceneNode* node);
ParticleEmitter* m_emitter;
protected:
/** The irrlicht scene node this object is attached to. */
scene::ISceneNode *m_node;
/** The mesh used here. It needs to be stored so that it can be
* removed from irrlicht's mesh cache when it is deleted. */
scene::IMesh *m_mesh;
/** The initial XYZ position of the object. */
core::vector3df m_init_xyz;
@ -88,42 +51,80 @@ protected:
/** The initial scale of the object. */
core::vector3df m_init_scale;
/** If a sound is attached to this object and/or this is a sound emitter object */
SFXBase* m_sound;
/** LOD group this object is part of, if it is LOD */
std::string m_lod_group;
/** For action trigger objects */
std::string m_action;
std::string m_interaction;
std::string m_type;
LODNode* m_lod_emitter_node;
bool m_soccer_ball;
public:
TrackObject(const XMLNode &xml_node);
TrackObject();
TrackObject(const core::vector3df& pos, const core::vector3df& hpr,
const core::vector3df& scale, const std::string& model);
~TrackObject();
virtual void update(float dt);
virtual void reset();
/** To finish object constructions. Called after the track model
* is ready. */
virtual void init() {};
/** Called when an explosion happens. As a default does nothing, will
* e.g. be overwritten by physical objects etc. */
virtual void handleExplosion(const Vec3& pos, bool directHit) {};
void setEnable(bool mode);
TrackObjectPresentation(const XMLNode& xml_node);
virtual ~TrackObjectPresentation() {}
virtual void reset() {}
virtual void setEnable(bool enabled) {}
virtual void update(float dt) {}
virtual void move(const core::vector3df& xyz, const core::vector3df& hpr,
const core::vector3df& scale) {}
virtual const core::vector3df& getPosition() const { return m_init_xyz; }
virtual const core::vector3df& getRotation() const { return m_init_hpr; }
virtual const core::vector3df& getScale() const { return m_init_scale; }
LEAK_CHECK()
};
class TrackObjectPresentationSceneNode : public TrackObjectPresentation
{
protected:
scene::ISceneNode* m_node;
public:
TrackObjectPresentationSceneNode(const XMLNode& xml_node) :
TrackObjectPresentation(xml_node)
{
m_node = NULL;
}
virtual const core::vector3df& getPosition() const OVERRIDE;
virtual const core::vector3df& getRotation() const OVERRIDE;
virtual const core::vector3df& getScale() const OVERRIDE;
virtual void move(const core::vector3df& xyz, const core::vector3df& hpr,
const core::vector3df& scale) OVERRIDE;
virtual void setEnable(bool enabled) OVERRIDE;
virtual void reset() OVERRIDE;
scene::ISceneNode* getNode() { return m_node; }
const scene::ISceneNode* getNode() const { return m_node; }
};
class TrackObjectPresentationEmpty : public TrackObjectPresentationSceneNode
{
public:
TrackObjectPresentationEmpty(const XMLNode& xml_node);
virtual ~TrackObjectPresentationEmpty();
};
class TrackObjectPresentationMesh : public TrackObjectPresentationSceneNode
{
private:
/** The mesh used here. It needs to be stored so that it can be
* removed from irrlicht's mesh cache when it is deleted. */
scene::IMesh *m_mesh;
/** True if it is a looped animation. */
bool m_is_looped;
/** Start frame of the animation to be played. */
unsigned int m_frame_start;
/** End frame of the animation to be played. */
unsigned int m_frame_end;
public:
TrackObjectPresentationMesh(const XMLNode& xml_node, bool enabled);
virtual ~TrackObjectPresentationMesh();
virtual void reset() OVERRIDE;
/** 2-step construction */
void setNode(scene::ISceneNode* node)
@ -149,22 +150,182 @@ public:
m_node->setScale(m_init_scale);
}
}
};
class TrackObjectPresentationSound : public TrackObjectPresentation,
public TriggerItemListener
{
private:
/** If a sound is attached to this object and/or this is a sound emitter object */
SFXBase* m_sound;
/** Currently used for sound effects only, in cutscenes only atm */
std::string m_trigger_condition;
core::vector3df m_xyz;
public:
TrackObjectPresentationSound(const XMLNode& xml_node);
virtual ~TrackObjectPresentationSound();
virtual void onTriggerItemApproached(Item* who) OVERRIDE;
virtual void update(float dt) OVERRIDE;
void triggerSound(bool loop);
void stopSound();
/** Currently used for sound effects only, in cutscenes only atm */
const std::string& getTriggerCondition() const { return m_trigger_condition; }
virtual void move(const core::vector3df& xyz, const core::vector3df& hpr,
const core::vector3df& scale) OVERRIDE;
};
class TrackObjectPresentationBillboard : public TrackObjectPresentationSceneNode
{
/** To make the billboard disappear when close to the camera. Useful for light halos :
* instead of "colliding" with the camera and suddenly disappearing when clipped by
* frustum culling, it will gently fade out.
*/
bool m_fade_out_when_close;
float m_fade_out_start;
float m_fade_out_end;
public:
TrackObjectPresentationBillboard(const XMLNode& xml_node);
virtual ~TrackObjectPresentationBillboard();
virtual void update(float dt) OVERRIDE;
};
class TrackObjectPresentationParticles : public TrackObjectPresentation
{
private:
ParticleEmitter* m_emitter;
LODNode* m_lod_emitter_node;
std::string m_trigger_condition;
public:
TrackObjectPresentationParticles(const XMLNode& xml_node);
virtual ~TrackObjectPresentationParticles();
virtual void update(float dt) OVERRIDE;
virtual void move(const core::vector3df& xyz, const core::vector3df& hpr,
const core::vector3df& scale) OVERRIDE;
std::string& getTriggerCondition() { return m_trigger_condition; }
void triggerParticles();
};
class TrackObjectPresentationActionTrigger : public TrackObjectPresentation,
public TriggerItemListener
{
private:
/** For action trigger objects */
std::string m_action;
public:
TrackObjectPresentationActionTrigger(const XMLNode& xml_node);
virtual ~TrackObjectPresentationActionTrigger() {}
virtual void onTriggerItemApproached(Item* who) OVERRIDE;
};
/**
* \ingroup tracks
* This is a base object for any separate object on the track, which
* might also have a skeletal animation. This is used by objects that
* have an IPO animation, as well as physical objects.
*/
class TrackObject : public NoCopy
{
//public:
// The different type of track objects: physical objects, graphical
// objects (without a physical representation) - the latter might be
// eye candy (to reduce work for physics), ...
//enum TrackObjectType {TO_PHYSICAL, TO_GRAPHICAL};
private:
/** True if the object is currently being displayed. */
bool m_enabled;
TrackObjectPresentation* m_presentation;
protected:
/** The initial XYZ position of the object. */
core::vector3df m_init_xyz;
/** The initial hpr of the object. */
core::vector3df m_init_hpr;
/** The initial scale of the object. */
core::vector3df m_init_scale;
/** LOD group this object is part of, if it is LOD */
std::string m_lod_group;
std::string m_interaction;
std::string m_type;
bool m_soccer_ball;
PhysicalObject* m_rigid_body;
ThreeDAnimation* m_animator;
public:
TrackObject(const XMLNode &xml_node);
TrackObject();
/*
TrackObject(const core::vector3df& pos, const core::vector3df& hpr,
const core::vector3df& scale, const std::string& model);
*/
~TrackObject();
virtual void update(float dt);
virtual void reset();
/** To finish object constructions. Called after the track model
* is ready. */
virtual void init() {};
/** Called when an explosion happens. As a default does nothing, will
* e.g. be overwritten by physical objects etc. */
virtual void handleExplosion(const Vec3& pos, bool directHit) {};
void setEnable(bool mode);
const std::string& getLodGroup() const { return m_lod_group; }
const std::string& getType() const { return m_type; }
bool isSoccerBall() const { return m_soccer_ball; }
const PhysicalObject* getPhysics() const { return m_rigid_body; }
PhysicalObject* getPhysics() { return m_rigid_body; }
const core::vector3df getInitXYZ() const { return m_init_xyz; }
const core::vector3df getInitRotation() const { return m_init_hpr; }
const core::vector3df getInitScale() const { return m_init_scale; }
/** Currently used for sound effects only, in cutscenes only atm */
const std::string& getTriggerCondition() const { return m_trigger_condition; }
void move(const core::vector3df& xyz, const core::vector3df& hpr, const core::vector3df& scale);
template<typename T>
T* getPresentation() { return dynamic_cast<T*>(m_presentation); }
template<typename T>
const T* getPresentation() const { return dynamic_cast<T*>(m_presentation); }
void triggerSound(bool loop=false);
void stopSound();
void triggerParticles();
virtual void onTriggerItemApproached(Item* who);
ThreeDAnimation* getAnimator() { return m_animator; }
const ThreeDAnimation* getAnimator() const { return m_animator; }
const core::vector3df& getPosition() const;
const core::vector3df& getRotation() const;
const core::vector3df& getScale() const;
}; // TrackObject
#endif

View File

@ -20,7 +20,6 @@
#include "animations/ipo.hpp"
#include "config/user_config.hpp"
#include "animations/billboard_animation.hpp"
#include "animations/three_d_animation.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/lod_node.hpp"
@ -52,6 +51,8 @@ void TrackObjectManager::add(const XMLNode &xml_node)
{
try
{
m_all_objects.push_back(new TrackObject(xml_node));
/*
std::string groupname;
xml_node.get("lod_group", &groupname);
bool is_lod = !groupname.empty();
@ -67,11 +68,12 @@ void TrackObjectManager::add(const XMLNode &xml_node)
{
if (is_lod)
{
m_lod_objects[groupname].push_back(new PhysicalObject(xml_node));
assert(false); // TODO
//_lod_objects[groupname].push_back(new TrackObject(xml_node));
}
else
{
m_all_objects.push_back(new PhysicalObject(xml_node));
m_all_objects.push_back(new TrackObject(xml_node));
}
}
else if(type=="animation")
@ -106,6 +108,7 @@ void TrackObjectManager::add(const XMLNode &xml_node)
fprintf(stderr, "Unknown track object: '%s' - ignored.\n",
type.c_str());
}
*/
}
catch (std::exception& e)
{
@ -153,8 +156,8 @@ void TrackObjectManager::handleExplosion(const Vec3 &pos, const PhysicalObject *
TrackObject* curr;
for_in (curr, m_all_objects)
{
if(secondary_hits || mp==curr)
curr->handleExplosion(pos, mp == curr);
if(secondary_hits || mp == curr->getPhysics())
curr->handleExplosion(pos, mp == curr->getPhysics());
}
} // handleExplosion
@ -228,27 +231,33 @@ void TrackObjectManager::enableFog(bool enable)
TrackObject* curr;
for_in (curr, m_all_objects)
{
if (curr->getNode() != NULL)
TrackObjectPresentationMesh* meshPresentation =
curr->getPresentation<TrackObjectPresentationMesh>();
if (meshPresentation!= NULL)
{
adjustForFog(curr->getNode(), enable);
adjustForFog(meshPresentation->getNode(), enable);
}
}
} // enableFog
// ----------------------------------------------------------------------------
PhysicalObject* TrackObjectManager::insertObject(const std::string& model,
TrackObject* TrackObjectManager::insertObject(const std::string& model,
PhysicalObject::bodyTypes shape,
float mass, float radius,
const core::vector3df& hpr,
const core::vector3df& pos,
const core::vector3df& scale)
{
/*
PhysicalObject* object = new PhysicalObject(model, shape, mass, radius,
hpr, pos, scale);
object->init();
m_all_objects.push_back(object);
return object;
*/
assert(false);
// TODO
}
// ----------------------------------------------------------------------------
@ -256,7 +265,7 @@ PhysicalObject* TrackObjectManager::insertObject(const std::string& model,
* track objects, and then frees the object.
* \param obj The physical object to remove.
*/
void TrackObjectManager::removeObject(PhysicalObject* obj)
void TrackObjectManager::removeObject(TrackObject* obj)
{
m_all_objects.remove(obj);
delete obj;
@ -277,7 +286,7 @@ void TrackObjectManager::assingLodNodes(const std::vector<LODNode*>& lod_nodes)
std::vector<TrackObject*>& queue = m_lod_objects[ lod_nodes[n]->getGroupName() ];
assert( queue.size() > 0 );
TrackObject* obj = queue[ queue.size() - 1 ];
obj->setNode( lod_nodes[n] );
obj->getPresentation<TrackObjectPresentationMesh>()->setNode( lod_nodes[n] );
queue.erase( queue.end() - 1 );
m_all_objects.push_back(obj);

View File

@ -64,14 +64,14 @@ public:
/** Enable or disable fog on objects */
void enableFog(bool enable);
PhysicalObject* insertObject(const std::string& model,
TrackObject* insertObject(const std::string& model,
PhysicalObject::bodyTypes shape,
float mass, float radius,
const core::vector3df& hpr,
const core::vector3df& pos,
const core::vector3df& scale);
void removeObject(PhysicalObject* who);
void removeObject(TrackObject* who);
void assingLodNodes(const std::vector<LODNode*>& lod);