3dObjectTerrain.cpp
上传用户:shxiangxiu
上传日期:2007-01-03
资源大小:1101k
文件大小:49k
源码类别:

OpenGL

开发平台:

Visual C++

  1. /////////////////////////////////////////////////////////////////////////////
  2. // 3dObjectTerrain.cpp : implementation file
  3. //
  4. // glOOP (OpenGL Object Oriented Programming library)
  5. // Copyright (c) Craig Fahrnbach, ImageWare Development, 1997-1999
  6. // All rights reserved.
  7. //
  8. // OpenGL is a registered trademark of Silicon Graphics
  9. //
  10. //
  11. // This program is provided for educational and personal use only and
  12. // is provided without guarantee or warrantee expressed or implied.
  13. //
  14. // Commercial use is strickly prohibited without written permission
  15. // from ImageWare Development.
  16. //
  17. // This program is -not- in the public domain.
  18. //
  19. // Adapted from source code, with permission, by: Paul E. Martz
  20. /////////////////////////////////////////////////////////////////////////////
  21. #include "stdafx.h"
  22. #include "glOOP.h"
  23. #include "3dObjectDialog.h"
  24. #include <math.h>
  25. #ifdef _DEBUG
  26. #define new DEBUG_NEW
  27. #undef THIS_FILE
  28. static char THIS_FILE[] = __FILE__;
  29. #endif
  30. //////////////////////////////////////////////////////////////////
  31. // C3dObjectTerrain
  32. IMPLEMENT_DYNAMIC(C3dObjectTerrain, C3dObject)
  33. /////////////////////////////////////////////////////////////////////////////
  34. // C3dShape construction
  35. C3dObjectTerrain::C3dObjectTerrain()
  36. {
  37. // Set the attributes to default values..
  38.   m_iType = SHAPE_OBJECT;
  39.    m_szName.Format("Terrain %u", nTerrainObjects++);
  40. m_bSolidColor = FALSE;
  41. m_bSmoothNormals = TRUE;
  42. m_bReflect = FALSE;
  43. m_bMapTexturesToSubGrid = FALSE;
  44. m_bApplySubGridTextures = FALSE;
  45. m_pTextureSnow  = NULL;
  46. m_pTextureRock  = NULL;
  47. m_pTextureGrass = NULL;
  48. m_pTextureWater = NULL;
  49. m_iSize = 32;
  50. m_iTile = 1;
  51. m_fDepth = 50.0f;
  52. m_fWidth = 50.0f;
  53. m_fHeight =  1.1f;
  54. m_iHeightSeed = 0;
  55. m_fSeaLevel = 0.3f;
  56. m_iTerrainGridDisplayList = 0;
  57. m_iTexImageMap = 0;
  58. m_ColorSnow.SetColor4f(.95f, .95f, 1.f, 0.f); // White
  59. m_ColorRock.SetColor4f(.55f, .55f, .6f, 0.f); // Gray
  60. m_ColorGrass.SetColor4f(.2f, .4f, .2f, 0.f); // Green
  61. m_ColorWater.SetColor4f(.0f, .25f, .85f, 0.f); // Blue
  62. // Create our C3dPointArray object
  63. m_pPointArray = new C3dPointArray;
  64. ASSERT(m_pPointArray);
  65. // Create an array of points for our vertices
  66. if(m_pPointArray->Create((m_iSize+1)*(m_iSize+1)))
  67. {
  68. AfxMessageBox("Not enough memory to create array points!", MB_OK);
  69. m_pPointArray = NULL;
  70. return;
  71. }
  72. // Initialize our terrain vertices (points)
  73. InitTerrain();
  74. }
  75. /////////////////////////////////////////////////////////////////////////////
  76. // C3DWorld Destructor
  77. C3dObjectTerrain::~C3dObjectTerrain()
  78. {
  79. // Delete our point array
  80. if(m_pPointArray)
  81. delete m_pPointArray;
  82. // Delete our texture maps
  83. if(m_pTextureSnow)
  84. DeleteSubTexture(m_pTextureSnow);
  85. if(m_pTextureRock)
  86. DeleteSubTexture(m_pTextureRock);
  87. if(m_pTextureGrass)
  88. DeleteSubTexture(m_pTextureGrass);
  89. if(m_pTextureWater)
  90. DeleteSubTexture(m_pTextureWater);
  91. // Delete the Terrain Grid DisplayList
  92. if(m_iTerrainGridDisplayList)
  93. {
  94. glDeleteLists(m_iTerrainGridDisplayList, 1);
  95. m_iTerrainGridDisplayList = 0;
  96. }
  97. // Delete the Terrain Image Texturemap
  98. if(m_iTexImageMap)
  99. {
  100. glDeleteLists(m_iTexImageMap, 1);
  101. m_iTexImageMap = 0;
  102. }
  103. }
  104. /////////////////////////////////////////////////////////////////////////////
  105. // C3dObjectTerrain Methods or virtual function implimentation
  106. void C3dObjectTerrain::AddAttributePage(C3dWorld* pWorld, LPVOID pSht)
  107. {
  108. C3dObjectPropSheet* pSheet = (C3dObjectPropSheet*)pSht;
  109. ASSERT(pSheet);
  110. // Add the page to the property sheet
  111. pSheet->AddPage(&pSheet->m_TerrainPage);
  112. // Save the address of this object in the page
  113. pSheet->m_TerrainPage.m_pObject = this;
  114. // Add the page to the property sheet
  115. pSheet->AddPage(&pSheet->m_TerrainColorPage);
  116. // Save the address of this object in the page
  117. pSheet->m_TerrainColorPage.m_pObject = this;
  118. pSheet->m_TerrainColorPage.m_pWorld = pWorld;
  119. // Add the page to the property sheet
  120. pSheet->AddPage(&pSheet->m_TerrainTexturePage);
  121. // Save the address of this object in the page
  122. pSheet->m_TerrainTexturePage.m_pObject = this;
  123. }
  124. int C3dObjectTerrain::LoadBitMapImage(CImageList* pList)
  125. {
  126. CBitmap bitmap;
  127. // If the image index has been stored in this object,
  128. // return the index.
  129. if(m_iBMImage > -1)
  130. return m_iBMImage;
  131. // If the image index for this object type has been
  132. // created, store the index for this object and
  133. // return the index.
  134. if( iObjectTerrainBMImage > -1) {
  135. m_iBMImage = iObjectTerrainBMImage;
  136. return m_iBMImage;
  137. }
  138. // The image index for this object type has not been
  139. // loaded and the object image index has not been
  140. // stored.
  141. //
  142. // Load the bitmap for the non-selected object
  143. bitmap.LoadBitmap(IDB_OBJECT_TERRAIN);
  144. m_iBMImage = pList->Add(&bitmap, (COLORREF)0xFFFFFF);
  145. bitmap.DeleteObject();
  146. // Load the bitmap for the non-selected object
  147. bitmap.LoadBitmap(IDB_OBJECT_TERRAIN_SELECTED);
  148. pList->Add(&bitmap, (COLORREF)0xFFFFFF);
  149. bitmap.DeleteObject();
  150. iObjectTerrainBMImage = m_iBMImage;
  151. return m_iBMImage;
  152. }
  153. void C3dObjectTerrain::GetShapeBounds(C3dBoundingBox* pBox)
  154. {
  155. if(m_pPointArray)
  156. m_pPointArray->GetMinMax(pBox);
  157. // We need to calculate the overall size of the object based
  158. // on the number of times we have tiled the basic shape
  159. pBox->m_fMax[X] *= m_iTile;
  160. pBox->m_fMax[Y] *= m_iTile;
  161. pBox->m_fMin[X] *= m_iTile;
  162. pBox->m_fMin[Y] *= m_iTile;
  163. }
  164. void C3dObjectTerrain::Serialize(CArchive& ar, int iVersion)
  165. {
  166. CString szBuffer;
  167. if (ar.IsStoring())
  168. {
  169. // Save the Object Class header...
  170. szBuffer.Format("n%sC3dObjectTerrain {n", szIndent);
  171. ar.WriteString(szBuffer);
  172. // Save the this objects' specific data...
  173. szBuffer.Format("%stDepth         < %f >n", szIndent, m_fDepth);
  174. ar.WriteString(szBuffer);
  175. szBuffer.Format("%stWidth         < %f >n", szIndent, m_fWidth);
  176. ar.WriteString(szBuffer);
  177. szBuffer.Format("%stHeight        < %f >n", szIndent, m_fHeight);
  178. ar.WriteString(szBuffer);
  179. szBuffer.Format("%stHeight Seed   < %d >n", szIndent, m_iHeightSeed);
  180. ar.WriteString(szBuffer);
  181. szBuffer.Format("%stTile          < %d >n", szIndent, m_iTile);
  182. ar.WriteString(szBuffer);
  183. szBuffer.Format("%stReflectLight  < %d >n", szIndent, m_bReflect);
  184. ar.WriteString(szBuffer);
  185. szBuffer.Format("%stArraySize     < %d >n", szIndent, m_iSize);
  186. ar.WriteString(szBuffer);
  187. szBuffer.Format("%stSolid Color   < %d >n", szIndent, m_bSolidColor);
  188. ar.WriteString(szBuffer);
  189. szBuffer.Format("%stNum Points    < %d >n", szIndent, m_pPointArray->m_iNumPoints);
  190. ar.WriteString(szBuffer);
  191. for(int i=0; i<m_pPointArray->m_iNumPoints; i++)
  192. {
  193. szBuffer.Format("%stt        < %f, %f, %f >n", szIndent, m_pPointArray->m_pPoints[i].m_fOrigin[0],
  194. m_pPointArray->m_pPoints[i].m_fOrigin[1],
  195. m_pPointArray->m_pPoints[i].m_fOrigin[2]);
  196. ar.WriteString(szBuffer);
  197. }
  198. if(!m_bSolidColor)
  199. {
  200. szBuffer.Format("%st[color]n", szIndent);
  201. ar.WriteString(szBuffer);
  202. for(int i=0; i<m_pPointArray->m_iNumPoints; i++)
  203. {
  204. szBuffer.Format("%stt        < %f, %f, %f, %f >n", szIndent, m_pPointArray->m_pPoints[i].m_Color.m_fColor[0],
  205. m_pPointArray->m_pPoints[i].m_Color.m_fColor[1],
  206. m_pPointArray->m_pPoints[i].m_Color.m_fColor[2],
  207. m_pPointArray->m_pPoints[i].m_Color.m_fColor[3]);
  208. ar.WriteString(szBuffer);
  209. }
  210. }
  211. // Save the base class object data...
  212. C3dObject::Serialize(ar, iVersion);
  213. szBuffer.Format("%s}n", szIndent); // end of object def
  214. ar.WriteString(szBuffer);
  215. }
  216. else
  217. {
  218. ar.ReadString(szBuffer);
  219. szBuffer.TrimLeft(); // Remove leading white spaces
  220. sscanf(szBuffer, "Depth         < %f >n", &m_fDepth);
  221. ar.ReadString(szBuffer);
  222. szBuffer.TrimLeft();
  223. sscanf(szBuffer, "Width         < %f >n", &m_fWidth);
  224. ar.ReadString(szBuffer);
  225. szBuffer.TrimLeft();
  226. sscanf(szBuffer, "Height        < %f >n", &m_fHeight);
  227. ar.ReadString(szBuffer);
  228. szBuffer.TrimLeft();
  229. sscanf(szBuffer, "Height Seed   < %d >n", &m_iHeightSeed);
  230. ar.ReadString(szBuffer);
  231. szBuffer.TrimLeft();
  232. sscanf(szBuffer, "Tile          < %d >n", &m_iTile);
  233. ar.ReadString(szBuffer);
  234. szBuffer.TrimLeft();
  235. sscanf(szBuffer, "ReflectLight  < %d >n", &m_bReflect);
  236. ar.ReadString(szBuffer);
  237. szBuffer.TrimLeft();
  238. sscanf(szBuffer, "ArraySize     < %d >n", &m_iSize);
  239. ar.ReadString(szBuffer);
  240. szBuffer.TrimLeft();
  241. sscanf(szBuffer, "Solid Color   < %d >n", &m_bSolidColor);
  242. ar.ReadString(szBuffer);
  243. szBuffer.TrimLeft();
  244. sscanf(szBuffer, "Num Points    < %d >n", &m_pPointArray->m_iNumPoints);
  245. // Resize our control point array
  246. if(m_pPointArray->SetArraySize(m_pPointArray->m_iNumPoints))
  247. {
  248. AfxMessageBox("Not enough memory to create array points!", MB_OK);
  249. m_pPointArray = NULL;
  250. return;
  251. }
  252. // Read the shape vertice, or point data
  253. for(int i=0; i<m_pPointArray->m_iNumPoints; i++)
  254. {
  255. ar.ReadString(szBuffer);
  256. szBuffer.TrimLeft();
  257. sscanf(szBuffer, "< %f, %f, %f >n", &m_pPointArray->m_pPoints[i].m_fOrigin[X],
  258.  &m_pPointArray->m_pPoints[i].m_fOrigin[Y],
  259.  &m_pPointArray->m_pPoints[i].m_fOrigin[Z]);
  260. }
  261. if(!m_bSolidColor)
  262. {
  263. ar.ReadString(szBuffer); // [color] header
  264. // Read the shape vertice, or point data
  265. for(int i=0; i<m_pPointArray->m_iNumPoints; i++)
  266. {
  267. ar.ReadString(szBuffer);
  268. szBuffer.TrimLeft();
  269. sscanf(szBuffer, "< %f, %f, %f, %f >n", &m_pPointArray->m_pPoints[i].m_Color.m_fColor[0],
  270.  &m_pPointArray->m_pPoints[i].m_Color.m_fColor[1],
  271.  &m_pPointArray->m_pPoints[i].m_Color.m_fColor[2],
  272.  &m_pPointArray->m_pPoints[i].m_Color.m_fColor[3]);
  273. }
  274. // Initialize our terrain color height values
  275. InitColorHeightValues();
  276. }
  277. // Read the base class object data...
  278. C3dObject::Serialize(ar, iVersion);
  279. }
  280. }
  281. void C3dObjectTerrain::DisplayPoints(C3dWorld* pWorld, C3dCamera* pCamera)
  282. {
  283. static BOOL bDisplayMsg = TRUE;
  284. if(m_iTile>1 && bDisplayMsg)
  285. {
  286. AfxMessageBox("To edit the Terrain object points, the 'Tile' membern"
  287.   "variable must be set to one.", MB_OK);
  288. // Display the message only once per session
  289. bDisplayMsg = FALSE;
  290. return;
  291. }
  292. if(m_iTile==1)
  293. {
  294. // Display all points in our object
  295. if(m_pPointArray)
  296. {
  297. if(m_pPointArray->m_pPoints)
  298. m_pPointArray->Display(pWorld, pCamera, this, 5.0f, FALSE);
  299. }
  300. }
  301. }
  302. void C3dObjectTerrain::Build(C3dWorld* pWorld, C3dCamera* pCamera)
  303. {
  304. static int  iterations = 0;
  305. static BOOL textureLinear = FALSE;
  306. GLfloat x, y;
  307. int i, j;
  308. if(m_pPointArray == NULL)
  309. return;
  310. // This may take a while, so display an hour glass cursor
  311. CWaitCursor hourglass;
  312. // The following code is my initial attempt a multi-pass texturing.
  313. // The intention is to initially generate the image, with the objects
  314. // texture map, into our m_iTexImageMap texture map.  After the initial
  315. // texture is generated, we will then texture map this image onto the
  316. // terrain image with m_bReflect set appropriately.
  317. if(iterations && pWorld && pCamera)
  318. {
  319. // Render our initial Terrain and generate our m_iTexImageMap
  320. // Texture map, rendered using our C3dObject pTexture image 
  321. // if created.  (Set prior to calling this function.)
  322. RenderTextureImageMap(pWorld, pCamera);
  323. // Playing with sub texture maps
  324. // RenderTextureMaps();
  325. // Goes a little faster but looks like crud:
  326. //glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
  327. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, (GLfloat) GL_REPLACE);
  328. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  329. textureLinear ? (GLfloat) GL_LINEAR : (GLfloat) GL_NEAREST);
  330. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
  331. textureLinear ? (GLfloat) GL_LINEAR : (GLfloat) GL_NEAREST);
  332. // Enable Texture mapping, as it may be off at this time
  333. glEnable (GL_TEXTURE_2D);
  334. }
  335. // Build the final display list
  336. RenderTerrain(TRUE, m_bReflect);
  337. // Compile and build the list
  338. glNewList(m_iDisplayLists, GL_COMPILE_AND_EXECUTE);
  339. // Center our tiled image about the objects' origin
  340. glPushMatrix();
  341. glTranslatef((GLfloat)(m_fWidth * (GLfloat)(m_iTile-1))/2.0f,
  342.  (GLfloat)(m_fDepth * (GLfloat)(m_iTile-1))/2.0f,
  343.   0.0f);
  344. y = -m_fDepth * (GLfloat)(m_iTile-1);
  345. for (i=0; i<m_iTile; i++)
  346. {
  347. x = -m_fWidth * (GLfloat)(m_iTile-1);
  348. for (j=0; j<m_iTile; j++)
  349. {
  350. glPushMatrix();
  351. glTranslatef(x, y, 0.0f);
  352. if(m_iTerrainGridDisplayList)
  353. glCallList(m_iTerrainGridDisplayList);
  354. glPopMatrix ();
  355. x += m_fWidth;
  356. }
  357. y += m_fDepth;
  358. }
  359. glPopMatrix();
  360. glEndList();
  361. // Restore the cursor to its' default
  362. hourglass.Restore();
  363. }
  364. /////////////////////////////////////////////////////////////////////////////
  365. // C3dObjectTerrain Methods or Implementation
  366. void C3dObjectTerrain::CopyParameters(C3dObjectTerrain* pObj)
  367. {
  368. // Copy this objects parameters to the given terrain object.
  369. // This function is used by the CPageTerrainColor preview 
  370. // window.
  371. pObj->m_bApplySubGridTextures = m_bApplySubGridTextures;
  372. pObj->m_bMapTexturesToSubGrid = m_bMapTexturesToSubGrid;
  373. pObj->m_bReflect = m_bReflect;
  374. pObj->m_bSolidColor = m_bSolidColor;
  375. pObj->m_bSmoothNormals = m_bSmoothNormals;
  376. pObj->m_fSeaLevel = m_fSeaLevel;
  377. pObj->m_iHeightSeed = m_iHeightSeed;
  378. // Since this function is used by the preview window, we want
  379. // the image to fit 'mostly' within the window, so we will 
  380. // use our default settings.  We also want to conserve memory
  381. // so we will use the default array size setting.
  382. // pObj->m_fDepth = m_fDepth;
  383. // pObj->m_fWidth = m_fWidth;
  384. // pObj->m_fHeight = m_fHeight;
  385. // pObj->m_iSize = m_iSize;
  386. pObj->m_ColorSnow.SetColor4fv(&m_ColorSnow);
  387. pObj->m_ColorRock.SetColor4fv(&m_ColorRock);
  388. pObj->m_ColorGrass.SetColor4fv(&m_ColorGrass);
  389. pObj->m_ColorWater.SetColor4fv(&m_ColorWater);
  390. pObj->m_Color.SetColor4fv(&m_Color);
  391. }
  392. void C3dObjectTerrain::RenderTerrain(BOOL bCreateList, BOOL bReflect)
  393. {
  394. const int subSize = m_iSize;
  395.     int i, j;
  396. if(!m_iTerrainGridDisplayList)
  397. m_iTerrainGridDisplayList = glGenLists(1);// Create the DisplayList(s)
  398. if(bCreateList)
  399. {
  400. // Compile and build the list
  401. glNewList(m_iTerrainGridDisplayList, GL_COMPILE);
  402. // Call our TerrainTexImageMap as the Texture map
  403. glCallList (m_iTexImageMap);
  404. for (i=0; i<subSize; i++)
  405. {
  406. for (j=0; j<subSize; j++)
  407. {
  408. DisplayAsTriangleStrip(i, j, bReflect);
  409. // Multi-level texturing worked best displayed as triangles..
  410. // DisplayAsTriangles(i, j, bReflect);
  411. }
  412. }
  413. glEndList();
  414. }
  415. else
  416. {
  417. for (i=0; i<subSize; i++)
  418. {
  419. for (j=0; j<subSize; j++)
  420. DisplayAsTriangleStrip(i, j, bReflect);
  421. }
  422. }
  423. }
  424. void C3dObjectTerrain::DisplayAsTriangles(int i, int j, BOOL bReflect)
  425. {
  426. VECTORF p0, p1, p2, p3, normal[4];
  427. const int subSize = m_iSize, superSize = m_iSize+1;
  428. // Get the array points
  429. VecCopy3f (m_pPointArray->m_pPoints[    i*superSize+j].m_fOrigin, p0);
  430. VecCopy3f (m_pPointArray->m_pPoints[(i+1)*superSize+j].m_fOrigin, p1);
  431. VecCopy3f (m_pPointArray->m_pPoints[    i*superSize+j+1].m_fOrigin, p2);
  432. VecCopy3f (m_pPointArray->m_pPoints[(i+1)*superSize+j+1].m_fOrigin, p3);
  433. if(m_bSmoothNormals)
  434. {
  435. AvgNormals(  i,   j, m_pPointArray, &normal[0], TRUE);
  436. AvgNormals(i+1,   j, m_pPointArray, &normal[1], TRUE);
  437. AvgNormals(  i, j+1, m_pPointArray, &normal[2], TRUE);
  438. AvgNormals(i+1, j+1, m_pPointArray, &normal[3], TRUE);
  439. }
  440. else
  441. {
  442. CalNormalf(p2, p1, p0, normal[0]);
  443. CalNormalf(p1, p0, p2, normal[1]);
  444. CalNormalf(p0, p2, p1, normal[2]);
  445. CalNormalf(p3, p1, p2, normal[3]);
  446. }
  447. glBegin(GL_TRIANGLES);
  448. SetTextureList(p0, p1, p2);
  449. if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
  450. glTexCoord2f (0.f, 0.f);
  451. else
  452. SetTextureCoord(i, j);
  453. if(!m_bSolidColor)
  454. SetTerrainColor(i, j, bReflect);
  455. glNormal3fv(normal[0]);
  456. glVertex3fv(p0);
  457. if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
  458. glTexCoord2f (1.f, 0.f);
  459. else
  460. SetTextureCoord(i+1, j);
  461. if(!m_bSolidColor)
  462. SetTerrainColor(i+1, j, bReflect);
  463. glNormal3fv(normal[1]);
  464. glVertex3fv(p1);
  465. if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
  466. glTexCoord2f (0.f, 1.f);
  467. else
  468. SetTextureCoord(i, j+1);
  469. if(!m_bSolidColor)
  470. SetTerrainColor(i, j+1, bReflect);
  471. glNormal3fv(normal[2]);
  472. glVertex3fv(p2);
  473. glEnd();
  474. glBegin(GL_TRIANGLES);
  475. SetTextureList(p1, p2, p3);
  476. if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
  477. glTexCoord2f (1.f, 0.f);
  478. else
  479. SetTextureCoord(i+1, j);
  480. if(!m_bSolidColor)
  481. SetTerrainColor(i+1, j, bReflect);
  482. glNormal3fv(normal[1]);
  483. glVertex3fv(p1);
  484. if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
  485. glTexCoord2f (0.f, 1.f);
  486. else
  487. SetTextureCoord(i, j+1);
  488. if(!m_bSolidColor)
  489. SetTerrainColor(i, j+1, bReflect);
  490. glNormal3fv(normal[2]);
  491. glVertex3fv(p2);
  492. if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
  493. glTexCoord2f (1.f, 1.f);
  494. else
  495. SetTextureCoord(i+1, j+1);
  496. if(!m_bSolidColor)
  497. SetTerrainColor(i+1, j+1, bReflect);
  498. glNormal3fv(normal[3]);
  499. glVertex3fv(p3);
  500. glEnd ();
  501. }
  502. void C3dObjectTerrain::DisplayAsTriangleStrip(int i, int j, BOOL bReflect)
  503. {
  504. VECTORF p0, p1, p2, p3, normal[4];
  505. const int subSize = m_iSize, superSize = m_iSize+1;
  506. // Get the array points
  507. VecCopy3f (m_pPointArray->m_pPoints[    i*superSize+j].m_fOrigin, p0);
  508. VecCopy3f (m_pPointArray->m_pPoints[(i+1)*superSize+j].m_fOrigin, p1);
  509. VecCopy3f (m_pPointArray->m_pPoints[    i*superSize+j+1].m_fOrigin, p2);
  510. VecCopy3f (m_pPointArray->m_pPoints[(i+1)*superSize+j+1].m_fOrigin, p3);
  511. if(m_bSmoothNormals)
  512. {
  513. AvgNormals(  i,   j, m_pPointArray, &normal[0], TRUE);
  514. AvgNormals(i+1,   j, m_pPointArray, &normal[1], TRUE);
  515. AvgNormals(  i, j+1, m_pPointArray, &normal[2], TRUE);
  516. AvgNormals(i+1, j+1, m_pPointArray, &normal[3], TRUE);
  517. }
  518. else
  519. {
  520. CalNormalf(p2, p1, p0, normal[0]);
  521. CalNormalf(p1, p0, p2, normal[1]);
  522. CalNormalf(p0, p2, p1, normal[2]);
  523. CalNormalf(p3, p1, p2, normal[3]);
  524. }
  525. glBegin (GL_TRIANGLE_STRIP);
  526. // SetTextureList(p0, p1, p2);
  527. if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
  528. glTexCoord2f(0.f, 0.f);
  529. else
  530. SetTextureCoord(i, j);
  531. if(!m_bSolidColor)
  532. SetTerrainColor(i, j, bReflect);
  533. glNormal3fv(normal[0]);
  534. glVertex3fv(p0);
  535. if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
  536. glTexCoord2f(1.f, 0.f);
  537. else
  538. SetTextureCoord(i+1, j);
  539. if(!m_bSolidColor)
  540. SetTerrainColor(i+1, j, bReflect);
  541. glNormal3fv(normal[1]);
  542. glVertex3fv(p1);
  543. if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
  544. glTexCoord2f(0.f, 1.f);
  545. else
  546. SetTextureCoord(i, j+1);
  547. if(!m_bSolidColor)
  548. SetTerrainColor(i, j+1, bReflect);
  549. glNormal3fv(normal[2]);
  550. glVertex3fv(p2);
  551. // SetTextureList(p1, p2, p3);
  552. if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
  553. glTexCoord2f(1.f, 1.f);
  554. else
  555. SetTextureCoord(i+1, j+1);
  556. if(!m_bSolidColor)
  557. SetTerrainColor(i+1, j+1, bReflect);
  558. glNormal3fv(normal[3]);
  559. glVertex3fv(p3);
  560. glEnd ();
  561. }
  562. void C3dObjectTerrain::RenderTextureMaps()
  563. {
  564. // Render our multi-level texture maps
  565. if(m_pTextureSnow)
  566. // Apply the Dib Image to our shape..
  567. m_pTextureSnow->SetTexture();
  568. if(m_pTextureRock)
  569. // Apply the Dib Image to our shape..
  570. m_pTextureRock->SetTexture();
  571. if(m_pTextureGrass)
  572. // Apply the Dib Image to our shape..
  573. m_pTextureGrass->SetTexture();
  574. if(m_pTextureWater)
  575. // Apply the Dib Image to our shape..
  576. m_pTextureWater->SetTexture();
  577. }
  578. void C3dObjectTerrain::SetTextureCoord(int i, int j)
  579. {
  580. float steps = 1.0f/(float)(m_iSize+1);
  581. glTexCoord2f(i*steps, j*steps);
  582. }
  583. void C3dObjectTerrain::SetTextureList(VECTORF p1, VECTORF p2, VECTORF p3)
  584. {
  585. float aveHeight = (p1[Z]+p2[Z]+p3[Z])/3.0f;
  586. if(m_bMapTexturesToSubGrid)
  587. {
  588. if(aveHeight <= m_fWaterHeight)
  589. {
  590. if(m_pTextureWater)
  591. {
  592. m_pTextureWater->SetTexture();
  593. return;
  594. }
  595. }
  596. if(aveHeight <= m_fGrassHeight)
  597. {
  598. if(m_pTextureGrass)
  599. {
  600. m_pTextureGrass->SetTexture();
  601. return;
  602. }
  603. }
  604. if(aveHeight <= m_fRockHeight)
  605. {
  606. if(m_pTextureRock)
  607. {
  608. m_pTextureRock->SetTexture();
  609. return;
  610. }
  611. }
  612. if(aveHeight <= m_fSnowHeight)
  613. {
  614. if(m_pTextureSnow)
  615. {
  616. m_pTextureSnow->SetTexture();
  617. return;
  618. }
  619. }
  620. }
  621. // No Textures, so set our polygon mode to default
  622. // and disable texture maping.
  623. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  624. glDisable(GL_TEXTURE_2D);
  625. }
  626. void C3dObjectTerrain::InitTerrain()
  627. {
  628. float scale;
  629. // Calculate our scale based on its height & width
  630. scale = (m_fWidth+m_fHeight)/2;
  631. // Resize our control point array
  632. if(m_pPointArray->SetArraySize((m_iSize+1)*(m_iSize+1)))
  633. {
  634. AfxMessageBox("Not enough memory to create array points!", MB_OK);
  635. m_pPointArray = NULL;
  636. return; // function failed
  637. }
  638. FillFractualArray (m_pPointArray->m_pPoints, m_iSize, scale, m_fHeight);
  639. // Initialize our color components
  640. if(!m_bSolidColor)
  641. InitTerrainColor();
  642. }
  643. void C3dObjectTerrain::AvgNormals(int i, int j, C3dPointArray *fa, VECTORF* pNormal, BOOL bDiagonal)
  644. {
  645. VECTORF aveNormal, normals[6];
  646. VECTORF p1, p2, p3;
  647. int subSize = m_iSize+1;
  648. if(i==0 && j==0) // Bottom Left corner
  649. {
  650. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  651. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p2);
  652. VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p3);
  653. CalNormalf(p1, p3, p2, normals[0]);
  654. if(m_iTile > 1 && bDiagonal)
  655. {
  656. // Get the average normals for the other three corners
  657. AvgNormals(m_iSize, 0, fa, &normals[1], FALSE); // Bottom Right corner
  658. AvgNormals(m_iSize, m_iSize, fa, &normals[2], FALSE);// Top Right corner
  659. AvgNormals(0, m_iSize, fa, &normals[3], FALSE); // Top Left corner
  660. VecAddf(normals[0], normals[1], aveNormal);
  661. VecAddf(normals[2], aveNormal, aveNormal);
  662. VecAddf(normals[3], aveNormal, aveNormal);
  663. aveNormal[X] /= 4.0f;
  664. aveNormal[Y] /= 4.0f;
  665. aveNormal[Z] /= 4.0f;
  666. VecCopy3f(aveNormal, *pNormal);
  667. return;
  668. }
  669. VecCopy3f(normals[0], *pNormal);
  670. return;
  671. }
  672. if(i>=m_iSize && j==0) // Bottom Right Corner
  673. {
  674. // Average the two normals
  675. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  676. VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p2);
  677. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p3);
  678. CalNormalf(p1, p3, p2, normals[0]);
  679. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  680. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p2);
  681. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p3);
  682. CalNormalf(p1, p3, p2, normals[1]);
  683. VecAddf(normals[0], normals[1], aveNormal);
  684. aveNormal[X] /= 2.0f;
  685. aveNormal[Y] /= 2.0f;
  686. aveNormal[Z] /= 2.0f;
  687. if(m_iTile > 1 && bDiagonal)
  688. {
  689. // Get the average normals for the other three corners
  690. AvgNormals(m_iSize, m_iSize, fa, &normals[2], FALSE);// Top Right corner
  691. AvgNormals(0, m_iSize, fa, &normals[3], FALSE); // Top Left corner
  692. AvgNormals(0, 0, fa, &normals[4], FALSE); // Bottom Left corner
  693. VecAddf(normals[2], aveNormal, aveNormal);
  694. VecAddf(normals[3], aveNormal, aveNormal);
  695. VecAddf(normals[4], aveNormal, aveNormal);
  696. aveNormal[X] /= 4.0f;
  697. aveNormal[Y] /= 4.0f;
  698. aveNormal[Z] /= 4.0f;
  699. VecCopy3f(aveNormal, *pNormal);
  700. return;
  701. }
  702. VecCopy3f(aveNormal, *pNormal);
  703. return;
  704. }
  705. if(j>=m_iSize && i>=m_iSize) // Top Right Corner
  706. {
  707. // Only one normal
  708. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  709. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p2);
  710. VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p3);
  711. CalNormalf(p1, p3, p2, normals[0]);
  712. if(m_iTile > 1 && bDiagonal)
  713. {
  714. // Get the average normals for the other three corners
  715. AvgNormals(0, m_iSize, fa, &normals[1], FALSE); // Top Left corner
  716. AvgNormals(0, 0, fa, &normals[2], FALSE); // Bottom Left corner
  717. AvgNormals(m_iSize, 0, fa, &normals[3], FALSE); // Bottom Right corner
  718. VecAddf(normals[0], normals[1], aveNormal);
  719. VecAddf(normals[2], aveNormal, aveNormal);
  720. VecAddf(normals[3], aveNormal, aveNormal);
  721. aveNormal[X] /= 4.0f;
  722. aveNormal[Y] /= 4.0f;
  723. aveNormal[Z] /= 4.0f;
  724. VecCopy3f(aveNormal, *pNormal);
  725. return;
  726. }
  727. VecCopy3f(normals[0], *pNormal);
  728. return;
  729. }
  730. if(i==0 && j>=m_iSize) // Top Left Corner
  731. {
  732. // Average two normals
  733. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  734. VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p2);
  735. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p3);
  736. CalNormalf(p1, p3, p2, normals[0]);
  737. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  738. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p2);
  739. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p3);
  740. CalNormalf(p1, p3, p2, normals[1]);
  741. VecAddf(normals[0], normals[1], aveNormal);
  742. aveNormal[X] /= 2.0f;
  743. aveNormal[Y] /= 2.0f;
  744. aveNormal[Z] /= 2.0f;
  745. if(m_iTile > 1 && bDiagonal)
  746. {
  747. // Get the average normals for the other three corners
  748. AvgNormals(0, 0, fa, &normals[2], FALSE); // Bottom Left corner
  749. AvgNormals(m_iSize, 0, fa, &normals[3], FALSE); // Bottom Right corner
  750. AvgNormals(m_iSize, m_iSize, fa, &normals[4], FALSE);// Top Right corner
  751. VecAddf(normals[2], aveNormal, aveNormal);
  752. VecAddf(normals[3], aveNormal, aveNormal);
  753. VecAddf(normals[4], aveNormal, aveNormal);
  754. aveNormal[X] /= 4.0f;
  755. aveNormal[Y] /= 4.0f;
  756. aveNormal[Z] /= 4.0f;
  757. VecCopy3f(aveNormal, *pNormal);
  758. return;
  759. }
  760. VecCopy3f(aveNormal, *pNormal);
  761. return;
  762. }
  763. if(j==0 && i<m_iSize) // Bottom side
  764. {
  765. // Average the three bottom normals normals
  766. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  767. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p2);
  768. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p3);
  769. CalNormalf(p1, p3, p2, normals[0]);
  770. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  771. VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p2);
  772. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p3);
  773. CalNormalf(p1, p3, p2, normals[1]);
  774. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  775. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p2);
  776. VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p3);
  777. CalNormalf(p1, p3, p2, normals[2]);
  778. VecAddf(normals[0], normals[1], aveNormal);
  779. VecAddf(normals[2], aveNormal, aveNormal);
  780. aveNormal[X] /= 3.0f;
  781. aveNormal[Y] /= 3.0f;
  782. aveNormal[Z] /= 3.0f;
  783. if(m_iTile > 1 && bDiagonal)
  784. {
  785. // Get the average normal for the array point on the Top side
  786. AvgNormals(i, m_iSize, fa, &normals[3], FALSE);
  787. VecAddf(normals[3], aveNormal, aveNormal);
  788. aveNormal[X] /= 2.0f;
  789. aveNormal[Y] /= 2.0f;
  790. aveNormal[Z] /= 2.0f;
  791. VecCopy3f(aveNormal, *pNormal);
  792. return;
  793. }
  794. VecCopy3f(aveNormal, *pNormal);
  795. return;
  796. }
  797. if(i>=m_iSize && j<m_iSize) // Right Side
  798. {
  799. // Average the three side normals
  800. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  801. VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p2);
  802. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p3);
  803. CalNormalf(p1, p3, p2, normals[0]);
  804. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  805. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p2);
  806. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p3);
  807. CalNormalf(p1, p3, p2, normals[1]);
  808. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  809. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p2);
  810. VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p3);
  811. CalNormalf(p1, p3, p2, normals[2]);
  812. VecAddf(normals[0], normals[1], aveNormal);
  813. VecAddf(normals[2], aveNormal, aveNormal);
  814. aveNormal[X] /= 3.0f;
  815. aveNormal[Y] /= 3.0f;
  816. aveNormal[Z] /= 3.0f;
  817. if(m_iTile > 1 && bDiagonal)
  818. {
  819. // Get the average normal for the array point on the Left side
  820. AvgNormals(0, j, fa, &normals[3], FALSE);
  821. VecAddf(normals[3], aveNormal, aveNormal);
  822. aveNormal[X] /= 2.0f;
  823. aveNormal[Y] /= 2.0f;
  824. aveNormal[Z] /= 2.0f;
  825. VecCopy3f(aveNormal, *pNormal);
  826. return;
  827. }
  828. VecCopy3f(aveNormal, *pNormal);
  829. return;
  830. }
  831. if(j>=m_iSize && i<m_iSize) // Top side
  832. {
  833. // Average three normals
  834. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  835. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p2);
  836. VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p3);
  837. CalNormalf(p1, p3, p2, normals[0]);
  838. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  839. VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p2);
  840. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p3);
  841. CalNormalf(p1, p3, p2, normals[1]);
  842. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  843. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p2);
  844. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p3);
  845. CalNormalf(p1, p3, p2, normals[2]);
  846. VecAddf(normals[0], normals[1], aveNormal);
  847. VecAddf(normals[2], aveNormal, aveNormal);
  848. aveNormal[X] /= 3.0f;
  849. aveNormal[Y] /= 3.0f;
  850. aveNormal[Z] /= 3.0f;
  851. if(m_iTile > 1 && bDiagonal)
  852. {
  853. // Get the average normal for the array point on the Bottom side
  854. AvgNormals(i, 0, fa, &normals[3], FALSE);
  855. VecAddf(normals[3], aveNormal, aveNormal);
  856. aveNormal[X] /= 2.0f;
  857. aveNormal[Y] /= 2.0f;
  858. aveNormal[Z] /= 2.0f;
  859. VecCopy3f(aveNormal, *pNormal);
  860. return;
  861. }
  862. VecCopy3f(aveNormal, *pNormal);
  863. return;
  864. }
  865. if(i==0 && j<m_iSize) // Left Side
  866. {
  867. // Average the three normals on left side
  868. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  869. VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p2);
  870. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p3);
  871. CalNormalf(p1, p3, p2, normals[0]);
  872. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  873. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p2);
  874. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p3);
  875. CalNormalf(p1, p3, p2, normals[1]);
  876. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  877. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p2);
  878. VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p3);
  879. CalNormalf(p1, p3, p2, normals[2]);
  880. VecAddf(normals[0], normals[1], aveNormal);
  881. VecAddf(normals[2], aveNormal, aveNormal);
  882. aveNormal[X] /= 3.0f;
  883. aveNormal[Y] /= 3.0f;
  884. aveNormal[Z] /= 3.0f;
  885. if(m_iTile > 1 && bDiagonal)
  886. {
  887. // Get the average normal for the array point on the Right side
  888. AvgNormals(m_iSize, j, fa, &normals[3], FALSE);
  889. VecAddf(normals[3], aveNormal, aveNormal);
  890. aveNormal[X] /= 2.0f;
  891. aveNormal[Y] /= 2.0f;
  892. aveNormal[Z] /= 2.0f;
  893. VecCopy3f(aveNormal, *pNormal);
  894. return;
  895. }
  896. VecCopy3f(aveNormal, *pNormal);
  897. return;
  898. }
  899. // Point is not on sides of our terrain, so average all
  900. // six normals.
  901. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  902. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p2);
  903. VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p3);
  904. CalNormalf(p1, p3, p2, normals[0]);
  905. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  906. VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p2);
  907. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p3);
  908. CalNormalf(p1, p3, p2, normals[1]);
  909. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  910. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p2);
  911. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p3);
  912. CalNormalf(p1, p3, p2, normals[2]);
  913. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  914. VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p2);
  915. VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p3);
  916. CalNormalf(p1, p3, p2, normals[3]);
  917. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  918. VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p2);
  919. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p3);
  920. CalNormalf(p1, p3, p2, normals[4]);
  921. VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
  922. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p2);
  923. VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p3);
  924. CalNormalf(p1, p3, p2, normals[5]);
  925. VecAddf(normals[0], normals[1], aveNormal);
  926. VecAddf(normals[2], aveNormal, aveNormal);
  927. VecAddf(normals[3], aveNormal, aveNormal);
  928. VecAddf(normals[4], aveNormal, aveNormal);
  929. VecAddf(normals[5], aveNormal, aveNormal);
  930. aveNormal[X] /= 6.0f;
  931. aveNormal[Y] /= 6.0f;
  932. aveNormal[Z] /= 6.0f;
  933. VecCopy3f(aveNormal, *pNormal);
  934. }
  935. // randNum - Return a random floating point number such that
  936. // (min <= return-value <= max)
  937. // 32,767 values are possible for any given range.
  938. //
  939. float C3dObjectTerrain::RandNum (float min, float max)
  940. {
  941. int r;
  942. float x;
  943. r = rand ();
  944. x = (float)(r & 0x7fff) /
  945. (float)0x7fff;
  946. return (x * (max - min) + min);
  947. // fractRand is a useful interface to randnum.
  948. //
  949. #define FractRand(v) RandNum (-v, v)
  950. // powerOf2 - Returns 1 if size is a power of 2. Returns 0 if size is
  951. // not a power of 2, or is zero.
  952. //
  953. int C3dObjectTerrain::PowerOf2 (int size)
  954. {
  955. int i, bitcount = 0;
  956. // Note this code assumes that (sizeof(int)*8) will yield the
  957. // number of bits in an int. Should be portable to most
  958. // platforms.
  959. for (i=0; i<sizeof(int)*8; i++)
  960. if (size & (1<<i))
  961.     bitcount++;
  962. if (bitcount == 1)
  963. // One bit. Must be a power of 2.
  964. return (1);
  965.     else
  966. // either size==0, or size not a power of 2. Sorry, Charlie.
  967. return (0);
  968. }
  969. // AvgDiamondVals - Given the i,j location as the center of a diamond,
  970. // average the data values at the four corners of the diamond and
  971. // return it. "Stride" represents the distance from the diamond center
  972. // to a diamond corner.
  973. //
  974. float C3dObjectTerrain::AvgDiamondVals (int i, int j, int stride,
  975.      int size, int subSize, C3dPoint *fa)
  976. {
  977.     /* In this diagram, our input stride is 1, the i,j location is
  978.        indicated by "X", and the four value we want to average are
  979.        "*"s:
  980.            .   *   .
  981.            *   X   *
  982.            .   *   .
  983.        */
  984. // In order to support tiled surfaces which meet seamless at the
  985. // edges (that is, they "wrap"), We need to be careful how we
  986. // calculate averages when the i,j diamond center lies on an edge
  987. // of the array. The first four 'if' clauses handle these
  988. // cases. The final 'else' clause handles the general case (in
  989. // which i,j is not on an edge).
  990. if (i == 0)
  991. return ((float) (fa[(i*size) + j-stride].m_fOrigin[Z] +
  992.  fa[(i*size) + j+stride].m_fOrigin[Z] +
  993.  fa[((subSize-stride)*size) + j].m_fOrigin[Z] +
  994.  fa[((i+stride)*size) + j].m_fOrigin[Z]) * .25f);
  995. else if (i == size-1)
  996. return ((float) (fa[(i*size) + j-stride].m_fOrigin[Z] +
  997.  fa[(i*size) + j+stride].m_fOrigin[Z] +
  998.  fa[((i-stride)*size) + j].m_fOrigin[Z] +
  999.  fa[((0+stride)*size) + j].m_fOrigin[Z]) * .25f);
  1000. else if (j == 0)
  1001. return ((float) (fa[((i-stride)*size) + j].m_fOrigin[Z] +
  1002.  fa[((i+stride)*size) + j].m_fOrigin[Z] +
  1003.  fa[(i*size) + j+stride].m_fOrigin[Z] +
  1004.  fa[(i*size) + subSize-stride].m_fOrigin[Z]) * .25f);
  1005. else if (j == size-1)
  1006. return ((float) (fa[((i-stride)*size) + j].m_fOrigin[Z] +
  1007.  fa[((i+stride)*size) + j].m_fOrigin[Z] +
  1008.  fa[(i*size) + j-stride].m_fOrigin[Z] +
  1009.  fa[(i*size) + 0+stride].m_fOrigin[Z]) * .25f);
  1010. else
  1011. return ((float) (fa[((i-stride)*size) + j].m_fOrigin[Z] +
  1012.  fa[((i+stride)*size) + j].m_fOrigin[Z] +
  1013.  fa[(i*size) + j-stride].m_fOrigin[Z] +
  1014.  fa[(i*size) + j+stride].m_fOrigin[Z]) * .25f);
  1015. }
  1016. // AvgSquareVals - Given the i,j location as the center of a square,
  1017. // average the data values at the four corners of the square and return
  1018. // it. "Stride" represents half the length of one side of the square.
  1019. float C3dObjectTerrain::AvgSquareVals (int i, int j, int stride, int size, C3dPoint *fa)
  1020. {
  1021.     /* In this diagram, our input stride is 1, the i,j location is
  1022.        indicated by "*", and the four value we want to average are
  1023.        "X"s:
  1024.            X   .   X
  1025.            .   *   .
  1026.            X   .   X
  1027.        */
  1028.     return ((float) (fa[((i-stride)*size) + j-stride].m_fOrigin[Z] +
  1029.      fa[((i-stride)*size) + j+stride].m_fOrigin[Z] +
  1030.      fa[((i+stride)*size) + j-stride].m_fOrigin[Z] +
  1031.      fa[((i+stride)*size) + j+stride].m_fOrigin[Z]) * .25f);
  1032. }
  1033. // FillFractualArray - Use the diamond-square algorithm to tessalate a
  1034. // grid of float values into a fractal height map.
  1035. //
  1036. void C3dObjectTerrain::FillFractualArray (C3dPoint *fa, int size,
  1037.  float heightScale, float h)
  1038. {
  1039. int i, j;
  1040. int stride;
  1041. int oddline;
  1042. int subSize;
  1043. int seedValue;
  1044. float ratio, scale;
  1045. if (!PowerOf2(size) || (size==1))
  1046. {
  1047. // We can't tesselate the array if it is not a power of 2.
  1048. #ifdef DEBUG
  1049. printf ("Error: FillFractualArray: size %d is not a power of 2.n");
  1050. #endif /* DEBUG */
  1051. return;
  1052.     }
  1053. // subSize is the dimension of the array in terms of connected line
  1054. // segments, while size is the dimension in terms of number of
  1055. // vertices.
  1056. subSize = size;
  1057. size++;
  1058. // Initialize random number generator
  1059. if(m_iHeightSeed < 0)
  1060. {
  1061. // Seed the random-number generator with current time so that
  1062. // the numbers will be different every time we run.
  1063. seedValue = (unsigned)time( NULL );
  1064. srand( seedValue );
  1065. m_iHeightSeed = seedValue;
  1066. }
  1067. else
  1068.     srand (m_iHeightSeed);
  1069.     // Set up our roughness constants.
  1070. // Random numbers are always generated in the range 0.0 to 1.0.
  1071. // 'scale' is multiplied by the randum number.
  1072. // 'ratio' is multiplied by 'scale' after each iteration
  1073. // to effectively reduce the random number range.
  1074. ratio = (float) pow ((double)2.0,(double)-h);
  1075. scale = heightScale * ratio;
  1076.     /* Seed the first four values. For example, in a 4x4 array, we
  1077.        would initialize the data points indicated by '*':
  1078.            *   .   .   .   *
  1079.            .   .   .   .   .
  1080.            .   .   .   .   .
  1081.            .   .   .   .   .
  1082.            *   .   .   .   *
  1083.        In terms of the "diamond-square" algorithm, this gives us
  1084.        "squares".
  1085.        We want the four corners of the array to have the same
  1086.        point. This will allow us to tile the arrays next to each other
  1087.        such that they join seemlessly.
  1088.    */
  1089. stride = subSize / 2;
  1090. fa[(0*size)+0].m_fOrigin[Z] = fa[(subSize*size)+0].m_fOrigin[Z] =
  1091. fa[(subSize*size)+subSize].m_fOrigin[Z] =
  1092. fa[(0*size)+subSize].m_fOrigin[Z] = 0.f;
  1093. // Now we add ever-increasing detail based on the "diamond" seeded
  1094. // values. We loop over stride, which gets cut in half at the
  1095. // bottom of the loop. Since it's an int, eventually division by 2
  1096. // will produce a zero result, terminating the loop.
  1097. while (stride)
  1098. {
  1099. /* Take the existing "square" data and produce "diamond"
  1100.    data. On the first pass through with a 4x4 matrix, the
  1101.    existing data is shown as "X"s, and we need to generate the
  1102.        "*" now:
  1103.                X   .   .   .   X
  1104.                .   .   .   .   .
  1105.                .   .   *   .   .
  1106.                .   .   .   .   .
  1107.                X   .   .   .   X
  1108.   It doesn't look like diamonds. What it actually is, for the
  1109.       first pass, is the corners of four diamonds meeting at the
  1110.       center of the array. */
  1111. for (i=stride; i<subSize; i+=stride)
  1112. {
  1113. for (j=stride; j<subSize; j+=stride)
  1114. {
  1115. fa[(i * size) + j].m_fOrigin[Z] = scale * FractRand (.5f) +
  1116. AvgSquareVals (i, j, stride, size, fa);
  1117. j += stride;
  1118. }
  1119. i += stride;
  1120. }
  1121. /* Take the existing "diamond" data and make it into
  1122.        "squares". Back to our 4X4 example: The first time we
  1123.        encounter this code, the existing values are represented by
  1124.        "X"s, and the values we want to generate here are "*"s:
  1125.                X   .   *   .   X
  1126.                .   .   .   .   .
  1127.                *   .   X   .   *
  1128.                .   .   .   .   .
  1129.                X   .   *   .   X
  1130.        i and j represent our (x,y) position in the array. The
  1131.        first value we want to generate is at (i=2,j=0), and we use
  1132.        "oddline" and "stride" to increment j to the desired value.
  1133.        */
  1134. oddline = 0;
  1135. for (i=0; i<subSize; i+=stride)
  1136. {
  1137.     oddline = (oddline == 0);
  1138. for (j=0; j<subSize; j+=stride)
  1139. {
  1140. if ((oddline) && !j)
  1141. j+=stride;
  1142. // i and j are setup. Call avgDiamondVals with the
  1143. // current position. It will return the average of the
  1144. // surrounding diamond data points.
  1145. fa[(i * size) + j].m_fOrigin[Z] = scale * FractRand (.5f) +
  1146. AvgDiamondVals (i, j, stride, size, subSize, fa);
  1147. // To wrap edges seamlessly, copy edge values around
  1148. // to other side of array.
  1149. if (i==0)
  1150. fa[(subSize*size) + j].m_fOrigin[Z] =
  1151. fa[(i * size) + j].m_fOrigin[Z];
  1152. if (j==0)
  1153. fa[(i*size) + subSize].m_fOrigin[Z] =
  1154. fa[(i * size) + j].m_fOrigin[Z];
  1155. j+=stride;
  1156. }
  1157. }
  1158. // reduce random number range.
  1159. scale *= ratio;
  1160. stride >>= 1;
  1161.     }
  1162. // Now that we have the terrain height values, calculate
  1163. // the width and depth values.
  1164. float width, depth;
  1165. width = -m_fWidth/2.0f;
  1166. // Initialize our terrain color height values
  1167. InitColorHeightValues();
  1168. float seaHeight;
  1169. if(m_fSeaLevel > .0f)
  1170. seaHeight = ((m_fSnowHeight-m_fWaterHeight)*m_fSeaLevel) + m_fWaterHeight;
  1171. for(i=0; i<size; i++)
  1172. {
  1173. depth = -m_fDepth/2.0f;
  1174. for(j=0; j<size; j++)
  1175. {
  1176. fa[(i*size) + j].m_fOrigin[X]=width;
  1177. fa[(i*size) + j].m_fOrigin[Y]=depth;
  1178. if(m_fSeaLevel > .0f)
  1179. {
  1180. if(fa[(i*size) + j].m_fOrigin[Z]<=seaHeight)
  1181. fa[(i*size) + j].m_fOrigin[Z]=seaHeight;
  1182. }
  1183. depth += (m_fDepth/(GLfloat)subSize);
  1184. }
  1185. width += (m_fWidth/(GLfloat)subSize);
  1186. }
  1187. }
  1188. // InitColorHeightValues
  1189. //
  1190. // The h1 and h2 parameters are set to 1/3 and 2/3 of the height values and 
  1191. // h3 and h4 will be the max and min height values height values stored in the
  1192. // 2D fract array.
  1193. void C3dObjectTerrain::InitColorHeightValues()
  1194. {
  1195. float min, max;
  1196. int i;
  1197. // Set the min/max initially to very large opposite numbers
  1198.     min = (float)LARGE_NUMBER;
  1199.     max = (float)-LARGE_NUMBER;
  1200. for (i=0; i<m_pPointArray->m_iNumPoints; i++)
  1201. {
  1202. if(m_pPointArray->m_pPoints[i].m_fOrigin[Z] > max)
  1203. max = m_pPointArray->m_pPoints[i].m_fOrigin[Z];
  1204. else if(m_pPointArray->m_pPoints[i].m_fOrigin[Z] < min)
  1205.     min = m_pPointArray->m_pPoints[i].m_fOrigin[Z];
  1206. }
  1207. m_fSnowHeight  = max;
  1208. m_fRockHeight  = (max - min) * .66f + min;
  1209. m_fGrassHeight = (max - min) * .33f + min;
  1210. m_fWaterHeight = min;
  1211. }
  1212. void C3dObjectTerrain::InitTerrainColor()
  1213. {
  1214.     int i;
  1215. // Set our terrain color height values.  These settings are then used in
  1216. // our rinky-dink-but-effective coloring, scheme wherein the lower 1/3
  1217. // of terrain is colored dark green, the middle third is colored grey,
  1218. // and the upper third is white.  Our sealevel is colored blue.
  1219. InitColorHeightValues();
  1220. for (i=0; i<m_pPointArray->m_iNumPoints; i++)
  1221. {
  1222. float z = m_pPointArray->m_pPoints[i].m_fOrigin[Z];
  1223. if(z > m_fRockHeight)
  1224. m_pPointArray->m_pPoints[i].m_Color.SetColor4fv(&m_ColorSnow);
  1225. else if(z > m_fGrassHeight)
  1226. m_pPointArray->m_pPoints[i].m_Color.SetColor4fv(&m_ColorRock);
  1227. else
  1228. m_pPointArray->m_pPoints[i].m_Color.SetColor4fv(&m_ColorGrass);
  1229. if(m_fSeaLevel > .0f)
  1230. {
  1231. if(z == m_fWaterHeight)
  1232. m_pPointArray->m_pPoints[i].m_Color.SetColor4fv(&m_ColorWater);
  1233. }
  1234. }
  1235. }
  1236. void C3dObjectTerrain::SetTerrainColor(int i, int j, BOOL bReflect)
  1237. {
  1238. static C3dColor LastColor;
  1239. float h1;
  1240. if(i+j != 0)
  1241. {
  1242. // To DRAMATICALLY reduce the size of the display list, and hence, increase
  1243. // the speed, lets' minimize setting the material properties..
  1244. if(m_pPointArray->m_pPoints[i*(m_iSize+1)+j].m_Color.Compare(&LastColor))
  1245. // This points color components are identical to the last one set,
  1246. // so there is no need to set the material properties again.
  1247. return;
  1248. }
  1249. h1 = m_pPointArray->m_pPoints[i*(m_iSize+1)+j].m_fOrigin[Z];
  1250. if(h1 == m_fWaterHeight || h1 > m_fRockHeight)
  1251. {
  1252. if(bReflect)
  1253. {
  1254. // Set snow material properties
  1255. GLfloat ambColor[] = {0.2f, 0.2f, 0.2f, 1.0f};
  1256. GLfloat difColor[] = {0.8f, 0.8f, 0.8f, 1.0f};
  1257. GLfloat spcColor[] = {0.9f, 0.9f, 0.9f, 1.0f};
  1258. GLfloat emmColor[] = {0.0f, 0.0f, 0.0f, 1.0f};
  1259. // Set material properties to default values
  1260. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,  ambColor);
  1261. glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,  difColor);
  1262. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spcColor);
  1263. glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emmColor);
  1264. glMaterialf(GL_FRONT, GL_SHININESS, 20.0f);
  1265. }
  1266. }
  1267. else
  1268. {
  1269. if(bReflect)
  1270. {
  1271. // All three vertices lay in the horizonal plane, so set its
  1272. // color and water material properties
  1273. GLfloat ambColor[] = {0.2f, 0.2f, 0.2f, 1.0f};
  1274. GLfloat difColor[] = {0.8f, 0.8f, 0.8f, 1.0f};
  1275. GLfloat spcColor[] = {0.0f, 0.0f, 0.0f, 1.0f};
  1276. GLfloat emmColor[] = {0.0f, 0.0f, 0.0f, 1.0f};
  1277. // Set material properties to default values
  1278. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,  ambColor);
  1279. glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,  difColor);
  1280. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spcColor);
  1281. glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emmColor);
  1282. glMaterialf(GL_FRONT, GL_SHININESS, 0.0f);
  1283. }
  1284. }
  1285. glColor4fv(m_pPointArray->m_pPoints[i*(m_iSize+1)+j].m_Color.m_fColor);
  1286. // Save the color components
  1287. LastColor.SetColor4fv(&m_pPointArray->m_pPoints[i*(m_iSize+1)+j].m_Color);
  1288. }
  1289. BOOL C3dObjectTerrain::AddSubTexture(LPSTR szFileName, CTexture** pTexture)
  1290. {
  1291. if(*pTexture)
  1292. // If we already have a texture, delete it
  1293. DeleteSubTexture(*pTexture);
  1294. // Create a TextureMap of the appropriate type
  1295. CTexture::CreateTexture(szFileName, the3dEngine.m_hPalette, pTexture);
  1296. if(pTexture)
  1297. {
  1298. CTexture* pText = *pTexture;
  1299. // Is the TextureMap an CTextureAviMovie?
  1300. if( pText->IsKindOf(RUNTIME_CLASS(CTextureAviMovie)) )
  1301. {
  1302. // Create an AVI animation and add to the list
  1303. CAnimAVI* pAnim = new CAnimAVI;
  1304. ASSERT(pAnim);
  1305. m_AnimList.Append(pAnim);
  1306. // Cross link the two objects so that they are 'aware' of
  1307. // each other..
  1308. // Save the CTextureAviMovie pointer
  1309. pAnim->m_pAviMovie = (CTextureAviMovie*)pTexture;
  1310. // Save the CAnimAVI pointer
  1311. CTextureAviMovie* pAviVideo = (CTextureAviMovie*)pTexture;
  1312. pAviVideo->m_pAnimAVI = pAnim;
  1313. }
  1314. return TRUE;
  1315. }
  1316. else
  1317. return FALSE;
  1318. }
  1319. void C3dObjectTerrain::DeleteSubTexture(CTexture* pTexture)
  1320. {
  1321. if(pTexture)
  1322. {
  1323. if( pTexture->IsKindOf(RUNTIME_CLASS(CTextureAviMovie)) )
  1324. {
  1325. // TextureMap is of class type CTextureAviMovie, so find the animation
  1326. // procedure in the list, remove from list and delete it..
  1327. CAnimation* pAnimation = m_AnimList.Find(SZ_ANIMATE_AVI);
  1328. if(pAnimation)
  1329. {
  1330. m_AnimList.Remove(pAnimation);
  1331. delete pAnimation;
  1332. }
  1333. }
  1334. // Now that we have removed any associated object members,
  1335. // delete the texturemap
  1336. delete pTexture;
  1337. pTexture = NULL;
  1338. }
  1339. }
  1340. // renderTeximageMap
  1341. //
  1342. // If the teximage map is dirty, allocate and tesselate a new
  1343. // one. Render it to the screen as lit triangles. Read the
  1344. // image back and set it as a texture map in a display list.
  1345. BOOL C3dObjectTerrain::RenderTextureImageMap(C3dWorld* pWorld, C3dCamera* pCamera)
  1346. {
  1347. UINT pmapDim, smallDim;
  1348. // Find the biggest power of two that will fit
  1349. // in the current window. This is where we will 
  1350. // draw the image.
  1351. smallDim = (pCamera->m_iScreenWidth > pCamera->m_iScreenHeight) ?
  1352. pCamera->m_iScreenHeight : pCamera->m_iScreenWidth;
  1353. pmapDim = 1 << (UINT) (log ((float) smallDim) / log (2.));
  1354. // Save our gl States
  1355. glPushAttrib (0xfffffff);
  1356. // Only draw into biggest power of 2 square.
  1357. glViewport (0, 0, pmapDim, pmapDim);
  1358. glMatrixMode (GL_PROJECTION);
  1359.     glLoadIdentity ();
  1360. glOrtho (-m_fWidth/2.0f, m_fWidth/2.0f,
  1361.  -m_fDepth/2.0f, m_fDepth/2.0f, 0.0f, pCamera->m_fFar);
  1362. glMatrixMode (GL_MODELVIEW);
  1363.     glLoadIdentity ();
  1364. // The terrain array is rendered into the XY plane as viewed looking
  1365. // along the -Z axis. We need to move the 'camera' position up in Z
  1366. // so that we don't clip any polygons.
  1367. glTranslatef(0.f, 0.f, -10.f);
  1368. // Init lights now. Light position must be specified
  1369. // after our translation.
  1370. pWorld->InitializeLights(pCamera);
  1371. // Set our state flags
  1372. glDisable (GL_DEPTH_TEST);
  1373. glDisable (GL_FOG);
  1374. glEnable (GL_LIGHTING);
  1375. glDisable (GL_BLEND);
  1376.     // Clear our color buffer
  1377. glClear (GL_COLOR_BUFFER_BIT);
  1378. // Render the terrain
  1379. RenderTerrain(FALSE, FALSE);
  1380. // Flush all commands to draw the image
  1381. glFlush ();
  1382. GLubyte *pmap;
  1383. pmap = (GLubyte *) malloc (pmapDim*pmapDim*3);
  1384. if (pmap==NULL)
  1385. return (FALSE);
  1386. // Read the screen pixels
  1387. glReadPixels (0, 0, pmapDim, pmapDim, GL_RGB, GL_UNSIGNED_BYTE, pmap);
  1388. if(!m_iTexImageMap)
  1389. // Create our texture map display list
  1390. m_iTexImageMap = glGenLists(1);// Create the DisplayList(s)
  1391. glNewList(m_iTexImageMap, GL_COMPILE);
  1392. glTexImage2D (GL_TEXTURE_2D, 0, // lod
  1393.   3, // Number of components
  1394.   pmapDim, pmapDim, // width, height
  1395.   0, // Border
  1396.   GL_RGB, // Format
  1397.   GL_UNSIGNED_BYTE, // Type
  1398.   pmap); // Pointer to our pixels
  1399. glEndList ();
  1400. // Now that we have our texture map display list, 
  1401. // free our pixel memory
  1402. free (pmap);
  1403. // Restore our gl States
  1404. glPopAttrib ();
  1405. // Clear the buffers
  1406. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  1407. // Re-position our camera and lights to their original position
  1408. pCamera->ResetView(0, 0);
  1409. pCamera->PositionCamera();
  1410. pWorld->InitializeLights(pCamera);
  1411. return (TRUE);
  1412. }