/* $Id: isosurf.c,v 1.15 2002/10/18 17:47:35 kschultz Exp $ */ /* * Display an isosurface of 3-D wind speed volume. * * Command line options: * -info print GL implementation information * * Brian Paul This file in public domain. */ /* Keys: * ===== * * - Arrow keys to rotate * - 's' toggles smooth shading * - 'l' toggles lighting * - 'f' toggles fog * - 'I' and 'i' zoom in and out * - 'c' toggles a user clip plane * - 'm' toggles colorful materials in GL_TRIANGLES modes. * - '+' and '-' move the user clip plane * * Other options are available via the popup menu. */ #include #include #include #include #include #ifdef _WIN32 #include #undef CLIP_MASK #endif #define GL_GLEXT_LEGACY #include "GL/glut.h" #include "readtex.c" /* I know, this is a hack. KW: me too. */ #define TEXTURE_FILE "../images/reflect.rgb" #define LIT 0x00000001 #define UNLIT 0x00000002 #define REFLECT 0x00000004 #define POINT_FILTER 0x00000008 #define LINEAR_FILTER 0x00000010 #define GLVERTEX 0x00000020 #define DRAW_ELTS 0x00000040 #define DRAW_ARRAYS 0x00000080 #define ARRAY_ELT 0x00000100 #define LOCKED 0x00000200 #define UNLOCKED 0x00000400 #define IMMEDIATE 0x00000800 #define DISPLAYLIST 0x00001000 #define SHADE_SMOOTH 0x00002000 #define SHADE_FLAT 0x00004000 #define TRIANGLES 0x00008000 #define STRIPS 0x00010000 #define POINTS 0x00020000 #define USER_CLIP 0x00040000 #define NO_USER_CLIP 0x00080000 #define MATERIALS 0x00100000 #define NO_MATERIALS 0x00200000 #define FOG 0x00400000 #define NO_FOG 0x00800000 #define QUIT 0x01000000 #define GLINFO 0x02000000 #define STIPPLE 0x04000000 #define NO_STIPPLE 0x08000000 #define POLYGON_FILL 0x10000000 #define POLYGON_LINE 0x20000000 #define LIGHT_MASK (LIT|UNLIT|REFLECT) #define FILTER_MASK (POINT_FILTER|LINEAR_FILTER) #define RENDER_STYLE_MASK (GLVERTEX|DRAW_ARRAYS|DRAW_ELTS|ARRAY_ELT) #define DLIST_MASK (IMMEDIATE|DISPLAYLIST) #define LOCK_MASK (LOCKED|UNLOCKED) #define MATERIAL_MASK (MATERIALS|NO_MATERIALS) #define PRIMITIVE_MASK (TRIANGLES|STRIPS|POINTS) #define CLIP_MASK (USER_CLIP|NO_USER_CLIP) #define SHADE_MASK (SHADE_SMOOTH|SHADE_FLAT) #define FOG_MASK (FOG|NO_FOG) #define STIPPLE_MASK (STIPPLE|NO_STIPPLE) #define POLYGON_MASK (POLYGON_FILL|POLYGON_LINE) #define MAXVERTS 10000 static GLint maxverts = MAXVERTS; static float data[MAXVERTS][6]; static float compressed_data[MAXVERTS][6]; static float expanded_data[MAXVERTS*3][6]; static GLuint indices[MAXVERTS]; static GLuint tri_indices[MAXVERTS*3]; static GLuint strip_indices[MAXVERTS]; static GLfloat col[100][4]; static GLint numverts, num_tri_verts, numuniq; static GLfloat xrot; static GLfloat yrot; static GLfloat dist; static GLint state, allowed = ~0; static GLboolean doubleBuffer = GL_TRUE; static GLdouble plane[4]; static GLuint surf1, dlist_state; static GLboolean PrintInfo = GL_FALSE; static GLubyte halftone[] = { 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55}; static void read_surface( char *filename ) { FILE *f; f = fopen(filename,"r"); if (!f) { printf("couldn't read %s\n", filename); exit(1); } numverts = 0; while (!feof(f) && numverts 0) return 1; \ return 0; \ } COMPARE_FUNC(0) COMPARE_FUNC(1) COMPARE_FUNC(2) COMPARE_FUNC(3) COMPARE_FUNC(4) COMPARE_FUNC(5) COMPARE_FUNC(6) int (*(compare[7]))( const void *a, const void *b ) = { compare_axis_0, compare_axis_1, compare_axis_2, compare_axis_3, compare_axis_4, compare_axis_5, compare_axis_6, }; #define VEC_ELT(f, s, i) (float *)(((char *)f) + s * i) static int sort_axis( int axis, int vec_size, int vec_stride, struct data_idx *indices, int start, int finish, float *out, int uniq, const float fudge ) { int i; if (finish-start > 2) { qsort( indices+start, finish-start, sizeof(*indices), compare[axis] ); } else if (indices[start].data[axis] > indices[start+1].data[axis]) { struct data_idx tmp = indices[start]; indices[start] = indices[start+1]; indices[start+1] = tmp; } if (axis == vec_size-1) { for (i = start ; i < finish ; ) { float max = indices[i].data[axis] + fudge; float *dest = VEC_ELT(out, vec_stride, uniq); int j; for (j = 0 ; j < vec_size ; j++) dest[j] = indices[i].data[j]; for ( ; i < finish && max >= indices[i].data[axis]; i++) indices[i].uniq_idx = uniq; uniq++; } } else { for (i = start ; i < finish ; ) { int j = i + 1; float max = indices[i].data[axis] + fudge; while (j < finish && max >= indices[j].data[axis]) j++; if (j == i+1) { float *dest = VEC_ELT(out, vec_stride, uniq); int k; indices[i].uniq_idx = uniq; for (k = 0 ; k < vec_size ; k++) dest[k] = indices[i].data[k]; uniq++; } else { uniq = sort_axis( axis+1, vec_size, vec_stride, indices, i, j, out, uniq, fudge ); } i = j; } } return uniq; } static void extract_indices1( const struct data_idx *in, unsigned int *out, int n ) { int i; for ( i = 0 ; i < n ; i++ ) { out[in[i].idx] = in[i].uniq_idx; } } static void compactify_arrays(void) { int i; struct data_idx *ind; ind = (struct data_idx *) malloc( sizeof(struct data_idx) * numverts ); for (i = 0 ; i < numverts ; i++) { ind[i].idx = i; ind[i].data = data[i]; } numuniq = sort_axis(0, sizeof(compressed_data[0])/sizeof(float), sizeof(compressed_data[0]), ind, 0, numverts, (float *)compressed_data, 0, 1e-6); printf("Nr unique vertex/normal pairs: %d\n", numuniq); extract_indices1( ind, indices, numverts ); free( ind ); } static void expand_arrays(void) { int i; int parity = 0; for (i = 2 ; i < numverts ; i++, parity ^= 1) { int v0 = i-2+parity; int v1 = i-1-parity; int v2 = i; memcpy( expanded_data[(i-2)*3+0], data[v0], sizeof(data[0]) ); memcpy( expanded_data[(i-2)*3+1], data[v1], sizeof(data[0]) ); memcpy( expanded_data[(i-2)*3+2], data[v2], sizeof(data[0]) ); } } static float myrand( float max ) { return max*rand()/(RAND_MAX+1.0); } static void make_tri_indices( void ) { unsigned int *v = tri_indices; unsigned int parity = 0; int i, j; for (j=2;j Can't do strips here as ordering has been lost in * compaction process... */ glVertexPointerEXT( 3, GL_FLOAT, sizeof(data[0]), numuniq, compressed_data ); glNormalPointerEXT( GL_FLOAT, sizeof(data[0]), numuniq, &compressed_data[0][3]); #ifdef GL_EXT_compiled_vertex_array if (allowed & LOCKED) { if (state & LOCKED) { glLockArraysEXT( 0, numuniq ); } else { glUnlockArraysEXT(); } } #endif } else if ((state & PRIMITIVE_MASK) == TRIANGLES && (state & RENDER_STYLE_MASK) == DRAW_ARRAYS) { fprintf(stderr, "enabling big arrays\n"); /* Only get here for TRIANGLES and drawarrays */ glVertexPointerEXT( 3, GL_FLOAT, sizeof(data[0]), (numverts-2) * 3, expanded_data ); glNormalPointerEXT( GL_FLOAT, sizeof(data[0]), (numverts-2) * 3, &expanded_data[0][3]); #ifdef GL_EXT_compiled_vertex_array if (allowed & LOCKED) { if (state & LOCKED) { glLockArraysEXT( 0, (numverts-2)*3 ); } else { glUnlockArraysEXT(); } } #endif } else { fprintf(stderr, "enabling normal arrays\n"); glVertexPointerEXT( 3, GL_FLOAT, sizeof(data[0]), numverts, data ); glNormalPointerEXT( GL_FLOAT, sizeof(data[0]), numverts, &data[0][3]); #ifdef GL_EXT_compiled_vertex_array if (allowed & LOCKED) { if (state & LOCKED) { glLockArraysEXT( 0, numverts ); } else { glUnlockArraysEXT(); } } #endif } } #endif if (m & DLIST_MASK) { UPDATE(state, m, DLIST_MASK); } if (m & MATERIAL_MASK) { UPDATE(state, m, MATERIAL_MASK); } print_flags("new flags", state); glutPostRedisplay(); } static void Init(int argc, char *argv[]) { GLfloat fogColor[4] = {0.5,1.0,0.5,1.0}; xrot = 0; yrot = 0; dist = -6; plane[0] = 1.0; plane[1] = 0.0; plane[2] = -1.0; plane[3] = 0.0; glClearColor(0.0, 0.0, 1.0, 0.0); glEnable( GL_DEPTH_TEST ); glEnable( GL_VERTEX_ARRAY_EXT ); glEnable( GL_NORMAL_ARRAY_EXT ); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum( -1.0, 1.0, -1.0, 1.0, 5, 25 ); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClipPlane(GL_CLIP_PLANE0, plane); InitMaterials(); set_matrix(); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); /* Green fog is easy to see */ glFogi(GL_FOG_MODE,GL_EXP2); glFogfv(GL_FOG_COLOR,fogColor); glFogf(GL_FOG_DENSITY,0.15); glHint(GL_FOG_HINT,GL_DONT_CARE); { static int firsttime = 1; if (firsttime) { firsttime = 0; compactify_arrays(); expand_arrays(); make_tri_indices(); if (!LoadRGBMipmaps(TEXTURE_FILE, GL_RGB)) { printf("Error: couldn't load texture image\n"); exit(1); } } } ModeMenu(SHADE_SMOOTH| LIT| POINT_FILTER| NO_USER_CLIP| NO_MATERIALS| NO_FOG| NO_STIPPLE| IMMEDIATE| STRIPS| UNLOCKED| GLVERTEX); if (PrintInfo) { printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION)); printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR)); printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS)); } } static void Reshape(int width, int height) { glViewport(0, 0, (GLint)width, (GLint)height); } static void Key( unsigned char key, int x, int y ) { (void) x; (void) y; switch (key) { case 27: exit(0); case 'f': ModeMenu((state ^ FOG_MASK) & FOG_MASK); break; case 's': ModeMenu((state ^ SHADE_MASK) & SHADE_MASK); break; case 't': ModeMenu((state ^ STIPPLE_MASK) & STIPPLE_MASK); break; case 'l': ModeMenu((state ^ LIGHT_MASK) & (LIT|UNLIT)); break; case 'm': ModeMenu((state ^ MATERIAL_MASK) & MATERIAL_MASK); break; case 'c': ModeMenu((state ^ CLIP_MASK) & CLIP_MASK); break; case 'v': ModeMenu((LOCKED|IMMEDIATE|DRAW_ELTS|TRIANGLES) & allowed); break; case 'V': ModeMenu(UNLOCKED|IMMEDIATE|GLVERTEX|STRIPS); break; case 'b': Benchmark(5.0, 0); break; case 'B': Benchmark(0, 5.0); break; case 'i': dist += .25; set_matrix(); glutPostRedisplay(); break; case 'I': dist -= .25; set_matrix(); glutPostRedisplay(); break; case '-': case '_': plane[3] += 2.0; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClipPlane(GL_CLIP_PLANE0, plane); set_matrix(); glutPostRedisplay(); break; case '+': case '=': plane[3] -= 2.0; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClipPlane(GL_CLIP_PLANE0, plane); set_matrix(); glutPostRedisplay(); break; case ' ': Init(0,0); break; } } static void SpecialKey( int key, int x, int y ) { (void) x; (void) y; switch (key) { case GLUT_KEY_LEFT: yrot -= 15.0; break; case GLUT_KEY_RIGHT: yrot += 15.0; break; case GLUT_KEY_UP: xrot += 15.0; break; case GLUT_KEY_DOWN: xrot -= 15.0; break; default: return; } set_matrix(); glutPostRedisplay(); } static GLint Args(int argc, char **argv) { GLint i; GLint mode = 0; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-sb") == 0) { doubleBuffer = GL_FALSE; } else if (strcmp(argv[i], "-db") == 0) { doubleBuffer = GL_TRUE; } else if (strcmp(argv[i], "-info") == 0) { PrintInfo = GL_TRUE; } else if (strcmp(argv[i], "-10") == 0) { maxverts = 10; } else if (strcmp(argv[i], "-100") == 0) { maxverts = 100; } else if (strcmp(argv[i], "-1000") == 0) { maxverts = 1000; } else { printf("%s (Bad option).\n", argv[i]); return QUIT; } } return mode; } int main(int argc, char **argv) { GLenum type; char *extensions; GLuint arg_mode = Args(argc, argv); if (arg_mode & QUIT) exit(0); read_surface( "isosurf.dat" ); glutInitWindowPosition(0, 0); glutInitWindowSize(400, 400); type = GLUT_DEPTH; type |= GLUT_RGB; type |= (doubleBuffer) ? GLUT_DOUBLE : GLUT_SINGLE; glutInitDisplayMode(type); if (glutCreateWindow("Isosurface") <= 0) { exit(0); } /* Make sure server supports the vertex array extension */ extensions = (char *) glGetString( GL_EXTENSIONS ); if (!strstr( extensions, "GL_EXT_vertex_array" )) { printf("Vertex arrays not supported by this renderer\n"); allowed &= ~(LOCKED|DRAW_ARRAYS|DRAW_ELTS|ARRAY_ELT); } else if (!strstr( extensions, "GL_EXT_compiled_vertex_array" )) { printf("Compiled vertex arrays not supported by this renderer\n"); allowed &= ~LOCKED; } Init(argc, argv); ModeMenu(arg_mode); glutCreateMenu(ModeMenu); glutAddMenuEntry("GL info", GLINFO); glutAddMenuEntry("", 0); glutAddMenuEntry("Lit", LIT); glutAddMenuEntry("Unlit", UNLIT); glutAddMenuEntry("Reflect", REFLECT); glutAddMenuEntry("", 0); glutAddMenuEntry("Smooth", SHADE_SMOOTH); glutAddMenuEntry("Flat", SHADE_FLAT); glutAddMenuEntry("", 0); glutAddMenuEntry("Fog", FOG); glutAddMenuEntry("No Fog", NO_FOG); glutAddMenuEntry("", 0); glutAddMenuEntry("Stipple", STIPPLE); glutAddMenuEntry("No Stipple", NO_STIPPLE); glutAddMenuEntry("", 0); glutAddMenuEntry("Polygon Mode Fill", POLYGON_FILL); glutAddMenuEntry("Polygon Mode Line", POLYGON_LINE); glutAddMenuEntry("", 0); glutAddMenuEntry("Point Filtered", POINT_FILTER); glutAddMenuEntry("Linear Filtered", LINEAR_FILTER); glutAddMenuEntry("", 0); glutAddMenuEntry("GL_TRIANGLES", TRIANGLES); glutAddMenuEntry("GL_TRIANGLE_STRIPS", STRIPS); glutAddMenuEntry("GL_POINTS", POINTS); glutAddMenuEntry("", 0); glutAddMenuEntry("Displaylist", DISPLAYLIST); glutAddMenuEntry("Immediate", IMMEDIATE); glutAddMenuEntry("", 0); if (allowed & LOCKED) { glutAddMenuEntry("Locked Arrays (CVA)", LOCKED); glutAddMenuEntry("Unlocked Arrays", UNLOCKED); glutAddMenuEntry("", 0); } glutAddMenuEntry("glVertex", GLVERTEX); if (allowed & DRAW_ARRAYS) { glutAddMenuEntry("glDrawElements", DRAW_ELTS); glutAddMenuEntry("glDrawArrays", DRAW_ARRAYS); glutAddMenuEntry("glArrayElement", ARRAY_ELT); } glutAddMenuEntry("", 0); glutAddMenuEntry("Quit", QUIT); glutAttachMenu(GLUT_RIGHT_BUTTON); glutReshapeFunc(Reshape); glutKeyboardFunc(Key); glutSpecialFunc(SpecialKey); glutDisplayFunc(Display); glutMainLoop(); return 0; }