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

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