/* 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;
}