| 1 | greg | 1.1 | /* Copyright (c) 1986 Regents of the University of California */ | 
| 2 |  |  |  | 
| 3 |  |  | #ifndef lint | 
| 4 |  |  | static char SCCSid[] = "$SunId$ LBL"; | 
| 5 |  |  | #endif | 
| 6 |  |  |  | 
| 7 |  |  | /* | 
| 8 |  |  | *  rpict.c - routines and variables for picture generation. | 
| 9 |  |  | * | 
| 10 |  |  | *     8/14/85 | 
| 11 |  |  | */ | 
| 12 |  |  |  | 
| 13 |  |  | #include  "ray.h" | 
| 14 |  |  |  | 
| 15 |  |  | #ifdef BSD | 
| 16 |  |  | #include  <sys/time.h> | 
| 17 |  |  | #include  <sys/resource.h> | 
| 18 | greg | 1.14 | #else | 
| 19 |  |  | #include  <signal.h> | 
| 20 | greg | 1.1 | #endif | 
| 21 | greg | 1.16 | #include  <sys/fcntl.h> | 
| 22 | greg | 1.1 |  | 
| 23 |  |  | #include  "view.h" | 
| 24 |  |  |  | 
| 25 |  |  | #include  "random.h" | 
| 26 |  |  |  | 
| 27 | greg | 1.12 | VIEW  ourview = STDVIEW;                /* view parameters */ | 
| 28 |  |  | int  hresolu = 512;                     /* horizontal resolution */ | 
| 29 |  |  | int  vresolu = 512;                     /* vertical resolution */ | 
| 30 | greg | 1.13 | double  pixaspect = 1.0;                /* pixel aspect ratio */ | 
| 31 | greg | 1.1 |  | 
| 32 |  |  | int  psample = 4;                       /* pixel sample size */ | 
| 33 |  |  | double  maxdiff = .05;                  /* max. difference for interpolation */ | 
| 34 | greg | 1.3 | double  dstrpix = 0.67;                 /* square pixel distribution */ | 
| 35 | greg | 1.1 |  | 
| 36 |  |  | double  dstrsrc = 0.0;                  /* square source distribution */ | 
| 37 | greg | 1.4 | double  shadthresh = .05;               /* shadow threshold */ | 
| 38 | greg | 1.5 | double  shadcert = .5;                  /* shadow certainty */ | 
| 39 | greg | 1.1 |  | 
| 40 |  |  | int  maxdepth = 6;                      /* maximum recursion depth */ | 
| 41 |  |  | double  minweight = 5e-3;               /* minimum ray weight */ | 
| 42 |  |  |  | 
| 43 |  |  | COLOR  ambval = BLKCOLOR;               /* ambient value */ | 
| 44 |  |  | double  ambacc = 0.2;                   /* ambient accuracy */ | 
| 45 | greg | 1.6 | int  ambres = 32;                       /* ambient resolution */ | 
| 46 | greg | 1.1 | int  ambdiv = 128;                      /* ambient divisions */ | 
| 47 |  |  | int  ambssamp = 0;                      /* ambient super-samples */ | 
| 48 |  |  | int  ambounce = 0;                      /* ambient bounces */ | 
| 49 |  |  | char  *amblist[128];                    /* ambient include/exclude list */ | 
| 50 |  |  | int  ambincl = -1;                      /* include == 1, exclude == 0 */ | 
| 51 |  |  |  | 
| 52 |  |  | int  ralrm = 0;                         /* seconds between reports */ | 
| 53 |  |  |  | 
| 54 |  |  | double  pctdone = 0.0;                  /* percentage done */ | 
| 55 |  |  |  | 
| 56 |  |  | extern long  nrays;                     /* number of rays traced */ | 
| 57 |  |  |  | 
| 58 |  |  | #define  MAXDIV         32              /* maximum sample size */ | 
| 59 |  |  |  | 
| 60 |  |  | #define  pixjitter()    (.5+dstrpix*(.5-frandom())) | 
| 61 |  |  |  | 
| 62 | greg | 1.11 | double  pixvalue(); | 
| 63 | greg | 1.1 |  | 
| 64 | greg | 1.11 |  | 
| 65 | greg | 1.1 | quit(code)                      /* quit program */ | 
| 66 |  |  | int  code; | 
| 67 |  |  | { | 
| 68 |  |  | if (code || ralrm > 0)          /* report status */ | 
| 69 |  |  | report(); | 
| 70 |  |  |  | 
| 71 |  |  | exit(code); | 
| 72 |  |  | } | 
| 73 |  |  |  | 
| 74 |  |  |  | 
| 75 |  |  | report()                /* report progress */ | 
| 76 |  |  | { | 
| 77 |  |  | #ifdef BSD | 
| 78 |  |  | struct rusage  rubuf; | 
| 79 |  |  | double  t; | 
| 80 |  |  |  | 
| 81 |  |  | getrusage(RUSAGE_SELF, &rubuf); | 
| 82 |  |  | t = (rubuf.ru_utime.tv_usec + rubuf.ru_stime.tv_usec) / 1e6; | 
| 83 |  |  | t += rubuf.ru_utime.tv_sec + rubuf.ru_stime.tv_sec; | 
| 84 |  |  | getrusage(RUSAGE_CHILDREN, &rubuf); | 
| 85 |  |  | t += (rubuf.ru_utime.tv_usec + rubuf.ru_stime.tv_usec) / 1e6; | 
| 86 |  |  | t += rubuf.ru_utime.tv_sec + rubuf.ru_stime.tv_sec; | 
| 87 |  |  |  | 
| 88 |  |  | sprintf(errmsg, "%ld rays, %4.2f%% done after %5.4f CPU hours\n", | 
| 89 |  |  | nrays, pctdone, t/3600.0); | 
| 90 |  |  | #else | 
| 91 | greg | 1.14 | signal(SIGALRM, report); | 
| 92 | greg | 1.1 | sprintf(errmsg, "%ld rays, %4.2f%% done\n", nrays, pctdone); | 
| 93 |  |  | #endif | 
| 94 |  |  | eputs(errmsg); | 
| 95 |  |  |  | 
| 96 |  |  | if (ralrm > 0) | 
| 97 |  |  | alarm(ralrm); | 
| 98 |  |  | } | 
| 99 |  |  |  | 
| 100 |  |  |  | 
| 101 | greg | 1.11 | render(zfile, oldfile)                          /* render the scene */ | 
| 102 |  |  | char  *zfile, *oldfile; | 
| 103 | greg | 1.1 | { | 
| 104 | greg | 1.16 | extern long  lseek(); | 
| 105 | greg | 1.1 | COLOR  *scanbar[MAXDIV+1];      /* scanline arrays of pixel values */ | 
| 106 | greg | 1.11 | float  *zbar[MAXDIV+1];         /* z values */ | 
| 107 | greg | 1.1 | int  ypos;                      /* current scanline */ | 
| 108 | greg | 1.15 | int  ystep;                     /* current y step size */ | 
| 109 | greg | 1.16 | int  zfd; | 
| 110 | greg | 1.1 | COLOR  *colptr; | 
| 111 | greg | 1.11 | float  *zptr; | 
| 112 | greg | 1.1 | register int  i; | 
| 113 | greg | 1.10 | /* check sampling */ | 
| 114 |  |  | if (psample < 1) | 
| 115 | greg | 1.1 | psample = 1; | 
| 116 | greg | 1.10 | else if (psample > MAXDIV) | 
| 117 |  |  | psample = MAXDIV; | 
| 118 | greg | 1.9 | /* allocate scanlines */ | 
| 119 | greg | 1.1 | for (i = 0; i <= psample; i++) { | 
| 120 | greg | 1.12 | scanbar[i] = (COLOR *)malloc(hresolu*sizeof(COLOR)); | 
| 121 | greg | 1.1 | if (scanbar[i] == NULL) | 
| 122 | greg | 1.11 | goto memerr; | 
| 123 | greg | 1.1 | } | 
| 124 | greg | 1.11 | /* open z file */ | 
| 125 |  |  | if (zfile != NULL) { | 
| 126 | greg | 1.16 | if ((zfd = open(zfile, O_WRONLY|O_CREAT, 0666)) == -1) { | 
| 127 | greg | 1.11 | sprintf(errmsg, "cannot open z file \"%s\"", zfile); | 
| 128 |  |  | error(SYSTEM, errmsg); | 
| 129 |  |  | } | 
| 130 |  |  | for (i = 0; i <= psample; i++) { | 
| 131 | greg | 1.12 | zbar[i] = (float *)malloc(hresolu*sizeof(float)); | 
| 132 | greg | 1.11 | if (zbar[i] == NULL) | 
| 133 |  |  | goto memerr; | 
| 134 |  |  | } | 
| 135 |  |  | } else { | 
| 136 | greg | 1.16 | zfd = -1; | 
| 137 | greg | 1.11 | for (i = 0; i <= psample; i++) | 
| 138 |  |  | zbar[i] = NULL; | 
| 139 |  |  | } | 
| 140 | greg | 1.1 | /* write out boundaries */ | 
| 141 | greg | 1.12 | fputresolu(YMAJOR|YDECR, hresolu, vresolu, stdout); | 
| 142 | greg | 1.10 | /* recover file and compute first */ | 
| 143 | greg | 1.11 | i = salvage(oldfile); | 
| 144 | greg | 1.16 | if (zfd != -1 && lseek(zfd, (long)i*hresolu*sizeof(float), 0) == -1) | 
| 145 | greg | 1.11 | error(SYSTEM, "z file seek error in render"); | 
| 146 | greg | 1.12 | ypos = vresolu-1 - i; | 
| 147 |  |  | fillscanline(scanbar[0], zbar[0], hresolu, ypos, psample); | 
| 148 | greg | 1.15 | ystep = psample; | 
| 149 | greg | 1.10 | /* compute scanlines */ | 
| 150 | greg | 1.15 | for (ypos -= ystep; ypos > -ystep; ypos -= ystep) { | 
| 151 |  |  | /* record progress */ | 
| 152 |  |  | pctdone = 100.0*(vresolu-ypos-ystep)/vresolu; | 
| 153 |  |  | /* bottom adjust? */ | 
| 154 |  |  | if (ypos < 0) { | 
| 155 |  |  | ystep += ypos; | 
| 156 |  |  | ypos = 0; | 
| 157 |  |  | } | 
| 158 |  |  | colptr = scanbar[ystep];                /* move base to top */ | 
| 159 |  |  | scanbar[ystep] = scanbar[0]; | 
| 160 | greg | 1.1 | scanbar[0] = colptr; | 
| 161 | greg | 1.15 | zptr = zbar[ystep]; | 
| 162 |  |  | zbar[ystep] = zbar[0]; | 
| 163 | greg | 1.11 | zbar[0] = zptr; | 
| 164 | greg | 1.10 | /* fill base line */ | 
| 165 | greg | 1.12 | fillscanline(scanbar[0], zbar[0], hresolu, ypos, psample); | 
| 166 | greg | 1.10 | /* fill bar */ | 
| 167 | greg | 1.15 | fillscanbar(scanbar, zbar, hresolu, ypos, ystep); | 
| 168 | greg | 1.10 | /* write it out */ | 
| 169 | greg | 1.15 | for (i = ystep; i > 0; i--) { | 
| 170 | greg | 1.16 | if (zfd!=-1 && write(zfd,zbar[i],hresolu*sizeof(float)) | 
| 171 |  |  | < hresolu*sizeof(float)) | 
| 172 | greg | 1.1 | goto writerr; | 
| 173 | greg | 1.12 | if (fwritescan(scanbar[i],hresolu,stdout) < 0) | 
| 174 | greg | 1.11 | goto writerr; | 
| 175 |  |  | } | 
| 176 | greg | 1.1 | if (fflush(stdout) == EOF) | 
| 177 |  |  | goto writerr; | 
| 178 |  |  | } | 
| 179 | greg | 1.11 | /* clean up */ | 
| 180 | greg | 1.16 | if (zfd != -1) { | 
| 181 |  |  | if (write(zfd,zbar[0],hresolu*sizeof(float)) | 
| 182 |  |  | < hresolu*sizeof(float)) | 
| 183 | greg | 1.11 | goto writerr; | 
| 184 | greg | 1.16 | close(zfd); | 
| 185 | greg | 1.11 | for (i = 0; i <= psample; i++) | 
| 186 |  |  | free((char *)zbar[i]); | 
| 187 |  |  | } | 
| 188 | greg | 1.15 | fwritescan(scanbar[0], hresolu, stdout); | 
| 189 | greg | 1.10 | if (fflush(stdout) == EOF) | 
| 190 |  |  | goto writerr; | 
| 191 | greg | 1.1 | for (i = 0; i <= psample; i++) | 
| 192 |  |  | free((char *)scanbar[i]); | 
| 193 | greg | 1.11 | pctdone = 100.0; | 
| 194 | greg | 1.1 | return; | 
| 195 |  |  | writerr: | 
| 196 |  |  | error(SYSTEM, "write error in render"); | 
| 197 | greg | 1.11 | memerr: | 
| 198 |  |  | error(SYSTEM, "out of memory in render"); | 
| 199 | greg | 1.1 | } | 
| 200 |  |  |  | 
| 201 |  |  |  | 
| 202 | greg | 1.11 | fillscanline(scanline, zline, xres, y, xstep)   /* fill scan line at y */ | 
| 203 | greg | 1.1 | register COLOR  *scanline; | 
| 204 | greg | 1.11 | register float  *zline; | 
| 205 | greg | 1.9 | int  xres, y, xstep; | 
| 206 | greg | 1.1 | { | 
| 207 |  |  | int  b = xstep; | 
| 208 | greg | 1.11 | double  z; | 
| 209 | greg | 1.1 | register int  i; | 
| 210 |  |  |  | 
| 211 | greg | 1.11 | z = pixvalue(scanline[0], 0, y); | 
| 212 |  |  | if (zline) zline[0] = z; | 
| 213 | greg | 1.1 |  | 
| 214 | greg | 1.15 | for (i = xstep; i < xres-1+xstep; i += xstep) { | 
| 215 |  |  | if (i >= xres) { | 
| 216 |  |  | xstep += xres-1-i; | 
| 217 |  |  | i = xres-1; | 
| 218 |  |  | } | 
| 219 | greg | 1.11 | z = pixvalue(scanline[i], i, y); | 
| 220 |  |  | if (zline) zline[i] = z; | 
| 221 | greg | 1.1 |  | 
| 222 | greg | 1.11 | b = fillsample(scanline+i-xstep, zline ? zline+i-xstep : NULL, | 
| 223 |  |  | i-xstep, y, xstep, 0, b/2); | 
| 224 | greg | 1.1 | } | 
| 225 |  |  | } | 
| 226 |  |  |  | 
| 227 |  |  |  | 
| 228 | greg | 1.11 | fillscanbar(scanbar, zbar, xres, y, ysize)      /* fill interior */ | 
| 229 | greg | 1.1 | register COLOR  *scanbar[]; | 
| 230 | greg | 1.11 | register float  *zbar[]; | 
| 231 | greg | 1.9 | int  xres, y, ysize; | 
| 232 | greg | 1.1 | { | 
| 233 |  |  | COLOR  vline[MAXDIV+1]; | 
| 234 | greg | 1.11 | float  zline[MAXDIV+1]; | 
| 235 | greg | 1.1 | int  b = ysize; | 
| 236 | greg | 1.11 | double  z; | 
| 237 | greg | 1.1 | register int  i, j; | 
| 238 |  |  |  | 
| 239 | greg | 1.8 | for (i = 0; i < xres; i++) { | 
| 240 | greg | 1.1 |  | 
| 241 |  |  | copycolor(vline[0], scanbar[0][i]); | 
| 242 |  |  | copycolor(vline[ysize], scanbar[ysize][i]); | 
| 243 | greg | 1.11 | if (zbar[0]) { | 
| 244 |  |  | zline[0] = zbar[0][i]; | 
| 245 |  |  | zline[ysize] = zbar[ysize][i]; | 
| 246 |  |  | } | 
| 247 | greg | 1.1 |  | 
| 248 | greg | 1.11 | b = fillsample(vline, zbar[0] ? zline : NULL, | 
| 249 |  |  | i, y, 0, ysize, b/2); | 
| 250 | greg | 1.1 |  | 
| 251 |  |  | for (j = 1; j < ysize; j++) | 
| 252 |  |  | copycolor(scanbar[j][i], vline[j]); | 
| 253 | greg | 1.11 | if (zbar[0]) | 
| 254 |  |  | for (j = 1; j < ysize; j++) | 
| 255 |  |  | zbar[j][i] = zline[j]; | 
| 256 | greg | 1.1 | } | 
| 257 |  |  | } | 
| 258 |  |  |  | 
| 259 |  |  |  | 
| 260 |  |  | int | 
| 261 | greg | 1.11 | fillsample(colline, zline, x, y, xlen, ylen, b) /* fill interior points */ | 
| 262 | greg | 1.1 | register COLOR  *colline; | 
| 263 | greg | 1.11 | register float  *zline; | 
| 264 | greg | 1.1 | int  x, y; | 
| 265 |  |  | int  xlen, ylen; | 
| 266 |  |  | int  b; | 
| 267 |  |  | { | 
| 268 | greg | 1.11 | extern double  fabs(); | 
| 269 | greg | 1.1 | double  ratio; | 
| 270 | greg | 1.11 | double  z; | 
| 271 | greg | 1.1 | COLOR  ctmp; | 
| 272 |  |  | int  ncut; | 
| 273 |  |  | register int  len; | 
| 274 |  |  |  | 
| 275 |  |  | if (xlen > 0)                   /* x or y length is zero */ | 
| 276 |  |  | len = xlen; | 
| 277 |  |  | else | 
| 278 |  |  | len = ylen; | 
| 279 |  |  |  | 
| 280 |  |  | if (len <= 1)                   /* limit recursion */ | 
| 281 |  |  | return(0); | 
| 282 |  |  |  | 
| 283 | greg | 1.11 | if (b > 0 | 
| 284 |  |  | || (zline && 2.*fabs(zline[0]-zline[len]) > maxdiff*(zline[0]+zline[len])) | 
| 285 |  |  | || bigdiff(colline[0], colline[len], maxdiff)) { | 
| 286 | greg | 1.1 |  | 
| 287 | greg | 1.11 | z = pixvalue(colline[len>>1], x + (xlen>>1), y + (ylen>>1)); | 
| 288 |  |  | if (zline) zline[len>>1] = z; | 
| 289 | greg | 1.1 | ncut = 1; | 
| 290 |  |  |  | 
| 291 |  |  | } else {                                        /* interpolate */ | 
| 292 |  |  |  | 
| 293 |  |  | copycolor(colline[len>>1], colline[len]); | 
| 294 |  |  | ratio = (double)(len>>1) / len; | 
| 295 |  |  | scalecolor(colline[len>>1], ratio); | 
| 296 | greg | 1.11 | if (zline) zline[len>>1] = zline[len] * ratio; | 
| 297 |  |  | ratio = 1.0 - ratio; | 
| 298 | greg | 1.1 | copycolor(ctmp, colline[0]); | 
| 299 |  |  | scalecolor(ctmp, ratio); | 
| 300 |  |  | addcolor(colline[len>>1], ctmp); | 
| 301 | greg | 1.11 | if (zline) zline[len>>1] += zline[0] * ratio; | 
| 302 | greg | 1.1 | ncut = 0; | 
| 303 |  |  | } | 
| 304 |  |  | /* recurse */ | 
| 305 | greg | 1.11 | ncut += fillsample(colline, zline, x, y, xlen>>1, ylen>>1, (b-1)/2); | 
| 306 | greg | 1.1 |  | 
| 307 | greg | 1.11 | ncut += fillsample(colline+(len>>1), zline ? zline+(len>>1) : NULL, | 
| 308 |  |  | x+(xlen>>1), y+(ylen>>1), | 
| 309 |  |  | xlen-(xlen>>1), ylen-(ylen>>1), b/2); | 
| 310 | greg | 1.1 |  | 
| 311 |  |  | return(ncut); | 
| 312 |  |  | } | 
| 313 |  |  |  | 
| 314 |  |  |  | 
| 315 | greg | 1.11 | double | 
| 316 | greg | 1.1 | pixvalue(col, x, y)             /* compute pixel value */ | 
| 317 |  |  | COLOR  col;                     /* returned color */ | 
| 318 |  |  | int  x, y;                      /* pixel position */ | 
| 319 |  |  | { | 
| 320 |  |  | static RAY  thisray;    /* our ray for this pixel */ | 
| 321 |  |  |  | 
| 322 | greg | 1.12 | viewray(thisray.rorg, thisray.rdir, &ourview, | 
| 323 |  |  | (x+pixjitter())/hresolu, (y+pixjitter())/vresolu); | 
| 324 | greg | 1.1 |  | 
| 325 |  |  | rayorigin(&thisray, NULL, PRIMARY, 1.0); | 
| 326 |  |  |  | 
| 327 |  |  | rayvalue(&thisray);                     /* trace ray */ | 
| 328 |  |  |  | 
| 329 |  |  | copycolor(col, thisray.rcol);           /* return color */ | 
| 330 | greg | 1.11 |  | 
| 331 |  |  | return(thisray.rot);                    /* return distance */ | 
| 332 | greg | 1.1 | } | 
| 333 |  |  |  | 
| 334 |  |  |  | 
| 335 |  |  | int | 
| 336 |  |  | salvage(oldfile)                /* salvage scanlines from killed program */ | 
| 337 |  |  | char  *oldfile; | 
| 338 |  |  | { | 
| 339 |  |  | COLR  *scanline; | 
| 340 |  |  | FILE  *fp; | 
| 341 |  |  | int  x, y; | 
| 342 |  |  |  | 
| 343 |  |  | if (oldfile == NULL) | 
| 344 |  |  | return(0); | 
| 345 | greg | 1.9 |  | 
| 346 |  |  | if ((fp = fopen(oldfile, "r")) == NULL) { | 
| 347 | greg | 1.1 | sprintf(errmsg, "cannot open recover file \"%s\"", oldfile); | 
| 348 |  |  | error(WARNING, errmsg); | 
| 349 |  |  | return(0); | 
| 350 |  |  | } | 
| 351 |  |  | /* discard header */ | 
| 352 |  |  | getheader(fp, NULL); | 
| 353 |  |  | /* get picture size */ | 
| 354 | greg | 1.7 | if (fgetresolu(&x, &y, fp) != (YMAJOR|YDECR)) { | 
| 355 | greg | 1.2 | sprintf(errmsg, "bad recover file \"%s\"", oldfile); | 
| 356 |  |  | error(WARNING, errmsg); | 
| 357 | greg | 1.1 | fclose(fp); | 
| 358 |  |  | return(0); | 
| 359 |  |  | } | 
| 360 |  |  |  | 
| 361 | greg | 1.12 | if (x != hresolu || y != vresolu) { | 
| 362 | greg | 1.1 | sprintf(errmsg, "resolution mismatch in recover file \"%s\"", | 
| 363 |  |  | oldfile); | 
| 364 |  |  | error(USER, errmsg); | 
| 365 |  |  | } | 
| 366 |  |  |  | 
| 367 | greg | 1.12 | scanline = (COLR *)malloc(hresolu*sizeof(COLR)); | 
| 368 | greg | 1.1 | if (scanline == NULL) | 
| 369 |  |  | error(SYSTEM, "out of memory in salvage"); | 
| 370 | greg | 1.12 | for (y = 0; y < vresolu; y++) { | 
| 371 |  |  | if (freadcolrs(scanline, hresolu, fp) < 0) | 
| 372 | greg | 1.1 | break; | 
| 373 | greg | 1.12 | if (fwritecolrs(scanline, hresolu, stdout) < 0) | 
| 374 | greg | 1.1 | goto writerr; | 
| 375 |  |  | } | 
| 376 |  |  | if (fflush(stdout) == EOF) | 
| 377 |  |  | goto writerr; | 
| 378 |  |  | free((char *)scanline); | 
| 379 |  |  | fclose(fp); | 
| 380 |  |  | unlink(oldfile); | 
| 381 |  |  | return(y); | 
| 382 |  |  | writerr: | 
| 383 |  |  | error(SYSTEM, "write error in salvage"); | 
| 384 |  |  | } |