Irrlicht only: added support for height computation for items

(and other models loaded for a track), items now do rotate
and can be collected (though no icons are displayed yet,
nor do attachments work).


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@3196 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2009-02-25 13:14:27 +00:00
parent a9b0a695d4
commit 253f495021
11 changed files with 189 additions and 59 deletions

View File

@ -435,6 +435,7 @@ void RaceGUI::drawPowerupIcons ( Kart* player_kart, int offset_x,
int y1 = (int)(user_config->m_height*5/6 * ratio_y) + offset_y;
int nSize=(int)(64.0f*std::min(ratio_x, ratio_y));
#ifndef HAVE_IRRLICHT
powerup->getIcon()->apply();
int n = player_kart->getNumPowerup() ;
@ -453,7 +454,7 @@ void RaceGUI::drawPowerupIcons ( Kart* player_kart, int offset_x,
glTexCoord2f(0, 1); glVertex2i( i*30 + x1 , y1+nSize);
} // for i
glEnd () ;
#endif
} // drawPowerupIcons
//-----------------------------------------------------------------------------

View File

@ -198,6 +198,45 @@ int XMLNode::get(core::vector3df *value) const
if(get("z", &f)) { value->Z = f; bits |= 4; }
if(get("r", &f)) { value->Z = f; bits |= 4; }
return bits;
}
} // core::vector3df
// ----------------------------------------------------------------------------
/** Interprets the attributes 'x', 'y', 'z' as a 3d vector and set the
* corresponding elements of value. Not all values need to be defined as
* attributes (and the correspnding elements of the vector will not be
* changed). It returns a bit field for each defined value, i.e. if x
* and y are defined, 3 is returned.
* \param value Vector to return the values in.
*/
int XMLNode::getXYZ(core::vector3df *value) const
{
float f;
int bits=0;
core::vector3df result = *value;
if(get("x", &f)) { value->X = f; bits |= 1; }
if(get("y", &f)) { value->Y = f; bits |= 2; }
if(get("z", &f)) { value->Z = f; bits |= 4; }
return bits;
} // getXYZ
// ----------------------------------------------------------------------------
/** Interprets the attributes 'h', 'p', 'r' as a 3d vector and set the
* corresponding elements of value. Not all values need to be defined as
* attributes (and the correspnding elements of the vector will not be
* changed). It returns a bit field for each defined value, i.e. if x and y
* are defined, 3 is returned.
* \param value Vector to return the values in.
*/
int XMLNode::getHPR(core::vector3df *value) const
{
float f;
int bits=0;
core::vector3df result = *value;
if(get("h", &f)) { value->X = f; bits |= 1; }
if(get("p", &f)) { value->Y = f; bits |= 2; }
if(get("r", &f)) { value->Z = f; bits |= 4; }
return bits;
} // getHPR
// ----------------------------------------------------------------------------
#endif

View File

@ -50,6 +50,8 @@ public:
int get(const std::string &attribute, std::vector<float> *value) const;
int get(const std::string &attribute, std::vector<int> *value) const;
int get(core::vector3df *value) const;
int getXYZ(core::vector3df *value) const;
int getHPR(core::vector3df *value) 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

@ -19,6 +19,7 @@
#include "items/item.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/scene.hpp"
#include "karts/kart.hpp"
#include "utils/coord.hpp"
@ -43,6 +44,9 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
m_collected = false;
m_time_till_return = 0.0f; // not strictly necessary, see isCollected()
#ifdef HAVE_IRRLICHT
m_root = irr_driver->addMesh(mesh);
m_root->setPosition(xyz.toIrrVector());
m_root->grab();
#else
m_root = new ssgTransform();
m_root->ref();
@ -56,6 +60,8 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
Item::~Item()
{
#ifdef HAVE_IRRLICHT
m_root->drop();
#else
stk_scene->remove(m_root);
ssgDeRefDelete(m_root);
@ -94,14 +100,18 @@ void Item::update(float delta)
hell.setZ( (m_time_till_return>1.0f) ? -1000000.0f
: m_coord.getXYZ().getZ() - m_time_till_return / 2.0f);
#ifndef HAVE_IRRLICHT
#ifdef HAVE_IRRLICHT
m_root->setPosition(hell.toIrrVector());
#else
m_root->setTransform(hell.toFloat());
#endif
}
else
{
m_collected = false;
#ifndef HAVE_IRRLICHT
#ifdef HAVE_IRRLICHT
#else
m_root->setTransform(const_cast<sgCoord*>(&m_coord.toSgCoord()));
#endif
} // T>0
@ -112,10 +122,12 @@ void Item::update(float delta)
if(!m_rotate) return;
// have it rotate
#ifdef HAVE_IRRLICHT
#else
Vec3 rotation(delta*M_PI, 0, 0);
m_coord.setHPR(m_coord.getHPR()+rotation);
#ifdef HAVE_IRRLICHT
m_root->setRotation(m_coord.getHPR().toIrrHPR());
m_root->setPosition(m_coord.getXYZ().toIrrVector());
#else
m_root->setTransform(const_cast<sgCoord*>(&m_coord.toSgCoord()));
#endif
}

