1 //
2 // "$Id$"
3 //
4 // Fractal drawing demo for the Fast Light Tool Kit (FLTK).
5 //
6 // This is a GLUT demo program, with modifications to
7 // demonstrate how to add FLTK controls to a GLUT program.   The GLUT
8 // code is unchanged except for the end (search for FLTK to find changes).
9 //
10 // Copyright 1998-2016 by Bill Spitzak and others.
11 //
12 // This library is free software. Distribution and use rights are outlined in
13 // the file "COPYING" which should have been included with this file.  If this
14 // file is missing or damaged, see the license at:
15 //
16 //     http://www.fltk.org/COPYING.php
17 //
18 // Please report all bugs and problems on the following page:
19 //
20 //     http://www.fltk.org/str.php
21 //
22 
23 #include <config.h>
24 #if !HAVE_GL || !HAVE_GL_GLU_H
25 #include <FL/Fl.H>
26 #include <FL/fl_message.H>
main(int,char **)27 int main(int, char**) {
28   fl_alert("This demo does not work without GL and GLU");
29   return 1;
30 }
31 #else
32 /*
33  * To compile: cc -o fractals fractals.c -lGL -lGLU -lX11 -lglut -lXmu -lm
34  *
35  * Usage: fractals
36  *
37  * Homework 6, Part 2: fractal mountains and fractal trees
38  * (Pretty Late)
39  *
40  * Draws fractal mountains and trees -- and an island of mountains in water
41  * (I tried having trees on the island but it didn't work too well.)
42  *
43  * Two viewer modes: polar and flying (both restrained to y>0 for up vector).
44  * Keyboard 0->9 and +/- control speed when flying.
45  *
46  * Only keyboard commands are 0-9 and +/- for speed in flying mode.
47  *
48  * Fog would make the island look much better, but I couldn't get it to work
49  * correctly.  Would line up on -z axis not from eye.
50  *
51  * Philip Winston - 3/4/95
52  * pwinston@hmc.edu
53  * http://www.cs.hmc.edu/people/pwinston
54  *
55  */
56 
57 #include <FL/glut.H>
58 #include <FL/glu.h>
59 
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <math.h>
63 #include <limits.h>           /* ULONG_MAX is defined here */
64 #include <float.h>            /* FLT_MAX is atleast defined here */
65 
66 #include <time.h>  /* for random seed */
67 
68 #include "fracviewer.h"
69 
70 #if defined(WIN32) || defined(__EMX__)
71 #  define drand48() (((float) rand())/((float) RAND_MAX))
72 #  define srand48(x) (srand((x)))
73 #elif defined __APPLE__
74 #  define drand48() (((float) rand())/((float) RAND_MAX))
75 #  define srand48(x) (srand((x)))
76 #endif
77 
78 typedef enum { NOTALLOWED, MOUNTAIN, TREE, ISLAND, BIGMTN, STEM, LEAF,
79                MOUNTAIN_MAT, WATER_MAT, LEAF_MAT, TREE_MAT, STEMANDLEAVES,
80                AXES } DisplayLists;
81 
82 #define MAXLEVEL 8
83 
84 int Rebuild = 1,        /* Rebuild display list in next display? */
85     fractal = TREE,     /* What fractal are we building */
86     Level   = 4;        /* levels of recursion for fractals */
87 
88 int DrawAxes = 0;
89 
90 /***************************************************************/
91 /************************* VECTOR JUNK *************************/
92 /***************************************************************/
93 
94   /* print vertex to stderr */
printvert(float v[3])95 void printvert(float v[3])
96 {
97   fprintf(stderr, "(%f, %f, %f)\n", v[0], v[1], v[2]);
98 }
99 
100 #if 0	// removed for FL, it is in fracviewer.c
101   /* normalizes v */
102 void normalize(GLfloat v[3])
103 {
104   GLfloat d = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
105 
106   if (d == 0)
107     fprintf(stderr, "Zero length vector in normalize\n");
108   else
109     v[0] /= d; v[1] /= d; v[2] /= d;
110 }
111 
112   /* calculates a normalized crossproduct to v1, v2 */
113 void ncrossprod(float v1[3], float v2[3], float cp[3])
114 {
115   cp[0] = v1[1]*v2[2] - v1[2]*v2[1];
116   cp[1] = v1[2]*v2[0] - v1[0]*v2[2];
117   cp[2] = v1[0]*v2[1] - v1[1]*v2[0];
118   normalize(cp);
119 }
120 #endif
121 
122   /* calculates normal to the triangle designated by v1, v2, v3 */
triagnormal(float v1[3],float v2[3],float v3[3],float norm[3])123 void triagnormal(float v1[3], float v2[3], float v3[3], float norm[3])
124 {
125   float vec1[3], vec2[3];
126 
127   vec1[0] = v3[0] - v1[0];  vec2[0] = v2[0] - v1[0];
128   vec1[1] = v3[1] - v1[1];  vec2[1] = v2[1] - v1[1];
129   vec1[2] = v3[2] - v1[2];  vec2[2] = v2[2] - v1[2];
130 
131   ncrossprod(vec2, vec1, norm);
132 }
133 
xzlength(float v1[3],float v2[3])134 float xzlength(float v1[3], float v2[3])
135 {
136   return sqrt((v1[0] - v2[0])*(v1[0] - v2[0]) +
137               (v1[2] - v2[2])*(v1[2] - v2[2]));
138 }
139 
xzslope(float v1[3],float v2[3])140 float xzslope(float v1[3], float v2[3])
141 {
142   return ((v1[0] != v2[0]) ? ((v1[2] - v2[2]) / (v1[0] - v2[0]))
143 	                   : FLT_MAX);
144 }
145 
146 
147 /***************************************************************/
148 /************************ MOUNTAIN STUFF ***********************/
149 /***************************************************************/
150 
151 GLfloat DispFactor[MAXLEVEL];  /* Array of what to multiply random number
152 				  by for a given level to get midpoint
153 				  displacement  */
154 GLfloat DispBias[MAXLEVEL];  /* Array of what to add to random number
155 				before multiplying it by DispFactor */
156 
157 #define NUMRANDS 191
158 float RandTable[NUMRANDS];  /* hash table of random numbers so we can
159 			       raise the same midpoints by the same amount */
160 
161          /* The following are for permitting an edge of a moutain to be   */
162          /* pegged so it won't be displaced up or down.  This makes it    */
163          /* easier to setup scenes and makes a single moutain look better */
164 
165 GLfloat Verts[3][3],    /* Vertices of outside edges of mountain */
166         Slopes[3];      /* Slopes between these outside edges */
167 int     Pegged[3];      /* Is this edge pegged or not */
168 
169  /*
170   * Comes up with a new table of random numbers [0,1)
171   */
InitRandTable(unsigned int seed)172 void InitRandTable(unsigned int seed)
173 {
174   int i;
175 
176   srand48((long) seed);
177   for (i = 0; i < NUMRANDS; i++)
178     RandTable[i] = drand48() - 0.5;
179 }
180 
181   /* calculate midpoint and displace it if required */
Midpoint(GLfloat mid[3],GLfloat v1[3],GLfloat v2[3],int edge,int level)182 void Midpoint(GLfloat mid[3], GLfloat v1[3], GLfloat v2[3],
183 	      int edge, int level)
184 {
185   unsigned hash;
186 
187   mid[0] = (v1[0] + v2[0]) / 2;
188   mid[1] = (v1[1] + v2[1]) / 2;
189   mid[2] = (v1[2] + v2[2]) / 2;
190   if (!Pegged[edge] || (fabs(xzslope(Verts[edge], mid)
191                         - Slopes[edge]) > 0.00001)) {
192     srand48((int)((v1[0]+v2[0])*23344));
193     hash = unsigned(drand48() * 7334334);
194     srand48((int)((v2[2]+v1[2])*43433));
195     hash = (unsigned)(drand48() * 634344 + hash) % NUMRANDS;
196     mid[1] += ((RandTable[hash] + DispBias[level]) * DispFactor[level]);
197   }
198 }
199 
200   /*
201    * Recursive moutain drawing routine -- from lecture with addition of
202    * allowing an edge to be pegged.  This function requires the above
203    * globals to be set, as well as the Level global for fractal level
204    */
205 static float cutoff = -1;
206 
FMR(GLfloat v1[3],GLfloat v2[3],GLfloat v3[3],int level)207 void FMR(GLfloat v1[3], GLfloat v2[3], GLfloat v3[3], int level)
208 {
209   if (level == Level) {
210     GLfloat norm[3];
211     if (v1[1] <= cutoff && v2[1]<=cutoff && v3[1]<=cutoff) return;
212     triagnormal(v1, v2, v3, norm);
213     glNormal3fv(norm);
214     glVertex3fv(v1);
215     glVertex3fv(v2);
216     glVertex3fv(v3);
217 
218   } else {
219     GLfloat m1[3], m2[3], m3[3];
220 
221     Midpoint(m1, v1, v2, 0, level);
222     Midpoint(m2, v2, v3, 1, level);
223     Midpoint(m3, v3, v1, 2, level);
224 
225     FMR(v1, m1, m3, level + 1);
226     FMR(m1, v2, m2, level + 1);
227     FMR(m3, m2, v3, level + 1);
228     FMR(m1, m2, m3, level + 1);
229   }
230 }
231 
232  /*
233   * sets up lookup tables and calls recursive mountain function
234   */
FractalMountain(GLfloat v1[3],GLfloat v2[3],GLfloat v3[3],int pegged[3])235 void FractalMountain(GLfloat v1[3], GLfloat v2[3], GLfloat v3[3],
236                      int pegged[3])
237 {
238   GLfloat lengths[MAXLEVEL];
239   GLfloat fraction[8] = { 0.3, 0.3, 0.4, 0.2, 0.3, 0.2, 0.4, 0.4  };
240   GLfloat bias[8]     = { 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1  };
241   int i;
242   float avglen = (xzlength(v1, v2) +
243                   xzlength(v2, v3) +
244 		  xzlength(v3, v1) / 3);
245 
246   for (i = 0; i < 3; i++) {
247     Verts[0][i] = v1[i];      /* set mountain vertex globals */
248     Verts[1][i] = v2[i];
249     Verts[2][i] = v3[i];
250     Pegged[i] = pegged[i];
251   }
252 
253   Slopes[0] = xzslope(Verts[0], Verts[1]);   /* set edge slope globals */
254   Slopes[1] = xzslope(Verts[1], Verts[2]);
255   Slopes[2] = xzslope(Verts[2], Verts[0]);
256 
257   lengths[0] = avglen;
258   for (i = 1; i < Level; i++) {
259     lengths[i] = lengths[i-1]/2;     /* compute edge length for each level */
260   }
261 
262   for (i = 0; i < Level; i++) {     /* DispFactor and DispBias arrays */
263     DispFactor[i] = (lengths[i] * ((i <= 7) ? fraction[i] : fraction[7]));
264     DispBias[i]   = ((i <= 7) ? bias[i] : bias[7]);
265   }
266 
267   glBegin(GL_TRIANGLES);
268     FMR(v1, v2, v3, 0);    /* issues no GL but vertex calls */
269   glEnd();
270 }
271 
272  /*
273   * draw a mountain and build the display list
274   */
CreateMountain(void)275 void CreateMountain(void)
276 {
277   GLfloat v1[3] = { 0, 0, -1 }, v2[3] = { -1, 0, 1 }, v3[3] = { 1, 0, 1 };
278   int pegged[3] = { 1, 1, 1 };
279 
280   glNewList(MOUNTAIN, GL_COMPILE);
281   glPushAttrib(GL_LIGHTING_BIT);
282     glCallList(MOUNTAIN_MAT);
283     FractalMountain(v1, v2, v3, pegged);
284   glPopAttrib();
285   glEndList();
286 }
287 
288   /*
289    * new random numbers to make a different moutain
290    */
NewMountain(void)291 void NewMountain(void)
292 {
293   InitRandTable(time(NULL));
294 }
295 
296 /***************************************************************/
297 /***************************** TREE ****************************/
298 /***************************************************************/
299 
300 long TreeSeed;   /* for srand48 - remember so we can build "same tree"
301                      at a different level */
302 
303  /*
304   * recursive tree drawing thing, fleshed out from class notes pseudocode
305   */
FractalTree(int level,long level_seed)306 void FractalTree(int level, long level_seed)
307 {
308   if (level == Level) {
309       glPushMatrix();
310         glRotatef(drand48()*180, 0, 1, 0);
311         glCallList(STEMANDLEAVES);
312       glPopMatrix();
313   } else {
314     glCallList(STEM);
315     glPushMatrix();
316     glRotatef(drand48()*180, 0, 1, 0);
317     glTranslatef(0, 1, 0);
318     glScalef(0.7, 0.7, 0.7);
319 
320       srand48(level_seed+1);
321       glPushMatrix();
322         glRotatef(110 + drand48()*40, 0, 1, 0);
323         glRotatef(30 + drand48()*20, 0, 0, 1);
324         FractalTree(level + 1, level_seed+4);
325       glPopMatrix();
326 
327       srand48(level_seed+2);
328       glPushMatrix();
329         glRotatef(-130 + drand48()*40, 0, 1, 0);
330         glRotatef(30 + drand48()*20, 0, 0, 1);
331         FractalTree(level + 1, level_seed+5);
332       glPopMatrix();
333 
334       srand48(level_seed+3);
335       glPushMatrix();
336         glRotatef(-20 + drand48()*40, 0, 1, 0);
337         glRotatef(30 + drand48()*20, 0, 0, 1);
338         FractalTree(level + 1, level_seed+6);
339       glPopMatrix();
340 
341     glPopMatrix();
342   }
343 }
344 
345   /*
346    * Create display lists for a leaf, a set of leaves, and a stem
347    */
CreateTreeLists(void)348 void CreateTreeLists(void)
349 {
350   GLUquadricObj *cylquad = gluNewQuadric();
351   int i;
352 
353   glNewList(STEM, GL_COMPILE);
354   glPushMatrix();
355     glRotatef(-90, 1, 0, 0);
356     gluCylinder(cylquad, 0.1, 0.08, 1, 10, 2 );
357   glPopMatrix();
358   glEndList();
359 
360   glNewList(LEAF, GL_COMPILE);  /* I think this was jeff allen's leaf idea */
361     glBegin(GL_TRIANGLES);
362       glNormal3f(-0.1, 0, 0.25);  /* not normalized */
363       glVertex3f(0, 0, 0);
364       glVertex3f(0.25, 0.25, 0.1);
365       glVertex3f(0, 0.5, 0);
366 
367       glNormal3f(0.1, 0, 0.25);
368       glVertex3f(0, 0, 0);
369       glVertex3f(0, 0.5, 0);
370       glVertex3f(-0.25, 0.25, 0.1);
371     glEnd();
372   glEndList();
373 
374   glNewList(STEMANDLEAVES, GL_COMPILE);
375   glPushMatrix();
376   glPushAttrib(GL_LIGHTING_BIT);
377     glCallList(STEM);
378     glCallList(LEAF_MAT);
379     for(i = 0; i < 3; i++) {
380       glTranslatef(0, 0.333, 0);
381       glRotatef(90, 0, 1, 0);
382       glPushMatrix();
383         glRotatef(0, 0, 1, 0);
384         glRotatef(50, 1, 0, 0);
385         glCallList(LEAF);
386       glPopMatrix();
387       glPushMatrix();
388         glRotatef(180, 0, 1, 0);
389         glRotatef(60, 1, 0, 0);
390         glCallList(LEAF);
391       glPopMatrix();
392     }
393   glPopAttrib();
394   glPopMatrix();
395   glEndList();
396 
397   gluDeleteQuadric(cylquad);
398 }
399 
400  /*
401   * draw and build display list for tree
402   */
CreateTree(void)403 void CreateTree(void)
404 {
405   srand48(TreeSeed);
406 
407   glNewList(TREE, GL_COMPILE);
408     glPushMatrix();
409     glPushAttrib(GL_LIGHTING_BIT);
410     glCallList(TREE_MAT);
411     glTranslatef(0, -1, 0);
412     FractalTree(0, TreeSeed);
413     glPopAttrib();
414     glPopMatrix();
415   glEndList();
416 }
417 
418  /*
419   * new seed for a new tree (groan)
420   */
NewTree(void)421 void NewTree(void)
422 {
423   TreeSeed = time(NULL);
424 }
425 
426 /***************************************************************/
427 /*********************** FRACTAL PLANET ************************/
428 /***************************************************************/
429 
CreateIsland(void)430 void CreateIsland(void)
431 {
432   cutoff = .06;
433   CreateMountain();
434   cutoff = -1;
435   glNewList(ISLAND, GL_COMPILE);
436   glPushAttrib(GL_LIGHTING_BIT);
437   glMatrixMode(GL_MODELVIEW);
438   glPushMatrix();
439     glCallList(WATER_MAT);
440 
441     glBegin(GL_QUADS);
442       glNormal3f(0, 1, 0);
443       glVertex3f(10, 0.01, 10);
444       glVertex3f(10, 0.01, -10);
445       glVertex3f(-10, 0.01, -10);
446       glVertex3f(-10, 0.01, 10);
447     glEnd();
448 
449     glPushMatrix();
450     glTranslatef(0, -0.1, 0);
451     glCallList(MOUNTAIN);
452     glPopMatrix();
453 
454     glPushMatrix();
455     glRotatef(135, 0, 1, 0);
456     glTranslatef(0.2, -0.15, -0.4);
457     glCallList(MOUNTAIN);
458     glPopMatrix();
459 
460     glPushMatrix();
461     glRotatef(-60, 0, 1, 0);
462     glTranslatef(0.7, -0.07, 0.5);
463     glCallList(MOUNTAIN);
464     glPopMatrix();
465 
466     glPushMatrix();
467     glRotatef(-175, 0, 1, 0);
468     glTranslatef(-0.7, -0.05, -0.5);
469     glCallList(MOUNTAIN);
470     glPopMatrix();
471 
472     glPushMatrix();
473     glRotatef(165, 0, 1, 0);
474     glTranslatef(-0.9, -0.12, 0.0);
475     glCallList(MOUNTAIN);
476     glPopMatrix();
477 
478   glPopMatrix();
479   glPopAttrib();
480   glEndList();
481 }
482 
483 
NewFractals(void)484 void NewFractals(void)
485 {
486   NewMountain();
487   NewTree();
488 }
489 
Create(int fract)490 void Create(int fract)
491 {
492   switch(fract) {
493     case MOUNTAIN:
494       CreateMountain();
495       break;
496     case TREE:
497       CreateTree();
498       break;
499     case ISLAND:
500       CreateIsland();
501       break;
502   }
503 }
504 
505 
506 
507 /***************************************************************/
508 /**************************** OPENGL ***************************/
509 /***************************************************************/
510 
511 
SetupMaterials(void)512 void SetupMaterials(void)
513 {
514   GLfloat mtn_ambuse[] =   { 0.426, 0.256, 0.108, 1.0 };
515   GLfloat mtn_specular[] = { 0.394, 0.272, 0.167, 1.0 };
516   GLfloat mtn_shininess[] = { 10 };
517 
518   GLfloat water_ambuse[] =   { 0.0, 0.1, 0.5, 1.0 };
519   GLfloat water_specular[] = { 0.0, 0.1, 0.5, 1.0 };
520   GLfloat water_shininess[] = { 10 };
521 
522   GLfloat tree_ambuse[] =   { 0.4, 0.25, 0.1, 1.0 };
523   GLfloat tree_specular[] = { 0.0, 0.0, 0.0, 1.0 };
524   GLfloat tree_shininess[] = { 0 };
525 
526   GLfloat leaf_ambuse[] =   { 0.0, 0.8, 0.0, 1.0 };
527   GLfloat leaf_specular[] = { 0.0, 0.8, 0.0, 1.0 };
528   GLfloat leaf_shininess[] = { 10 };
529 
530   glNewList(MOUNTAIN_MAT, GL_COMPILE);
531     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mtn_ambuse);
532     glMaterialfv(GL_FRONT, GL_SPECULAR, mtn_specular);
533     glMaterialfv(GL_FRONT, GL_SHININESS, mtn_shininess);
534   glEndList();
535 
536   glNewList(WATER_MAT, GL_COMPILE);
537     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, water_ambuse);
538     glMaterialfv(GL_FRONT, GL_SPECULAR, water_specular);
539     glMaterialfv(GL_FRONT, GL_SHININESS, water_shininess);
540   glEndList();
541 
542   glNewList(TREE_MAT, GL_COMPILE);
543     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, tree_ambuse);
544     glMaterialfv(GL_FRONT, GL_SPECULAR, tree_specular);
545     glMaterialfv(GL_FRONT, GL_SHININESS, tree_shininess);
546   glEndList();
547 
548   glNewList(LEAF_MAT, GL_COMPILE);
549     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, leaf_ambuse);
550     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, leaf_specular);
551     glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, leaf_shininess);
552   glEndList();
553 }
554 
myGLInit(void)555 void myGLInit(void)
556 {
557   GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
558   GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
559   GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
560   GLfloat light_position[] = { 0.0, 0.3, 0.3, 0.0 };
561 
562   GLfloat lmodel_ambient[] = { 0.4, 0.4, 0.4, 1.0 };
563 
564   glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
565   glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
566   glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
567   glLightfv(GL_LIGHT0, GL_POSITION, light_position);
568 
569   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
570 
571   glEnable(GL_LIGHTING);
572   glEnable(GL_LIGHT0);
573 
574   glDepthFunc(GL_LEQUAL);
575   glEnable(GL_DEPTH_TEST);
576 
577   glEnable(GL_NORMALIZE);
578 #if 0
579   glEnable(GL_CULL_FACE);
580   glCullFace(GL_BACK);
581 #endif
582 
583   glShadeModel(GL_SMOOTH);
584 #if 0
585   glEnable(GL_BLEND);
586   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
587 #endif
588 
589   SetupMaterials();
590   CreateTreeLists();
591 
592   glFlush();
593 }
594 
595 /***************************************************************/
596 /************************ GLUT STUFF ***************************/
597 /***************************************************************/
598 
599 int winwidth = 1;
600 int winheight = 1;
601 
reshape(int w,int h)602 void reshape(int w, int h)
603 {
604   glViewport(0,0,w,h);
605 
606   winwidth  = w;
607   winheight = h;
608 }
609 
display(void)610 void display(void)
611 {
612   time_t curtime;
613   char buf[255];
614   static time_t fpstime = 0;
615   static int fpscount = 0;
616   static int fps = 0;
617 
618   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
619 
620   glMatrixMode(GL_PROJECTION);
621   glLoadIdentity();
622   gluPerspective(60.0, (GLdouble)winwidth/winheight, 0.01, 100);
623   agvViewTransform();
624 
625   glMatrixMode(GL_MODELVIEW);
626   glLoadIdentity();
627 
628   if (Rebuild) {
629     Create(fractal);
630     Rebuild = 0;
631   }
632 
633   glCallList(fractal);
634 
635   if (DrawAxes)
636     glCallList(AXES);
637 
638   glMatrixMode(GL_PROJECTION);
639   glLoadIdentity();
640   gluOrtho2D(0.0, winwidth, 0.0, winheight);
641 
642   sprintf(buf, "FPS=%d", fps);
643   glColor3f(1.0f, 1.0f, 1.0f);
644   gl_font(FL_HELVETICA, 12);
645   gl_draw(buf, 10, 10);
646 
647   //
648   // Use glFinish() instead of glFlush() to avoid getting many frames
649   // ahead of the display (problem with some Linux OpenGL implementations...)
650   //
651 
652   glFinish();
653 
654   // Update frames-per-second
655   fpscount ++;
656   curtime = time(NULL);
657   if ((curtime - fpstime) >= 2)
658   {
659     fps      = (fps + fpscount / (curtime - fpstime)) / 2;
660     fpstime  = curtime;
661     fpscount = 0;
662   }
663 }
664 
visible(int v)665 void visible(int v)
666 {
667   if (v == GLUT_VISIBLE)
668     agvSetAllowIdle(1);
669   else {
670     glutIdleFunc(NULL);
671     agvSetAllowIdle(0);
672   }
673 }
674 
menuuse(int v)675 void menuuse(int v)
676 {
677   if (v == GLUT_MENU_NOT_IN_USE)
678     agvSetAllowIdle(1);
679   else {
680     glutIdleFunc(NULL);
681     agvSetAllowIdle(0);
682   }
683 }
684 
685 /***************************************************************/
686 /******************* MENU SETUP & HANDLING *********************/
687 /***************************************************************/
688 
689 typedef enum { MENU_QUIT, MENU_RAND, MENU_MOVE, MENU_AXES } MenuChoices;
690 
setlevel(int value)691 void setlevel(int value)
692 {
693   Level = value;
694   Rebuild = 1;
695   glutPostRedisplay();
696 }
697 
choosefract(int value)698 void choosefract(int value)
699 {
700   fractal = value;
701   Rebuild = 1;
702   glutPostRedisplay();
703 }
704 
handlemenu(int value)705 void handlemenu(int value)
706 {
707   switch (value) {
708     case MENU_QUIT:
709       exit(0);
710       break;
711     case MENU_RAND:
712       NewFractals();
713       Rebuild = 1;
714       glutPostRedisplay();
715       break;
716     case MENU_AXES:
717       DrawAxes = !DrawAxes;
718       glutPostRedisplay();
719       break;
720     }
721 }
722 
MenuInit(void)723 void MenuInit(void)
724 {
725   int submenu3, submenu2, submenu1;
726 
727   submenu1 = glutCreateMenu(setlevel);
728   glutAddMenuEntry((char *)"0", 0);  glutAddMenuEntry((char *)"1", 1);
729   glutAddMenuEntry((char *)"2", 2);  glutAddMenuEntry((char *)"3", 3);
730   glutAddMenuEntry((char *)"4", 4);  glutAddMenuEntry((char *)"5", 5);
731   glutAddMenuEntry((char *)"6", 6);  glutAddMenuEntry((char *)"7", 7);
732   glutAddMenuEntry((char *)"8", 8);
733 
734   submenu2 = glutCreateMenu(choosefract);
735   glutAddMenuEntry((char *)"Moutain", MOUNTAIN);
736   glutAddMenuEntry((char *)"Tree", TREE);
737   glutAddMenuEntry((char *)"Island", ISLAND);
738 
739   submenu3 = glutCreateMenu(agvSwitchMoveMode);
740   glutAddMenuEntry((char *)"Flying", FLYING);
741   glutAddMenuEntry((char *)"Polar", POLAR);
742 
743   glutCreateMenu(handlemenu);
744   glutAddSubMenu((char *)"Level", submenu1);
745   glutAddSubMenu((char *)"Fractal", submenu2);
746   glutAddSubMenu((char *)"Movement", submenu3);
747   glutAddMenuEntry((char *)"New Fractal",      MENU_RAND);
748   glutAddMenuEntry((char *)"Toggle Axes", MENU_AXES);
749   glutAddMenuEntry((char *)"Quit",             MENU_QUIT);
750   glutAttachMenu(GLUT_RIGHT_BUTTON);
751 }
752 
753 
754 /***************************************************************/
755 /**************************** MAIN *****************************/
756 /***************************************************************/
757 
758 // FLTK-style callbacks to Glut menu callback translators:
setlevel(Fl_Widget *,void * value)759 void setlevel(Fl_Widget*, void *value) {setlevel(fl_intptr_t(value));}
760 
choosefract(Fl_Widget *,void * value)761 void choosefract(Fl_Widget*, void *value) {choosefract(fl_intptr_t(value));}
762 
handlemenu(Fl_Widget *,void * value)763 void handlemenu(Fl_Widget*, void *value) {handlemenu(fl_intptr_t(value));}
764 
765 #include <FL/Fl_Button.H>
766 #include <FL/Fl_Group.H>
767 #include <FL/Fl_Window.H>
768 
main(int argc,char ** argv)769 int main(int argc, char** argv)
770 {
771   Fl::use_high_res_GL(1);
772 //  glutInit(&argc, argv); // this line removed for FLTK
773 
774   // create FLTK window:
775   Fl_Window window(512+20, 512+100);
776   window.resizable(window);
777 
778   // create a bunch of buttons:
779   Fl_Group *g = new Fl_Group(110,50,400-110,30,"Level:");
780   g->align(FL_ALIGN_LEFT);
781   g->begin();
782   Fl_Button *b;
783   b = new Fl_Button(110,50,30,30,"0"); b->callback(setlevel,(void*)0);
784   b = new Fl_Button(140,50,30,30,"1"); b->callback(setlevel,(void*)1);
785   b = new Fl_Button(170,50,30,30,"2"); b->callback(setlevel,(void*)2);
786   b = new Fl_Button(200,50,30,30,"3"); b->callback(setlevel,(void*)3);
787   b = new Fl_Button(230,50,30,30,"4"); b->callback(setlevel,(void*)4);
788   b = new Fl_Button(260,50,30,30,"5"); b->callback(setlevel,(void*)5);
789   b = new Fl_Button(290,50,30,30,"6"); b->callback(setlevel,(void*)6);
790   b = new Fl_Button(320,50,30,30,"7"); b->callback(setlevel,(void*)7);
791   b = new Fl_Button(350,50,30,30,"8"); b->callback(setlevel,(void*)8);
792   g->end();
793 
794   b = new Fl_Button(400,50,100,30,"New Fractal"); b->callback(handlemenu,(void*)MENU_RAND);
795 
796   b = new Fl_Button( 10,10,100,30,"Mountain"); b->callback(choosefract,(void*)MOUNTAIN);
797   b = new Fl_Button(110,10,100,30,"Tree"); b->callback(choosefract,(void*)TREE);
798   b = new Fl_Button(210,10,100,30,"Island"); b->callback(choosefract,(void*)ISLAND);
799   b = new Fl_Button(400,10,100,30,"Quit"); b->callback(handlemenu,(void*)MENU_QUIT);
800 
801 
802   window.show(argc,argv); // glut will die unless parent window visible
803   window.begin(); // this will cause Glut window to be a child
804   glutInitWindowSize(512, 512);
805   glutInitWindowPosition(10,90); // place it inside parent window
806   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_MULTISAMPLE);
807   glutCreateWindow("Fractal Planet?");
808   window.end();
809   window.resizable(glut_window);
810 
811   agvInit(1); /* 1 cause we don't have our own idle */
812 
813   glutReshapeFunc(reshape);
814   glutDisplayFunc(display);
815   glutVisibilityFunc(visible);
816   glutMenuStateFunc(menuuse);
817 
818   NewFractals();
819   agvMakeAxesList(AXES);
820   myGLInit();
821   MenuInit();
822 
823   glutMainLoop(); // you could use Fl::run() instead
824 
825   return 0;
826 }
827 #endif
828 
829 //
830 // End of "$Id$".
831 //
832