/**************************************************************** * - 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 ***************************************************************/ /* NOTE: POPUP MENU SUPPORT NOT WORKING */ #include #include #include #include #include #include #include #include #include #include #include #include /* creation routine for control form */ extern Widget createForm(Widget parent); /* routine that builds the window for the control panel */ static Widget buildMyForm(Widget parent); /* 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); /* X11 widget callbacks */ static void menuCB(Widget w, XtPointer client, XtPointer call); static void resetCB(Widget w, XtPointer client, XtPointer call); static void quitCB(Widget w, XtPointer client, XtPointer call); static void radiusCB(Widget w, XtPointer client, XtPointer call); /* the ID for our OpenGL window */ /* (needs to be global for the resetCB() and radiusCB() functions */ static int winid; /* viewing parameters */ const float origaspect = 1.0; const float origradius = 500.0; const float origAxy = 0.0; const float origAyz = 90.0; const float orignearclip = 1.0; float aspect; float radius; float Axy; float Ayz; float nearclip; /* Coordinates of the vertices of a unit cube */ static int Cv[][3] = { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, }; /* fallback X11 resource strings, for initialization */ static String config[] = { "*pglWindow.geometry: 400x400", NULL }; /* identifiers for our display lists */ static enum { figure = 1, cube, 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; /* set initial values for viewing parameters */ aspect = origaspect; radius = origradius; Axy = origAxy; Ayz = origAyz; nearclip= orignearclip; /* open a window */ app = pglInitialize("sample", config); /* create a simple control panel */ buildMyForm(app); /* enter main control loop */ pglManageWindows(); pglMainLoop(); } /* routine to build the control panel */ static Widget buildMyForm(Widget parent) { Widget formWindow; Widget form; /* set up an X window... */ formWindow = XtVaCreatePopupShell("topLevelShell", topLevelShellWidgetClass, parent, XmNtitle, "Sample Program", XmNiconName, "sample", XmNx, 393, XmNy, 311, XmNwidth, 200, XmNheight, 200, NULL); /* populate the control panel... */ form = createForm(formWindow); /* ...make it come alive! */ XtManageChild(form); XtPopup(formWindow, XtGrabNone); return formWindow; } /* routine to populate the control panel */ Widget createForm(Widget parent) { XmString xmstr; Widget form; Widget resetButton; Widget radiusLabel; Widget radiusField; Widget quitButton; Arg args[20]; int argn = 0; form = XtVaCreateManagedWidget("form", xmFormWidgetClass, parent, XmNshadowThickness, 2, XmNshadowType, XmSHADOW_OUT, XmNresizePolicy, XmRESIZE_GROW, XmNwidth, 178, XmNheight, 73, NULL); xmstr = XmStringCreateSimple("Reset"); resetButton = XtVaCreateManagedWidget("resetButton", xmPushButtonWidgetClass, form, XmNlabelString, xmstr, XmNrecomputeSize, False, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 50, XmNtopOffset, 4, XmNleftOffset, 4, XmNx, 4, XmNy, 4, XmNwidth, 85, XmNheight, 35, NULL); XtAddCallback(resetButton, XmNactivateCallback, resetCB, NULL); XmStringFree(xmstr); xmstr = XmStringCreateSimple("New Radius:"); radiusLabel = XtVaCreateManagedWidget("radiusLabel", xmLabelWidgetClass, form, XmNalignment, XmALIGNMENT_END, XmNlabelString, xmstr, XmNrecomputeSize, True, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, resetButton, XmNtopOffset, 4, XmNbottomAttachment, XmATTACH_NONE, XmNtopOffset, 4, XmNbottomOffset, 0, XmNleftOffset, 4, XmNheight, 35, XmNx, 4, NULL); XmStringFree(xmstr); radiusField = XtVaCreateManagedWidget("radiusField", xmTextFieldWidgetClass, form, XmNvalue, "750", XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET, XmNtopWidget, radiusLabel, XmNtopOffset, -4, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, radiusLabel, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_FORM, XmNtopOffset, -4, XmNleftOffset, 0, XmNrightOffset, 4, XmNwidth, 89, XmNheight, 35, NULL); XtAddCallback(radiusField, XmNactivateCallback, radiusCB, NULL); xmstr = XmStringCreateSimple("Quit"); quitButton = XtVaCreateManagedWidget("quitButton", xmPushButtonWidgetClass, form, XmNlabelString, xmstr, XmNrecomputeSize, False, XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET, XmNtopWidget, resetButton, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, resetButton, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, resetButton, XmNleftOffset, 2, XmNrightAttachment, XmATTACH_FORM, XmNtopOffset, 0, XmNbottomOffset, 0, XmNleftOffset, 2, XmNrightOffset, 4, XmNwidth, 83, XmNheight, 35, NULL); XmStringFree(xmstr); XtAddCallback(quitButton, XmNactivateCallback, quitCB, NULL); winid = pglOpenSubwindow(form, "My Sample Program", initCB, PGL_DOUBLE|PGL_INDEX); 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); /* set GL window resources */ XtSetArg(args[argn], XmNtopAttachment, XmATTACH_WIDGET); argn++; XtSetArg(args[argn], XmNtopWidget, radiusLabel); argn++; XtSetArg(args[argn], XmNbottomAttachment, XmATTACH_FORM); argn++; XtSetArg(args[argn], XmNleftAttachment, XmATTACH_FORM); argn++; XtSetArg(args[argn], XmNrightAttachment, XmATTACH_FORM); argn++; XtSetValues(pglGetGLWidget(winid), args, argn); return form; } /***********************/ /* PGL-STYLE CALLBACKS */ /***********************/ static void initCB(int window, pglCallbackInfo info) { /* turn on Z-buffering */ glEnable(GL_DEPTH_TEST); /* define drawing commands to draw a unit cube: * 8 corners, 6 faces (right-handed) */ glNewList(cube, GL_COMPILE); glBegin(GL_QUADS); glIndexi(1); glVertex3iv(Cv[0]); glVertex3iv(Cv[3]); glVertex3iv(Cv[2]); glVertex3iv(Cv[1]); glIndexi(2); glVertex3iv(Cv[0]); glVertex3iv(Cv[1]); glVertex3iv(Cv[5]); glVertex3iv(Cv[4]); glIndexi(4); glVertex3iv(Cv[0]); glVertex3iv(Cv[4]); glVertex3iv(Cv[7]); glVertex3iv(Cv[3]); glIndexi(6); glVertex3iv(Cv[4]); glVertex3iv(Cv[5]); glVertex3iv(Cv[6]); glVertex3iv(Cv[7]); glIndexi(3); glVertex3iv(Cv[2]); glVertex3iv(Cv[3]); glVertex3iv(Cv[7]); glVertex3iv(Cv[6]); glIndexi(5); glVertex3iv(Cv[2]); glVertex3iv(Cv[6]); glVertex3iv(Cv[5]); glVertex3iv(Cv[1]); glEnd(); glEndList(); /* define drawing commands to draw our scene: * three cubes variously transformed */ glNewList(figure, GL_COMPILE); glPushMatrix(); /* cube centered at origin, scaled */ glScalef(100, 100, 100); glCallList(cube); glPopMatrix(); glPushMatrix(); /* cube 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(cube); glPopMatrix(); glPushMatrix(); /* another cube, distorted */ glTranslatef(-50.0, -150.0, -70.0); glScalef(30.0, 20.0, 50.0); glRotatef(30, 1, 0, 0); glCallList(cube); 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 */ glIndexi(1); glVertex3i(0, 0, 0); glVertex3i(150, 0, 0); glIndexi(2); glVertex3i(0, 0, 0); glVertex3i(0, 150, 0); glIndexi(4); glVertex3i(0, 0, 0); glVertex3i(0, 0, 150); glEnd(); glEndList(); /* initialize the projection matrix, and draw the scene */ 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 axes and the scene */ glCallList(axes); 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 */ exposeCB(window, info); } static void inputCB(int window, pglCallbackInfo info) { XButtonEvent bev = info->event->xbutton; XMotionEvent mev = info->event->xmotion; static int which = -1; switch ( bev.type ) { case ButtonPress: /* press */ which = bev.button; xx = bev.x; yy = bev.y; break; case MotionNotify: /* 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; default: return; } 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 */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, aspect, nearclip, 750); } /* callbacks for the control panel */ void resetCB(Widget w, XtPointer client, XtPointer call) { aspect = origaspect; radius = origradius; Axy = origAxy; Ayz = origAyz; nearclip= orignearclip; /* fix the projection matrix */ pglSetCurrentWindow(winid); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, aspect, nearclip, 750); exposeCB(winid, NULL); } void quitCB(Widget w, XtPointer client, XtPointer call) { exit(0); } void radiusCB(Widget w, XtPointer client, XtPointer call) { float value; char s[20]; /* convert input value to an integer */ value = strtod(XmTextFieldGetString(w), NULL); /* set the new radius value */ if ( value > 0.0 ) radius = value; /* re-write value, in case it's changed */ sprintf(s, "%6.2f", radius); XmTextFieldSetString(w, s); /* fix the projection matrix */ pglSetCurrentWindow(winid); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, aspect, nearclip, 750); exposeCB(winid, NULL); }