aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPerttu Ahola <celeron55@gmail.com>2014-01-06 13:24:06 +0200
committerPerttu Ahola <celeron55@gmail.com>2014-01-06 13:24:31 +0200
commitd76957ee22c27adab89cee551e3ab1c85d8717cc (patch)
tree4facd7100f9c527203681000a1ffb14351eecc81
parent86c616a545efcc8ed8487440d686a17358170756 (diff)
downloadminetest-d76957ee22c27adab89cee551e3ab1c85d8717cc.tar.gz
minetest-d76957ee22c27adab89cee551e3ab1c85d8717cc.tar.bz2
minetest-d76957ee22c27adab89cee551e3ab1c85d8717cc.zip
Create new instance of mesh every time it's required (Solves #703)
-rw-r--r--src/client.cpp56
-rw-r--r--src/client.h4
-rw-r--r--src/content_cao.cpp3
-rw-r--r--src/gamedef.h5
4 files changed, 44 insertions, 24 deletions
diff --git a/src/client.cpp b/src/client.cpp
index 09c940a7a..b830bcdf3 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 a74668d5b..1ed80a2b0 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<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 640ab6c73..840103cc7 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"<<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 1d46b028e..6da288bad 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.