| 1 | gregl | 3.1 | /* Copyright (c) 1997 Silicon Graphics, Inc. */ | 
| 2 |  |  |  | 
| 3 |  |  | #ifndef lint | 
| 4 |  |  | static char SCCSid[] = "$SunId$ SGI"; | 
| 5 |  |  | #endif | 
| 6 |  |  |  | 
| 7 |  |  | /* | 
| 8 |  |  | * OpenGL GLX driver for holodeck display. | 
| 9 | gregl | 3.2 | * Based on x11 driver. | 
| 10 | gregl | 3.1 | */ | 
| 11 |  |  |  | 
| 12 |  |  | #include "standard.h" | 
| 13 |  |  | #include "tonemap.h" | 
| 14 |  |  | #include "rhdriver.h" | 
| 15 |  |  |  | 
| 16 |  |  | #include  <GL/glx.h> | 
| 17 |  |  |  | 
| 18 |  |  | #include  "x11icon.h" | 
| 19 |  |  |  | 
| 20 |  |  | #ifndef FEQ | 
| 21 |  |  | #define FEQ(a,b)        ((a)-(b) <= FTINY && (a)-(b) >= -FTINY) | 
| 22 |  |  | #endif | 
| 23 |  |  |  | 
| 24 |  |  | #ifndef int4 | 
| 25 |  |  | #define int4    int | 
| 26 |  |  | #endif | 
| 27 |  |  |  | 
| 28 |  |  | #ifndef FREEPCT | 
| 29 | gregl | 3.2 | #define FREEPCT         10              /* percentage of values to free */ | 
| 30 | gregl | 3.1 | #endif | 
| 31 |  |  |  | 
| 32 |  |  | #ifndef NCONEV | 
| 33 |  |  | #define NCONEV          7               /* number of cone base vertices */ | 
| 34 |  |  | #endif | 
| 35 |  |  | #ifndef CONEH | 
| 36 | gregl | 3.3 | #define CONEH           3.              /* cone height (fraction of depth) */ | 
| 37 | gregl | 3.1 | #endif | 
| 38 |  |  | #ifndef CONEW | 
| 39 | gregl | 3.3 | #define CONEW           0.05            /* cone width (fraction of screen) */ | 
| 40 | gregl | 3.1 | #endif | 
| 41 | gregl | 3.2 | #ifndef DIRPEN | 
| 42 |  |  | #define DIRPEN          0.001           /* direction penalty factor */ | 
| 43 |  |  | #endif | 
| 44 | gregl | 3.3 | #ifndef VALUA | 
| 45 |  |  | #define VALUA           16              /* target value area (pixels) */ | 
| 46 |  |  | #endif | 
| 47 | gregl | 3.1 |  | 
| 48 | gregl | 3.2 | #define GAMMA           1.4             /* default gamma correction */ | 
| 49 | gregl | 3.1 |  | 
| 50 |  |  | #define MOVPCT          7               /* percent distance to move /frame */ | 
| 51 |  |  | #define MOVDIR(b)       ((b)==Button1 ? 1 : (b)==Button2 ? 0 : -1) | 
| 52 |  |  | #define MOVDEG          (-5)            /* degrees to orbit CW/down /frame */ | 
| 53 |  |  | #define MOVORB(s)       ((s)&ShiftMask ? 1 : (s)&ControlMask ? -1 : 0) | 
| 54 |  |  |  | 
| 55 |  |  | #define MINWIDTH        480             /* minimum graphics window width */ | 
| 56 |  |  | #define MINHEIGHT       400             /* minimum graphics window height */ | 
| 57 |  |  |  | 
| 58 |  |  | #define VIEWDIST        356             /* assumed viewing distance (mm) */ | 
| 59 |  |  |  | 
| 60 |  |  | #define BORWIDTH        5               /* border width */ | 
| 61 |  |  |  | 
| 62 |  |  | #define  ourscreen      DefaultScreen(ourdisplay) | 
| 63 |  |  | #define  ourroot        RootWindow(ourdisplay,ourscreen) | 
| 64 |  |  | #define  ourmask        (StructureNotifyMask|ExposureMask|KeyPressMask|\ | 
| 65 |  |  | ButtonPressMask|ButtonReleaseMask) | 
| 66 |  |  |  | 
| 67 |  |  | #define  levptr(etype)  ((etype *)¤tevent) | 
| 68 |  |  |  | 
| 69 |  |  | struct driver   odev;                   /* global device driver structure */ | 
| 70 |  |  |  | 
| 71 |  |  | static XEvent  currentevent;            /* current event */ | 
| 72 |  |  |  | 
| 73 |  |  | static int  mapped = 0;                 /* window is mapped? */ | 
| 74 |  |  | static unsigned long  ourblack=0, ourwhite=~0; | 
| 75 |  |  |  | 
| 76 |  |  | static Display  *ourdisplay = NULL;     /* our display */ | 
| 77 |  |  | static XVisualInfo  *ourvinf;           /* our visual information */ | 
| 78 |  |  | static Window  gwind = 0;               /* our graphics window */ | 
| 79 |  |  | static GLXContext       gctx;           /* our GLX context */ | 
| 80 |  |  |  | 
| 81 |  |  | static double   mindepth = FHUGE;       /* minimum depth value so far */ | 
| 82 | gregl | 3.2 | static double   maxdepth = 0.;          /* maximum depth value so far */ | 
| 83 | gregl | 3.1 |  | 
| 84 |  |  | static double   pwidth, pheight;        /* pixel dimensions (mm) */ | 
| 85 |  |  |  | 
| 86 |  |  | static FVECT    conev[NCONEV];          /* drawing cone */ | 
| 87 |  |  | static double   coneh;                  /* cone height */ | 
| 88 |  |  |  | 
| 89 |  |  | static int      inpresflags;            /* input result flags */ | 
| 90 |  |  |  | 
| 91 |  |  | static int      headlocked = 0;         /* lock vertical motion */ | 
| 92 |  |  |  | 
| 93 | gregl | 3.3 | static int      quicken = 0;            /* quicker, sloppier update rate? */ | 
| 94 |  |  |  | 
| 95 | gregl | 3.1 | static struct { | 
| 96 |  |  | float           (*wp)[3];       /* world intersection point array */ | 
| 97 |  |  | int4            *wd;            /* world direction array */ | 
| 98 |  |  | TMbright        *brt;           /* encoded brightness array */ | 
| 99 |  |  | BYTE            (*chr)[3];      /* encoded chrominance array */ | 
| 100 |  |  | BYTE            (*rgb)[3];      /* tone-mapped color array */ | 
| 101 |  |  | BYTE            *alpha;         /* alpha values */ | 
| 102 |  |  | int             nl;             /* count of values */ | 
| 103 |  |  | int             bl, tl;         /* bottom and top (next) value index */ | 
| 104 |  |  | int             tml;            /* next value needing tone-mapping */ | 
| 105 |  |  | int             drl;            /* next value in need of drawing */ | 
| 106 |  |  | char            *base;          /* base of allocated memory */ | 
| 107 |  |  | }       rV;                     /* our collection of values */ | 
| 108 |  |  |  | 
| 109 | gregl | 3.2 | static int      *valmap = NULL;         /* sorted map of screen values */ | 
| 110 |  |  | static int      vmaplen = 0;            /* value map length */ | 
| 111 |  |  |  | 
| 112 | gregl | 3.1 | #define redraw()        (rV.drl = rV.bl) | 
| 113 |  |  |  | 
| 114 |  |  | static int  resizewindow(), getevent(), getkey(), moveview(), | 
| 115 |  |  | setGLview(), getmove(), fixwindow(), mytmflags(), | 
| 116 | gregl | 3.2 | drawvalue(), valcmp(), clralphas(), setalphas(), mergalphas(), | 
| 117 |  |  | IndexValue(), Compost(), FindValue(), TMapValues(), | 
| 118 |  |  | AllocValues(), FreeValues(); | 
| 119 | gregl | 3.1 |  | 
| 120 | gregl | 3.2 | extern int4     encodedir(); | 
| 121 |  |  | extern double   fdir2diff(), dir2diff(); | 
| 122 | gregl | 3.1 |  | 
| 123 | gregl | 3.2 |  | 
| 124 | gregl | 3.1 | dev_open(id)                    /* initialize X11 driver */ | 
| 125 |  |  | char  *id; | 
| 126 |  |  | { | 
| 127 |  |  | extern char     *getenv(); | 
| 128 |  |  | static int      atlBest[] = {GLX_RGBA, GLX_RED_SIZE,8, | 
| 129 |  |  | GLX_GREEN_SIZE,8, GLX_BLUE_SIZE,8, | 
| 130 | gregl | 3.2 | GLX_ALPHA_SIZE,8, GLX_DEPTH_SIZE,15, | 
| 131 |  |  | None}; | 
| 132 | gregl | 3.1 | char    *gv; | 
| 133 |  |  | double  gamval = GAMMA; | 
| 134 |  |  | XSetWindowAttributes    ourwinattr; | 
| 135 |  |  | XWMHints        ourxwmhints; | 
| 136 |  |  | XSizeHints      oursizhints; | 
| 137 |  |  | /* open display server */ | 
| 138 |  |  | ourdisplay = XOpenDisplay(NULL); | 
| 139 |  |  | if (ourdisplay == NULL) | 
| 140 |  |  | error(USER, "cannot open X-windows; DISPLAY variable set?\n"); | 
| 141 |  |  | /* find a usable visual */ | 
| 142 |  |  | ourvinf = glXChooseVisual(ourdisplay, ourscreen, atlBest); | 
| 143 |  |  | if (ourvinf == NULL) | 
| 144 |  |  | error(USER, "no suitable visuals available"); | 
| 145 |  |  | /* get a context */ | 
| 146 |  |  | gctx = glXCreateContext(ourdisplay, ourvinf, NULL, GL_TRUE); | 
| 147 |  |  | /* set gamma and tone mapping */ | 
| 148 |  |  | if ((gv = XGetDefault(ourdisplay, "radiance", "gamma")) != NULL | 
| 149 |  |  | || (gv = getenv("DISPLAY_GAMMA")) != NULL) | 
| 150 |  |  | gamval = atof(gv); | 
| 151 |  |  | if (tmInit(mytmflags(), stdprims, gamval) == NULL) | 
| 152 |  |  | error(SYSTEM, "not enough memory in dev_open"); | 
| 153 |  |  | /* open window */ | 
| 154 |  |  | ourwinattr.background_pixel = ourblack; | 
| 155 |  |  | ourwinattr.border_pixel = ourblack; | 
| 156 |  |  | ourwinattr.event_mask = ourmask; | 
| 157 |  |  | /* this is stupid */ | 
| 158 |  |  | ourwinattr.colormap = XCreateColormap(ourdisplay, ourroot, | 
| 159 |  |  | ourvinf->visual, AllocNone); | 
| 160 |  |  | gwind = XCreateWindow(ourdisplay, ourroot, 0, 0, | 
| 161 |  |  | DisplayWidth(ourdisplay,ourscreen)-2*BORWIDTH, | 
| 162 |  |  | DisplayHeight(ourdisplay,ourscreen)-2*BORWIDTH, | 
| 163 |  |  | BORWIDTH, ourvinf->depth, InputOutput, ourvinf->visual, | 
| 164 |  |  | CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &ourwinattr); | 
| 165 |  |  | if (gwind == 0) | 
| 166 |  |  | error(SYSTEM, "cannot create window\n"); | 
| 167 |  |  | XStoreName(ourdisplay, gwind, id); | 
| 168 |  |  | /* set window manager hints */ | 
| 169 |  |  | ourxwmhints.flags = InputHint|IconPixmapHint; | 
| 170 |  |  | ourxwmhints.input = True; | 
| 171 |  |  | ourxwmhints.icon_pixmap = XCreateBitmapFromData(ourdisplay, | 
| 172 |  |  | gwind, x11icon_bits, x11icon_width, x11icon_height); | 
| 173 |  |  | XSetWMHints(ourdisplay, gwind, &ourxwmhints); | 
| 174 |  |  | oursizhints.min_width = MINWIDTH; | 
| 175 |  |  | oursizhints.min_height = MINHEIGHT; | 
| 176 |  |  | oursizhints.flags = PMinSize; | 
| 177 |  |  | XSetNormalHints(ourdisplay, gwind, &oursizhints); | 
| 178 | gregl | 3.2 | /* set GLX context */ | 
| 179 |  |  | glXMakeCurrent(ourdisplay, gwind, gctx); | 
| 180 |  |  | glEnable(GL_DEPTH_TEST); | 
| 181 |  |  | glDepthFunc(GL_LEQUAL); | 
| 182 |  |  | glShadeModel(GL_FLAT); | 
| 183 |  |  | glDisable(GL_DITHER); | 
| 184 | gregl | 3.1 | /* figure out sensible view */ | 
| 185 |  |  | pwidth = (double)DisplayWidthMM(ourdisplay, ourscreen) / | 
| 186 |  |  | DisplayWidth(ourdisplay, ourscreen); | 
| 187 |  |  | pheight = (double)DisplayHeightMM(ourdisplay, ourscreen) / | 
| 188 |  |  | DisplayHeight(ourdisplay, ourscreen); | 
| 189 |  |  | copystruct(&odev.v, &stdview); | 
| 190 |  |  | odev.v.type = VT_PER; | 
| 191 | gregl | 3.2 | /* map the window */ | 
| 192 |  |  | XMapWindow(ourdisplay, gwind); | 
| 193 |  |  | dev_input();                    /* sets size and view angles */ | 
| 194 |  |  | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | 
| 195 |  |  | /* allocate our value list */ | 
| 196 |  |  | if (!AllocValues(DisplayWidth(ourdisplay,ourscreen) * | 
| 197 | gregl | 3.3 | DisplayHeight(ourdisplay,ourscreen) / VALUA)) | 
| 198 | gregl | 3.2 | error(SYSTEM, "insufficient memory for value storage"); | 
| 199 | gregl | 3.1 | odev.name = id; | 
| 200 |  |  | odev.ifd = ConnectionNumber(ourdisplay); | 
| 201 |  |  | } | 
| 202 |  |  |  | 
| 203 |  |  |  | 
| 204 |  |  | dev_close()                     /* close our display and free resources */ | 
| 205 |  |  | { | 
| 206 |  |  | glXMakeCurrent(ourdisplay, None, NULL); | 
| 207 |  |  | glXDestroyContext(ourdisplay, gctx); | 
| 208 |  |  | XDestroyWindow(ourdisplay, gwind); | 
| 209 |  |  | gwind = 0; | 
| 210 |  |  | XCloseDisplay(ourdisplay); | 
| 211 |  |  | ourdisplay = NULL; | 
| 212 |  |  | tmDone(NULL); | 
| 213 |  |  | FreeValues(); | 
| 214 |  |  | odev.v.type = 0; | 
| 215 |  |  | odev.hres = odev.vres = 0; | 
| 216 |  |  | odev.ifd = -1; | 
| 217 |  |  | } | 
| 218 |  |  |  | 
| 219 |  |  |  | 
| 220 |  |  | int | 
| 221 |  |  | dev_view(nv)                    /* assign new driver view */ | 
| 222 |  |  | register VIEW   *nv; | 
| 223 |  |  | { | 
| 224 |  |  | if (nv->type != VT_PER ||               /* check view legality */ | 
| 225 |  |  | nv->horiz > 120. || nv->vert > 120.) { | 
| 226 |  |  | error(COMMAND, "illegal view type/angle"); | 
| 227 |  |  | nv->type = VT_PER; | 
| 228 |  |  | nv->horiz = odev.v.horiz; | 
| 229 |  |  | nv->vert = odev.v.vert; | 
| 230 |  |  | return(0); | 
| 231 |  |  | } | 
| 232 |  |  | if (nv != &odev.v) { | 
| 233 |  |  | if (!FEQ(nv->horiz,odev.v.horiz) ||     /* resize window? */ | 
| 234 |  |  | !FEQ(nv->vert,odev.v.vert)) { | 
| 235 |  |  | int     dw = DisplayWidth(ourdisplay,ourscreen); | 
| 236 |  |  | int     dh = DisplayHeight(ourdisplay,ourscreen); | 
| 237 |  |  |  | 
| 238 |  |  | dw -= 25;       /* for window frame */ | 
| 239 |  |  | dh -= 50; | 
| 240 |  |  | odev.hres = 2.*VIEWDIST/pwidth * | 
| 241 |  |  | tan(PI/180./2.*nv->horiz); | 
| 242 |  |  | odev.vres = 2.*VIEWDIST/pheight * | 
| 243 |  |  | tan(PI/180./2.*nv->vert); | 
| 244 |  |  | if (odev.hres > dw) { | 
| 245 |  |  | odev.vres = dw * odev.vres / odev.hres; | 
| 246 |  |  | odev.hres = dw; | 
| 247 |  |  | } | 
| 248 |  |  | if (odev.vres > dh) { | 
| 249 |  |  | odev.hres = dh * odev.hres / odev.vres; | 
| 250 |  |  | odev.vres = dh; | 
| 251 |  |  | } | 
| 252 |  |  | XResizeWindow(ourdisplay, gwind, odev.hres, odev.vres); | 
| 253 | gregl | 3.2 | dev_input();    /* get resize event */ | 
| 254 | gregl | 3.1 | } | 
| 255 |  |  | copystruct(&odev.v, nv); | 
| 256 |  |  | setGLview(); | 
| 257 | gregl | 3.2 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | 
| 258 |  |  | redraw(); | 
| 259 | gregl | 3.1 | } | 
| 260 |  |  | return(1); | 
| 261 |  |  | } | 
| 262 |  |  |  | 
| 263 |  |  |  | 
| 264 |  |  | int | 
| 265 |  |  | dev_input()                     /* get X11 input */ | 
| 266 |  |  | { | 
| 267 |  |  | inpresflags = 0; | 
| 268 |  |  |  | 
| 269 |  |  | do | 
| 270 |  |  | getevent(); | 
| 271 |  |  |  | 
| 272 |  |  | while (XQLength(ourdisplay) > 0); | 
| 273 |  |  |  | 
| 274 |  |  | return(inpresflags); | 
| 275 |  |  | } | 
| 276 |  |  |  | 
| 277 |  |  |  | 
| 278 |  |  | dev_value(c, p, v)              /* add a pixel value to our list */ | 
| 279 |  |  | COLR    c; | 
| 280 |  |  | FVECT   p, v; | 
| 281 |  |  | { | 
| 282 |  |  | register int    li; | 
| 283 |  |  |  | 
| 284 | gregl | 3.2 | li = rV.tl++; | 
| 285 |  |  | if (rV.tl >= rV.nl)     /* get next leaf in ring */ | 
| 286 |  |  | rV.tl = 0; | 
| 287 |  |  | if (rV.tl == rV.bl)     /* need to shake some free */ | 
| 288 |  |  | Compost(FREEPCT); | 
| 289 | gregl | 3.1 | VCOPY(rV.wp[li], p); | 
| 290 |  |  | rV.wd[li] = encodedir(v); | 
| 291 |  |  | tmCvColrs(&rV.brt[li], rV.chr[li], c, 1); | 
| 292 |  |  | } | 
| 293 |  |  |  | 
| 294 |  |  |  | 
| 295 |  |  | int | 
| 296 |  |  | dev_flush()                     /* flush output */ | 
| 297 |  |  | { | 
| 298 |  |  | if (mapped) { | 
| 299 |  |  | TMapValues(0); | 
| 300 |  |  | while (rV.drl != rV.tl) { | 
| 301 |  |  | drawvalue(rV.drl); | 
| 302 |  |  | if (++rV.drl >= rV.nl) | 
| 303 |  |  | rV.drl = 0; | 
| 304 |  |  | } | 
| 305 |  |  | glFlush(); | 
| 306 |  |  | } | 
| 307 |  |  | return(XPending(ourdisplay)); | 
| 308 |  |  | } | 
| 309 |  |  |  | 
| 310 |  |  |  | 
| 311 |  |  | static int | 
| 312 |  |  | mytmflags()                     /* figure out tone mapping flags */ | 
| 313 |  |  | { | 
| 314 |  |  | extern char     *progname; | 
| 315 |  |  | register char   *cp, *tail; | 
| 316 |  |  | /* find basic name */ | 
| 317 |  |  | for (cp = tail = progname; *cp; cp++) | 
| 318 |  |  | if (*cp == '/') | 
| 319 |  |  | tail = cp+1; | 
| 320 |  |  | for (cp = tail; *cp && *cp != '.'; cp++) | 
| 321 |  |  | ; | 
| 322 |  |  | if (cp-tail == 3 && !strncmp(tail, "glx", 3)) | 
| 323 |  |  | return(TM_F_CAMERA); | 
| 324 |  |  | if (cp-tail == 4 && !strncmp(tail, "glxh", 4)) | 
| 325 |  |  | return(TM_F_HUMAN); | 
| 326 |  |  | error(USER, "illegal driver name"); | 
| 327 |  |  | } | 
| 328 |  |  |  | 
| 329 |  |  |  | 
| 330 |  |  | static | 
| 331 |  |  | setGLview()                     /* set our GL view */ | 
| 332 |  |  | { | 
| 333 |  |  | double  xmin, xmax, ymin, ymax, zmin, zmax; | 
| 334 |  |  | double  d, cx, sx, crad; | 
| 335 |  |  | FVECT   vx, vy; | 
| 336 |  |  | register int    i, j; | 
| 337 |  |  | /* compute view frustum */ | 
| 338 |  |  | if (normalize(odev.v.vdir) == 0.0) | 
| 339 |  |  | return; | 
| 340 |  |  | if (mindepth < maxdepth) { | 
| 341 |  |  | zmin = 0.25*mindepth; | 
| 342 | gregl | 3.2 | zmax = 4.0*(1.+CONEH)*maxdepth; | 
| 343 | gregl | 3.1 | } else { | 
| 344 |  |  | zmin = 0.01; | 
| 345 |  |  | zmax = 1000.; | 
| 346 |  |  | } | 
| 347 |  |  | if (odev.v.vfore > FTINY) | 
| 348 |  |  | zmin = odev.v.vfore; | 
| 349 |  |  | if (odev.v.vaft > FTINY) | 
| 350 |  |  | zmax = odev.v.vaft; | 
| 351 |  |  | xmax = zmin * tan(PI/180./2. * odev.v.horiz); | 
| 352 |  |  | xmin = -xmax; | 
| 353 |  |  | d = odev.v.hoff * (xmax - xmin); | 
| 354 |  |  | xmin += d; xmax += d; | 
| 355 |  |  | ymax = zmin * tan(PI/180./2. * odev.v.vert); | 
| 356 |  |  | ymin = -ymax; | 
| 357 |  |  | d = odev.v.voff * (ymax - ymin); | 
| 358 |  |  | ymin += d; ymax += d; | 
| 359 |  |  | /* set view matrix */ | 
| 360 |  |  | glMatrixMode(GL_PROJECTION); | 
| 361 |  |  | glLoadIdentity(); | 
| 362 |  |  | glFrustum(xmin, xmax, ymin, ymax, zmin, zmax); | 
| 363 |  |  | gluLookAt(odev.v.vp[0], odev.v.vp[1], odev.v.vp[2], | 
| 364 |  |  | odev.v.vp[0] + odev.v.vdir[0], | 
| 365 |  |  | odev.v.vp[1] + odev.v.vdir[1], | 
| 366 |  |  | odev.v.vp[2] + odev.v.vdir[2], | 
| 367 |  |  | odev.v.vup[0], odev.v.vup[1], odev.v.vup[2]); | 
| 368 |  |  | /* set viewport */ | 
| 369 |  |  | glViewport(0, 0, odev.hres, odev.vres); | 
| 370 |  |  | /* initialize cone for Vornoi polys */ | 
| 371 |  |  | coneh = CONEH*(zmax - zmin); | 
| 372 |  |  | crad = 0.5 * CONEW * 0.5*(xmax-xmin + ymax-ymin) * (zmin+coneh)/zmin; | 
| 373 |  |  | vy[0] = vy[1] = vy[2] = 0.; | 
| 374 |  |  | for (i = 0; i < 3; i++) | 
| 375 |  |  | if (odev.v.vdir[i] < 0.6 && odev.v.vdir[i] > -0.6) | 
| 376 |  |  | break; | 
| 377 |  |  | vy[i] = 1.; | 
| 378 |  |  | fcross(vx, vy, odev.v.vdir); | 
| 379 |  |  | normalize(vx); | 
| 380 |  |  | fcross(vy, odev.v.vdir, vx); | 
| 381 |  |  | for (j = 0, d = 0.; j < NCONEV; j++, d += 2.*PI/NCONEV) { | 
| 382 |  |  | cx = crad*cos(d); sx = crad*sin(d); | 
| 383 |  |  | for (i = 0; i < 3; i++) | 
| 384 |  |  | conev[j][i] = coneh*odev.v.vdir[i] + | 
| 385 |  |  | cx*vx[i] + sx*vy[i]; | 
| 386 |  |  | } | 
| 387 |  |  | } | 
| 388 |  |  |  | 
| 389 |  |  |  | 
| 390 | gregl | 3.3 | #define SUCCSTEP        8       /* skip step when successful */ | 
| 391 |  |  | #define MAXSTEP         64 | 
| 392 |  |  |  | 
| 393 | gregl | 3.1 | static | 
| 394 |  |  | drawvalue(li)                   /* draw a pixel value as a cone */ | 
| 395 |  |  | register int    li; | 
| 396 |  |  | { | 
| 397 | gregl | 3.3 | static int      skipstep = 1; | 
| 398 | gregl | 3.2 | static FVECT    disp; | 
| 399 |  |  | FVECT   apex; | 
| 400 |  |  | double  d, dorg, dnew, h, v; | 
| 401 | gregl | 3.1 | register int    i; | 
| 402 | gregl | 3.3 | /* check for quicker update */ | 
| 403 |  |  | if (quicken) { | 
| 404 |  |  | if (li % skipstep) | 
| 405 |  |  | return; | 
| 406 |  |  | if (skipstep < MAXSTEP) | 
| 407 |  |  | skipstep++; | 
| 408 |  |  | } | 
| 409 | gregl | 3.2 | /* compute cone coordinates */ | 
| 410 |  |  | disp[0] = rV.wp[li][0] - odev.v.vp[0]; | 
| 411 |  |  | disp[1] = rV.wp[li][1] - odev.v.vp[1]; | 
| 412 |  |  | disp[2] = rV.wp[li][2] - odev.v.vp[2]; | 
| 413 |  |  | dorg = DOT(disp,odev.v.vdir); | 
| 414 |  |  | if (dorg <= odev.v.vfore) | 
| 415 |  |  | return;         /* clipped too near */ | 
| 416 |  |  | if (odev.v.vaft > FTINY && dorg > odev.v.vaft) | 
| 417 |  |  | return;         /* clipped too far */ | 
| 418 |  |  | if (dorg > 1e5) {       /* background pixel */ | 
| 419 |  |  | dnew = maxdepth; | 
| 420 |  |  | d = dnew/dorg; | 
| 421 | gregl | 3.3 | dorg = maxdepth; | 
| 422 | gregl | 3.2 | } else {                /* foreground pixel, compute penalty */ | 
| 423 |  |  | normalize(disp); | 
| 424 |  |  | d = dnew = dorg + coneh*fdir2diff(rV.wd[li],disp)*DIRPEN; | 
| 425 |  |  | } | 
| 426 |  |  | /* compute adjusted apex position */ | 
| 427 |  |  | disp[0] *= d; disp[1] *= d; disp[2] *= d; | 
| 428 |  |  | apex[0] = odev.v.vp[0] + disp[0]; | 
| 429 |  |  | apex[1] = odev.v.vp[1] + disp[1]; | 
| 430 |  |  | apex[2] = odev.v.vp[2] + disp[2]; | 
| 431 |  |  | /* compute view position and base offset */ | 
| 432 |  |  | h = DOT(disp,odev.v.hvec)/(dnew*odev.v.hn2); | 
| 433 |  |  | v = DOT(disp,odev.v.vvec)/(dnew*odev.v.vn2); | 
| 434 |  |  | if (fabs(h - odev.v.hoff) > 0.5 || fabs(v - odev.v.voff) > 0.5) | 
| 435 |  |  | return;         /* clipped off screen */ | 
| 436 |  |  | if (dorg < mindepth) | 
| 437 |  |  | mindepth = dorg; | 
| 438 |  |  | if (dorg > maxdepth) | 
| 439 |  |  | maxdepth = dorg; | 
| 440 | gregl | 3.1 | for (i = 0; i < 3; i++) | 
| 441 |  |  | disp[i] = apex[i] + coneh*(h*odev.v.hvec[i] + v*odev.v.vvec[i]); | 
| 442 | gregl | 3.2 | /* draw cone (pyramid approx.) */ | 
| 443 | gregl | 3.1 | glColor4ub(rV.rgb[li][0], rV.rgb[li][1], rV.rgb[li][2], rV.alpha[li]); | 
| 444 |  |  | glBegin(GL_TRIANGLE_FAN); | 
| 445 |  |  | glVertex3f(apex[0], apex[1], apex[2]); | 
| 446 |  |  | for (i = 0; i < NCONEV; i++) | 
| 447 |  |  | glVertex3d(conev[i][0] + disp[0], conev[i][1] + disp[1], | 
| 448 |  |  | conev[i][2] + disp[2]); | 
| 449 | gregl | 3.2 | /* connect last face to first */ | 
| 450 | gregl | 3.1 | glVertex3d(conev[0][0] + disp[0], conev[0][1] + disp[1], | 
| 451 |  |  | conev[0][2] + disp[2]); | 
| 452 | gregl | 3.2 | glEnd();                /* done */ | 
| 453 | gregl | 3.3 | skipstep = SUCCSTEP; | 
| 454 | gregl | 3.1 | } | 
| 455 |  |  |  | 
| 456 | gregl | 3.3 | #undef SUCCSTEP | 
| 457 |  |  | #undef MAXSTEP | 
| 458 | gregl | 3.1 |  | 
| 459 | gregl | 3.3 |  | 
| 460 | gregl | 3.1 | #define LEAFSIZ         (3*sizeof(float)+sizeof(int4)+\ | 
| 461 |  |  | sizeof(TMbright)+7*sizeof(BYTE)) | 
| 462 |  |  |  | 
| 463 |  |  | static | 
| 464 |  |  | AllocValues(n)                  /* allocate space for n values */ | 
| 465 |  |  | register int    n; | 
| 466 |  |  | { | 
| 467 |  |  | unsigned        nbytes; | 
| 468 |  |  | register unsigned       i; | 
| 469 |  |  |  | 
| 470 |  |  | if (n <= 0) | 
| 471 |  |  | return(0); | 
| 472 |  |  | if (rV.nl >= n) | 
| 473 |  |  | return(rV.nl); | 
| 474 |  |  | else if (rV.nl > 0) | 
| 475 |  |  | free(rV.base); | 
| 476 |  |  | /* round space up to nearest power of 2 */ | 
| 477 |  |  | nbytes = n*LEAFSIZ + 8; | 
| 478 |  |  | for (i = 1024; nbytes > i; i <<= 1) | 
| 479 |  |  | ; | 
| 480 |  |  | n = (i - 8) / LEAFSIZ;  /* should we make sure n is even? */ | 
| 481 |  |  | rV.base = (char *)malloc(n*LEAFSIZ); | 
| 482 |  |  | if (rV.base == NULL) | 
| 483 |  |  | return(0); | 
| 484 |  |  | /* assign larger alignment types earlier */ | 
| 485 |  |  | rV.wp = (float (*)[3])rV.base; | 
| 486 |  |  | rV.wd = (int4 *)(rV.wp + n); | 
| 487 |  |  | rV.brt = (TMbright *)(rV.wd + n); | 
| 488 |  |  | rV.chr = (BYTE (*)[3])(rV.brt + n); | 
| 489 |  |  | rV.rgb = (BYTE (*)[3])(rV.chr + n); | 
| 490 |  |  | rV.alpha = (BYTE *)(rV.rgb + n); | 
| 491 |  |  | rV.nl = n; | 
| 492 |  |  | rV.drl = rV.tml = rV.bl = rV.tl = 0; | 
| 493 |  |  | return(n); | 
| 494 |  |  | } | 
| 495 |  |  |  | 
| 496 |  |  | #undef  LEAFSIZ | 
| 497 |  |  |  | 
| 498 |  |  |  | 
| 499 |  |  | static | 
| 500 |  |  | FreeValues()                    /* free our allocated values */ | 
| 501 |  |  | { | 
| 502 |  |  | if (rV.nl <= 0) | 
| 503 |  |  | return; | 
| 504 |  |  | free(rV.base); | 
| 505 |  |  | rV.base = NULL; | 
| 506 |  |  | rV.nl = 0; | 
| 507 |  |  | } | 
| 508 |  |  |  | 
| 509 |  |  |  | 
| 510 |  |  | static | 
| 511 | gregl | 3.2 | clralphas()                     /* prepare for new alpha values */ | 
| 512 |  |  | { | 
| 513 |  |  | if (!vmaplen) | 
| 514 |  |  | return; | 
| 515 |  |  | free((char *)valmap); | 
| 516 |  |  | valmap = NULL; | 
| 517 |  |  | vmaplen = 0; | 
| 518 |  |  | } | 
| 519 |  |  |  | 
| 520 |  |  |  | 
| 521 |  |  | static int | 
| 522 |  |  | valcmp(v1p, v2p)                /* compare two pixel values */ | 
| 523 |  |  | int     *v1p, *v2p; | 
| 524 |  |  | { | 
| 525 |  |  | register int    v1 = *v1p, v2 = *v2p; | 
| 526 |  |  | register int    c; | 
| 527 |  |  |  | 
| 528 |  |  | if ((c = rV.rgb[v1][0] - rV.rgb[v2][0])) return(c); | 
| 529 |  |  | if ((c = rV.rgb[v1][1] - rV.rgb[v2][1])) return(c); | 
| 530 |  |  | if ((c = rV.rgb[v1][2] - rV.rgb[v2][2])) return(c); | 
| 531 |  |  | return(rV.alpha[v1] - rV.alpha[v2]); | 
| 532 |  |  | } | 
| 533 |  |  |  | 
| 534 |  |  |  | 
| 535 |  |  | static | 
| 536 |  |  | mergalphas(adest, al1, n1, al2, n2)     /* merge two sorted alpha lists */ | 
| 537 |  |  | register int    *adest, *al1, *al2; | 
| 538 |  |  | int     n1, n2; | 
| 539 |  |  | { | 
| 540 |  |  | register int    cmp; | 
| 541 |  |  |  | 
| 542 |  |  | while (n1 | n2) { | 
| 543 |  |  | if (!n1) cmp = 1; | 
| 544 |  |  | else if (!n2) cmp = -1; | 
| 545 |  |  | else cmp = valcmp(al1, al2); | 
| 546 |  |  | if (cmp > 0) { | 
| 547 |  |  | *adest++ = *al2++; | 
| 548 |  |  | n2--; | 
| 549 |  |  | } else { | 
| 550 |  |  | *adest++ = *al1++; | 
| 551 |  |  | n1--; | 
| 552 |  |  | } | 
| 553 |  |  | } | 
| 554 |  |  | } | 
| 555 |  |  |  | 
| 556 |  |  |  | 
| 557 |  |  | static | 
| 558 |  |  | setalphas(vbeg, nvals)          /* add values to our map and set alphas */ | 
| 559 |  |  | int     vbeg, nvals; | 
| 560 |  |  | { | 
| 561 |  |  | register int    *newmap; | 
| 562 |  |  | short   ccmp[3], lastalpha; | 
| 563 |  |  | int     newmaplen; | 
| 564 |  |  |  | 
| 565 |  |  | if (nvals <= 0) | 
| 566 |  |  | return; | 
| 567 |  |  | newmaplen = vmaplen + nvals;    /* allocate new map */ | 
| 568 |  |  | newmap = (int *)malloc(newmaplen*sizeof(int)); | 
| 569 |  |  | if (newmap == NULL) | 
| 570 |  |  | error(SYSTEM, "out of memory in setalphas"); | 
| 571 |  |  | while (nvals--) {               /* add new values to end */ | 
| 572 |  |  | rV.alpha[vbeg] = 255; | 
| 573 |  |  | newmap[vmaplen+nvals] = vbeg++; | 
| 574 |  |  | } | 
| 575 |  |  | if (nvals >= 3*vmaplen) {       /* resort the combined array */ | 
| 576 |  |  | while (vmaplen--) | 
| 577 |  |  | newmap[vmaplen] = valmap[vmaplen]; | 
| 578 |  |  | qsort((char *)newmap, newmaplen, sizeof(int), valcmp); | 
| 579 |  |  | } else {                        /* perform merge sort */ | 
| 580 |  |  | qsort((char *)(newmap+vmaplen), newmaplen-vmaplen, | 
| 581 |  |  | sizeof(int), valcmp); | 
| 582 |  |  | mergalphas(newmap, valmap, vmaplen, | 
| 583 |  |  | newmap+vmaplen, newmaplen-vmaplen); | 
| 584 |  |  | } | 
| 585 |  |  | if (valmap != NULL)             /* free old map and assign new one */ | 
| 586 |  |  | free((char *)valmap); | 
| 587 |  |  | valmap = newmap; | 
| 588 |  |  | vmaplen = newmaplen; | 
| 589 |  |  | lastalpha = 0;                  /* set new alpha values */ | 
| 590 |  |  | ccmp[0] = ccmp[1] = ccmp[2] = 256; | 
| 591 |  |  | while (newmaplen--) | 
| 592 |  |  | if (rV.rgb[*newmap][0] == ccmp[0] && | 
| 593 |  |  | rV.rgb[*newmap][1] == ccmp[1] && | 
| 594 |  |  | rV.rgb[*newmap][2] == ccmp[2]) { | 
| 595 |  |  | if (lastalpha >= 255) | 
| 596 |  |  | newmap++; | 
| 597 |  |  | else if (rV.alpha[*newmap] < 255) | 
| 598 |  |  | lastalpha = rV.alpha[*newmap++]; | 
| 599 |  |  | else | 
| 600 |  |  | rV.alpha[*newmap++] = ++lastalpha; | 
| 601 |  |  | } else { | 
| 602 |  |  | ccmp[0] = rV.rgb[*newmap][0]; | 
| 603 |  |  | ccmp[1] = rV.rgb[*newmap][1]; | 
| 604 |  |  | ccmp[2] = rV.rgb[*newmap][2]; | 
| 605 |  |  | if (rV.alpha[*newmap] < 255) | 
| 606 |  |  | lastalpha = rV.alpha[*newmap++]; | 
| 607 |  |  | else | 
| 608 |  |  | rV.alpha[*newmap++] = lastalpha = 1; | 
| 609 |  |  | } | 
| 610 |  |  | } | 
| 611 |  |  |  | 
| 612 |  |  |  | 
| 613 |  |  | static | 
| 614 | gregl | 3.1 | TMapValues(redo)                /* map our values to RGB */ | 
| 615 |  |  | int     redo; | 
| 616 |  |  | { | 
| 617 |  |  | int     aorg, alen, borg, blen; | 
| 618 |  |  | /* recompute mapping? */ | 
| 619 |  |  | if (redo) | 
| 620 |  |  | rV.tml = rV.bl; | 
| 621 |  |  | /* already done? */ | 
| 622 |  |  | if (rV.tml == rV.tl) | 
| 623 |  |  | return(1); | 
| 624 |  |  | /* compute segments */ | 
| 625 |  |  | aorg = rV.tml; | 
| 626 |  |  | if (rV.tl >= aorg) { | 
| 627 |  |  | alen = rV.tl - aorg; | 
| 628 |  |  | blen = 0; | 
| 629 |  |  | } else { | 
| 630 |  |  | alen = rV.nl - aorg; | 
| 631 |  |  | borg = 0; | 
| 632 |  |  | blen = rV.tl; | 
| 633 |  |  | } | 
| 634 |  |  | /* (re)compute tone mapping? */ | 
| 635 |  |  | if (rV.tml == rV.bl) { | 
| 636 |  |  | tmClearHisto(); | 
| 637 |  |  | tmAddHisto(rV.brt+aorg, alen, 1); | 
| 638 |  |  | if (blen > 0) | 
| 639 |  |  | tmAddHisto(rV.brt+borg, blen, 1); | 
| 640 |  |  | if (tmComputeMapping(0., 0., 0.) != TM_E_OK) | 
| 641 |  |  | return(0); | 
| 642 | gregl | 3.2 | clralphas();            /* restart value list */ | 
| 643 |  |  | rV.drl = rV.bl;         /* need to redraw */ | 
| 644 | gregl | 3.1 | } | 
| 645 |  |  | if (tmMapPixels(rV.rgb+aorg, rV.brt+aorg, | 
| 646 |  |  | rV.chr+aorg, alen) != TM_E_OK) | 
| 647 |  |  | return(0); | 
| 648 |  |  | if (blen > 0) | 
| 649 |  |  | tmMapPixels(rV.rgb+borg, rV.brt+borg, | 
| 650 |  |  | rV.chr+borg, blen); | 
| 651 | gregl | 3.2 | setalphas(aorg, alen);          /* compute add'l alpha values */ | 
| 652 |  |  | if (blen > 0) | 
| 653 |  |  | setalphas(borg, blen); | 
| 654 |  |  | rV.tml = rV.tl;                 /* we're all up to date */ | 
| 655 | gregl | 3.1 | return(1); | 
| 656 |  |  | } | 
| 657 |  |  |  | 
| 658 |  |  |  | 
| 659 |  |  | static int | 
| 660 |  |  | Compost(pct)                    /* free up some values */ | 
| 661 |  |  | int     pct; | 
| 662 |  |  | { | 
| 663 |  |  | int     nused, nclear, nmapped, ndrawn; | 
| 664 |  |  | /* figure out how many values to clear */ | 
| 665 |  |  | nclear = rV.nl * pct / 100; | 
| 666 |  |  | nused = rV.tl - rV.bl; | 
| 667 |  |  | if (nused <= 0) nused += rV.nl; | 
| 668 |  |  | nclear -= rV.nl - nused; | 
| 669 |  |  | if (nclear <= 0) | 
| 670 |  |  | return(0); | 
| 671 | gregl | 3.2 | if (nclear >= nused) {  /* clear them all? */ | 
| 672 | gregl | 3.1 | rV.drl = rV.tml = rV.bl = rV.tl = 0; | 
| 673 |  |  | return(nused); | 
| 674 |  |  | } | 
| 675 |  |  | /* else clear values from bottom */ | 
| 676 |  |  | ndrawn = rV.drl - rV.bl; | 
| 677 |  |  | if (ndrawn < 0) ndrawn += rV.nl; | 
| 678 |  |  | nmapped = rV.tml - rV.bl; | 
| 679 |  |  | if (nmapped < 0) nmapped += rV.nl; | 
| 680 |  |  | rV.bl += nclear; | 
| 681 |  |  | if (rV.bl >= rV.nl) rV.bl -= rV.nl; | 
| 682 |  |  | if (ndrawn < nclear) rV.drl = rV.bl; | 
| 683 |  |  | if (nmapped < nclear) rV.tml = rV.bl; | 
| 684 |  |  | return(nclear); | 
| 685 |  |  | } | 
| 686 |  |  |  | 
| 687 |  |  |  | 
| 688 |  |  | static | 
| 689 |  |  | getevent()                      /* get next event */ | 
| 690 |  |  | { | 
| 691 |  |  | XNextEvent(ourdisplay, levptr(XEvent)); | 
| 692 |  |  | switch (levptr(XEvent)->type) { | 
| 693 |  |  | case ConfigureNotify: | 
| 694 |  |  | resizewindow(levptr(XConfigureEvent)); | 
| 695 |  |  | break; | 
| 696 |  |  | case UnmapNotify: | 
| 697 |  |  | mapped = 0; | 
| 698 |  |  | break; | 
| 699 |  |  | case MapNotify: | 
| 700 |  |  | mapped = 1; | 
| 701 |  |  | break; | 
| 702 |  |  | case Expose: | 
| 703 |  |  | fixwindow(levptr(XExposeEvent)); | 
| 704 |  |  | break; | 
| 705 |  |  | case KeyPress: | 
| 706 |  |  | getkey(levptr(XKeyPressedEvent)); | 
| 707 |  |  | break; | 
| 708 |  |  | case ButtonPress: | 
| 709 |  |  | getmove(levptr(XButtonPressedEvent)); | 
| 710 |  |  | break; | 
| 711 |  |  | } | 
| 712 |  |  | } | 
| 713 |  |  |  | 
| 714 |  |  |  | 
| 715 |  |  | static | 
| 716 |  |  | draw3dline(wp)                  /* draw 3d line in world coordinates */ | 
| 717 |  |  | register FVECT  wp[2]; | 
| 718 |  |  | { | 
| 719 |  |  | glVertex3d(wp[0][0], wp[0][1], wp[0][2]); | 
| 720 |  |  | glVertex3d(wp[1][0], wp[1][1], wp[1][2]); | 
| 721 |  |  | } | 
| 722 |  |  |  | 
| 723 |  |  |  | 
| 724 |  |  | static | 
| 725 |  |  | draw_grids()                    /* draw holodeck section grids */ | 
| 726 |  |  | { | 
| 727 | gregl | 3.2 | static BYTE     gridrgba[4] = {0x0, 0xff, 0xff, 0x00}; | 
| 728 | gregl | 3.1 |  | 
| 729 |  |  | if (!mapped) | 
| 730 |  |  | return; | 
| 731 |  |  | glColor4ub(gridrgba[0], gridrgba[1], gridrgba[2], gridrgba[3]); | 
| 732 |  |  | /* draw each grid line */ | 
| 733 |  |  | glBegin(GL_LINES); | 
| 734 |  |  | gridlines(draw3dline); | 
| 735 |  |  | glEnd(); | 
| 736 |  |  | } | 
| 737 |  |  |  | 
| 738 |  |  |  | 
| 739 |  |  | static int | 
| 740 | gregl | 3.2 | IndexValue(rgba)                /* locate a pixel by it's framebuffer value */ | 
| 741 |  |  | register BYTE   rgba[4]; | 
| 742 |  |  | { | 
| 743 |  |  | register int    *vp; | 
| 744 |  |  | /* check legality */ | 
| 745 |  |  | if (rgba[3] == 0 || rgba[3] == 255) | 
| 746 |  |  | return(-1); | 
| 747 |  |  | /* borrow a value slot */ | 
| 748 |  |  | rV.rgb[rV.tl][0] = rgba[0]; | 
| 749 |  |  | rV.rgb[rV.tl][1] = rgba[1]; | 
| 750 |  |  | rV.rgb[rV.tl][2] = rgba[2]; | 
| 751 |  |  | rV.alpha[rV.tl] = rgba[3]; | 
| 752 |  |  | /* find it */ | 
| 753 |  |  | vp = (int *)bsearch((char *)&rV.tl, (char *)valmap, vmaplen, | 
| 754 |  |  | sizeof(int), valcmp); | 
| 755 |  |  | if (vp == NULL) | 
| 756 |  |  | return(-1); | 
| 757 |  |  | return(*vp); | 
| 758 |  |  | } | 
| 759 |  |  |  | 
| 760 |  |  |  | 
| 761 |  |  | static int | 
| 762 | gregl | 3.1 | FindValue(dx, dy)               /* find a value on the display */ | 
| 763 |  |  | int     dx, dy; | 
| 764 |  |  | { | 
| 765 | gregl | 3.2 | BYTE    rgba[4]; | 
| 766 |  |  |  | 
| 767 |  |  | if (dx < 0 || dy < 0 || dx >= odev.hres || dy >= odev.vres) | 
| 768 |  |  | return(-1); | 
| 769 |  |  | glReadPixels(dx, dy, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, rgba); | 
| 770 |  |  | return(IndexValue(rgba)); | 
| 771 | gregl | 3.1 | } | 
| 772 |  |  |  | 
| 773 |  |  |  | 
| 774 |  |  | static | 
| 775 |  |  | moveview(dx, dy, mov, orb)      /* move our view */ | 
| 776 |  |  | int     dx, dy, mov, orb; | 
| 777 |  |  | { | 
| 778 |  |  | VIEW    nv; | 
| 779 |  |  | FVECT   odir, v1; | 
| 780 |  |  | double  d; | 
| 781 |  |  | register int    li; | 
| 782 |  |  | /* start with old view */ | 
| 783 |  |  | copystruct(&nv, &odev.v); | 
| 784 |  |  | /* change view direction */ | 
| 785 |  |  | if (mov | orb) { | 
| 786 |  |  | if ((li = FindValue(dx, dy)) < 0) | 
| 787 |  |  | return(0);      /* not on window */ | 
| 788 |  |  | VSUM(odir, rV.wp[li], nv.vp, -1.); | 
| 789 |  |  | } else { | 
| 790 |  |  | if (viewray(nv.vp, nv.vdir, &odev.v, | 
| 791 |  |  | (dx+.5)/odev.hres, (dy+.5)/odev.vres) < -FTINY) | 
| 792 |  |  | return(0);      /* outside view */ | 
| 793 |  |  | } | 
| 794 |  |  | if (orb && mov) {               /* orbit left/right */ | 
| 795 |  |  | spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov); | 
| 796 |  |  | VSUM(nv.vp, rV.wp[li], odir, -1.); | 
| 797 |  |  | spinvector(nv.vdir, nv.vdir, nv.vup, d); | 
| 798 |  |  | } else if (orb) {               /* orbit up/down */ | 
| 799 |  |  | fcross(v1, odir, nv.vup); | 
| 800 |  |  | if (normalize(v1) == 0.) | 
| 801 |  |  | return(0); | 
| 802 |  |  | spinvector(odir, odir, v1, d=MOVDEG*PI/180.*orb); | 
| 803 |  |  | VSUM(nv.vp, rV.wp[li], odir, -1.); | 
| 804 |  |  | spinvector(nv.vdir, nv.vdir, v1, d); | 
| 805 |  |  | } else if (mov) {               /* move forward/backward */ | 
| 806 |  |  | d = MOVPCT/100. * mov; | 
| 807 |  |  | VSUM(nv.vp, nv.vp, odir, d); | 
| 808 |  |  | } | 
| 809 |  |  | if (!mov ^ !orb && headlocked) {        /* restore head height */ | 
| 810 |  |  | VSUM(v1, odev.v.vp, nv.vp, -1.); | 
| 811 |  |  | d = DOT(v1, odev.v.vup); | 
| 812 |  |  | VSUM(nv.vp, nv.vp, odev.v.vup, d); | 
| 813 |  |  | } | 
| 814 |  |  | if (setview(&nv) != NULL) | 
| 815 |  |  | return(0);      /* illegal view */ | 
| 816 |  |  | dev_view(&nv); | 
| 817 |  |  | inpresflags |= DFL(DC_SETVIEW); | 
| 818 |  |  | return(1); | 
| 819 |  |  | } | 
| 820 |  |  |  | 
| 821 |  |  |  | 
| 822 |  |  | static | 
| 823 |  |  | getmove(ebut)                           /* get view change */ | 
| 824 |  |  | XButtonPressedEvent     *ebut; | 
| 825 |  |  | { | 
| 826 |  |  | int     movdir = MOVDIR(ebut->button); | 
| 827 |  |  | int     movorb = MOVORB(ebut->state); | 
| 828 |  |  | Window  rootw, childw; | 
| 829 |  |  | int     rootx, rooty, wx, wy; | 
| 830 |  |  | unsigned int    statemask; | 
| 831 |  |  |  | 
| 832 | gregl | 3.3 | quicken = 1;                    /* accelerate update rate */ | 
| 833 | gregl | 3.1 | XNoOp(ourdisplay); | 
| 834 |  |  |  | 
| 835 |  |  | while (!XCheckMaskEvent(ourdisplay, | 
| 836 |  |  | ButtonReleaseMask, levptr(XEvent))) { | 
| 837 |  |  |  | 
| 838 |  |  | if (!XQueryPointer(ourdisplay, gwind, &rootw, &childw, | 
| 839 |  |  | &rootx, &rooty, &wx, &wy, &statemask)) | 
| 840 |  |  | break;          /* on another screen */ | 
| 841 |  |  |  | 
| 842 |  |  | if (!moveview(wx, odev.vres-1-wy, movdir, movorb)) { | 
| 843 |  |  | sleep(1); | 
| 844 |  |  | continue; | 
| 845 |  |  | } | 
| 846 |  |  | draw_grids(); | 
| 847 |  |  | dev_flush(); | 
| 848 |  |  | } | 
| 849 |  |  | if (!(inpresflags & DFL(DC_SETVIEW))) { /* do final motion */ | 
| 850 |  |  | movdir = MOVDIR(levptr(XButtonReleasedEvent)->button); | 
| 851 |  |  | wx = levptr(XButtonReleasedEvent)->x; | 
| 852 |  |  | wy = levptr(XButtonReleasedEvent)->y; | 
| 853 |  |  | moveview(wx, odev.vres-1-wy, movdir, movorb); | 
| 854 | gregl | 3.2 | } else { | 
| 855 |  |  | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | 
| 856 |  |  | redraw(); | 
| 857 | gregl | 3.1 | } | 
| 858 | gregl | 3.3 | quicken = 0; | 
| 859 | gregl | 3.1 | dev_flush(); | 
| 860 |  |  | } | 
| 861 |  |  |  | 
| 862 |  |  |  | 
| 863 |  |  | static | 
| 864 |  |  | getkey(ekey)                            /* get input key */ | 
| 865 |  |  | register XKeyPressedEvent  *ekey; | 
| 866 |  |  | { | 
| 867 |  |  | int  n; | 
| 868 |  |  | char    buf[8]; | 
| 869 |  |  |  | 
| 870 |  |  | n = XLookupString(ekey, buf, sizeof(buf), NULL, NULL); | 
| 871 |  |  | if (n != 1) | 
| 872 |  |  | return; | 
| 873 |  |  | switch (buf[0]) { | 
| 874 |  |  | case 'h':                       /* turn on height motion lock */ | 
| 875 |  |  | headlocked = 1; | 
| 876 |  |  | return; | 
| 877 |  |  | case 'H':                       /* turn off height motion lock */ | 
| 878 |  |  | headlocked = 0; | 
| 879 |  |  | return; | 
| 880 |  |  | case 'l':                       /* retrieve last view */ | 
| 881 |  |  | inpresflags |= DFL(DC_LASTVIEW); | 
| 882 |  |  | return; | 
| 883 |  |  | case 'p':                       /* pause computation */ | 
| 884 |  |  | inpresflags |= DFL(DC_PAUSE); | 
| 885 |  |  | return; | 
| 886 |  |  | case 'v':                       /* spit out view */ | 
| 887 |  |  | inpresflags |= DFL(DC_GETVIEW); | 
| 888 |  |  | return; | 
| 889 |  |  | case '\n': | 
| 890 |  |  | case '\r':                      /* resume computation */ | 
| 891 |  |  | inpresflags |= DFL(DC_RESUME); | 
| 892 |  |  | return; | 
| 893 |  |  | case CTRL('R'):                 /* redraw screen */ | 
| 894 |  |  | TMapValues(1); | 
| 895 | gregl | 3.2 | glClear(GL_DEPTH_BUFFER_BIT); | 
| 896 | gregl | 3.1 | redraw(); | 
| 897 |  |  | return; | 
| 898 |  |  | case CTRL('L'):                 /* refresh from server */ | 
| 899 |  |  | if (inpresflags & DFL(DC_REDRAW)) | 
| 900 |  |  | return; | 
| 901 |  |  | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | 
| 902 |  |  | glDisable(GL_DEPTH_TEST); | 
| 903 |  |  | draw_grids(); | 
| 904 |  |  | glEnable(GL_DEPTH_TEST); | 
| 905 |  |  | glFlush(); | 
| 906 |  |  | Compost(100);                   /* get rid of old values */ | 
| 907 |  |  | inpresflags |= DFL(DC_REDRAW);  /* resend values from server */ | 
| 908 |  |  | return; | 
| 909 |  |  | case 'K':                       /* kill rtrace process(es) */ | 
| 910 |  |  | inpresflags |= DFL(DC_KILL); | 
| 911 |  |  | break; | 
| 912 |  |  | case 'R':                       /* restart rtrace */ | 
| 913 |  |  | inpresflags |= DFL(DC_RESTART); | 
| 914 |  |  | break; | 
| 915 |  |  | case 'C':                       /* clobber holodeck */ | 
| 916 |  |  | inpresflags |= DFL(DC_CLOBBER); | 
| 917 |  |  | break; | 
| 918 |  |  | case 'q':                       /* quit the program */ | 
| 919 |  |  | inpresflags |= DFL(DC_QUIT); | 
| 920 |  |  | return; | 
| 921 |  |  | default: | 
| 922 |  |  | XBell(ourdisplay, 0); | 
| 923 |  |  | return; | 
| 924 |  |  | } | 
| 925 |  |  | } | 
| 926 |  |  |  | 
| 927 |  |  |  | 
| 928 |  |  | static | 
| 929 |  |  | fixwindow(eexp)                         /* repair damage to window */ | 
| 930 |  |  | register XExposeEvent  *eexp; | 
| 931 |  |  | { | 
| 932 | gregl | 3.2 | if (odev.hres == 0 || odev.vres == 0)   /* first exposure */ | 
| 933 |  |  | resizewindow((XConfigureEvent *)eexp); | 
| 934 | gregl | 3.1 | if (eexp->width == odev.hres && eexp->height == odev.vres) | 
| 935 |  |  | TMapValues(1); | 
| 936 | gregl | 3.2 | if (!eexp->count) { | 
| 937 |  |  | glClear(GL_DEPTH_BUFFER_BIT); | 
| 938 | gregl | 3.1 | redraw(); | 
| 939 | gregl | 3.2 | } | 
| 940 | gregl | 3.1 | } | 
| 941 |  |  |  | 
| 942 |  |  |  | 
| 943 |  |  | static | 
| 944 |  |  | resizewindow(ersz)                      /* resize window */ | 
| 945 |  |  | register XConfigureEvent  *ersz; | 
| 946 |  |  | { | 
| 947 |  |  | if (ersz->width == odev.hres && ersz->height == odev.vres) | 
| 948 |  |  | return; | 
| 949 |  |  |  | 
| 950 |  |  | odev.hres = ersz->width; | 
| 951 |  |  | odev.vres = ersz->height; | 
| 952 |  |  |  | 
| 953 |  |  | odev.v.horiz = 2.*180./PI * atan(0.5/VIEWDIST*pwidth*odev.hres); | 
| 954 |  |  | odev.v.vert = 2.*180./PI * atan(0.5/VIEWDIST*pheight*odev.vres); | 
| 955 |  |  |  | 
| 956 |  |  | setGLview(); | 
| 957 |  |  |  | 
| 958 |  |  | inpresflags |= DFL(DC_SETVIEW); | 
| 959 |  |  | } |