1
2/*
3 * Display an isosurface of 3-D wind speed volume.
4 *
5 * Command line options:
6 *    -info      print GL implementation information
7 *
8 * Brian Paul  This file in public domain.
9 */
10
11
12/* Keys:
13 * =====
14 *
15 *   - Arrow keys to rotate
16 *   - 's' toggles smooth shading
17 *   - 'l' toggles lighting
18 *   - 'f' toggles fog
19 *   - 'I' and 'i' zoom in and out
20 *   - 'c' toggles a user clip plane
21 *   - 'm' toggles colorful materials in GL_TRIANGLES modes.
22 *   - '+' and '-' move the user clip plane
23 *
24 * Other options are available via the popup menu.
25 */
26
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30#include <math.h>
31#ifdef _WIN32
32#include <windows.h>
33#undef CLIP_MASK
34#endif
35#include <GL/glew.h>
36#include "glut_wrap.h"
37
38#include "readtex.h"
39#define TEXTURE_FILE DEMOS_DATA_DIR "reflect.rgb"
40
41#define LIT		0x00000001
42#define UNLIT		0x00000002
43#define REFLECT		0x00000004
44#define POINT_FILTER	0x00000008
45#define LINEAR_FILTER	0x00000010
46#define GLVERTEX	0x00000020
47#define DRAW_ELTS	0x00000040
48#define DRAW_ARRAYS	0x00000080
49#define ARRAY_ELT	0x00000100
50#define LOCKED	        0x00000200
51#define UNLOCKED	0x00000400
52#define IMMEDIATE	0x00000800
53#define DISPLAYLIST	0x00001000
54#define SHADE_SMOOTH	0x00002000
55#define SHADE_FLAT	0x00004000
56#define TRIANGLES	0x00008000
57#define STRIPS		0x00010000
58#define POINTS		0x00020000
59#define USER_CLIP	0x00040000
60#define NO_USER_CLIP	0x00080000
61#define MATERIALS	0x00100000
62#define NO_MATERIALS	0x00200000
63#define FOG		0x00400000
64#define NO_FOG		0x00800000
65#define QUIT		0x01000000
66#define GLINFO		0x02000000
67#define STIPPLE		0x04000000
68#define NO_STIPPLE	0x08000000
69#define POLYGON_FILL	0x10000000
70#define POLYGON_LINE	0x20000000
71#define POLYGON_POINT	0x40000000
72
73#define LIGHT_MASK		(LIT|UNLIT|REFLECT)
74#define FILTER_MASK		(POINT_FILTER|LINEAR_FILTER)
75#define RENDER_STYLE_MASK	(GLVERTEX|DRAW_ARRAYS|DRAW_ELTS|ARRAY_ELT)
76#define DLIST_MASK		(IMMEDIATE|DISPLAYLIST)
77#define LOCK_MASK		(LOCKED|UNLOCKED)
78#define MATERIAL_MASK		(MATERIALS|NO_MATERIALS)
79#define PRIMITIVE_MASK		(TRIANGLES|STRIPS|POINTS)
80#define CLIP_MASK		(USER_CLIP|NO_USER_CLIP)
81#define SHADE_MASK		(SHADE_SMOOTH|SHADE_FLAT)
82#define FOG_MASK		(FOG|NO_FOG)
83#define STIPPLE_MASK		(STIPPLE|NO_STIPPLE)
84#define POLYGON_MASK		(POLYGON_FILL|POLYGON_LINE|POLYGON_POINT)
85
86#define MAXVERTS 10000
87static GLint maxverts = MAXVERTS;
88static float data[MAXVERTS][6];
89static float compressed_data[MAXVERTS][6];
90static float expanded_data[MAXVERTS*3][6];
91static GLuint indices[MAXVERTS];
92static GLuint tri_indices[MAXVERTS*3];
93static GLuint strip_indices[MAXVERTS];
94static GLfloat col[100][4];
95static GLint numverts, num_tri_verts, numuniq;
96
97static GLfloat xrot;
98static GLfloat yrot;
99static GLfloat dist;
100static GLint state, allowed = ~0;
101static GLboolean doubleBuffer = GL_TRUE;
102static GLdouble plane[4];
103static GLuint surf1, dlist_state;
104
105static GLboolean PrintInfo = GL_FALSE;
106
107
108static GLubyte halftone[] = {
109   0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
110   0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
111   0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
112   0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
113   0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
114   0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
115   0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
116   0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
117   0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA,
118   0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
119   0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55};
120
121
122static void read_surface( char *filename )
123{
124   FILE *f;
125
126   f = fopen(filename,"r");
127   if (!f) {
128      printf("couldn't read %s\n", filename);
129      exit(1);
130   }
131
132   numverts = 0;
133   while (!feof(f) && numverts<maxverts) {
134      int result;
135      result = fscanf( f, "%f %f %f  %f %f %f",
136	               &data[numverts][0], &data[numverts][1], &data[numverts][2],
137	               &data[numverts][3], &data[numverts][4], &data[numverts][5] );
138      (void) result;
139      numverts++;
140   }
141   numverts--;
142
143   printf("%d vertices, %d triangles\n", numverts, numverts-2);
144   fclose(f);
145}
146
147
148
149static void print_flags( const char *msg, GLuint flags )
150{
151   fprintf(stderr,
152	   "%s (0x%x): %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
153	   msg, flags,
154	   (flags & GLVERTEX) ? "glVertex, " : "",
155	   (flags & DRAW_ARRAYS) ? "glDrawArrays, " : "",
156	   (flags & DRAW_ELTS) ? "glDrawElements, " : "",
157	   (flags & ARRAY_ELT) ? "glArrayElement, " : "",
158	   (flags & LOCKED) ? "locked arrays, " : "",
159	   (flags & TRIANGLES) ? "GL_TRIANGLES, " : "",
160	   (flags & STRIPS) ? "GL_TRIANGLE_STRIP, " : "",
161	   (flags & POINTS) ? "GL_POINTS, " : "",
162	   (flags & DISPLAYLIST) ? "as a displaylist, " : "",
163	   (flags & LIT) ? "lit, " : "",
164	   (flags & UNLIT) ? "unlit, " : "",
165	   (flags & REFLECT) ? "reflect, " : "",
166	   (flags & SHADE_FLAT) ? "flat-shaded, " : "",
167	   (flags & USER_CLIP) ? "user_clip, " : "",
168	   (flags & MATERIALS) ? "materials, " : "",
169	   (flags & FOG) ? "fog, " : "",
170	   (flags & STIPPLE) ? "stipple, " : "",
171	   (flags & POLYGON_LINE) ? "polygon mode line, " : "",
172	   (flags & POLYGON_POINT) ? "polygon mode point, " : "");
173}
174
175
176
177struct data_idx {
178   float *data;
179   int idx;
180   int uniq_idx;
181};
182
183
184#define COMPARE_FUNC( AXIS )                            \
185static int compare_axis_##AXIS( const void *a, const void *b )	\
186{							\
187   float t = ( (*(struct data_idx *)a).data[AXIS] -	\
188	       (*(struct data_idx *)b).data[AXIS] );	\
189   							\
190   if (t < 0) return -1;				\
191   if (t > 0) return 1;					\
192   return 0;						\
193}
194
195COMPARE_FUNC(0)
196COMPARE_FUNC(1)
197COMPARE_FUNC(2)
198COMPARE_FUNC(3)
199COMPARE_FUNC(4)
200COMPARE_FUNC(5)
201COMPARE_FUNC(6)
202
203int (*(compare[7]))( const void *a, const void *b ) =
204{
205   compare_axis_0,
206   compare_axis_1,
207   compare_axis_2,
208   compare_axis_3,
209   compare_axis_4,
210   compare_axis_5,
211   compare_axis_6,
212};
213
214
215#define VEC_ELT(f, s, i)  (float *)(((char *)f) + s * i)
216
217static int sort_axis( int axis,
218		      int vec_size,
219		      int vec_stride,
220		      struct data_idx *indices,
221		      int start,
222		      int finish,
223		      float *out,
224		      int uniq,
225		      const float fudge )
226{
227   int i;
228
229   if (finish-start > 2)
230   {
231      qsort( indices+start, finish-start, sizeof(*indices), compare[axis] );
232   }
233   else if (indices[start].data[axis] > indices[start+1].data[axis])
234   {
235      struct data_idx tmp = indices[start];
236      indices[start] = indices[start+1];
237      indices[start+1] = tmp;
238   }
239
240   if (axis == vec_size-1) {
241      for (i = start ; i < finish ; ) {
242	 float max = indices[i].data[axis] + fudge;
243	 float *dest = VEC_ELT(out, vec_stride, uniq);
244	 int j;
245
246	 for (j = 0 ; j < vec_size ; j++)
247	    dest[j] = indices[i].data[j];
248
249	 for ( ; i < finish && max >= indices[i].data[axis]; i++)
250	    indices[i].uniq_idx = uniq;
251
252	 uniq++;
253      }
254   } else {
255      for (i = start ; i < finish ; ) {
256	 int j = i + 1;
257	 float max = indices[i].data[axis] + fudge;
258	 while (j < finish && max >= indices[j].data[axis]) j++;
259	 if (j == i+1) {
260	    float *dest = VEC_ELT(out, vec_stride, uniq);
261	    int k;
262
263	    indices[i].uniq_idx = uniq;
264
265	    for (k = 0 ; k < vec_size ; k++)
266	       dest[k] = indices[i].data[k];
267
268	    uniq++;
269	 } else {
270	    uniq = sort_axis( axis+1, vec_size, vec_stride,
271			      indices, i, j, out, uniq, fudge );
272	 }
273	 i = j;
274      }
275   }
276
277   return uniq;
278}
279
280
281static void extract_indices1( const struct data_idx *in, unsigned int *out,
282			      int n )
283{
284   int i;
285   for ( i = 0 ; i < n ; i++ ) {
286      out[in[i].idx] = in[i].uniq_idx;
287   }
288}
289
290
291static void compactify_arrays(void)
292{
293   int i;
294   struct data_idx *ind;
295
296   ind = (struct data_idx *) malloc( sizeof(struct data_idx) * numverts );
297
298   for (i = 0 ; i < numverts ; i++) {
299      ind[i].idx = i;
300      ind[i].data = data[i];
301   }
302
303   numuniq = sort_axis(0,
304		       sizeof(compressed_data[0])/sizeof(float),
305		       sizeof(compressed_data[0]),
306		       ind,
307		       0,
308		       numverts,
309		       (float *)compressed_data,
310		       0,
311		       1e-6);
312
313   printf("Nr unique vertex/normal pairs: %d\n", numuniq);
314
315   extract_indices1( ind, indices, numverts );
316   free( ind );
317}
318
319static void expand_arrays(void)
320{
321   int i;
322   int parity = 0;
323   for (i = 2 ; i < numverts ; i++, parity ^= 1) {
324      int v0 = i-2+parity;
325      int v1 = i-1-parity;
326      int v2 = i;
327      memcpy( expanded_data[(i-2)*3+0], data[v0], sizeof(data[0]) );
328      memcpy( expanded_data[(i-2)*3+1], data[v1], sizeof(data[0]) );
329      memcpy( expanded_data[(i-2)*3+2], data[v2], sizeof(data[0]) );
330   }
331}
332
333static float myrand( float max )
334{
335   return max*rand()/(RAND_MAX+1.0);
336}
337
338
339static void make_tri_indices( void )
340{
341   unsigned int *v = tri_indices;
342   unsigned int parity = 0;
343   int i, j;
344
345   for (j=2;j<numverts;j++,parity^=1) {
346      if (parity) {
347	 *v++ = indices[j-1];
348	 *v++ = indices[j-2];
349	 *v++ = indices[j];
350      } else {
351	 *v++ = indices[j-2];
352	 *v++ = indices[j-1];
353	 *v++ = indices[j];
354      }
355   }
356
357   num_tri_verts = v - tri_indices;
358   printf("num_tri_verts: %d\n", num_tri_verts);
359
360   for (i = j = 0 ; i < num_tri_verts ; i += 600, j++) {
361      col[j][3] = 1;
362      col[j][2] = myrand(1);
363      col[j][1] = myrand(1);
364      col[j][0] = myrand(1);
365   }
366
367   for (i = 0; i < numverts ; i++)
368      strip_indices[i] = i;
369}
370
371#define MIN(x,y) (x < y) ? x : y
372
373static void draw_surface( unsigned int with_state )
374{
375   GLint i, j;
376
377   if (with_state & DISPLAYLIST) {
378      if ((with_state & (RENDER_STYLE_MASK|PRIMITIVE_MASK|MATERIAL_MASK)) !=
379	  dlist_state) {
380	 /*
381	  */
382	 fprintf(stderr, "rebuilding displaylist\n");
383
384	 if (dlist_state)
385	    glDeleteLists( surf1, 1 );
386
387	 dlist_state = with_state & (RENDER_STYLE_MASK|PRIMITIVE_MASK|
388				     MATERIAL_MASK);
389	 surf1 = glGenLists(1);
390	 glNewList(surf1, GL_COMPILE);
391	 draw_surface( dlist_state );
392	 glEndList();
393      }
394
395      glCallList( surf1 );
396      return;
397   }
398
399   switch (with_state & (RENDER_STYLE_MASK|PRIMITIVE_MASK)) {
400
401   case (DRAW_ELTS|TRIANGLES):
402      if (with_state & MATERIALS) {
403	 for (j = i = 0 ; i < num_tri_verts ; i += 600, j++) {
404	    GLuint nr = MIN(num_tri_verts-i, 600);
405	    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col[j]);
406	    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col[j]);
407	    glDrawElements( GL_TRIANGLES, nr, GL_UNSIGNED_INT, tri_indices+i );
408	 }
409      } else {
410	 glDrawElements( GL_TRIANGLES, num_tri_verts, GL_UNSIGNED_INT,
411			 tri_indices );
412      }
413      break;
414
415   case (DRAW_ARRAYS|TRIANGLES):
416      glDrawArrays( GL_TRIANGLES, 0, (numverts-2)*3 );
417      break;
418
419   case (ARRAY_ELT|TRIANGLES):
420      if (with_state & MATERIALS) {
421	 for (j = i = 0 ; i < num_tri_verts ; i += 600, j++) {
422	    GLuint nr = MIN(num_tri_verts-i, 600);
423	    GLuint k;
424	    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col[j]);
425	    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col[j]);
426	    glBegin( GL_TRIANGLES );
427	    for (k = 0 ; k < nr ; k++)
428	       glArrayElement( tri_indices[i+k] );
429	    glEnd();
430	 }
431      } else {
432	 glBegin( GL_TRIANGLES );
433	 for (i = 0 ; i < num_tri_verts ; i++)
434	    glArrayElement( tri_indices[i] );
435
436	 glEnd();
437      }
438      break;
439
440
441      /* Uses the original arrays (including duplicate elements):
442       */
443   case (DRAW_ARRAYS|STRIPS):
444      glDrawArrays( GL_TRIANGLE_STRIP, 0, numverts );
445      break;
446   case (DRAW_ELTS|STRIPS):
447      glDrawElements( GL_TRIANGLE_STRIP, numverts,
448		      GL_UNSIGNED_INT, strip_indices );
449      break;
450
451      /* Uses the original arrays (including duplicate elements):
452       */
453   case (ARRAY_ELT|STRIPS):
454      glBegin( GL_TRIANGLE_STRIP );
455      for (i = 0 ; i < numverts ; i++)
456	 glArrayElement( i );
457      glEnd();
458      break;
459
460   case (DRAW_ARRAYS|POINTS):
461      glDrawArrays( GL_POINTS, 0, numuniq );
462      break;
463   case (DRAW_ELTS|POINTS):
464      /* can use numuniq with strip_indices as strip_indices[i] == i.
465       */
466      glDrawElements( GL_POINTS, numuniq,
467		      GL_UNSIGNED_INT, strip_indices );
468      break;
469   case (ARRAY_ELT|POINTS):
470      /* just emit each unique element once:
471       */
472      glBegin( GL_POINTS );
473      for (i = 0 ; i < numuniq ; i++)
474	 glArrayElement( i );
475      glEnd();
476      break;
477
478   case (GLVERTEX|TRIANGLES):
479      if (with_state & MATERIALS) {
480	 for (j = i = 0 ; i < num_tri_verts ; i += 600, j++) {
481	    GLuint nr = MIN(num_tri_verts-i, 600);
482	    GLuint k;
483	    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col[j]);
484	    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col[j]);
485	    glBegin( GL_TRIANGLES );
486	    for (k = 0 ; k < nr ; k++) {
487	       glNormal3fv( &compressed_data[tri_indices[i+k]][3] );
488	       glVertex3fv( &compressed_data[tri_indices[i+k]][0] );
489	    }
490	    glEnd();
491	 }
492      } else {
493	 glBegin( GL_TRIANGLES );
494	 for (i = 0 ; i < num_tri_verts ; i++) {
495	    glNormal3fv( &compressed_data[tri_indices[i]][3] );
496	    glVertex3fv( &compressed_data[tri_indices[i]][0] );
497	 }
498	 glEnd();
499      }
500      break;
501
502   case (GLVERTEX|POINTS):
503      /* Renders all points, but not in strip order...  Shouldn't be a
504       * problem, but people may be confused as to why points are so
505       * much faster in this demo...  And why cva doesn't help them...
506       */
507      glBegin( GL_POINTS );
508      for ( i = 0 ; i < numuniq ; i++ ) {
509         glNormal3fv( &compressed_data[i][3] );
510         glVertex3fv( &compressed_data[i][0] );
511      }
512      glEnd();
513      break;
514
515   case (GLVERTEX|STRIPS):
516      if (with_state & MATERIALS) {
517         glBegin( GL_TRIANGLE_STRIP );
518         for (i=0;i<numverts;i++) {
519            if (i % 600 == 0 && i != 0) {
520               unsigned j = i / 600;
521               glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, col[j]);
522               glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col[j]);
523            }
524            glNormal3fv( &data[i][3] );
525            glVertex3fv( &data[i][0] );
526         }
527         glEnd();
528      }
529      else {
530         glBegin( GL_TRIANGLE_STRIP );
531         for (i=0;i<numverts;i++) {
532            glNormal3fv( &data[i][3] );
533            glVertex3fv( &data[i][0] );
534         }
535         glEnd();
536      }
537      break;
538
539   default:
540      fprintf(stderr, "unimplemented mode %x...\n",
541	      (with_state & (RENDER_STYLE_MASK|PRIMITIVE_MASK)));
542      break;
543   }
544}
545
546
547
548static void Display(void)
549{
550    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
551    draw_surface( state );
552    glFlush();
553    if (doubleBuffer) glutSwapBuffers();
554}
555
556
557/* KW: only do this when necessary, so CVA can re-use results.
558 */
559static void set_matrix( void )
560{
561   glMatrixMode(GL_MODELVIEW);
562   glLoadIdentity();
563   glTranslatef( 0.0, 0.0, dist );
564   glRotatef( yrot, 0.0, 1.0, 0.0 );
565   glRotatef( xrot, 1.0, 0.0, 0.0 );
566}
567
568static void Benchmark( float xdiff, float ydiff )
569{
570   int startTime, endTime;
571   int draws;
572   double seconds, fps, triPerSecond;
573
574   printf("Benchmarking...\n");
575
576   draws = 0;
577   startTime = glutGet(GLUT_ELAPSED_TIME);
578   xrot = 0.0;
579   do {
580      xrot += xdiff;
581      yrot += ydiff;
582      set_matrix();
583      Display();
584      draws++;
585      endTime = glutGet(GLUT_ELAPSED_TIME);
586   } while (endTime - startTime < 5000);   /* 5 seconds */
587
588   /* Results */
589   seconds = (double) (endTime - startTime) / 1000.0;
590   triPerSecond = (numverts - 2) * draws / seconds;
591   fps = draws / seconds;
592   printf("Result:  triangles/sec: %g  fps: %g\n", triPerSecond, fps);
593}
594
595
596static void InitMaterials(void)
597{
598    static float ambient[] = {0.1, 0.1, 0.1, 1.0};
599    static float diffuse[] = {0.5, 1.0, 1.0, 1.0};
600    static float position0[] = {0.0, 0.0, 20.0, 0.0};
601    static float position1[] = {0.0, 0.0, -20.0, 0.0};
602    static float front_mat_shininess[] = {60.0};
603    static float front_mat_specular[] = {0.2, 0.2, 0.2, 1.0};
604    static float front_mat_diffuse[] = {0.5, 0.28, 0.38, 1.0};
605    /*
606    static float back_mat_shininess[] = {60.0};
607    static float back_mat_specular[] = {0.5, 0.5, 0.2, 1.0};
608    static float back_mat_diffuse[] = {1.0, 1.0, 0.2, 1.0};
609    */
610    static float lmodel_ambient[] = {1.0, 1.0, 1.0, 1.0};
611    static float lmodel_twoside[] = {GL_FALSE};
612
613    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
614    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
615    glLightfv(GL_LIGHT0, GL_POSITION, position0);
616    glEnable(GL_LIGHT0);
617
618    glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
619    glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
620    glLightfv(GL_LIGHT1, GL_POSITION, position1);
621    glEnable(GL_LIGHT1);
622
623    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
624    glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
625
626    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_mat_shininess);
627    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_mat_specular);
628    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, front_mat_diffuse);
629
630    glPolygonStipple (halftone);
631}
632
633
634
635#define UPDATE(o,n,mask) (o&=~mask, o|=n&mask)
636#define CHANGED(o,n,mask) ((n&mask) && (n&mask) != (o&mask) )
637
638static void ModeMenu(int m)
639{
640   m &= allowed;
641
642   if (!m) return;
643
644   if (m==QUIT)
645      exit(0);
646
647   if (m==GLINFO) {
648      printf("GL_VERSION: %s\n", (char *) glGetString(GL_VERSION));
649      printf("GL_EXTENSIONS: %s\n", (char *) glGetString(GL_EXTENSIONS));
650      printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));
651      return;
652   }
653
654   if (CHANGED(state, m, FILTER_MASK)) {
655      UPDATE(state, m, FILTER_MASK);
656      if (m & LINEAR_FILTER) {
657	 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
658	 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
659      } else {
660	 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
661	 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
662      }
663   }
664
665   if (CHANGED(state, m, LIGHT_MASK)) {
666      UPDATE(state, m, LIGHT_MASK);
667      if (m & LIT) {
668	 glEnable(GL_LIGHTING);
669	 glDisable(GL_TEXTURE_GEN_S);
670	 glDisable(GL_TEXTURE_GEN_T);
671	 glDisable(GL_TEXTURE_2D);
672      }
673      else if (m & UNLIT) {
674	 glDisable(GL_LIGHTING);
675	 glDisable(GL_TEXTURE_GEN_S);
676	 glDisable(GL_TEXTURE_GEN_T);
677	 glDisable(GL_TEXTURE_2D);
678      }
679      else if (m & REFLECT) {
680	 glDisable(GL_LIGHTING);
681	 glEnable(GL_TEXTURE_GEN_S);
682	 glEnable(GL_TEXTURE_GEN_T);
683	 glEnable(GL_TEXTURE_2D);
684      }
685   }
686
687   if (CHANGED(state, m, SHADE_MASK)) {
688      UPDATE(state, m, SHADE_MASK);
689      if (m & SHADE_SMOOTH)
690	 glShadeModel(GL_SMOOTH);
691      else
692	 glShadeModel(GL_FLAT);
693   }
694
695
696   if (CHANGED(state, m, CLIP_MASK)) {
697      UPDATE(state, m, CLIP_MASK);
698      if (m & USER_CLIP) {
699	 glEnable(GL_CLIP_PLANE0);
700      } else {
701	 glDisable(GL_CLIP_PLANE0);
702      }
703   }
704
705   if (CHANGED(state, m, FOG_MASK)) {
706      UPDATE(state, m, FOG_MASK);
707      if (m & FOG) {
708	 glEnable(GL_FOG);
709      }
710      else {
711	 glDisable(GL_FOG);
712      }
713   }
714
715   if (CHANGED(state, m, STIPPLE_MASK)) {
716      UPDATE(state, m, STIPPLE_MASK);
717      if (m & STIPPLE) {
718	 glEnable(GL_POLYGON_STIPPLE);
719      }
720      else {
721	 glDisable(GL_POLYGON_STIPPLE);
722      }
723   }
724
725   if (CHANGED(state, m, POLYGON_MASK)) {
726      UPDATE(state, m, POLYGON_MASK);
727      if (m & POLYGON_FILL) {
728	 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
729      }
730      else if (m & POLYGON_LINE) {
731	 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
732      }
733      else {
734	 glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
735      }
736   }
737
738   if (CHANGED(state, m, (LOCK_MASK|RENDER_STYLE_MASK|PRIMITIVE_MASK)))
739   {
740      if (m & (PRIMITIVE_MASK)) {
741	 UPDATE(state, m, (PRIMITIVE_MASK));
742      }
743
744      if (m & (RENDER_STYLE_MASK)) {
745	 UPDATE(state, m, (RENDER_STYLE_MASK));
746      }
747
748      if (m & LOCK_MASK) {
749	 UPDATE(state, m, (LOCK_MASK));
750      }
751
752
753      print_flags("primitive", state & PRIMITIVE_MASK);
754      print_flags("render style", state & RENDER_STYLE_MASK);
755
756      if ((state & PRIMITIVE_MASK) != STRIPS &&
757	  ((state & RENDER_STYLE_MASK) == DRAW_ELTS ||
758	   (state & RENDER_STYLE_MASK) == ARRAY_ELT ||
759	   (state & PRIMITIVE_MASK) == POINTS))
760      {
761	 fprintf(stderr, "enabling small arrays\n");
762	 /* Rendering any primitive with draw-element/array-element
763	  *  --> Can't do strips here as ordering has been lost in
764	  *  compaction process...
765	  */
766	 glVertexPointer( 3, GL_FLOAT, sizeof(data[0]), compressed_data );
767	 glNormalPointer( GL_FLOAT, sizeof(data[0]), &compressed_data[0][3] );
768#ifdef GL_EXT_compiled_vertex_array
769	 if (allowed & LOCKED) {
770	    if (state & LOCKED) {
771	       glLockArraysEXT( 0, numuniq );
772	    } else {
773	       glUnlockArraysEXT();
774	    }
775	 }
776#endif
777      }
778      else if ((state & PRIMITIVE_MASK) == TRIANGLES &&
779	       (state & RENDER_STYLE_MASK) == DRAW_ARRAYS) {
780	 fprintf(stderr, "enabling big arrays\n");
781	 /* Only get here for TRIANGLES and drawarrays
782	  */
783	 glVertexPointer( 3, GL_FLOAT, sizeof(data[0]), expanded_data );
784	 glNormalPointer( GL_FLOAT, sizeof(data[0]), &expanded_data[0][3] );
785
786#ifdef GL_EXT_compiled_vertex_array
787	 if (allowed & LOCKED) {
788	    if (state & LOCKED) {
789	       glLockArraysEXT( 0, (numverts-2)*3 );
790	    } else {
791	       glUnlockArraysEXT();
792	    }
793	 }
794#endif
795      }
796      else {
797	 fprintf(stderr, "enabling normal arrays\n");
798	 glVertexPointer( 3, GL_FLOAT, sizeof(data[0]), data );
799	 glNormalPointer( GL_FLOAT, sizeof(data[0]), &data[0][3] );
800#ifdef GL_EXT_compiled_vertex_array
801	 if (allowed & LOCKED) {
802	    if (state & LOCKED) {
803	       glLockArraysEXT( 0, numverts );
804	    } else {
805	       glUnlockArraysEXT();
806	    }
807	 }
808#endif
809      }
810
811   }
812
813
814   if (m & DLIST_MASK) {
815      UPDATE(state, m, DLIST_MASK);
816   }
817
818   if (m & MATERIAL_MASK) {
819      UPDATE(state, m, MATERIAL_MASK);
820   }
821
822   print_flags("new flags", state);
823
824   glutPostRedisplay();
825}
826
827
828
829static void Init(int argc, char *argv[])
830{
831   GLfloat fogColor[4] = {0.5,1.0,0.5,1.0};
832
833   xrot = 0;
834   yrot = 0;
835   dist = -6;
836   plane[0] = 1.0;
837   plane[1] = 0.0;
838   plane[2] = -1.0;
839   plane[3] = 0.0;
840
841   glClearColor(0.0, 0.0, 1.0, 0.0);
842   glEnable( GL_DEPTH_TEST );
843   glEnableClientState( GL_VERTEX_ARRAY );
844   glEnableClientState( GL_NORMAL_ARRAY );
845
846   glMatrixMode(GL_PROJECTION);
847   glLoadIdentity();
848   glFrustum( -1.0, 1.0, -1.0, 1.0, 5, 25 );
849
850   glMatrixMode(GL_MODELVIEW);
851   glLoadIdentity();
852   glClipPlane(GL_CLIP_PLANE0, plane);
853
854   InitMaterials();
855
856   set_matrix();
857
858   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
859   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
860
861   glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
862   glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
863
864
865   /* Green fog is easy to see */
866   glFogi(GL_FOG_MODE,GL_EXP2);
867   glFogfv(GL_FOG_COLOR,fogColor);
868   glFogf(GL_FOG_DENSITY,0.15);
869   glHint(GL_FOG_HINT,GL_DONT_CARE);
870
871   {
872      static int firsttime = 1;
873      if (firsttime) {
874	 firsttime = 0;
875	 compactify_arrays();
876	 expand_arrays();
877	 make_tri_indices();
878
879	 if (!LoadRGBMipmaps(TEXTURE_FILE, GL_RGB)) {
880	    printf("Error: couldn't load texture image\n");
881	    exit(1);
882	 }
883      }
884   }
885
886   ModeMenu(SHADE_SMOOTH|
887	    LIT|
888	    POINT_FILTER|
889	    NO_USER_CLIP|
890	    NO_MATERIALS|
891	    NO_FOG|
892	    NO_STIPPLE|
893	    IMMEDIATE|
894	    STRIPS|
895	    UNLOCKED|
896	    GLVERTEX);
897
898   if (PrintInfo) {
899      printf("GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
900      printf("GL_VERSION    = %s\n", (char *) glGetString(GL_VERSION));
901      printf("GL_VENDOR     = %s\n", (char *) glGetString(GL_VENDOR));
902      printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
903   }
904}
905
906
907
908static void Reshape(int width, int height)
909{
910    glViewport(0, 0, (GLint)width, (GLint)height);
911}
912
913
914
915static void Key( unsigned char key, int x, int y )
916{
917   (void) x;
918   (void) y;
919   switch (key) {
920   case 27:
921      exit(0);
922   case 'f':
923      ModeMenu((state ^ FOG_MASK) & FOG_MASK);
924      break;
925   case 's':
926      ModeMenu((state ^ SHADE_MASK) & SHADE_MASK);
927      break;
928   case 't':
929      ModeMenu((state ^ STIPPLE_MASK) & STIPPLE_MASK);
930      break;
931   case 'l':
932      ModeMenu((state ^ LIGHT_MASK) & (LIT|UNLIT));
933      break;
934   case 'm':
935      ModeMenu((state ^ MATERIAL_MASK) & MATERIAL_MASK);
936      break;
937   case 'c':
938      ModeMenu((state ^ CLIP_MASK) & CLIP_MASK);
939      break;
940   case 'v':
941      ModeMenu((LOCKED|IMMEDIATE|DRAW_ELTS|TRIANGLES) & allowed);
942      break;
943   case 'V':
944      ModeMenu(UNLOCKED|IMMEDIATE|GLVERTEX|STRIPS);
945      break;
946   case 'b':
947      Benchmark(5.0, 0);
948      break;
949   case 'B':
950      Benchmark(0, 5.0);
951      break;
952   case 'i':
953      dist += .25;
954      set_matrix();
955      glutPostRedisplay();
956      break;
957   case 'I':
958      dist -= .25;
959      set_matrix();
960      glutPostRedisplay();
961      break;
962   case '-':
963   case '_':
964      plane[3] += 0.5;
965      glMatrixMode(GL_MODELVIEW);
966      glLoadIdentity();
967      glClipPlane(GL_CLIP_PLANE0, plane);
968      set_matrix();
969      glutPostRedisplay();
970      break;
971   case '+':
972   case '=':
973      plane[3] -= 0.5;
974      glMatrixMode(GL_MODELVIEW);
975      glLoadIdentity();
976      glClipPlane(GL_CLIP_PLANE0, plane);
977      set_matrix();
978      glutPostRedisplay();
979      break;
980   case ' ':
981      Init(0,0);
982      break;
983   }
984}
985
986
987static void SpecialKey( int key, int x, int y )
988{
989   (void) x;
990   (void) y;
991   switch (key) {
992   case GLUT_KEY_LEFT:
993      yrot -= 15.0;
994      break;
995   case GLUT_KEY_RIGHT:
996      yrot += 15.0;
997      break;
998   case GLUT_KEY_UP:
999      xrot += 15.0;
1000      break;
1001   case GLUT_KEY_DOWN:
1002      xrot -= 15.0;
1003      break;
1004   default:
1005      return;
1006   }
1007   set_matrix();
1008   glutPostRedisplay();
1009}
1010
1011
1012
1013static GLint Args(int argc, char **argv)
1014{
1015   GLint i;
1016   GLint mode = 0;
1017
1018   for (i = 1; i < argc; i++) {
1019      if (strcmp(argv[i], "-sb") == 0) {
1020         doubleBuffer = GL_FALSE;
1021      }
1022      else if (strcmp(argv[i], "-db") == 0) {
1023         doubleBuffer = GL_TRUE;
1024      }
1025      else if (strcmp(argv[i], "-info") == 0) {
1026         PrintInfo = GL_TRUE;
1027      }
1028      else if (strcmp(argv[i], "-10") == 0) {
1029         maxverts = 10;
1030      }
1031      else if (strcmp(argv[i], "-100") == 0) {
1032	 maxverts = 100;
1033      }
1034      else if (strcmp(argv[i], "-1000") == 0) {
1035	 maxverts = 1000;
1036      }
1037      else {
1038         printf("%s (Bad option).\n", argv[i]);
1039	 return QUIT;
1040      }
1041   }
1042
1043   return mode;
1044}
1045
1046int main(int argc, char **argv)
1047{
1048   GLenum type;
1049
1050   GLuint arg_mode = Args(argc, argv);
1051
1052   if (arg_mode & QUIT)
1053      exit(0);
1054
1055   read_surface(DEMOS_DATA_DIR "isosurf.dat");
1056
1057   glutInitWindowSize(400, 400);
1058   glutInit( &argc, argv);
1059
1060   type = GLUT_DEPTH;
1061   type |= GLUT_RGB;
1062   type |= (doubleBuffer) ? GLUT_DOUBLE : GLUT_SINGLE;
1063   glutInitDisplayMode(type);
1064
1065   if (glutCreateWindow("Isosurface") <= 0) {
1066      exit(0);
1067   }
1068
1069   glewInit();
1070
1071   /* Make sure server supports vertex arrays */
1072   if (!GLEW_VERSION_1_1)
1073   {
1074      printf("Vertex arrays not supported by this renderer\n");
1075      allowed &= ~(LOCKED|DRAW_ARRAYS|DRAW_ELTS|ARRAY_ELT);
1076   }
1077   else if (!GLEW_EXT_compiled_vertex_array)
1078   {
1079      printf("Compiled vertex arrays not supported by this renderer\n");
1080      allowed &= ~LOCKED;
1081   }
1082
1083   Init(argc, argv);
1084   ModeMenu(arg_mode);
1085
1086   glutCreateMenu(ModeMenu);
1087   glutAddMenuEntry("GL info",               GLINFO);
1088   glutAddMenuEntry("", 0);
1089   glutAddMenuEntry("Lit",                   LIT);
1090   glutAddMenuEntry("Unlit",                 UNLIT);
1091   glutAddMenuEntry("Reflect",               REFLECT);
1092   glutAddMenuEntry("", 0);
1093   glutAddMenuEntry("Smooth",                SHADE_SMOOTH);
1094   glutAddMenuEntry("Flat",                  SHADE_FLAT);
1095   glutAddMenuEntry("", 0);
1096   glutAddMenuEntry("Fog",                   FOG);
1097   glutAddMenuEntry("No Fog",                NO_FOG);
1098   glutAddMenuEntry("", 0);
1099   glutAddMenuEntry("Stipple",               STIPPLE);
1100   glutAddMenuEntry("No Stipple",            NO_STIPPLE);
1101   glutAddMenuEntry("", 0);
1102   glutAddMenuEntry("Polygon Mode Fill",     POLYGON_FILL);
1103   glutAddMenuEntry("Polygon Mode Line",     POLYGON_LINE);
1104   glutAddMenuEntry("Polygon Mode Points",   POLYGON_POINT);
1105   glutAddMenuEntry("", 0);
1106   glutAddMenuEntry("Point Filtered",        POINT_FILTER);
1107   glutAddMenuEntry("Linear Filtered",       LINEAR_FILTER);
1108   glutAddMenuEntry("", 0);
1109   glutAddMenuEntry("GL_TRIANGLES",          TRIANGLES);
1110   glutAddMenuEntry("GL_TRIANGLE_STRIPS",    STRIPS);
1111   glutAddMenuEntry("GL_POINTS",             POINTS);
1112   glutAddMenuEntry("", 0);
1113   glutAddMenuEntry("Displaylist",           DISPLAYLIST);
1114   glutAddMenuEntry("Immediate",             IMMEDIATE);
1115   glutAddMenuEntry("", 0);
1116   if (allowed & LOCKED) {
1117      glutAddMenuEntry("Locked Arrays (CVA)", LOCKED);
1118      glutAddMenuEntry("Unlocked Arrays",     UNLOCKED);
1119      glutAddMenuEntry("", 0);
1120   }
1121   glutAddMenuEntry("glVertex",               GLVERTEX);
1122   if (allowed & DRAW_ARRAYS) {
1123      glutAddMenuEntry("glDrawElements",      DRAW_ELTS);
1124      glutAddMenuEntry("glDrawArrays",	      DRAW_ARRAYS);
1125      glutAddMenuEntry("glArrayElement",      ARRAY_ELT);
1126   }
1127   glutAddMenuEntry("", 0);
1128   glutAddMenuEntry("Quit",                   QUIT);
1129   glutAttachMenu(GLUT_RIGHT_BUTTON);
1130
1131   glutReshapeFunc(Reshape);
1132   glutKeyboardFunc(Key);
1133   glutSpecialFunc(SpecialKey);
1134   glutDisplayFunc(Display);
1135
1136   glutMainLoop();
1137   return 0;
1138}
1139