| 1 | #ifndef lint | 
| 2 | static const char       RCSid[] = "$Id$"; | 
| 3 | #endif | 
| 4 | /* | 
| 5 | * Routines for drawing samples using depth buffer checks. | 
| 6 | */ | 
| 7 |  | 
| 8 | #include "standard.h" | 
| 9 |  | 
| 10 | #include <GL/glx.h> | 
| 11 | #include <GL/glu.h> | 
| 12 |  | 
| 13 | #include "rhd_odraw.h" | 
| 14 |  | 
| 15 | #ifndef DEPTHEPS | 
| 16 | #define DEPTHEPS        0.02            /* depth epsilon */ | 
| 17 | #endif | 
| 18 | #ifndef SAMPSPERBLOCK | 
| 19 | #define SAMPSPERBLOCK   1024            /* target samples per image block */ | 
| 20 | #endif | 
| 21 | #ifndef SFREEFRAC | 
| 22 | #define SFREEFRAC       0.2             /* fraction to free at a time */ | 
| 23 | #endif | 
| 24 | #ifndef REDRAWTHRESH | 
| 25 | #define REDRAWTHRESH    10240           /* number of samples for dissolve */ | 
| 26 | #endif | 
| 27 | #ifndef MAXFAN | 
| 28 | #define MAXFAN          32              /* maximum arms in a triangle fan */ | 
| 29 | #endif | 
| 30 | #ifndef MINFAN | 
| 31 | #define MINFAN          4               /* minimum arms in a triangle fan */ | 
| 32 | #endif | 
| 33 | #ifndef FANSIZE | 
| 34 | #define FANSIZE         3.5             /* fan sizing factor */ | 
| 35 | #endif | 
| 36 |  | 
| 37 | #define NEWMAP          01              /* need to recompute mapping */ | 
| 38 | #define NEWRGB          02              /* need to remap RGB values */ | 
| 39 | #define NEWHIST         04              /* clear histogram as well */ | 
| 40 |  | 
| 41 | struct ODview   *odView;        /* our view list */ | 
| 42 | int     odNViews;               /* number of views in our list */ | 
| 43 |  | 
| 44 | struct ODsamp   odS;            /* sample values */ | 
| 45 |  | 
| 46 | static int      needmapping;    /* what needs doing with tone map */ | 
| 47 |  | 
| 48 |  | 
| 49 | #define SAMP32  (32*(2*sizeof(short)+sizeof(union ODfunion)+sizeof(TMbright)+\ | 
| 50 | 6*sizeof(BYTE))+sizeof(int4)) | 
| 51 |  | 
| 52 | int | 
| 53 | odInit(n)                               /* initialize drawing routines */ | 
| 54 | int     n; | 
| 55 | { | 
| 56 | int     nbytes, i, j, k, nextsamp, count, blockdiv; | 
| 57 | int     res[2]; | 
| 58 |  | 
| 59 | if (odNViews > 0) {             /* deallocate view structures */ | 
| 60 | for (i = odNViews; i--; ) { | 
| 61 | free((void *)odView[i].bmap); | 
| 62 | free((void *)odView[i].pmap); | 
| 63 | if (odView[i].emap != NULL) | 
| 64 | free((void *)odView[i].emap); | 
| 65 | } | 
| 66 | free((void *)odView); | 
| 67 | odView = NULL; | 
| 68 | odNViews = 0; | 
| 69 | } | 
| 70 | if (n && n != odS.nsamp) { | 
| 71 | /* round space up to nearest power of 2 */ | 
| 72 | nbytes = (n+31)/32 * SAMP32; | 
| 73 | for (i = 1024; nbytes > i-8; i <<= 1) | 
| 74 | ; | 
| 75 | n = (i-8)/SAMP32 * 32; | 
| 76 | needmapping = NEWHIST; | 
| 77 | } | 
| 78 | if (n != odS.nsamp) {   /* (re)allocate sample array */ | 
| 79 | if (odS.nsamp) | 
| 80 | free(odS.base); | 
| 81 | odS.nsamp = 0; | 
| 82 | if (!n) | 
| 83 | return(0); | 
| 84 | nbytes = (n+31)/32 * SAMP32; | 
| 85 | odS.base = (char *)malloc(nbytes); | 
| 86 | if (odS.base == NULL) | 
| 87 | return(0); | 
| 88 | /* assign larger alignment types earlier */ | 
| 89 | odS.f = (union ODfunion *)odS.base; | 
| 90 | odS.redraw = (int4 *)(odS.f + n); | 
| 91 | odS.ip = (short (*)[2])(odS.redraw + n/32); | 
| 92 | odS.brt = (TMbright *)(odS.ip + n); | 
| 93 | odS.chr = (BYTE (*)[3])(odS.brt + n); | 
| 94 | odS.rgb = (BYTE (*)[3])(odS.chr + n); | 
| 95 | odS.nsamp = n; | 
| 96 | } | 
| 97 | if (!n) | 
| 98 | return(0); | 
| 99 | /* allocate view information */ | 
| 100 | count = 0;                      /* count pixels */ | 
| 101 | for (i = 0; dev_auxview(i, res) != NULL; i++) | 
| 102 | count += res[0]*res[1]; | 
| 103 | odView = (struct ODview *)malloc(i*sizeof(struct ODview)); | 
| 104 | if (odView == NULL) | 
| 105 | return(0); | 
| 106 | odNViews = i; | 
| 107 | blockdiv = sqrt(count/(n/SAMPSPERBLOCK)) + 0.5; | 
| 108 | if (blockdiv < 8) blockdiv = 8; | 
| 109 | nextsamp = 0; count /= blockdiv*blockdiv;       /* # blocks */ | 
| 110 | while (i--) {                   /* initialize each view */ | 
| 111 | dev_auxview(i, res); | 
| 112 | odView[i].hhi = res[0]; | 
| 113 | odView[i].hlow = (res[0] + blockdiv/2) / blockdiv; | 
| 114 | if (odView[i].hlow < 1) odView[i].hlow = 1; | 
| 115 | odView[i].vhi = res[1]; | 
| 116 | odView[i].vlow = (res[1] + blockdiv/2) / blockdiv; | 
| 117 | if (odView[i].vlow < 1) odView[i].vlow = 1; | 
| 118 | odView[i].emap = NULL; | 
| 119 | odView[i].dmap = NULL; | 
| 120 | odView[i].pmap = (int4 *)calloc(FL4NELS(res[0]*res[1]), | 
| 121 | sizeof(int4)); | 
| 122 | if (odView[i].pmap == NULL) | 
| 123 | return(0); | 
| 124 | j = odView[i].hlow*odView[i].vlow; | 
| 125 | odView[i].bmap = (struct ODblock *)malloc( | 
| 126 | j * sizeof(struct ODblock)); | 
| 127 | if (odView[i].bmap == NULL) | 
| 128 | return(0); | 
| 129 | DCHECK(count<=0 | nextsamp>=n, | 
| 130 | CONSISTENCY, "counter botch in odInit"); | 
| 131 | if (!i) count = j; | 
| 132 | odView[i].sfirst = nextsamp; | 
| 133 | while (j--) {           /* initialize blocks & free lists */ | 
| 134 | odView[i].bmap[j].pthresh = FHUGE; | 
| 135 | odView[i].bmap[j].first = k = nextsamp; | 
| 136 | nextsamp += odView[i].bmap[j].nsamp = | 
| 137 | (n - nextsamp)/count--; | 
| 138 | odView[i].bmap[j].free = k; | 
| 139 | while (++k < nextsamp) | 
| 140 | odS.nextfree(k-1) = k; | 
| 141 | odS.nextfree(k-1) = ENDFREE; | 
| 142 | odView[i].bmap[j].nused = 0; | 
| 143 | } | 
| 144 | odView[i].snext = nextsamp; | 
| 145 | odView[i].n2redraw = 0; | 
| 146 | } | 
| 147 | CLR4ALL(odS.redraw, odS.nsamp);         /* clear redraw flags */ | 
| 148 | for (i = odS.nsamp; i--; ) {            /* clear values */ | 
| 149 | odS.ip[i][0] = odS.ip[i][1] = -1; | 
| 150 | odS.brt[i] = TM_NOBRT; | 
| 151 | } | 
| 152 | needmapping |= NEWMAP;                  /* compute new map on update */ | 
| 153 | return(odS.nsamp);                      /* return number of samples */ | 
| 154 | } | 
| 155 |  | 
| 156 | #undef SAMP32 | 
| 157 |  | 
| 158 |  | 
| 159 | int | 
| 160 | sampcmp(s0, s1)                 /* sample order, descending proximity */ | 
| 161 | int     *s0, *s1; | 
| 162 | { | 
| 163 | register double diff = odS.closeness(*s1) - odS.closeness(*s0); | 
| 164 |  | 
| 165 | return (diff > FTINY ? 1 : diff < -FTINY ? -1 : 0); | 
| 166 | } | 
| 167 |  | 
| 168 |  | 
| 169 | int | 
| 170 | odAllocBlockSamp(vn, hh, vh, prox)      /* allocate sample from block */ | 
| 171 | int     vn, hh, vh; | 
| 172 | double  prox; | 
| 173 | { | 
| 174 | int     si[SAMPSPERBLOCK+SAMPSPERBLOCK/4]; | 
| 175 | int     hl, vl; | 
| 176 | VIEW    *vw; | 
| 177 | FVECT   ro, rd; | 
| 178 | int     res[2]; | 
| 179 | register struct ODblock *bp; | 
| 180 | register int    i, j; | 
| 181 | /* get block */ | 
| 182 | hl = hh*odView[vn].hlow/odView[vn].hhi; | 
| 183 | vl = vh*odView[vn].vlow/odView[vn].vhi; | 
| 184 | bp = odView[vn].bmap + vl*odView[vn].hlow + hl; | 
| 185 | if (prox > bp->pthresh) | 
| 186 | return(-1);             /* worse than free list occupants */ | 
| 187 | /* check for duplicate pixel */ | 
| 188 | if (CHK4(odView[vn].pmap, vh*odView[vn].hhi + hh)) | 
| 189 | i = bp->first + bp->nsamp; | 
| 190 | else | 
| 191 | i = 0; | 
| 192 | while (i-- > bp->first) | 
| 193 | if (hh == odS.ip[i][0] && vh == odS.ip[i][1]) { /* found it! */ | 
| 194 | /* search free list for it */ | 
| 195 | if (i == bp->free) | 
| 196 | break;          /* special case */ | 
| 197 | if (bp->free != ENDFREE) | 
| 198 | for (j = bp->free; odS.nextfree(j) != ENDFREE; | 
| 199 | j = odS.nextfree(j)) | 
| 200 | if (odS.nextfree(j) == i) { | 
| 201 | odS.nextfree(j) = | 
| 202 | odS.nextfree(i); | 
| 203 | bp->nused++; | 
| 204 | goto gotit; | 
| 205 | } | 
| 206 | if (prox >= 0.99*odS.closeness(i)) | 
| 207 | return(-1);     /* previous sample is fine */ | 
| 208 | goto gotit; | 
| 209 | } | 
| 210 | if (bp->free != ENDFREE) {      /* allocate from free list */ | 
| 211 | i = bp->free; | 
| 212 | if (odS.ip[i][0] >= 0 & odS.ip[i][1] >= 0) | 
| 213 | CLR4(odView[vn].pmap, odS.ip[i][1]*odView[vn].hhi + | 
| 214 | odS.ip[i][0]); | 
| 215 | bp->free = odS.nextfree(i); | 
| 216 | bp->nused++; | 
| 217 | goto gotit; | 
| 218 | } | 
| 219 | DCHECK(bp->nsamp<=0, CONSISTENCY, | 
| 220 | "no available samples in odAllocBlockSamp"); | 
| 221 | DCHECK(bp->nsamp > sizeof(si)/sizeof(si[0]), CONSISTENCY, | 
| 222 | "too many samples in odAllocBlockSamp"); | 
| 223 | /* free some samples */ | 
| 224 | if ((vw = dev_auxview(vn, res)) == NULL) | 
| 225 | error(CONSISTENCY, "bad view number in odAllocBlockSamp"); | 
| 226 | for (i = bp->nsamp; i--; )      /* figure out which are worse */ | 
| 227 | si[i] = bp->first + i; | 
| 228 | qsort((char *)si, bp->nsamp, sizeof(int), sampcmp); | 
| 229 | i = bp->nsamp*SFREEFRAC + .5;   /* put them into free list */ | 
| 230 | if (i >= bp->nsamp) i = bp->nsamp-1;    /* paranoia */ | 
| 231 | bp->pthresh = odS.closeness(si[i]);     /* new proximity threshold */ | 
| 232 | while (--i > 0) { | 
| 233 | odS.nextfree(si[i]) = bp->free; | 
| 234 | bp->free = si[i]; | 
| 235 | bp->nused--; | 
| 236 | } | 
| 237 | i = si[0];                      /* use worst sample */ | 
| 238 | CLR4(odView[vn].pmap, odS.ip[i][1]*odView[vn].hhi + odS.ip[i][0]); | 
| 239 | gotit: | 
| 240 | odS.ip[i][0] = hh; | 
| 241 | odS.ip[i][1] = vh; | 
| 242 | odS.closeness(i) = prox; | 
| 243 | SET4(odView[vn].pmap, vh*odView[vn].hhi + hh); | 
| 244 | return(i); | 
| 245 | } | 
| 246 |  | 
| 247 |  | 
| 248 | odSample(c, d, p)                       /* add a sample value */ | 
| 249 | COLR    c; | 
| 250 | FVECT   d, p; | 
| 251 | { | 
| 252 | FVECT   disp; | 
| 253 | double  d0, d1, h, v, prox; | 
| 254 | register VIEW   *vw; | 
| 255 | int     hh, vh; | 
| 256 | int     res[2]; | 
| 257 | register int    i, id; | 
| 258 |  | 
| 259 | DCHECK(odS.nsamp<=0, CONSISTENCY, "no samples allocated in odSample"); | 
| 260 | /* add value to each view */ | 
| 261 | for (i = 0; (vw = dev_auxview(i, res)) != NULL; i++) { | 
| 262 | DCHECK(i>=odNViews, CONSISTENCY, "too many views in odSample"); | 
| 263 | CHECK(vw->type!=VT_PER, INTERNAL, | 
| 264 | "cannot handle non-perspective views"); | 
| 265 | if (p != NULL) {                /* compute view position */ | 
| 266 | VSUB(disp, p, vw->vp); | 
| 267 | d0 = DOT(disp, vw->vdir); | 
| 268 | if (d0 <= vw->vfore+FTINY) | 
| 269 | continue;               /* too close */ | 
| 270 | } else { | 
| 271 | VCOPY(disp, d); | 
| 272 | d0 = DOT(disp, vw->vdir); | 
| 273 | if (d0 <= FTINY)                /* behind view */ | 
| 274 | continue; | 
| 275 | } | 
| 276 | h = DOT(disp,vw->hvec)/(d0*vw->hn2) + 0.5 - vw->hoff; | 
| 277 | if (h < 0. || h >= 1.) | 
| 278 | continue;                       /* left or right */ | 
| 279 | v = DOT(disp,vw->vvec)/(d0*vw->vn2) + 0.5 - vw->voff; | 
| 280 | if (v < 0. || v >= 1.) | 
| 281 | continue;                       /* above or below */ | 
| 282 | hh = h * res[0]; | 
| 283 | vh = v * res[1]; | 
| 284 | if (odView[i].dmap != NULL) {           /* check depth */ | 
| 285 | d1 = odView[i].dmap[vh*res[0] + hh]; | 
| 286 | if (d1 < 0.99*FHUGE && (d0 > (1.+DEPTHEPS)*d1 || | 
| 287 | (1.+DEPTHEPS)*d0 < d1)) | 
| 288 | continue;                       /* occlusion error */ | 
| 289 | } | 
| 290 | if (p != NULL) {                /* compute closeness (sin^2) */ | 
| 291 | d1 = DOT(disp, d); | 
| 292 | prox = 1. - d1*d1/DOT(disp,disp); | 
| 293 | } else | 
| 294 | prox = 0.; | 
| 295 | /* allocate sample */ | 
| 296 | id = odAllocBlockSamp(i, hh, vh, prox); | 
| 297 | if (id < 0) | 
| 298 | continue;               /* not good enough */ | 
| 299 | /* convert color */ | 
| 300 | tmCvColrs(&odS.brt[id], odS.chr[id], c, 1); | 
| 301 | if (imm_mode | needmapping)             /* if immediate mode */ | 
| 302 | needmapping |= NEWRGB;          /* map it later */ | 
| 303 | else                                    /* else map it now */ | 
| 304 | tmMapPixels(odS.rgb[id], &odS.brt[id], odS.chr[id], 1); | 
| 305 | SET4(odS.redraw, id);                   /* mark for redraw */ | 
| 306 | odView[i].n2redraw++; | 
| 307 | } | 
| 308 | } | 
| 309 |  | 
| 310 |  | 
| 311 | odRemap(newhist)                        /* recompute tone mapping */ | 
| 312 | int     newhist; | 
| 313 | { | 
| 314 | needmapping |= NEWMAP|NEWRGB; | 
| 315 | if (newhist) | 
| 316 | needmapping |= NEWHIST; | 
| 317 | } | 
| 318 |  | 
| 319 |  | 
| 320 | odRedrawAll()                           /* mark all samples for redraw */ | 
| 321 | { | 
| 322 | register int    i; | 
| 323 |  | 
| 324 | if ((needmapping&(NEWMAP|NEWRGB)) == (NEWMAP|NEWRGB)) | 
| 325 | return;                 /* will be called later, anyway */ | 
| 326 | for (i = odS.nsamp; i--; ) | 
| 327 | if (odS.ip[i][0] >= 0) | 
| 328 | SET4(odS.redraw, i); | 
| 329 | /* not right, but not important */ | 
| 330 | for (i = 0; i < odNViews; i++) | 
| 331 | odView[i].n2redraw = odView[i].snext - odView[i].sfirst; | 
| 332 | } | 
| 333 |  | 
| 334 |  | 
| 335 | odRedraw(vn, hmin, vmin, hmax, vmax)    /* redraw view region */ | 
| 336 | int     vn, hmin, vmin, hmax, vmax; | 
| 337 | { | 
| 338 | int     i, j; | 
| 339 | register struct ODblock *bp; | 
| 340 | register int    k; | 
| 341 |  | 
| 342 | if (vn<0 | vn>=odNViews) | 
| 343 | return; | 
| 344 | /* check view limits */ | 
| 345 | if (hmin < 0) hmin = 0; | 
| 346 | if (hmax >= odView[vn].hhi) hmax = odView[vn].hhi-1; | 
| 347 | if (vmin < 0) vmin = 0; | 
| 348 | if (vmax >= odView[vn].vhi) vmax = odView[vn].vhi-1; | 
| 349 | if (hmax <= hmin | vmax <= vmin) | 
| 350 | return; | 
| 351 | /* convert to low resolution */ | 
| 352 | hmin = hmin * odView[vn].hlow / odView[vn].hhi; | 
| 353 | hmax = hmax * odView[vn].hlow / odView[vn].hhi; | 
| 354 | vmin = vmin * odView[vn].vlow / odView[vn].vhi; | 
| 355 | vmax = vmax * odView[vn].vlow / odView[vn].vhi; | 
| 356 | /* mark block samples for redraw, inclusive */ | 
| 357 | for (i = hmin; i <= hmax; i++) | 
| 358 | for (j = vmin; j <= vmax; j++) { | 
| 359 | bp = odView[vn].bmap + j*odView[vn].hlow + i; | 
| 360 | for (k = bp->nsamp; k--; ) | 
| 361 | if (odS.ip[bp->first+k][0] >= 0) { | 
| 362 | SET4(odS.redraw, bp->first+k); | 
| 363 | odView[vn].n2redraw++; | 
| 364 | } | 
| 365 | } | 
| 366 | } | 
| 367 |  | 
| 368 |  | 
| 369 | odDepthMap(vn, dm)                      /* assign depth map for view */ | 
| 370 | int     vn; | 
| 371 | GLfloat *dm; | 
| 372 | { | 
| 373 | double  d0, d1; | 
| 374 | int     i, j, hmin, hmax, vmin, vmax; | 
| 375 | register int    k, l; | 
| 376 |  | 
| 377 | if (dm == NULL) {                       /* free edge map */ | 
| 378 | if (vn<0 | vn>=odNViews) | 
| 379 | return;                 /* too late -- they're gone! */ | 
| 380 | if (odView[vn].emap != NULL) | 
| 381 | free((void *)odView[vn].emap); | 
| 382 | odView[vn].emap = NULL; | 
| 383 | odView[vn].dmap = NULL; | 
| 384 | return; | 
| 385 | } | 
| 386 | DCHECK(vn<0 | vn>=odNViews, CONSISTENCY, | 
| 387 | "bad view number in odDepthMap"); | 
| 388 | odView[vn].dmap = dm;                   /* initialize edge map */ | 
| 389 | if (odView[vn].emap == NULL) { | 
| 390 | odView[vn].emap = (int4 *)malloc( | 
| 391 | FL4NELS(odView[vn].hlow*odView[vn].vlow)*sizeof(int4)); | 
| 392 | if (odView[vn].emap == NULL) | 
| 393 | error(SYSTEM, "out of memory in odDepthMap"); | 
| 394 | } | 
| 395 | CLR4ALL(odView[vn].emap, odView[vn].hlow*odView[vn].vlow); | 
| 396 | /* compute edge map */ | 
| 397 | vmin = odView[vn].vhi;                  /* enter loopsville */ | 
| 398 | for (j = odView[vn].vlow; j--; ) { | 
| 399 | vmax = vmin; | 
| 400 | vmin = j*odView[vn].vhi/odView[vn].vlow; | 
| 401 | hmin = odView[vn].hhi; | 
| 402 | for (i = odView[vn].hlow; i--; ) { | 
| 403 | hmax = hmin; | 
| 404 | hmin = i*odView[vn].hhi/odView[vn].hlow; | 
| 405 | for (l = vmin; l < vmax; l++) { /* vertical edges */ | 
| 406 | d1 = dm[l*odView[vn].hhi+hmin]; | 
| 407 | for (k = hmin+1; k < hmax; k++) { | 
| 408 | d0 = d1; | 
| 409 | d1 = dm[l*odView[vn].hhi+k]; | 
| 410 | if (d0 > (1.+DEPTHEPS)*d1 || | 
| 411 | (1.+DEPTHEPS)*d0 < d1) { | 
| 412 | SET4(odView[vn].emap, | 
| 413 | j*odView[vn].hlow + i); | 
| 414 | break; | 
| 415 | } | 
| 416 | } | 
| 417 | if (k < hmax) | 
| 418 | break; | 
| 419 | } | 
| 420 | if (l < vmax) | 
| 421 | continue; | 
| 422 | for (k = hmin; k < hmax; k++) { /* horizontal edges */ | 
| 423 | d1 = dm[vmin*odView[vn].hhi+k]; | 
| 424 | for (l = vmin+1; l < vmax; l++) { | 
| 425 | d0 = d1; | 
| 426 | d1 = dm[l*odView[vn].hhi+k]; | 
| 427 | if (d0 > (1.+DEPTHEPS)*d1 || | 
| 428 | (1.+DEPTHEPS)*d0 < d1) { | 
| 429 | SET4(odView[vn].emap, | 
| 430 | j*odView[vn].hlow + i); | 
| 431 | break; | 
| 432 | } | 
| 433 | } | 
| 434 | if (l < vmax) | 
| 435 | break; | 
| 436 | } | 
| 437 | } | 
| 438 | } | 
| 439 | } | 
| 440 |  | 
| 441 |  | 
| 442 | odUpdate(vn)                            /* update this view */ | 
| 443 | int     vn; | 
| 444 | { | 
| 445 | static short    primes[] = {9431,6803,4177,2659,1609,887,587,251,47,1}; | 
| 446 | int     myprime; | 
| 447 | register int    i, n; | 
| 448 |  | 
| 449 | DCHECK(vn<0 | vn>=odNViews, CONSISTENCY, | 
| 450 | "bad view number in odUpdate"); | 
| 451 | /* need to do some tone mapping? */ | 
| 452 | if (needmapping & NEWRGB) { | 
| 453 | if (needmapping & NEWMAP) { | 
| 454 | if (needmapping & NEWHIST) | 
| 455 | tmClearHisto(); | 
| 456 | needmapping &= ~NEWHIST; | 
| 457 | if (tmAddHisto(odS.brt,odS.nsamp,1) != TM_E_OK) | 
| 458 | return; | 
| 459 | if (tmComputeMapping(0.,0.,0.) != TM_E_OK) | 
| 460 | return; | 
| 461 | needmapping &= ~NEWMAP; | 
| 462 | odRedrawAll();                  /* redraw everything */ | 
| 463 | } | 
| 464 | if (tmMapPixels(odS.rgb,odS.brt,odS.chr,odS.nsamp) != TM_E_OK) | 
| 465 | return; | 
| 466 | needmapping &= ~NEWRGB; | 
| 467 | } | 
| 468 | if (odView[vn].n2redraw <= 0) | 
| 469 | return; | 
| 470 | #if REDRAWTHRESH | 
| 471 | if (odView[vn].n2redraw < REDRAWTHRESH) | 
| 472 | goto quickdraw; | 
| 473 | /* pick a good prime step size */ | 
| 474 | n = odView[vn].snext - odView[vn].sfirst; | 
| 475 | for (i = 0; primes[i]<<5 >= n; i++) | 
| 476 | ; | 
| 477 | while ((myprime = primes[i++]) > 1) | 
| 478 | if (n % myprime) | 
| 479 | break; | 
| 480 | /* dissolve in new samples */ | 
| 481 | for (i = odView[vn].sfirst; n-- > 0; i += myprime) { | 
| 482 | if (i >= odView[vn].snext) | 
| 483 | i -= odView[vn].snext - odView[vn].sfirst; | 
| 484 | if (CHK4(odS.redraw, i)) { | 
| 485 | odDrawSamp(vn, i); | 
| 486 | CLR4(odS.redraw, i); | 
| 487 | } | 
| 488 | } | 
| 489 | odView[vn].n2redraw = 0; | 
| 490 | return; | 
| 491 | quickdraw:                              /* quicker sparse flag checking */ | 
| 492 | #endif | 
| 493 | /* redraw samples at end */ | 
| 494 | for (i = odView[vn].snext-31; i < odView[vn].snext; i++) | 
| 495 | if (CHK4(odS.redraw, i)) { | 
| 496 | odDrawSamp(vn, i); | 
| 497 | CLR4(odS.redraw, i); | 
| 498 | } | 
| 499 | /* faster flag checks in middle */ | 
| 500 | for (n = odView[vn].snext>>5; n-- > (odView[vn].sfirst+0x1f)>>5; ) | 
| 501 | for (i = 0; odS.redraw[n]; i++)         /* skips faster */ | 
| 502 | if (odS.redraw[n] & 1L<<i) { | 
| 503 | odDrawSamp(vn, (n<<5)+i); | 
| 504 | odS.redraw[n] &= ~(1L<<i); | 
| 505 | } | 
| 506 | /* redraw samples at beginning */ | 
| 507 | for (i = odView[vn].sfirst; i < odView[vn].sfirst+31; i++) | 
| 508 | if (CHK4(odS.redraw, i)) { | 
| 509 | odDrawSamp(vn, i); | 
| 510 | CLR4(odS.redraw, i); | 
| 511 | } | 
| 512 | odView[vn].n2redraw = 0; | 
| 513 | } | 
| 514 |  | 
| 515 |  | 
| 516 | /* this turned out to be unnecessary */ | 
| 517 | #if 0 | 
| 518 | static | 
| 519 | clip_end(p, o, vp)                      /* clip line segment to view */ | 
| 520 | GLshort p[3]; | 
| 521 | short   o[2]; | 
| 522 | register struct ODview  *vp; | 
| 523 | { | 
| 524 | if (p[0] < 0) { | 
| 525 | p[1] = -o[0]*(p[1]-o[1])/(p[0]-o[0]) + o[1]; | 
| 526 | p[2] = -o[0]*p[2]/(p[0]-o[0]); | 
| 527 | p[0] = 0; | 
| 528 | } else if (p[0] >= vp->hhi) { | 
| 529 | p[1] = (vp->hhi-1-o[0])*(p[1]-o[1])/(p[0]-o[0]) + o[1]; | 
| 530 | p[2] = (vp->hhi-1-o[0])*p[2]/(p[0]-o[0]); | 
| 531 | p[0] = vp->hhi-1; | 
| 532 | } | 
| 533 | if (p[1] < 0) { | 
| 534 | p[0] = -o[1]*(p[0]-o[0])/(p[1]-o[1]) + o[0]; | 
| 535 | p[2] = -o[1]*p[2]/(p[1]-o[1]); | 
| 536 | p[1] = 0; | 
| 537 | } else if (p[1] >= vp->vhi) { | 
| 538 | p[0] = (vp->vhi-1-o[1])*(p[0]-o[0])/(p[1]-o[1]) + o[0]; | 
| 539 | p[2] = (vp->vhi-1-o[1])*p[2]/(p[1]-o[1]); | 
| 540 | p[1] = vp->vhi-1; | 
| 541 | } | 
| 542 | } | 
| 543 | #endif | 
| 544 |  | 
| 545 |  | 
| 546 | static int | 
| 547 | make_arms(ar, cp, vp, sz)               /* make arms for triangle fan */ | 
| 548 | GLshort ar[MAXFAN][3]; | 
| 549 | short   cp[2]; | 
| 550 | register struct ODview  *vp; | 
| 551 | double  sz; | 
| 552 | { | 
| 553 | int     na, dv; | 
| 554 | double  hrad, vrad, phi; | 
| 555 | register int    i; | 
| 556 |  | 
| 557 | DCHECK(sz > 1, CONSISTENCY, "super-unary size in make_arms"); | 
| 558 | na = MAXFAN*sz + 0.5;                   /* keep arc length constant */ | 
| 559 | if (na < MINFAN) na = MINFAN; | 
| 560 | hrad = FANSIZE*sz*vp->hhi/vp->hlow; | 
| 561 | vrad = FANSIZE*sz*vp->vhi/vp->vlow; | 
| 562 | if (hrad*vrad < 2.25) | 
| 563 | hrad = vrad = 1.5; | 
| 564 | dv = OMAXDEPTH*sz + 0.5; | 
| 565 | for (i = 0; i < na; i++) { | 
| 566 | phi = (2.*PI)*i/na; | 
| 567 | ar[i][0] = cp[0] + tcos(phi)*hrad + 0.5; | 
| 568 | ar[i][1] = cp[1] + tsin(phi)*vrad + 0.5; | 
| 569 | ar[i][2] = dv; | 
| 570 | /* clip_end(ar[i], cp, vp); */ | 
| 571 | } | 
| 572 | return(na); | 
| 573 | } | 
| 574 |  | 
| 575 |  | 
| 576 | static int | 
| 577 | depthchange(vp, x0, y0, x1, y1)         /* check depth discontinuity */ | 
| 578 | register struct ODview  *vp; | 
| 579 | int     x0, y0, x1, y1; | 
| 580 | { | 
| 581 | register double d0, d1; | 
| 582 |  | 
| 583 | DCHECK(x0<0 | x0>=vp->hhi | y0<0 | y0>=vp->vhi, | 
| 584 | CONSISTENCY, "coordinates off view in depthchange"); | 
| 585 |  | 
| 586 | if (x1<0 | x1>=vp->hhi | y1<0 | y1>=vp->vhi) | 
| 587 | return(1); | 
| 588 |  | 
| 589 | d0 = vp->dmap[y0*vp->hhi + x0]; | 
| 590 | d1 = vp->dmap[y1*vp->hhi + x1]; | 
| 591 |  | 
| 592 | return((1.+DEPTHEPS)*d0 < d1 || d0 > (1.+DEPTHEPS)*d1); | 
| 593 | } | 
| 594 |  | 
| 595 |  | 
| 596 | static | 
| 597 | clip_edge(p, o, vp)                     /* clip line segment to depth edge */ | 
| 598 | GLshort p[3]; | 
| 599 | short   o[2]; | 
| 600 | register struct ODview  *vp; | 
| 601 | { | 
| 602 | int     x, y, xstep, ystep, rise, rise2, run, run2, n; | 
| 603 |  | 
| 604 | DCHECK(vp->dmap==NULL, CONSISTENCY, | 
| 605 | "clip_edge called with no depth map"); | 
| 606 | x = o[0]; y = o[1]; | 
| 607 | run = p[0] - x; | 
| 608 | xstep = run > 0 ? 1 : -1; | 
| 609 | run *= xstep; | 
| 610 | rise = p[1] - y; | 
| 611 | ystep = rise > 0 ? 1 : -1; | 
| 612 | rise *= ystep; | 
| 613 | rise2 = run2 = 0; | 
| 614 | if (rise > run) rise2 = 1; | 
| 615 | else run2 = 1; | 
| 616 | n = rise + run; | 
| 617 | while (n--)                     /* run out arm, checking depth */ | 
| 618 | if (run2 > rise2) { | 
| 619 | x += xstep; | 
| 620 | rise2 += rise; | 
| 621 | if (depthchange(vp, x-xstep, y, x, y)) | 
| 622 | break; | 
| 623 | } else { | 
| 624 | y += ystep; | 
| 625 | run2 += run; | 
| 626 | if (depthchange(vp, x, y-ystep, x, y)) | 
| 627 | break; | 
| 628 | } | 
| 629 | if (n < 0)                      /* found something? */ | 
| 630 | return; | 
| 631 | if (run > rise) | 
| 632 | p[2] = (x - o[0])*p[2]/(p[0] - o[0]); | 
| 633 | else | 
| 634 | p[2] = (y - o[1])*p[2]/(p[1] - o[1]); | 
| 635 | p[0] = x; | 
| 636 | p[1] = y; | 
| 637 | } | 
| 638 |  | 
| 639 |  | 
| 640 | static int | 
| 641 | getblock(vp, h, v)                      /* get block index */ | 
| 642 | register struct ODview  *vp; | 
| 643 | register int    h, v; | 
| 644 | { | 
| 645 | if (h<0 | h>=vp->hhi | v<0 | v>=vp->vhi) | 
| 646 | return(-1); | 
| 647 | return(h*vp->hlow/vp->hhi + v*vp->vlow/vp->vhi*vp->hlow); | 
| 648 | } | 
| 649 |  | 
| 650 |  | 
| 651 | static int | 
| 652 | blockedge(vp, bi0, bi1)                 /* check for edge between blocks? */ | 
| 653 | register struct ODview  *vp; | 
| 654 | register int    bi0, bi1; | 
| 655 | { | 
| 656 | if (bi1 == bi0) | 
| 657 | return(0);              /* same block */ | 
| 658 | if (bi1 < 0) | 
| 659 | return(1);              /* end off view */ | 
| 660 | if (CHK4(vp->emap, bi1)) | 
| 661 | return(1);              /* end block has edges */ | 
| 662 | if (bi1 == bi0+1 || bi1 == bi0-1 || | 
| 663 | bi1 == bi0+vp->hlow || bi1 == bi0-vp->hlow) | 
| 664 | return(0);              /* end in adjacent block -- no edges */ | 
| 665 | return(1);                      /* conservative for rarer case */ | 
| 666 | } | 
| 667 |  | 
| 668 |  | 
| 669 | odDrawSamp(vn, id)                      /* draw view sample */ | 
| 670 | int     vn; | 
| 671 | register int    id; | 
| 672 | { | 
| 673 | GLshort arm[MAXFAN][3]; | 
| 674 | int     narms, blockindex; | 
| 675 | register struct ODview  *vp; | 
| 676 | double  size; | 
| 677 | int     home_edges; | 
| 678 | register int    i; | 
| 679 |  | 
| 680 | vp = odView + vn; | 
| 681 | blockindex = getblock(vp, odS.ip[id][0], odS.ip[id][1]); | 
| 682 | DCHECK(blockindex<0, CONSISTENCY, "bad sample handed to odDrawSamp"); | 
| 683 | DCHECK(vp->bmap[blockindex].nused <= 0, | 
| 684 | CONSISTENCY, "bad in-use count in odDrawSamp"); | 
| 685 | /* create triangle fan */ | 
| 686 | size = 1./sqrt((double)vp->bmap[blockindex].nused); | 
| 687 | narms = make_arms(arm, odS.ip[id], vp, size); | 
| 688 | if (vp->emap != NULL) {         /* check for edge collisions */ | 
| 689 | home_edges = CHK4(vp->emap, blockindex); | 
| 690 | for (i = 0; i < narms; i++) | 
| 691 | if (home_edges || blockedge(vp, blockindex, | 
| 692 | getblock(vp, arm[i][0], arm[i][1]))) | 
| 693 | clip_edge(arm[i], odS.ip[id], vp); | 
| 694 | } | 
| 695 | /* draw triangle fan */ | 
| 696 | glColor3ub(odS.rgb[id][0], odS.rgb[id][1], odS.rgb[id][2]); | 
| 697 | glBegin(GL_TRIANGLE_FAN); | 
| 698 | glVertex3s((GLshort)odS.ip[id][0], (GLshort)odS.ip[id][1], (GLshort)0); | 
| 699 | for (i = 0; i < narms; i++) | 
| 700 | glVertex3sv(arm[i]); | 
| 701 | glVertex3sv(arm[0]);            /* connect last to first */ | 
| 702 | glEnd(); | 
| 703 | } |