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