From 1f1ad9fd23b07a1c1b5477ee0dbf2c4fdaabccef Mon Sep 17 00:00:00 2001
From: kwolekr <kwolekr@minetest.net>
Date: Fri, 15 Mar 2013 22:43:35 -0400
Subject: [PATCH] Optimize Mapgen::updateLighting(), add setLighting()

---
 src/mapgen.cpp | 117 +++++++++++++++++++++++++++++++++++++++++++++----
 src/mapgen.h   |   4 ++
 2 files changed, 113 insertions(+), 8 deletions(-)

diff --git a/src/mapgen.cpp b/src/mapgen.cpp
index 156863170..699b51789 100644
--- a/src/mapgen.cpp
+++ b/src/mapgen.cpp
@@ -51,21 +51,19 @@ FlagDesc flagdesc_mapgen[] = {
 
 void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax) {
 	bool isliquid, wasliquid;
-	u32 i;
+	v3s16 em  = vm->m_area.getExtent();
 
 	for (s16 z = nmin.Z; z <= nmax.Z; z++) {
 		for (s16 x = nmin.X; x <= nmax.X; x++) {
-			v2s16 p2d(x, z);
 			wasliquid = true;
-			v3s16 em  = vm->m_area.getExtent();
-			i = vm->m_area.index(v3s16(p2d.X, nmax.Y, p2d.Y));
-
+			
+			u32 i = vm->m_area.index(x, nmax.Y, z);
 			for (s16 y = nmax.Y; y >= nmin.Y; y--) {
 				isliquid = ndef->get(vm->m_data[i]).isLiquid();
 				
 				// there was a change between liquid and nonliquid, add to queue
 				if (isliquid != wasliquid)
-					trans_liquid->push_back(v3s16(p2d.X, y, p2d.Y));
+					trans_liquid->push_back(v3s16(x, y, z));
 
 				wasliquid = isliquid;
 				vm->m_area.add_y(em, i, -1);
@@ -75,7 +73,108 @@ void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nm
 }
 
 
+void Mapgen::setLighting(v3s16 nmin, v3s16 nmax, u8 light) {
+	ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
+	VoxelArea a(nmin - v3s16(1,0,1) * MAP_BLOCKSIZE,
+				nmax + v3s16(1,0,1) * MAP_BLOCKSIZE);
+
+	for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
+		for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
+			u32 i = vm->m_area.index(a.MinEdge.X, y, z);
+			for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++)
+				vm->m_data[i].param1 = light;
+		}
+	}
+}
+
+
+void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) {
+	if (light <= 1 || !a.contains(p))
+		return;
+		
+	u32 vi = vm->m_area.index(p);
+	MapNode &nn = vm->m_data[vi];
+
+	light--;
+	// should probably compare masked, but doesn't seem to make a difference
+	if (light <= nn.param1 || !ndef->get(nn).light_propagates)
+		return;
+	
+	nn.param1 = light;
+	
+	lightSpread(a, p + v3s16(0, 0, 1), light);
+	lightSpread(a, p + v3s16(0, 1, 0), light);
+	lightSpread(a, p + v3s16(1, 0, 0), light);
+	lightSpread(a, p - v3s16(0, 0, 1), light);
+	lightSpread(a, p - v3s16(0, 1, 0), light);
+	lightSpread(a, p - v3s16(1, 0, 0), light);
+}
+
+
 void Mapgen::updateLighting(v3s16 nmin, v3s16 nmax) {
+	VoxelArea a(nmin - v3s16(1,0,1) * MAP_BLOCKSIZE,
+				nmax + v3s16(1,0,1) * MAP_BLOCKSIZE);
+	bool block_is_underground = (water_level >= nmax.Y);
+
+	ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
+	//TimeTaker t("updateLighting");
+
+	// first, send vertical rays of sunshine downward
+	v3s16 em = vm->m_area.getExtent();
+	for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
+		for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++) {
+			// see if we can get a light value from the overtop
+			u32 i = vm->m_area.index(x, a.MaxEdge.Y + 1, z);
+			if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
+				if (block_is_underground)
+					continue;
+			} else if ((vm->m_data[i].param1 & 0x0F) != LIGHT_SUN) {
+				continue;
+			}
+			vm->m_area.add_y(em, i, -1);
+
+			for (int y = a.MaxEdge.Y; y >= a.MinEdge.Y; y--) {
+				MapNode &n = vm->m_data[i];
+				if (!ndef->get(n).sunlight_propagates)
+					break;
+				n.param1 = LIGHT_SUN;
+				vm->m_area.add_y(em, i, -1);
+			}
+		}
+	}
+	
+	// now spread the sunlight and light up any sources
+	for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
+		for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
+			u32 i = vm->m_area.index(a.MinEdge.X, y, z);
+			for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++) {
+				MapNode &n = vm->m_data[i];
+				if (n.getContent() == CONTENT_IGNORE ||
+					!ndef->get(n).light_propagates)
+					continue;
+				
+				u8 light_produced = ndef->get(n).light_source & 0x0F;
+				if (light_produced)
+					n.param1 = light_produced;
+				
+				u8 light = n.param1 & 0x0F;
+				if (light) {
+					lightSpread(a, v3s16(x,     y,     z + 1), light);
+					lightSpread(a, v3s16(x,     y + 1, z    ), light);
+					lightSpread(a, v3s16(x + 1, y,     z    ), light);
+					lightSpread(a, v3s16(x,     y,     z - 1), light);
+					lightSpread(a, v3s16(x,     y - 1, z    ), light);
+					lightSpread(a, v3s16(x - 1, y,     z    ), light);
+				}
+			}
+		}
+	}
+	
+	//printf("updateLighting: %dms\n", t.stop());
+}
+
+
+void Mapgen::updateLightingOld(v3s16 nmin, v3s16 nmax) {
 	enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
 
 	VoxelArea a(nmin - v3s16(1,0,1) * MAP_BLOCKSIZE,
@@ -84,14 +183,16 @@ void Mapgen::updateLighting(v3s16 nmin, v3s16 nmax) {
 	bool sunlight = !block_is_underground;
 
 	ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
+	
 	for (int i = 0; i < 2; i++) {
 		enum LightBank bank = banks[i];
-        std::set<v3s16> light_sources;
-        std::map<v3s16, u8> unlight_from;
+		std::set<v3s16> light_sources;
+		std::map<v3s16, u8> unlight_from;
 
 		voxalgo::clearLightAndCollectSources(*vm, a, bank, ndef,
                                         light_sources, unlight_from);
 		voxalgo::propagateSunlight(*vm, a, sunlight, light_sources, ndef);
+
 		vm->unspreadLight(bank, unlight_from, light_sources, ndef);
 		vm->spreadLight(bank, light_sources, ndef);
 	}
diff --git a/src/mapgen.h b/src/mapgen.h
index 67ea9fbd4..e5b0b6399 100644
--- a/src/mapgen.h
+++ b/src/mapgen.h
@@ -46,6 +46,7 @@ class ManualMapVoxelManipulator;
 class VoxelManipulator;
 class INodeDefManager;
 class BlockMakeData;
+class VoxelArea;
 
 struct MapgenParams {
 	std::string mg_name;
@@ -76,7 +77,10 @@ class Mapgen {
 	INodeDefManager *ndef;
 
 	void updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax);
+	void setLighting(v3s16 nmin, v3s16 nmax, u8 light);
+	void lightSpread(VoxelArea &a, v3s16 p, u8 light);
 	void updateLighting(v3s16 nmin, v3s16 nmax);
+	void updateLightingOld(v3s16 nmin, v3s16 nmax);
 
 	virtual void makeChunk(BlockMakeData *data) {};
 	virtual int getGroundLevelAtPoint(v2s16 p) = 0;
-- 
GitLab