Fractal ExampleView.cpp
上传用户:sycq158
上传日期:2008-10-22
资源大小:15361k
文件大小:27k
源码类别:

游戏

开发平台:

Visual C++

  1. // Fractal ExampleView.cpp : implementation of the CFractalExampleView class
  2. //
  3. //
  4. // Written by: Paul E. Martz
  5. // 
  6. // Copyright 1997 by Paul E. Martz, all right reserved
  7. //
  8. // Non-commercial use by individuals is permitted.
  9. //
  10. #include "stdafx.h"
  11. #include <math.h>
  12. #include "Fractal Example.h"
  13. #include "Fractal ExampleDoc.h"
  14. #include "Fractal ExampleView.h"
  15. #include "FractalOptionsDlg.h"
  16. #include "fractmod.h"
  17. #define CLOUDMAP 10
  18. #define TEXIMAGEMAP 20
  19. /////////////////////////////////////////////////////////////////////////////
  20. #ifdef _DEBUG
  21. #define new DEBUG_NEW
  22. #undef THIS_FILE
  23. static char THIS_FILE[] = __FILE__;
  24. #endif
  25. /////////////////////////////////////////////////////////////////////////////
  26. // CFractalExampleView
  27. IMPLEMENT_DYNCREATE(CFractalExampleView, COpenGLView)
  28. BEGIN_MESSAGE_MAP(CFractalExampleView, COpenGLView)
  29. //{{AFX_MSG_MAP(CFractalExampleView)
  30. ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions)
  31. ON_WM_KEYDOWN()
  32. ON_WM_KEYUP()
  33. ON_WM_DESTROY()
  34. //}}AFX_MSG_MAP
  35. END_MESSAGE_MAP()
  36. /////////////////////////////////////////////////////////////////////////////
  37. // CFractalExampleView construction/destruction
  38. CFractalExampleView::CFractalExampleView()
  39. {
  40. // TODO: add construction code here
  41. }
  42. CFractalExampleView::~CFractalExampleView()
  43. {
  44. }
  45. /////////////////////////////////////////////////////////////////////////////
  46. // CFractalExampleView drawing
  47. /////////////////////////////////////////////////////////////////////////////
  48. // CFractalExampleView diagnostics
  49. #ifdef _DEBUG
  50. void CFractalExampleView::AssertValid() const
  51. {
  52. CView::AssertValid();
  53. }
  54. void CFractalExampleView::Dump(CDumpContext& dc) const
  55. {
  56. CView::Dump(dc);
  57. }
  58. CFractalExampleDoc* CFractalExampleView::GetDocument() // non-debug version is inline
  59. {
  60. ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFractalExampleDoc)));
  61. return (CFractalExampleDoc*)m_pDocument;
  62. }
  63. #endif //_DEBUG
  64. ///////////////////////////////////////////
  65. // static routines used for rendering
  66. // Scale value passed into fractal generation routines.
  67. #define DEF_HEIGHT_SCALE 1.f
  68. // Keep linker happy
  69. #ifdef __cplusplus
  70. extern "C" {
  71. #endif
  72. // These next few routines are declared external by fractmod.c
  73. // They are referenced by fractmod.c's functions:
  74. //   draw1DFractArrayAsLines
  75. //   draw2DFractArrayAsLines
  76. //   draw2DFractArrayAsTriangles
  77. // If you don't use those functions from fractmod.c, these
  78. // functions here could be left blank. However they would
  79. // still need to be declared to resolve the symbols (unless
  80. // you removed their references in fractmod.c).
  81. void draw3DTriangle (float x1, float y1, float z1,
  82.      float x2, float y2, float z2,
  83.      float x3, float y3, float z3,
  84.      float nx, float ny, float nz)
  85. {
  86.     glBegin (GL_TRIANGLES);
  87.     glNormal3f (nx, ny, nz);
  88.     glVertex3f (x1, y1, z1);
  89.     glVertex3f (x2, y2, z2);
  90.     glVertex3f (x3, y3, z3);
  91.     glEnd ();
  92. }
  93. void draw3DLine (float x1, float y1, float z1,
  94.  float x2, float y2, float z2)
  95. {
  96.     glBegin (GL_LINES);
  97.     glVertex3f (x1, y1, z1);
  98.     glVertex3f (x2, y2, z2);
  99.     glEnd ();
  100. }
  101. void draw2DLine (float x1, float y1,
  102.  float x2, float y2)
  103. {
  104.     glBegin (GL_LINES);
  105.     glVertex2f (x1, y1);
  106.     glVertex2f (x2, y2);
  107.     glEnd ();
  108. }
  109. #ifdef __cplusplus
  110. }
  111. #endif
  112. // Sets up lighting in OpenGL but does not enable it.
  113. // Lighting will be enabled in ::renderTeximageMap().
  114. static void initLights ()
  115. {
  116.     GLfloat light_ambient[]  = {.5f, .5f, .5f, 1.f};
  117.     GLfloat light_specular[] = {0.f, 0.f, 0.f, 1.f};
  118.     GLfloat light_diffuse[]  = {1.f, 1.f, 1.f, 1.f};
  119.     GLfloat light_position[] = {1.f, .5f, 1.f, 0.f}; /* w=0 ==> directional */
  120.     glLightfv (GL_LIGHT1, GL_POSITION, light_position);
  121.     glLightfv (GL_LIGHT1, GL_DIFFUSE, light_diffuse);
  122.     glLightfv (GL_LIGHT1, GL_SPECULAR, light_specular);
  123.     glLightModelfv (GL_LIGHT_MODEL_AMBIENT, light_ambient);
  124.     glEnable (GL_LIGHT1);
  125.     glColorMaterial (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
  126.     glEnable (GL_COLOR_MATERIAL);
  127. }
  128. /////////////////////////////////////////////////////////////////////////////
  129. // CFractalExampleView message handlers
  130. void CFractalExampleView::OnInitialUpdate() 
  131. {
  132. COpenGLView::OnInitialUpdate();
  133. // Probably not the best place in the world to 
  134. // initialize all this stuff. But it works for me.
  135. // And after all, this is a hack, isn't it?
  136.     glPixelStorei(GL_PACK_ALIGNMENT, 1);
  137.     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  138. //* Default values you see in the View Options dialog box.
  139. colorInvert = FALSE;
  140. iterations = 2;
  141. cloudIter = 5;
  142. teximageIter = 8;
  143. renderMode = twoDR_lines;
  144. arrayIs2D = TRUE;
  145. tile = 1;
  146. randomSeed = 0;
  147. aaLines = TRUE;
  148. textureLinear = TRUE;
  149. // Initial rotations, translations, and a toggle for 
  150. // the shift key status.
  151. shiftKeyStatus = FALSE;
  152. yRot = 0.f;
  153. yTrans = -.5f;
  154. zTrans = -3.f;
  155. // Ptrs to data and dirty flags. Initially, all 
  156. // are NULL and dirty.
  157. surfFA = NULL;
  158. surfFAdirty = TRUE;
  159. teximageFA = NULL;
  160. teximageFAdirty = TRUE;
  161. cloudFA = NULL;
  162. cloudFAdirty = TRUE;
  163. cloudH = surfaceH = teximageH = 0.7f;
  164. }
  165. // surfToSky
  166. //
  167. // Converts a 2D fract array into a nice blue and white
  168. // cloudy sky texture map. First, it finds the average height
  169. // value in the map. Then it clamps values to +/- SKY_LIMIT
  170. // around the average value. Values in the array are then
  171. // mapped from a medium blue to white. The resulting RGB 
  172. // values are stored in skyTex.
  173. //
  174. // Note that while the fract array is assumed to have dimension
  175. // (size+1)X(size+1), skyTex must have dimension sizeXsize.
  176. // This facilitates its being used as an OpenGL texture map.
  177. static void surfToSky (float *fa, int size, GLubyte *skyTex)
  178. {
  179.     int i, j;
  180.     const int subSize = size;
  181.     unsigned char *skyptr;
  182.     float shadeFactor;
  183.     float skyAv=0.f;
  184.     size++;
  185.     for (i=0; i<size*size; i++)
  186. skyAv += fa[i];
  187. skyAv /= (float)(size*size);
  188. #define SKY_LIMIT 0.2f
  189.     skyptr = skyTex;
  190.     for (i=0; i<subSize; i++) {
  191. for (j=0; j<subSize; j++) {
  192. if (fa[i*size+j] < (skyAv - SKY_LIMIT))
  193. shadeFactor = -SKY_LIMIT;
  194. else if (fa[i*size+j] > (skyAv + SKY_LIMIT))
  195. shadeFactor = SKY_LIMIT;
  196. else
  197. shadeFactor = fa[i*size+j] - skyAv;
  198. /* shadeFactor is now in range -SKY_LIMIT - SKY_LIMIT.
  199.    scale shadeFactor to range 0.0 - 0.5 */
  200. shadeFactor = ((shadeFactor + SKY_LIMIT) *
  201.    (.5f / (2.f * SKY_LIMIT)));
  202. /* Make red and green range from 0.41 - 0.9 */
  203. skyptr[0] = (GLubyte)((.4 + shadeFactor) * 255); /* red */
  204. skyptr[1] = (GLubyte)((.4 + shadeFactor) * 255); /* green */
  205. skyptr[2] = (GLubyte)(.9 * 255.); /* blue */
  206. skyptr += 3;
  207. }
  208.     }
  209. }
  210. // renderCloudMap
  211. //
  212. // Render the cloud texture map. If the cloud fract array
  213. // doesn't already exist, allocate it, tesselate it, and
  214. // create the texture map using surfToSky. Then create a 
  215. // display list with this texture map in the list.
  216. //
  217. // Once we have the texture map, we simply draw a quad as
  218. // big as will fit in the window, with the cloud texture map
  219. // applied to it.
  220. BOOL CFractalExampleView::renderCloudMap ()
  221. {
  222. CWaitCursor hourglass;
  223.     int size = 1 << cloudIter;
  224. if (cloudFA && cloudFAdirty) {
  225. freeFractArray (cloudFA);
  226. cloudFA = NULL;
  227. }
  228. if (!cloudFA) {
  229. cloudFA = alloc2DFractArray (size);
  230. if (cloudFA==NULL) return (FALSE);
  231. fill2DFractArray (cloudFA, size, randomSeed,
  232. DEF_HEIGHT_SCALE, cloudH);
  233. }
  234. glPushAttrib (0xfffffff);
  235. if (cloudFAdirty) {
  236. GLubyte *tmap;
  237. tmap = (GLubyte *) malloc (size*size*3);
  238. if (tmap==NULL) return (FALSE);
  239. surfToSky (cloudFA, size, tmap);
  240. glNewList (CLOUDMAP, GL_COMPILE);
  241. glTexImage2D (GL_TEXTURE_2D, 0, /* lod */
  242.       3, /* num components */
  243.       size, size, /* width, height */
  244.       0, /* border */
  245.       GL_RGB, GL_UNSIGNED_BYTE, /* format, type */
  246.       tmap);
  247. glEndList ();
  248. free (tmap);
  249. }
  250. glCallList (CLOUDMAP);
  251. glMatrixMode (GL_PROJECTION);
  252.     glLoadIdentity ();
  253. if (currentWidth > currentHeight)
  254. glOrtho (-1.f, aspectRatio*2.f-1.f,
  255. -1.f, 1.f, 1., -1.);
  256. else 
  257.   glOrtho (-1.f, 1.f,
  258. -1.f, 2.f/aspectRatio-1.f, 1., -1.);
  259. glMatrixMode (GL_MODELVIEW);
  260.     glLoadIdentity ();
  261. glDisable (GL_DEPTH_TEST);
  262. glDisable (GL_FOG);
  263. glDisable (GL_LIGHTING);
  264. glDisable (GL_BLEND);
  265. glEnable (GL_TEXTURE_2D);
  266.     
  267. glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
  268. (GLfloat) GL_REPLACE);
  269. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  270. (GLfloat) GL_NEAREST);
  271. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
  272. (GLfloat) GL_NEAREST);
  273. glClear (GL_COLOR_BUFFER_BIT);
  274. glBegin (GL_QUADS); {
  275. glTexCoord2f (0.f, 0.f); glVertex2f (-1.f, -1.f);
  276. glTexCoord2f (1.f, 0.f); glVertex2f (1.f, -1.f);
  277. glTexCoord2f (1.f, 1.f); glVertex2f (1.f, 1.f);
  278. glTexCoord2f (0.f, 1.f); glVertex2f (-1.f, 1.f);
  279. } glEnd ();
  280. glFlush ();
  281. glPopAttrib ();
  282. cloudFAdirty = FALSE;
  283. return (TRUE);
  284. }
  285. // setH1H2
  286. //
  287. // The h1 and h2 parameters are set to 1/3 and 2/3 of the
  288. // height values stored in the 2D fract array. These values
  289. // are then used in our rinky-dink-but-effective coloring,
  290. // scheme wherein the lower 1/3 of terrain is colored dark
  291. // green, the middle third is colored grey, and the upper
  292. // third is white.
  293. void setH1H2 (float *fa, int size, float *h1, float *h2)
  294. {
  295.     float min, max;
  296.     int i;
  297.     size++;
  298.     min = 2.f;
  299.     max = -2.f;
  300.     for (i=0; i<size*size; i++) {
  301. if (fa[i] > max)
  302.     max = fa[i];
  303. else if (fa[i] < min)
  304.     min = fa[i];
  305.     }
  306.     *h1 = (max - min) * .66f + min;
  307.     *h2 = (max - min) * .33f + min;
  308. }
  309. // SET_COLOR -- Based on the height value, set the current 
  310. // color to dark green, grey, or white.
  311. #define SET_COLOR(h,h1,h2)
  312.     if (h > h1) 
  313. glColor3f (.95f, .95f, 1.f); 
  314.     else if (h > h2) 
  315. glColor3f (.55f, .55f, .6f); 
  316.     else 
  317. glColor3f (.2f, .4f, .2f); 
  318. }
  319. // TEXCOORD -- Based on the current values of X and Z passed
  320. // in as U and V, Set the texture coordinate. Sinze X and Z
  321. // could range from -1.0 to 1.0, this is simply a matter of
  322. // adding 1 and dividing by 2.
  323. #define TEXCOORD(u,v) 
  324.     glTexCoord2f ((u+1.f)*.5f, -((v-1.f)*.5f))
  325. // getNormal
  326. //
  327. // Given the three vertices of a triangle, return a surface
  328. // normal to that triangle.
  329. static void getNormal (float x1, float y1, float z1,
  330.        float x2, float y2, float z2,
  331.        float x3, float y3, float z3,
  332.        float *normal)
  333. {
  334.     float len;
  335.     float v1x, v1y, v1z;
  336.     float v2x, v2y, v2z;
  337.     v1x = x2 - x1;
  338.     v1y = y2 - y1;
  339.     v1z = z2 - z1;
  340.     v2x = x3 - x1;
  341.     v2y = y3 - y1;
  342.     v2z = z3 - z1;
  343.     normal[0] = v1y*v2z - v1z*v2y;
  344.     normal[1] = v1z*v2x - v1x*v2z;
  345.     normal[2] = v1x*v2y - v1y*v2x;
  346.     len = (float) sqrt (normal[0]*normal[0] + normal[1]*normal[1] +
  347. normal[2]*normal[2]);
  348.     normal[0] /= len;
  349.     normal[1] /= len;
  350.     normal[2] /= len;
  351. }
  352. // genNormal
  353. //
  354. // Use getNormal to get the Normal for the specified triangle.
  355. // Then set the current normal in OpenGL.
  356. static void genNormal (float x1, float y1, float z1,
  357.        float x2, float y2, float z2,
  358.        float x3, float y3, float z3)
  359. {
  360.     float norm[3];
  361.     getNormal (x1, y1, z1,
  362.        x2, y2, z2,
  363.        x3, y3, z3, norm);
  364.     glNormal3f (norm[0], norm[1], norm[2]);
  365. }
  366. // renderAsTriangle
  367. //
  368. // As far as OpenGL efficiency goes, this routine will be better
  369. // than fractmod.c's draw2DFractArrayAsTriangles because it uses
  370. // the triangle strip primitive. If the "lights" param is non-zero,
  371. // surface normals are specified. If the "dotex" param is non-zero,
  372. // texture coordinates are sprcified.
  373. static void renderAsTriangles (float *fa, int sz,
  374.        int lights, int dotex)
  375. {
  376. float h1, h2;
  377.     int i, j;
  378.     float x, z, inc;
  379.     const int subSize = sz, superSize = sz+1;
  380. // h1 and h2 will be 1/3 and 2/3 of our height
  381. // values. The SET_COLOR macro uses this to determine
  382. // the syrface color for a given height.
  383.   setH1H2 (fa, subSize, &h1, &h2);
  384. inc = 2.f / subSize;
  385.     z = -1.f;
  386.     for (i=0; i<subSize; i++) {
  387. glBegin (GL_TRIANGLE_STRIP);
  388. x = -1.f, j=0;
  389. if (dotex)
  390. TEXCOORD (x, z);
  391. else {
  392. if (lights)
  393. genNormal (x, fa[i*superSize+j], z,
  394.    x, fa[(i+1)*superSize+j], z+inc,
  395.    x+inc, fa[i*superSize+j+1], z);
  396. SET_COLOR (fa[i*superSize+j], h1, h2);
  397. }
  398. glVertex3f (x, fa[i*superSize+j], z);
  399. if (dotex)
  400.     TEXCOORD (x, z+inc);
  401. else {
  402.     if (lights)
  403. genNormal (x, fa[(i+1)*superSize+j], z+inc,
  404.    x+inc, fa[(i+1)*superSize+j+1], z+inc,
  405.    x+inc, fa[i*superSize+j+1], z);
  406.     SET_COLOR (fa[(i+1)*superSize+j], h1, h2);
  407. }
  408. glVertex3f (x, fa[(i+1)*superSize+j], z+inc);
  409. for (; j<subSize; j++) {
  410. if (dotex)
  411. TEXCOORD (x+inc, z);
  412.     else {
  413. if (lights)
  414. genNormal (x, fa[(i*superSize)+j], z,
  415.        x, fa[(i+1)*superSize+j], z+inc,
  416.        x+inc, fa[i*superSize+j+1], z);
  417. SET_COLOR (fa[i*superSize+j+1], h1, h2);
  418.     }
  419.     glVertex3f (x+inc, fa[i*superSize+j+1], z);
  420. if (dotex)
  421. TEXCOORD (x+inc, z+inc);
  422.     else {
  423. if (lights)
  424. genNormal (x, fa[(i+1)*superSize+j], z+inc,
  425.        x+inc, fa[(i+1)*superSize+j+1], z+inc,
  426.        x+inc, fa[i*superSize+j+1], z);
  427. SET_COLOR (fa[(i+1)*superSize+j+1], h1, h2);
  428. }
  429.     glVertex3f (x+inc, fa[(i+1)*superSize+j+1], z+inc);
  430.     x += inc;
  431. }
  432. z += inc;
  433. glEnd ();
  434.     }
  435. }
  436. // renderTeximageMap
  437. //
  438. // If the teximage map is dirty, allocate and tesselate a new
  439. // one. Render it to the screen as lit triangles. Read the
  440. // image back and set it as a texture map in a display list.
  441. BOOL CFractalExampleView::renderTeximageMap ()
  442. {
  443. CWaitCursor hourglass;
  444.     int size = 1 << teximageIter;
  445. UINT pmapDim, smallDim;
  446. if (teximageFA && teximageFAdirty) {
  447. freeFractArray (teximageFA);
  448. teximageFA = NULL;
  449. }
  450. if (!teximageFA) {
  451. teximageFA = alloc2DFractArray (size);
  452. if (teximageFA==NULL) return (FALSE);
  453. fill2DFractArray (teximageFA, size, randomSeed,
  454. DEF_HEIGHT_SCALE, teximageH);
  455. }
  456. // Find the biggest power of two that will fit
  457. // in the current window. This is where we will 
  458. // draw the image.
  459. smallDim = (currentWidth > currentHeight) ?
  460. currentHeight : currentWidth;
  461. pmapDim = 1 << (UINT) (log ((float) smallDim) / log (2.));
  462. glPushAttrib (0xfffffff);
  463. // Only draw into biggest power of 2 square.
  464. glViewport (0, 0, pmapDim, pmapDim);
  465. glMatrixMode (GL_PROJECTION);
  466.     glLoadIdentity ();
  467. glOrtho (-1.f, 1.f,
  468. -1.f, 1.f, 1., -1.);
  469. glMatrixMode (GL_MODELVIEW);
  470.     glLoadIdentity ();
  471. // The array is rendered into the XZ plane. We need to
  472. // rotate by 90 degrees so we will be looking at it
  473. // "top down".
  474. glRotatef (90.f, 1.f, 0.f, 0.f);
  475. // Init lights now. Light position must be specified
  476. // after the rotate, or else it won't be rotated.
  477. initLights ();
  478. glDisable (GL_DEPTH_TEST);
  479. glDisable (GL_FOG);
  480. glEnable (GL_LIGHTING);
  481. glDisable (GL_BLEND);
  482.     
  483. glClear (GL_COLOR_BUFFER_BIT);
  484. renderAsTriangles (teximageFA, size, 1, 0);
  485. glFlush ();
  486. glPopAttrib ();
  487. if (teximageFAdirty) {
  488. GLubyte *pmap;
  489. pmap = (GLubyte *) malloc (pmapDim*pmapDim*3);
  490. if (pmap==NULL) return (FALSE);
  491. glReadPixels (0, 0, pmapDim, pmapDim,
  492.       GL_RGB, GL_UNSIGNED_BYTE, pmap);
  493. glNewList (TEXIMAGEMAP, GL_COMPILE);
  494. glTexImage2D (GL_TEXTURE_2D, 0, /* lod */
  495.       3, /* num components */
  496.       pmapDim, pmapDim, /* width, height */
  497.       0, /* border */
  498.       GL_RGB, GL_UNSIGNED_BYTE, /* format, type */
  499.       pmap);
  500. glEndList ();
  501. free (pmap);
  502. }
  503. teximageFAdirty = FALSE;
  504. return (TRUE);
  505. }
  506. // renderFullImage
  507. //
  508. // First we render the sky. If the sky fract array is dirty,
  509. // we make a new one by calling renderCloudMap. The sky is
  510. // rendering as an 8-sided pyramid.
  511. // The apex is at (0,2,0), just above
  512. // the origin. The base of the eight walls are positioned
  513. // roughly in a circle of radius 15, in the XZ plane, around
  514. // the point (0,-1,0). Fig is enabled for the sky with a fog
  515. // range of (3,11). For speed, no Z buffering when rendering
  516. // the sky.
  517. // 
  518. // Then, we render the surface fract array for as many times
  519. // as it is tiled, and it is texture mapped with the teximage
  520. // map. If the teximage map is dirty, we make a clean one by
  521. // calling renderTeximageMap.
  522. BOOL CFractalExampleView::renderFullImage ()
  523. {
  524. CWaitCursor hourglass;
  525.     int size = 1 << iterations;
  526. GLfloat fogColor[4] = {.84f, .87f, 1.f, 1.f};
  527. // Validate the surface texture map
  528. if (teximageFAdirty)
  529. renderTeximageMap ();
  530. // validate the cloud texture map
  531. if (cloudFAdirty)
  532. renderCloudMap ();
  533. // validate the surface
  534. if (surfFA && surfFAdirty) {
  535. freeFractArray (surfFA);
  536. surfFA = NULL;
  537. }
  538. if (!surfFA) {
  539. surfFA = alloc2DFractArray (size);
  540. if (surfFA==NULL) return (FALSE);
  541. fill2DFractArray (surfFA, size, randomSeed,
  542. DEF_HEIGHT_SCALE, surfaceH);
  543. surfFAdirty = FALSE;
  544. }
  545. glMatrixMode (GL_PROJECTION);
  546.     glLoadIdentity ();
  547. gluPerspective (60., aspectRatio, .1, 15.0);
  548.     glMatrixMode (GL_MODELVIEW);
  549.     glLoadIdentity ();
  550. glTranslatef (0.f, yTrans, zTrans);
  551.     glRotatef (yRot, 0.f, 1.f, 0.f);
  552. glPushAttrib (0xffffffff);
  553. // fog range will be 3 to 11 for sky, but will
  554. // be a little closer when we render the terrain.
  555. // This creates that nice kind of true atmospheric
  556. // effect when looking through more air (along
  557. // the horizon) as opposed to straight up.
  558. glFogf (GL_FOG_DENSITY, 1.f);
  559. glFogf (GL_FOG_START, 3.f);
  560. glFogf (GL_FOG_END, 11.f);
  561. glFogi (GL_FOG_MODE, GL_LINEAR);
  562. glFogfv (GL_FOG_COLOR, fogColor);
  563. glEnable (GL_FOG);
  564. glDisable (GL_DITHER);
  565. // invertColors doesn't apply here; clear to fog color.
  566. glClearColor (fogColor[0], fogColor[1], fogColor[2], 1.f);
  567. glClear (GL_COLOR_BUFFER_BIT |
  568. GL_DEPTH_BUFFER_BIT);
  569. glDisable (GL_LIGHTING);
  570. glDisable (GL_DEPTH_TEST);
  571. // Goes a little faster but looks like crud:
  572. //glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
  573. glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
  574. (GLfloat) GL_REPLACE);
  575. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  576. textureLinear ? (GLfloat) GL_LINEAR
  577. : (GLfloat) GL_NEAREST);
  578. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
  579. textureLinear ? (GLfloat) GL_LINEAR
  580. : (GLfloat) GL_NEAREST);
  581. glEnable (GL_TEXTURE_2D);
  582. glCallList (CLOUDMAP);
  583. // TMMAX defines texture map wrapping.
  584. #define TMMAX 3.f // wrap from -3 to 3, or six times across our pyramid
  585. #define TMMAX45 (TMMAX * 0.707f) // roughly sine(TMMAX)
  586. // Kludgey, but it works:
  587. // This is an 8-sided pyramid covered with the cloud
  588. // texture, wrapped 4 times.
  589. glBegin (GL_TRIANGLE_FAN); {
  590. glTexCoord2f (0.f, 0.f); glVertex3f (0.f, 2.f, 0.f);
  591. glTexCoord2f (-TMMAX45, -TMMAX45); glVertex3f (-10.f, -1.f, 10.f);
  592. glTexCoord2f (0.f, -TMMAX); glVertex3f (0.f, -1.f, 15.f);
  593. glTexCoord2f (TMMAX45, -TMMAX45); glVertex3f (10.f, -1.f, 10.f);
  594. glTexCoord2f (TMMAX, 0.f); glVertex3f (15.f, -1.f, 0.f);
  595. glTexCoord2f (TMMAX45, TMMAX45); glVertex3f (10.f, -1.f, -10.f);
  596. glTexCoord2f (0.f, TMMAX); glVertex3f (0.f, -1.f, -15.f);
  597. glTexCoord2f (-TMMAX45, TMMAX45); glVertex3f (-10.f, -1.f, -10.f);
  598. glTexCoord2f (-TMMAX, 0.f); glVertex3f (-15.f, -1.f, 0.f);
  599. glTexCoord2f (-TMMAX45, -TMMAX45); glVertex3f (-10.f, -1.f, 10.f);
  600. } glEnd ();
  601. // Don't need depth test for sky but turn it on for
  602. // rendering the height map because I'm too lazy to do
  603. // painter's algorithm.
  604. glEnable (GL_DEPTH_TEST);
  605. glEnable (GL_CULL_FACE);
  606. // Here's the tighter fog range for the surface.
  607. glFogf (GL_FOG_START, 2.f);
  608. glFogf (GL_FOG_END, 7.f);
  609. // surface texture map
  610. glCallList (TEXIMAGEMAP);
  611. float x, z;
  612. UINT i, j;
  613. z = -1.f * (float) (tile-1);
  614. for (i=0; i<tile; i++) {
  615. x = -1.f * (float) (tile-1);
  616. for (j=0; j<tile; j++) {
  617. glPushMatrix ();
  618. glTranslatef (x, 0.f, z);
  619. renderAsTriangles (surfFA, size, 0, 1);
  620. glPopMatrix ();
  621. x += 2.f;
  622. }
  623. z += 2.f;
  624. }
  625. glPopAttrib ();
  626. return (TRUE);
  627. }
  628. // RenderScene
  629. //
  630. // This function overrides the same function in COpenGLView.
  631. // Here we handle rendering 1D midpoint displacement or 2D mesh
  632. // / lines, both of which are line rendering modes. If our
  633. // renderMode variable is set to anything else, we call
  634. // another function to handle the rendering. BOOL CFractalExampleView::RenderScene() {
  635.     int size = 1 << iterations;
  636. GLfloat black[4] = {0.f, 0.f, 0.f, 1.f};
  637. GLfloat white[4] = {1.f, 1.f, 1.f, 1.f};
  638. // Handle inverted colors.
  639. if (colorInvert)
  640.     glClearColor (black[0], black[1], black[2], black[3]);
  641. else
  642.     glClearColor (white[0], white[1], white[2], white[3]);
  643. // Handle non line mode renderMode settings.
  644. if (renderMode == twoDR_clouds)
  645. return (renderCloudMap ());
  646. else if (renderMode == twoDR_teximage)
  647. return (renderTeximageMap ());
  648. else if (renderMode == twoDR_rendered)
  649. return (renderFullImage ());
  650. // Shouldn't take too long, unless drawing huge
  651. // AA scenes, but what the heck...
  652. CWaitCursor hourglass;
  653. glMatrixMode (GL_PROJECTION);
  654.     glLoadIdentity ();
  655. if (arrayIs2D)
  656. // Needs to be identical to the same call in renderFullScene.
  657.     gluPerspective (60., aspectRatio, .1, 15.0);
  658. else
  659. glOrtho (-aspectRatio, aspectRatio, -1., 1., 1., -1.);
  660.     glMatrixMode (GL_MODELVIEW);
  661.     glLoadIdentity ();
  662. if (arrayIs2D) {
  663.     glTranslatef (0.f, yTrans, zTrans);
  664. glRotatef (yRot, 0.f, 1.f, 0.f);
  665. }
  666. glPushAttrib (0xffffffff);
  667. glDisable (GL_DEPTH_TEST);
  668. glDisable (GL_LIGHTING);
  669. if (colorInvert)
  670. glColor4fv (white);
  671. else
  672. glColor4fv (black);
  673. if (aaLines) {
  674. glEnable (GL_LINE_SMOOTH);
  675. glEnable (GL_BLEND);
  676. glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  677. }
  678. else {
  679. glDisable (GL_LINE_SMOOTH);
  680. glDisable (GL_BLEND);
  681. }
  682.     
  683. glClear (GL_COLOR_BUFFER_BIT |
  684. GL_DEPTH_BUFFER_BIT);
  685. if (arrayIs2D) {
  686. float x, z;
  687. UINT i, j;
  688. // validate surface
  689. if (surfFA && surfFAdirty) {
  690. freeFractArray (surfFA);
  691. surfFA = NULL;
  692. }
  693. if (!surfFA) {
  694. surfFA = alloc2DFractArray (size);
  695. if (surfFA==NULL) return (FALSE);
  696. fill2DFractArray (surfFA, size, randomSeed,
  697. DEF_HEIGHT_SCALE, surfaceH);
  698. surfFAdirty = FALSE;
  699. }
  700. z = -1.f * (float) (tile-1);
  701. for (i=0; i<tile; i++) {
  702. x = -1.f * (float) (tile-1);
  703. for (j=0; j<tile; j++) {
  704. glPushMatrix ();
  705. glTranslatef (x, 0.f, z);
  706. draw2DFractArrayAsLines (surfFA, size);
  707. glPopMatrix ();
  708. x += 2.f;
  709. }
  710. z += 2.f;
  711. }
  712. }
  713. else {
  714. float x;
  715. UINT i;
  716.     float *fa;
  717. // Always validate and free 1D array.
  718. // We won't be doing any realtime transformations on it.
  719. fa = alloc1DFractArray (size);
  720. if (fa==NULL) return (FALSE);
  721. fill1DFractArray (fa, size, randomSeed,
  722. DEF_HEIGHT_SCALE, surfaceH);
  723. x = -1.f * (float) (tile-1);
  724. for (i=0; i<tile; i++) {
  725. glPushMatrix ();
  726. glTranslatef (x, 0.f, 0.f);
  727. draw1DFractArrayAsLines (fa, size);
  728. glPopMatrix ();
  729. x += 2.f;
  730. }
  731. freeFractArray (fa);
  732. }
  733. glFlush();
  734. glPopAttrib ();
  735. return (TRUE);
  736. }
  737. // OnViewOptions
  738. //
  739. // Handles dialog box paramter changes and records them in the View.
  740. void CFractalExampleView::OnViewOptions() 
  741. {
  742. CFractalOptionsDlg dlg;
  743. CString oneD = "1D midpoint displacement";
  744. CString twoDLines = "2D mesh / lines";
  745. CString twoDClouds = "2D mesh / clouds";
  746. CString twoDTeximage = "2D mesh / teximage";
  747. CString twoDRendered = "2D mesh / rendered";
  748. dlg.m_invert = colorInvert;
  749. dlg.m_aaLines = aaLines;
  750. dlg.m_textureLinear = textureLinear;
  751. dlg.m_randomSeed = randomSeed;
  752. dlg.m_tile = tile;
  753. dlg.m_iterations = iterations;
  754. dlg.m_cloudIter = cloudIter;
  755. dlg.m_teximageIter = teximageIter;
  756. if (!arrayIs2D)
  757. dlg.m_renderType = oneD;
  758. else if (renderMode == twoDR_lines)
  759. dlg.m_renderType = twoDLines;
  760. else if (renderMode == twoDR_clouds)
  761. dlg.m_renderType = twoDClouds;
  762. else if (renderMode == twoDR_teximage)
  763. dlg.m_renderType = twoDTeximage;
  764. else if (renderMode == twoDR_rendered)
  765. dlg.m_renderType = twoDRendered;
  766. dlg.m_cloudH = cloudH;
  767. dlg.m_surfaceH = surfaceH;
  768. dlg.m_teximageH = teximageH;
  769. if (dlg.DoModal () == IDOK) {
  770. teximageFAdirty = (teximageFAdirty ||
  771. (teximageH != dlg.m_teximageH) ||
  772. (randomSeed != dlg.m_randomSeed) ||
  773. (teximageIter != dlg.m_teximageIter));
  774. surfFAdirty = (surfFAdirty ||
  775. (surfaceH != dlg.m_surfaceH) ||
  776. (randomSeed != dlg.m_randomSeed) ||
  777. (iterations != dlg.m_iterations));
  778. cloudFAdirty = (cloudFAdirty ||
  779. (cloudH != dlg.m_cloudH) ||
  780. (randomSeed != dlg.m_randomSeed) ||
  781. (cloudIter != dlg.m_cloudIter));
  782. colorInvert = dlg.m_invert;
  783. aaLines = dlg.m_aaLines;
  784. textureLinear = dlg.m_textureLinear;
  785. randomSeed = dlg.m_randomSeed;
  786. tile = dlg.m_tile;
  787. iterations = dlg.m_iterations;
  788. cloudIter = dlg.m_cloudIter;
  789. teximageIter = dlg.m_teximageIter;
  790. arrayIs2D = !(dlg.m_renderType == oneD);
  791. if (dlg.m_renderType == twoDClouds)
  792. renderMode = twoDR_clouds;
  793. else if (dlg.m_renderType == twoDTeximage)
  794. renderMode = twoDR_teximage;
  795. else if (dlg.m_renderType == twoDRendered)
  796. renderMode = twoDR_rendered;
  797. else // default: if (dlg.m_renderType == twoDLines)
  798. renderMode = twoDR_lines;
  799. cloudH = dlg.m_cloudH;
  800. surfaceH = dlg.m_surfaceH;
  801. teximageH = dlg.m_teximageH;
  802. OnDraw ( GetDC() );
  803. }
  804. }
  805. //OnSize
  806. //
  807. // Handles resize events. Records width, height, and 
  808. //aspectRatio in the View. void CFractalExampleView::OnSize (UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy);
  809. if (0 >= cx || 0 >= cy)
  810. return;
  811. currentWidth = cx;
  812. currentHeight = cy;
  813. glViewport(0, 0, cx, cy);
  814. // compute the aspect ratio
  815. // this will keep all dimension scales equal
  816. aspectRatio = (float)cx/(float)cy;
  817. }
  818. // OnKeyDown
  819. //
  820. // Translates keypress events to rotations or translations
  821. // which are then recorded in the View object.
  822. void CFractalExampleView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
  823. {
  824. BOOL needRedraw = FALSE;
  825. switch (nChar) {
  826. case VK_LEFT:
  827. yRot += 3.f;
  828. needRedraw = TRUE;
  829. break;
  830. case VK_UP:
  831. if (shiftKeyStatus)
  832. yTrans += .05f;
  833. else
  834. zTrans += .05f;
  835. needRedraw = TRUE;
  836. break;
  837. case VK_RIGHT:
  838. yRot -= 3.f;
  839. needRedraw = TRUE;
  840. break;
  841. case VK_DOWN:
  842. if (shiftKeyStatus)
  843. yTrans -= .05f;
  844. else
  845. zTrans -= .05f;
  846. needRedraw = TRUE;
  847. break;
  848. case VK_SHIFT:
  849. shiftKeyStatus = TRUE;
  850. return;
  851. }
  852. if (needRedraw) {
  853. OnDraw ( GetDC() );
  854. return;
  855. }
  856. else
  857. // Let parent class handle other keys.
  858. COpenGLView::OnKeyDown(nChar, nRepCnt, nFlags);
  859. }
  860. // OnKeyUp
  861. //
  862. // Tracks state of the shift key. There's got to be a better
  863. // way to tell whether a key is shifted or not than by
  864. // tracking press and release events on the shift key.
  865. void CFractalExampleView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
  866. {
  867. switch (nChar) {
  868. case VK_SHIFT:
  869. shiftKeyStatus = FALSE;
  870. return;
  871. }
  872. COpenGLView::OnKeyUp(nChar, nRepCnt, nFlags);
  873. }
  874. // OnDestroy
  875. //
  876. // Free all that memory.
  877. void CFractalExampleView::OnDestroy() 
  878. {
  879. COpenGLView::OnDestroy();
  880. if (surfFA) 
  881. freeFractArray (surfFA);
  882. if (teximageFA) 
  883. freeFractArray (teximageFA);
  884. if (cloudFA)
  885. freeFractArray (cloudFA);
  886. }