summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--source/HeiGen.cpp90
-rw-r--r--source/HeiGen.h36
-rw-r--r--source/cChunkGenerator.cpp17
3 files changed, 143 insertions, 0 deletions
diff --git a/source/HeiGen.cpp b/source/HeiGen.cpp
index 6513d2730..b2e9e48c8 100644
--- a/source/HeiGen.cpp
+++ b/source/HeiGen.cpp
@@ -26,6 +26,96 @@ void cHeiGenFlat::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cHeiGenCache:
+
+cHeiGenCache::cHeiGenCache(cTerrainHeightGen * a_HeiGenToCache, int a_CacheSize) :
+ m_HeiGenToCache(a_HeiGenToCache),
+ m_CacheSize(a_CacheSize),
+ m_CacheOrder(new int[a_CacheSize]),
+ m_CacheData(new sCacheData[a_CacheSize]),
+ m_NumHits(0),
+ m_NumMisses(0),
+ m_TotalChain(0)
+{
+ for (int i = 0; i < m_CacheSize; i++)
+ {
+ m_CacheOrder[i] = i;
+ m_CacheData[i].m_ChunkX = 0x7fffffff;
+ m_CacheData[i].m_ChunkZ = 0x7fffffff;
+ }
+}
+
+
+
+
+
+cHeiGenCache::~cHeiGenCache()
+{
+ delete m_CacheData;
+ delete m_CacheOrder;
+ delete m_HeiGenToCache;
+}
+
+
+
+
+
+void cHeiGenCache::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
+{
+ if (((m_NumHits + m_NumMisses) % 1024) == 10)
+ {
+ LOGD("HeiGenCache: %d hits, %d misses, saved %.2f %%", m_NumHits, m_NumMisses, 100.0 * m_NumHits / (m_NumHits + m_NumMisses));
+ LOGD("HeiGenCache: Avg cache chain length: %.2f", (float)m_TotalChain / m_NumHits);
+ }
+
+ for (int i = 0; i < m_CacheSize; i++)
+ {
+ if (
+ (m_CacheData[m_CacheOrder[i]].m_ChunkX != a_ChunkX) ||
+ (m_CacheData[m_CacheOrder[i]].m_ChunkZ != a_ChunkZ)
+ )
+ {
+ continue;
+ }
+ // Found it in the cache
+ int Idx = m_CacheOrder[i];
+
+ // Move to front:
+ for (int j = i; j > 0; j--)
+ {
+ m_CacheOrder[j] = m_CacheOrder[j - 1];
+ }
+ m_CacheOrder[0] = Idx;
+
+ // Use the cached data:
+ memcpy(a_HeightMap, m_CacheData[Idx].m_HeightMap, sizeof(a_HeightMap));
+
+ m_NumHits++;
+ m_TotalChain += i;
+ return;
+ } // for i - cache
+
+ // Not in the cache:
+ m_NumMisses++;
+ m_HeiGenToCache->GenHeightMap(a_ChunkX, a_ChunkZ, a_HeightMap);
+
+ // Insert it as the first item in the MRU order:
+ int Idx = m_CacheOrder[m_CacheSize - 1];
+ for (int i = m_CacheSize - 1; i > 0; i--)
+ {
+ m_CacheOrder[i] = m_CacheOrder[i - 1];
+ } // for i - m_CacheOrder[]
+ m_CacheOrder[0] = Idx;
+ memcpy(m_CacheData[Idx].m_HeightMap, a_HeightMap, sizeof(a_HeightMap));
+ m_CacheData[Idx].m_ChunkX = a_ChunkX;
+ m_CacheData[Idx].m_ChunkZ = a_ChunkZ;
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cHeiGenClassic:
cHeiGenClassic::cHeiGenClassic(int a_Seed, float a_HeightFreq1, float a_HeightAmp1, float a_HeightFreq2, float a_HeightAmp2, float a_HeightFreq3, float a_HeightAmp3) :
diff --git a/source/HeiGen.h b/source/HeiGen.h
index 869f1c67a..d3074487f 100644
--- a/source/HeiGen.h
+++ b/source/HeiGen.h
@@ -39,6 +39,42 @@ protected:
+/// A simple cache that stores N most recently generated chunks' heightmaps; N being settable upon creation
+class cHeiGenCache :
+ public cTerrainHeightGen
+{
+public:
+ cHeiGenCache(cTerrainHeightGen * a_HeiGenToCache, int a_CacheSize); // Takes ownership of a_HeiGenToCache
+ ~cHeiGenCache();
+
+protected:
+
+ cTerrainHeightGen * m_HeiGenToCache;
+
+ struct sCacheData
+ {
+ int m_ChunkX;
+ int m_ChunkZ;
+ cChunkDef::HeightMap m_HeightMap;
+ } ;
+
+ // To avoid moving large amounts of data for the MRU behavior, we MRU-ize indices to an array of the actual data
+ int m_CacheSize;
+ int * m_CacheOrder; // MRU-ized order, indices into m_CacheData array
+ sCacheData * m_CacheData; // m_CacheData[m_CacheOrder[0]] is the most recently used
+
+ // Cache statistics
+ int m_NumHits;
+ int m_NumMisses;
+ int m_TotalChain; // Number of cache items walked to get to a hit (only added for hits)
+
+ virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
+} ;
+
+
+
+
+
class cHeiGenClassic :
public cTerrainHeightGen
{
diff --git a/source/cChunkGenerator.cpp b/source/cChunkGenerator.cpp
index 1687e0e13..23d6b8422 100644
--- a/source/cChunkGenerator.cpp
+++ b/source/cChunkGenerator.cpp
@@ -177,10 +177,12 @@ void cChunkGenerator::InitHeightGen(cIniFile & a_IniFile)
HeightGenName = "classic";
}
+ bool CacheOffByDefault = false;
if (NoCaseCompare(HeightGenName, "flat") == 0)
{
int Height = a_IniFile.GetValueI("Generator", "FlatHeight", 5);
m_HeightGen = new cHeiGenFlat(Height);
+ CacheOffByDefault = true; // We're generating faster than a cache would retrieve data
}
else if (NoCaseCompare(HeightGenName, "classic") == 0)
{
@@ -201,6 +203,21 @@ void cChunkGenerator::InitHeightGen(cIniFile & a_IniFile)
}
m_HeightGen = new cHeiGenBiomal(m_Seed, *m_BiomeGen);
}
+
+ // Add a cache, if requested:
+ int CacheSize = a_IniFile.GetValueI("Generator", "HeightGenCacheSize", CacheOffByDefault ? 0 : 64);
+ if (CacheSize > 0)
+ {
+ if (CacheSize < 4)
+ {
+ LOGWARNING("Heightgen cache size set too low, would hurt performance instead of helping. Increasing from %d to %d",
+ CacheSize, 4
+ );
+ CacheSize = 4;
+ }
+ LOGINFO("Using a cache for Heightgen of size %d.", CacheSize);
+ m_HeightGen = new cHeiGenCache(m_HeightGen, CacheSize);
+ }
}