| 14 |  | #include <GL/glx.h> | 
| 15 |  | #include <GL/glu.h> | 
| 16 |  |  | 
| 17 | – | #include "random.h" | 
| 17 |  | #include "rhd_odraw.h" | 
| 18 |  |  | 
| 19 |  | #ifndef DEPTHEPS | 
| 37 |  |  | 
| 38 |  | #define NEWMAP          01              /* need to recompute mapping */ | 
| 39 |  | #define NEWRGB          02              /* need to remap RGB values */ | 
| 40 | + | #define NEWHIST         04              /* clear histogram as well */ | 
| 41 |  |  | 
| 42 |  | struct ODview   *odView;        /* our view list */ | 
| 43 |  | int     odNViews;               /* number of views in our list */ | 
| 57 |  | int     nbytes, i, j, k, nextsamp, count, blockdiv; | 
| 58 |  | int     res[2]; | 
| 59 |  |  | 
| 60 | < | if (odNViews) {                 /* deallocate view structures */ | 
| 61 | < | for (i = 0; i < odNViews; i++) { | 
| 60 | > | if (odNViews > 0) {             /* deallocate view structures */ | 
| 61 | > | for (i = odNViews; i--; ) { | 
| 62 |  | free((char *)odView[i].bmap); | 
| 63 | + | free((char *)odView[i].pmap); | 
| 64 |  | if (odView[i].emap != NULL) | 
| 65 |  | free((char *)odView[i].emap); | 
| 66 |  | } | 
| 74 |  | for (i = 1024; nbytes > i-8; i <<= 1) | 
| 75 |  | ; | 
| 76 |  | n = (i-8)/SAMP32 * 32; | 
| 77 | < | needmapping = NEWMAP; | 
| 77 | > | needmapping = NEWHIST; | 
| 78 |  | } | 
| 79 |  | if (n != odS.nsamp) {   /* (re)allocate sample array */ | 
| 80 |  | if (odS.nsamp) | 
| 109 |  | if (blockdiv < 8) blockdiv = 8; | 
| 110 |  | nextsamp = 0; count /= blockdiv*blockdiv;       /* # blocks */ | 
| 111 |  | while (i--) {                   /* initialize each view */ | 
| 111 | – | odView[i].emap = NULL; | 
| 112 | – | odView[i].dmap = NULL; | 
| 112 |  | dev_auxview(i, res); | 
| 113 |  | odView[i].hhi = res[0]; | 
| 114 |  | odView[i].hlow = (res[0] + blockdiv/2) / blockdiv; | 
| 116 |  | odView[i].vhi = res[1]; | 
| 117 |  | odView[i].vlow = (res[1] + blockdiv/2) / blockdiv; | 
| 118 |  | if (odView[i].vlow < 1) odView[i].vlow = 1; | 
| 119 | + | odView[i].emap = NULL; | 
| 120 | + | odView[i].dmap = NULL; | 
| 121 | + | odView[i].pmap = (int4 *)calloc(FL4NELS(res[0]*res[1]), | 
| 122 | + | sizeof(int4)); | 
| 123 | + | if (odView[i].pmap == NULL) | 
| 124 | + | return(0); | 
| 125 |  | j = odView[i].hlow*odView[i].vlow; | 
| 126 |  | odView[i].bmap = (struct ODblock *)malloc( | 
| 127 |  | j * sizeof(struct ODblock)); | 
| 130 |  | DCHECK(count<=0 | nextsamp>=n, | 
| 131 |  | CONSISTENCY, "counter botch in odInit"); | 
| 132 |  | if (!i) count = j; | 
| 133 | < | while (j--) { | 
| 133 | > | odView[i].sfirst = nextsamp; | 
| 134 | > | while (j--) {           /* initialize blocks & free lists */ | 
| 135 | > | odView[i].bmap[j].pthresh = FHUGE; | 
| 136 |  | odView[i].bmap[j].first = k = nextsamp; | 
| 137 |  | nextsamp += odView[i].bmap[j].nsamp = | 
| 138 |  | (n - nextsamp)/count--; | 
| 142 |  | odS.nextfree(k-1) = ENDFREE; | 
| 143 |  | odView[i].bmap[j].nused = 0; | 
| 144 |  | } | 
| 145 | + | odView[i].snext = nextsamp; | 
| 146 |  | } | 
| 147 |  | CLR4ALL(odS.redraw, odS.nsamp);         /* clear redraw flags */ | 
| 148 | < | for (i = odS.nsamp; i--; )              /* clear values */ | 
| 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 |  |  | 
| 167 |  |  | 
| 168 |  |  | 
| 169 |  | int | 
| 170 | < | odAllocBlockSamp(vn, hl, vl)            /* allocate sample from block */ | 
| 171 | < | int     vn, hl, vl; | 
| 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; | 
| 181 | < |  | 
| 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 (bp->free != ENDFREE) {      /* check free list first */ | 
| 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 = -1; | 
| 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.999*odS.closeness(i)) | 
| 207 | > | return(-1);     /* previous sample is fine */ | 
| 208 | > | goto gotit; | 
| 209 | > | } | 
| 210 | > | DCHECK(i>=-1, WARNING, "pixel in presence map not found in block"); | 
| 211 | > | if (bp->free != ENDFREE) {      /* allocate from free list */ | 
| 212 |  | i = bp->free; | 
| 213 | + | if (odS.ip[i][0] >= 0 & odS.ip[i][1] >= 0) | 
| 214 | + | CLR4(odView[vn].pmap, odS.ip[i][1]*odView[vn].hhi + | 
| 215 | + | odS.ip[i][0]); | 
| 216 |  | bp->free = odS.nextfree(i); | 
| 217 |  | bp->nused++; | 
| 218 | < | return(i); | 
| 218 | > | goto gotit; | 
| 219 |  | } | 
| 220 |  | DCHECK(bp->nsamp<=0, CONSISTENCY, | 
| 221 |  | "no available samples in odAllocBlockSamp"); | 
| 227 |  | for (i = bp->nsamp; i--; )      /* figure out which are worse */ | 
| 228 |  | si[i] = bp->first + i; | 
| 229 |  | qsort((char *)si, bp->nsamp, sizeof(int), sampcmp); | 
| 230 | < | i = bp->nsamp*SFREEFRAC + .5;   /* put them in a list */ | 
| 230 | > | i = bp->nsamp*SFREEFRAC + .5;   /* put them into free list */ | 
| 231 | > | if (i >= bp->nsamp) i = bp->nsamp-1;    /* paranoia */ | 
| 232 | > | bp->pthresh = odS.closeness(si[i]);     /* new proximity threshold */ | 
| 233 |  | while (--i > 0) { | 
| 234 |  | odS.nextfree(si[i]) = bp->free; | 
| 235 |  | bp->free = si[i]; | 
| 236 |  | bp->nused--; | 
| 237 |  | } | 
| 238 | < | return(si[0]);                  /* return first free sample */ | 
| 238 | > | i = si[0];                      /* use worst sample */ | 
| 239 | > | CLR4(odView[vn].pmap, odS.ip[i][1]*odView[vn].hhi + odS.ip[i][0]); | 
| 240 | > | gotit: | 
| 241 | > | odS.ip[i][0] = hh; | 
| 242 | > | odS.ip[i][1] = vh; | 
| 243 | > | odS.closeness(i) = prox; | 
| 244 | > | SET4(odView[vn].pmap, vh*odView[vn].hhi + hh); | 
| 245 | > | return(i); | 
| 246 |  | } | 
| 247 |  |  | 
| 248 |  |  | 
| 251 |  | FVECT   d, p; | 
| 252 |  | { | 
| 253 |  | FVECT   disp; | 
| 254 | < | double  d0, d1, h, v; | 
| 254 | > | double  d0, d1, h, v, prox; | 
| 255 |  | register VIEW   *vw; | 
| 256 | < | int     hl, vl, hh, vh; | 
| 256 | > | int     hh, vh; | 
| 257 |  | int     res[2]; | 
| 258 |  | register int    i, id; | 
| 259 |  |  | 
| 288 |  | (1.+DEPTHEPS)*d0 < d1)) | 
| 289 |  | continue;                       /* occlusion error */ | 
| 290 |  | } | 
| 238 | – | hl = hh*odView[i].hlow/res[0]; | 
| 239 | – | vl = vh*odView[i].vlow/res[1]; | 
| 240 | – | /* may duplicate samples */ | 
| 241 | – | id = odAllocBlockSamp(i, hl, vl); | 
| 242 | – | odS.ip[id][0] = hh; | 
| 243 | – | odS.ip[id][1] = vh; | 
| 291 |  | if (p != NULL) {                /* compute closeness (sin^2) */ | 
| 292 |  | d1 = DOT(disp, d); | 
| 293 | < | odS.closeness(id) = 1. - d1*d1/DOT(disp,disp); | 
| 293 | > | prox = 1. - d1*d1/DOT(disp,disp); | 
| 294 |  | } else | 
| 295 | < | odS.closeness(id) = 0.; | 
| 295 | > | prox = 0.; | 
| 296 | > | /* allocate sample */ | 
| 297 | > | id = odAllocBlockSamp(i, hh, vh, prox); | 
| 298 | > | if (id < 0) | 
| 299 | > | continue;               /* not good enough */ | 
| 300 |  | /* convert color */ | 
| 301 |  | tmCvColrs(&odS.brt[id], odS.chr[id], c, 1); | 
| 302 |  | if (imm_mode | needmapping)             /* if immediate mode */ | 
| 308 |  | } | 
| 309 |  |  | 
| 310 |  |  | 
| 311 | < | odRemap()                               /* recompute tone mapping */ | 
| 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 | + | } | 
| 330 | + |  | 
| 331 | + |  | 
| 332 |  | odRedraw(vn, hmin, vmin, hmax, vmax)    /* redraw view region */ | 
| 333 |  | int     vn, hmin, vmin, hmax, vmax; | 
| 334 |  | { | 
| 369 |  | int     i, j, hmin, hmax, vmin, vmax; | 
| 370 |  | register int    k, l; | 
| 371 |  |  | 
| 306 | – | DCHECK(vn<0 | vn>=odNViews, CONSISTENCY, | 
| 307 | – | "bad view number in odDepthMap"); | 
| 372 |  | if (dm == NULL) {                       /* free edge map */ | 
| 373 | + | if (vn<0 | vn>=odNViews) | 
| 374 | + | return;                 /* too late -- they're gone! */ | 
| 375 |  | if (odView[vn].emap != NULL) | 
| 376 |  | free((char *)odView[vn].emap); | 
| 377 |  | odView[vn].emap = NULL; | 
| 378 |  | odView[vn].dmap = NULL; | 
| 379 |  | return; | 
| 380 |  | } | 
| 381 | + | DCHECK(vn<0 | vn>=odNViews, CONSISTENCY, | 
| 382 | + | "bad view number in odDepthMap"); | 
| 383 |  | odView[vn].dmap = dm;                   /* initialize edge map */ | 
| 384 |  | if (odView[vn].emap == NULL) { | 
| 385 |  | odView[vn].emap = (int4 *)malloc( | 
| 437 |  | odUpdate(vn)                            /* update this view */ | 
| 438 |  | int     vn; | 
| 439 |  | { | 
| 440 | < | int     i, j; | 
| 373 | < | register struct ODblock *bp; | 
| 374 | < | register int    k; | 
| 440 | > | register int    i, j; | 
| 441 |  |  | 
| 442 |  | DCHECK(vn<0 | vn>=odNViews, CONSISTENCY, | 
| 443 |  | "bad view number in odUpdate"); | 
| 444 |  | /* need to do some tone mapping? */ | 
| 445 |  | if (needmapping & NEWRGB) { | 
| 446 |  | if (needmapping & NEWMAP) { | 
| 447 | < | tmClearHisto(); | 
| 447 | > | if (needmapping & NEWHIST) | 
| 448 | > | tmClearHisto(); | 
| 449 | > | needmapping &= ~NEWHIST; | 
| 450 |  | if (tmAddHisto(odS.brt,odS.nsamp,1) != TM_E_OK) | 
| 451 |  | return; | 
| 452 |  | if (tmComputeMapping(0.,0.,0.) != TM_E_OK) | 
| 453 |  | return; | 
| 454 | < | for (k = odS.nsamp; k--; )      /* redraw all */ | 
| 455 | < | if (odS.ip[k][0] >= 0) | 
| 388 | < | SET4(odS.redraw, k); | 
| 454 | > | needmapping &= ~NEWMAP; | 
| 455 | > | odRedrawAll();                  /* redraw everything */ | 
| 456 |  | } | 
| 457 |  | if (tmMapPixels(odS.rgb,odS.brt,odS.chr,odS.nsamp) != TM_E_OK) | 
| 458 |  | return; | 
| 459 | < | needmapping = 0;                /* reset flag */ | 
| 459 | > | needmapping &= ~NEWRGB; | 
| 460 |  | } | 
| 461 | < | /* draw each block in view */ | 
| 462 | < | for (i = odView[vn].hlow; i--; ) | 
| 463 | < | for (j = odView[vn].vlow; j--; ) { | 
| 464 | < | /* get block */ | 
| 465 | < | bp = odView[vn].bmap + j*odView[vn].hlow + i; | 
| 466 | < | /* do quick, conservative flag check */ | 
| 400 | < | for (k = (bp->first+bp->nsamp+31)>>5; | 
| 401 | < | k-- > bp->first>>5; ) | 
| 402 | < | if (odS.redraw[k]) | 
| 403 | < | break;          /* non-zero flag */ | 
| 404 | < | if (k < bp->first>>5) | 
| 405 | < | continue;               /* no flags set */ | 
| 406 | < | for (k = bp->nsamp; k--; )      /* sample by sample */ | 
| 407 | < | if (CHK4(odS.redraw, bp->first+k)) { | 
| 408 | < | odDrawBlockSamp(vn, i, j, bp->first+k); | 
| 409 | < | CLR4(odS.redraw, bp->first+k); | 
| 410 | < | } | 
| 461 | > | /* this code segment was too slow */ | 
| 462 | > | #if 0 | 
| 463 | > | for (i = odView[vn].sfirst; i < odView[vn].snext; i++) | 
| 464 | > | if (CHK4(odS.redraw, i)) { | 
| 465 | > | odDrawSamp(vn, i); | 
| 466 | > | CLR4(odS.redraw, i); | 
| 467 |  | } | 
| 468 | + | #else | 
| 469 | + | /* redraw samples at each end */ | 
| 470 | + | for (i = odView[vn].sfirst; i < odView[vn].sfirst+31; i++) | 
| 471 | + | if (CHK4(odS.redraw, i)) { | 
| 472 | + | odDrawSamp(vn, i); | 
| 473 | + | CLR4(odS.redraw, i); | 
| 474 | + | } | 
| 475 | + | for (i = odView[vn].snext-31; i < odView[vn].snext; i++) | 
| 476 | + | if (CHK4(odS.redraw, i)) { | 
| 477 | + | odDrawSamp(vn, i); | 
| 478 | + | CLR4(odS.redraw, i); | 
| 479 | + | } | 
| 480 | + | /* faster flag checks in middle */ | 
| 481 | + | for (j = odView[vn].snext>>5; j-- > (odView[vn].sfirst+0x1f)>>5; ) | 
| 482 | + | for (i = 0; odS.redraw[j]; i++)         /* skips faster */ | 
| 483 | + | if (odS.redraw[j] & 1L<<i) { | 
| 484 | + | odDrawSamp(vn, (j<<5)+i); | 
| 485 | + | odS.redraw[j] &= ~(1L<<i); | 
| 486 | + | } | 
| 487 | + | #endif | 
| 488 |  | } | 
| 489 |  |  | 
| 490 |  |  | 
| 491 | + | /* this turned out to be unnecessary */ | 
| 492 |  | #if 0 | 
| 493 |  | static | 
| 494 |  | clip_end(p, o, vp)                      /* clip line segment to view */ | 
| 526 |  | double  sz; | 
| 527 |  | { | 
| 528 |  | int     na, dv; | 
| 529 | < | double  hrad, vrad, phi0, phi; | 
| 529 | > | double  hrad, vrad, phi; | 
| 530 |  | register int    i; | 
| 531 |  |  | 
| 532 |  | DCHECK(sz > 1, CONSISTENCY, "super-unary size in make_arms"); | 
| 536 |  | vrad = FANSIZE*sz*vp->vhi/vp->vlow; | 
| 537 |  | if (hrad*vrad < 2.25) | 
| 538 |  | hrad = vrad = 1.5; | 
| 462 | – | phi0 = (2.*PI) * frandom(); | 
| 539 |  | dv = OMAXDEPTH*sz + 0.5; | 
| 540 |  | for (i = 0; i < na; i++) { | 
| 541 | < | phi = phi0 + (2.*PI)*i/na; | 
| 541 | > | phi = (2.*PI)*i/na; | 
| 542 |  | ar[i][0] = cp[0] + tcos(phi)*hrad + 0.5; | 
| 543 |  | ar[i][1] = cp[1] + tsin(phi)*vrad + 0.5; | 
| 544 |  | ar[i][2] = dv; | 
| 623 |  | } | 
| 624 |  |  | 
| 625 |  |  | 
| 626 | < | odDrawBlockSamp(vn, h, v, id)           /* draw sample in view block */ | 
| 627 | < | int     vn, h, v; | 
| 626 | > | static int | 
| 627 | > | blockedge(vp, bi0, bi1)                 /* check for edge between blocks? */ | 
| 628 | > | register struct ODview  *vp; | 
| 629 | > | register int    bi0, bi1; | 
| 630 | > | { | 
| 631 | > | if (bi1 < 0) | 
| 632 | > | return(1);              /* end off view */ | 
| 633 | > | if (CHK4(vp->emap, bi1)) | 
| 634 | > | return(1);              /* end has edges */ | 
| 635 | > | if (bi1 == bi0+1 || bi1 == bi0-1 || | 
| 636 | > | bi1 == bi0+vp->hlow || bi1 == bi0-vp->hlow) | 
| 637 | > | return(0);              /* end in adjacent block -- no edges */ | 
| 638 | > | return(1);                      /* conservative for rarer case */ | 
| 639 | > | } | 
| 640 | > |  | 
| 641 | > |  | 
| 642 | > | odDrawSamp(vn, id)                      /* draw view sample */ | 
| 643 | > | int     vn; | 
| 644 |  | register int    id; | 
| 645 |  | { | 
| 646 |  | GLshort arm[MAXFAN][3]; | 
| 647 | < | int     narms, blockindex, bi1; | 
| 647 | > | int     narms, blockindex; | 
| 648 |  | register struct ODview  *vp; | 
| 649 |  | double  size; | 
| 650 |  | int     home_edges; | 
| 651 |  | register int    i; | 
| 652 |  |  | 
| 653 |  | vp = odView + vn; | 
| 654 | < | blockindex = v*vp->hlow + h; | 
| 655 | < | DCHECK(odS.ip[id][0]*vp->hlow/vp->hhi != h | | 
| 564 | < | odS.ip[id][1]*vp->vlow/vp->vhi != v, | 
| 565 | < | CONSISTENCY, "bad sample position in odDrawBlockSamp"); | 
| 654 | > | blockindex = getblock(vp, odS.ip[id][0], odS.ip[id][1]); | 
| 655 | > | DCHECK(blockindex<0, CONSISTENCY, "bad sample handed to odDrawSamp"); | 
| 656 |  | DCHECK(vp->bmap[blockindex].nused <= 0, | 
| 657 | < | CONSISTENCY, "bad in-use count in odDrawBlockSamp"); | 
| 657 | > | CONSISTENCY, "bad in-use count in odDrawSamp"); | 
| 658 |  | /* create triangle fan */ | 
| 659 |  | size = 1./sqrt((double)vp->bmap[blockindex].nused); | 
| 660 |  | narms = make_arms(arm, odS.ip[id], vp, size); | 
| 661 |  | if (vp->emap != NULL) {         /* check for edge collisions */ | 
| 662 |  | home_edges = CHK4(vp->emap, blockindex); | 
| 663 |  | for (i = 0; i < narms; i++) | 
| 664 | < | /* the following test is flawed, because we could | 
| 665 | < | * be passing through a block on a diagonal run */ | 
| 576 | < | if (home_edges || | 
| 577 | < | ( (bi1 = getblock(vp, arm[i][0], arm[i][1])) | 
| 578 | < | != blockindex && | 
| 579 | < | (bi1 < 0 || CHK4(vp->emap, bi1)) )) | 
| 664 | > | if (home_edges || blockedge(vp, blockindex, | 
| 665 | > | getblock(vp, arm[i][0], arm[i][1]))) | 
| 666 |  | clip_edge(arm[i], odS.ip[id], vp); | 
| 667 |  | } | 
| 668 |  | /* draw triangle fan */ |