Create new instance of mesh every time it's required (Solves #703)
authorPerttu Ahola <celeron55@gmail.com>
Mon, 6 Jan 2014 11:24:06 +0000 (13:24 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Mon, 6 Jan 2014 11:24:31 +0000 (13:24 +0200)
src/client.cpp
src/client.h
src/content_cao.cpp
src/gamedef.h

index 09c940a7a1bf1fd0ae27228dc0788a5de0b7a43f..b830bcdf321c6813f3e04e3dad087e7799a6d378 100644 (file)
@@ -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;
+}
+
index a74668d5b8c1de2c561edd573baaee56f3a7530f..1ed80a2b0225dd58ef3c02f00c7b779b67a99cd0 100644 (file)
@@ -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<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
index 640ab6c7302ae9162785299c5936a553297356d7..840103cc74644f7406ae98e569258b4c7bdad3e7 100644 (file)
@@ -957,10 +957,11 @@ public:
                }
                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,
index 1d46b028e359f8103f75c66b2692ae8c6d9e4e71..6da288bad8879992475c30592ec6045f8a6440b0 100644 (file)
@@ -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.