Refactor LOD loading to make it easier to make animated LOD objects next

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@10321 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
auria 2011-12-04 00:51:20 +00:00
parent ee27609d42
commit 3c4c88e57f
6 changed files with 269 additions and 130 deletions

View File

@ -24,7 +24,7 @@
#include <ISceneNode.h>
namespace irr
{
namespace scene { class ISceneManager; }
namespace scene { class ISceneManager; class ISceneNode; }
}
using namespace irr;
@ -49,7 +49,7 @@ private:
core::aabbox3d<f32> Box;
std::vector<int> m_detail;
std::vector<scene::ISceneNode*> m_nodes;
std::vector<irr::scene::ISceneNode*> m_nodes;
std::set<scene::ISceneNode*> m_nodes_set;

View File

@ -340,6 +340,7 @@
9598A5B613CFBA83000B83EA /* hardware_skinning.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9598A5B413CFBA83000B83EA /* hardware_skinning.cpp */; };
959DE0C613C297B90068ED78 /* swatter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 959DE0C413C297B90068ED78 /* swatter.cpp */; };
95A0BA2413E63F6700620EA6 /* kart_with_stats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95A0BA2213E63F6700620EA6 /* kart_with_stats.cpp */; };
95AA4C67148AF2CC0053771D /* lod_node_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95AA4C65148AF2CC0053771D /* lod_node_loader.cpp */; };
95AAD98012BAD36300B7B8A3 /* tutorial_screen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95AAD97E12BAD36300B7B8A3 /* tutorial_screen.cpp */; };
95B5CD14102DE08F00EF2001 /* device_config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95B5CD13102DE08F00EF2001 /* device_config.cpp */; };
95BF1E68127513A100F78AE7 /* max_speed.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95BF1E66127513A100F78AE7 /* max_speed.cpp */; };
@ -1149,6 +1150,8 @@
95A540411481BEB60086FE38 /* dummy_network_http.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = dummy_network_http.hpp; path = ../../addons/dummy_network_http.hpp; sourceTree = SOURCE_ROOT; };
95A540581481C4760086FE38 /* dummy_sfx.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = dummy_sfx.hpp; path = ../../audio/dummy_sfx.hpp; sourceTree = SOURCE_ROOT; };
95A5405B1481C4DB0086FE38 /* music_dummy.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = music_dummy.hpp; path = ../../audio/music_dummy.hpp; sourceTree = SOURCE_ROOT; };
95AA4C65148AF2CC0053771D /* lod_node_loader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = lod_node_loader.cpp; path = ../../tracks/lod_node_loader.cpp; sourceTree = SOURCE_ROOT; };
95AA4C66148AF2CC0053771D /* lod_node_loader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = lod_node_loader.hpp; path = ../../tracks/lod_node_loader.hpp; sourceTree = SOURCE_ROOT; };
95AAD97E12BAD36300B7B8A3 /* tutorial_screen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = tutorial_screen.cpp; path = ../../states_screens/tutorial_screen.cpp; sourceTree = SOURCE_ROOT; };
95AAD97F12BAD36300B7B8A3 /* tutorial_screen.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = tutorial_screen.hpp; path = ../../states_screens/tutorial_screen.hpp; sourceTree = SOURCE_ROOT; };
95B5CD12102DE08F00EF2001 /* device_config.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = device_config.hpp; path = ../../config/device_config.hpp; sourceTree = SOURCE_ROOT; };
@ -2632,6 +2635,8 @@
955DE8881004273B006A4F3C /* check_structure.hpp */,
953789720FC7829100DD1F8E /* graph_node.cpp */,
953789710FC7829100DD1F8E /* graph_node.hpp */,
95AA4C65148AF2CC0053771D /* lod_node_loader.cpp */,
95AA4C66148AF2CC0053771D /* lod_node_loader.hpp */,
951C357E0FC05BF400A48379 /* quad_set.cpp */,
951C357D0FC05BF400A48379 /* quad_set.hpp */,
953789810FC7831400DD1F8E /* quad.cpp */,
@ -3177,6 +3182,7 @@
95703D1B1468C63F006334D7 /* btGeometryUtil.cpp in Sources */,
95703D1C1468C63F006334D7 /* btQuickprof.cpp in Sources */,
95703D1D1468C63F006334D7 /* btSerializer.cpp in Sources */,
95AA4C67148AF2CC0053771D /* lod_node_loader.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -1148,7 +1148,10 @@ int main(int argc, char *argv[] )
// Get into menu mode initially.
input_manager->setMode(InputManager::MENU);
GUIEngine::addLoadingIcon( irr_driver->getTexture(
file_manager->getGUIDir() + "/options_input.png") );
main_loop = new MainLoop();
material_manager -> loadMaterial ();
GUIEngine::addLoadingIcon( irr_driver->getTexture(

View File

@ -0,0 +1,187 @@
// $Id$
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2007 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 "tracks/lod_node_loader.hpp"
using namespace irr;
#include "graphics/irr_driver.hpp"
#include "graphics/lod_node.hpp"
#include "io/xml_node.hpp"
#include <IAnimatedMeshSceneNode.h>
#include <ISceneManager.h>
LodNodeLoader::LodNodeLoader()
{
}
// ----------------------------------------------------------------------------
bool PairCompare(const std::pair<int, std::string>& i, const std::pair<int, std::string>& j)
{
return (i.first < j.first);
}
// ----------------------------------------------------------------------------
/** Check a XML node in case it contains a LOD object and if so remember it */
bool LodNodeLoader::check(const XMLNode* xml)
{
float lod_distance = -1.0f;
xml->get("lod_distance", &lod_distance);
bool lod_instance = false;
xml->get("lod_instance", &lod_instance);
std::string lodgroup;
xml->get("lod_group", &lodgroup);
if (!lodgroup.empty())
{
if (lod_instance)
{
lod_instances[lodgroup].push_back(xml);
}
else
{
std::string model_name;
xml->get("model", &model_name);
lod_groups[lodgroup][(int)lod_distance] = model_name;
}
return true;
}
else
{
return false;
}
}
// ----------------------------------------------------------------------------
/**
* Call when the XML file is fully parsed and we're ready to create the node
* @param cache the individual meshes will be added there
* @param[out] out the nodes are added here
*/
void LodNodeLoader::done(std::string directory,
std::vector<scene::IMesh*>& cache,
std::vector<LODNode*>& out)
{
scene::ISceneManager* sm = irr_driver->getSceneManager();
scene::ISceneNode* sroot = sm->getRootSceneNode();
// Creating LOD nodes is more complicated than one might have hoped, on the C++ side;
// but it was done this way to minimize the work needed on the side of the artists
// 1. Sort LOD groups (highest detail first, lowest detail last)
std::map<std::string, std::vector< std::pair<int, std::string> > > sorted_lod_groups;
std::map<std::string, std::map<int, std::string> >::iterator it;
for (it = lod_groups.begin(); it != lod_groups.end(); it++)
{
std::map<int, std::string>::iterator it2;
for (it2 = it->second.begin(); it2 != it->second.end(); it2++)
{
//printf("Copying before sort : (%i) %s is in group %s\n", it2->first, it2->second.c_str(), it->first.c_str());
sorted_lod_groups[it->first].push_back( std::pair<int, std::string>(it2->first, it2->second) );
}
std::sort( sorted_lod_groups[it->first].begin(), sorted_lod_groups[it->first].end(), PairCompare );
//printf("Group '%s' :\n", it->first.c_str());
//for (unsigned int x=0; x<sorted_lod_groups[it->first].size(); x++)
//{
// printf(" - (%i) %s\n", sorted_lod_groups[it->first][x].first, sorted_lod_groups[it->first][x].second.c_str());
//}
}
// 2. Read the XML nodes and instanciate LOD scene nodes where relevant
std::string groupname;
std::map< std::string, std::vector< const XMLNode* > >::iterator it3;
for (it3 = lod_instances.begin(); it3 != lod_instances.end(); it3++)
{
std::vector< std::pair<int, std::string> >& group = sorted_lod_groups[it3->first];
std::vector< const XMLNode* >& v = it3->second;
for (unsigned int n=0; n<v.size(); n++)
{
const XMLNode* node = v[n];
if(node->getName()!="static-object")
{
fprintf(stderr, "Incorrect tag '%s' used in LOD instance - ignored\n",
node->getName().c_str());
continue;
}
groupname = "";
node->get("lod_group", &groupname);
//if (model_name != sorted_lod_groups[it3->first][0].second) continue;
core::vector3df xyz(0,0,0);
node->get("xyz", &xyz);
core::vector3df hpr(0,0,0);
node->get("hpr", &hpr);
core::vector3df scale(1.0f, 1.0f, 1.0f);
node->get("scale", &scale);
std::string full_path;
if (group.size() > 0)
{
LODNode* lod_node = new LODNode(sroot, sm);
for (unsigned int m=0; m<group.size(); m++)
{
full_path = directory + "/" + group[m].second;
// TODO: check whether the mesh contains animations or not, and use a static
// mesh when there are no animations?
scene::IAnimatedMesh *a_mesh = irr_driver->getAnimatedMesh(full_path);
if(!a_mesh)
{
fprintf(stderr, "Warning: object model '%s' not found, ignored.\n",
full_path.c_str());
continue;
}
a_mesh->grab();
cache.push_back(a_mesh);
irr_driver->grabAllTextures(a_mesh);
scene::IAnimatedMeshSceneNode* scene_node =
irr_driver->addAnimatedMesh(a_mesh);
scene_node->setPosition(xyz);
scene_node->setRotation(hpr);
scene_node->setScale(scale);
lod_node->add( group[m].first, scene_node, true );
}
#ifdef DEBUG
std::string debug_name = groupname+" (LOD track-object)";
lod_node->setName(debug_name.c_str());
#endif
out.push_back(lod_node);
}
else
{
fprintf(stderr, "[LodNodeLoader] WARNING, LOD group '%s' is empty\n", groupname.c_str());
}
}
} // end for
}

