| 1 | greg | 2.15 | /* Copyright (c) 1995 Regents of the University of California */ | 
| 2 | greg | 1.1 |  | 
| 3 |  |  | #ifndef lint | 
| 4 |  |  | static char SCCSid[] = "$SunId$ LBL"; | 
| 5 |  |  | #endif | 
| 6 |  |  |  | 
| 7 |  |  | /* | 
| 8 |  |  | *  rview.c - routines and variables for interactive view generation. | 
| 9 |  |  | * | 
| 10 |  |  | *     3/24/87 | 
| 11 |  |  | */ | 
| 12 |  |  |  | 
| 13 | greg | 1.15 | #include  "ray.h" | 
| 14 | greg | 1.1 |  | 
| 15 |  |  | #include  "rpaint.h" | 
| 16 |  |  |  | 
| 17 |  |  | #include  <signal.h> | 
| 18 |  |  |  | 
| 19 |  |  | #include  <ctype.h> | 
| 20 |  |  |  | 
| 21 | greg | 1.9 | VIEW  ourview = STDVIEW;                /* viewing parameters */ | 
| 22 |  |  | int  hresolu, vresolu;                  /* image resolution */ | 
| 23 | greg | 1.15 |  | 
| 24 |  |  | int  dimlist[MAXDIM];                   /* sampling dimensions */ | 
| 25 |  |  | int  ndims = 0;                         /* number of sampling dimensions */ | 
| 26 |  |  | int  samplendx = 0;                     /* index for this sample */ | 
| 27 | greg | 1.1 |  | 
| 28 |  |  | int  psample = 8;                       /* pixel sample size */ | 
| 29 | greg | 2.8 | double  maxdiff = .15;                  /* max. sample difference */ | 
| 30 | greg | 1.1 |  | 
| 31 | greg | 2.8 | double  exposure = 1.0;                 /* exposure for scene */ | 
| 32 | greg | 1.1 |  | 
| 33 | greg | 2.8 | double  dstrsrc = 0.0;                  /* square source distribution */ | 
| 34 |  |  | double  shadthresh = .1;                /* shadow threshold */ | 
| 35 |  |  | double  shadcert = .25;                 /* shadow certainty */ | 
| 36 | greg | 1.16 | int  directrelay = 0;                   /* number of source relays */ | 
| 37 | greg | 1.18 | int  vspretest = 128;                   /* virtual source pretest density */ | 
| 38 | greg | 2.9 | int  directvis = 1;                     /* sources visible? */ | 
| 39 | greg | 2.8 | double  srcsizerat = 0.;                /* maximum ratio source size/dist. */ | 
| 40 | greg | 2.15 |  | 
| 41 |  |  | COLOR  cextinction = BLKCOLOR;          /* global extinction coefficient */ | 
| 42 |  |  | double  salbedo = 0.;                   /* global scattering albedo */ | 
| 43 |  |  | double  seccg = 0.;                     /* global scattering eccentricity */ | 
| 44 |  |  | double  ssampdist = 0.;                 /* scatter sampling distance */ | 
| 45 | greg | 1.1 |  | 
| 46 | greg | 2.8 | double  specthresh = .3;                /* specular sampling threshold */ | 
| 47 |  |  | double  specjitter = 1.;                /* specular sampling jitter */ | 
| 48 | greg | 2.5 |  | 
| 49 | greg | 2.14 | int  backvis = 1;                       /* back face visibility */ | 
| 50 |  |  |  | 
| 51 | greg | 1.1 | int  maxdepth = 4;                      /* maximum recursion depth */ | 
| 52 | greg | 2.8 | double  minweight = 1e-2;               /* minimum ray weight */ | 
| 53 | greg | 1.1 |  | 
| 54 |  |  | COLOR  ambval = BLKCOLOR;               /* ambient value */ | 
| 55 | greg | 2.8 | double  ambacc = 0.2;                   /* ambient accuracy */ | 
| 56 | greg | 1.5 | int  ambres = 8;                        /* ambient resolution */ | 
| 57 | greg | 1.1 | int  ambdiv = 32;                       /* ambient divisions */ | 
| 58 |  |  | int  ambssamp = 0;                      /* ambient super-samples */ | 
| 59 |  |  | int  ambounce = 0;                      /* ambient bounces */ | 
| 60 |  |  | char  *amblist[128];                    /* ambient include/exclude list */ | 
| 61 |  |  | int  ambincl = -1;                      /* include == 1, exclude == 0 */ | 
| 62 |  |  |  | 
| 63 |  |  | int  greyscale = 0;                     /* map colors to brightness? */ | 
| 64 | greg | 1.11 | char  *devname = dev_default;           /* output device name */ | 
| 65 | greg | 1.1 |  | 
| 66 |  |  | struct driver  *dev = NULL;             /* driver functions */ | 
| 67 |  |  |  | 
| 68 | greg | 2.11 | char  rifname[128];                     /* rad input file name */ | 
| 69 |  |  |  | 
| 70 | greg | 1.1 | VIEW  oldview;                          /* previous view parameters */ | 
| 71 |  |  |  | 
| 72 |  |  | PNODE  ptrunk;                          /* the base of our image */ | 
| 73 |  |  | RECT  pframe;                           /* current frame boundaries */ | 
| 74 |  |  | int  pdepth;                            /* image depth in current frame */ | 
| 75 |  |  |  | 
| 76 | greg | 1.12 | static char  *reserve_mem = NULL;       /* pre-allocated reserve memory */ | 
| 77 |  |  |  | 
| 78 | greg | 1.20 | #define RESERVE_AMT     32768           /* amount of memory to reserve */ | 
| 79 | greg | 1.12 |  | 
| 80 | greg | 2.8 | #define  CTRL(c)        ((c)-'@') | 
| 81 | greg | 1.1 |  | 
| 82 |  |  |  | 
| 83 |  |  | quit(code)                      /* quit program */ | 
| 84 |  |  | int  code; | 
| 85 |  |  | { | 
| 86 | greg | 2.10 | #ifdef MSTATS | 
| 87 |  |  | if (code == 2 && errno == ENOMEM) | 
| 88 |  |  | printmemstats(stderr); | 
| 89 |  |  | #endif | 
| 90 | greg | 1.1 | devclose(); | 
| 91 |  |  | exit(code); | 
| 92 |  |  | } | 
| 93 |  |  |  | 
| 94 |  |  |  | 
| 95 |  |  | devopen(dname)                          /* open device driver */ | 
| 96 |  |  | char  *dname; | 
| 97 |  |  | { | 
| 98 | greg | 1.6 | extern char  *progname, *octname; | 
| 99 | greg | 1.7 | char  *id; | 
| 100 | greg | 1.1 | register int  i; | 
| 101 | greg | 1.6 |  | 
| 102 | greg | 1.7 | id = octname!=NULL ? octname : progname; | 
| 103 | greg | 1.1 | /* check device table */ | 
| 104 |  |  | for (i = 0; devtable[i].name; i++) | 
| 105 |  |  | if (!strcmp(dname, devtable[i].name)) | 
| 106 | greg | 1.7 | if ((dev = (*devtable[i].init)(dname, id)) == NULL) { | 
| 107 | greg | 1.1 | sprintf(errmsg, "cannot initialize %s", dname); | 
| 108 |  |  | error(USER, errmsg); | 
| 109 |  |  | } else | 
| 110 |  |  | return; | 
| 111 | greg | 2.8 | #ifndef NIX | 
| 112 | greg | 1.1 | /* not there, try exec */ | 
| 113 | greg | 1.7 | if ((dev = comm_init(dname, id)) == NULL) { | 
| 114 | greg | 1.1 | sprintf(errmsg, "cannot start device \"%s\"", dname); | 
| 115 |  |  | error(USER, errmsg); | 
| 116 |  |  | } | 
| 117 | greg | 2.8 | #endif | 
| 118 | greg | 1.1 | } | 
| 119 |  |  |  | 
| 120 |  |  |  | 
| 121 |  |  | devclose()                              /* close our device */ | 
| 122 |  |  | { | 
| 123 |  |  | if (dev != NULL) | 
| 124 |  |  | (*dev->close)(); | 
| 125 |  |  | dev = NULL; | 
| 126 |  |  | } | 
| 127 |  |  |  | 
| 128 |  |  |  | 
| 129 |  |  | printdevices()                          /* print list of output devices */ | 
| 130 |  |  | { | 
| 131 |  |  | register int  i; | 
| 132 |  |  |  | 
| 133 |  |  | for (i = 0; devtable[i].name; i++) | 
| 134 |  |  | printf("%-16s # %s\n", devtable[i].name, devtable[i].descrip); | 
| 135 |  |  | } | 
| 136 |  |  |  | 
| 137 |  |  |  | 
| 138 |  |  | rview()                         /* do a view */ | 
| 139 |  |  | { | 
| 140 |  |  | char  buf[32]; | 
| 141 |  |  |  | 
| 142 |  |  | devopen(devname);               /* open device */ | 
| 143 | greg | 1.14 | newimage();                     /* start image (calls fillreserves) */ | 
| 144 |  |  |  | 
| 145 | greg | 1.1 | for ( ; ; ) {                   /* quit in command() */ | 
| 146 | greg | 1.14 | while (hresolu <= 1<<pdepth && vresolu <= 1<<pdepth) | 
| 147 | greg | 1.1 | command("done: "); | 
| 148 | greg | 1.14 | while (reserve_mem == NULL) | 
| 149 |  |  | command("out of memory: "); | 
| 150 |  |  | errno = 0; | 
| 151 |  |  | if (hresolu <= psample<<pdepth && vresolu <= psample<<pdepth) { | 
| 152 | greg | 1.1 | sprintf(buf, "%d sampling...\n", 1<<pdepth); | 
| 153 |  |  | (*dev->comout)(buf); | 
| 154 |  |  | rsample(); | 
| 155 |  |  | } else { | 
| 156 |  |  | sprintf(buf, "%d refining...\n", 1<<pdepth); | 
| 157 |  |  | (*dev->comout)(buf); | 
| 158 | greg | 1.9 | refine(&ptrunk, 0, 0, hresolu, vresolu, pdepth+1); | 
| 159 | greg | 1.1 | } | 
| 160 | greg | 1.14 | if (errno == ENOMEM)            /* ran out of memory */ | 
| 161 |  |  | freereserves(); | 
| 162 |  |  | else if (dev->inpready)         /* noticed some input */ | 
| 163 | greg | 1.1 | command(": "); | 
| 164 | greg | 1.14 | else                            /* finished this depth */ | 
| 165 | greg | 1.1 | pdepth++; | 
| 166 |  |  | } | 
| 167 |  |  | } | 
| 168 |  |  |  | 
| 169 |  |  |  | 
| 170 | greg | 1.14 | fillreserves()                  /* fill memory reserves */ | 
| 171 | greg | 1.12 | { | 
| 172 |  |  | if (reserve_mem != NULL) | 
| 173 | greg | 1.14 | return; | 
| 174 | greg | 1.12 | reserve_mem = malloc(RESERVE_AMT); | 
| 175 |  |  | } | 
| 176 |  |  |  | 
| 177 |  |  |  | 
| 178 | greg | 1.14 | freereserves()                  /* free memory reserves */ | 
| 179 | greg | 1.12 | { | 
| 180 | greg | 1.14 | if (reserve_mem == NULL) | 
| 181 |  |  | return; | 
| 182 | greg | 1.12 | free(reserve_mem); | 
| 183 |  |  | reserve_mem = NULL; | 
| 184 |  |  | } | 
| 185 |  |  |  | 
| 186 |  |  |  | 
| 187 | greg | 1.1 | command(prompt)                 /* get/execute command */ | 
| 188 |  |  | char  *prompt; | 
| 189 |  |  | { | 
| 190 | greg | 2.8 | #define  badcom(s)      strncmp(s, inpbuf, args-inpbuf-1) | 
| 191 | greg | 1.1 | char  inpbuf[256]; | 
| 192 |  |  | char  *args; | 
| 193 |  |  | again: | 
| 194 | greg | 1.10 | (*dev->comin)(inpbuf, prompt);          /* get command + arguments */ | 
| 195 | greg | 1.1 | for (args = inpbuf; *args && *args != ' '; args++) | 
| 196 |  |  | ; | 
| 197 |  |  | if (*args) *args++ = '\0'; | 
| 198 |  |  | else *++args = '\0'; | 
| 199 |  |  |  | 
| 200 |  |  | switch (inpbuf[0]) { | 
| 201 | greg | 2.10 | case 'f':                               /* new frame (or free mem.) */ | 
| 202 |  |  | if (badcom("frame")) { | 
| 203 |  |  | if (badcom("free")) | 
| 204 |  |  | goto commerr; | 
| 205 |  |  | free_objmem(); | 
| 206 |  |  | break; | 
| 207 |  |  | } | 
| 208 | greg | 1.1 | getframe(args); | 
| 209 |  |  | break; | 
| 210 |  |  | case 'v':                               /* view */ | 
| 211 |  |  | if (badcom("view")) | 
| 212 |  |  | goto commerr; | 
| 213 |  |  | getview(args); | 
| 214 |  |  | break; | 
| 215 |  |  | case 'l':                               /* last view */ | 
| 216 |  |  | if (badcom("last")) | 
| 217 |  |  | goto commerr; | 
| 218 |  |  | lastview(args); | 
| 219 | greg | 2.11 | break; | 
| 220 |  |  | case 'V':                               /* save view */ | 
| 221 |  |  | if (badcom("V")) | 
| 222 |  |  | goto commerr; | 
| 223 |  |  | saveview(args); | 
| 224 |  |  | break; | 
| 225 |  |  | case 'L':                               /* load view */ | 
| 226 |  |  | if (badcom("L")) | 
| 227 |  |  | goto commerr; | 
| 228 |  |  | loadview(args); | 
| 229 | greg | 1.1 | break; | 
| 230 |  |  | case 'e':                               /* exposure */ | 
| 231 |  |  | if (badcom("exposure")) | 
| 232 |  |  | goto commerr; | 
| 233 |  |  | getexposure(args); | 
| 234 |  |  | break; | 
| 235 |  |  | case 's':                               /* set a parameter */ | 
| 236 | greg | 2.13 | if (badcom("set")) { | 
| 237 |  |  | #ifdef  SIGTSTP | 
| 238 |  |  | if (!badcom("stop")) | 
| 239 |  |  | goto dostop; | 
| 240 |  |  | #endif | 
| 241 | greg | 1.1 | goto commerr; | 
| 242 | greg | 2.13 | } | 
| 243 | greg | 1.1 | setparam(args); | 
| 244 |  |  | break; | 
| 245 |  |  | case 'n':                               /* new picture */ | 
| 246 |  |  | if (badcom("new")) | 
| 247 |  |  | goto commerr; | 
| 248 |  |  | newimage(); | 
| 249 |  |  | break; | 
| 250 |  |  | case 't':                               /* trace a ray */ | 
| 251 |  |  | if (badcom("trace")) | 
| 252 |  |  | goto commerr; | 
| 253 |  |  | traceray(args); | 
| 254 |  |  | break; | 
| 255 |  |  | case 'a':                               /* aim camera */ | 
| 256 |  |  | if (badcom("aim")) | 
| 257 |  |  | goto commerr; | 
| 258 |  |  | getaim(args); | 
| 259 |  |  | break; | 
| 260 | greg | 2.10 | case 'm':                               /* move camera (or memstats) */ | 
| 261 | greg | 1.1 | if (badcom("move")) | 
| 262 | greg | 2.8 | #ifdef  MSTATS | 
| 263 | greg | 2.2 | { | 
| 264 |  |  | if (badcom("memory")) | 
| 265 |  |  | goto commerr; | 
| 266 |  |  | printmemstats(stderr); | 
| 267 |  |  | break; | 
| 268 |  |  | } | 
| 269 |  |  | #else | 
| 270 | greg | 1.1 | goto commerr; | 
| 271 | greg | 2.2 | #endif | 
| 272 | greg | 1.1 | getmove(args); | 
| 273 |  |  | break; | 
| 274 | greg | 1.8 | case 'r':                               /* rotate/repaint */ | 
| 275 |  |  | if (badcom("rotate")) { | 
| 276 | greg | 2.13 | if (badcom("repaint")) { | 
| 277 |  |  | if (badcom("redraw")) | 
| 278 |  |  | goto commerr; | 
| 279 |  |  | redraw(); | 
| 280 |  |  | break; | 
| 281 |  |  | } | 
| 282 | greg | 1.8 | getrepaint(args); | 
| 283 |  |  | break; | 
| 284 |  |  | } | 
| 285 | greg | 1.1 | getrotate(args); | 
| 286 |  |  | break; | 
| 287 |  |  | case 'p':                               /* pivot view */ | 
| 288 | greg | 2.13 | if (badcom("pivot")) { | 
| 289 |  |  | if (badcom("pause")) | 
| 290 |  |  | goto commerr; | 
| 291 |  |  | goto again; | 
| 292 |  |  | } | 
| 293 | greg | 1.1 | getpivot(args); | 
| 294 |  |  | break; | 
| 295 | greg | 2.4 | case CTRL('R'):                         /* redraw */ | 
| 296 | greg | 1.1 | redraw(); | 
| 297 |  |  | break; | 
| 298 |  |  | case 'w':                               /* write */ | 
| 299 |  |  | if (badcom("write")) | 
| 300 |  |  | goto commerr; | 
| 301 |  |  | writepict(args); | 
| 302 |  |  | break; | 
| 303 |  |  | case 'q':                               /* quit */ | 
| 304 |  |  | if (badcom("quit")) | 
| 305 |  |  | goto commerr; | 
| 306 |  |  | quit(0); | 
| 307 | greg | 2.4 | case CTRL('C'):                         /* interrupt */ | 
| 308 | greg | 1.1 | goto again; | 
| 309 | greg | 2.8 | #ifdef  SIGTSTP | 
| 310 | greg | 2.13 | case CTRL('Z'):;                        /* stop */ | 
| 311 |  |  | dostop: | 
| 312 | greg | 1.1 | devclose(); | 
| 313 |  |  | kill(0, SIGTSTP); | 
| 314 |  |  | /* pc stops here */ | 
| 315 |  |  | devopen(devname); | 
| 316 |  |  | redraw(); | 
| 317 |  |  | break; | 
| 318 |  |  | #endif | 
| 319 |  |  | case '\0':                              /* continue */ | 
| 320 |  |  | break; | 
| 321 |  |  | default:; | 
| 322 |  |  | commerr: | 
| 323 |  |  | if (iscntrl(inpbuf[0])) | 
| 324 |  |  | sprintf(errmsg, "^%c: unknown control", | 
| 325 |  |  | inpbuf[0]|0100); | 
| 326 |  |  | else | 
| 327 |  |  | sprintf(errmsg, "%s: unknown command", inpbuf); | 
| 328 |  |  | error(COMMAND, errmsg); | 
| 329 |  |  | break; | 
| 330 |  |  | } | 
| 331 | greg | 2.8 | #undef  badcom | 
| 332 | greg | 1.1 | } | 
| 333 |  |  |  | 
| 334 |  |  |  | 
| 335 |  |  | rsample()                       /* sample the image */ | 
| 336 |  |  | { | 
| 337 |  |  | int  xsiz, ysiz, y; | 
| 338 |  |  | RECT  r; | 
| 339 |  |  | PNODE  *p; | 
| 340 |  |  | register RECT  *rl; | 
| 341 | greg | 2.8 | register PNODE  **pl; | 
| 342 | greg | 1.1 | register int  x; | 
| 343 |  |  | /* | 
| 344 |  |  | *     We initialize the bottom row in the image at our current | 
| 345 | greg | 2.8 | * resolution.  During sampling, we check super-pixels to the | 
| 346 | greg | 1.1 | * right and above by calling bigdiff().  If there is a significant | 
| 347 |  |  | * difference, we subsample the super-pixels.  The testing process | 
| 348 |  |  | * includes initialization of the next row. | 
| 349 |  |  | */ | 
| 350 | greg | 2.12 | xsiz = (((long)(pframe.r-pframe.l)<<pdepth)+hresolu-1) / hresolu; | 
| 351 |  |  | ysiz = (((long)(pframe.u-pframe.d)<<pdepth)+vresolu-1) / vresolu; | 
| 352 | greg | 1.1 | rl = (RECT *)malloc(xsiz*sizeof(RECT)); | 
| 353 | greg | 1.12 | if (rl == NULL) | 
| 354 | greg | 1.14 | return; | 
| 355 | greg | 1.1 | pl = (PNODE **)malloc(xsiz*sizeof(PNODE *)); | 
| 356 | greg | 2.7 | if (pl == NULL) { | 
| 357 |  |  | free((char *)rl); | 
| 358 | greg | 1.14 | return; | 
| 359 | greg | 2.7 | } | 
| 360 | greg | 1.1 | /* | 
| 361 |  |  | * Initialize the bottom row. | 
| 362 |  |  | */ | 
| 363 |  |  | rl[0].l = rl[0].d = 0; | 
| 364 | greg | 1.9 | rl[0].r = hresolu; rl[0].u = vresolu; | 
| 365 | greg | 1.1 | pl[0] = findrect(pframe.l, pframe.d, &ptrunk, rl, pdepth); | 
| 366 |  |  | for (x = 1; x < xsiz; x++) { | 
| 367 |  |  | rl[x].l = rl[x].d = 0; | 
| 368 | greg | 1.9 | rl[x].r = hresolu; rl[x].u = vresolu; | 
| 369 |  |  | pl[x] = findrect(pframe.l+((x*hresolu)>>pdepth), | 
| 370 | greg | 1.1 | pframe.d, &ptrunk, rl+x, pdepth); | 
| 371 |  |  | } | 
| 372 |  |  | /* sample the image */ | 
| 373 |  |  | for (y = 0; /* y < ysiz */ ; y++) { | 
| 374 |  |  | for (x = 0; x < xsiz-1; x++) { | 
| 375 | greg | 1.20 | if (dev->inpready || errno == ENOMEM) | 
| 376 | greg | 1.1 | goto escape; | 
| 377 |  |  | /* | 
| 378 |  |  | * Test super-pixel to the right. | 
| 379 |  |  | */ | 
| 380 |  |  | if (pl[x] != pl[x+1] && bigdiff(pl[x]->v, | 
| 381 |  |  | pl[x+1]->v, maxdiff)) { | 
| 382 |  |  | refine(pl[x], rl[x].l, rl[x].d, | 
| 383 |  |  | rl[x].r, rl[x].u, 1); | 
| 384 |  |  | refine(pl[x+1], rl[x+1].l, rl[x+1].d, | 
| 385 |  |  | rl[x+1].r, rl[x+1].u, 1); | 
| 386 |  |  | } | 
| 387 |  |  | } | 
| 388 |  |  | if (y >= ysiz-1) | 
| 389 |  |  | break; | 
| 390 |  |  | for (x = 0; x < xsiz; x++) { | 
| 391 | greg | 1.20 | if (dev->inpready || errno == ENOMEM) | 
| 392 | greg | 1.1 | goto escape; | 
| 393 |  |  | /* | 
| 394 |  |  | * Find super-pixel at this position in next row. | 
| 395 |  |  | */ | 
| 396 |  |  | r.l = r.d = 0; | 
| 397 | greg | 1.9 | r.r = hresolu; r.u = vresolu; | 
| 398 |  |  | p = findrect(pframe.l+((x*hresolu)>>pdepth), | 
| 399 |  |  | pframe.d+(((y+1)*vresolu)>>pdepth), | 
| 400 | greg | 1.1 | &ptrunk, &r, pdepth); | 
| 401 |  |  | /* | 
| 402 |  |  | * Test super-pixel in next row. | 
| 403 |  |  | */ | 
| 404 |  |  | if (pl[x] != p && bigdiff(pl[x]->v, p->v, maxdiff)) { | 
| 405 |  |  | refine(pl[x], rl[x].l, rl[x].d, | 
| 406 |  |  | rl[x].r, rl[x].u, 1); | 
| 407 |  |  | refine(p, r.l, r.d, r.r, r.u, 1); | 
| 408 |  |  | } | 
| 409 |  |  | /* | 
| 410 |  |  | * Copy into super-pixel array. | 
| 411 |  |  | */ | 
| 412 |  |  | rl[x].l = r.l; rl[x].d = r.d; | 
| 413 |  |  | rl[x].r = r.r; rl[x].u = r.u; | 
| 414 |  |  | pl[x] = p; | 
| 415 |  |  | } | 
| 416 |  |  | } | 
| 417 |  |  | escape: | 
| 418 |  |  | free((char *)rl); | 
| 419 |  |  | free((char *)pl); | 
| 420 |  |  | } | 
| 421 |  |  |  | 
| 422 |  |  |  | 
| 423 |  |  | int | 
| 424 |  |  | refine(p, xmin, ymin, xmax, ymax, pd)           /* refine a node */ | 
| 425 | greg | 2.8 | register PNODE  *p; | 
| 426 | greg | 1.1 | int  xmin, ymin, xmax, ymax; | 
| 427 |  |  | int  pd; | 
| 428 |  |  | { | 
| 429 |  |  | int  growth; | 
| 430 |  |  | int  mx, my; | 
| 431 |  |  | int  i; | 
| 432 |  |  |  | 
| 433 |  |  | if (dev->inpready)                      /* quit for input */ | 
| 434 |  |  | return(0); | 
| 435 |  |  |  | 
| 436 |  |  | if (pd <= 0)                            /* depth limit */ | 
| 437 |  |  | return(0); | 
| 438 |  |  |  | 
| 439 |  |  | mx = (xmin + xmax) >> 1; | 
| 440 |  |  | my = (ymin + ymax) >> 1; | 
| 441 |  |  | growth = 0; | 
| 442 |  |  |  | 
| 443 |  |  | if (p->kid == NULL) {                   /* subdivide */ | 
| 444 |  |  |  | 
| 445 |  |  | if ((p->kid = newptree()) == NULL) | 
| 446 | greg | 1.20 | return(0); | 
| 447 | greg | 1.1 | /* | 
| 448 |  |  | *  The following paint order can leave a black pixel | 
| 449 | greg | 2.7 | *  if redraw() is called in (*dev->paintr)(). | 
| 450 | greg | 1.1 | */ | 
| 451 |  |  | if (p->x >= mx && p->y >= my) | 
| 452 |  |  | pcopy(p, p->kid+UR); | 
| 453 |  |  | else | 
| 454 |  |  | paint(p->kid+UR, mx, my, xmax, ymax); | 
| 455 |  |  | if (p->x < mx && p->y >= my) | 
| 456 |  |  | pcopy(p, p->kid+UL); | 
| 457 |  |  | else | 
| 458 |  |  | paint(p->kid+UL, xmin, my, mx, ymax); | 
| 459 |  |  | if (p->x >= mx && p->y < my) | 
| 460 |  |  | pcopy(p, p->kid+DR); | 
| 461 |  |  | else | 
| 462 |  |  | paint(p->kid+DR, mx, ymin, xmax, my); | 
| 463 |  |  | if (p->x < mx && p->y < my) | 
| 464 |  |  | pcopy(p, p->kid+DL); | 
| 465 |  |  | else | 
| 466 |  |  | paint(p->kid+DL, xmin, ymin, mx, my); | 
| 467 |  |  |  | 
| 468 |  |  | growth++; | 
| 469 |  |  | } | 
| 470 |  |  | /* do children */ | 
| 471 |  |  | if (mx > pframe.l) { | 
| 472 |  |  | if (my > pframe.d) | 
| 473 |  |  | growth += refine(p->kid+DL, xmin, ymin, mx, my, pd-1); | 
| 474 |  |  | if (my < pframe.u) | 
| 475 |  |  | growth += refine(p->kid+UL, xmin, my, mx, ymax, pd-1); | 
| 476 |  |  | } | 
| 477 |  |  | if (mx < pframe.r) { | 
| 478 |  |  | if (my > pframe.d) | 
| 479 |  |  | growth += refine(p->kid+DR, mx, ymin, xmax, my, pd-1); | 
| 480 |  |  | if (my < pframe.u) | 
| 481 |  |  | growth += refine(p->kid+UR, mx, my, xmax, ymax, pd-1); | 
| 482 |  |  | } | 
| 483 |  |  | /* recompute sum */ | 
| 484 |  |  | if (growth) { | 
| 485 |  |  | setcolor(p->v, 0.0, 0.0, 0.0); | 
| 486 |  |  | for (i = 0; i < 4; i++) | 
| 487 |  |  | addcolor(p->v, p->kid[i].v); | 
| 488 |  |  | scalecolor(p->v, 0.25); | 
| 489 |  |  | } | 
| 490 |  |  | return(growth); | 
| 491 |  |  | } |