From 253f495021abe8220658029b3621e16546218568 Mon Sep 17 00:00:00 2001 From: hikerstk Date: Wed, 25 Feb 2009 13:14:27 +0000 Subject: [PATCH] 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 --- src/gui/race_gui.cpp | 3 +- src/io/xml_node.cpp | 41 ++++++++++- src/io/xml_node.hpp | 2 + src/items/item.cpp | 20 ++++- src/items/item.hpp | 10 +-- src/items/item_manager.cpp | 12 ++- src/items/item_manager.hpp | 2 +- src/physics/triangle_mesh.cpp | 13 ++++ src/physics/triangle_mesh.hpp | 5 +- src/tracks/track.cpp | 133 +++++++++++++++++++++++----------- src/tracks/track.hpp | 7 +- 11 files changed, 189 insertions(+), 59 deletions(-) diff --git a/src/gui/race_gui.cpp b/src/gui/race_gui.cpp index 9d0f6268d..cc7fd06eb 100644 --- a/src/gui/race_gui.cpp +++ b/src/gui/race_gui.cpp @@ -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 //----------------------------------------------------------------------------- diff --git a/src/io/xml_node.cpp b/src/io/xml_node.cpp index fbe9ae1c1..898b3e51c 100755 --- a/src/io/xml_node.cpp +++ b/src/io/xml_node.cpp @@ -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 diff --git a/src/io/xml_node.hpp b/src/io/xml_node.hpp index 22211fe15..38b3d6138 100755 --- a/src/io/xml_node.hpp +++ b/src/io/xml_node.hpp @@ -50,6 +50,8 @@ public: int get(const std::string &attribute, std::vector *value) const; int get(const std::string &attribute, std::vector *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; } diff --git a/src/items/item.cpp b/src/items/item.cpp index 9494c675c..e3c3f8d80 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -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(&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(&m_coord.toSgCoord())); #endif } diff --git a/src/items/item.hpp b/src/items/item.hpp index 2ddd39ecc..dfda45ac5 100644 --- a/src/items/item.hpp +++ b/src/items/item.hpp @@ -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 diff --git a/src/items/item_manager.cpp b/src/items/item_manager.cpp index 2b2b3d7b6..c90caa61b 100644 --- a/src/items/item_manager.cpp +++ b/src/items/item_manager.cpp @@ -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 m_all_meshes; #else ssgEntity *m_item_model[Item::ITEM_SILVER_COIN+1]; diff --git a/src/physics/triangle_mesh.cpp b/src/physics/triangle_mesh.cpp index 71effa4cf..0e2c188d6 100644 --- a/src/physics/triangle_mesh.cpp +++ b/src/physics/triangle_mesh.cpp @@ -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 + +// ----------------------------------------------------------------------------- diff --git a/src/physics/triangle_mesh.hpp b/src/physics/triangle_mesh.hpp index 223c543ab..a2c2b833f 100644 --- a/src/physics/triangle_mesh.hpp +++ b/src/physics/triangle_mesh.hpp @@ -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 #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 diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index a5c72f576..f93ec05c5 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -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; igetMeshBufferCount(); i++) { - scene::IMeshBuffer *mb = track->getMeshBuffer(i); +void Track::convertTrackToBullet(const scene::IMesh *mesh) +{ + for(unsigned int i=0; igetMeshBufferCount(); 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; jgetIndexCount(); 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 igetTrackFile(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 '"<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; diff --git a/src/tracks/track.hpp b/src/tracks/track.hpp index 1348d516a..39f849aa7 100644 --- a/src/tracks/track.hpp +++ b/src/tracks/track.hpp @@ -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& 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