//topogen.cpp
//makes a big heightmap
//betopp 2011
//uploaded to freenode #vidyadev, public domain
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <ImfChannelList.h>
#include <ImfTiledOutputFile.h>
#include <half.h>
#define MAPSIZE 16385
#define CELLSIZE 256
#define HM(hmx,hmy) heightmap[((hmy)*MAPSIZE)+(hmx)]
#define VARDECAY 0.3f
void squarestep(float *heightmap, int xmin, int ymin, int xmax, int ymax, float var)
{
if(xmin >= (xmax))
return;
if(ymin >= (ymax))
return;
int xmiddle = (xmin + xmax) / 2;
int ymiddle = (ymin + ymax) / 2;
HM( xmiddle, ymiddle ) = (HM(xmax, ymax) + HM(xmax, ymin) + HM(xmin, ymax) + HM(xmin, ymin)) / 4.0f;
HM( xmiddle, ymiddle ) += 2.0f * (((float)random() / (float)RAND_MAX) - 0.5f) * var;
}
void squarestep_for_offset(float *heightmap, int offset, int stepsize, float var)
{
int cx;
int cy;
for(cy=offset;cy<(MAPSIZE-stepsize);cy+=stepsize)
{
for(cx=offset;cx<(MAPSIZE-stepsize);cx+=stepsize)
{
squarestep(heightmap, cx, cy, cx+stepsize, cy+stepsize, var);
}
}
}
void diamonds(float *heightmap, float var)
{
int cy, cx;
for(cy=1;cy<MAPSIZE-1;cy++)
{
for(cx=1;cx<MAPSIZE-1;cx++)
{
if( ((cx+cy)%2) )
{
HM(cx, cy) = ((HM((cx+1), cy)) + (HM((cx-1), cy)) + (HM(cx, (cy+1))) + (HM(cx, (cy-1)))) / 4.0f;
HM( cx, cy) += 2.0f * (((float)random() / (float)RAND_MAX) - 0.5f) * var;
}
}
}
}
void writeexr(half *heightmap)
{
/* int cellx, celly;
for(celly = 0; celly < (MAPSIZE-1)/CELLSIZE; celly++)
{
for(cellx = 0; cellx < (MAPSIZE-1)/CELLSIZE; cellx++)
{
}
}*/
/* float pixelAspectRatio = 1,
const Imath::V2f &screenWindowCenter = Imath::V2f (0, 0),
float screenWindowWidth = 1,
LineOrder lineOrder = INCREASING_Y,
Compression = ZIP_COMPRESSION);*/
Imf::Header imfH(MAPSIZE-1, MAPSIZE-1, 1, Imath::V2f (0, 0), 1, Imf::INCREASING_Y, Imf::B44A_COMPRESSION);
imfH.channels().insert("Z", Imf::Channel(Imf::HALF));
imfH.setTileDescription(Imf::TileDescription(CELLSIZE, CELLSIZE, Imf::MIPMAP_LEVELS));
Imf::TiledOutputFile imfOut("heightmap.exr", imfH);
Imf::FrameBuffer imfFB;
imfFB.insert("Z", Imf::Slice(Imf::HALF, (char*)heightmap, sizeof(half), sizeof(half)*MAPSIZE));
imfOut.setFrameBuffer(imfFB);
int lsize = MAPSIZE-1;
int level;
for(level=0;level<imfOut.numLevels();++level)
{
imfOut.writeTiles(0, imfOut.numXTiles(level)-1, 0, imfOut.numYTiles(level)-1, level);
lsize = lsize / 2;
int cx, cy;
for(cy=0;cy<lsize;cy++)
{
for(cx=0;cx<lsize;cx++)
{
int lowx = 2*cx;
int highx = lowx + 1;
int lowy = 2*cy*MAPSIZE;
int highy = lowy + MAPSIZE;
heightmap[(cy*MAPSIZE)+cx] = (heightmap[lowx+lowy] + heightmap[lowx+highy] + heightmap[highx+lowy] + heightmap[highx+highy]) / 4.0f;
}
}
}
}
int main(int argc, const char **argv)
{
int count;
int squaresize;
float var = 100.0f;
//allocate and initialize the map
float *heightmap = (float*)malloc(sizeof(float)*MAPSIZE*MAPSIZE);
for(count=0;count<MAPSIZE*MAPSIZE;count++)
{
heightmap[count] = 0.0f;
}
for(squaresize=(MAPSIZE-1);squaresize>1;squaresize = squaresize/2)
{
squarestep_for_offset(heightmap, 0, squaresize, var);
squarestep_for_offset(heightmap, squaresize/2, squaresize, var);
var *= VARDECAY;
}
diamonds(heightmap, var);
float min = 999999.0f;
float max = -999999.0f;
for(count=0;count<MAPSIZE*MAPSIZE;count++)
{
if(heightmap[count] < min)
min = heightmap[count];
if(heightmap[count] > max)
max = heightmap[count];
}
printf("min max %f %f\n", min, max);
half *halfbuf = (half*)heightmap;
for(count=0;count<MAPSIZE*MAPSIZE;count++)
{
halfbuf[count] = half((heightmap[count] - min) / (max - min));
}
//write chunky map
writeexr(halfbuf);
return 0;
}