--- ray/src/hd/rhd_glx.c 1998/08/21 11:38:21 3.21 +++ ray/src/hd/rhd_glx.c 2003/07/21 22:30:18 3.30 @@ -1,9 +1,6 @@ -/* Copyright (c) 1998 Silicon Graphics, Inc. */ - #ifndef lint -static char SCCSid[] = "$SunId$ SGI"; +static const char RCSid[] = "$Id: rhd_glx.c,v 3.30 2003/07/21 22:30:18 schorsch Exp $"; #endif - /* * OpenGL GLX driver for holodeck display. * Based on old GLX driver using cones. @@ -21,14 +18,14 @@ static char SCCSid[] = "$SunId$ SGI"; #endif #include "standard.h" -#include "rhd_sample.h" -#include #include #include #ifdef STEREO #include #endif + +#include "rhd_sample.h" #ifdef DOBJ #include "rhdobj.h" #endif @@ -36,7 +33,7 @@ static char SCCSid[] = "$SunId$ SGI"; #include "x11icon.h" #ifndef RAYQLEN -#define RAYQLEN 250 /* max. rays to queue before flush */ +#define RAYQLEN 1024 /* max. rays to queue before flush */ #endif #ifndef FEQ @@ -45,13 +42,15 @@ static char SCCSid[] = "$SunId$ SGI"; #define GAMMA 1.4 /* default gamma correction */ +#define FRAMESTATE(s) (((s)&(ShiftMask|ControlMask))==(ShiftMask|ControlMask)) + #define MOVPCT 7 /* percent distance to move /frame */ #define MOVDIR(b) ((b)==Button1 ? 1 : (b)==Button2 ? 0 : -1) #define MOVDEG (-5) /* degrees to orbit CW/down /frame */ #define MOVORB(s) ((s)&ShiftMask ? 1 : (s)&ControlMask ? -1 : 0) #ifndef TARGETFPS -#define TARGETFPS 4.0 /* target frames/sec during motion */ +#define TARGETFPS 2.0 /* target frames/sec during motion */ #endif #define MINWIDTH 480 /* minimum graphics window width */ @@ -74,7 +73,11 @@ static char SCCSid[] = "$SunId$ SGI"; struct driver odev; /* global device driver structure */ +char odev_args[64]; /* command arguments */ + +#ifdef STEREO static VIEW vwright; /* right eye view */ +#endif static int rayqleft = 0; /* rays left to queue before flush */ @@ -99,11 +102,14 @@ static int inpresflags; /* input result flags */ static int headlocked = 0; /* lock vertical motion */ static int resizewindow(), getevent(), getkey(), moveview(), wipeclean(), - setglpersp(), getmove(), fixwindow(), mytmflags(); + setglpersp(), getframe(), getmove(), fixwindow(), mytmflags(); #ifdef STEREO static int pushright(), popright(); #endif +static double getdistance(); +#define mapdepth(d) ((d)> 0.9995 ? FHUGE: dev_zmin/ \ + (1.-(d)*(1.-dev_zmin/dev_zmax))) extern time_t time(); @@ -124,7 +130,7 @@ char *id; XSizeHints oursizhints; /* check for unsupported stereo */ #ifdef NOSTEREO - error(USER, "stereo display driver unavailable"); + error(INTERNAL, "stereo display driver unavailable"); #endif /* open display server */ ourdisplay = XOpenDisplay(NULL); @@ -216,7 +222,8 @@ char *id; pheight *= 2.; setstereobuf(STEREO_BUFFER_LEFT); #endif - copystruct(&odev.v, &stdview); + checkglerr("setting rendering parameters"); + odev.v = stdview; odev.v.type = VT_PER; /* map the window */ XMapWindow(ourdisplay, gwind); @@ -253,7 +260,7 @@ dev_close() /* close our display and free resources dev_clear() /* clear our representation */ { smInit(rsL.max_samp); - wipeclean(); + wipeclean(1); rayqleft = 0; /* hold off update */ } @@ -272,46 +279,53 @@ register VIEW *nv; nv->vert = odev.v.vert; return(0); } - if (nv != &odev.v && /* resize window? */ - (!FEQ(nv->horiz,odev.v.horiz) || - !FEQ(nv->vert,odev.v.vert))) { - int dw = DisplayWidth(ourdisplay,ourscreen); - int dh = DisplayHeight(ourdisplay,ourscreen); + if (nv != &odev.v) { + /* resize window? */ + if (!FEQ(nv->horiz,odev.v.horiz) || + !FEQ(nv->vert,odev.v.vert)) { + int dw = DisplayWidth(ourdisplay,ourscreen); + int dh = DisplayHeight(ourdisplay,ourscreen); - dw -= 25; /* for window frame */ - dh -= 50; + dw -= 25; /* for window frame */ + dh -= 50; #ifdef STEREO - dh /= 2; + dh /= 2; #endif - odev.hres = 2.*VIEWDIST/pwidth * - tan(PI/180./2.*nv->horiz); - odev.vres = 2.*VIEWDIST/pheight * - tan(PI/180./2.*nv->vert); - if (odev.hres > dw) { - odev.vres = dw * odev.vres / odev.hres; - odev.hres = dw; + odev.hres = 2.*VIEWDIST/pwidth * + tan(PI/180./2.*nv->horiz); + odev.vres = 2.*VIEWDIST/pheight * + tan(PI/180./2.*nv->vert); + if (odev.hres > dw) { + odev.vres = dw * odev.vres / odev.hres; + odev.hres = dw; + } + if (odev.vres > dh) { + odev.hres = dh * odev.hres / odev.vres; + odev.vres = dh; + } + XResizeWindow(ourdisplay, gwind, odev.hres, odev.vres); + dev_input(); /* get resize event */ } - if (odev.vres > dh) { - odev.hres = dh * odev.hres / odev.vres; - odev.vres = dh; - } - XResizeWindow(ourdisplay, gwind, odev.hres, odev.vres); - dev_input(); /* get resize event */ + odev.v = *nv; /* setview() already called */ } - copystruct(&odev.v, nv); /* setview() already called */ - setglpersp(&odev.v); #ifdef STEREO - copystruct(&vwright, nv); + vwright = *nv; d = eyesepdist / sqrt(nv->hn2); VSUM(vwright.vp, nv->vp, nv->hvec, d); /* setview(&vwright); -- Unnecessary */ #endif - checkglerr("setting view"); - wipeclean(); + wipeclean(0); return(1); } +dev_section(gfn, pfn) /* add octree for geometry rendering */ +char *gfn, *pfn; +{ + /* unimplemented */ +} + + dev_auxcom(cmd, args) /* process an auxiliary command */ char *cmd, *args; { @@ -367,8 +381,7 @@ FVECT d, p; return; } #endif - smNewSamp(c, d, p); /* add to display representation */ - if (p != NULL) { + if (p != NULL) { /* add depth to our range */ depth = (p[0] - odev.v.vp[0])*d[0] + (p[1] - odev.v.vp[1])*d[1] + (p[2] - odev.v.vp[2])*d[2]; @@ -379,6 +392,7 @@ FVECT d, p; maxdpth = depth; } } + smNewSamp(c, d, p); /* add to display representation */ if (!--rayqleft) dev_flush(); /* flush output */ } @@ -387,22 +401,22 @@ FVECT d, p; int dev_flush() /* flush output */ { + if (mapped) { #ifdef STEREO - pushright(); /* update right eye */ - glClear(GL_DEPTH_BUFFER_BIT); - smUpdate(&vwright, 100); + pushright(); /* update right eye */ + smUpdate(&vwright, MAXQUALITY); #ifdef DOBJ - dobj_render(); /* usually in foreground */ + dobj_render(); /* usually in foreground */ #endif - popright(); /* update left eye */ - glClear(GL_DEPTH_BUFFER_BIT); + popright(); /* update left eye */ #endif - smUpdate(&odev.v, 100); + smUpdate(&odev.v, MAXQUALITY); + checkglerr("rendering mesh"); #ifdef DOBJ - dobj_render(); + dobj_render(); #endif - glFlush(); /* flush OGL */ - checkglerr("flushing display"); + glFlush(); /* flush OGL */ + } rayqleft = RAYQLEN; /* flush X11 and return # pending */ return(odev.inpready = XPending(ourdisplay)); @@ -433,6 +447,7 @@ pushright() /* push on right view */ glPushMatrix(); d = -eyesepdist / sqrt(odev.v.hn2); glTranslated(d*odev.v.hvec[0], d*odev.v.hvec[1], d*odev.v.hvec[2]); + checkglerr("setting right view"); } @@ -485,7 +500,10 @@ getevent() /* get next event */ getkey(levptr(XKeyPressedEvent)); break; case ButtonPress: - getmove(levptr(XButtonPressedEvent)); + if (FRAMESTATE(levptr(XButtonPressedEvent)->state)) + getframe(levptr(XButtonPressedEvent)); + else + getmove(levptr(XButtonPressedEvent)); break; } } @@ -501,53 +519,72 @@ register FVECT wp[2]; static -draw_grids() /* draw holodeck section grids */ +draw_grids(fore) /* draw holodeck section grids */ +int fore; { - static BYTE gridrgba[4] = {0x0, 0xff, 0xff, 0x00}; - - if (!mapped) - return; - glColor4ub(gridrgba[0], gridrgba[1], gridrgba[2], gridrgba[3]); + if (fore) + glColor4ub(0, 255, 255, 0); + else + glColor4ub(0, 0, 0, 0); glBegin(GL_LINES); /* draw each grid line */ gridlines(draw3dline); glEnd(); + checkglerr("drawing grid lines"); } +static double +getdistance(dx, dy, direc) /* distance from fore plane along view ray */ +int dx, dy; +FVECT direc; +{ + GLfloat gldepth; + double dist; + if (dx<0 | dx>=odev.hres | dy<0 | dy>=odev.vres) + return(FHUGE); + glReadPixels(dx,dy, 1,1, GL_DEPTH_COMPONENT,GL_FLOAT, &gldepth); + dist = mapdepth(gldepth); + if (dist >= .99*FHUGE) + return(FHUGE); + return((dist-odev.v.vfore)/DOT(direc,odev.v.vdir)); +} + + static moveview(dx, dy, mov, orb) /* move our view */ int dx, dy, mov, orb; { VIEW nv; FVECT odir, v1, wip; - double d; + double d,d1; register int li; /* start with old view */ - copystruct(&nv, &odev.v); - /* change view direction */ + nv = odev.v; + /* orient our motion */ if (viewray(v1, odir, &odev.v, (dx+.5)/odev.hres, (dy+.5)/odev.vres) < -FTINY) return(0); /* outside view */ - if (mov | orb) { + if (mov | orb) { /* moving relative to geometry */ + d = getdistance(dx, dy, odir);/*distance from front plane */ #ifdef DOBJ - d = dobj_trace(NULL, v1, odir); /* check objects */ - /* is holodeck in front? */ - if ((li = smFindSamp(v1, odir)) >= 0 && - (rsL.wp[li][0] - nv.vp[0])*odir[0] + - (rsL.wp[li][1] - nv.vp[1])*odir[1] + - (rsL.wp[li][2] - nv.vp[2])*odir[2] < d) - VCOPY(wip, rsL.wp[li]); - else if (d < .99*FHUGE) /* object is closer */ - VSUM(wip, nv.vp, odir, d); - else /* nothing visible */ - return(0); -#else - if ((li = smFindSamp(v1, odir)) < 0) - return(0); /* not on window */ - VCOPY(wip, rsL.wp[li]); + d1 = dobj_trace(NULL, v1, odir); /* check objects */ + /* check holodeck */ + if (d1 < d) + d = d1; #endif - VSUM(odir, wip, nv.vp, -1.); - } else + if (d >= .99*FHUGE) + d = 0.5*(dev_zmax+dev_zmin); /* just guess */ + VSUM(wip, v1, odir, d); + VSUB(odir, wip, odev.v.vp); +#if 0 + fprintf(stderr, "moveview: hit %s at (%f,%f,%f) (t=%f)\n", + li < 0 ? "object" : "mesh", + wip[0], wip[1], wip[2], + (wip[0]-odev.v.vp[0])*odir[0] + + (wip[1]-odev.v.vp[1])*odir[1] + + (wip[2]-odev.v.vp[2])*odir[2]); +#endif + } else /* panning with constant viewpoint */ VCOPY(nv.vdir, odir); if (orb && mov) { /* orbit left/right */ spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov); @@ -566,7 +603,7 @@ int dx, dy, mov, orb; } if (!mov ^ !orb && headlocked) { /* restore head height */ VSUM(v1, odev.v.vp, nv.vp, -1.); - d = DOT(v1, odev.v.vup); + d = DOT(v1, nv.vup); VSUM(nv.vp, nv.vp, odev.v.vup, d); } if (setview(&nv) != NULL) @@ -578,65 +615,95 @@ int dx, dy, mov, orb; static +getframe(ebut) /* get focus frame */ +XButtonPressedEvent *ebut; +{ + int startx = ebut->x, starty = ebut->y; + int endx, endy; + + XMaskEvent(ourdisplay, ButtonReleaseMask, levptr(XEvent)); + endx = levptr(XButtonReleasedEvent)->x; + endy = levptr(XButtonReleasedEvent)->y; + if (endx == startx | endy == starty) { + XBell(ourdisplay, 0); + return; + } + if (endx < startx) {register int c = endx; endx = startx; startx = c;} + if (endy < starty) {register int c = endy; endy = starty; starty = c;} + sprintf(odev_args, "%.3f %.3f %.3f %.3f", + (startx+.5)/odev.hres, 1.-(endy+.5)/odev.vres, + (endx+.5)/odev.hres, 1.-(starty+.5)/odev.vres); + inpresflags |= DFL(DC_FOCUS); +} + + +static getmove(ebut) /* get view change */ XButtonPressedEvent *ebut; { int movdir = MOVDIR(ebut->button); int movorb = MOVORB(ebut->state); - int qlevel = 99; + int qlevel = MAXQUALITY-1; time_t lasttime, thistime; int nframes; Window rootw, childw; int rootx, rooty, wx, wy; unsigned int statemask; - XNoOp(ourdisplay); + XNoOp(ourdisplay); /* makes sure we're not idle */ - lasttime = time(0); nframes = 0; + nframes = 0; while (!XCheckMaskEvent(ourdisplay, ButtonReleaseMask, levptr(XEvent))) { - + /* get cursor position */ if (!XQueryPointer(ourdisplay, gwind, &rootw, &childw, &rootx, &rooty, &wx, &wy, &statemask)) break; /* on another screen */ + draw_grids(0); /* clear old grid lines */ +#ifdef STEREO + pushright(); draw_grids(0); popright(); +#endif + /* compute view motion */ if (!moveview(wx, odev.vres-1-wy, movdir, movorb)) { sleep(1); lasttime++; - continue; + continue; /* cursor in bad place */ } + draw_grids(1); /* redraw grid */ #ifdef STEREO pushright(); - glClear(GL_COLOR_BUFFER_BIT); - draw_grids(); + draw_grids(1); smUpdate(&vwright, qlevel); #ifdef DOBJ dobj_render(); #endif popright(); #endif - glClear(GL_COLOR_BUFFER_BIT); - draw_grids(); + /* redraw mesh */ smUpdate(&odev.v, qlevel); #ifdef DOBJ - dobj_render(); + dobj_render(); /* redraw object */ #endif glFlush(); - checkglerr("moving view"); - nframes++; + /* figure out good quality level */ + if (!nframes++) { /* ignore first frame */ + lasttime = time(0); + continue; + } thistime = time(0); - if (thistime - lasttime >= 3 || + if (thistime - lasttime >= 6 || nframes > (int)(3*3*TARGETFPS)) { - qlevel = thistime<=lasttime ? 1000 : + qlevel = thistime<=lasttime ? 3*MAXQUALITY : (int)((double)nframes/(thistime-lasttime) / TARGETFPS * qlevel + 0.5); - lasttime = thistime; nframes = 0; - if (qlevel > 99) { - if (qlevel > 300) { /* put on the brakes */ + nframes = 0; + if (qlevel >= MAXQUALITY) { + if (qlevel >= 3*MAXQUALITY) { /* brakes!! */ sleep(1); lasttime++; } - qlevel = 99; + qlevel = MAXQUALITY-1; } else if (qlevel < 1) qlevel = 1; } @@ -657,20 +724,18 @@ register VIEW *vp; double d, xmin, xmax, ymin, ymax; if (mindpth >= maxdpth) { - dev_zmin = 0.1; + dev_zmin = 1.; dev_zmax = 100.; } else { - dev_zmin = 0.5*mindpth; - dev_zmax = 1.5*maxdpth; - if (dev_zmin > dev_zmax/100.) - dev_zmin = dev_zmax/100.; + dev_zmin = 0.1*mindpth; + dev_zmax = 5.0*maxdpth; } if (odev.v.vfore > FTINY) dev_zmin = odev.v.vfore; if (odev.v.vaft > FTINY) dev_zmax = odev.v.vaft; - if (dev_zmin < dev_zmax/5000.) - dev_zmin = dev_zmax/5000.; + if (dev_zmin*500. < dev_zmax) + dev_zmax = dev_zmin*500.; xmax = dev_zmin * tan(PI/180./2. * odev.v.horiz); xmin = -xmax; d = odev.v.hoff * (xmax - xmin); @@ -688,19 +753,23 @@ register VIEW *vp; odev.v.vp[1] + odev.v.vdir[1], odev.v.vp[2] + odev.v.vdir[2], odev.v.vup[0], odev.v.vup[1], odev.v.vup[2]); + checkglerr("setting perspective view"); } static -wipeclean() /* prepare for redraw */ +wipeclean(tmflag) /* prepare for redraw */ +int tmflag; { + /* clear depth buffer */ #ifdef STEREO setstereobuf(STEREO_BUFFER_RIGHT); glClear(GL_DEPTH_BUFFER_BIT); setstereobuf(STEREO_BUFFER_LEFT); #endif glClear(GL_DEPTH_BUFFER_BIT); - smClean(); + smClean(tmflag); /* reset drawing routines */ + setglpersp(&odev.v); /* reset view & clipping planes */ } @@ -708,6 +777,9 @@ static getkey(ekey) /* get input key */ register XKeyPressedEvent *ekey; { + Window rootw, childw; + int rootx, rooty, wx, wy; + unsigned int statemask; int n; char buf[8]; @@ -730,23 +802,36 @@ register XKeyPressedEvent *ekey; case 'v': /* spit out view */ inpresflags |= DFL(DC_GETVIEW); return; + case 'f': /* frame view position */ + if (!XQueryPointer(ourdisplay, gwind, &rootw, &childw, + &rootx, &rooty, &wx, &wy, &statemask)) + return; /* on another screen */ + sprintf(odev_args, "%.4f %.4f", (wx+.5)/odev.hres, + 1.-(wy+.5)/odev.vres); + inpresflags |= DFL(DC_FOCUS); + return; + case 'F': /* unfocus */ + odev_args[0] = '\0'; + inpresflags |= DFL(DC_FOCUS); + return; case '\n': case '\r': /* resume computation */ inpresflags |= DFL(DC_RESUME); return; case CTRL('R'): /* redraw screen */ - wipeclean(); + wipeclean(1); return; case CTRL('L'): /* refresh from server */ if (inpresflags & DFL(DC_REDRAW)) return; + setglpersp(&odev.v); /* reset clipping planes */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glDisable(GL_DEPTH_TEST); - draw_grids(); + glDisable(GL_DEPTH_TEST); /* so grids will clear */ + draw_grids(1); #ifdef STEREO pushright(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - draw_grids(); + draw_grids(1); popright(); #endif glEnable(GL_DEPTH_TEST); @@ -784,7 +869,7 @@ register XExposeEvent *eexp; } if (eexp->count) /* wait for final exposure */ return; - wipeclean(); /* clear depth */ + wipeclean(0); /* clear depth */ }