/**************************************************************** * - viewing position controlled by mouse * - leftmouse: polar angles, rightmouse: distance from origin * - use z-buffering to correctly sort 3d objects * - use begin-vertex-end drawing routines * * K. Perry, ICGL, Sept 1995 ***************************************************************/ #include #include #include #include #include #include #include #include #include /* GL window callbacks */ static void initCB(int window, pglCallbackInfo info); static void exposeCB(int window, pglCallbackInfo info); static void resizeCB(int window, pglCallbackInfo info); static void inputCB(int window, pglCallbackInfo info); static void menuCB(Widget w, XtPointer client, XtPointer call); /* viewing parameters */ float aspect = 1.0; float radius = 500.0; float Axy = 0.0; float Ayz = 90.0; float nearclip= 1.0; /* fallback X11 resource strings, for initialization */ static String config[] = { "*pglWindow.geometry: 400x400", NULL }; /* identifiers for our display lists */ static enum { figure = 1, sphere, axes } displayLists; /* identifiers for our menu items */ static enum { byebye, near1, near2 } menuValues; /* temporary variables, for motion callbacks */ static int xx; static int yy; main(int argc, char** argv) { Widget app; int winid; /* open a window */ app = pglInitialize("sample", config); winid = pglOpenWindow("My Sample Program", initCB, PGL_DOUBLE|PGL_RGBA); pglSetCallback(winid, PGL_EXPOSE, exposeCB); pglSetCallback(winid, PGL_RESIZE, resizeCB); pglSetCallback(winid, PGL_INPUT, inputCB); /* create a menu */ pglMakeMenu(winid, "Pick Something"); pglAddMenuItem(winid, "near=1", near1, menuCB); pglAddMenuItem(winid, "near=150", near2, menuCB); pglAddMenuItem(winid, "quit", byebye, menuCB); /* enter main control loop */ pglManageWindows(); pglMainLoop(); } /***********************/ /* PGL-STYLE CALLBACKS */ /***********************/ static void initCB(int window, pglCallbackInfo info) { GLUquadricObj* quadric = gluNewQuadric(); /* turn on Z-buffering */ glEnable(GL_DEPTH_TEST); glEnable(GL_NORMALIZE); glShadeModel(GL_SMOOTH); /* The rest of this subroutine defines 3 Display Lists * (sphere, figure, and axes), which hold the OpenGL * drawing commands we will use later to draw our picture */ /* define drawing commands to draw a unit sphere: */ glNewList(sphere, GL_COMPILE); glColor3f(1, 1, 1); /* make a sphere of radius 1, with a 20x20 triangulation */ gluSphere(quadric, 1, 20, 20); glEndList(); /* define drawing commands to draw our scene: * three spheres variously transformed */ glNewList(figure, GL_COMPILE); glPushMatrix(); /* sphere centered at origin, scaled */ glScalef(100, 100, 100); glCallList(sphere); glPopMatrix(); glPushMatrix(); /* sphere translated, scaled, intersects first */ glTranslatef(100, 100, 100); glScalef(50, 50, 50); glRotatef(90, 0, 1, 0); glRotatef(90, 0, 0, 1); glTranslatef(-.5, -.5, -.5); glCallList(sphere); glPopMatrix(); glPushMatrix(); /* another sphere, distorted */ glTranslatef(-50.0, -150.0, -70.0); glScalef(30.0, 20.0, 50.0); glRotatef(30, 1, 0, 0); glCallList(sphere); glPopMatrix(); glEndList(); /* define drawing commands to draw axes at the point of rotation */ glNewList(axes, GL_COMPILE); glBegin(GL_LINES); /* 3 axial lines, differently colored */ glColor3f(1, 0, 0); glVertex3i(0, 0, 0); glVertex3i(150, 0, 0); glColor3f(0, 1, 0); glVertex3i(0, 0, 0); glVertex3i(0, 150, 0); glColor3f(0, 0, 1); glVertex3i(0, 0, 0); glVertex3i(0, 0, 150); glEnd(); glEndList(); /* initialize the projection matrix, and draw the picture */ resizeCB(window, info); } static void exposeCB(int window, pglCallbackInfo info) { /* clear background to black; clear Z-buffer */ glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT); /* set up the viewing matrix */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0, 0, -radius); glRotatef(0, 0, 0, 1); glRotatef(-Ayz, 1, 0, 0); glRotatef(-Axy, 0, 0, 1); /* draw the coordinate axes by calling our * previously stored Display List */ glDisable(GL_LIGHTING); glCallList(axes); /* turn on lighting, then draw the scene by calling our * other previously stored Display List. */ glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glColorMaterial(GL_FRONT, GL_DIFFUSE); glEnable(GL_COLOR_MATERIAL); glCallList(figure); /* swap buffers */ pglSwapBuffers(window); } static void resizeCB(int window, pglCallbackInfo info) { /* resize, reshape */ aspect = info->width/(float)info->height; glViewport(0, 0, info->width, info->height); /* re-load the projection matrix, * in case aspect or nearclip have changed */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, aspect, nearclip, 750); /* re-draw the picture */ exposeCB(window, info); } static void inputCB(int window, pglCallbackInfo info) { XButtonEvent bev = info->event->xbutton; XMotionEvent mev = info->event->xmotion; static int which = -1; /* decide what type of event we got */ switch ( bev.type ) { case ButtonPress: /* mouse button pressed */ /* (note: RIGHTMOUSE pops up the menu, instead of calling inputCB() * so we don't have to worry about RIGHTMOUSE here */ which = bev.button; /* possible values: Button1, Button2, Button3 */ xx = bev.x; yy = bev.y; break; case MotionNotify: /* mouse motion */ switch ( which ) { case Button1: /* update the viewer's orientation */ Axy -= (mev.x - xx); Ayz += (mev.y - yy); xx = mev.x; yy = mev.y; break; case Button2: /* update the viewer's distance from the origin */ radius += (mev.y - yy); yy = mev.y; break; default: return; } break; /* some other possible event types you can check for */ case ButtonRelease: /* mouse button released */ case KeyPress: /* keyboard key pressed */ case KeyRelease: /* keyboard key released */ case EnterNotify: /* mouse entered window */ case LeaveNotify: /* mouse left window */ case FocusIn: /* application obtained keyboard focus */ case FocusOut: /* application lost keyboard focus */ default: return; } /* re-draw the picture */ exposeCB(window, info); } /***********************/ /* X11-STYLE CALLBACKS */ /***********************/ /* callback for GL window's popup menu */ static void menuCB(Widget w, XtPointer client, XtPointer call) { /* perform user-requested updates */ switch ( (int)client ) { case near1: nearclip = 1.0; break; case near2: nearclip = 150.0; break; case byebye: exit(0); } /* fix the projection matrix, in case nearclip has changed */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, aspect, nearclip, 750); }