Back to index

radiance  4R0+20100331
rhd_glx1.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: rhd_glx1.c,v 3.6 2006/06/07 17:52:04 schorsch Exp $";
00003 #endif
00004 /*
00005  * OpenGL GLX driver for holodeck display.
00006  * Based on x11 driver.
00007  */
00008 
00009 #include "standard.h"
00010 
00011 #include  <GL/glx.h>
00012 #include  <GL/glu.h>
00013 
00014 #include "platform.h"
00015 #include "rhd_qtree.h"
00016 #include "rhdriver.h"
00017 #include "rhdisp.h"
00018 #include  "x11icon.h"
00019 
00020 #ifndef RAYQLEN
00021 #define RAYQLEN             50000         /* max. rays to queue before flush */
00022 #endif
00023 
00024 #ifndef FEQ
00025 #define FEQ(a,b)     ((a)-(b) <= FTINY && (a)-(b) >= -FTINY)
00026 #endif
00027 
00028 #ifndef MAXCONE
00029 #define MAXCONE             16            /* number of different cone sizes */
00030 #endif
00031 #ifndef MAXVERT
00032 #define MAXVERT             64            /* maximum number of cone vertices */
00033 #endif
00034 #ifndef MINVERT
00035 #define MINVERT             4             /* minimum number of cone vertices */
00036 #endif
00037 #ifndef DEPTHFACT
00038 #define DEPTHFACT    16.           /* multiplier for depth tests */
00039 #endif
00040 
00041 #define GAMMA        1.4           /* default gamma correction */
00042 
00043 #define MOVPCT              7             /* percent distance to move /frame */
00044 #define MOVDIR(b)    ((b)==Button1 ? 1 : (b)==Button2 ? 0 : -1)
00045 #define MOVDEG              (-5)          /* degrees to orbit CW/down /frame */
00046 #define MOVORB(s)    ((s)&ShiftMask ? 1 : (s)&ControlMask ? -1 : 0)
00047 
00048 #define MINWIDTH     480           /* minimum graphics window width */
00049 #define MINHEIGHT    400           /* minimum graphics window height */
00050 
00051 #define VIEWDIST     356           /* assumed viewing distance (mm) */
00052 
00053 #define BORWIDTH     5             /* border width */
00054 
00055 #define  ourscreen   DefaultScreen(ourdisplay)
00056 #define  ourroot     RootWindow(ourdisplay,ourscreen)
00057 #define  ourmask     (StructureNotifyMask|ExposureMask|KeyPressMask|\
00058                      ButtonPressMask|ButtonReleaseMask)
00059 
00060 #define  levptr(etype)      ((etype *)&currentevent)
00061 
00062 struct driver odev;                /* global device driver structure */
00063 
00064 TMstruct      *tmGlobal;           /* global tone-mapping structure */
00065 
00066 char odev_args[64];                /* command arguments */
00067 
00068 static XEvent  currentevent;              /* current event */
00069 
00070 static int  mapped = 0;                   /* window is mapped? */
00071 static unsigned long  ourblack=0, ourwhite=~0;
00072 
00073 static Display  *ourdisplay = NULL;       /* our display */
00074 static XVisualInfo  *ourvinf;             /* our visual information */
00075 static Window  gwind = 0;          /* our graphics window */
00076 static GLXContext    gctx;         /* our GLX context */
00077 
00078 static double pwidth, pheight;     /* pixel dimensions (mm) */
00079 
00080 static double curzmax = 1e4;              /* current depth upper limit */
00081 static double nxtzmax = 0.;        /* maximum (finite) depth so far */
00082 
00083 static struct {
00084        double rad;          /* cone radius */
00085        int    nverts;              /* number of vertices */
00086        FVECT  *va;          /* allocated vertex array */
00087 } cone[MAXCONE];     /* precomputed cones for drawing */
00088 
00089 static int    inpresflags;         /* input result flags */
00090 
00091 static int    headlocked = 0;             /* lock vertical motion */
00092 
00093 
00094 static int mytmflags(void);
00095 static void initcones(void);
00096 static void freecones(void);
00097 static void getevent(void);
00098 static void draw3dline(FVECT       wp[2]);
00099 static void draw_grids(void);
00100 static int moveview(int     dx, int       dy, int       mov, int      orb);
00101 static void getmove(XButtonPressedEvent   *ebut);
00102 static void getkey(XKeyPressedEvent  *ekey);
00103 static void fixwindow(XExposeEvent  *eexp);
00104 static void resizewindow(XConfigureEvent  *ersz);
00105 
00106 
00107 extern void
00108 dev_open(
00109        char  *id
00110 )
00111 {
00112        extern char   *getenv();
00113        static RGBPRIMS      myprims = STDPRIMS;
00114        static int    atlBest[] = {GLX_RGBA, GLX_RED_SIZE,8,
00115                             GLX_GREEN_SIZE,8, GLX_BLUE_SIZE,8,
00116                             GLX_DEPTH_SIZE,15, None};
00117        char   *ev;
00118        double gamval = GAMMA;
00119        RGBPRIMP      dpri = stdprims;
00120        XSetWindowAttributes ourwinattr;
00121        XWMHints      ourxwmhints;
00122        XSizeHints    oursizhints;
00123                                    /* set quadtree globals */
00124        qtMinNodesiz = 3;
00125        qtDepthEps = 0.07;
00126                                    /* open display server */
00127        ourdisplay = XOpenDisplay(NULL);
00128        if (ourdisplay == NULL)
00129               error(USER, "cannot open X-windows; DISPLAY variable set?\n");
00130                                    /* find a usable visual */
00131        ourvinf = glXChooseVisual(ourdisplay, ourscreen, atlBest);
00132        if (ourvinf == NULL)
00133               error(USER, "no suitable visuals available");
00134                                    /* get a context */
00135        gctx = glXCreateContext(ourdisplay, ourvinf, NULL, GL_TRUE);
00136                                    /* set gamma and tone mapping */
00137        if ((ev = XGetDefault(ourdisplay, "radiance", "gamma")) != NULL
00138                      || (ev = getenv("DISPLAY_GAMMA")) != NULL)
00139               gamval = atof(ev);
00140        if ((ev = getenv("DISPLAY_PRIMARIES")) != NULL &&
00141                      sscanf(ev, "%f %f %f %f %f %f %f %f",
00142                             &myprims[RED][CIEX],&myprims[RED][CIEY],
00143                             &myprims[GRN][CIEX],&myprims[GRN][CIEY],
00144                             &myprims[BLU][CIEX],&myprims[BLU][CIEY],
00145                             &myprims[WHT][CIEX],&myprims[WHT][CIEY]) >= 6)
00146               dpri = myprims;
00147        tmGlobal = tmInit(mytmflags(), dpri, gamval);
00148        if (tmGlobal == NULL)
00149               error(SYSTEM, "not enough memory in dev_open");
00150                                    /* open window */
00151        ourwinattr.background_pixel = ourblack;
00152        ourwinattr.border_pixel = ourblack;
00153        ourwinattr.event_mask = ourmask;
00154                                    /* this is stupid */
00155        ourwinattr.colormap = XCreateColormap(ourdisplay, ourroot,
00156                             ourvinf->visual, AllocNone);
00157        gwind = XCreateWindow(ourdisplay, ourroot, 0, 0,
00158               DisplayWidth(ourdisplay,ourscreen)-2*BORWIDTH,
00159               DisplayHeight(ourdisplay,ourscreen)-2*BORWIDTH,
00160               BORWIDTH, ourvinf->depth, InputOutput, ourvinf->visual,
00161               CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &ourwinattr);
00162        if (gwind == 0)
00163               error(SYSTEM, "cannot create window\n");
00164        XStoreName(ourdisplay, gwind, id);
00165                                    /* set window manager hints */
00166        ourxwmhints.flags = InputHint|IconPixmapHint;
00167        ourxwmhints.input = True;
00168        ourxwmhints.icon_pixmap = XCreateBitmapFromData(ourdisplay,
00169                      gwind, x11icon_bits, x11icon_width, x11icon_height);
00170        XSetWMHints(ourdisplay, gwind, &ourxwmhints);
00171        oursizhints.min_width = MINWIDTH;
00172        oursizhints.min_height = MINHEIGHT;
00173        oursizhints.flags = PMinSize;
00174        XSetNormalHints(ourdisplay, gwind, &oursizhints);
00175                                    /* set GLX context */
00176        glXMakeCurrent(ourdisplay, gwind, gctx);
00177        glEnable(GL_DEPTH_TEST);
00178        glDepthFunc(GL_LEQUAL);
00179        glShadeModel(GL_FLAT);
00180        glDisable(GL_DITHER);
00181        glDisable(GL_CULL_FACE);
00182        glMatrixMode(GL_PROJECTION);
00183        glOrtho(0., 1., 0., 1., -.01, 1.01);
00184        glTranslated(0., 0., -1.01);
00185                                    /* figure out sensible view */
00186        pwidth = (double)DisplayWidthMM(ourdisplay, ourscreen) /
00187                      DisplayWidth(ourdisplay, ourscreen);
00188        pheight = (double)DisplayHeightMM(ourdisplay, ourscreen) /
00189                      DisplayHeight(ourdisplay, ourscreen);
00190        odev.v = stdview;
00191        odev.v.type = VT_PER;
00192                                    /* map the window */
00193        XMapWindow(ourdisplay, gwind);
00194        dev_input();                /* sets size and view angles */
00195                                    /* allocate our leaf pile */
00196        if (!qtAllocLeaves(DisplayWidth(ourdisplay,ourscreen) *
00197                      DisplayHeight(ourdisplay,ourscreen) * 3 /
00198                      (qtMinNodesiz*qtMinNodesiz*2)))
00199               error(SYSTEM, "insufficient memory for value storage");
00200        odev.name = id;
00201        odev.ifd = ConnectionNumber(ourdisplay);
00202                                    /* initialize cone array */
00203        initcones();
00204 }
00205 
00206 
00207 extern void
00208 dev_close(void)                    /* close our display and free resources */
00209 {
00210        glXMakeCurrent(ourdisplay, None, NULL);
00211        glXDestroyContext(ourdisplay, gctx);
00212        XDestroyWindow(ourdisplay, gwind);
00213        gwind = 0;
00214        XCloseDisplay(ourdisplay);
00215        ourdisplay = NULL;
00216        qtFreeLeaves();
00217        tmDone(tmGlobal);
00218        freecones();
00219        odev.v.type = 0;
00220        odev.hres = odev.vres = 0;
00221        odev.ifd = -1;
00222 }
00223 
00224 
00225 extern void
00226 dev_clear(void)                    /* clear our quadtree */
00227 {
00228        qtCompost(100);
00229        glClear(GL_DEPTH_BUFFER_BIT);
00230        rayqleft = 0;               /* hold off update */
00231 }
00232 
00233 
00234 extern int
00235 dev_view(                   /* assign new driver view */
00236        register VIEW *nv
00237 )
00238 {
00239        if (nv->type == VT_PAR ||          /* check view legality */
00240                      nv->horiz > 160. || nv->vert > 160.) {
00241               error(COMMAND, "illegal view type/angle");
00242               nv->type = odev.v.type;
00243               nv->horiz = odev.v.horiz;
00244               nv->vert = odev.v.vert;
00245               return(0);
00246        }
00247        if (nv->vfore > FTINY) {
00248               error(COMMAND, "cannot handle fore clipping");
00249               nv->vfore = 0.;
00250               return(0);
00251        }
00252        if (nv != &odev.v) {
00253               if (!FEQ(nv->horiz,odev.v.horiz) ||       /* resize window? */
00254                             !FEQ(nv->vert,odev.v.vert)) {
00255                      int    dw = DisplayWidth(ourdisplay,ourscreen);
00256                      int    dh = DisplayHeight(ourdisplay,ourscreen);
00257 
00258                      dw -= 25;     /* for window frame */
00259                      dh -= 50;
00260                      odev.hres = 2.*VIEWDIST/pwidth *
00261                                    tan(PI/180./2.*nv->horiz);
00262                      odev.vres = 2.*VIEWDIST/pheight *
00263                                    tan(PI/180./2.*nv->vert);
00264                      if (odev.hres > dw) {
00265                             odev.vres = dw * odev.vres / odev.hres;
00266                             odev.hres = dw;
00267                      }
00268                      if (odev.vres > dh) {
00269                             odev.hres = dh * odev.hres / odev.vres;
00270                             odev.vres = dh;
00271                      }
00272                      XResizeWindow(ourdisplay, gwind, odev.hres, odev.vres);
00273                      dev_input();  /* get resize event */
00274               }
00275               odev.v = *nv;
00276        }
00277        if (nxtzmax > FTINY) {
00278               curzmax = nxtzmax;
00279               nxtzmax = 0.;
00280        }
00281        glClear(GL_DEPTH_BUFFER_BIT);
00282        qtReplant();
00283        return(1);
00284 }
00285 
00286 
00287 extern void
00288 dev_section(         /* add octree for geometry rendering */
00289        char   *gfn,
00290        char   *pfn
00291 )
00292 {
00293        /* unimplemented */
00294 }
00295 
00296 
00297 extern void
00298 dev_auxcom(          /* process an auxiliary command */
00299        char   *cmd,
00300        char   *args
00301 )
00302 {
00303        sprintf(errmsg, "%s: unknown command", cmd);
00304        error(COMMAND, errmsg);
00305 }
00306 
00307 
00308 extern VIEW *
00309 dev_auxview(         /* return nth auxiliary view */
00310        int    n,
00311        int    hvres[2]
00312 )
00313 {
00314        if (n)
00315               return(NULL);
00316        hvres[0] = odev.hres; hvres[1] = odev.vres;
00317        return(&odev.v);
00318 }
00319 
00320 
00321 extern int
00322 dev_input(void)                    /* get X11 input */
00323 {
00324        inpresflags = 0;
00325 
00326        do
00327               getevent();
00328 
00329        while (XQLength(ourdisplay) > 0);
00330 
00331        return(inpresflags);
00332 }
00333 
00334 
00335 extern int
00336 dev_flush(void)                    /* flush output */
00337 {
00338        qtUpdate();
00339        glFlush();
00340        rayqleft = RAYQLEN;
00341        return(XPending(ourdisplay));
00342 }
00343 
00344 
00345 extern void
00346 dev_cone(            /* render a cone in view coordinates */
00347        BYTE   rgb[3],
00348        FVECT  ip,
00349        double rad
00350 )
00351 {
00352        register int  ci, j;
00353        double apexh, basez;
00354                                    /* is window mapped? */
00355        if (!mapped)
00356               return;
00357                                    /* compute apex height (0. to 1.) */
00358        if (ip[2] > 1e6)
00359               apexh = 1. - 1./DEPTHFACT;
00360        else {
00361               if (ip[2] > nxtzmax)
00362                      nxtzmax = ip[2];
00363               if (ip[2] >= curzmax)
00364                      apexh = 1. - 1./DEPTHFACT;
00365               else
00366                      apexh = 1. - ip[2]/(curzmax*DEPTHFACT);
00367        }
00368        rad *= 1.25;                /* find conservative cone match */
00369        for (ci = 0; ci < MAXCONE-1; ci++)
00370               if (cone[ci].rad >= rad)
00371                      break;
00372                                    /* draw it */
00373        glColor3ub(rgb[0], rgb[1], rgb[2]);
00374        glBegin(GL_TRIANGLE_FAN);
00375        glVertex3d(ip[0], ip[1], apexh);   /* start with apex */
00376        basez = apexh*cone[ci].va[0][2];   /* base z's all the same */
00377        for (j = 0; j < cone[ci].nverts; j++)     /* draw each face */
00378               glVertex3d(ip[0]+cone[ci].va[j][0], ip[1]+cone[ci].va[j][1],
00379                             basez);
00380                                           /* connect last to first */
00381        glVertex3d(ip[0]+cone[ci].va[0][0], ip[1]+cone[ci].va[0][1], basez);
00382        glEnd();                           /* all done */
00383 }
00384 
00385 
00386 static int
00387 mytmflags(void)                    /* figure out tone mapping flags */
00388 {
00389        extern char   *progname;
00390        register char *cp, *tail;
00391                                    /* find basic name */
00392        for (cp = tail = progname; *cp; cp++)
00393               if (*cp == '/')
00394                      tail = cp+1;
00395        for (cp = tail; *cp && *cp != '.'; cp++)
00396               ;
00397        if (cp-tail == 4 && !strncmp(tail, "glx1", 4))
00398               return(TM_F_CAMERA|TM_F_NOSTDERR);
00399        if (cp-tail == 5 && !strncmp(tail, "glx1h", 5))
00400               return(TM_F_HUMAN|TM_F_NOSTDERR);
00401        error(USER, "illegal driver name");
00402        return -1; /* pro forma return */
00403 }
00404 
00405 
00406 static void
00407 initcones(void)                    /* initialize cone vertices */
00408 {
00409        register int  i, j;
00410        double minrad, d;
00411 
00412        if (cone[0].nverts)
00413               freecones();
00414        minrad = 2.*qtMinNodesiz/(double)(DisplayWidth(ourdisplay,ourscreen) +
00415                                    DisplayHeight(ourdisplay,ourscreen));
00416        for (i = 0; i < MAXCONE; i++) {
00417               d = (double)i/(MAXCONE-1); d *= d; /* x^2 distribution */
00418               cone[i].rad = minrad + (1.-minrad)*d;
00419               cone[i].nverts = MINVERT + 0.5 + (MAXVERT-MINVERT)*d;
00420               cone[i].va = (FVECT *)malloc(cone[i].nverts*sizeof(FVECT));
00421               if (cone[i].va == NULL)
00422                      error(SYSTEM, "out of memory in initcones");
00423               for (j = cone[i].nverts; j--; ) {
00424                      d = 2.*PI * (j+.5) / (cone[i].nverts);
00425                      cone[i].va[j][0] = cos(d) * cone[i].rad;
00426                      cone[i].va[j][1] = sin(d) * cone[i].rad;
00427                      cone[i].va[j][2] = 1. - cone[i].rad;
00428               }
00429        }
00430 }
00431 
00432 
00433 static void
00434 freecones(void)                    /* free cone vertices */
00435 {
00436        register int  i;
00437 
00438        for (i = MAXCONE; i--; )
00439               if (cone[i].nverts) {
00440                      free((void *)cone[i].va);
00441                      cone[i].va = NULL;
00442                      cone[i].nverts = 0;
00443               }
00444 }
00445 
00446 
00447 static void
00448 getevent(void)                     /* get next event */
00449 {
00450        XNextEvent(ourdisplay, levptr(XEvent));
00451        switch (levptr(XEvent)->type) {
00452        case ConfigureNotify:
00453               resizewindow(levptr(XConfigureEvent));
00454               break;
00455        case UnmapNotify:
00456               mapped = 0;
00457               break;
00458        case MapNotify:
00459               mapped = 1;
00460               break;
00461        case Expose:
00462               fixwindow(levptr(XExposeEvent));
00463               break;
00464        case KeyPress:
00465               getkey(levptr(XKeyPressedEvent));
00466               break;
00467        case ButtonPress:
00468               getmove(levptr(XButtonPressedEvent));
00469               break;
00470        }
00471 }
00472 
00473 
00474 static void
00475 draw3dline(                 /* draw 3d line in world coordinates */
00476        register FVECT       wp[2]
00477 )
00478 {
00479        glVertex3d(wp[0][0], wp[0][1], wp[0][2]);
00480        glVertex3d(wp[1][0], wp[1][1], wp[1][2]);
00481 }
00482 
00483 
00484 static void
00485 draw_grids(void)                   /* draw holodeck section grids */
00486 {
00487        static BYTE   gridrgba[4] = {0x0, 0xff, 0xff, 0x00};
00488        double xmin, xmax, ymin, ymax, zmin, zmax;
00489        double d;
00490                                    /* can we even do it? */
00491        if (!mapped || odev.v.type != VT_PER)
00492               return;
00493                                    /* compute view frustum */
00494        if (normalize(odev.v.vdir) == 0.0)
00495               return;
00496        zmin = 0.01;
00497        zmax = 10000.;
00498        if (odev.v.vfore > FTINY)
00499               zmin = odev.v.vfore;
00500        if (odev.v.vaft > FTINY)
00501               zmax = odev.v.vaft;
00502        xmax = zmin * tan(PI/180./2. * odev.v.horiz);
00503        xmin = -xmax;
00504        d = odev.v.hoff * (xmax - xmin);
00505        xmin += d; xmax += d;
00506        ymax = zmin * tan(PI/180./2. * odev.v.vert);
00507        ymin = -ymax;
00508        d = odev.v.voff * (ymax - ymin);
00509        ymin += d; ymax += d;
00510                                    /* set view matrix */
00511        glMatrixMode(GL_PROJECTION);
00512        glPushMatrix();
00513        glLoadIdentity();
00514        glFrustum(xmin, xmax, ymin, ymax, zmin, zmax);
00515        gluLookAt(odev.v.vp[0], odev.v.vp[1], odev.v.vp[2],
00516               odev.v.vp[0] + odev.v.vdir[0],
00517               odev.v.vp[1] + odev.v.vdir[1],
00518               odev.v.vp[2] + odev.v.vdir[2],
00519               odev.v.vup[0], odev.v.vup[1], odev.v.vup[2]);
00520        glDisable(GL_DEPTH_TEST);   /* write no depth values */
00521        glColor4ub(gridrgba[0], gridrgba[1], gridrgba[2], gridrgba[3]);
00522        glBegin(GL_LINES);          /* draw each grid line */
00523        gridlines(draw3dline);
00524        glEnd();
00525        glEnable(GL_DEPTH_TEST);    /* restore rendering params */
00526        glPopMatrix();
00527 }
00528 
00529 
00530 static int
00531 moveview(     /* move our view */
00532        int    dx,
00533        int    dy,
00534        int    mov,
00535        int    orb
00536 )
00537 {
00538        VIEW   nv;
00539        FVECT  odir, v1;
00540        double d;
00541        register int  li;
00542                             /* start with old view */
00543        nv = odev.v;
00544                             /* change view direction */
00545        if (mov | orb) {
00546               if ((li = qtFindLeaf(dx, dy)) < 0)
00547                      return(0);    /* not on window */
00548               VSUM(odir, qtL.wp[li], nv.vp, -1.);
00549        } else {
00550               if (viewray(nv.vp, nv.vdir, &odev.v,
00551                             (dx+.5)/odev.hres, (dy+.5)/odev.vres) < -FTINY)
00552                      return(0);    /* outside view */
00553        }
00554        if (orb && mov) {           /* orbit left/right */
00555               spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov);
00556               VSUM(nv.vp, qtL.wp[li], odir, -1.);
00557               spinvector(nv.vdir, nv.vdir, nv.vup, d);
00558        } else if (orb) {           /* orbit up/down */
00559               fcross(v1, odir, nv.vup);
00560               if (normalize(v1) == 0.)
00561                      return(0);
00562               spinvector(odir, odir, v1, d=MOVDEG*PI/180.*orb);
00563               VSUM(nv.vp, qtL.wp[li], odir, -1.);
00564               spinvector(nv.vdir, nv.vdir, v1, d);
00565        } else if (mov) {           /* move forward/backward */
00566               d = MOVPCT/100. * mov;
00567               VSUM(nv.vp, nv.vp, odir, d);
00568        }
00569        if (!mov ^ !orb && headlocked) {   /* restore head height */
00570               VSUM(v1, odev.v.vp, nv.vp, -1.);
00571               d = DOT(v1, odev.v.vup);
00572               VSUM(nv.vp, nv.vp, odev.v.vup, d);
00573        }
00574        if (setview(&nv) != NULL)
00575               return(0);    /* illegal view */
00576        dev_view(&nv);
00577        inpresflags |= DFL(DC_SETVIEW);
00578        return(1);
00579 }
00580 
00581 
00582 static void
00583 getmove(                           /* get view change */
00584        XButtonPressedEvent  *ebut
00585 )
00586 {
00587        int    movdir = MOVDIR(ebut->button);
00588        int    movorb = MOVORB(ebut->state);
00589        int    oldnodesiz = qtMinNodesiz;
00590        Window rootw, childw;
00591        int    rootx, rooty, wx, wy;
00592        unsigned int  statemask;
00593 
00594        qtMinNodesiz = 24;          /* accelerate update rate */
00595        XNoOp(ourdisplay);
00596 
00597        while (!XCheckMaskEvent(ourdisplay,
00598                      ButtonReleaseMask, levptr(XEvent))) {
00599 
00600               if (!XQueryPointer(ourdisplay, gwind, &rootw, &childw,
00601                             &rootx, &rooty, &wx, &wy, &statemask))
00602                      break;        /* on another screen */
00603 
00604               if (!moveview(wx, odev.vres-1-wy, movdir, movorb)) {
00605                      sleep(1);
00606                      continue;
00607               }
00608               glClear(GL_COLOR_BUFFER_BIT);
00609               qtUpdate();
00610               draw_grids();
00611               glFlush();
00612        }
00613        if (!(inpresflags & DFL(DC_SETVIEW))) {   /* do final motion */
00614               movdir = MOVDIR(levptr(XButtonReleasedEvent)->button);
00615               wx = levptr(XButtonReleasedEvent)->x;
00616               wy = levptr(XButtonReleasedEvent)->y;
00617               moveview(wx, odev.vres-1-wy, movdir, movorb);
00618        }
00619        dev_flush();
00620 
00621        qtMinNodesiz = oldnodesiz;  /* restore quadtree resolution */
00622 }
00623 
00624 
00625 static void
00626 getkey(                            /* get input key */
00627        register XKeyPressedEvent  *ekey
00628 )
00629 {
00630        int  n;
00631        char   buf[8];
00632 
00633        n = XLookupString(ekey, buf, sizeof(buf), NULL, NULL);
00634        if (n != 1)
00635               return;
00636        switch (buf[0]) {
00637        case 'h':                   /* turn on height motion lock */
00638               headlocked = 1;
00639               return;
00640        case 'H':                   /* turn off height motion lock */
00641               headlocked = 0;
00642               return;
00643        case 'l':                   /* retrieve last view */
00644               inpresflags |= DFL(DC_LASTVIEW);
00645               return;
00646        case 'p':                   /* pause computation */
00647               inpresflags |= DFL(DC_PAUSE);
00648               return;
00649        case 'v':                   /* spit out view */
00650               inpresflags |= DFL(DC_GETVIEW);
00651               return;
00652        case '\n':
00653        case '\r':                  /* resume computation */
00654               inpresflags |= DFL(DC_RESUME);
00655               return;
00656        case CTRL('R'):                    /* redraw screen */
00657               if (nxtzmax > FTINY) {
00658                      curzmax = nxtzmax;
00659                      nxtzmax = 0.;
00660               }
00661               glClear(GL_DEPTH_BUFFER_BIT);
00662               qtRedraw(0, 0, odev.hres, odev.vres);
00663               return;
00664        case CTRL('L'):                    /* refresh from server */
00665               if (inpresflags & DFL(DC_REDRAW))
00666                      return;
00667               if (nxtzmax > FTINY) {
00668                      curzmax = nxtzmax;
00669                      nxtzmax = 0.;
00670               }
00671               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00672               draw_grids();
00673               glFlush();
00674               qtCompost(100);                    /* get rid of old values */
00675               inpresflags |= DFL(DC_REDRAW);     /* resend values from server */
00676               rayqleft = 0;               /* hold off update */
00677               return;
00678        case 'K':                   /* kill rtrace process(es) */
00679               inpresflags |= DFL(DC_KILL);
00680               break;
00681        case 'R':                   /* restart rtrace */
00682               inpresflags |= DFL(DC_RESTART);
00683               break;
00684        case 'C':                   /* clobber holodeck */
00685               inpresflags |= DFL(DC_CLOBBER);
00686               break;
00687        case 'q':                   /* quit the program */
00688               inpresflags |= DFL(DC_QUIT);
00689               return;
00690        default:
00691               XBell(ourdisplay, 0);
00692               return;
00693        }
00694 }
00695 
00696 
00697 static void
00698 fixwindow(                         /* repair damage to window */
00699        register XExposeEvent  *eexp
00700 )
00701 {
00702        int    xmin, xmax, ymin, ymax;
00703 
00704        if (odev.hres == 0 || odev.vres == 0)     /* first exposure */
00705               resizewindow((XConfigureEvent *)eexp);
00706        xmin = eexp->x; xmax = eexp->x + eexp->width;
00707        ymin = odev.vres - eexp->y - eexp->height; ymax = odev.vres - eexp->y;
00708                                           /* clear portion of depth */
00709        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
00710        glDepthFunc(GL_ALWAYS);
00711        glBegin(GL_POLYGON);
00712        glVertex3d((double)xmin/odev.hres, (double)ymin/odev.vres, 0.);
00713        glVertex3d((double)xmax/odev.hres, (double)ymin/odev.vres, 0.);
00714        glVertex3d((double)xmax/odev.hres, (double)ymax/odev.vres, 0.);
00715        glVertex3d((double)xmin/odev.hres, (double)ymax/odev.vres, 0.);
00716        glEnd();
00717        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00718        glDepthFunc(GL_LEQUAL);
00719        qtRedraw(xmin, ymin, xmax, ymax);
00720 }
00721 
00722 
00723 static void
00724 resizewindow(               /* resize window */
00725        register XConfigureEvent  *ersz
00726 )
00727 {
00728        glViewport(0, 0, ersz->width, ersz->height);
00729 
00730        if (ersz->width == odev.hres && ersz->height == odev.vres)
00731               return;
00732 
00733        odev.hres = ersz->width;
00734        odev.vres = ersz->height;
00735 
00736        odev.v.horiz = 2.*180./PI * atan(0.5/VIEWDIST*pwidth*odev.hres);
00737        odev.v.vert = 2.*180./PI * atan(0.5/VIEWDIST*pheight*odev.vres);
00738 
00739        inpresflags |= DFL(DC_SETVIEW);
00740 }