diff --git a/src/client.cpp b/src/client.cpp index 09c940a7a1bf1fd0ae27228dc0788a5de0b7a43f..b830bcdf321c6813f3e04e3dad087e7799a6d378 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -893,30 +893,12 @@ bool Client::loadMedia(const std::string &data, const std::string &filename) name = removeStringEnd(filename, model_ext); if(name != "") { - verbosestream<<"Client: Storing model into Irrlicht: " + verbosestream<<"Client: Storing model into memory: " <<"\""<<filename<<"\""<<std::endl; - scene::ISceneManager *smgr = m_device->getSceneManager(); - - //check if mesh was already cached - scene::IAnimatedMesh *mesh = - 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(); + if(m_mesh_data.count(filename)) + errorstream<<"Multiple models with name \""<<filename.c_str() + <<"\" found; replacing previous model"<<std::endl; + m_mesh_data[filename] = data; return true; } @@ -2836,3 +2818,31 @@ MtEventManager* Client::getEventManager() 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; +} + diff --git a/src/client.h b/src/client.h index a74668d5b8c1de2c561edd573baaee56f3a7530f..1ed80a2b0225dd58ef3c02f00c7b779b67a99cd0 100644 --- a/src/client.h +++ b/src/client.h @@ -420,6 +420,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef virtual MtEventManager* getEventManager(); virtual bool checkLocalPrivilege(const std::string &priv) { return checkPrivilege(priv); } + virtual scene::IAnimatedMesh* getMesh(const std::string &filename); // The following set of functions is used by ClientMediaDownloader // Insert a media file appropriately into the appropriate manager @@ -509,6 +510,9 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef // Detached inventories // key = name 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 diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 640ab6c7302ae9162785299c5936a553297356d7..840103cc74644f7406ae98e569258b4c7bdad3e7 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -957,10 +957,11 @@ class GenericCAO : public ClientActiveObject } else if(m_prop.visual == "mesh"){ 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) { 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->setScale(v3f(m_prop.visual_size.X, m_prop.visual_size.Y, diff --git a/src/gamedef.h b/src/gamedef.h index 1d46b028e359f8103f75c66b2692ae8c6d9e4e71..6da288bad8879992475c30592ec6045f8a6440b0 100644 --- a/src/gamedef.h +++ b/src/gamedef.h @@ -31,6 +31,9 @@ class ISoundManager; class IShaderSource; class MtEventManager; class IRollbackReportSink; +namespace irr { namespace scene { + class IAnimatedMesh; +}} /* An interface for fetching game-global definitions like tool and @@ -58,6 +61,8 @@ class IGameDef // Only usable on the client virtual ISoundManager* getSoundManager()=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 // environment thread.