View File

@ -0,0 +1,57 @@
// $Id$
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2007 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
// MERCHANTe ABILITY 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_LOD_NODE_LOADER_HPP
#define HEADER_LOD_NODE_LOADER_HPP
class XMLNode;
class LODNode;
#include <map>
#include <vector>
namespace irr
{
namespace scene
{
class IMesh;
}
}
/** Utility class to load level-of-detail nodes
* \ingroup tracks
*/
class LodNodeLoader
{
private:
std::map< std::string, std::map< int, std::string > > lod_groups;
std::map< std::string, std::vector< const XMLNode* > > lod_instances;
public:
LodNodeLoader();
bool check(const XMLNode* xml);
void done(std::string directory,
std::vector<irr::scene::IMesh*>& cache,
std::vector<LODNode*>& out);
}; // LodNodeLoader
#endif // HEADER_LOD_NODE_LOADER_HPP

View File

@ -50,6 +50,7 @@ using namespace irr;
#include "race/race_manager.hpp"
#include "tracks/bezier_curve.hpp"
#include "tracks/check_manager.hpp"
#include "tracks/lod_node_loader.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/quad_set.hpp"
#include "tracks/track_object_manager.hpp"
@ -595,12 +596,6 @@ void Track::convertTrackToBullet(scene::ISceneNode *node)
// ----------------------------------------------------------------------------
bool PairCompare(const std::pair<int, std::string>& i, const std::pair<int, std::string>& j)
{
return (i.first < j.first);
}
/** 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.
@ -676,9 +671,8 @@ bool Track::loadMainTrack(const XMLNode &root)
m_aabb_max.setY(m_aabb_max.getY()+30.0f);
World::getWorld()->getPhysics()->init(m_aabb_min, m_aabb_max);
std::map< std::string, std::map< int, std::string > > lod_groups;
std::map< std::string, std::vector< const XMLNode* > > lod_instances;
LodNodeLoader lodLoader;
for(unsigned int i=0; i<track_node->getNumNodes(); i++)
{
const XMLNode *n=track_node->getNode(i);
@ -707,14 +701,7 @@ bool Track::loadMainTrack(const XMLNode &root)
core::vector3df scale(1.0f, 1.0f, 1.0f);
n->get("scale", &scale);
float lod_distance = -1.0f;
n->get("lod_distance", &lod_distance);
bool lod_instance = false;
n->get("lod_instance", &lod_instance);
std::string lodgroup;
n->get("lod_group", &lodgroup);
lodLoader.check(n);
if (tangent)
{
@ -750,18 +737,9 @@ bool Track::loadMainTrack(const XMLNode &root)
handleAnimatedTextures(scene_node, *n);
m_all_nodes.push_back( scene_node );
}
else if (!lodgroup.empty())
else if (lodLoader.check(n))
{
if (lod_instance)
{
lod_instances[lodgroup].push_back(n);
//printf("LOD instance : '%s' @ (%.2f, %.2f, %.2f)\n", lodgroup.c_str(), xyz.X, xyz.Y, xyz.Z);
}
else
{
lod_groups[lodgroup][(int)lod_distance] = model_name;
//printf("LOD Model Definition : group='%s', detail='%i', model='%s'\n", lodgroup.c_str(), detail, model_name.c_str());
}
// nothing to do
}
else
{
@ -799,109 +777,16 @@ bool Track::loadMainTrack(const XMLNode &root)
}
} // for i
scene::ISceneManager* sm = irr_driver->getSceneManager();
scene::ISceneNode* sroot = sm->getRootSceneNode();
// ================ Level Of Detail ================
// Creating LOD nodes is more complicated than one might have hoped, on the C++ side;
// but it was done this way to minimize the work needed on the side of the artists
// 1. Sort LOD groups (highest detail first, lowest detail last)
std::map<std::string, std::vector< std::pair<int, std::string> > > sorted_lod_groups;
std::map<std::string, std::map<int, std::string> >::iterator it;
for (it = lod_groups.begin(); it != lod_groups.end(); it++)
std::vector<LODNode*> lod_nodes;
lodLoader.done(m_root, m_all_cached_meshes, lod_nodes);
for (unsigned int n=0; n<lod_nodes.size(); n++)
{
std::map<int, std::string>::iterator it2;
for (it2 = it->second.begin(); it2 != it->second.end(); it2++)
{
//printf("Copying before sort : (%i) %s is in group %s\n", it2->first, it2->second.c_str(), it->first.c_str());
sorted_lod_groups[it->first].push_back( std::pair<int, std::string>(it2->first, it2->second) );
}
std::sort( sorted_lod_groups[it->first].begin(), sorted_lod_groups[it->first].end(), PairCompare );
//printf("Group '%s' :\n", it->first.c_str());
//for (unsigned int x=0; x<sorted_lod_groups[it->first].size(); x++)
//{
// printf(" - (%i) %s\n", sorted_lod_groups[it->first][x].first, sorted_lod_groups[it->first][x].second.c_str());
//}
// FIXME: support for animated textures on LOD objects
// handleAnimatedTextures( lod_nodes[n], *node );
m_all_nodes.push_back( lod_nodes[n] );
}
// 2. Read the XML nodes and instanciate LOD scene nodes where relevant
std::string groupname;
std::map< std::string, std::vector< const XMLNode* > >::iterator it3;
for (it3 = lod_instances.begin(); it3 != lod_instances.end(); it3++)
{
std::vector< std::pair<int, std::string> >& group = sorted_lod_groups[it3->first];
std::vector< const XMLNode* >& v = it3->second;
for (unsigned int n=0; n<v.size(); n++)
{
const XMLNode* node = v[n];
if(node->getName()!="static-object")
{
fprintf(stderr, "Incorrect tag '%s' used in LOD instance - ignored\n",
node->getName().c_str());
continue;
}
groupname = "";
node->get("lod_group", &groupname);
//if (model_name != sorted_lod_groups[it3->first][0].second) continue;
core::vector3df xyz(0,0,0);
node->get("xyz", &xyz);
core::vector3df hpr(0,0,0);
node->get("hpr", &hpr);
core::vector3df scale(1.0f, 1.0f, 1.0f);
node->get("scale", &scale);
if (group.size() > 0)
{
LODNode* lod_node = new LODNode(sroot, sm);
for (unsigned int m=0; m<group.size(); m++)
{
full_path = m_root + "/" + group[m].second;
// TODO: check whether the mesh contains animations or not, and use a static
// mesh when there are no animations?
scene::IAnimatedMesh *a_mesh = irr_driver->getAnimatedMesh(full_path);
if(!a_mesh)
{
fprintf(stderr, "Warning: object model '%s' not found, ignored.\n",
full_path.c_str());
continue;
}
a_mesh->grab(); // see above for usage in m_all_cached_meshes
m_all_cached_meshes.push_back(a_mesh);
irr_driver->grabAllTextures(a_mesh);
scene::IAnimatedMeshSceneNode* scene_node =
irr_driver->addAnimatedMesh(a_mesh);
scene_node->setPosition(xyz);
scene_node->setRotation(hpr);
scene_node->setScale(scale);
lod_node->add( group[m].first, scene_node, true );
}
#ifdef DEBUG
std::string debug_name = groupname+" (LOD track-object)";
lod_node->setName(debug_name.c_str());
#endif
handleAnimatedTextures(lod_node, *node);
m_all_nodes.push_back( lod_node );
}
else
{
fprintf(stderr, "[Track] WARNING, LOD group '%s' is empty\n", groupname.c_str());
}
}
}
// =================================================
// This will (at this stage) only convert the main track model.
for(unsigned int i=0; i<m_all_nodes.size(); i++)
{
@ -1192,6 +1077,7 @@ void Track::loadTrackModel(World* parent, unsigned int mode_id)
if(name=="track" || name=="default-start") continue;
if(name=="object")
{
// FIXME: this may be LOD
m_track_object_manager->add(*node);
}
else if(name=="water")