Appendix F. Example Mixed-Model Programs With Xlib
Prev |  | Next

## Appendix F. Example Mixed-Model Programs With Xlib

This appendix contains two example mixed-model programs that use Xlib. Each example program is shown first in IRIS GL, then in OpenGL.

## Example One: iobounce.c

`iobounce.c` is a simple interactive program that bounces a ball around a 2D surface. Users can use the mouse buttons to change the velocity of the ball. The IRIS GL version of the program is presented first, then the OpenGL version.

### IRIS GL Version of iobounce.c

The IRIS GL version of `iobounce.c` is a “pure” IRIS GL program; it does not contain X calls.

    /*                iobounce.c:
     *                "pool" ball that "bounces" around a 2-d "surface".
     *                RIGHTMOUSE stops ball
     *                MIDDLEMOUSE increases y velocity
     *                LEFTMOUSE increases x velocity
     */

    #include <stdio.h>
    #include <gl/gl.h>
    #include <gl/device.h>

    long xmaxscrn, ymaxscrn;  /* maximum size of screen in x and y */

    #define XMIN 100
    #define YMIN 100
    #define XMAX 900
    #define YMAX 700

    long xvelocity = 0, yvelocity = 0;

    main()
    {
        Device dev;
        short val;
        long sizex, sizey;

        initialize();

        while (TRUE) {
           while (qtest()) {
              dev = qread(&val);
              switch (dev) {
                    case REDRAW:  /* redraw window re: move/resize/push/pop */
                        reshapeviewport();
                        ortho2(XMIN - 0.5, XMAX + 0.5, YMIN - 0.5,
                               YMAX + 0.5);
                        drawball();
                        break;
                    case LEFTMOUSE:     /* increase xvelocity */
                        if (xvelocity >= 0)
                            xvelocity++;
                        else
                            xvelocity--;
                        break;
                    case MIDDLEMOUSE:   /* increase yvelocity */
                        if (yvelocity >= 0)
                            yvelocity++;
                        else
                            yvelocity--;
                        break;
                    case RIGHTMOUSE:     /* stop ball */
                        xvelocity = yvelocity = 0;
                        break;
                    case ESCKEY:
                        gexit();
                        exit(0);
                }
            }
            drawball();
        }
    }

    initialize() {

        xmaxscrn = getgdesc(GD_XPMAX)-1;
        ymaxscrn = getgdesc(GD_YPMAX)-1;
        prefposition(xmaxscrn/4,xmaxscrn*3/4,ymaxscrn/4,ymaxscrn*3/4);
        winopen("iobounce");
        winconstraints();

        doublebuffer();
        gconfig();
        shademodel(FLAT);

        ortho2(XMIN - 0.5, XMAX + 0.5, YMIN - 0.5, YMAX + 0.5);

        qdevice(ESCKEY);
        qdevice(LEFTMOUSE);
        qdevice(MIDDLEMOUSE);
        qdevice(RIGHTMOUSE);
    }

    drawball() {
        static xpos = 500,ypos = 500;
        long radius = 10;

        color(BLACK);
        clear();
        xpos += xvelocity;
        ypos += yvelocity;
        if (xpos > XMAX - radius ||
            xpos < XMIN + radius) {
            xpos -= xvelocity;
            xvelocity = -xvelocity;
        }
        if (ypos > YMAX - radius ||
            ypos < YMIN + radius) {
            ypos -= yvelocity;
            yvelocity = -yvelocity;
        }
        color(YELLOW);
        circfi(xpos, ypos, radius);
        swapbuffers();
    }

### OpenGL Version of iobounce.c

