Code:
//----------------------------------------------------------
// Complicated function generating the terrain and the regions
//----------------------------------------------------------
void VoronoiDiagram::VoronoiTiles(Bitmap *bmpHeights, Bitmap *bmp0, int number_of_regions, region *regions)
{
for(int x = 0; x < bmpHeights->height; x++)
{
for(int y = 0; y < bmpHeights->width; y++)
{
if(bmpHeights->map[x][y].b == 255)
{
rm.belowSea[rm.belowSeaCount].x = x;
rm.belowSea[rm.belowSeaCount].y = y;
rm.belowSeaCount++;
}
if(bmpHeights->map[x][y].b != 255)
{
rm.aboveSeaLevel[rm.aboveCount].y = y/2;
rm.aboveSeaLevel[rm.aboveCount].x = x/2;
rm.aboveCount++;
}
}
}
int rows = settings.rows;
int columns = settings.columns;
int columnSpacing = bmp0->width / (columns + 1);// Is width
int rowSpacing = bmp0->height / (rows + 1); //Is height
int number_of_points = 200;//Number of fragments
voronoi_point points[4096];
voronoi_point regionPoints[4096];
int height = bmp0->height;
int width = bmp0->width;
//Bitmap bmpV(width, height);
//clearToRGB(0,0,0);
//Generate voronoii points
for(unsigned __int8 n = 0; n < number_of_points; n++)
{
points[n].x = (0.10 * height) + rand()%int(0.80 * height);
points[n].y = (0.10 * width) + rand()%int(0.80 * width);
points[n].col.r = rand()%255;
points[n].col.g = rand()%255;
points[n].col.b = rand()%255;
}
//Select region points from rows and columns if inland
if(settings.mapType == "inland")
{
cout << "Map type: inland.";
//
//***Generate these points in a snaking pattern***
//Region points from number of rows and columns
//
int curX = 0;
int curY = 0;
int n = 0;
int total = rows * columns;
for(int a = 0; a < rows; a++)
{
curY += rowSpacing;
curX = 0;
for(int b = 0; b < columns; b++)
{
curX += columnSpacing;
regionPoints[n].y = curX;
regionPoints[n].x = curY;
regionPoints[n].col.r = regions[n].colour.r;
regionPoints[n].col.g = regions[n].colour.g;
regionPoints[n].col.b = regions[n].colour.b;
n++;
}
a++;
curY += rowSpacing;
for(int b = columns-1; b >= 0; b--)
{
regionPoints[n].y = curX;
regionPoints[n].x = curY;
regionPoints[n].col.r = regions[n].colour.r;
regionPoints[n].col.g = regions[n].colour.g;
regionPoints[n].col.b = regions[n].colour.b;
n++;
curX -= columnSpacing;
}
//cout << "region points = " << n << endl;
}
}
//Put region color around the point
//
//--------------------------
// 1) Get grid positions
//--------------------------
//
if(settings.mapType == "coastal2")
{
//
//***Generate these points in a snaking pattern***
//Region points from number of rows and columns
//
int curX = 0;
int curY = 0;
int n = 0;
int total = rows * columns;
for(__int8 a = 0; a < rows; a++)
{
curY += rowSpacing;
curX = 0;
for(__int8 b = 0; b < columns; b++)
{
curX += columnSpacing;
regionPoints[n].y = curX;
regionPoints[n].x = curY;
regionPoints[n].col.r = regions[n].colour.r;
regionPoints[n].col.g = regions[n].colour.g;
regionPoints[n].col.b = regions[n].colour.b;
n++;
}
a++;
curY += rowSpacing;
for(__int8 b = columns-1; b >= 0; b--)
{
regionPoints[n].y = curX;
regionPoints[n].x = curY;
regionPoints[n].col.r = regions[n].colour.r;
regionPoints[n].col.g = regions[n].colour.g;
regionPoints[n].col.b = regions[n].colour.b;
n++;
curX -= columnSpacing;
}
//cout << "region points = " << total << endl;
}
}
//Use original algorithm
/*
//Randomize the region points
for(__int8 n2 = 0; n2 < number_of_regions; n2++)
{
int rndX = -3 + rand()%6;
int rndY = -3 + rand()%6;
if(regionPoints[n2].x + rndX > 0 && regionPoints[n2].x + rndX < width){regionPoints[n2].x = regionPoints[n2].x + rndX;};
if(regionPoints[n2].y + rndY > 0 && regionPoints[n2].y + rndY < height){regionPoints[n2].y = regionPoints[n2].y + rndY;};
}
*/
//Draw settlement positions
for(__int8 n2 = 0; n2 < number_of_regions; n2++)
{
//bmpV.map[regionPoints[n2].x][regionPoints[n2].y].r = 255;
//bmpV.map[regionPoints[n2].x][regionPoints[n2].y].g = 255;
//bmpV.map[regionPoints[n2].x][regionPoints[n2].y].b = 255;
//Update the region position for each region (the row & column grid location)
regions[n2].regionPos.x = regionPoints[n2].x;
regions[n2].regionPos.y = regionPoints[n2].y;
regions[n2].settlementPos.x = regionPoints[n2].y;
regions[n2].settlementPos.y = regionPoints[n2].x;
}
//TGA tga2;
//tga2.write_tga( "C:\\Users\\User\\Desktop\\voronoii_2.tga" , &bmpV );
//system("PAUSE");
//return &bmpV;
//Slightly randomize region point position
/*
if(settings->randomizeSettlementPositions)
{
for(int n = 0; n < number_of_regions; n++)
{
regionPoints[n].x = (0.10 * height) + rand()%int(0.80 * height);
regionPoints[n].y = (0.10 * width) + rand()%int(0.80 * width);
regionPoints[n].col.r = regions[n].colour.r;
regionPoints[n].col.g = regions[n].colour.g;
regionPoints[n].col.b = regions[n].colour.b;
}
}
*/
/*
//Output voronoii bitmap
for(int x = 0; x < height; x++)
{
for(int y = 0; y < width; y++)
{
//Find closest point to current pixel...
int closestIndex = 0;
float closestDistance = height * width + 100;
for(int n = 0; n < number_of_points; n++)
{
float curDist = distance(x, y, 0, points[n].x, points[n].y, 0);
if(curDist < closestDistance)
{
closestIndex = n;
closestDistance = curDist;
}
}
bmpV.map[x][y].r = points[closestIndex].col.r; bmpV.map[x][y].g = points[closestIndex].col.g; bmpV.map[x][y].b = points[closestIndex].col.b;
}
}
*/
/*
//Draw settlement positions (Only if fixed positions selected)
if(!settings.randomizeSettlementPositions)
{
for(int n = 0; n < number_of_regions; n++)
{
bmpV.map[regionPoints[n].x][regionPoints[n].y].r = 0;
bmpV.map[regionPoints[n].x][regionPoints[n].y].g = 0;
bmpV.map[regionPoints[n].x][regionPoints[n].y].b = 0;
}
}
TGA tga;
tga.write_tga( "C:\\Users\\User\\Desktop\\voronoii.tga" , &bmpV );
*/
//--------------------------
// 2) Get coloured regions
//--------------------------
//Change voronoii point colors to correspond to nearest region point
for(unsigned __int8 i = 0; i < number_of_points; i++)
{
int x = points[i].x;
int y = points[i].y;
//Find closest point to current pixel
int closestIndex = 0;
float closestDistance = height * width + 100;
for(unsigned __int8 n = 0; n < number_of_regions; n++)
{
float curDist = distance(x, y, 0, regionPoints[n].x, regionPoints[n].y, 0);
if(curDist < closestDistance)
{
closestIndex = n;
closestDistance = curDist;
}
}
points[i].col.r = regionPoints[closestIndex].col.r;
points[i].col.g = regionPoints[closestIndex].col.g;
points[i].col.b = regionPoints[closestIndex].col.b;
}
//------------------------------------------------------
//-----------------------------------------
//3) Draw islands at positions on terrain
//-----------------------------------------
//Joins all provinces in grid like form
//Settlement is the region point
for(unsigned __int8 n = 0; n < number_of_regions; n++)
{
//bmp0->map[regionPoints[n].x][regionPoints[n].y].r = 0;
//bmp0->map[regionPoints[n].x][regionPoints[n].y].g = 0;
//bmp0->map[regionPoints[n].x][regionPoints[n].y].b = 0;
/*
//Surround region point with region color
rgb curCol;
curCol.r = 255;//regionPoints[n].col.r;
curCol.g = 255;//regionPoints[n].col.g;
curCol.b = 255;//regionPoints[n].col.b;
//Surround region point with region color
bmp0->map[regionPoints[n].x - 1][regionPoints[n].y].r = curCol.r;
bmp0->map[regionPoints[n].x - 1][regionPoints[n].y].g = curCol.g;
bmp0->map[regionPoints[n].x - 1][regionPoints[n].y].b = curCol.b;
bmp0->map[regionPoints[n].x - 1][regionPoints[n].y - 1].r = curCol.r;
bmp0->map[regionPoints[n].x - 1][regionPoints[n].y - 1].g = curCol.g;
bmp0->map[regionPoints[n].x - 1][regionPoints[n].y - 1].b = curCol.b;
bmp0->map[regionPoints[n].x][regionPoints[n].y - 1].r = curCol.r;
bmp0->map[regionPoints[n].x][regionPoints[n].y - 1].g = curCol.g;
bmp0->map[regionPoints[n].x][regionPoints[n].y - 1].b = curCol.b;
bmp0->map[regionPoints[n].x][regionPoints[n].y + 1].r = curCol.r;
bmp0->map[regionPoints[n].x][regionPoints[n].y + 1].g = curCol.g;
bmp0->map[regionPoints[n].x][regionPoints[n].y + 1].b = curCol.b;
bmp0->map[regionPoints[n].x + 1][regionPoints[n].y + 1].r = curCol.r;
bmp0->map[regionPoints[n].x + 1][regionPoints[n].y + 1].g = curCol.g;
bmp0->map[regionPoints[n].x + 1][regionPoints[n].y + 1].b = curCol.b;
bmp0->map[regionPoints[n].x + 1][regionPoints[n].y].r = curCol.r;
bmp0->map[regionPoints[n].x + 1][regionPoints[n].y].g = curCol.g;
bmp0->map[regionPoints[n].x + 1][regionPoints[n].y].b = curCol.b;
bmp0->map[regionPoints[n].x + 1][regionPoints[n].y - 1].r = curCol.r;
bmp0->map[regionPoints[n].x + 1][regionPoints[n].y - 1].g = curCol.g;
bmp0->map[regionPoints[n].x + 1][regionPoints[n].y - 1].b = curCol.b;
bmp0->map[regionPoints[n].x - 1][regionPoints[n].y + 1].r = curCol.r;
bmp0->map[regionPoints[n].x - 1][regionPoints[n].y + 1].g = curCol.g;
bmp0->map[regionPoints[n].x - 1][regionPoints[n].y + 1].b = curCol.b;
*/
regions[n].actualSettlementPos.x = regionPoints[n].x;
regions[n].actualSettlementPos.y = regionPoints[n].y;
pos2d pos;
pos.x = (regions[n].actualSettlementPos.x*2) + 1;
pos.y = (regions[n].actualSettlementPos.y*2) + 1;
if(settings.mapType != "inland")//Inland
{
rm.GenerateIslandAtPosition(pos);
}
}
//Smooth the terrain map before assigning region colors
rm.smooth();
//-----------------------------------------
// 4) Colorize the bitmap pixels & make sure they are above sea level
//-----------------------------------------
for(int x = 0; x < height; x++)
{
for(int y = 0; y < width; y++)
{
//Find closest point to current pixel...
int closestIndex = 0;
float closestDistance = height * width + 100;
for(int n = 0; n < number_of_points; n++)
{
float curDist = distance(x, y, 0, points[n].x, points[n].y, 0);
if(curDist < closestDistance)
{
closestIndex = n;
closestDistance = curDist;
}
}
bool found = false;
for(int a = 0; a < number_of_regions-1; a++)
{
//rm.makePassable((regions[a].actualSettlementPos.x), (regions[a].actualSettlementPos.y), (regions[a+1].actualSettlementPos.x), (regions[a+1].actualSettlementPos.y));
}
found = false;
if (rm.terrain[(x*2)+1][(y*2)+1] > settings.seaHeight + 5){found = true;}//Above sea level
if (rm.mustBePassableSmall[x][y] == true){found = true;}//Above sea level
if(found == true)
{
bmp0->map[x][y].r = points[closestIndex].col.r; bmp0->map[x][y].g = points[closestIndex].col.g; bmp0->map[x][y].b = points[closestIndex].col.b;
}
else
{
bmp0->map[x][y].r = 41; bmp0->map[x][y].g = 140; bmp0->map[x][y].b = 233;//Sea
}
}
}
//------------------------------------------------------------------------
// !!!!!!!!!!! This fails to allocate settlements if land mass is small !!!!!!!!!!!
//------------------------------------------------------------------------
//5) Put settlement at centre of mass
//if(settings.mapType != "inland")
pos2d curRegion[4096];
int curRegionPxCount;
if(1==1)
{
//Put the settlement in the centre of mass of each region
//Regions must be of minimum size
//Generate the region points array
for(int h = 0; h < number_of_regions; h++)
{
int curR = regions[h].colour.r;
int curG = regions[h].colour.g;
int curB = regions[h].colour.b;
curRegionPxCount = 0;
for(int g = 0; g < width; g++)
{
for(int w = 0; w < height; w++)
{
if(bmp0->map[w][g].r == curR && bmp0->map[w][g].g == curG && bmp0->map[w][g].b == curB)
{
curRegion[curRegionPxCount].x = g;
curRegion[curRegionPxCount].y = w;
curRegionPxCount++;
}
}
}
//Generate edge list
rm.edgePointCount = 0;
//-------------------
//For every pixel in the current region
//-------------------
for(int i = 0; i < curRegionPxCount; i++)
{
//cout << "crpc: " << curRegionPxCount << endl;
pos2d curPoint = curRegion[i];
int curX = curPoint.x;
int curY = curPoint.y;
//Greatest and least values for current pixel
int greatestY = -1;
int greatestX = -1;
int leastX = 1000;
int leastY = 1000;
int curEdge = 0;
//IDENTIFY HIGHEST AND LOWEST FOR CURRENT PIXEL
for( int k = 0 ; k < curRegionPxCount ; k++ )
{
pos2d scanPoint2 = curRegion[k];
if(scanPoint2.y == curY && scanPoint2.x >= greatestX)
{
greatestX = scanPoint2.x;
}
if(scanPoint2.y == curY && scanPoint2.x <= leastX)
{
leastX = scanPoint2.x;
}
if(scanPoint2.x == curX && scanPoint2.y <= leastY)
{
leastY = scanPoint2.y;
}
if(scanPoint2.x == curX && scanPoint2.y >= greatestY)
{
greatestY = scanPoint2.y;
}
}
if(curX >= greatestX)
{
rm.edgePoints[rm.edgePointCount].x = curPoint.x;
rm.edgePoints[rm.edgePointCount].y = curY;
rm.edgePointCount++;
}
if(curX <= leastX)
{
rm.edgePoints[rm.edgePointCount].x = curPoint.x;
rm.edgePoints[rm.edgePointCount].y = curY;
rm.edgePointCount++;
}
if(curY <= leastY)
{
rm.edgePoints[rm.edgePointCount].x = curPoint.x;
rm.edgePoints[rm.edgePointCount].y = curY;
rm.edgePointCount++;
}
if(curY >= greatestY)
{
rm.edgePoints[rm.edgePointCount].x = curPoint.x;
rm.edgePoints[rm.edgePointCount].y = curY;
rm.edgePointCount++;
}
}
//----------------------------------
/*
//Draw edges
for( int k = 0 ; k < rm.edgePointCount ; k++ )
{
//For border rivers...
rm.edgePositions[rm.edgePositionCount].x = rm.edgePoints[k].x;
rm.edgePositions[rm.edgePositionCount].y = rm.edgePoints[k].y;
rm.edgePositionCount++;
//cout << rm.edgePositionCount << endl;
bmp0->map[rm.edgePoints[k].y][rm.edgePoints[k].x].r = 255;
bmp0->map[rm.edgePoints[k].y][rm.edgePoints[k].x].g = 255;
bmp0->map[rm.edgePoints[k].y][rm.edgePoints[k].x].b = 255;
}
*/
//-----------------------------------------
//Region loop end (int h)
//MessageBoxA(NULL, "reg", "reg", MB_OK | MB_ICONINFORMATION);
int ic = 0;
float distances[8192];
int closestIndex;
int closestDist = 1000;
//Put the settlement at point furthest away from all edges.
for( int j = 0 ; j < curRegionPxCount ; j++ )
{
pos2d scanPoint = curRegion[j];
closestDist = 10000;
//Find pixel's closest edge
for(int u = 0; u < rm.edgePointCount; u++)
{
pos2d edgePoint = rm.edgePoints[u];
float dist = distance((float)scanPoint.x, (float)scanPoint.y, 0, (float)edgePoint.x, (float)edgePoint.y, 0);
if(dist <= closestDist)
{
closestIndex = j;
closestDist = dist;
}
}
distances[ic] = closestDist; // Distance for this point //
ic++;
}
int maxDist = 0;
int maxIndex = 0;
//Maximum distance from edge
for(int a = 0; a < ic; a++)
{
//cout << distances[a] << endl;
if(distances[a] > maxDist)
{
//cout << distances[a] << endl;
maxIndex = a;
maxDist = distances[a];
}
}
//
//stringstream f;
int inside[8192];//Inside index int
int insideCount = 0;
//Greater than 5 from edge
for(int a = 0; a < ic; a++)
{
//cout << distances[a] << endl;
if(distances[a] > 1)
{
//f << distances[a] << ", ";
//MessageBoxA(NULL, f.str().c_str(), "Message", MB_OK | MB_ICONINFORMATION);
inside[insideCount] = a;
insideCount++;
}
}
//MessageBoxA(NULL, f.str().c_str(), "Message", MB_OK | MB_ICONINFORMATION);
//Furthest index:
int mx;// = curRegion[maxIndex].x;
int my;// = curRegion[maxIndex].y;
int indexI = 0;
if(insideCount > 0)
{
indexI = inside[rand()%insideCount];
}
mx = curRegion[indexI].y;
my = curRegion[indexI].x;
//cout << "m " << mx << " "<< my;
//system("PAUSE");
bmp0->map[ mx ] [ my ].r = 0;
bmp0->map[ mx ] [ my ].g = 0;
bmp0->map[ mx ] [ my ].b = 0;
//rm.makePassable((regions[h].actualSettlementPos.x), (regions[h].actualSettlementPos.y), (regions[h+1].actualSettlementPos.x), (regions[h+1].actualSettlementPos.y));
regions[h].actualSettlementPos.y = my;
regions[h].actualSettlementPos.x = mx;
rm.hill_1((mx * 2) + 1, (my * 2) + 1, 0, 10, 50);
//stringstream f;
//f << number_of_regions;
//MessageBoxA(NULL, f.str().c_str(), "sp", MB_OK | MB_ICONINFORMATION);
}
}
//Surround settlement point with region color
for(unsigned __int8 n = 0; n < number_of_regions; n++)
{
rgb curCol;
curCol.r = regionPoints[n].col.r;
curCol.g = regionPoints[n].col.g;
curCol.b = regionPoints[n].col.b;
pos2d point;
point = regions[n].actualSettlementPos;
bmp0->map[point.x - 1][point.y].r = curCol.r;
bmp0->map[point.x - 1][point.y].g = curCol.g;
bmp0->map[point.x - 1][point.y].b = curCol.b;
bmp0->map[point.x - 1][point.y - 1].r = curCol.r;
bmp0->map[point.x - 1][point.y - 1].g = curCol.g;
bmp0->map[point.x - 1][point.y - 1].b = curCol.b;
bmp0->map[point.x][point.y - 1].r = curCol.r;
bmp0->map[point.x][point.y - 1].g = curCol.g;
bmp0->map[point.x][point.y - 1].b = curCol.b;
bmp0->map[point.x][point.y + 1].r = curCol.r;
bmp0->map[point.x][point.y + 1].g = curCol.g;
bmp0->map[point.x][point.y + 1].b = curCol.b;
bmp0->map[point.x + 1][point.y + 1].r = curCol.r;
bmp0->map[point.x + 1][point.y + 1].g = curCol.g;
bmp0->map[point.x + 1][point.y + 1].b = curCol.b;
bmp0->map[point.x + 1][point.y].r = curCol.r;
bmp0->map[point.x + 1][point.y].g = curCol.g;
bmp0->map[point.x + 1][point.y].b = curCol.b;
bmp0->map[point.x + 1][point.y - 1].r = curCol.r;
bmp0->map[point.x + 1][point.y - 1].g = curCol.g;
bmp0->map[point.x + 1][point.y - 1].b = curCol.b;
bmp0->map[point.x - 1][point.y + 1].r = curCol.r;
bmp0->map[point.x - 1][point.y + 1].g = curCol.g;
bmp0->map[point.x - 1][point.y + 1].b = curCol.b;
}