Prechádzať zdrojové kódy

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

Perttu Ahola 10 rokov pred
rodič
commit
d76957ee22
4 zmenil súbory, kde vykonal 44 pridanie a 24 odobranie
  1. 33 23
      src/client.cpp
  2. 4 0
      src/client.h
  3. 2 1
      src/content_cao.cpp
  4. 5 0
      src/gamedef.h

+ 33 - 23
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;
+}
+

+ 4 - 0
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

+ 2 - 1
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,

+ 5 - 0
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.