Thie example contains the OpenGL version of `iobounce.c`. Windowing and event handling are now controlled with Xlib, rather than IRIS GL calls.

    /*                   iobounce.c:
     *
     *   "pool ball" that "bounces" around a 2-d "surface".
     *            RIGHTMOUSE stops ball
     *            MIDDLEMOUSE increases y velocity
     *            LEFTMOUSE increases x velocity
     *
     *           (ported from ~4Dgifts/example/grafix/iobounce.c)
     */

    #include <GL/glx.h>
    #include <GL/gl.h>
    #include <GL/glu.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <X11/keysym.h>
    #include <X11/Xlib.h>
    #include <X11/Xutil.h>

    #define XMIN 100
    #define YMIN 100
    #define XMAX 900
    #define YMAX 700

    #define BLACK           0
    #define YELLOW          3

    #define LEFTMOUSE       3
    #define MIDDLEMOUSE     2
    #define RIGHTMOUSE      1

    #define TRUE            1
    #define FALSE           0

    long xmaxscrn, ymaxscrn; /* maximum size of screen /*
                             /* in x and y */

    Display *dpy;            /* The X server connection */
    Atom del_atom;           /* WM_DELETE_WINDOW atom   */
    Window glwin;            /* handle to the GL window */
    XEvent event;

    static void openwindow(char *);
    static void drawball(void);
    static void clean_exit(void);

    long xvelocity = 0, yvelocity = 0;

    main(int argc, char *argv[])
    {
        int myExpose, myConfigure,
            myButtRelease, myKeyPress,
            myButtonNumber;   /* store which events occur */
        long xsize, ysize;

        myExpose = myConfigure = myButtRelease = myKeyPress =
                   myButtonNumber = FALSE;

        openwindow(argv[0]);

        while (TRUE) {

            KeySym keysym;
            char buf[4];

        /* this "do while" loop does the `get events' half of the     */
        /* "get events,process events" action of the infinite while.  */
        /* This is to ensure the event queue is always drained before */
        /* the events that have come in are processed.                */
        while (XEventsQueued(dpy,QueuedAfterReading)) { /* end "do { } while"
                           * XEventsQueued(dpy,QueuedAfterReading)
                           * is like qtest()--it only tells you if
                           * there're any events presently in the
                           * queue.it does not disturb the event
                           * queue's contents in any way.       */

                XNextEvent(dpy, &event);
                switch (event.type) {

                /* "Expose" events are sort of like "REDRAW" in gl-speak in
                 * terms of when a window or a previously invisible part
                 * becomes visible */
                    case Expose:   /* Exposures */
                        myExpose = TRUE;
                        break;

                /* "ConfigNotify" events are like "REDRAW" in terms of changes to
                 * a window's size or position.*/
                    case ConfigureNotify:  /* Resize GL manually */
                        xsize = event.xconfigure.width;
                        ysize = event.xconfigure.height;
                        myConfigure = TRUE;
                        break;

                /* Wait for "ButtonRelease" events so the queue doesn't fill up
                 * the way it would if the user sits on ButtonPresss. */
                    case ButtonRelease:
                        if (event.xbutton.button == Button1) {
                            myButtonNumber = LEFTMOUSE;
                            myButtRelease = TRUE;
                        } else if (event.xbutton.button ==
                                   Button2) {
                            myButtonNumber = MIDDLEMOUSE;
                            myButtRelease = TRUE;
                        } else if (event.xbutton.button ==
                                   Button3) {
                            myButtonNumber = RIGHTMOUSE;
                            myButtRelease = TRUE;
                        }  /* twirl the green sphere */
                        break;

                /* "ClientMessage" is generated if the WM itself is dying
                 * and sends an exit signal to any running prog. */
                    case ClientMessage:
                        if (event.xclient.data.l[0] == del_atom)
                            clean_exit();
                        break;

                /* "KeyPress" events are those that would be generated before
                 * whenever queueing up any KEYBD key via qdevice. */
                    case KeyPress:
                       /* save out which unmodified key (i.e. the key was not
                        * modified w/something like "Shift", "Ctrl", or "Alt")
                        * got pressed for use below. */
                        XLookupString((XKeyEvent *)&event, buf, 4, &keysym, 0);
                        myKeyPress = TRUE;
                        break;

                }  /* end switch (event.type) */
            }

        /* On an "Expose" event, redraw the affected pop'd or
         * de-iconized window
         */
            if (myExpose) {
                drawball();       /* draw the GL stuff */
                myExpose = FALSE; /* reset flag--queue now empty */
            }

        /* On a "ConfigureNotify" event, the GL window has either
         * been moved or resized.  Respond accordingly and then
         * redraw its contents.
         */

            if (myConfigure) {
                glViewport(0, 0, xsize, ysize);
                glLoadIdentity();
                gluOrtho2D(XMIN-0.5, XMAX+0.5, YMIN-0.5, YMAX+0.5);
                drawball();           /* draw the GL stuff */
                myConfigure = FALSE;  /* reset flag--queue now
                                       * empty */
            }

        /* On a "ButtonRelease" event, myButtonNumber stores which
         * mouse button was pressed/released and then we update
         * x/yvelocity accordingly
         * /
            if (myButtRelease) {
                if (myButtonNumber == LEFTMOUSE) {  /* increase
                                                       xvelocity */
                    if (xvelocity >= 0)
                        xvelocity += 3;
                    else
                        xvelocity -= 3;
                } else if (myButtonNumber == MIDDLEMOUSE) {
                                                     /* increase yvelocity*/
                    if (yvelocity >= 0)
                        yvelocity += 3;
                    else
                        yvelocity -= 3;
                } else if (myButtonNumber == RIGHTMOUSE) {
                                                   /* stop ball */
                    xvelocity = yvelocity = 0;
                } else {
                    fprintf(stderr,"ERROR: %s thinks
                            mouse button # ");
                    fprintf(stderr,"%d was
                            pressed(?)\n",argv[0],myButtonNumber);
                }
                drawball();
                myButtRelease = FALSE;
            }

            /* On a keypress of Esc key, exit program. */
            if (myKeyPress) {
                if (keysym == XK_Escape)
                    clean_exit();
            }

            drawball();

        }
    }

    static int attributeList[] = { GLX_DOUBLEBUFFER,
                                   None };
    GLUquadricObj *qobj;

    static Bool WaitForNotify(Display *d, XEvent *e, char *arg) {
        return (e->type == MapNotify) && (e->xmap.window ==
                                          (Window)arg);
    }

    static void openwindow(char *progname) {

        int scrnnum;       /* X screen number  */
        int xorig, yorig;  /* window (upper-left) origin */
        XVisualInfo *vi;
        GLXContext cx;
        Colormap cmap;
        XSizeHints Winhints;/* used to fix window size */
        XSetWindowAttributes swa;
        XColor colorstruct;

        /* Connect to the X server and get screen info */
        if ((dpy = XOpenDisplay(NULL)) == NULL) {
            fprintf(stderr, "%s: cannot connect to X server %s\n",
                                     progname, XDisplayName(NULL));
            exit(1);
        }
        scrnnum = DefaultScreen(dpy);
        ymaxscrn = DisplayHeight(dpy, scrnnum);
        xmaxscrn = DisplayWidth(dpy, scrnnum);

        /* get an appropriate visual */
        vi = glXChooseVisual(dpy, DefaultScreen(dpy),
                             attributeList);
        if (vi == NULL) {
            printf("Couldn't get visual.\n");
            exit(0);
        }

        /* create a GLX context */
        cx = glXCreateContext(dpy, vi, None, GL_TRUE);

        if (cx == NULL) {
            printf("Couldn't get context.\n");
            exit(0);
        }

        /* create a colormap */
        cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
                               vi->visual, AllocAll);

        XSync(dpy, 0);
        /* create a window */
        swa.colormap = cmap;
        swa.border_pixel = 0;

        /* express interest in certain events */
        swa.event_mask = StructureNotifyMask | KeyPressMask |
                         ButtonPressMask |
                         ButtonReleaseMask | ExposureMask;
        glwin = XCreateWindow(dpy, RootWindow(dpy, vi->screen),
                              10, 10, 300, 300,
                              0, vi->depth, InputOutput,
                              vi->visual,
                              CWBorderPixel|CWColormap|CWEventMask, &swa);

        XMapWindow(dpy, glwin);
        XIfEvent(dpy, &event, WaitForNotify, (char*)glwin);

        /* connect the context to the window */
        glXMakeCurrent(dpy, glwin, cx);

       /* express interest in WM killing this app */
        if ((del_atom = XInternAtom(dpy, "WM_DELETE_WINDOW",
                                    True)) != None)
            XSetWMProtocols(dpy, glwin, &del_atom, 1);

        colorstruct.pixel = BLACK;
        colorstruct.red   = 0;
        colorstruct.green = 0;
        colorstruct.blue  = 0;
        colorstruct.flags = DoRed | DoGreen | DoBlue;
        XStoreColor(dpy, cmap, &colorstruct);
        colorstruct.pixel = YELLOW;
        colorstruct.red   = 65535;
        colorstruct.green = 65535;
        colorstruct.blue  = 0;
        colorstruct.flags = DoRed | DoGreen | DoBlue;
        XStoreColor(dpy, cmap, &colorstruct);

        glLoadIdentity();
        gluOrtho2D(XMIN - 0.5,  XMAX + 0.5,  YMIN - 0.5,  YMAX + 0.5);

        /* clear the buffer */
        glClearIndex((GLfloat)BLACK);
        qobj = gluNewQuadric();
        gluQuadricDrawStyle(qobj,GLU_FILL);
        glFlush();
    }

    static void drawball(void) {
        static int xpos = 500, ypos = 500;
        GLdouble radius = 14.0;

        glClear(GL_COLOR_BUFFER_BIT);
        xpos += xvelocity;
        ypos += yvelocity;
        if (xpos > XMAX - radius || xpos < XMIN + radius) {
            xpos -= xvelocity;
            xvelocity = -xvelocity;
        }
        if (ypos > YMAX - radius || ypos < YMIN + radius) {
            ypos -= yvelocity;
            yvelocity = -yvelocity;
        }

        glIndexi(YELLOW);
        glPushMatrix();
        glTranslatef(xpos,  ypos, 0.);
        gluDisk( qobj, 0., radius, 10, 1);
        glPopMatrix();
        glXSwapBuffers(dpy, glwin);
    }

    /*  clean_exit  --  Clean up before exiting */
    static void clean_exit(void)
    {
        gluDeleteQuadric(qobj);
        XCloseDisplay(dpy);
        exit(0);
    }

