www.pudn.com > terrain.rar > FRACTMOD.C
#include#include #include "math.h" #include "fractmod.h" #ifdef __cplusplus extern "C" { #endif #ifdef _WINDOWS /* 为HPUX而写,控制Win32编译*/ #define random() rand() #define srandom(x) srand(x) #endif /* 随机返回一个(min,max)之间的值。 (任意一个范围被分为32767个值。) */ static float randnum (float min, float max) { int r; float x; r = random (); x = (float)(r & 0x7fff) / (float)0x7fff; return (x * (max - min) + min); } /* 定义randnum的简化界面 */ #define fractRand(v) randnum (-v, v) /* 计算数组中中点i所在线段端点值的平均值。 * * Called by fill1DFractArray. */ static float avgEndpoints (int i, int stride, float *fa) { return ((float) (fa[i-stride] + fa[i+stride]) * .5f); } /* 计算棱锥四角的平均值,(i,j)为棱锥中心点, stride为中心到角的纵横间隔, size是纵横横向点个数 由于是正方形,纵横间隔及两方向点均相等。 注意,size为纵横向顶点数,而subSize为线段数,均代表数组维数。 size=subSize+1; Called by fill2DFractArray. */ static float avgDiamondVals (int i, int j, int stride, int size, int subSize, float *fa) { /* 为支持排列表面无缝拼接,当(i,j)处于数组的某条边时要特别注意。 下面头四条if语句处理这种情。最后的else处理一般情况(i,j不在边界上)。*/ if (i == 0) return ((float) (fa[(i*size) + j-stride] + //j-strid fa[(i*size) + j+stride] + //j+strid fa[((subSize-stride)*size) + j] + //i-strid,不存在,用对边上的顶点 fa[((i+stride)*size) + j]) * .25f);//i+strid else if (i == size-1) return ((float) (fa[(i*size) + j-stride] + //j-strid fa[(i*size) + j+stride] + //j+strid fa[((i-stride)*size) + j] + //i-strid fa[((0+stride)*size) + j]) * .25f);//i+strid,不存在,用对边上的顶点 else if (j == 0) return ((float) (fa[((i-stride)*size) + j] + fa[((i+stride)*size) + j] + fa[(i*size) + j+stride] + fa[(i*size) + subSize-stride]) * .25f); else if (j == size-1) return ((float) (fa[((i-stride)*size) + j] + fa[((i+stride)*size) + j] + fa[(i*size) + j-stride] + fa[(i*size) + 0+stride]) * .25f); else return ((float) (fa[((i-stride)*size) + j] + //i-strid fa[((i+stride)*size) + j] + //i+strid fa[(i*size) + j-stride] + //j-strid fa[(i*size) + j+stride]) * .25f); //j+strid } /* 平均 中心位于(i,j)的正方形四角的数据值 stride为正方形边长度。 X.X .*. X.X 与棱锥步不同,这次不会有边界的问题。 Called by fill2DFractArray. */ static float avgSquareVals (int i, int j, int stride, int size, float *fa) { return ((float) (fa[((i-stride)*size) + j-stride] + fa[((i-stride)*size) + j+stride] + fa[((i+stride)*size) + j-stride] + fa[((i+stride)*size) + j+stride]) * .25f); } /*判断size是否为2的次方,是则返回1,不是或为0则返回0。*/ static int powerOf2 (int size) { int i, bitcount = 0; /* 下面的代码假定sizeof(int)*8可以算出一个整型数的位数。 适用于多数平台 */ for (i=0; i >= 1; } } /*用diamond-square算法拼嵌一个浮点数网格填充二维分形高度图*/ void fill2DFractArray (float *fa, int size, int seedValue, float heightScale, float h) { int i, j; int stride; int oddline; int subSize; float ratio, scale; //只处理维数为2的整数次方的数组 if (!powerOf2(size) || (size==1)) { return; } /* subSize 以纵横向线段数计的数组维数 segments 以顶点数计的数组维数 */ subSize = size; size++; /* initialize random number generator */ srandom (seedValue); /* 设定我们的粗糙度常量 随机数始终在0.0到1.0范围内生成。 随机数将乘上scale,每次迭代后scale将乘上ratio以有效的减少随机数范围。*/ ratio = (float) pow (2.,-h); scale = heightScale * ratio; /* 设置前四个种子值。如一个4X4数组,我们将初始化下边*代表的点: * . . . * . . . . . . . . . . . . . . . * . . . * 按diamond-square算法的术语,这将给我们正方形。 数组四角赋相同的值,这使我们排列数组时能无缝的拼接起来*/ stride = subSize / 2; fa[(0*size)+0] = fa[(subSize*size)+0] = fa[(subSize*size)+subSize] = fa[(0*size)+subSize] = 0.f; /*现在依据棱锥种子值递增加入细节。 根据stride循环,每次循环末尾都会将stride减半, 直到stride为0时结束 */ while (stride) { /* 先用square数据生成diamond数据。 第一遍经过4X4矩阵时,已有数据为下边的X, 我们要生成*处的数据: X . . . X . . . . . . . * . . . . . . . X . . . X */ for (i=stride; i >= 1; } } /* * alloc1DFractArray - Allocate float-sized data points for a 1D strip * containing size line segments. */ float *alloc1DFractArray (int size) { /* Increment size (see comment in alloc2DFractArray, below, for an explanation). */ size++; return ((float *) malloc (sizeof(float) * size)); } /* * alloc2DFractArray - Allocate float-sized data points for a sizeXsize * mesh. */ float *alloc2DFractArray (int size) { /* For a sizeXsize array, we need (size+1)X(size+1) space. For example, a 2x2 mesh needs 3x3=9 data points: * * * * * * * * * To account for this, increment 'size'. */ size++; return ((float *) malloc (sizeof(float) * size * size)); } /* * freeFractArray - Takes a pointer to float and frees it. Can be used * to free data that was allocated by either alloc1DFractArray or * alloc2DFractArray. */ void freeFractArray (float *fa) { free (fa); } extern void draw2DLine (float, float, float, float); /* 注意,要使用draw1DFractArrayAsLines将数组绘制成线段要先自己定义 四个参数的draw2DLine,参数为两个端点的x,y坐标。*/ void draw1DFractArrayAsLines (float *fa, int size) { int i; float x, inc; inc = 2.f / size; x = -1.f; for (i=0; i