TERRAIN.CPP
Upload User: nthssl
Upload Date: 2022-04-05
Package Size: 25357k
Code Size: 9k
Category:

OpenCV

Development Platform:

Visual C++

  1. #include "terrain.h"
  2. CTerrain::CTerrain()
  3. {
  4. width = 256;
  5. scanDepth = 80.0;
  6. terrainMul = 50.0;
  7. textureMul = 0.25;
  8. heightMul = 175.0;
  9. fogColor[0] = 0.75f;
  10. fogColor[1] = 0.9f;
  11. fogColor[2] = 1.0f;
  12. fogColor[3] = 1.0f;
  13. // CObject attributes
  14. position = CVector(0,0,0);
  15. velocity = CVector(0,0,0);
  16. acceleration = CVector(0,0,0);
  17. size = sqrt(width*terrainMul*width*terrainMul + width*terrainMul*width*terrainMul);
  18. BuildTerrain(width, 0.5f);
  19. }
  20. CTerrain::CTerrain(int w, float rFactor)
  21. {
  22. width = w;
  23. scanDepth = 80.0;
  24. terrainMul = 50.0;
  25. textureMul = 0.25;
  26. heightMul = 175.0;
  27. fogColor[0] = 0.75f;
  28. fogColor[1] = 0.9f;
  29. fogColor[2] = 1.0f;
  30. fogColor[3] = 1.0f;
  31. heightMap = NULL;
  32. // CObject attributes
  33. position = CVector(0,0,0);
  34. velocity = CVector(0,0,0);
  35. acceleration = CVector(0,0,0);
  36. size = sqrt(width*terrainMul*width*terrainMul + width*terrainMul*width*terrainMul);
  37. BuildTerrain(width, rFactor);
  38. }
  39. void CTerrain::BuildTerrain(int w, float rFactor)
  40. {
  41. width = w;
  42. heightMap = new float[width*width];
  43. MakeTerrainPlasma(heightMap, width, rFactor);
  44. // load texture
  45. terrainTex[0].LoadTexture("ground.tga");
  46. glGenTextures(1, &terrainTex[0].texID);
  47. glBindTexture(GL_TEXTURE_2D, terrainTex[0].texID);
  48. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  49. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  50. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); //or GL_CLAMP
  51. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //or GL_CLAMP
  52. switch (terrainTex[0].textureType)
  53. {
  54. case BMP:
  55. gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, terrainTex[0].width, terrainTex[0].height,
  56. GL_RGB, GL_UNSIGNED_BYTE, terrainTex[0].data);
  57. break;
  58. case PCX:
  59. gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, terrainTex[0].width, terrainTex[0].height,
  60. GL_RGBA, GL_UNSIGNED_BYTE, terrainTex[0].data);
  61. break;
  62. case TGA:
  63. gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, terrainTex[0].width, terrainTex[0].height,
  64. GL_RGB, GL_UNSIGNED_BYTE, terrainTex[0].data);
  65. break;
  66. default:
  67. break;
  68. }
  69. }
  70. void CTerrain::OnCollision(CObject *collisionObject)
  71. {}
  72. void CTerrain::OnDraw(CCamera *camera)
  73. {
  74. int z, x;
  75. glEnable(GL_DEPTH_TEST);
  76. glFogi(GL_FOG_MODE, GL_LINEAR);
  77. glFogfv(GL_FOG_COLOR, fogColor);
  78. glFogf(GL_FOG_START, scanDepth * 0.2f);
  79. glFogf(GL_FOG_END, scanDepth * 2.5);
  80. glHint(GL_FOG_HINT, GL_FASTEST);
  81. glEnable(GL_FOG);
  82. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  83. glEnable(GL_BLEND);
  84. glEnable(GL_ALPHA_TEST);
  85. glAlphaFunc(GL_GREATER,0.0);
  86. glDisable(GL_ALPHA_TEST);
  87. // push/pop objects that move with the camera (e.g. a sun, the sky)
  88. //glTranslatef(camera->x, camera->y, camera->z);
  89. glEnable(GL_TEXTURE_2D);
  90. glBindTexture(GL_TEXTURE_2D, terrainTex[0].texID);
  91. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  92. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  93. glColor3f(1.0, 1.0, 1.0);
  94. for (z = (int)(camera->position.z / terrainMul - scanDepth), z=z<0?0:z; (z < camera->position.z / terrainMul + scanDepth) && z < width-1; z++)
  95. {
  96. glBegin(GL_TRIANGLE_STRIP);
  97. for (x = (int)(camera->position.x / terrainMul - scanDepth), x=x<0?0:x; (x < camera->position.x / terrainMul + scanDepth) && x < width-1; x++)
  98. {
  99. // glColor3f(heightMap[x+z*width], heightMap[x+z*width], heightMap[x+z*width]);
  100. glTexCoord2f(textureMul * x, textureMul * z);
  101. glVertex3f((float)x*terrainMul, (float)heightMap[x + z*width]*heightMul, (float)z*terrainMul);
  102. // glColor3f(heightMap[x+1+z*width], heightMap[x+1+z*width], heightMap[x+1+z*width]);
  103. glTexCoord2f(textureMul * (x+1), textureMul * z);
  104. glVertex3f((float)(x+1)*terrainMul, (float)heightMap[x+1 + z*width]*heightMul, (float)z*terrainMul);
  105. // glColor3f(heightMap[x+(z+1)*width], heightMap[x+(z+1)*width], heightMap[x+(z+1)*width]);
  106. glTexCoord2f(textureMul * x, textureMul * (z+1));
  107. glVertex3f((float)x*terrainMul, (float)heightMap[x + (z+1)*width]*heightMul, (float)(z+1)*terrainMul);
  108. // glColor3f(heightMap[x+1+(z+1)*width], heightMap[x+1+(z+1)*width], heightMap[x+1+(z+1)*width]);
  109. glTexCoord2f(textureMul * (x+1), textureMul * (z+1));
  110. glVertex3f((float)(x+1)*terrainMul, (float)heightMap[x+1 + (z+1)*width]*heightMul, (float)(z+1)*terrainMul);
  111. }
  112. glEnd();
  113. }
  114. }
  115. // RangedRandom()
  116. // Returns a random number between v1 and v2
  117. float CTerrain::RangedRandom(float v1,float v2)
  118. {
  119. return v1 + (v2-v1)*((float)rand())/((float)RAND_MAX);
  120. }
  121. // NormalizeTerrain()
  122. // Given a height field, normalize it so that the minimum altitude
  123. // is 0.0 and the maximum altitude is 1.0
  124. void CTerrain::NormalizeTerrain(float field[],int size)
  125. {
  126. float maxVal,minVal,dh;
  127. int i;
  128. /*
  129. Find the maximum and minimum values in the height field
  130. */ 
  131. maxVal = field[0];
  132. minVal = field[0];
  133. for (i=1;i<size*size;i++)
  134. {
  135. if (field[i] > maxVal) 
  136. {
  137. maxVal = field[i];
  138. }
  139. else if (field[i] < minVal) 
  140. {
  141. minVal = field[i];
  142. }
  143. }
  144. /*
  145. Find the altitude range (dh)
  146. */
  147. if (maxVal <= minVal) return;
  148. dh = maxVal-minVal;
  149. /*
  150. Scale all the values so they are in the range 0-1
  151. */
  152. for (i=0;i<size*size;i++)
  153. {
  154. field[i] = (field[i]-minVal)/dh;
  155. }
  156. }
  157. // FilterHeightBand()
  158. // Erosion filter -
  159. // FilterHeightBand applies a FIR filter across a row or column of the height field
  160. void CTerrain::FilterHeightBand(float *band,int stride,int count,float filter)
  161. {
  162. int i,j=stride;
  163. float v = band[0];
  164. for (i=0;i<count-1;i++)
  165. {
  166. band[j] = filter*v + (1-filter)*band[j];
  167. v = band[j];
  168. j+=stride;
  169. }
  170. }
  171. // FilterHeightField()
  172. // Erosion filter -
  173. // Erodes a terrain in all 4 directions
  174. void CTerrain::FilterHeightField(float field[],int size,float filter)
  175. {
  176. int i;
  177. // Erode rows left to right
  178. for (i=0;i<size;i++)
  179. {
  180. FilterHeightBand(&field[size*i],1,size,filter);
  181. }
  182. // Erode rows right to left
  183. for (i=0;i<size;i++)
  184. {
  185. FilterHeightBand(&field[size*i+size-1],-1,size,filter);
  186. }
  187. // Erode columns top to bottom
  188. for (i=0;i<size;i++)
  189. {
  190. FilterHeightBand(&field[i],size,size,filter);
  191. }
  192. // Erode columns bottom to top
  193. for (i=0;i<size;i++)
  194. {
  195. FilterHeightBand(&field[size*(size-1)+i],-size,size,filter);
  196. }
  197. }
  198. // MakeTerrainPlasma()
  199. // desc: Genereate terrain using diamond-square (plasma) algorithm
  200. void CTerrain::MakeTerrainPlasma(float field[],int size,float rough)
  201. {
  202. int i,j,ni,nj,mi,mj,pmi,pmj,rectSize = size;
  203. float dh = (float)rectSize/2,r = (float)pow(2,-1*rough);
  204. // Since the terrain wraps, all 4 "corners" are represented by the value at 0,0,
  205. // so seeding the heightfield is very straightforward
  206. // Note that it doesn't matter what we use for a seed value, since we're going to
  207. // renormalize the terrain after we're done
  208. field[0] = 0;
  209. while(rectSize > 0)
  210. {
  211. /*
  212. Diamond step -
  213. Find the values at the center of the retangles by averaging the values at 
  214. the corners and adding a random offset:
  215. a.....b
  216. .     .  
  217. .  e  .
  218. .     .
  219. c.....d   
  220. e  = (a+b+c+d)/4 + random
  221. In the code below:
  222. a = (i,j)
  223. b = (ni,j)
  224. c = (i,nj)
  225. d = (ni,nj)
  226. e = (mi,mj)
  227. */
  228.        
  229. for (i=0;i<size;i+=rectSize)
  230. for (j=0;j<size;j+=rectSize)
  231. {
  232. ni = (i+rectSize)%size;
  233. nj = (j+rectSize)%size;
  234. mi = (i+rectSize/2);
  235. mj = (j+rectSize/2);
  236. field[mi+mj*size] = (field[i+j*size] + field[ni+j*size] + field[i+nj*size] + field[ni+nj*size])/4 + RangedRandom(-dh/2,dh/2);
  237. }
  238. /*
  239. Square step -
  240. Find the values on the left and top sides of each rectangle
  241. The right and bottom sides are the left and top sides of the neighboring rectangles,
  242.   so we don't need to calculate them
  243. The height field wraps, so we're never left hanging.  The right side of the last
  244. rectangle in a row is the left side of the first rectangle in the row.  The bottom
  245. side of the last rectangle in a column is the top side of the first rectangle in
  246. the column
  247.               .......
  248.       .     .
  249.       .     .
  250.       .  d  .
  251.       .     .
  252.       .     .
  253. ......a..g..b
  254. .     .     .
  255. .     .     .
  256. .  e  h  f  .
  257. .     .     .
  258. .     .     .
  259. ......c......
  260. g = (d+f+a+b)/4 + random
  261. h = (a+c+e+f)/4 + random
  262. In the code below:
  263. a = (i,j) 
  264. b = (ni,j) 
  265. c = (i,nj) 
  266. d = (mi,pmj) 
  267. e = (pmi,mj) 
  268. f = (mi,mj) 
  269. g = (mi,j)
  270. h = (i,mj)
  271. */
  272. for (i=0;i<size;i+=rectSize)
  273. for (j=0;j<size;j+=rectSize)
  274. {
  275. ni = (i+rectSize)%size;
  276. nj = (j+rectSize)%size;
  277. mi = (i+rectSize/2);
  278. mj = (j+rectSize/2);
  279. pmi = (i-rectSize/2+size)%size;
  280. pmj = (j-rectSize/2+size)%size;
  281. // Calculate the square value for the top side of the rectangle
  282. field[mi+j*size] = (field[i+j*size] + field[ni+j*size] + field[mi+pmj*size] + field[mi+mj*size])/4 + RangedRandom(-dh/2,dh/2);
  283. // Calculate the square value for the left side of the rectangle
  284. field[i+mj*size] = (field[i+j*size] + field[i+nj*size] + field[pmi+mj*size] + field[mi+mj*size])/4 + RangedRandom(-dh/2,dh/2);
  285. }
  286. // Setup values for next iteration
  287. // At this point, the height field has valid values at each of the coordinates that fall on a rectSize/2 boundary
  288. rectSize /= 2;
  289. dh *= r;
  290. }
  291. // Normalize terrain so minimum value is 0 and maximum value is 1
  292. NormalizeTerrain(field,size);
  293. }