CTerrain.cpp
上传用户:arsena_zhu
上传日期:2022-07-12
资源大小:399k
文件大小:29k
源码类别:

OpenGL

开发平台:

Visual C++

  1. /*
  2.    Class Name:
  3.       CTerrain.
  4.    Created by:
  5.       Allen Sherrod (Programming Ace of www.UltimateGameProgramming.com).
  6.    Description:
  7.       This class is a base class used to load and save a terrain.
  8. */
  9. #include "main.h"
  10. float mod(float f)
  11. {
  12. while(f >= 1) f--;
  13. return f;
  14. }
  15. CTerrain::CTerrain()
  16. {
  17.    bInvert = true;
  18.    fScale = 0.1f;
  19.    pVertex = NULL;
  20.    pTexCoords = NULL;
  21.    pTexCoords2 = NULL;
  22.    iVerts = 0;
  23.    iTriangles = 0;
  24.    iDetail = 1;
  25. }
  26. CTerrain::~CTerrain()
  27. {
  28.    ShutDown();
  29. }
  30. bool CTerrain::LoadMap(char *filename, int detailRepeats)
  31. {
  32. FILE *f = NULL;
  33. f = fopen(filename, "rb");
  34. if(f == NULL) return false;
  35. fread(&side, 1, sizeof(side), f);
  36. if (side > 1024 || side < 32) side = 128;
  37. side_ = side-1;
  38. hMap = new float[side*side];
  39.   fread(hMap, sizeof(*hMap), side*side, f);
  40. if(f == NULL) { MessageBox(NULL, "f == NULL :/", "map loading failed", MB_OK); fclose(f); return false; }
  41. fclose(f);
  42. if (detailRepeats == 0)
  43. { if (iDetail == 0) iDetail = 16; }
  44. else iDetail = detailRepeats;
  45. CreateTerrainMesh();
  46. return true;
  47. }
  48. bool CTerrain::SaveMap(char *filename)
  49. {
  50. FILE *f = NULL;
  51. f = fopen(filename, "wb");
  52. if(f == NULL) return false;
  53. fwrite(&side, 1, sizeof(side), f);
  54.   fwrite(hMap, sizeof(*hMap), side*side, f);
  55. if(f == NULL) { MessageBox(NULL, "f == NULL :/", "map loading failed", MB_OK); fclose(f); return false; }
  56. fclose(f);
  57. return true;
  58. }
  59. void CTerrain::ConvertMesh()
  60. {
  61. for (int x=0 ; x < side ; x++)
  62. {
  63. for (int z=0 ; z < side ; z++)
  64. {
  65. hMap[x + z*side] = GetHeight(x, z);
  66. }
  67. }
  68. }
  69. void CTerrain::CreateTerrainMesh()
  70. {
  71.    // Index counters.
  72.    int i = 0, t = 0, t2 = 0;
  73.    if(pVertex) delete[] pVertex;
  74.    if(pTexCoords) delete[] pTexCoords;
  75.    if(pTexCoords2) delete[] pTexCoords2;
  76.    iVerts = 0;
  77.    iTriangles = 0;
  78.    //Sizes we need for the points/color and tex coords.
  79.    int size = ((side - 1) *
  80.               (side - 1) * 6) * 3;
  81.    int tSize = ((side - 1) *
  82.               (side - 1) * 6) * 2;
  83.    // Create enough space for all vertex points and their colors.
  84.    pVertex = new float[size];
  85.    pTexCoords = new float[tSize];
  86.    pTexCoords2 = new float[tSize];
  87.    // Loop through and generate a grid.  Use the height map
  88.    // when setting the Y to create the terrain mesh.  Create 2 triangles
  89.    // each iteration.
  90.    for(int z = 0; z < side - 1; z++)
  91.    {
  92. for(int x = 0; x < side - 1; x++)
  93.    {
  94.       // Calculate texture coords for these tris.
  95.       float left = (float)x / side;
  96.       float right = ((float)x + 1) / side;
  97.    float bottom = (float)z / side;
  98.    float top = (float)(z + 1) / side;
  99.                // V1.
  100.       pTexCoords[t++] = left;
  101.       pTexCoords[t++] = bottom;
  102.       pTexCoords2[t2++] = left * iDetail;
  103.       pTexCoords2[t2++] = bottom * iDetail;
  104.       pVertex[i++] = (float)x;
  105.       pVertex[i++] = GetDataHeight(x, z);
  106.       pVertex[i++] = (float)z;
  107.       iVerts++;
  108.                // V2.
  109.             pTexCoords[t++] = left;
  110.       pTexCoords[t++] = top;
  111.       pTexCoords2[t2++] = left * iDetail;
  112.       pTexCoords2[t2++] = top * iDetail;
  113.       pVertex[i++] = (float)x;
  114.       pVertex[i++] = GetDataHeight(x, z + 1);
  115.       pVertex[i++] = (float)z + 1;
  116.       iVerts++;
  117.                // V3.
  118.             pTexCoords[t++] = right;
  119.       pTexCoords[t++] = bottom;
  120.       pTexCoords2[t2++] = right * iDetail;
  121.       pTexCoords2[t2++] = bottom * iDetail;
  122.       pVertex[i++] = (float)x + 1;
  123.       pVertex[i++] = GetDataHeight(x + 1, z);
  124.       pVertex[i++] = (float)z;
  125.       iVerts++;
  126.                // V4.
  127.             pTexCoords[t++] = right;
  128.       pTexCoords[t++] = bottom;
  129.       pTexCoords2[t2++] = right * iDetail;
  130.       pTexCoords2[t2++] = bottom * iDetail;
  131.       pVertex[i++] = (float)x + 1;
  132.       pVertex[i++] = GetDataHeight(x + 1, z);
  133.       pVertex[i++] = (float)z;
  134.       iVerts++;
  135.                // V5.
  136.             pTexCoords[t++] = right;
  137.       pTexCoords[t++] = top;
  138.       pTexCoords2[t2++] = right * iDetail;
  139.       pTexCoords2[t2++] = top * iDetail;
  140.       pVertex[i++] = (float)x + 1;
  141.       pVertex[i++] = GetDataHeight(x + 1, z + 1);
  142.       pVertex[i++] = (float)z + 1;
  143.       iVerts++;
  144.                // V6.
  145.             pTexCoords[t++] = left;
  146.       pTexCoords[t++] = top;
  147.             pTexCoords2[t2++] = left * iDetail;
  148.       pTexCoords2[t2++] = top * iDetail;
  149.       pVertex[i++] = (float)x;
  150.       pVertex[i++] = GetDataHeight(x, z + 1);
  151.       pVertex[i++] = (float)z + 1;
  152.       iVerts++;
  153.             iTriangles += 2;
  154.    }
  155.    }
  156. }
  157. void CTerrain::CreateTexCoords()
  158. {
  159.    // Index counters.
  160.    int t = 0, t2 = 0;
  161.    if(pTexCoords) delete[] pTexCoords;
  162.    if(pTexCoords2) delete[] pTexCoords2;
  163.    //Sizes we need for the points/color and tex coords.
  164.    int size = ((side - 1) *
  165.               (side - 1) * 6) * 3;
  166.    int tSize = ((side - 1) *
  167.               (side - 1) * 6) * 2;
  168.    // Create enough space for all vertex points and their colors.
  169.    pTexCoords = new float[tSize];
  170.    pTexCoords2 = new float[tSize];
  171.    // Loop through and generate a grid.  Use the height map
  172.    // when setting the Y to create the terrain mesh.  Create 2 triangles
  173.    // each iteration.
  174.    for(int z = 0; z < side - 1; z++)
  175.    {
  176. for(int x = 0; x < side - 1; x++)
  177.    {
  178.       // Calculate texture coords for these tris.
  179.       float left = (float)x / side;
  180.       float right = ((float)x + 1) / side;
  181.    float bottom = (float)z / side;
  182.    float top = (float)(z + 1) / side;
  183.                // V1.
  184.       pTexCoords[t++] = left;
  185.       pTexCoords[t++] = bottom;
  186.       pTexCoords2[t2++] = left * iDetail;
  187.       pTexCoords2[t2++] = bottom * iDetail;
  188.                // V2.
  189.             pTexCoords[t++] = left;
  190.       pTexCoords[t++] = top;
  191.       pTexCoords2[t2++] = left * iDetail;
  192.       pTexCoords2[t2++] = top * iDetail;
  193.                // V3.
  194.             pTexCoords[t++] = right;
  195.       pTexCoords[t++] = bottom;
  196.       pTexCoords2[t2++] = right * iDetail;
  197.       pTexCoords2[t2++] = bottom * iDetail;
  198.                // V4.
  199.             pTexCoords[t++] = right;
  200.       pTexCoords[t++] = bottom;
  201.       pTexCoords2[t2++] = right * iDetail;
  202.       pTexCoords2[t2++] = bottom * iDetail;
  203.                // V5.
  204.             pTexCoords[t++] = right;
  205.       pTexCoords[t++] = top;
  206.       pTexCoords2[t2++] = right * iDetail;
  207.       pTexCoords2[t2++] = top * iDetail;
  208.                // V6.
  209.             pTexCoords[t++] = left;
  210.       pTexCoords[t++] = top;
  211.             pTexCoords2[t2++] = left * iDetail;
  212.       pTexCoords2[t2++] = top * iDetail;
  213.    }
  214.    }
  215. }
  216. void CTerrain::SetHeightScale(int val)
  217. {
  218.    // Set the scale value to want is passed in.
  219.    fScale = val;
  220. }
  221. void CTerrain::SetDataHeight(int x, int z, float set)
  222. {
  223. if (x < 0 || z < 0 || x >= side || z >= side) return;
  224. hMap[x + side * z] = set;
  225. }
  226. float CTerrain::GetDataHeight(int x, int z)
  227. {
  228. if (x < 0 || z < 0 || x >= side || z >= side) return 0;
  229. return hMap[x + side * z];
  230. }
  231. float CTerrain::RegionPercent(int tileType, float height)
  232. {
  233. float distance1 = 0, distance2 = 0;
  234.    // First we test each tile and see if the test height is greater than its optimal height.
  235.    // We only test those that are the type we sent it.
  236. if(m_tiles.texTiles[0].image)
  237.    {
  238.    if(tileType == 0 && height < m_tiles.regions[0].optimalHeight)
  239.    return 1.0f;
  240.    }
  241. else if(m_tiles.texTiles[1].image)
  242.    {
  243.    if(tileType == 1 && height < m_tiles.regions[1].optimalHeight)
  244.    return 1.0f;
  245.    }
  246. else if(m_tiles.texTiles[2].image)
  247.    {
  248.    if(tileType == 2 && height < m_tiles.regions[2].optimalHeight)
  249.    return 1.0f;
  250.    }
  251. else if(m_tiles.texTiles[3].image)
  252.    {
  253.    if(tileType == 3 && height < m_tiles.regions[3].optimalHeight)
  254.    return 1.0f;
  255.    }
  256. // If the height we are testing is below or above the choose tile type then we return 0.
  257. if(height < m_tiles.regions[tileType].lowHeight)
  258. return 0.0f;
  259. else if(height > m_tiles.regions[tileType].highHeight)
  260. return 0.0f;
  261. // If the height is below the optimal height
  262. if(height < m_tiles.regions[tileType].optimalHeight)
  263.    {
  264.    // Get the distance between the m_tiles lowest height and the test height.
  265.    distance1 = (float)(height - m_tiles.regions[tileType].lowHeight);
  266.          // Get the distance between the optimal height and the lowest height.
  267.    distance2 = (float)(m_tiles.regions[tileType].optimalHeight -
  268.                m_tiles.regions[tileType].lowHeight);
  269.          // return the percent.
  270.    return (distance1 / distance2);
  271.    }
  272.    else if(height == m_tiles.regions[tileType].optimalHeight)
  273.       {
  274.          // Else if the height equals the optimal height we send in full color.
  275.    return 1.0f;
  276.       }
  277. else if(height > m_tiles.regions[tileType].optimalHeight)
  278.    {
  279.    // Else if the height is greater than the optimal height.
  280.          // Get the distance between the max height from the optimal height.
  281.    distance1 = (float)(m_tiles.regions[tileType].highHeight -
  282.                          m_tiles.regions[tileType].optimalHeight);
  283.          // Return the distance - the test height -
  284.          // optimal height / by the distance to get %.
  285.    return((distance1 - (height -
  286.           m_tiles.regions[tileType].optimalHeight)) / distance1);
  287.    }
  288.    // Return 0 if we get here.
  289. return 0.0f;
  290. }
  291. void CTerrain::GetTexCoords(unsigned int texWidth, unsigned int texHeight,
  292.                             unsigned int x, unsigned int z, float &tu, float &tv)
  293. {
  294.    // These two will store the amount of times the texture
  295.    // repeats across the terrain along the x and z.
  296. int totalWidthRepeats = -1;
  297. int totalHeightRepeats = -1;
  298.    // Temp number to hold temp values.
  299.    int i = 0;
  300. // Calculate the amount of times this image would repeat across the x.
  301. while(totalWidthRepeats == -1)
  302.    {
  303.    i++;
  304.    // We test if this point (x value) is less than the width times i.
  305.          // If x is 156 and the image width is 256 then it will not repeat.
  306.          // If x is 512 and the image width is 256 then the image will repeat
  307.          // at least 1 time.
  308.    if(x < (texWidth * i)) totalWidthRepeats = i - 1;
  309.    }
  310. // Reset.
  311. i = 0;
  312. // Calculate the amount of times this image would repeat across the z.
  313. while(totalHeightRepeats == -1)
  314.    {
  315.    i++;
  316.    // Same as with the x.
  317.    if(z < (texHeight * i)) totalHeightRepeats = i - 1;
  318.    }
  319. // Calculate the final texture coordinate.
  320. tu = (float)(x - (texWidth * totalWidthRepeats));
  321. tv = (float)(z - (texHeight * totalHeightRepeats));
  322. }
  323. float CTerrain::InterpolateDataHeight(int x, int z, float textureMapRatio)
  324. {
  325. float low = 0, high = 0;
  326. float interpolatedX = 0.0f, interpolatedZ = 0.0f;
  327. float interpolation = 0.0f;
  328.   float scaledX = x * textureMapRatio;
  329. float scaledZ = z * textureMapRatio;
  330. // Set low as the height of this point.
  331. low = GetDataHeight((int)scaledX, (int)scaledZ);
  332. // Set the high value.  If scaled x + 1 is greater than the entire size of the map then
  333.    // we send the low to return as default.  Else we grab the high x.
  334.    // This way we don't go out  of bounds in the array.
  335. if((scaledX + 1) > side)
  336. return low;
  337. else
  338. high = GetDataHeight((int)scaledX + 1, (int)scaledZ);
  339. // Set the interpolation to be the remainder of scaled x - itself.
  340. // This will give us a value between  0 and 0.99.  Then we interpolate
  341. // the high and low.
  342. interpolation = (scaledX - (int)scaledX);
  343. interpolatedX = ((high - low) * interpolation) + low;
  344. // Next we do the same thing for the z that we did for the x.
  345. if((scaledZ + 1 ) > side)
  346. return low;
  347. else
  348. high = GetDataHeight((int)scaledX, (int)scaledZ + 1);
  349. // Calculate the interpolation for z.
  350. interpolation = (scaledZ - (int)scaledZ);
  351. interpolatedZ = ((high - low) * interpolation) + low;
  352. // Average out the interpolation for the x and z.
  353. return (interpolatedX + interpolatedZ) / 2;
  354. }
  355. float CTerrain::InterpolateHeight(int x, int z, float textureMapRatio)
  356. {
  357. float low = 0, high = 0;
  358. float interpolatedX = 0.0f, interpolatedZ = 0.0f;
  359. float interpolation = 0.0f;
  360.   float scaledX = x * textureMapRatio;
  361. float scaledZ = z * textureMapRatio;
  362. // Set low as the height of this point.
  363. low = GetHeight((int)scaledX, (int)scaledZ);
  364. // Set the high value.  If scaled x + 1 is greater than the entire size of the map then
  365.    // we send the low to return as default.  Else we grab the high x.
  366.    // This way we don't go out  of bounds in the array.
  367. if((scaledX + 1) > side)
  368. return low;
  369. else
  370. high = GetHeight((int)scaledX + 1, (int)scaledZ);
  371. // Set the interpolation to be the remainder of scaled x - itself.
  372. // This will give us a value between  0 and 0.99.  Then we interpolate
  373. // the high and low.
  374. interpolation = (scaledX - (int)scaledX);
  375. interpolatedX = ((high - low) * interpolation) + low;
  376. // Next we do the same thing for the z that we did for the x.
  377. if((scaledZ + 1 ) > side)
  378. return low;
  379. else
  380. high = GetHeight((int)scaledX, (int)scaledZ + 1);
  381. // Calculate the interpolation for z.
  382. interpolation = (scaledZ - (int)scaledZ);
  383. interpolatedZ = ((high - low) * interpolation) + low;
  384. // Average out the interpolation for the x and z.
  385. return (interpolatedX + interpolatedZ) / 2;
  386. }
  387. unsigned char *CTerrain::GenerateTextureMap(unsigned int imageSize)
  388. {
  389.    // Red, green, and blue color values.  OpenGL texture id.
  390. unsigned char red = 0, green = 0, blue = 0;
  391.    // Set of texture coords and last height which is used in combining the images.
  392. float tu, tv;
  393.   int lastHeight = 1;
  394.    // Each of these hold the total color values of each used in the final image.
  395. float totalRed = 0, totalGreen = 0, totalBlue = 0;
  396.    // Blend amounts for each texture tile and the ratio between the terrain size and image size.
  397.    float blendList[4] = {0};
  398. float textureMapRatio = (float)side / (float)imageSize;
  399. // Reset the number of m_tiles.
  400. m_tiles.numTiles = 0;
  401.    // First we loop through the max amount of m_tiles we can have and see how many actually
  402.    // have images.  This way the user does not have to have a set number of images before
  403.    // we can generate a texture.  Need just at least 1 to see anything.
  404. for(int i = 0; i < 4; i++)
  405.    {
  406.    if(m_tiles.texTiles[i].image) m_tiles.numTiles++;
  407.    }
  408.    if(m_tiles.numTiles == 0) return NULL;
  409. // Loop through again to calculate the tile regions.
  410. for(int i = 0; i < 4; i++)
  411.    {
  412.    // If the image was loaded, perform calculations.
  413.    if(m_tiles.texTiles[i].image)
  414.       {
  415.       // Here we calculate the low, optimal, and high height for this region.
  416.       m_tiles.regions[i].lowHeight = lastHeight + 1;
  417.        
  418.                lastHeight += (int)(GetMaxHeight() / m_tiles.numTiles);
  419.       m_tiles.regions[i].optimalHeight = lastHeight;
  420.       m_tiles.regions[i].highHeight = (lastHeight -
  421.          m_tiles.regions[i].lowHeight) + lastHeight;
  422.       }
  423.    }
  424. // Create the texture array.
  425. unsigned char *image = new unsigned char[imageSize * imageSize * 3];
  426. // And the last part in the generation is to create the 2D image.
  427. for(unsigned int z = 0; z < imageSize; z++)
  428.    {
  429.    for(unsigned int x = 0; x < imageSize; x++)
  430.       {
  431.       // Intialize the color variables.
  432.       totalRed = 0.0f;
  433.       totalGreen = 0.0f;
  434.       totalBlue = 0.0f;
  435.       // Loop through all tiles and generate each final pixel color.
  436.       for(int i = 0; i < m_tiles.numTiles; i++)
  437.          {
  438.       // Calculate the texture coords.  This is used to
  439.       // get a pixel from  each tile.
  440.       GetTexCoords(m_tiles.texTiles[i].width,
  441.                                  m_tiles.texTiles[i].height, x, z,
  442.                                  tu, tv);
  443.       // Get the color of the pixel for the set of texture coords.
  444.       int index = (((unsigned int)tv * imageSize) + (unsigned int)tu) * 3;
  445.       red = m_tiles.texTiles[i].image[index + 0];
  446.       green = m_tiles.texTiles[i].image[index + 1];
  447.       blue = m_tiles.texTiles[i].image[index + 2];
  448.       // Calculate the amount to blend this pixel with the rest.
  449.       
  450.       blendList[i] = RegionPercent(i, InterpolateDataHeight(x, z, textureMapRatio));
  451.       // Store the pixel from this tile to the total.
  452.       totalRed += red * blendList[i];
  453.       totalGreen += green * blendList[i];
  454.       totalBlue += blue * blendList[i];
  455.          }
  456.       // Set a pixel in our final texture image.
  457.       image[((z * imageSize) + x) * 3] = (unsigned char)totalRed;
  458.                image[((z * imageSize) + x) * 3 + 1] = (unsigned char)totalGreen;
  459.                image[((z * imageSize) + x) * 3 + 2] = (unsigned char)totalBlue;
  460.       }
  461.    }
  462.    return image;
  463. }
  464. void CTerrain::ShutDown()
  465. {
  466.    // Release all resources used by the terrain.
  467. fScale = 0.0f;
  468. delete[] m_tiles.texTiles[0].image;
  469. delete[] m_tiles.texTiles[1].image;
  470. delete[] m_tiles.texTiles[2].image;
  471. delete[] m_tiles.texTiles[3].image;
  472.    
  473.    if(pVertex)
  474.       {
  475.          delete[] pVertex;
  476.          pVertex = NULL;
  477.       }
  478.    if(pTexCoords)
  479.       {
  480.          delete[] pTexCoords;
  481.          pTexCoords = NULL;
  482.       }
  483.    if(pTexCoords2)
  484.       {
  485.          delete[] pTexCoords2;
  486.          pTexCoords2 = NULL;
  487.       }
  488.    if(hMap)
  489.       {
  490.          delete[] hMap;
  491.          side = 0;
  492.       }
  493. }
  494. float CTerrain::GetMaxHeight()
  495. {
  496. float max = 0;
  497. for (int x=0 ; x < side ; x++)
  498. {
  499. for (int z=0 ; z < side ; z++)
  500. {
  501. if (max < GetHeight(x, z)) max = GetHeight(x, z);
  502. }
  503. }
  504. return max;
  505. }
  506. float CTerrain::GetMinHeight()
  507. {
  508. float min = 0;
  509. for (int x=0 ; x < side ; x++)
  510. {
  511. for (int z=0 ; z < side ; z++)
  512. {
  513. if (min > GetHeight(x, z)) min = GetHeight(x, z);
  514. }
  515. }
  516. return min;
  517. }
  518. float *CTerrain::GetTriangle(float x, float z)
  519. {
  520. int tri_index = (int)z * (side_)*2 + (int)x * 2;
  521. if (mod(x)+mod(z) > 1) tri_index++;
  522. return &pVertex[tri_index*9];
  523. }
  524. float CTerrain::GetHeight(int x, int z)
  525. {
  526. bool xmax, zmax;
  527. xmax = (x == side_);
  528. zmax = (z == side_);
  529. if (xmax && zmax)
  530. return GetVertex(x-1, z-1, 4);
  531. if (xmax)
  532. return GetVertex(x-1, z, 3);
  533. if (zmax)
  534. return GetVertex(x, z-1, 5);
  535. return GetVertex(x, z, 0); // default index is zero
  536. }
  537. void CTerrain::AddToHeight(int x, int z, float add)
  538. {
  539. float set = GetHeight(x, z);
  540. SetHeight(x, z, set+add);
  541. }
  542. void CTerrain::SetHeight(int x, int z, float set)
  543. { /* |34|  x
  544.      |25|  |
  545.      |01|  +->z */
  546. SetVertex(x,   z,   0, set);
  547. SetVertex(x-1, z,   2, set);
  548. SetVertex(x-1, z,   3, set);
  549. SetVertex(x,   z-1, 1, set);
  550. SetVertex(x,   z-1, 5, set);
  551. SetVertex(x-1, z-1, 4, set);
  552. }
  553. int CTerrain::ConvertToI(int x, int z, int index)
  554. { /* |34|  x
  555.      |25|  |
  556.      |01|  +->z */
  557.   if (x < 0 || x > side-2) return 0;
  558.   if (z < 0 || z > side-2) return 0;
  559.   
  560. int i = z*(side_)*2 + x*2;  // set to triangle index
  561. i *= 9; // convert to index of first float in triangle
  562. i += index*3 + 1; // go to requested point and add one for y-coord
  563. if (i < 0 || i > (18*(side_)*(side_)))
  564. return 0; // if it is negative, or greater than MAX
  565. return i;
  566. }
  567. void CTerrain::SetVertex(int x, int z, int index, float set)
  568. {
  569. int i = ConvertToI(x, z, index);
  570. if (i == 0) return;
  571. pVertex[i] = set;
  572. }
  573. float CTerrain::GetVertex(int x, int z, int index)
  574. {
  575. int i = ConvertToI(x, z, index);
  576. if (i == 0) return 0; // so zero should never be used on terrain
  577. return pVertex[i];
  578. }
  579. void CTerrain::AddToVertex(int x, int z, int index, float add)
  580. {
  581. SetVertex(x, z, index, GetVertex(x, z, index)+add);
  582. }
  583. void CTerrain::CreatePlaneFromTri(float tri[9], float *plane)
  584. {
  585. CVector tri1(tri[0], tri[1], tri[2]);
  586. CVector tri2(tri[3], tri[4], tri[5]);
  587. CVector tri3(tri[6], tri[7], tri[8]);
  588. CVector normal;
  589. normal.CrossProduct(tri3 - tri1, tri2 - tri1);
  590. normal.Normal();
  591. float a, b, c, d;
  592. a = normal.x;   b = normal.y;   c = normal.z;
  593. d = - (a * tri1.x + b * tri1.y + c * tri1.z);
  594. plane[0] = a;
  595. plane[1] = b;
  596. plane[2] = c;
  597. plane[3] = d;
  598. }
  599. float CTerrain::GetRealHeight(float x, float z)
  600. {
  601. if (x < 0 || z < 0 || x >= side_ || z >= side_) return 0;
  602. float *triangle = GetTriangle(x, z);
  603. float plane[4]; // a b c d
  604. CreatePlaneFromTri(triangle, plane);
  605. float y = plane[0]*x + plane[2]*z + plane[3];
  606. if (plane[1] == 0)
  607. err("WTF???", "division by zero, plane D equals zero");
  608. else
  609. y /= -plane[1];
  610. return y;
  611. }
  612. ////////////////////////////////////////////////////////////////////////////////
  613. ////////////////////////////////////////////////////////////////////////////////
  614. ////////////////////////////////////////////////////////////////////////////////
  615. ////////////////////////////////////////////////////////////////////////////////
  616. ////////////////////////////////////////////////////////////////////////////////
  617. ////////////////////////////////////////////////////////////////////////////////
  618. ////////////////////////////////////////////////////////////////////////////////
  619. ////////////////////////////////////////////////////////////////////////////////
  620. ////////////////////////////////////////////////////////////////////////////////
  621. ////////////////////////////////////////////////////////////////////////////////
  622. ////////////////////////////////////////////////////////////////////////////////
  623. ////////////////////////////////////////////////////////////////////////////////
  624. ////////////////////////////////////////////////////////////////////////////////
  625. ////////////////////////////////////////////////////////////////////////////////
  626. ////////////////////////////////////////////////////////////////////////////////
  627. ////////////////////////////////////////////////////////////////////////////////
  628. CTerrainData::CTerrainData()
  629. {
  630. iTexID = 0;
  631. glActiveTextureARB = NULL;
  632. glClientActiveTextureARB = NULL;
  633. mode = GL_TRIANGLES;
  634. }
  635. bool CTerrainData::InitExtensions()
  636. {
  637. char *extension = (char*)glGetString(GL_EXTENSIONS);
  638. if(strstr(extension, "GL_ARB_multitexture") == 0) return false;
  639. glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
  640. glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)wglGetProcAddress("glClientActiveTextureARB");
  641. if(!glActiveTextureARB || !glClientActiveTextureARB) return false;
  642. return true;
  643. }
  644. bool CTerrainData::LoadDetailTexture(char *detail_tex)
  645. {
  646. if(!LoadTGA(&terrDetailTex, detail_tex)) return false;
  647. return true;
  648. }
  649. bool CTerrainData::InitTextures()
  650. {
  651. unsigned char *img;
  652. // converts from verts (our editted stuff) into float heightmap
  653. terr->ConvertMesh();
  654. img = terr->GenerateTextureMap(256);
  655. glGenTextures(1, &iTexID);
  656. glBindTexture(GL_TEXTURE_2D, iTexID);
  657. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  658. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  659. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
  660. glGenTextures(1, &terrDetailTex.texID);
  661. glBindTexture(GL_TEXTURE_2D, terrDetailTex.texID);
  662. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  663. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  664. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, terrDetailTex.width,
  665.  terrDetailTex.height, 0, GL_RGB, GL_UNSIGNED_BYTE, terrDetailTex.image);
  666. delete[] img;
  667. return true;
  668. }
  669. void CTerrainData::SetMode(int m)
  670. {
  671. mode = m;
  672. }
  673. void CTerrainData::RenderAll()
  674. {
  675. // Apply the textures.
  676. glActiveTextureARB(GL_TEXTURE0_ARB);
  677. glEnable(GL_TEXTURE_2D);
  678. glBindTexture(GL_TEXTURE_2D, iTexID);
  679. glActiveTextureARB(GL_TEXTURE1_ARB);
  680. glEnable(GL_TEXTURE_2D);
  681. glBindTexture(GL_TEXTURE_2D, terrDetailTex.texID);
  682. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
  683. glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2);
  684. glActiveTextureARB(GL_TEXTURE0_ARB);
  685. // Set pointers.
  686. glEnableClientState(GL_VERTEX_ARRAY);
  687. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  688. glVertexPointer(3, GL_FLOAT, 0, terr->pVertex);
  689. glTexCoordPointer(2, GL_FLOAT, 0, terr->pTexCoords);
  690. glClientActiveTextureARB(GL_TEXTURE1_ARB);
  691. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  692. glTexCoordPointer(2, GL_FLOAT, 0, terr->pTexCoords2);
  693. glClientActiveTextureARB(GL_TEXTURE0_ARB);
  694. glDrawArrays(mode, 0,  terr->iVerts);
  695. // Disable all the client states we enabled.
  696. glDisableClientState(GL_VERTEX_ARRAY);
  697. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  698. glClientActiveTextureARB(GL_TEXTURE1_ARB);
  699. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  700. glClientActiveTextureARB(GL_TEXTURE0_ARB);
  701. }
  702. void CTerrainData::Destroy()
  703. {
  704. terr->ShutDown();
  705. delete[] terrDetailTex.image;
  706. glDeleteTextures(1, &iTexID);
  707. }
  708. bool CTerrainData::Init(CTerrain *tt)
  709. {
  710. terr = tt; // set terrain pointer
  711. if (!InitExtensions()) return false;
  712. return true;
  713. }
  714. bool CTerrainData::Generate(char *map, int detail, char *t0, char *t1, char *t2, char *t3, char *detail_tex)
  715. {
  716. if (terr == NULL) err("null");
  717. terr->LoadMap(map, detail);
  718. terr->LoadTile(0, t0);
  719. terr->LoadTile(1, t1);
  720. terr->LoadTile(2, t2);
  721. terr->LoadTile(3, t3);
  722. if (!LoadDetailTexture(detail_tex)) return false;
  723. if (!InitTextures()) return false;
  724. return true;
  725. }
  726. bool CTerrain::LoadTile(int tileType, char *filename)
  727. {
  728. return LoadTGA(&m_tiles.texTiles[tileType], filename);
  729. }
  730. ////////////////////////////////////////////////////////////////////////////////
  731. ////////////////////////////////////////////////////////////////////////////////
  732. ////////////////////////////////////////////////////////////////////////////////
  733. ////////////////////////////////////////////////////////////////////////////////
  734. /*******************************************************************************
  735. * CTerrainEdit
  736. *******************************************************************************/
  737. ////////////////////////////////////////////////////////////////////////////////
  738. ////////////////////////////////////////////////////////////////////////////////
  739. void CTerrainEdit::Zero()
  740. {
  741. for (int x=0 ; x < t->side ; x++)
  742. {
  743. for (int z=0 ; z < t->side ; z++)
  744. {
  745. t->SetHeight(x, z, 0);
  746. }
  747. }
  748. }
  749. void CTerrainEdit::Normalize(float scale)
  750. {
  751. float max = t->GetMaxHeight();
  752. float min = t->GetMinHeight();
  753. float range = max-min;
  754. if (range == 0) range = 0.001;
  755. float mm;
  756. for (int x=0 ; x < t->side ; x++)
  757. {
  758. for (int z=0 ; z < t->side ; z++)
  759. {
  760. mm = t->GetHeight(x, z);
  761. t->SetHeight(x, z, scale * mm / range);
  762. }
  763. }
  764. }
  765. void CTerrainEdit::Increase(float power)
  766. {
  767. float mm;
  768. for (int x=0 ; x < t->side ; x++)
  769. {
  770. for (int z=0 ; z < t->side ; z++)
  771. {
  772. mm = t->GetHeight(x, z);
  773. t->SetHeight(x, z, mm+power);
  774. }
  775. }
  776. }
  777. void CTerrainEdit::Flatten(float power)
  778. {
  779. float mm;
  780. for (int x=0 ; x < t->side ; x++)
  781. {
  782. for (int z=0 ; z < t->side ; z++)
  783. {
  784. mm = t->GetHeight(x, z);
  785. t->SetHeight(x, z, pow(mm, power));
  786. }
  787. }
  788. }
  789. void CTerrainEdit::Multiply(float m)
  790. {
  791. float mm;
  792. for (int x=0 ; x < t->side ; x++)
  793. {
  794. for (int z=0 ; z < t->side ; z++)
  795. {
  796. mm = t->GetHeight(x, z);
  797. t->SetHeight(x, z, mm*m);
  798. }
  799. }
  800. }
  801. void CTerrainEdit::DoHill(int x, int z, int radius, float power)
  802. {
  803. for (int xr=-radius ; xr <= radius ; xr++)
  804. {
  805. for (int zr=-radius ; zr <= radius ; zr++)
  806. {
  807. float change = radius - sqrt(xr*xr + zr*zr);
  808. if (change < 0) change = 0;
  809. change *= power;
  810. t->AddToHeight(x+xr, z+zr, change);
  811. }
  812. }
  813. }
  814. void CTerrainEdit::CreateHill(int x, int y, int radius, int iters, float power)
  815. {
  816. for (int j=0 ; j < iters ; j++)
  817. {
  818. DoHill(x, y, radius, power);
  819. }
  820. }
  821. void CTerrainEdit::GenerateIsland(int width_x, int width_z, int x_pos, int y_pos, int iters, int max_radius, int max_iters)
  822. {
  823. for (int i=0 ; i < iters ; i++)
  824. {
  825. int height = rand() % max_iters;
  826. int radius = rand() % max_radius;
  827. int x = rand() % width_x + x_pos - width_x/2;
  828. int y = rand() % width_z + y_pos - width_z/2;
  829. CreateHill(x, y, radius, height);
  830. }
  831. }
  832. void CTerrainEdit::GenerateTerrain(int iters, int max_radius, int max_iters)
  833. {
  834. for (int i=0 ; i < iters ; i++)
  835. {
  836. int height = rand() % max_iters;
  837. int radius = rand() % max_radius;
  838. int x = (rand()%(t->side*2))-t->side;
  839. int y = (rand()%(t->side*2))-t->side;
  840. CreateHill(x, y, radius, iters, 0.1);
  841. }
  842. }