From a18525a14eca664dc93be01e55b0efd1ce08b0fa Mon Sep 17 00:00:00 2001
From: Perttu Ahola <celeron55@gmail.com>
Date: Mon, 29 Nov 2010 14:03:40 +0200
Subject: [PATCH] fixed face updating slowness bug

---
 src/client.cpp   |   4 +-
 src/client.h     |   1 +
 src/main.cpp     |   4 ++
 src/map.cpp      |   2 +-
 src/map.h        |   2 +
 src/mapblock.cpp | 120 +++++++++++++++++++++++++++++++++++++++++++++--
 src/server.cpp   |   2 +-
 7 files changed, 127 insertions(+), 8 deletions(-)

diff --git a/src/client.cpp b/src/client.cpp
index b461549d2..7652e047e 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -1224,8 +1224,7 @@ bool Client::AsyncProcessData()
 	}
 	return false;
 
-	/*
-	LazyMeshUpdater mesh_updater(&m_env);
+	/*LazyMeshUpdater mesh_updater(&m_env);
 	for(;;)
 	{
 		bool r = AsyncProcessPacket(mesh_updater);
@@ -1233,6 +1232,7 @@ bool Client::AsyncProcessData()
 			break;
 	}
 	return false;*/
+
 }
 
 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
diff --git a/src/client.h b/src/client.h
index 92375974a..e7811d28f 100644
--- a/src/client.h
+++ b/src/client.h
@@ -95,6 +95,7 @@ struct IncomingPacket
 	s32 *m_refcount;
 };
 
