213 lines
4.8 KiB
C++
213 lines
4.8 KiB
C++
|
|
// VoronoiMap.cpp
|
|
|
|
// Implements the cVoronoiMap class that implements a Voronoi algorithm over a noise to produce a map
|
|
|
|
#include "Globals.h"
|
|
#include "VoronoiMap.h"
|
|
|
|
|
|
|
|
|
|
|
|
cVoronoiMap::cVoronoiMap(int a_Seed, int a_CellSize, int a_JitterSize) :
|
|
m_Noise1(a_Seed + 1),
|
|
m_Noise2(a_Seed + 2),
|
|
m_Noise3(a_Seed + 3),
|
|
m_CellSize(std::max(a_CellSize, 2)),
|
|
m_JitterSize(Clamp(a_JitterSize, 1, a_CellSize)),
|
|
m_OddRowOffset(0),
|
|
m_CurrentCellX(9999999), // Cell coords that are definitely out of the range for normal generator, so that the first query will overwrite them
|
|
m_CurrentCellZ(9999999)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void cVoronoiMap::SetCellSize(int a_CellSize)
|
|
{
|
|
a_CellSize = std::max(a_CellSize, 2); // Cell size must be at least 2
|
|
m_CellSize = a_CellSize;
|
|
|
|
// For compatibility with previous version, which didn't have the jitter, we set jitter here as well.
|
|
m_JitterSize = a_CellSize;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void cVoronoiMap::SetJitterSize(int a_JitterSize)
|
|
{
|
|
m_JitterSize = Clamp(a_JitterSize, 1, m_CellSize);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void cVoronoiMap::SetOddRowOffset(int a_OddRowOffset)
|
|
{
|
|
m_OddRowOffset = Clamp(a_OddRowOffset, -m_CellSize, m_CellSize);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int cVoronoiMap::GetValueAt(int a_X, int a_Y)
|
|
{
|
|
int SeedX, SeedY, MinDist2;
|
|
return GetValueAt(a_X, a_Y, SeedX, SeedY, MinDist2);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int cVoronoiMap::GetValueAt(int a_X, int a_Y, int & a_MinDist)
|
|
{
|
|
int SeedX, SeedY, MinDist2;
|
|
int res = GetValueAt(a_X, a_Y, SeedX, SeedY, MinDist2);
|
|
a_MinDist = (a_X - SeedX) * (a_X - SeedX) + (a_Y - SeedY) * (a_Y - SeedY);
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int cVoronoiMap::GetValueAt(
|
|
int a_X, int a_Y, // Coords to query
|
|
int & a_NearestSeedX, int & a_NearestSeedY, // Coords of the closest cell
|
|
int & a_MinDist2 // Distance to the second closest cell
|
|
)
|
|
{
|
|
int CellX = a_X / m_CellSize;
|
|
int CellY = a_Y / m_CellSize;
|
|
|
|
UpdateCell(CellX, CellY);
|
|
|
|
// Get 5x5 neighboring cell seeds, compare distance to each. Return the value in the minumim-distance cell
|
|
int NearestSeedX = 0, NearestSeedY = 0;
|
|
int MinDist = m_CellSize * m_CellSize * 16; // There has to be a cell closer than this
|
|
int MinDist2 = MinDist;
|
|
int res = 0; // Will be overriden
|
|
for (int x = 0; x < 5; x++)
|
|
{
|
|
for (int y = 0; y < 5; y++)
|
|
{
|
|
int SeedX = m_SeedX[x][y];
|
|
int SeedY = m_SeedZ[x][y];
|
|
|
|
int Dist = (SeedX - a_X) * (SeedX - a_X) + (SeedY - a_Y) * (SeedY - a_Y);
|
|
if (Dist < MinDist)
|
|
{
|
|
NearestSeedX = SeedX;
|
|
NearestSeedY = SeedY;
|
|
MinDist2 = MinDist;
|
|
MinDist = Dist;
|
|
res = m_Noise3.IntNoise2DInt(x + CellX - 2, y + CellY - 2);
|
|
}
|
|
else if (Dist < MinDist2)
|
|
{
|
|
MinDist2 = Dist;
|
|
}
|
|
} // for z
|
|
} // for x
|
|
|
|
a_NearestSeedX = NearestSeedX;
|
|
a_NearestSeedY = NearestSeedY;
|
|
a_MinDist2 = MinDist2;
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void cVoronoiMap::FindNearestSeeds(
|
|
int a_X, int a_Y,
|
|
int & a_NearestSeedX, int & a_NearestSeedY,
|
|
int & a_SecondNearestSeedX, int & a_SecondNearestSeedY
|
|
)
|
|
{
|
|
int CellX = a_X / m_CellSize;
|
|
int CellY = a_Y / m_CellSize;
|
|
|
|
UpdateCell(CellX, CellY);
|
|
|
|
// Get 5x5 neighboring cell seeds, compare distance to each. Return the value in the minumim-distance cell
|
|
int NearestSeedX = 0, NearestSeedY = 0;
|
|
int SecondNearestSeedX = 0, SecondNearestSeedY = 0;
|
|
int MinDist = m_CellSize * m_CellSize * 16; // There has to be a cell closer than this
|
|
int MinDist2 = MinDist;
|
|
for (int x = 0; x < 5; x++)
|
|
{
|
|
for (int y = 0; y < 5; y++)
|
|
{
|
|
int SeedX = m_SeedX[x][y];
|
|
int SeedY = m_SeedZ[x][y];
|
|
|
|
int Dist = (SeedX - a_X) * (SeedX - a_X) + (SeedY - a_Y) * (SeedY - a_Y);
|
|
if (Dist < MinDist)
|
|
{
|
|
SecondNearestSeedX = NearestSeedX;
|
|
SecondNearestSeedY = NearestSeedY;
|
|
MinDist2 = MinDist;
|
|
NearestSeedX = SeedX;
|
|
NearestSeedY = SeedY;
|
|
MinDist = Dist;
|
|
}
|
|
else if (Dist < MinDist2)
|
|
{
|
|
SecondNearestSeedX = SeedX;
|
|
SecondNearestSeedY = SeedY;
|
|
MinDist2 = Dist;
|
|
}
|
|
} // for z
|
|
} // for x
|
|
|
|
a_NearestSeedX = NearestSeedX;
|
|
a_NearestSeedY = NearestSeedY;
|
|
a_SecondNearestSeedX = SecondNearestSeedX;
|
|
a_SecondNearestSeedY = SecondNearestSeedY;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void cVoronoiMap::UpdateCell(int a_CellX, int a_CellZ)
|
|
{
|
|
// If the specified cell is currently cached, bail out:
|
|
if ((a_CellX == m_CurrentCellX) && (a_CellZ == m_CurrentCellZ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Update the cell cache for the new cell position:
|
|
int NoiseBaseX = a_CellX - 2;
|
|
int NoiseBaseZ = a_CellZ - 2;
|
|
for (int x = 0; x < 5; x++)
|
|
{
|
|
int BaseX = (NoiseBaseX + x) * m_CellSize;
|
|
int OddRowOffset = ((NoiseBaseX + x) & 0x01) * m_OddRowOffset;
|
|
for (int z = 0; z < 5; z++)
|
|
{
|
|
int OffsetX = (m_Noise1.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_JitterSize;
|
|
int OffsetZ = (m_Noise2.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_JitterSize;
|
|
m_SeedX[x][z] = BaseX + OffsetX;
|
|
m_SeedZ[x][z] = (NoiseBaseZ + z) * m_CellSize + OddRowOffset + OffsetZ;
|
|
} // for z
|
|
} // for x
|
|
m_CurrentCellX = a_CellX;
|
|
m_CurrentCellZ = a_CellZ;
|
|
}
|
|
|
|
|
|
|
|
|