/** * My first GLUT prog. * Uses most GLUT calls to prove it all works. * G Edwards, 30 Aug 95. * * Notes: * Display lists are not shared between windows, and there doesn't seem to be * any provision for this in GLUT. See glxCreateContext. * * The windows are internally indexed 0,1,2,3,4,5,6. The actual window ids * returned by glut are held in winId[0], ... * * Todo: * * Could reorder the windows so 0,1,2,3,4,5,6 are the gfx, 7,8 text. * * 30 Aug 95 GJE Created. Version 1.00 * 05 Sep 95 GJE Version 1.01. * 07 Sep 95 GJE Version 1.02. More or less complete. All possible GLUT * calls used, except dials/buttons/tablet/spaceball stuff. * 15 Sep 95 GJE Add "trackball" code. * * Calls not used yet: these callbacks are registered but inactive. * * glutSpaceballFunc * glutButtonBoxFunc * glutDialsFunc * glutTabletMotionFunc * glutTabletButtonFunc * * Tested on: * R3K Indigo Starter * R4K Indigo Elan * R4K Indy XZ * R4K Indy XL * R4K Indigo2 Extreme */ #include #include #include #include #include /* Controls */ #define VERSION "1.00" #define DATE "16Sep95" #define DELAY 1000 /* delay for timer test */ #define MENUDELAY 200 /* hack to fix glutMenuStateFunc bug */ #define MAXWIN 9 /* max no. of windows */ int AUTODELAY = 1500; /* delay in demo mode */ #define VERSIONLONG "Version " VERSION "/" DATE ", compiled " __DATE__ ", " __TIME__ ", file " __FILE__ int pos[MAXWIN][2] = { {50, 150}, /* win 0 */ {450, 150}, /* win 1 */ {50, 600}, /* win 2 */ {450, 600}, /* win 3 */ {10, 10}, /* subwin 4 (relative to parent win 0) */ {300, 400}, /* help win 5 */ {850, 150}, /* cmap win 6 */ {850, 600}, /* cmap win 7 */ {250, 450} /* text win 8 */ }; int size[MAXWIN][2] = { {350, 350}, /* win 0 */ {350, 350}, /* win 1 */ {350, 350}, /* win 2 */ {350, 350}, /* win 3 */ {200, 200}, /* subwin 4 */ {700, 300}, /* help win 5 */ {350, 350}, /* cmap win 6 */ {350, 350}, /* cmap win 7 */ {800, 450} /* text win 8 */ }; /* Macros */ #define PR if(debug)printf /* #define GLNEWLIST(a, b) glNewList(a, b), fprintf(stderr, "creating list %d \n", a); */ /* #define GLCALLLIST(a) glCallList(a), fprintf(stderr, "calling list %d \n", a); */ /* #define GLUTSETWINDOW(x) glutSetWindow(x), fprintf(stderr, "gsw at %d\n", __LINE__) */ /* Globals */ int winId[MAXWIN] = {0}; /* table of glut window id's */ GLboolean winVis[MAXWIN] = {GL_FALSE}; /* is window visible */ GLboolean text[MAXWIN] = {GL_FALSE}; /* is text on */ GLboolean winFreeze[MAXWIN] = {GL_FALSE}; /* user requested menuFreeze */ GLboolean menuFreeze = GL_FALSE; /* menuFreeze while menus posted */ GLboolean timerOn = GL_FALSE; /* timer active */ GLboolean animation = GL_TRUE; /* idle func animation on */ GLboolean debug = GL_FALSE; /* dump all events */ GLboolean showKeys = GL_FALSE; /* dump key events */ GLboolean demoMode = GL_FALSE; /* run automatic demo */ GLboolean backdrop = GL_FALSE; /* use backdrop polygon */ GLboolean passive = GL_FALSE; /* report passive motions */ GLboolean leftDown = GL_FALSE; /* left button down ? */ GLboolean middleDown = GL_FALSE; /* middle button down ? */ int displayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH; int currentShape = 0; /* current glut shape */ int scrollLine = 0, scrollCol = 0; /* help scrolling params */ int lineWidth = 1; /* line width */ int angle = 0; /* global rotation angle */ char *textPtr[1000] = {0}; /* pointers to text window text */ int textCount = 0, helpCount = 0; /* text list indexes */ float scaleFactor = 0.0; /* window size scale factor */ #ifdef ALPHA #undef ALPHA /* Avoid problems with DEC's ALPHA machines. */ #endif int menu1, menu2, menu3, menu4, menu5, menu6 = 0, menu7, menu8; enum { RGBA, INDEX, SINGLE, DOUBLEBUFFER, DEPTH, ACCUM, ALPHA, STENCIL, MULTISAMPLE, STEREO, MODES }; char *modeNames[] = {"RGBA", "INDEX", "SINGLE", "DOUBLE", "DEPTH", "ACCUM", "ALPHA", "STENCIL", "MULTISAMPLE", "STEREO"}; int glutMode[] = {GLUT_RGBA, GLUT_INDEX, GLUT_SINGLE, GLUT_DOUBLE, GLUT_DEPTH, GLUT_ACCUM, GLUT_ALPHA, GLUT_STENCIL, GLUT_MULTISAMPLE, GLUT_STEREO}; int modes[MODES] = {0}; GLboolean menuButton[3] = {0, 0, 1}; enum { MOUSEBUTTON, MOUSEMOTION, APPLY, RESET }; /* Prototypes */ void gfxInit(int); void drawScene(void); void idleFunc(void); void reshapeFunc(int width, int height); void visible(int state); void keyFunc(unsigned char key, int x, int y); void mouseFunc(int button, int state, int x, int y); void motionFunc(int x, int y); void passiveMotionFunc(int x, int y); void entryFunc(int state); void specialFunc(int key, int x, int y); void menuStateFunc(int state); void timerFunc(int value); #if 0 void delayedReinstateMenuStateCallback(int value); #endif void menuFunc(int value); void showText(void); void textString(int x, int y, char *str, void *font); void strokeString(int x, int y, char *str, void *font); void makeMenus(void); int idToIndex(int id); void setInitDisplayMode(void); void createMenu6(void); void removeCallbacks(void); void addCallbacks(void); void dumpIds(void); void updateHelp(void); void updateAll(void); void killWindow(int index); void makeWindow(int index); void warning(char *msg); void autoDemo(int); void positionWindow(int index); void reshapeWindow(int index); void iconifyWindow(int index); void showWindow(int index); void hideWindow(int index); void pushWindow(int index); void popWindow(int index); void attachMenus(void); void killAllWindows(void); void makeAllWindows(void); void updateText(void); void updateScrollWindow(int index, char **ptr); void redefineShapes(int shape); GLboolean match(char *, char *); void checkArgs(int argc, char *argv[]); void scaleWindows(float); void commandLineHelp(void); void trackBall(int mode, int button, int state, int x, int y); void spaceballMotionCB(int, int, int); void spaceballRotateCB(int, int, int); void spaceballButtonCB(int, int); void buttonBoxCB(int, int); void dialsCB(int, int); void tabletMotionCB(int, int); void tabletButtonCB(int, int, int, int); /* strdup is actually not a standard ANSI C or POSIX routine so implement a private one. OpenVMS does not have a strdup; Linux's standard libc doesn't declare strdup by default (unless BSD or SVID interfaces are requested). */ static char * stralloc(const char *string) { char *copy; copy = malloc(strlen(string) + 1); if (copy == NULL) return NULL; strcpy(copy, string); return copy; } /* main */ int main(int argc, char **argv) { /* General init */ glutInit(&argc, argv); /* Check args */ checkArgs(argc, argv); /* Scale window position/size if needed. Ignore aspect ratios. */ if (scaleFactor > 0.0) scaleWindows(scaleFactor); else scaleWindows(glutGet(GLUT_SCREEN_WIDTH) / 1280.0); /* Set initial display mode */ modes[RGBA] = 1; modes[DOUBLEBUFFER] = 1; modes[DEPTH] = 1; setInitDisplayMode(); /* Set up menus */ makeMenus(); /* Make some windows */ makeWindow(0); makeWindow(1); /* Global callbacks */ glutIdleFunc(idleFunc); glutMenuStateFunc(menuStateFunc); /* Start demo if needed */ if (demoMode) autoDemo(-2); /* Fall into event loop */ glutMainLoop(); return 0; /* ANSI C requires main to return int. */ } /* gfxInit - Init opengl for each window */ void gfxInit(int index) { GLfloat grey10[] = {0.10, 0.10, 0.10, 1.0}; GLfloat grey20[] = {0.2, 0.2, 0.2, 1.0}; GLfloat black[] = {0.0, 0.0, 0.0, 0.0}; GLfloat diffuse0[] = {1.0, 0.0, 0.0, 1.0}; GLfloat diffuse1[] = {0.0, 1.0, 0.0, 1.0}; GLfloat diffuse2[] = {1.0, 1.0, 0.0, 1.0}; GLfloat diffuse3[] = {0.0, 1.0, 1.0, 1.0}; GLfloat diffuse4[] = {1.0, 0.0, 1.0, 1.0}; #define XX 3 #define YY 3 #define ZZ -2.5 float vertex[][3] = { {-XX, -YY, ZZ}, {+XX, -YY, ZZ}, {+XX, +YY, ZZ}, {-XX, +YY, ZZ} }; /* warning: This func mixes RGBA and CMAP calls in an ugly fashion */ redefineShapes(currentShape); /* set up display lists */ glutSetWindow(winId[index]); /* hack - redefineShapes changes glut win */ /* Shaded backdrop square (RGB or CMAP) */ glNewList(100, GL_COMPILE); glPushAttrib(GL_LIGHTING); glDisable(GL_LIGHTING); glBegin(GL_POLYGON); glColor4fv(black); glIndexi(0); glVertex3fv(vertex[0]); glColor4fv(grey10); glIndexi(3); glVertex3fv(vertex[1]); glColor4fv(grey20); glIndexi(4); glVertex3fv(vertex[2]); glColor4fv(grey10); glIndexi(7); glVertex3fv(vertex[3]); glEnd(); glPopAttrib(); glIndexi(9); glEndList(); /* Set proj+view */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(40.0, 1.0, 1.0, 20.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.); glTranslatef(0.0, 0.0, -1.0); if (index == 6 || index == 7) goto colorindex; /* Set basic material, lighting for RGB windows */ if (index == 0) glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse0); else if (index == 1) glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse1); else if (index == 2) glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse2); else if (index == 3) glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse3); else if (index == 4) glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse4); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); if (index == 4) glClearColor(0.15, 0.15, 0.15, 1); else glClearColor(0.1, 0.1, 0.1, 1.0); return; /* Set GL basics for CMAP windows 6,7 */ colorindex: glEnable(GL_DEPTH_TEST); if (glutGet(GLUT_WINDOW_COLORMAP_SIZE) < 16) warning("Color map size too small for color index window"); /* Try to reuse an existing color map */ if ((index == 6) && (winId[7] != 0)) { glutCopyColormap(winId[7]); } else if ((index == 7) && (winId[6] != 0)) { glutCopyColormap(winId[6]); } else { glutSetColor(8, 0.1, 0.1, 0.1); glutSetColor(9, 1.0, 0.5, 0.0); glutSetColor(10, 1.0, 0.6, 0.8); } glClearIndex(8); glIndexi(index + 3); } /* makeMenus - Create popup menus */ void makeMenus(void) { /* General control / debug */ menu2 = glutCreateMenu(menuFunc); glutAddMenuEntry("toggle auto demo mode (a)", 312); glutAddMenuEntry("toggle freezing in menus", 300); glutAddMenuEntry("toggle text per window (t)", 301); glutAddMenuEntry("toggle global timer", 302); glutAddMenuEntry("toggle global animation", 303); glutAddMenuEntry("toggle per window animation", 304); glutAddMenuEntry("toggle debug prints (D)", 305); glutAddMenuEntry("toggle shaded backdrop", 307); glutAddMenuEntry("toggle passive motion callback", 308); glutAddMenuEntry("increase line width (l)", 310); glutAddMenuEntry("decrease line width (L)", 311); /* Shapes */ menu3 = glutCreateMenu(menuFunc); glutAddMenuEntry("sphere", 200); glutAddMenuEntry("cube", 201); glutAddMenuEntry("cone", 202); glutAddMenuEntry("torus", 203); glutAddMenuEntry("dodecahedron", 204); glutAddMenuEntry("octahedron", 205); glutAddMenuEntry("tetrahedron", 206); glutAddMenuEntry("icosahedron", 207); glutAddMenuEntry("teapot", 208); /* Open/close windows */ menu4 = glutCreateMenu(menuFunc); glutAddMenuEntry("open all windows", 450); glutAddMenuEntry("close all windows", 451); glutAddMenuEntry(" ", 9999); glutAddMenuEntry("create win 0", 400); glutAddMenuEntry("create win 1", 401); glutAddMenuEntry("create win 2", 402); glutAddMenuEntry("create win 3", 403); glutAddMenuEntry("create sub window", 404); glutAddMenuEntry("create color index win 6", 406); glutAddMenuEntry("create color index win 7", 407); glutAddMenuEntry(" ", 9999); glutAddMenuEntry("destroy win 0", 410); glutAddMenuEntry("destroy win 1", 411); glutAddMenuEntry("destroy win 2", 412); glutAddMenuEntry("destroy win 3", 413); glutAddMenuEntry("destroy sub window", 414); glutAddMenuEntry("destroy color index win 6", 416); glutAddMenuEntry("destroy color index win 7", 417); /* Window manager stuff */ menu5 = glutCreateMenu(menuFunc); glutAddMenuEntry("move current win", 430); glutAddMenuEntry("resize current win", 431); glutAddMenuEntry("iconify current win", 432); glutAddMenuEntry("show current win", 433); glutAddMenuEntry("hide current win", 434); glutAddMenuEntry("push current win", 435); glutAddMenuEntry("pop current win", 436); glutAddMenuEntry(" ", 9999); glutAddMenuEntry("move win 1", 420); glutAddMenuEntry("resize win 1", 421); glutAddMenuEntry("iconify win 1", 422); glutAddMenuEntry("show win 1", 423); glutAddMenuEntry("hide win 1", 424); glutAddMenuEntry("push win 1", 425); glutAddMenuEntry("pop win 1", 426); /* Gfx modes */ createMenu6(); /* build dynamically */ /* Texty reports */ menu7 = glutCreateMenu(menuFunc); glutAddMenuEntry("report current win modes", 700); glutAddMenuEntry("report current device data", 701); glutAddMenuEntry("check OpenGL extensions", 702); glutAddMenuEntry("dump internal data (d)", 703); /* Play with menus */ menu8 = glutCreateMenu(menuFunc); glutAddMenuEntry("toggle menus on left button", 805); glutAddMenuEntry("toggle menus on middle button", 806); glutAddMenuEntry("toggle menus on right button", 807); glutAddMenuEntry("---------------------------", 9999); glutAddMenuEntry("add plain items", 800); glutAddMenuEntry("add submenu items", 801); glutAddMenuEntry("change new entries to plain items", 802); glutAddMenuEntry("change new entries to submenus", 803); glutAddMenuEntry("remove all new items", 804); glutAddMenuEntry("---------------------------", 9999); /* Main menu */ menu1 = glutCreateMenu(menuFunc); glutAddSubMenu("control", menu2); glutAddSubMenu("shapes", menu3); glutAddSubMenu("windows", menu4); glutAddSubMenu("window ops", menu5); glutAddSubMenu("gfx modes", menu6); glutAddSubMenu("reports", menu7); glutAddSubMenu("menus", menu8); glutAddMenuEntry("help (h)", 101); glutAddMenuEntry("quit (esc)", 100); } /* createMenu6 - Dynamically rebuild menu of display modes to show current choices */ void createMenu6(void) { char str[100]; int i; if (menu6 != 0) glutDestroyMenu(menu6); menu6 = glutCreateMenu(menuFunc); for (i = 0; i < MODES; i++) { sprintf(str, "%srequest %s", (modes[i] ? "+ " : " "), modeNames[i]); glutAddMenuEntry(str, 602 + i); } } /* menuFunc - Process return codes from popup menus */ void menuFunc(int value) { static int initItems = 10; int items, m; if (initItems == 0) { glutSetMenu(menu8); initItems = glutGet(GLUT_MENU_NUM_ITEMS); } PR("Menu returned value %d \n", value); switch (value) { /* GLUT shapes */ case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: redefineShapes(value - 200); break; /* Overall controls */ case 300: menuFreeze = !menuFreeze; break; case 301: text[idToIndex(glutGetWindow())] = !(text[idToIndex(glutGetWindow())]); break; case 302: timerOn = !timerOn; if (timerOn) glutTimerFunc(DELAY, timerFunc, 1); break; case 303: animation = !animation; if (animation) glutIdleFunc(idleFunc); else glutIdleFunc(NULL); break; case 304: winFreeze[idToIndex(glutGetWindow())] = !(winFreeze[idToIndex( glutGetWindow())]); break; case 305: debug = !debug; break; case 307: backdrop = !backdrop; break; case 308: passive = !passive; if (passive) glutPassiveMotionFunc(passiveMotionFunc); else glutPassiveMotionFunc(NULL); break; case 310: lineWidth += 1; updateAll(); break; case 311: lineWidth -= 1; if (lineWidth < 1) lineWidth = 1; updateAll(); break; case 312: demoMode = !demoMode; if (demoMode) autoDemo(-2); break; /* Window create/destroy. */ /* Creates */ case 400: makeWindow(0); break; case 401: makeWindow(1); break; case 402: makeWindow(2); break; case 403: makeWindow(3); break; case 404: makeWindow(4); break; case 406: makeWindow(6); break; case 407: makeWindow(7); break; /* Destroys */ case 410: killWindow(0); break; case 411: killWindow(1); break; case 412: killWindow(2); break; case 413: killWindow(3); break; case 414: killWindow(4); break; case 416: killWindow(6); break; case 417: killWindow(7); break; case 450: makeAllWindows(); break; case 451: killAllWindows(); break; /* Window movements etc. */ case 420: positionWindow(1); break; case 421: reshapeWindow(1); break; case 422: iconifyWindow(1); break; case 423: showWindow(1); break; case 424: hideWindow(1); break; case 425: pushWindow(1); break; case 426: popWindow(1); break; case 430: positionWindow(idToIndex(glutGetWindow())); break; case 431: reshapeWindow(idToIndex(glutGetWindow())); break; case 432: iconifyWindow(idToIndex(glutGetWindow())); break; case 433: showWindow(idToIndex(glutGetWindow())); break; case 434: hideWindow(idToIndex(glutGetWindow())); break; case 435: pushWindow(idToIndex(glutGetWindow())); break; case 436: popWindow(idToIndex(glutGetWindow())); break; /* Test gfx modes. */ case 600: makeWindow(3); break; case 601: killWindow(3); break; case 602: case 603: case 604: case 605: case 606: case 607: case 608: case 609: case 610: case 611: modes[value - 602] = !modes[value - 602]; setInitDisplayMode(); break; /* Text reports */ /* This is pretty ugly. */ #define INDENT 30 #define REPORTSTART(text) \ printf("\n" text "\n"); \ textPtr[0] = (char *)malloc(strlen(text)+1); \ strcpy(textPtr[0], text); \ textCount = 1; #define REPORTEND \ scrollLine = 0; \ textPtr[textCount] = NULL; \ makeWindow(8); \ updateText(); #define GLUTGET(name) \ { \ char str[100], str2[100]; \ int s, len; \ sprintf(str, # name); \ len = (int) strlen(# name); \ for(s = 0 ; s < INDENT-len; s++) \ strcat(str, " "); \ sprintf(str2, ": %d\n",glutGet(name)); \ strcat(str, str2); \ printf(str); \ textPtr[textCount] = stralloc(str); \ textCount++; \ } case 700: printf("XXXXXX glutGetWindow = %d\n", glutGetWindow()); REPORTSTART("glutGet():"); GLUTGET(GLUT_WINDOW_X); GLUTGET(GLUT_WINDOW_Y); GLUTGET(GLUT_WINDOW_WIDTH); GLUTGET(GLUT_WINDOW_HEIGHT); GLUTGET(GLUT_WINDOW_BUFFER_SIZE); GLUTGET(GLUT_WINDOW_STENCIL_SIZE); GLUTGET(GLUT_WINDOW_DEPTH_SIZE); GLUTGET(GLUT_WINDOW_RED_SIZE); GLUTGET(GLUT_WINDOW_GREEN_SIZE); GLUTGET(GLUT_WINDOW_BLUE_SIZE); GLUTGET(GLUT_WINDOW_ALPHA_SIZE); GLUTGET(GLUT_WINDOW_ACCUM_RED_SIZE); GLUTGET(GLUT_WINDOW_ACCUM_GREEN_SIZE); GLUTGET(GLUT_WINDOW_ACCUM_BLUE_SIZE); GLUTGET(GLUT_WINDOW_ACCUM_ALPHA_SIZE); GLUTGET(GLUT_WINDOW_DOUBLEBUFFER); GLUTGET(GLUT_WINDOW_RGBA); GLUTGET(GLUT_WINDOW_PARENT); GLUTGET(GLUT_WINDOW_NUM_CHILDREN); GLUTGET(GLUT_WINDOW_COLORMAP_SIZE); GLUTGET(GLUT_WINDOW_NUM_SAMPLES); GLUTGET(GLUT_STEREO); GLUTGET(GLUT_SCREEN_WIDTH); GLUTGET(GLUT_SCREEN_HEIGHT); GLUTGET(GLUT_SCREEN_HEIGHT_MM); GLUTGET(GLUT_SCREEN_WIDTH_MM); GLUTGET(GLUT_MENU_NUM_ITEMS); GLUTGET(GLUT_DISPLAY_MODE_POSSIBLE); GLUTGET(GLUT_INIT_DISPLAY_MODE); GLUTGET(GLUT_INIT_WINDOW_X); GLUTGET(GLUT_INIT_WINDOW_Y); GLUTGET(GLUT_INIT_WINDOW_WIDTH); GLUTGET(GLUT_INIT_WINDOW_HEIGHT); GLUTGET(GLUT_ELAPSED_TIME); REPORTEND; break; #define GLUTDEVGET(name) \ { \ char str[100], str2[100]; \ int len, s; \ sprintf(str, # name); \ len = (int) strlen(# name); \ for(s = 0 ; s < INDENT-len; s++) \ strcat(str, " "); \ sprintf(str2, ": %d\n", \ glutDeviceGet(name)); \ strcat(str, str2); \ printf(str); \ textPtr[textCount] = stralloc(str); \ textCount++; \ } case 701: REPORTSTART("glutDeviceGet():"); GLUTDEVGET(GLUT_HAS_KEYBOARD); GLUTDEVGET(GLUT_HAS_MOUSE); GLUTDEVGET(GLUT_HAS_SPACEBALL); GLUTDEVGET(GLUT_HAS_DIAL_AND_BUTTON_BOX); GLUTDEVGET(GLUT_HAS_TABLET); GLUTDEVGET(GLUT_NUM_MOUSE_BUTTONS); GLUTDEVGET(GLUT_NUM_SPACEBALL_BUTTONS); GLUTDEVGET(GLUT_NUM_BUTTON_BOX_BUTTONS); GLUTDEVGET(GLUT_NUM_DIALS); GLUTDEVGET(GLUT_NUM_TABLET_BUTTONS); REPORTEND; break; #define EXTCHECK(name) \ { \ char str[100], str2[100]; \ int len, s; \ sprintf(str, # name); \ len = (int) strlen(# name); \ for(s = 0 ; s < INDENT-len; s++) \ strcat(str, " "); \ sprintf(str2, ": %s\n", \ glutExtensionSupported(# name)? \ "yes": "no"); \ strcat(str, str2); \ printf(str); \ textPtr[textCount] = stralloc(str); \ textCount++; \ } case 702: REPORTSTART("glutExtensionSupported():"); EXTCHECK(GL_EXT_abgr); EXTCHECK(GL_EXT_blend_color); EXTCHECK(GL_EXT_blend_minmax); EXTCHECK(GL_EXT_blend_logic_op); EXTCHECK(GL_EXT_blend_subtract); EXTCHECK(GL_EXT_polygon_offset); EXTCHECK(GL_EXT_texture); EXTCHECK(GL_EXT_guaranteed_to_fail); EXTCHECK(GLX_SGI_swap_control); EXTCHECK(GLX_SGI_video_sync); EXTCHECK(GLX_SGIS_multi_sample); REPORTEND; break; case 703: dumpIds(); break; /* Mess around with menus */ case 800: if (glutGetMenu() != menu8) /* just a test */ printf("glutGetMenu() returned unexpected value\n"); glutAddMenuEntry("help", 101); glutAddMenuEntry("help", 101); glutAddMenuEntry("help", 101); glutAddMenuEntry("help", 101); glutAddMenuEntry("help", 101); break; case 801: glutAddSubMenu("shapes", menu3); glutAddSubMenu("shapes", menu3); glutAddSubMenu("shapes (a long string to break menus with)", menu3); glutAddSubMenu("shapes", menu3); glutAddSubMenu("shapes", menu3); break; case 802: items = glutGet(GLUT_MENU_NUM_ITEMS); for (m = initItems + 1; m <= items; m++) { glutChangeToMenuEntry(m, "help", 101); } break; case 803: items = glutGet(GLUT_MENU_NUM_ITEMS); for (m = initItems + 1; m <= items; m++) { glutChangeToSubMenu(m, "shapes", menu3); } break; case 804: items = glutGet(GLUT_MENU_NUM_ITEMS); /* reverse order so renumbering not aproblem */ for (m = items; m >= initItems + 1; m--) { glutRemoveMenuItem(m); } break; case 805: menuButton[0] = !menuButton[0]; attachMenus(); break; case 806: menuButton[1] = !menuButton[1]; attachMenus(); break; case 807: menuButton[2] = !menuButton[2]; attachMenus(); break; /* Direct menu items. */ case 100: exit(0); break; case 101: if (winId[5] == 0) makeWindow(5); else killWindow(5); break; case 9999: break; default: fprintf(stderr, "\007Unhandled case %d in menu callback\n", value); } } /* redefineShapes - Remake the shapes display lists */ void redefineShapes(int shape) { int i; #define C3 \ switch(i) \ { \ case 0: \ case 3: \ C1; \ break; \ \ case 1: \ case 2: \ case 4: \ case 6: \ case 7: \ C2; \ break; \ } \ currentShape = shape for (i = 0; i < MAXWIN; i++) { if (winId[i]) { glutSetWindow(winId[i]); if (glIsList(i + 1)) glDeleteLists(i + 1, 1); glNewList(i + 1, GL_COMPILE); switch (shape) { #undef C1 #define C1 glutSolidSphere(1.5, 10, 10) #undef C2 #define C2 glutWireSphere(1.5, 10, 10) case 0: C3; break; #undef C1 #define C1 glutSolidCube(2) #undef C2 #define C2 glutWireCube(2) case 1: C3; break; #undef C1 #define C1 glutSolidCone(1.5, 1.75, 10, 10); #undef C2 #define C2 glutWireCone(1.5, 1.75, 10, 10); case 2: C3; break; #undef C1 #define C1 glutSolidTorus(0.5, 1.1, 10, 10) #undef C2 #define C2 glutWireTorus(0.5, 1.1, 10, 10) case 3: C3; break; #undef C1 #define C1 glScalef(.8, .8, .8);glutSolidDodecahedron() #undef C2 #define C2 glScalef(.8, .8, .8);glutWireDodecahedron() case 4: C3; break; #undef C1 #define C1 glScalef(1.5, 1.5, 1.5);glutSolidOctahedron() #undef C2 #define C2 glScalef(1.5, 1.5, 1.5);glutWireOctahedron() case 5: C3; break; #undef C1 #define C1 glScalef(1.8, 1.8, 1.8);glutSolidTetrahedron() #undef C2 #define C2 glScalef(1.8, 1.8, 1.8);glutWireTetrahedron() case 6: C3; break; #undef C1 #define C1 glScalef(1.5, 1.5, 1.5);glutSolidIcosahedron() #undef C2 #define C2 glScalef(1.5, 1.5, 1.5);glutWireIcosahedron() case 7: C3; break; #undef C1 #define C1 glutSolidTeapot(1.5); #undef C2 #define C2 glutWireTeapot(1.5); case 8: C3; break; } glEndList(); } } } /* positionWindow - Shift a window */ void positionWindow(int index) { int x, y; if (winId[index] == 0) return; glutSetWindow(winId[index]); x = glutGet(GLUT_WINDOW_X); y = glutGet(GLUT_WINDOW_Y); glutPositionWindow(x + 50, y + 50); } /* reshapeWindow - Change window size a little */ void reshapeWindow(int index) { int x, y; if (winId[index] == 0) return; glutSetWindow(winId[index]); x = glutGet(GLUT_WINDOW_WIDTH); y = glutGet(GLUT_WINDOW_HEIGHT); /* glutReshapeWindow(x * (index % 2? 0.8: 1.2), y * (index % 2? 1.2: 0.8)); */ glutReshapeWindow(x * 1.0, y * 0.8); } /* iconifyWindow - Iconify a window */ void iconifyWindow(int index) { if (winId[index] == 0) return; glutSetWindow(winId[index]); glutIconifyWindow(); } /* showWindow - Show a window (map or uniconify it) */ void showWindow(int index) { if (winId[index] == 0) return; glutSetWindow(winId[index]); glutShowWindow(); } /* hideWindow - Hide a window (unmap it) */ void hideWindow(int index) { if (winId[index] == 0) return; glutSetWindow(winId[index]); glutHideWindow(); } /* pushWindow - Push a window */ void pushWindow(int index) { if (winId[index] == 0) return; glutSetWindow(winId[index]); glutPushWindow(); } /* popWindow - Pop a window */ void popWindow(int index) { if (winId[index] == 0) return; glutSetWindow(winId[index]); glutPopWindow(); } /* drawScene - Draw callback, triggered by expose events etc. in GLUT. */ void drawScene(void) { int winIndex; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); winIndex = idToIndex(glutGetWindow()); /* printf("drawScene for index %d, id %d\n", winIndex, glutGetWindow()); */ glPushMatrix(); glLineWidth(lineWidth); if (backdrop) glCallList(100); /* Left button spinning */ trackBall(APPLY, 0, 0, 0, 0); /* Apply continuous spinning */ glRotatef(angle, 0, 1, 0); glCallList(winIndex + 1); glPopMatrix(); if (text[winIndex]) showText(); glutSwapBuffers(); } /* showText - Render some text in the current GLUT window */ void showText(void) { glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, 100, 0, 100); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glColor3f(1.0, 1.0, 1.0); glIndexi(7); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glLineWidth(lineWidth); textString(1, 1, "GLUT_BITMAP_8_BY_13", GLUT_BITMAP_8_BY_13); textString(1, 5, "GLUT_BITMAP_9_BY_15", GLUT_BITMAP_9_BY_15); textString(1, 10, "GLUT_BITMAP_TIMES_ROMAN_10", GLUT_BITMAP_TIMES_ROMAN_10); textString(1, 15, "GLUT_BITMAP_TIMES_ROMAN_24", GLUT_BITMAP_TIMES_ROMAN_24); strokeString(1, 25, "GLUT_STROKE_ROMAN", GLUT_STROKE_ROMAN); strokeString(1, 35, "GLUT_STROKE_MONO_ROMAN", GLUT_STROKE_MONO_ROMAN); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } /* textString - Bitmap font string */ void textString(int x, int y, char *msg, void *font) { glRasterPos2f(x, y); while (*msg) { glutBitmapCharacter(font, *msg); msg++; } } /* strokeString - Stroke font string */ void strokeString(int x, int y, char *msg, void *font) { glPushMatrix(); glTranslatef(x, y, 0); glScalef(.04, .04, .04); while (*msg) { glutStrokeCharacter(font, *msg); msg++; } glPopMatrix(); } /* idleFunc - GLUT idle func callback - animates windows */ void idleFunc(void) { int i; if (!leftDown && !middleDown) angle += 1; angle = angle % 360; for (i = 0; i < MAXWIN; i++) { if (winId[i] && winVis[i] && !winFreeze[i]) { glutSetWindow(winId[i]); glutPostRedisplay(); } } } /* reshapeFunc - Reshape callback. */ void reshapeFunc(int width, int height) { int winId; float aspect; winId = glutGetWindow(); PR("reshape callback for window id %d \n", winId); glViewport(0, 0, width, height); aspect = (float) width / height; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(40.0, aspect, 1.0, 20.0); glMatrixMode(GL_MODELVIEW); } /* visible - Visibility callback. Turn off rendering in invisible windows */ void visible(int state) { int winId; static GLboolean someVisible = GL_TRUE; winId = glutGetWindow(); /* printf("visible: state = %d \n", state); */ if (state == GLUT_VISIBLE) { PR("Window id %d visible \n", winId); winVis[idToIndex(winId)] = GL_TRUE; } else { PR("Window %d not visible \n", winId); winVis[idToIndex(winId)] = GL_FALSE; } if ((winVis[0] == GL_FALSE) && (winVis[1] == GL_FALSE) && (winVis[2] == GL_FALSE) && (winVis[3] == GL_FALSE) && (winVis[6] == GL_FALSE) && (winVis[7] == GL_FALSE)) { glutIdleFunc(NULL); PR("All windows not visible; idle func disabled\n"); someVisible = GL_FALSE; } else { if (!someVisible) { PR("Some windows now visible; idle func enabled\n"); someVisible = GL_TRUE; if (animation) glutIdleFunc(idleFunc); } } } /* keyFunc - Ascii key callback */ /* ARGSUSED1 */ void keyFunc(unsigned char key, int x, int y) { int i, ii; if (debug || showKeys) printf("Ascii key '%c' 0x%02x\n", key, key); switch (key) { case 0x1b: exit(0); break; case 'a': demoMode = !demoMode; if (demoMode) autoDemo(-2); break; case 's': AUTODELAY = AUTODELAY * 0.666; break; case 'S': AUTODELAY = AUTODELAY * 1.5; break; case 'q': killWindow(idToIndex(glutGetWindow())); break; case 'k': showKeys = !showKeys; break; case 'p': demoMode = !demoMode; if (demoMode) autoDemo(-999); break; case 'D': debug = !debug; break; case 'd': dumpIds(); break; case 'h': if (winId[5] == 0) makeWindow(5); else killWindow(5); break; case 't': ii = idToIndex(glutGetWindow()); text[ii] = !text[ii]; break; case 'r': trackBall(RESET, 0, 0, 0, 0); break; case 'l': lineWidth += 1; updateAll(); break; case 'L': lineWidth -= 1; if (lineWidth < 1) lineWidth = 1; updateAll(); break; case '0': case '1': case '2': case '3': case '4': case '6': i = key - '0'; winVis[i] = !winVis[i]; break; case ')': makeWindow(0); break; case '!': makeWindow(1); break; case '@': makeWindow(2); break; case '#': makeWindow(3); break; } } /* specialFunc - Special keys callback (F keys, cursor keys etc. */ /* ARGSUSED1 */ void specialFunc(int key, int x, int y) { if (debug || showKeys) printf("Special key %d\n", key); switch (key) { case GLUT_KEY_PAGE_DOWN: scrollLine += 10; updateHelp(); updateText(); break; case GLUT_KEY_PAGE_UP: scrollLine -= 10; updateHelp(); updateText(); break; case GLUT_KEY_DOWN: scrollLine += 1; updateHelp(); updateText(); break; case GLUT_KEY_UP: scrollLine -= 1; updateHelp(); updateText(); break; case GLUT_KEY_HOME: scrollLine = 0; updateHelp(); updateText(); break; case GLUT_KEY_END: scrollLine = 9999; updateHelp(); updateText(); break; case GLUT_KEY_RIGHT: scrollCol -= 1; updateHelp(); updateText(); break; case GLUT_KEY_LEFT: scrollCol += 1; updateHelp(); updateText(); break; } } /* mouseFunc - Mouse button callback */ void mouseFunc(int button, int state, int x, int y) { PR("Mouse button %d, state %d, at pos %d, %d\n", button, state, x, y); trackBall(MOUSEBUTTON, button, state, x, y); } /* motionFunc - Mouse movement (with a button down) callback */ void motionFunc(int x, int y) { PR("Mouse motion at %d, %d\n", x, y); trackBall(MOUSEMOTION, 0, 0, x, y); glutPostRedisplay(); } /* passiveMotionFunc - Mouse movement (with no button down) callback */ void passiveMotionFunc(int x, int y) { printf("Mouse motion at %d, %d\n", x, y); } /* entryFunc - Window entry event callback */ void entryFunc(int state) { int winId = glutGetWindow(); PR("Entry event: window id %d (index %d), state %d \n", winId, idToIndex( winId), state); } /* menuStateFunc - Callback to tell us when menus are popped up/down. */ int menu_state = GLUT_MENU_NOT_IN_USE; void menuStateFunc(int state) { printf("menu stated = %d\n", state); menu_state = state; if (glutGetWindow() == 0) { PR("menuStateFunc: window invalid\n"); return; } PR("Menus are%sin use\n", state == GLUT_MENU_IN_USE ? " " : " not "); if ((state == GLUT_MENU_IN_USE) && menuFreeze) glutIdleFunc(NULL); else if (animation) glutIdleFunc(idleFunc); } /* timerFunc - General test of global timer */ void timerFunc(int value) { printf("timer callback: value %d\n", value); if (timerOn) { glutTimerFunc(DELAY, timerFunc, 1); } } #if 0 /* delayedReinstateMenuStateCallback - Hack to reinstate MenuStateCallback after a while. */ void delayedReinstateMenuStateCallback(int state) { glutMenuStateFunc(menuStateFunc); } #endif /* setInitDisplayMode - update display modes from display mode menu */ void setInitDisplayMode(void) { int i; displayMode = 0; for (i = 0; i < MODES; i++) { if (modes[i]) { /* printf("Requesting %s \n", modeNames[i]); */ displayMode |= glutMode[i]; } } glutInitDisplayMode(displayMode); createMenu6(); if (!glutGet(GLUT_DISPLAY_MODE_POSSIBLE)) warning("This display mode not supported\n"); } /* makeWindow - Create one of the windows */ void makeWindow(int index) { char str[99]; if (winId[index] != 0) { /* warning("Attempt to create window which is already created"); */ return; } switch (index) { case 0: /* ordinary RGB windows */ case 1: case 2: case 3: setInitDisplayMode(); glutInitWindowPosition(pos[index][0], pos[index][1]); glutInitWindowSize(size[index][0], size[index][1]); winId[index] = glutCreateWindow(" "); PR("Window %d id = %d \n", index, winId[index]); gfxInit(index); addCallbacks(); sprintf(str, "window %d (RGB)", index); glutSetWindowTitle(str); sprintf(str, "icon %d", index); glutSetIconTitle(str); glutSetMenu(menu1); glutAttachMenu(GLUT_RIGHT_BUTTON); break; case 4: /* subwindow */ setInitDisplayMode(); winId[index] = glutCreateSubWindow(winId[0], pos[index][0], pos[index] [1], size[index][0], size[index][1]); PR("Window %d id = %d \n", index, winId[index]); gfxInit(index); glutDisplayFunc(drawScene); glutVisibilityFunc(visible); glutReshapeFunc(reshapeFunc); break; case 5: /* help window */ case 8: /* text window */ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowPosition(pos[index][0], pos[index][1]); glutInitWindowSize(size[index][0], size[index][1]); winId[index] = glutCreateWindow(" "); PR("Window %d id = %d \n", index, winId[index]); /* addCallbacks(); */ glutKeyboardFunc(keyFunc); glutSpecialFunc(specialFunc); glClearColor(0.15, 0.15, 0.15, 1.0); glColor3f(1, 1, 1); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, 300, 0, 100); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (index == 5) { glutDisplayFunc(updateHelp); glutSetWindowTitle("help (RGB) win 5"); glutSetIconTitle("help"); } else { glutDisplayFunc(updateText); glutSetWindowTitle("text (RGB) win 8"); glutSetIconTitle("text"); } glutSetMenu(menu1); glutAttachMenu(GLUT_RIGHT_BUTTON); break; case 6: /* color index window */ case 7: /* color index window */ glutInitDisplayMode(GLUT_DOUBLE | GLUT_INDEX | GLUT_DEPTH); glutInitWindowPosition(pos[index][0], pos[index][1]); glutInitWindowSize(size[index][0], size[index][1]); winId[index] = glutCreateWindow(" "); PR("Window %d id = %d \n", index, winId[index]); gfxInit(index); addCallbacks(); sprintf(str, "window %d (color index)", index); glutSetWindowTitle(str); sprintf(str, "icon %d", index); glutSetIconTitle(str); glutSetMenu(menu1); glutAttachMenu(GLUT_RIGHT_BUTTON); break; } } /* killWindow - Kill one of the main windows */ void killWindow(int index) { int i; if (winId[index] == 0) { /* fprintf(stderr, "Attempt to kill invalid window in killWindow\n"); */ return; } PR("Killing win %d\n", index); glutSetWindow(winId[index]); /* Disable all callbacks for safety, although glutDestroyWindow should do this. */ removeCallbacks(); glutDestroyWindow(winId[index]); winId[index] = 0; winVis[index] = GL_FALSE; #if 0 /* If we reinstate the menu state func here, prog breaks. So reinstate it a little later. */ glutTimerFunc(MENUDELAY, delayedReinstateMenuStateCallback, 1); #endif if (index == 5) { /* help */ scrollLine = 0; scrollCol = 0; } if (index == 8) { /* text window */ for (i = 0; textPtr[i] != NULL; i++) { free(textPtr[i]); /* free the text strings */ textPtr[i] = NULL; } } } /* addCallbacks - Add some standard callbacks after creating a window */ void addCallbacks(void) { glutDisplayFunc(drawScene); glutVisibilityFunc(visible); glutReshapeFunc(reshapeFunc); glutKeyboardFunc(keyFunc); glutSpecialFunc(specialFunc); glutMouseFunc(mouseFunc); glutMotionFunc(motionFunc); glutEntryFunc(entryFunc); /* Callbacks for exotic input devices. Must get my dials & buttons back. */ glutSpaceballMotionFunc(spaceballMotionCB); glutSpaceballRotateFunc(spaceballRotateCB); glutSpaceballButtonFunc(spaceballButtonCB); glutButtonBoxFunc(buttonBoxCB); glutDialsFunc(dialsCB); glutTabletMotionFunc(tabletMotionCB); glutTabletButtonFunc(tabletButtonCB); } /* removeCallbacks - Remove all callbacks before destroying a window. GLUT probably does this anyway but we'll be safe. */ void removeCallbacks(void) { glutVisibilityFunc(NULL); glutReshapeFunc(NULL); glutKeyboardFunc(NULL); glutSpecialFunc(NULL); glutMouseFunc(NULL); glutMotionFunc(NULL); glutEntryFunc(NULL); } /* updateHelp - Update the help window after user scrolls. */ void updateHelp(void) { static char *helpPtr[] = { "(Use PGUP, PGDN, HOME, END, arrows to scroll help text) ", " ", "A demo program for GLUT. ", "G Edwards, Aug 95 ", "Exercises 99% of GLUT calls ", VERSIONLONG, " ", "This text uses GLUT_STROKE_MONO_ROMAN font, a built-in vector font.", "(Try resizing the help window). ", " ", "Keys: ", " esc quit ", " t toggle text on/off in each window ", " h toggle help ", " q quit current window ", " a auto demo ", " p pause/unpause demo ", " l increase line width (gfx & stroke text) ", " L decrease line width (gfx & stroke text) ", " r reset transforms ", " k show keyboard events ", " D show all events ", " ", "Mouse: ", " Left button: rotate ", " Middle button: pan ", " Left + middle: zoom ", NULL}; updateScrollWindow(5, helpPtr); } /* updateText - Update a text window */ void updateText(void) { int i; if (textPtr[0] == NULL) { for (i = 0; i < 20; i++) { textPtr[i] = (char *) malloc(50); strcpy(textPtr[i], "no current text"); } textPtr[20] = NULL; } updateScrollWindow(8, textPtr); } /* updateScrollWindow */ void updateScrollWindow(int index, char **ptr) { int i, j, lines = 0; if (winId[index] == 0) return; glutSetWindow(winId[index]); for (i = 0; ptr[i] != NULL; i++) lines++; if (scrollLine < 0) scrollLine = 0; if (scrollLine > (lines - 5)) scrollLine = lines - 5; glClear(GL_COLOR_BUFFER_BIT); glLineWidth(lineWidth); for (i = scrollLine, j = 1; ptr[i] != NULL; i++, j++) strokeString(scrollCol * 50, 100 - j * 6, ptr[i], GLUT_STROKE_MONO_ROMAN); glutSwapBuffers(); } /* updateAll - Update all visible windows after soem global change, eg. line width */ void updateAll(void) { int i; if (winId[5] != 0) updateHelp(); if (winId[8] != 0) updateText(); for (i = 0; i < MAXWIN; i++) if (winId[i]) { glutSetWindow(winId[i]); glutPostRedisplay(); } } /* idToIndex - Convert GLUT window id to our internal index */ int idToIndex(int id) { int i; for (i = 0; i < MAXWIN; i++) { if (winId[i] == id) return i; } fprintf(stderr, "error: id %d not found \n", id); return (-1); } /* warning - warning messages */ void warning(char *msg) { fprintf(stderr, "\007"); if (debug) { fprintf(stderr, "%s", msg); if (msg[strlen(msg)] != '\n') fprintf(stderr, "%s", "\n"); } } /* dumpIds - Debug: dump some internal data */ void dumpIds(void) { int i, j; printf("\nInternal data:\n"); for (i = 0; i < MAXWIN; i++) printf("Index %d, glut win id %d, visibility %d\n", i, winId[i], winVis[i]); for (i = 0; i < MAXWIN; i++) { if (winId[i]) glutSetWindow(winId[i]); else { printf("index %d - no glut window\n", i); continue; } for (j = 1; j <= MAXWIN; j++) printf("Index %d, display list %d %s defined\n", i, j, glIsList(j) ? "is " : "not"); } } /* autoDemo - Run auto demo/test This is a bit tricky. We need to start a timer sequence which progressively orders things to be done. The work really gets done when we return from our callback. Have to think about the event loop / callback design here. */ void autoDemo(int value) { #define STEP(a, b) \ case a: \ action(a); \ glutTimerFunc(AUTODELAY * b, autoDemo, next(a); \ break; static int index = 0; static int count = 0; static int restartValue = -2; if (value == -999) value = restartValue; restartValue = value; #define AUTODELAY2 AUTODELAY*0.66 /* fprintf(stderr, "autoDemo: value %d \n", value); */ if (!demoMode) return; if (menu_state == GLUT_MENU_IN_USE) { glutTimerFunc(AUTODELAY / 2, autoDemo, value); return; } switch (value) { /* Entry point; kill off existing windows. */ case -2: killAllWindows(); glutTimerFunc(AUTODELAY / 2, autoDemo, 1); break; /* Start making windows */ case -1: makeWindow(0); glutTimerFunc(AUTODELAY, autoDemo, 0); /* skip case 0 first time */ break; /* Change shape & backdrop */ case 0: currentShape = (currentShape + 1) % 9; redefineShapes(currentShape); count += 1; if (count % 2) backdrop = !backdrop; glutTimerFunc(AUTODELAY, autoDemo, 1); break; /* Keep making windows */ case 1: makeWindow(1); glutTimerFunc(AUTODELAY, autoDemo, 2); break; case 2: makeWindow(2); glutTimerFunc(AUTODELAY, autoDemo, 3); break; case 3: makeWindow(3); glutTimerFunc(AUTODELAY, autoDemo, 4); break; case 4: makeWindow(4); glutTimerFunc(AUTODELAY, autoDemo, 5); break; case 5: makeWindow(5); glutTimerFunc(AUTODELAY * 2, autoDemo, 51); break; case 51: makeWindow(6); glutTimerFunc(AUTODELAY * 2, autoDemo, 52); break; case 52: makeWindow(7); glutTimerFunc(AUTODELAY * 2, autoDemo, 53); break; /* Kill last 3 windows, leave 4 up. */ case 53: killWindow(7); glutTimerFunc(AUTODELAY, autoDemo, 54); break; case 54: killWindow(6); glutTimerFunc(AUTODELAY, autoDemo, 6); break; case 6: killWindow(5); glutTimerFunc(AUTODELAY, autoDemo, 7); break; case 7: killWindow(4); glutTimerFunc(AUTODELAY, autoDemo, 700); break; /* Change shape again */ case 700: currentShape = (currentShape + 1) % 9; redefineShapes(currentShape); glutTimerFunc(AUTODELAY, autoDemo, 701); break; /* Cycle 4 main windows through various window ops. */ case 701: positionWindow(index); index = (index + 1) % 4; glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 701 : 702); break; case 702: reshapeWindow(index); index = (index + 1) % 4; glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 702 : 703); break; case 703: iconifyWindow(index); index = (index + 1) % 4; glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 703 : 704); break; case 704: showWindow(index); index = (index + 1) % 4; glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 704 : 705); break; case 705: hideWindow(index); index = (index + 1) % 4; glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 705 : 706); break; case 706: showWindow(index); index = (index + 1) % 4; glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 706 : 707); break; case 707: pushWindow(index); index = (index + 1) % 4; glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 707 : 708); break; case 708: popWindow(index); index = (index + 1) % 4; glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 708 : 8); break; /* Kill all windows */ case 8: killWindow(3); glutTimerFunc(AUTODELAY, autoDemo, 9); break; case 9: killWindow(2); glutTimerFunc(AUTODELAY, autoDemo, 10); break; case 10: killWindow(1); glutTimerFunc(AUTODELAY, autoDemo, 11); break; case 11: killWindow(0); glutTimerFunc(AUTODELAY, autoDemo, -1); /* back to start */ break; } } /* attachMenus - Attach/detach menus to/from mouse buttons */ void attachMenus(void) { int i, b; int button[3] = {GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON}; for (i = 0; i < MAXWIN; i++) { if (winId[i] != 0) { for (b = 0; b < 3; b++) { glutSetWindow(winId[i]); glutSetMenu(menu1); if (menuButton[b]) glutAttachMenu(button[b]); else glutDetachMenu(button[b]); } } } } /* killAllWindows - Kill all windows (except 0) */ void killAllWindows(void) { int w; for (w = 1; w < MAXWIN; w++) if (winId[w]) killWindow(w); } /* makeAllWindows - Make all windows */ void makeAllWindows(void) { int w; for (w = 0; w < MAXWIN; w++) if (!winId[w]) makeWindow(w); } /* checkArgs - Check command line args */ void checkArgs(int argc, char *argv[]) { int argp; GLboolean quit = GL_FALSE; GLboolean error = GL_FALSE; #define AA argv[argp] #if 0 #define NEXT argp++; \ if(argp >= argc) \ { \ Usage(); \ Exit(1); \ } #endif argp = 1; while (argp < argc) { if (match(AA, "-help")) { commandLineHelp(); quit = GL_TRUE; } else if (match(AA, "-version")) { printf(VERSIONLONG "\n"); quit = GL_TRUE; } else if (match(AA, "-auto")) { demoMode = GL_TRUE; } else if (match(AA, "-scale")) { argp++; scaleFactor = atof(argv[argp]); } else { fprintf(stderr, "Unknown arg: %s\n", AA); error = GL_TRUE; quit = GL_TRUE; } argp++; } if (error) { commandLineHelp(); exit(1); } if (quit) exit(0); } /* commandLineHelp - Command line help */ void commandLineHelp(void) { printf("Usage:\n"); printf(" -h[elp] this stuff\n"); printf(" -v[ersion] show version\n"); printf(" -a[uto] start in auto demo mode\n"); printf(" -s[cale] f scale windows by f\n"); printf("Standard GLUT args:\n"); printf(" -iconic start iconic\n"); printf(" -display DISP use display DISP\n"); printf(" -direct use direct rendering (default)\n"); printf(" -indirect use indirect rendering\n"); printf(" -sync use synchronous X protocol\n"); printf(" -gldebug check OpenGL errors\n"); printf(" -geometry WxH+X+Y standard X window spec (overridden here) \n"); } /* match - Match a string (any unique substring). */ GLboolean match(char *arg, char *t) { if (strstr(t, arg)) return GL_TRUE; else return GL_FALSE; } /* scaleWindows - Scale initial window sizes ansd positions */ void scaleWindows(float scale) { int i; for (i = 0; i < MAXWIN; i++) { pos[i][0] = pos[i][0] * scale; pos[i][1] = pos[i][1] * scale; size[i][0] = size[i][0] * scale; size[i][1] = size[i][1] * scale; } } /* trackBall - A simple trackball (not with proper rotations). */ /** A simple trackball with spin = left button pan = middle button zoom = left + middle Doesn't have proper trackball rotation, ie axes which remain fixed in the scene. We should use the trackball code from 4Dgifts. */ #define STARTROTATE(x, y) \ { \ startMX = x; \ startMY = y; \ } #define STOPROTATE(x, y) \ { \ steadyXangle = varXangle; \ steadyYangle = varYangle; \ } #define STARTPAN(x, y) \ { \ startMX = x; \ startMY = y; \ } #define STOPPAN(x, y) \ { \ steadyX = varX; \ steadyY = varY; \ } #define STARTZOOM(x, y) \ { \ startMX = x; \ startMY = y; \ } #define STOPZOOM(x, y) \ { \ steadyZ = varZ; \ } static float fixAngle(float angle) { return angle - floor(angle / 360.0) * 360.0; } void trackBall(int mode, int button, int state, int x, int y) { static int startMX = 0, startMY = 0; /* initial mouse pos */ static int deltaMX = 0, deltaMY = 0; /* initial mouse pos */ static float steadyXangle = 0.0, steadyYangle = 0.0; static float varXangle = 0.0, varYangle = 0.0; static float steadyX = 0.0, steadyY = 0.0, steadyZ = 0.0; static float varX = 0.0, varY = 0.0, varZ = 0.0; switch (mode) { case RESET: steadyXangle = steadyYangle = steadyX = steadyY = steadyZ = 0.0; break; case MOUSEBUTTON: if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && !middleDown) { STARTROTATE(x, y); leftDown = GL_TRUE; } else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && middleDown) { STOPPAN(x, y); STARTZOOM(x, y); leftDown = GL_TRUE; } else if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN && !leftDown) { STARTPAN(x, y); middleDown = GL_TRUE; } else if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN && leftDown) { STOPROTATE(x, y); STARTZOOM(x, y); middleDown = GL_TRUE; } else if (state == GLUT_UP && button == GLUT_LEFT_BUTTON && !middleDown) { STOPROTATE(x, y); leftDown = GL_FALSE; } else if (state == GLUT_UP && button == GLUT_LEFT_BUTTON && middleDown) { STOPZOOM(x, y); STARTROTATE(x, y); leftDown = GL_FALSE; } else if (state == GLUT_UP && button == GLUT_MIDDLE_BUTTON && !leftDown) { STOPPAN(x, y); middleDown = GL_FALSE; } else if (state == GLUT_UP && button == GLUT_MIDDLE_BUTTON && leftDown) { STOPZOOM(x, y); STARTROTATE(x, y); middleDown = GL_FALSE; } break; case APPLY: if (leftDown && !middleDown) { glTranslatef(steadyX, steadyY, steadyZ); glRotatef(varXangle, 0, 1, 0); glRotatef(varYangle, 1, 0, 0); } /* Middle button pan */ else if (middleDown && !leftDown) { glTranslatef(varX, varY, steadyZ); glRotatef(steadyXangle, 0, 1, 0); glRotatef(steadyYangle, 1, 0, 0); } /* Left + middle zoom. */ else if (leftDown && middleDown) { glTranslatef(steadyX, steadyY, varZ); glRotatef(steadyXangle, 0, 1, 0); glRotatef(steadyYangle, 1, 0, 0); } /* Nothing down. */ else { glTranslatef(steadyX, steadyY, steadyZ); glRotatef(steadyXangle, 0, 1, 0); glRotatef(steadyYangle, 1, 0, 0); } break; case MOUSEMOTION: deltaMX = x - startMX; deltaMY = startMY - y; if (leftDown && !middleDown) { varXangle = fixAngle(steadyXangle + deltaMX); varYangle = fixAngle(steadyYangle + deltaMY); } else if (middleDown && !leftDown) { varX = steadyX + deltaMX / 100.0; varY = steadyY + deltaMY / 100.0; } else if (leftDown && middleDown) { varZ = steadyZ - deltaMY / 50.0; } break; } } /* Callbacks for exotic input devices. These have not been tested yet owing to the usual complete absence of such devices in the UK support group. */ /* spaceballMotionCB */ void spaceballMotionCB(int x, int y, int z) { printf("spaceballMotionCB: translations are X %d, Y %d, Z %d\n", x, y, z); } /* spaceballRotateCB */ void spaceballRotateCB(int x, int y, int z) { printf("spaceballRotateCB: rotations are X %d, Y %d, Z %d\n", x, y, z); } /* spaceballButtonCB */ void spaceballButtonCB(int button, int state) { printf("spaceballButtonCB: button %d, state %d\n", button, state); } /* buttonBoxCB */ void buttonBoxCB(int button, int state) { printf("buttonBoxCB: button %d, state %d\n", button, state); } /* dialsCB */ void dialsCB(int dial, int value) { printf("dialsCB: dial %d, value %d\n", dial, value); } /* tabletMotionCB */ void tabletMotionCB(int x, int y) { printf("tabletMotionCB: X %d, Y %d\n", x, y); } /* tabletButtonCB */ /* ARGSUSED2 */ void tabletButtonCB(int button, int state, int dummy1, int dummy2) { printf("tabletButtonCB: button %d, state %d\n", button, state); }