+// TODO: Remove this. It is not used as supposed.
 class LazyMeshUpdater
 {
 public:
diff --git a/src/main.cpp b/src/main.cpp
index 991185ca6..0452aca31 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -197,6 +197,8 @@ Before release:
 
 TODO: Check what goes wrong with caching map to disk (Kray)
 
+TODO: Remove LazyMeshUpdater. It is not used as supposed.
+
 Doing now:
 ======================================================================
 
@@ -335,6 +337,7 @@ void set_default_settings()
 	g_settings.set("height_randfactor", "constant 0.6");
 	g_settings.set("height_base", "linear 0 35 0");
 	g_settings.set("plants_amount", "1.0");
+	g_settings.set("ravines_amount", "1.0");
 	g_settings.set("objectdata_interval", "0.2");
 	g_settings.set("active_object_range", "2");
 	g_settings.set("max_simultaneous_block_sends_per_client", "2");
@@ -1024,6 +1027,7 @@ int main(int argc, char *argv[])
 
 	MapParams map_params;
 	map_params.plants_amount = g_settings.getFloat("plants_amount");
+	map_params.ravines_amount = g_settings.getFloat("ravines_amount");
 
 	/*
 		Ask some stuff
diff --git a/src/map.cpp b/src/map.cpp
index 1fbaf0899..2b11b7a48 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -1521,7 +1521,7 @@ MapSector * ServerMap::emergeSector(v2s16 p2d)
 		Add ravine (randomly)
 	*/
 	{
-		if(rand()%10 == 0)
+		if(rand()%(s32)(10.0 * m_params.ravines_amount) == 0)
 		{
 			s16 s = 6;
 			s16 x = rand()%(MAP_BLOCKSIZE-s*2-1)+s;
diff --git a/src/map.h b/src/map.h
index eb459fbca..2f0942182 100644
--- a/src/map.h
+++ b/src/map.h
@@ -388,9 +388,11 @@ struct MapParams
 	MapParams()
 	{
 		plants_amount = 1.0;
+		ravines_amount = 1.0;
 		//max_objects_in_block = 30;
 	}
 	float plants_amount;
+	float ravines_amount;
 	//u16 max_objects_in_block;
 };
 
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index 25561008a..5ca874946 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -283,6 +283,98 @@ void MapBlock::updateFastFaceRow(v3s16 startpos,
 	}
 }
 
+/*
+	This is used because CMeshBuffer::append() is very slow
+*/
+struct PreMeshBuffer
+{
+	video::SMaterial material;
+	core::array<u16> indices;
+	core::array<video::S3DVertex> vertices;
+};
+
+class MeshCollector
+{
+public:
+	void append(
+			video::SMaterial material,
+			const video::S3DVertex* const vertices,
+			u32 numVertices,
+			const u16* const indices,
+			u32 numIndices
+		)
+	{
+		PreMeshBuffer *p = NULL;
+		for(u32 i=0; i<m_prebuffers.size(); i++)
+		{
+			PreMeshBuffer &pp = m_prebuffers[i];
+			if(pp.material != material)
+				continue;
+
+			p = &pp;
+			break;
+		}
+
+		if(p == NULL)
+		{
+			PreMeshBuffer pp;
+			pp.material = material;
+			m_prebuffers.push_back(pp);
+			p = &m_prebuffers[m_prebuffers.size()-1];
+		}
+
+		u32 vertex_count = p->vertices.size();
+		for(u32 i=0; i<numIndices; i++)
+		{
+			u32 j = indices[i] + vertex_count;
+			if(j > 65535)
+			{
+				dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
+				// NOTE: Fix is to just add an another MeshBuffer
+			}
+			p->indices.push_back(j);
+		}
+		for(u32 i=0; i<numVertices; i++)
+		{
+			p->vertices.push_back(vertices[i]);
+		}
+	}
+
+	void fillMesh(scene::SMesh *mesh)
+	{
+		/*dstream<<"Filling mesh with "<<m_prebuffers.size()
+				<<" meshbuffers"<<std::endl;*/
+		for(u32 i=0; i<m_prebuffers.size(); i++)
+		{
+			PreMeshBuffer &p = m_prebuffers[i];
+
+			/*dstream<<"p.vertices.size()="<<p.vertices.size()
+					<<", p.indices.size()="<<p.indices.size()
+					<<std::endl;*/
+			
+			// Create meshbuffer
+			
+			// This is a "Standard MeshBuffer",
+			// it's a typedeffed CMeshBuffer<video::S3DVertex>
+			scene::IMeshBuffer *buf = new scene::SMeshBuffer();
+			// Set material
+			((scene::SMeshBuffer*)buf)->Material = p.material;
+			// Use VBO
+			//buf->setHardwareMappingHint(scene::EHM_STATIC);
+			// Add to mesh
+			mesh->addMeshBuffer(buf);
+			// Mesh grabbed it
+			buf->drop();
+
+			buf->append(p.vertices.pointer(), p.vertices.size(),
+					p.indices.pointer(), p.indices.size());
+		}
+	}
+
+private:
+	core::array<PreMeshBuffer> m_prebuffers;
+};
+
 void MapBlock::updateMesh()
 {
 	/*v3s16 p = getPosRelative();
@@ -344,7 +436,25 @@ void MapBlock::updateMesh()
 	
 	if(fastfaces_new->getSize() > 0)
 	{
+		MeshCollector collector;
+
+		core::list<FastFace*>::Iterator i = fastfaces_new->begin();
+
+		for(; i != fastfaces_new->end(); i++)
+		{
+			FastFace *f = *i;
+
+			const u16 indices[] = {0,1,2,2,3,0};
+
+			collector.append(g_materials[f->material], f->vertices, 4,
+					indices, 6);
+		}
+
 		mesh_new = new scene::SMesh();
+		
+		collector.fillMesh(mesh_new);
+
+#if 0
 		scene::IMeshBuffer *buf = NULL;
 
 		core::list<FastFace*>::Iterator i = fastfaces_new->begin();
@@ -377,17 +487,19 @@ void MapBlock::updateMesh()
 				}
 				material_in_use = f->material;
 			}
-
-			u16 indices[] = {0,1,2,2,3,0};
-			buf->append(f->vertices, 4, indices, 6);
+			
+			u16 new_indices[] = {0,1,2,2,3,0};
+			
+			//buf->append(f->vertices, 4, indices, 6);
 		}
+#endif
 
 		// Use VBO for mesh (this just would set this for ever buffer)
 		//mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
 		
 		/*std::cout<<"MapBlock has "<<fastfaces_new->getSize()<<" faces "
 				<<"and uses "<<mesh_new->getMeshBufferCount()
-				<<" materials"<<std::endl;*/
+				<<" materials (meshbuffers)"<<std::endl;*/
 	}
 
 	// TODO: Get rid of the FastFace stage
diff --git a/src/server.cpp b/src/server.cpp
index e17e21d32..16f6611ca 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -380,7 +380,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
 
 				Also, don't send blocks that are already flying.
 			*/
-			if(d >= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
+			if(d > BLOCK_SEND_DISABLE_LIMITS_MAX_D)
 			{
 				JMutexAutoLock lock(m_blocks_sending_mutex);
 				
-- 
GitLab