BTW, could you provide any concepts or directions to study myself the algorithm used for the generation of the colormap? Being new to the topic, and an autodidact, I'd like to understand that part of the program, but my wits are falling short it seems.
Yeah so at first what it did was for every pixel of the map, look at its terrain and climate, and put a predefined color there. The colors were picked by me by looking at the colormap from Paradox in various spots in the middle east, western europe and scandinavia. This was fine but it looked jarring wherever the climate abruptly changed. I tried to circumvent that by applying some blurring to the result image but it still wasn't good and it took too much time to process.
The new approach is two-steps. First it blurs the climate image a lot, and also cuts down its resolution by 4 times. This is done to speed up the loops. The main stuff is here :
Complicating matters is that I'm working with several images/arrays that are different sizes.
I'm going to assume Config.INPUT_MAP_SCALE = 2
Terrain.bmp is the reference, climate.bmp is 2 times smaller, and the temporary climateArray is 4 times smaller than that.
Code:
for (int x=0 ; x<loader.sizeX/4/Config.INPUT_MAP_SCALE ; x++)
for (int y=0 ; y<loader.sizeY/4/Config.INPUT_MAP_SCALE ; y++)
{
int r=0,g=0,b=0,num=0;
The first loop (x,y) is going through every pixel in climateArray, which is 1/8 the size of the reference map (sizeX, sizeY)
Code:
for (int rx=x-radius; rx<=x+radius; rx++)
{
for (int ry=y-radius; ry<=y+radius; ry++)
{
if (Coordinates.isValidCoordinates(rx*4*Config.INPUT_MAP_SCALE, ry*4*Config.INPUT_MAP_SCALE))
{
if (Utils.getDistanceSquared(rx, ry, x, y) <= (radius*radius))
{
r +=Utils.getColorR(loader.bufInClimate.getRGB(rx*4, ry*4));
g +=Utils.getColorG(loader.bufInClimate.getRGB(rx*4, ry*4));
b +=Utils.getColorB(loader.bufInClimate.getRGB(rx*4, ry*4));
num++;
}
}
}
}
climateArray[x][y] = (r/num << 16) + (g/num << 8) + b/num;
The second loop (rx, ry), is going through every pixel in a radius of 16 pixels around the (x,y) coordinates, and calculates the "average color" of every pixel in that radius (That's 16 pixels in climateArray, so 64 in climate.bmp or 128 on terrain.bmp)
Coordinates.isValidCoordinates is just checking that rx and ry are not going to cause out of bounds exceptions.
For every pixel in that loop, I extract it's RGB components and add them to variables r,g and b. Then increment variable num. At the end of the second loop, I divide r,g and b by num and make that the color of climateArray at (x,y)
So it takes something that looks like
this and turns it into something that looks like
that.
The second step is choosing the color of the terrain.
Code:
for (int x=0 ; x<loader.sizeX ; x++)
for (int y=0 ; y<loader.sizeY ; y++)
{
double polar, temperate, hot;
hot = Utils.getColorR(climateArray[x/4/Config.INPUT_MAP_SCALE][y/4/Config.INPUT_MAP_SCALE]) / 255.0;
temperate = Utils.getColorG(climateArray[x/4/Config.INPUT_MAP_SCALE][y/4/Config.INPUT_MAP_SCALE]) / 255.0;
polar = Utils.getColorB(climateArray[x/4/Config.INPUT_MAP_SCALE][y/4/Config.INPUT_MAP_SCALE]) / 255.0;
double sum = (hot + temperate + polar);
if (sum == 0)
{
polar = 1.0f;
sum = 1.0f;
}
hot = hot / sum;
temperate = temperate / sum;
polar = polar / sum;
For each terrain type I have pre-defined 3 colors : one for polar climate (blue), one for "hot" climate (red) and one for temperate climate (green). I look at the climateArray corresponding to those coordinates to get what the climate is like, most likely somewhere between 2 of those climates.
So for example if a point in climateArray has the color (166;239;0) That means it is somewhere between "hot" and temperate, leaning more towards the later. I normalize this by dividing each component by the sum of all 3 :
166 / (166 + 239 + 0) =~ 0.41
239 / (166 + 239 + 0) =~ 0.59
Code:
r=(int) (60*polar + 120*temperate + 190*hot);
g=(int) (110*polar + 150*temperate + 170*hot);
b=(int) (75*polar + 60*temperate + 90*hot);
And to get the final color I just calculate the weighted average of each pre-defined color, so in my example 41% of the hot color and 59% of the temperate color, and the cold color just gets ignored.
After that I also add a bit of randomness to the colors, and then add some light additional blurring (also done by calculating the average color, but in a much smaller radius).