View File

@ -39,15 +39,13 @@ class Item
public:
enum ItemType
{
ITEM_FIRST = -1,
ITEM_BONUS_BOX = 0,
ITEM_FIRST,
ITEM_BONUS_BOX = ITEM_FIRST,
ITEM_BANANA,
ITEM_GOLD_COIN,
ITEM_SILVER_COIN,
ITEM_BUBBLEGUM,
ITEM_LAST
ITEM_LAST = ITEM_BUBBLEGUM
};
private:
@ -57,6 +55,8 @@ private:
Coord m_coord; // Original coordinates, used mainly when
// collected items reappear.
#ifdef HAVE_IRRLICHT
/** Scene node of this item. */
scene::ISceneNode *m_root;
#else
ssgTransform* m_root; // The actual root of the item
#endif

View File

@ -26,6 +26,7 @@
#include "loader.hpp"
#include "material_manager.hpp"
#include "material.hpp"
#include "graphics/irr_driver.hpp"
#include "items/item_manager.hpp"
#include "items/bubblegumitem.hpp"
#include "karts/kart.hpp"
@ -160,6 +161,13 @@ void ItemManager::loadDefaultItems()
i != files.end(); ++i)
{
#ifdef HAVE_IRRLICHT
// FIXME: We should try to check the extension,
// i.e. load only .3ds files
scene::IMesh *mesh = irr_driver->getAnimatedMesh(*i);
if(!mesh) continue;
std::string shortName = StringUtils::basename(StringUtils::without_extension(*i));
m_all_meshes[shortName] = mesh;
mesh->grab();
#else
if(!StringUtils::has_suffix(*i, ".ac")) continue;
ssgEntity* h = loader->load(*i, CB_ITEM,
@ -179,7 +187,7 @@ void ItemManager::loadDefaultItems()
void ItemManager::setDefaultItemStyle()
{
// FIXME - This should go in an internal, system wide configuration file
std::string DEFAULT_NAMES[Item::ITEM_LAST - Item::ITEM_FIRST - 1];
std::string DEFAULT_NAMES[Item::ITEM_LAST - Item::ITEM_FIRST +1];
DEFAULT_NAMES[Item::ITEM_BONUS_BOX] = "gift-box";
DEFAULT_NAMES[Item::ITEM_BANANA] = "banana";
DEFAULT_NAMES[Item::ITEM_GOLD_COIN] = "nitrotank-big";
@ -188,7 +196,7 @@ void ItemManager::setDefaultItemStyle()
bool bError=0;
std::ostringstream msg;
for(int i=Item::ITEM_FIRST+1; i<Item::ITEM_LAST; i++)
for(int i=Item::ITEM_FIRST; i<=Item::ITEM_LAST; i++)
{
#ifdef HAVE_IRRLICHT
m_item_mesh[i] = m_all_meshes[DEFAULT_NAMES[i]];

View File

@ -40,7 +40,7 @@ private:
// This stores all item models
#ifdef HAVE_IRRLICHT
// FIXME: why ITEM_SILVER_COINT+1 in plib??
scene::IMesh *m_item_mesh[Item::ITEM_LAST];
scene::IMesh *m_item_mesh[Item::ITEM_LAST-Item::ITEM_FIRST+1];
std::map<std::string,scene::IMesh*> m_all_meshes;
#else
ssgEntity *m_item_model[Item::ITEM_SILVER_COIN+1];

View File

@ -76,3 +76,16 @@ void TriangleMesh::createBody(btCollisionObject::CollisionFlags flags)
} // createBody
// -----------------------------------------------------------------------------
/** Removes the created body from the physics world. This is used when creating
* a temporary rigid body of the main track to get bullet raycasts. Then the
* main track is removed, and the track (main track including all additional
* objects which were loaded later) is converted again.
*/
void TriangleMesh::removeBody()
{
RaceManager::getWorld()->getPhysics()->removeBody(m_body);
delete m_body;
m_body = 0;
} // removeBody
// -----------------------------------------------------------------------------

View File

@ -17,8 +17,8 @@
// 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_TRIANGLE_MESH_H
#define HEADER_TRIANGLE_MESH_H
#ifndef HEADER_TRIANGLE_MESH_HPP
#define HEADER_TRIANGLE_MESH_HPP
#include <vector>
#include "user_pointer.hpp"
@ -45,6 +45,7 @@ public:
const btVector3 &t3, const Material* m);
void createBody(btCollisionObject::CollisionFlags flags=
(btCollisionObject::CollisionFlags)0);
void removeBody();
const Material* getMaterial(int n) const {return m_triangleIndex2Material[n];}
};
#endif

View File

@ -58,16 +58,18 @@ const int Track::UNKNOWN_SECTOR = -1;
// ----------------------------------------------------------------------------
Track::Track( std::string filename_, float w, float h, bool stretch )
{
m_filename = filename_;
m_item_style = "";
m_track_2d_width = w;
m_track_2d_height = h;
m_do_stretch = stretch;
m_description = "";
m_designer = "";
m_screenshot = "";
m_top_view = "";
m_version = 0;
m_filename = filename_;
m_item_style = "";
m_track_2d_width = w;
m_track_2d_height = h;
m_do_stretch = stretch;
m_description = "";
m_designer = "";
m_screenshot = "";
m_top_view = "";
m_version = 0;
m_track_mesh = new TriangleMesh();
m_non_collision_mesh = new TriangleMesh();
#ifdef HAVE_IRRLICHT
m_all_nodes.clear();
m_all_meshes.clear();
@ -1147,11 +1149,20 @@ void Track::createPhysicsModel()
if(!m_model) return;
#endif
m_track_mesh = new TriangleMesh();
m_non_collision_mesh = new TriangleMesh();
#ifdef HAVE_IRRLICHT
convertTrackToBullet();
// Remove the temporary track rigid body, and then convert all objects
// (i.e. the track and all additional objects) into a new rigid body
// and convert this again. So this way we have an optimised track
// rigid body which includes all track objects.
// Note that removing the rigid body does not remove the already collected
// triangle information, so there is no need to convert the actual track
// (first element in m_track_mesh) again!
m_track_mesh->removeBody();
for(unsigned int i=1; i<m_all_meshes.size(); i++)
{
convertTrackToBullet(m_all_meshes[i]);
}
#else
// Collect all triangles in the track_mesh
sgMat4 mat;
@ -1166,19 +1177,10 @@ void Track::createPhysicsModel()
// -----------------------------------------------------------------------------
//* Convert the ssg track tree into its physics equivalents.
#ifdef HAVE_IRRLICHT
void Track::convertTrackToBullet()
{
// 0: start line
// 1: left/right drivelines or so
// 2: road
// 3: zipper or collectables??
// 4: barriers
// 5: plane
for(unsigned int i=0; i<m_all_meshes.size(); i++)
{
const scene::IMesh *track = m_all_meshes[i];
for(unsigned int i=0; i<track->getMeshBufferCount(); i++) {
scene::IMeshBuffer *mb = track->getMeshBuffer(i);
void Track::convertTrackToBullet(const scene::IMesh *mesh)
{
for(unsigned int i=0; i<mesh->getMeshBufferCount(); i++) {
scene::IMeshBuffer *mb = mesh->getMeshBuffer(i);
// FIXME: take translation/rotation into accou
if(mb->getVertexType()!=video::EVT_STANDARD) {
fprintf(stderr, "WARNING: Physics::convertTrack: Ignoring type '%d'!",
@ -1195,7 +1197,7 @@ void Track::convertTrackToBullet()
}
u16 *mbIndices = mb->getIndices();
btVector3 vertices[3];
Vec3 vertices[3];
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++) {
@ -1204,15 +1206,14 @@ void Track::convertTrackToBullet()
// (STK: Z up, irrlicht: Y up). We might want to change
// this as well, makes it easier to work with bullet and
// irrlicht together, without having to swap indices.
vertices[k] = btVector3(mbVertices[indx].Pos.X,
mbVertices[indx].Pos.Z,
mbVertices[indx].Pos.Y );
vertices[k] = Vec3(mbVertices[indx].Pos.X,
mbVertices[indx].Pos.Z,
mbVertices[indx].Pos.Y );
} // for k
m_track_mesh->addTriangle(vertices[0], vertices[1],
vertices[2], material );
} // for j
} // for i<getMeshBufferCount
} // for obj in children
} // convertTrackToBullet
@ -1284,6 +1285,46 @@ void Track::convertTrackToBullet(ssgEntity *track, sgMat4 m)
} // convertTrackToBullet
#endif
// ----------------------------------------------------------------------------
/** Loads the main track model (i.e. all other objects contained in the
* scene might use raycast on this track model to determine the actual
* height of the terrain.
*/
#ifdef HAVE_IRRLICHT
bool Track::loadMainTrack(const XMLNode &node)
{
std::string model_name;
node.get("model", &model_name);
std::string full_path = file_manager->getTrackFile(model_name,
getIdent());
scene::IMesh *mesh = irr_driver->getAnimatedMesh(full_path);
if(!mesh)
{
fprintf(stderr, "Warning: Main track model '%s' in '%s' not found, aborting.\n",
node.getName().c_str(), model_name.c_str());
exit(-1);
}
m_all_meshes.push_back(mesh);
scene::ISceneNode *scene_node = irr_driver->addOctTree(mesh);
core::vector3df xyz(0,0,0);
node.getXYZ(&xyz);
core::vector3df hpr(0,0,0);
node.getHPR(&hpr);
scene_node->setPosition(xyz);
scene_node->setRotation(hpr);
m_all_nodes.push_back(scene_node);
scene_node->setMaterialFlag(video::EMF_LIGHTING, false);
Vec3 min, max;
MeshTools::minMax3D(mesh, &min, &max);
RaceManager::getWorld()->getPhysics()->init(min, max);
// This will (at this stage) only convert the main track model.
convertTrackToBullet(mesh);
m_track_mesh->createBody();
return true;
} // loadMainTrack
#endif
// ----------------------------------------------------------------------------
void Track::loadTrackModel()
{
// Add the track directory to the texture search path
@ -1308,19 +1349,22 @@ void Track::loadTrackModel()
// Make sure that we have a track (which is used for raycasts to
// place other objects).
const XMLNode *node = xml->getNode(0);
if(!node || node->getName()!="track")
const XMLNode *node = xml->getNode("track");
if(!node)
{
std::ostringstream msg;
msg<< "No track model defined in '"<<path
<<"' (it must be the first element).";
<<"', aborting.";
throw std::runtime_error(msg.str());
}
loadMainTrack(*node);
for(unsigned int i=0; i<xml->getNumNodes(); i++)
{
const XMLNode *node = xml->getNode(i);
const std::string name = node->getName();
if(name=="track" || name=="object")
// The track object was already converted before the loop
if(name=="track") continue;
if(name=="object")
{
std::string model_name;
node->get("model", &model_name);
@ -1607,19 +1651,17 @@ void Track::loadTrackModel()
file_manager->popTextureSearchPath();
file_manager->popModelSearchPath ();
Vec3 min, max;
#ifdef HAVE_IRRLICHT
// FIXME: for now assume that mesh 0 is the actual track.
MeshTools::minMax3D(m_all_meshes[0], &min, &max);
const core::vector3df &sun_pos = getSunPos();
m_light = irr_driver->getSceneManager()->addLightSceneNode(0, sun_pos);
video::SLight light;
m_light->setLightData(light);
// Note: the physics world for irrlicht is created in loadMainTrack
#else
Vec3 min, max;
SSGHelp::MinMax(m_model, &min, &max);
#endif
RaceManager::getWorld()->getPhysics()->init(min, max);
#endif
createPhysicsModel();
} // loadTrack
@ -1634,7 +1676,16 @@ void Track::itemCommand(core::vector3df *xyz, Item::ItemType type,
return;
// if only 2d coordinates are given, let the item fall from very high
if(bNeedHeight) xyz->Z = 1000000.0f;
if(bNeedHeight)
{
Vec3 pos(*xyz);
float m_HoT;
Vec3 m_normal;
const Material *material;
pos.setZ(1000);
getTerrainInfo(pos, &m_HoT, &m_normal, &material);
xyz->Z = m_HoT;
}
// Even if 3d data are given, make sure that the item is on the ground
//xyz->Z = irr_dirver->getHeight( m_model, *xyz ) + 0.06f;

View File

@ -42,6 +42,7 @@ using namespace irr;
#include "utils/vec3.hpp"
class TriangleMesh;
class XMLNode;
class Track
{
@ -71,7 +72,9 @@ private:
Vec3 m_camera_final_hpr;
bool m_is_arena;
int m_version;
#ifdef HAVE_IRRLICHT
bool loadMainTrack(const XMLNode &node);
#endif
public:
enum RoadSide{ RS_DONT_KNOW = -1, RS_LEFT = 0, RS_RIGHT = 1 };
@ -239,7 +242,7 @@ private:
void readDrivelineFromFile(std::vector<Vec3>& line,
const std::string& file_ext);
#ifdef HAVE_IRRLICHT
void convertTrackToBullet();
void convertTrackToBullet(const scene::IMesh *mesh);
#else
void convertTrackToBullet(ssgEntity *track, sgMat4 m);
#endif