Create new instance of mesh every time it's required (Solves #703)

This commit is contained in:
Perttu Ahola 2014-01-06 13:24:06 +02:00
parent 86c616a545
commit d76957ee22
4 changed files with 44 additions and 24 deletions

@ -893,30 +893,12 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
name = removeStringEnd(filename, model_ext); name = removeStringEnd(filename, model_ext);
if(name != "") if(name != "")
{ {
verbosestream<<"Client: Storing model into Irrlicht: " verbosestream<<"Client: Storing model into memory: "
<<"\""<<filename<<"\""<<std::endl; <<"\""<<filename<<"\""<<std::endl;
scene::ISceneManager *smgr = m_device->getSceneManager(); if(m_mesh_data.count(filename))
errorstream<<"Multiple models with name \""<<filename.c_str()
//check if mesh was already cached <<"\" found; replacing previous model"<<std::endl;
scene::IAnimatedMesh *mesh = m_mesh_data[filename] = data;
smgr->getMeshCache()->getMeshByName(filename.c_str());
if (mesh != NULL) {
errorstream << "Multiple models with name: " << filename.c_str() <<
" found replacing previous model!" << std::endl;
smgr->getMeshCache()->removeMesh(mesh);
mesh = 0;
}
io::IFileSystem *irrfs = m_device->getFileSystem();
io::IReadFile *rfile = irrfs->createMemoryReadFile(
*data_rw, data_rw.getSize(), filename.c_str());
assert(rfile);
mesh = smgr->getMesh(rfile);
smgr->getMeshCache()->addMesh(filename.c_str(), mesh);
rfile->drop();
return true; return true;
} }
@ -2836,3 +2818,31 @@ MtEventManager* Client::getEventManager()
return m_event; return m_event;
} }
scene::IAnimatedMesh* Client::getMesh(const std::string &filename)
{
std::map<std::string, std::string>::const_iterator i =
m_mesh_data.find(filename);
if(i == m_mesh_data.end()){
errorstream<<"Client::getMesh(): Mesh not found: \""<<filename<<"\""
<<std::endl;
return NULL;
}
const std::string &data = i->second;
scene::ISceneManager *smgr = m_device->getSceneManager();
// Create the mesh, remove it from cache and return it
// This allows unique vertex colors and other properties for each instance
Buffer<char> data_rw(data.c_str(), data.size()); // Const-incorrect Irrlicht
io::IFileSystem *irrfs = m_device->getFileSystem();
io::IReadFile *rfile = irrfs->createMemoryReadFile(
*data_rw, data_rw.getSize(), filename.c_str());
assert(rfile);
scene::IAnimatedMesh *mesh = smgr->getMesh(rfile);
rfile->drop();
// NOTE: By playing with Irrlicht refcounts, maybe we could cache a bunch
// of uniquely named instances and re-use them
mesh->grab();
smgr->getMeshCache()->removeMesh(mesh);
return mesh;
}

@ -420,6 +420,7 @@ public:
virtual MtEventManager* getEventManager(); virtual MtEventManager* getEventManager();
virtual bool checkLocalPrivilege(const std::string &priv) virtual bool checkLocalPrivilege(const std::string &priv)
{ return checkPrivilege(priv); } { return checkPrivilege(priv); }
virtual scene::IAnimatedMesh* getMesh(const std::string &filename);
// The following set of functions is used by ClientMediaDownloader // The following set of functions is used by ClientMediaDownloader
// Insert a media file appropriately into the appropriate manager // Insert a media file appropriately into the appropriate manager
@ -509,6 +510,9 @@ private:
// Detached inventories // Detached inventories
// key = name // key = name
std::map<std::string, Inventory*> m_detached_inventories; std::map<std::string, Inventory*> m_detached_inventories;
// Storage for mesh data for creating multiple instances of the same mesh
std::map<std::string, std::string> m_mesh_data;
}; };
#endif // !CLIENT_HEADER #endif // !CLIENT_HEADER

@ -957,10 +957,11 @@ public:
} }
else if(m_prop.visual == "mesh"){ else if(m_prop.visual == "mesh"){
infostream<<"GenericCAO::addToScene(): mesh"<<std::endl; infostream<<"GenericCAO::addToScene(): mesh"<<std::endl;
scene::IAnimatedMesh *mesh = smgr->getMesh(m_prop.mesh.c_str()); scene::IAnimatedMesh *mesh = m_gamedef->getMesh(m_prop.mesh);
if(mesh) if(mesh)
{ {
m_animated_meshnode = smgr->addAnimatedMeshSceneNode(mesh, NULL); m_animated_meshnode = smgr->addAnimatedMeshSceneNode(mesh, NULL);
mesh->drop(); // The scene node took hold of it
m_animated_meshnode->animateJoints(); // Needed for some animations m_animated_meshnode->animateJoints(); // Needed for some animations
m_animated_meshnode->setScale(v3f(m_prop.visual_size.X, m_animated_meshnode->setScale(v3f(m_prop.visual_size.X,
m_prop.visual_size.Y, m_prop.visual_size.Y,

@ -31,6 +31,9 @@ class ISoundManager;
class IShaderSource; class IShaderSource;
class MtEventManager; class MtEventManager;
class IRollbackReportSink; class IRollbackReportSink;
namespace irr { namespace scene {
class IAnimatedMesh;
}}
/* /*
An interface for fetching game-global definitions like tool and An interface for fetching game-global definitions like tool and
@ -58,6 +61,8 @@ public:
// Only usable on the client // Only usable on the client
virtual ISoundManager* getSoundManager()=0; virtual ISoundManager* getSoundManager()=0;
virtual MtEventManager* getEventManager()=0; virtual MtEventManager* getEventManager()=0;
virtual scene::IAnimatedMesh* getMesh(const std::string &filename)
{ return NULL; }
// Only usable on the server, and NOT thread-safe. It is usable from the // Only usable on the server, and NOT thread-safe. It is usable from the
// environment thread. // environment thread.