/* Copyright (c) Mark J. Kilgard, 1995, 1996. */ /* This program is freely distributable without licensing fees and is provided without guarantee or warrantee expressed or implied. This program is -not- in the public domain. */ #include <stdlib.h> #include <stdio.h> #include <Xm/Form.h> /* Motif Form widget. */ #include <Xm/Frame.h> /* Motif Frame widget. */ #include <X11/keysym.h> #include <X11/Xutil.h> #include <X11/Xatom.h> /* For XA_RGB_DEFAULT_MAP. */ #include <X11/Xmu/StdCmap.h> /* For XmuLookupStandardColormap. */ #include <GL/gl.h> #include <GL/glu.h> #include <GL/glx.h> #include <X11/GLw/GLwMDrawA.h> /* Motif OpenGL drawing area. */ static int snglBuf[] = {GLX_RGBA, GLX_DEPTH_SIZE, 12, GLX_RED_SIZE, 1, None}; static int dblBuf[] = {GLX_RGBA, GLX_DEPTH_SIZE, 12, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 1, None}; static String fallbackResources[] = { "*glxarea*width: 300", "*glxarea*height: 300", "*frame*x: 20", "*frame*y: 20", "*frame*topOffset: 20", "*frame*bottomOffset: 20", "*frame*rightOffset: 20", "*frame*leftOffset: 20", "*frame*shadowType: SHADOW_IN", NULL }; Display *dpy; XtAppContext app; XtWorkProcId workId = 0; Widget toplevel, form, frame, glxarea; XVisualInfo *visinfo; GLXContext glxcontext; Colormap cmap; Bool doubleBuffer = True, spinning = False; void draw(void); Boolean spin(XtPointer clientData); void mapStateChanged(Widget w, XtPointer clientData, XEvent * event, Boolean * cont); Colormap getShareableColormap(XVisualInfo * vi); void graphicsInit(Widget w, XtPointer clientData, XtPointer call); void expose(Widget w, XtPointer clientData, XtPointer call); void resize(Widget w, XtPointer clientData, XtPointer call); void input(Widget w, XtPointer clientData, XtPointer callData); int main(int argc, char **argv) { /* Step 1. */ toplevel = XtAppInitialize(&app, "Glw", NULL, 0, &argc, argv, fallbackResources, NULL, 0); /* Step 2. */ XtAddEventHandler(toplevel, StructureNotifyMask, False, mapStateChanged, NULL); /* Step 3. */ dpy = XtDisplay(toplevel); visinfo = glXChooseVisual(dpy, DefaultScreen(dpy), dblBuf); if (visinfo == NULL) { visinfo = glXChooseVisual(dpy, DefaultScreen(dpy), snglBuf); if (visinfo == NULL) XtAppError(app, "no good visual"); doubleBuffer = False; } /* Step 4. */ form = XmCreateForm(toplevel, "form", NULL, 0); XtManageChild(form); frame = XmCreateFrame(form, "frame", NULL, 0); XtVaSetValues(frame, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); XtManageChild(frame); /* Step 5. */ cmap = getShareableColormap(visinfo); /* Step 6. */ glxarea = XtVaCreateManagedWidget("glxarea", glwMDrawingAreaWidgetClass, frame, GLwNvisualInfo, visinfo, XtNcolormap, cmap, NULL); /* Step 7. */ XtAddCallback(glxarea, GLwNginitCallback, graphicsInit, NULL); XtAddCallback(glxarea, GLwNexposeCallback, expose, NULL); XtAddCallback(glxarea, GLwNresizeCallback, resize, NULL); XtAddCallback(glxarea, GLwNinputCallback, input, NULL); /* Step 8. */ XtRealizeWidget(toplevel); XtAppMainLoop(app); return 0; /* ANSI C requires main to return int. */ } void graphicsInit(Widget w, XtPointer clientData, XtPointer call) { XVisualInfo *visinfo; /* Create OpenGL rendering context. */ XtVaGetValues(w, GLwNvisualInfo, &visinfo, NULL); glxcontext = glXCreateContext(XtDisplay(w), visinfo, 0, /* No sharing. */ True); /* Direct rendering if possible. */ /* Setup OpenGL state. */ glXMakeCurrent(XtDisplay(w), XtWindow(w), glxcontext); glEnable(GL_DEPTH_TEST); glClearDepth(1.0); glClearColor(0.0, 0.0, 0.0, 0.0); /* clear to black */ glMatrixMode(GL_PROJECTION); gluPerspective(40.0, 1.0, 10.0, 200.0); glMatrixMode(GL_MODELVIEW); glTranslatef(0.0, 0.0, -50.0); glRotatef(-58.0, 0.0, 1.0, 0.0); } void resize(Widget w, XtPointer clientData, XtPointer call) { GLwDrawingAreaCallbackStruct *callData; callData = (GLwDrawingAreaCallbackStruct *) call; glXMakeCurrent(XtDisplay(w), XtWindow(w), glxcontext); glXWaitX(); glViewport(0, 0, callData->width, callData->height); } void expose(Widget w, XtPointer clientData, XtPointer call) { draw(); } void draw(void) { glXMakeCurrent(dpy, XtWindow(glxarea), glxcontext); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBegin(GL_POLYGON); glColor3f(0.0, 0.0, 0.0); glVertex3f(-10.0, -10.0, 0.0); glColor3f(0.7, 0.7, 0.7); glVertex3f(10.0, -10.0, 0.0); glColor3f(1.0, 1.0, 1.0); glVertex3f(-10.0, 10.0, 0.0); glEnd(); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 0.0); glVertex3f(0.0, -10.0, -10.0); glColor3f(0.0, 1.0, 0.7); glVertex3f(0.0, -10.0, 10.0); glColor3f(0.0, 0.0, 1.0); glVertex3f(0.0, 5.0, -10.0); glEnd(); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 0.0); glVertex3f(-10.0, 6.0, 4.0); glColor3f(1.0, 0.0, 1.0); glVertex3f(-10.0, 3.0, 4.0); glColor3f(0.0, 0.0, 1.0); glVertex3f(4.0, -9.0, -10.0); glColor3f(1.0, 0.0, 1.0); glVertex3f(4.0, -6.0, -10.0); glEnd(); if (doubleBuffer) glXSwapBuffers(dpy, XtWindow(glxarea)); else glFlush(); /* Avoid indirect rendering latency from queuing. */ if (!glXIsDirect(dpy, glxcontext)) glFinish(); } void input(Widget w, XtPointer clientData, XtPointer callData) { XmDrawingAreaCallbackStruct *cd = (XmDrawingAreaCallbackStruct *) callData; char buffer[1]; KeySym keysym; switch (cd->event->type) { case KeyPress: if (XLookupString((XKeyEvent *) cd->event, buffer, 1, &keysym, NULL) > 0) { switch (keysym) { case XK_space: /* The spacebar. */ if (spinning) { XtRemoveWorkProc(workId); spinning = False; } else { workId = XtAppAddWorkProc(app, spin, NULL); spinning = True; } break; } } break; } } Boolean spin(XtPointer clientData) { glXMakeCurrent(dpy, XtWindow(glxarea), glxcontext); glRotatef(2.5, 1.0, 0.0, 0.0); draw(); return False; /* Leave work proc active. */ } void mapStateChanged(Widget w, XtPointer clientData, XEvent * event, Boolean * cont) { switch (event->type) { case MapNotify: if (spinning && workId != 0) workId = XtAppAddWorkProc(app, spin, NULL); break; case UnmapNotify: if (spinning) XtRemoveWorkProc(workId); break; } } Colormap getShareableColormap(XVisualInfo * vi) { Status status; XStandardColormap *standardCmaps; Colormap cmap; int i, numCmaps; /* Be lazy; using DirectColor too involved for this example. */ #if defined(_CH_) || defined(__cplusplus) if (vi->c_class != TrueColor) #else if (vi->class != TrueColor) #endif XtAppError(app, "no support for non-TrueColor visual"); /* If no standard colormap but TrueColor, just make an unshared one. */ status = XmuLookupStandardColormap(dpy, vi->screen, vi->visualid, vi->depth, XA_RGB_DEFAULT_MAP, False, /* Replace. */ True); /* Retain. */ if (status == 1) { status = XGetRGBColormaps(dpy, RootWindow(dpy, vi->screen), &standardCmaps, &numCmaps, XA_RGB_DEFAULT_MAP); if (status == 1) for (i = 0; i < numCmaps; i++) if (standardCmaps[i].visualid == vi->visualid) { cmap = standardCmaps[i].colormap; XFree(standardCmaps); return cmap; } } cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone); return cmap; }