diff --git a/src/client.cpp b/src/client.cpp index 09c940a7..b830bcdf 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: " <<"\""<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 \""<::const_iterator i = + m_mesh_data.find(filename); + if(i == m_mesh_data.end()){ + errorstream<<"Client::getMesh(): Mesh not found: \""<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 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 a74668d5..1ed80a2b 100644 --- a/src/client.h +++ b/src/client.h @@ -420,6 +420,7 @@ public: 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 @@ private: // Detached inventories // key = name std::map m_detached_inventories; + + // Storage for mesh data for creating multiple instances of the same mesh + std::map m_mesh_data; }; #endif // !CLIENT_HEADER diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 640ab6c7..840103cc 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -957,10 +957,11 @@ public: } else if(m_prop.visual == "mesh"){ infostream<<"GenericCAO::addToScene(): mesh"<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 1d46b028..6da288ba 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 @@ public: // 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.