## Example Two: zrgb.c

The `zrgb.c` example program includes depth buffering. This program won't work on 8-bit IRIS workstations. The IRIS GL version is presented first.

### IRIS GL Version of zrgb.c

This is the IRIS GL version of `zrgb.c`. Like `iobounce.c`, this is a pure IRIS GL program.

    /*                  zrgb.c
     *
     *  This program demostrates zbuffering 3 intersecting RGB
     *  polygons while in doublebuffer mode where,movement of the
     *  mouse with the LEFTMOUSE button depressed will, rotate the 3
     *  polygons. This is done via compound rotations allowing
     *  continuous screen-oriented rotations. (See orient(),
     *  and draw_scene() below).  Notice the effective way there
     *  is no wasted CPU usage when the user moves the mouse out
     *  of the window without holding down LEFTMOUSE--there is no
     *  qtest being performed and so the program simply blocks on
     *  the qread statement. Press the "Esc"[ape] key to exit.
     *  Please note that this program will not work on any 8-bit
     *  IRIS machine.
     *                                          ratman - 1989
     */

    #include <stdio.h>
    #include <gl/gl.h>
    #include <gl/device.h>

    Matrix objmat = {
        {1.0, 0.0, 0.0, 0.0},
        {0.0, 1.0, 0.0, 0.0},
        {0.0, 0.0, 1.0, 0.0},
        {0.0, 0.0, 0.0, 1.0},
    };

    Matrix idmat = {
        {1.0, 0.0, 0.0, 0.0},
        {0.0, 1.0, 0.0, 0.0},
        {0.0, 0.0, 1.0, 0.0},
        {0.0, 0.0, 0.0, 1.0},
    };

    /* Modes the program can be in */
    #define NOTHING 0
    #define ORIENT 1

    int mode = 0;
    int omx, mx, omy, my;  /* old and new mouse position */
    float scrnaspect;      /* aspect ratio value         */
    long zfar;             /* holds specific machine's   */
                           /* maximum Z depth value      */

    main(argc, argv)
    int argc;
    char *argv[];
    {
        long dev;
        short val;
        int redrawneeded=TRUE;  /* Is true when the scene */
                                /* needs redrawing */

        initialize(argv[0]);

        while (TRUE) {

            if (redrawneeded) {
                draw_scene();
                redrawneeded=FALSE;
            }

            while (qtest() || (!redrawneeded)) {

                switch(dev=qread(&val)) {

                case ESCKEY:   /* exit when key is going up, */
                               /* not down                   */
                    if (val)   /* this avoids the scenario   */
                               /* where a window             */
                        break; /* underneath this program's  */
                               /* window--say                */
                    exit(0);   /* another copy of this       */
                               /* program--getting the       */
                               /* ESC UP event and exiting   */
                               /* also.                      */
                case REDRAW:
                    reshapeviewport();
                    redrawneeded=TRUE;
                    break;

                case LEFTMOUSE:
                    if (val) {
                        mode = ORIENT;
                        omx = mx;
                        omy = my;
                    } else
                        mode = NOTHING;
                    break;

                case MOUSEX:
                    omx = mx;
                    mx = val;
                    if (mode == ORIENT) {
                        update_scene();
                        redrawneeded=TRUE;
                    }
                    break;

                case MOUSEY:
                    omy = my;
                    my = val;
                    if (mode == ORIENT) {
                        update_scene();
                        redrawneeded=TRUE;
                    }
                    break;
                }
            }
        }
    }

    initialize(progname)
    char *progname;
    {

        long xscrnsize;   /* size of screen in x used
                           * to set globals  */
        long testifZinst;

        /*
         * This program requires the following to run:
         *  -- z buffer
         *  -- ability to do double-buffered RGB mode
         */
        /* Test for Z buffer */
        testifZinst = getgdesc(GD_BITS_NORM_ZBUFFER);
        if (testifZinst == FALSE) {
             fprintf(stderr,"BUMmer!--%s won't work on ",
                             progname);
             fprintf(stderr,"this machine--zbuffer option not
                             installed.\n");
             exit(0);
        }
        /* Test for double-buffered RGB */
        if (getgdesc(GD_BITS_NORM_DBL_RED) == 0) {
             fprintf(stderr,"BUMmer!--%s won't work on ",
                             progname);
             fprintf(stderr,"this machine--not enough
                             bitplanes.\n");
             exit(0);

        }

        /* Code to keep same aspec ratio as the screen */
        keepaspect(getgdesc(GD_XMMAX), getgdesc(GD_YMMAX));
        scrnaspect =
               (float)getgdesc(GD_XMMAX)/(float)getgdesc(GD_YMMAX);

        winopen(progname);
        wintitle("Zbuffered RGB #1");

        doublebuffer();
        RGBmode();
        gconfig();
        zbuffer(TRUE);
        glcompat(GLC_ZRANGEMAP, 0);
        zfar = getgdesc(GD_ZMAX);

        qdevice(ESCKEY);
        qdevice(LEFTMOUSE);
        qdevice(MOUSEX);
        qdevice(MOUSEY);
    }

    update_scene() {

        switch (mode) {

            case ORIENT:
                orient();
                break;
        }
    }

    orient () {

        pushmatrix();

        loadmatrix(idmat);

        rotate(mx-omx, 'y');
        rotate(omy-my, 'x');

        multmatrix(objmat);
        getmatrix(objmat);
        popmatrix();
    }

    draw_scene() {

        czclear(0x00C86428, zfar);

        perspective(400, scrnaspect, 30.0, 60.0);
        translate(0.0, 0.0, -40.0);
        multmatrix(objmat);
        rotate(-580, 'y');   /* skews original view
                              * to show all polygons */
        draw_polys();

        swapbuffers();
    }
    float polygon1[3][3] = { {-10.0, -10.0,   0.0,},
                             { 10.0, -10.0,   0.0,},
                             {-10.0,  10.0,   0.0,} };

    float polygon2[3][3] = { {  0.0, -10.0, -10.0,},
                             {  0.0, -10.0,  10.0,},
                             {  0.0,   5.0, -10.0,} };

    float polygon3[4][3] = { {-10.0,   6.0,   4.0,},
                             {-10.0,   3.0,   4.0,},
                             {  4.0,  -9.0, -10.0,},
                             {  4.0,  -6.0, -10.0,} };

    draw_polys() {

        bgnpolygon();
        cpack(0x00000000);
        v3f(&polygon1[0][0]);
        cpack(0x007F7F7F);
        v3f(&polygon1[1][0]);
        cpack(0x00FFFFFF);
        v3f(&polygon1[2][0]);
        endpolygon();
        bgnpolygon();
        cpack(0x0000FFFF);
        v3f(&polygon2[0][0]);
        cpack(0x007FFF00);
        v3f(&polygon2[1][0]);
        cpack(0x00FF0000);
        v3f(&polygon2[2][0]);
        endpolygon();

        bgnpolygon();
        cpack(0x0000FFFF);
        v3f(&polygon3[0][0]);
        cpack(0x00FF00FF);
        v3f(&polygon3[1][0]);
        cpack(0x00FF0000);
        v3f(&polygon3[2][0]);
        cpack(0x00FF00FF);
        v3f(&polygon3[3][0]);
        endpolygon();
    }

### OpenGL Version of zrgb.c

This is the OpenGL version of `zrgb.c`.

    /*
     *                     zrgb.c
     */
    #include <GL/glx.h>
    /*
    #include <GL/gl.h>
    #include <GL/glu.h>
    */
    #include <stdio.h>
    #include <stdlib.h>
    #include <X11/keysym.h>
    #include <X11/Xlib.h>
    #include <X11/Xutil.h>

    #define TRUE            1
    #define FALSE           0

    Display *dpy;         /* The X server connection */
    Atom del_atom;        /* WM_DELETE_WINDOW atom   */
    Window glwin;         /* handle to the GL window */
    XEvent event;

    /* function declarations */

    static void openwindow(char *);
    static void resize_buffer(void);
    static void clean_exit(void);
    void initGL(void);
    void orient(void);
    void drawScene(void);
    void drawPolys(void);

    static float objmat[16] = {
             1.0, 0.0, 0.0, 0.0,
             0.0, 1.0, 0.0, 0.0,
             0.0, 0.0, 1.0, 0.0,
             0.0, 0.0, 0.0, 1.0,
    };

    short ax, ay, az;     /* angles for the "twirling" green
                           * sphere to ride on */
    long xsize, ysize;    /* current size-of-window keepers */
    long zfar;            /* used in czclear for the machine's
                           * zbuffer max */
    long buffermode;      /* flag tracks current window
                           * (single or double) */
    double scrnaspect;    /* aspect ratio value */
    int xpos, ypos, oxpos, oypos; /* old and new mouse position */

    main(argc,argv)
    int argc;
    char **argv;
    {
        int myExpose, myConfigure, myButtPress, myKeyPress;
        int needToDraw = 0;  /* don't set this to true until
                              * we get our first Expose event */

        myExpose = myConfigure = myButtPress = myKeyPress = FALSE;

        openwindow(argv[0]);

       /* start out making the singlebuffer window be
        * our current GL window */
        initGL();     /* do GL init stuff */

        /*
         * The event loop.
         */
        while (1) {      /* standard logic:  get event(s),
                          * process event(s) */

            XEvent event;
            KeySym keysym;
            char buf[4];

        /* this "do while" loop does the `get events'
         * half of the "get events, process events" action
         * of the infinite while. this is to ensure
         * the event queue is always drained before the events
         * that have come in are processed.
         */

            do {

                XNextEvent(dpy, &event);
                    switch (event.type) {

                /* "Expose" events are sort of like "REDRAW" in
                 * gl-speak in terms of when a window becomes
                 * visible, or a previously
                 * invisible part becomes visible.
                 */
                    case Expose:   /* Exposures */
                        needToDraw = myExpose = TRUE;
                        break;

                /* "ConfigNotify" events are like "REDRAW" in
                 * terms of changes to a window's size or position.
                 */
                    case ConfigureNotify: /* Resize GL manually */
                        xsize = event.xconfigure.width;
                        ysize = event.xconfigure.height;
                        needToDraw = myConfigure = TRUE;
                        break;

                /* Wait for "MotionNotify" events so the
                 * queue doesn't fill up
                 */
                    case MotionNotify:
                        myButtPress = TRUE;
                        xpos = event.xmotion.x;
                        ypos = event.xmotion.y;
                        break;

                /* "ClientMessage" is generated if the WM itself
                 * is being gunned down and sends an exit signal
                 * to any running prog.
                 */
                    case ClientMessage:
                        if (event.xclient.data.l[0] == del_atom)
                            clean_exit();
                        break;

                /* "KeyPress" events are those that would be
                 *  generated before whenever queueing up any
                    KEYBD key via qdevice.
                 */

                    case KeyPress:
                       /* save out which unmodified key (i.e. the
                        * key was not modified w/something like
                        * "Shift", "Ctrl", or "Alt") got pressed
                        * for use below.
                        */
                        XLookupString((XKeyEvent *)&event, buf, 4,
                                       &keysym, 0);
                        myKeyPress = TRUE;
                        break;

                  }  /* end switch (event.type) */

            } while (XPending(dpy));   /* end "do { } while".
                                        * XPending() is like
                                        * qtest()--it only
                                        * tells you if there're
                                        * any events presently in
                                        * the queue. it does not
                                        * disturb queue's contents
                                        * in any way.
                                        */

        /* On an "Expose" event, redraw the affected pop'd or
         * de-iconized window
         */
            if (myExpose) {
                resize_buffer();
                myExpose = FALSE; /* reset flag--queue now empty */
            }

        /* On a "ConfigureNotify" event, the GL window has either
         * been moved or resized. Respond accordingly and then
         * redraw its contents.
         */
            if (myConfigure) {
                oxpos = xpos;
                oypos = ypos;
                resize_buffer();
                myConfigure = FALSE;  /* reset flag--queue now
                                       * empty */
            }

            if (needToDraw) {
                drawScene();
                needToDraw = FALSE;
            }

            /* On a keypress of Esc key, exit program.
             */
            if (myKeyPress) {
                if (keysym == XK_Escape)
                    clean_exit();
            }

            if (myButtPress) {
                orient();
                drawScene();
                myButtPress = FALSE;
            }
        }      /* end while(1) */

    }      /* end main */

    static int attributeList[] = { GLX_RGBA,
                                   GLX_DOUBLEBUFFER,
                                   GLX_RED_SIZE, 1,
                                   GLX_GREEN_SIZE, 1,
                                   GLX_BLUE_SIZE, 1,
                                   GLX_DEPTH_SIZE, 1,
                                   None };
    static int attributeList2[] = { GLX_RGBA,
                                   GLX_RED_SIZE, 1,
                                   GLX_GREEN_SIZE, 1,
                                   GLX_BLUE_SIZE, 1,
                                   GLX_DEPTH_SIZE, 1,
                                   None };

    static Bool WaitForNotify(Display *d, XEvent *e, char *arg) {
        return (e->type == MapNotify) && (e->xmap.window ==
                                          (Window)arg);
    }

    XSizeHints Winhints;          /* used to fix window size */

    /* openwindow - establish connection to X server, get screen info, specify the
     * attributes we want the WM to try to provide, and create the GL window */
    static void openwindow(char *progname) {

        XVisualInfo *vi;
        GLXContext cx;
        Colormap cmap;
        XSizeHints Winhints;       /* used to fix window size*/
        XSetWindowAttributes swa;
        int scrnnum;               /* X screen number */
        int xorig, yorig;          /* window (upper-left) origin */
        long scrnheight;

       /* define window initial size */
        xorig = 50;  yorig = 40;
        xsize = 300; ysize = 240;
        scrnaspect = xsize / (double) ysize;

       /* Connect to the X server and get screen info */
        if ((dpy = XOpenDisplay(NULL)) == NULL) {
            fprintf(stderr, "%s: cannot connect to X server %s\n",
                                     progname, XDisplayName(NULL));
            exit(1);
        }

        scrnnum = DefaultScreen(dpy);
        scrnheight = DisplayHeight(dpy, scrnnum);

            /* get an appropriate visual */
        vi = glXChooseVisual(dpy, DefaultScreen(dpy),
                             attributeList);
        if (vi == NULL) {
            fprintf(stderr, "Unable to obtain visual
                             Doublebuffered visual\n");
            vi = glXChooseVisual(dpy, DefaultScreen(dpy),
                                 attributeList2);
        }
        if (vi == NULL) {
            printf("Unable to obtain Singlebuffered
                   VISUAL(????)\n");
            exit(0);
        }

        /* create a GLX context */
        cx = glXCreateContext(dpy, vi, None, GL_TRUE);

        /* create a colormap */
        cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
                               vi->visual, AllocNone);

        /* create a window */
        swa.colormap = cmap;
        swa.border_pixel = 0;
        swa.event_mask = StructureNotifyMask  | ButtonPressMask |
                         ExposureMask |
                         Button1MotionMask |
                         KeyPressMask;    /* express interest in
                                           * events */;
        glwin = XCreateWindow(dpy, RootWindow(dpy, vi->screen),
                              xorig, yorig, xsize, ysize,
                              0, vi->depth, InputOutput,
                              vi->visual,
                              CWBorderPixel|CWColormap|CWEventMask, &swa);

        XMapWindow(dpy, glwin);
        XIfEvent(dpy, &event, WaitForNotify, (char*)glwin);

        /* connect the context to the window */
        glXMakeCurrent(dpy, glwin, cx);

        if (!(glwin)) {
            fprintf(stderr,"%s: couldn't create `parent' X
                            window\n",progname);
            exit(1);
        }

       /* define string that will show up in the window title bar
        * (and icon) */
        XStoreName(dpy, glwin, "z-buffered rgb program");

       /* specify the values for the Window Size Hints we want to
        * enforce: this window's aspect ratio needs to stay at
        * 1:1, constrain min and max window size, and specify the
        * initial size of the window.
        */
        Winhints.width  = xsize;   /* specify desired x/y size of
                                    * window */
        Winhints.height = ysize;
        Winhints.min_width = xorig;  /* define min and max */
        Winhints.max_width = scrnheight-1;  /* width and height */
        Winhints.min_height = yorig;
        Winhints.max_height = scrnheight-1;
        Winhints.min_aspect.x = xsize;    /* keep aspect to a xsize:ysize ratio */
        Winhints.max_aspect.x = xsize;
        Winhints.min_aspect.y = ysize;
        Winhints.max_aspect.y = ysize;
        /* set the corresponding flags */
        Winhints.flags = USSize|PMaxSize|PMinSize|PAspect;
        XSetNormalHints(dpy, glwin, &Winhints);

        /* express interest in WM killing this app */
        if ((del_atom = XInternAtom(dpy, "WM_DELETE_WINDOW",
                                    True)) != None)
            XSetWMProtocols(dpy, glwin, &del_atom, 1);

        return ;
    }

    /*  window has been moved or resized so update viewport & CTM stuff. */
    static void resize_buffer() {

        XSync(dpy, False);  /* STILL NEED THIS????? */
                            /* Need before GL reshape */
        scrnaspect = xsize / (double) ysize;
        glViewport(0, 0, (short) (xsize-1), (short) (ysize-1));
    }

    /*  clean up before exiting */
    static void clean_exit(void)
    {
        XCloseDisplay(dpy);
        exit(0);
    }

    /* setup all necessary GL initialzation parameters. */
    void initGL()
    {
        glEnable(GL_DEPTH_TEST);
        glClearColor(0.16, 0.39, 0.78, 0.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
        gluPerspective(400.0, scrnaspect, 30.0, 1000.0);
    }

    void orient()
    {
        float dx, dy;
        glPushMatrix();
        dx = xpos-oxpos;
        dy = oypos-ypos;
        glLoadIdentity();
        glRotatef((float) (0.03*(xpos-oxpos)), 1.0, 0.0, 0.0);
        glRotatef((float) (0.03*(oypos-ypos)), 0.0, 1.0, 0.0);
        glMultMatrixf(objmat);
        glGetFloatv(GL_MODELVIEW_MATRIX, objmat);

        glPopMatrix();
    }

    void drawScene()
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glPushMatrix();
        glTranslatef(0.0, 0.0, -40.0);
        glMultMatrixf(objmat);
        glRotatef(-220.0, 0.0, 1.0, 0.0);  /* skews orig view to
                                            * show all polys */
        drawPolys();
        glPopMatrix();
        glFlush ();
        glXSwapBuffers(dpy, glwin);
    }

    float polygon1[3][3] = { {-10.0, -10.0,   0.0,},
                             { 10.0, -10.0,   0.0,},
                             {-10.0,  10.0,   0.0,} };

    float polygon2[3][3] = { {  0.0, -10.0, -10.0,},
                             {  0.0, -10.0,  10.0,},
                             {  0.0,   5.0, -10.0,} };

    float polygon3[4][3] = { {-10.0,   6.0,   4.0,},
                             {-10.0,   3.0,   4.0,},
                             {  4.0,  -9.0, -10.0,},
                             {  4.0,  -6.0, -10.0,} };

    void drawPolys()
    {
        glBegin(GL_POLYGON);
        glColor4f(0.0, 0.0, 0.0, 0.0);
        glVertex3fv(&polygon1[0][0]);
        glColor4f(0.5, 0.5, 0.5, 0.0);
        glVertex3fv(&polygon1[1][0]);
        glColor4f(1.0, 1.0, 1.0, 0.0);
        glVertex3fv(&polygon1[2][0]);
        glEnd();

        glBegin(GL_POLYGON);
        glColor4f(1.0, 1.0, 0.0, 0.0);
        glVertex3fv(&polygon2[0][0]);
        glColor4f(0.0, 1.0, 0.5, 0.0);
        glVertex3fv(&polygon2[1][0]);
        glColor4f(0.0, 0.0, 1.0, 0.0);
        glVertex3fv(&polygon2[2][0]);
        glEnd();

        glBegin(GL_POLYGON);
        glColor4f(1.0, 1.0, 0.0, 0.0);
        glVertex3fv(&polygon3[0][0]);
        glColor4f(1.0, 0.0, 1.0, 0.0);
        glVertex3fv(&polygon3[1][0]);
        glColor4f(0.0, 0.0, 1.0, 0.0);
        glVertex3fv(&polygon3[2][0]);
        glColor4f(1.0, 0.0, 1.0, 0.0);
        glVertex3fv(&polygon3[3][0]);
        glEnd();

    }

Prev | Table of Contents | Next
Appendix E. Example Program Using Xt and a WorkProc |  | Index