| 1 | gwlarson | 3.1 | #ifndef lint | 
| 2 | schorsch | 3.14 | static const char       RCSid[] = "$Id: rhpict.c,v 3.13 2003/07/21 22:30:18 schorsch Exp $"; | 
| 3 | gwlarson | 3.1 | #endif | 
| 4 |  |  | /* | 
| 5 |  |  | * Radiance holodeck picture generator | 
| 6 |  |  | */ | 
| 7 |  |  |  | 
| 8 | schorsch | 3.11 | #include <string.h> | 
| 9 |  |  |  | 
| 10 | gwlarson | 3.1 | #include "rholo.h" | 
| 11 |  |  | #include "view.h" | 
| 12 |  |  |  | 
| 13 |  |  | char    *progname;              /* our program name */ | 
| 14 |  |  | char    *hdkfile;               /* holodeck file name */ | 
| 15 | gwlarson | 3.7 | char    gargc;                  /* global argc */ | 
| 16 |  |  | char    **gargv;                /* global argv */ | 
| 17 | gwlarson | 3.1 |  | 
| 18 |  |  | VIEW    myview = STDVIEW;       /* current output view */ | 
| 19 |  |  | int     xres = 512, yres = 512; /* max. horizontal and vertical resolution */ | 
| 20 |  |  | char    *outspec = NULL;        /* output file specification */ | 
| 21 | gwlarson | 3.6 | double  randfrac = -1.;         /* random resampling fraction */ | 
| 22 | gwlarson | 3.1 | double  pixaspect = 1.;         /* pixel aspect ratio */ | 
| 23 |  |  | int     seqstart = 0;           /* sequence start frame */ | 
| 24 |  |  | double  expval = 1.;            /* exposure value */ | 
| 25 |  |  |  | 
| 26 |  |  | COLOR   *mypixel;               /* pixels being rendered */ | 
| 27 |  |  | float   *myweight;              /* weights (used to compute final pixels) */ | 
| 28 | gwlarson | 3.2 | float   *mydepth;               /* depth values (visibility culling) */ | 
| 29 | gwlarson | 3.1 | int     hres, vres;             /* current horizontal and vertical res. */ | 
| 30 |  |  |  | 
| 31 |  |  | extern int      nowarn;         /* turn warnings off? */ | 
| 32 |  |  |  | 
| 33 |  |  |  | 
| 34 |  |  | main(argc, argv) | 
| 35 |  |  | int     argc; | 
| 36 |  |  | char    *argv[]; | 
| 37 |  |  | { | 
| 38 |  |  | int     i, rval; | 
| 39 |  |  |  | 
| 40 | gwlarson | 3.7 | gargc = argc; gargv = argv; | 
| 41 | gwlarson | 3.1 | progname = argv[0];                     /* get arguments */ | 
| 42 |  |  | for (i = 1; i < argc && argv[i][0] == '-'; i++) { | 
| 43 |  |  | rval = getviewopt(&myview, argc-i, argv+i); | 
| 44 |  |  | if (rval >= 0) {                /* view option */ | 
| 45 |  |  | i += rval; | 
| 46 |  |  | continue; | 
| 47 |  |  | } | 
| 48 |  |  | switch (argv[i][1]) { | 
| 49 |  |  | case 'w':                       /* turn off warnings */ | 
| 50 |  |  | nowarn++; | 
| 51 |  |  | break; | 
| 52 |  |  | case 'p':                       /* pixel aspect/exposure */ | 
| 53 |  |  | if (badarg(argc-i-1,argv+i+1,"f")) | 
| 54 |  |  | goto userr; | 
| 55 | gwlarson | 3.3 | if (argv[i][2] == 'a') | 
| 56 | gwlarson | 3.1 | pixaspect = atof(argv[++i]); | 
| 57 | gwlarson | 3.3 | else if (argv[i][2] == 'e') { | 
| 58 | gwlarson | 3.1 | expval = atof(argv[++i]); | 
| 59 | schorsch | 3.14 | if ((argv[i][0] == '-') | (argv[i][0] == '+')) | 
| 60 | gwlarson | 3.1 | expval = pow(2., expval); | 
| 61 |  |  | } else | 
| 62 |  |  | goto userr; | 
| 63 |  |  | break; | 
| 64 |  |  | case 'x':                       /* horizontal resolution */ | 
| 65 |  |  | if (badarg(argc-i-1,argv+i+1,"i")) | 
| 66 |  |  | goto userr; | 
| 67 |  |  | xres = atoi(argv[++i]); | 
| 68 |  |  | break; | 
| 69 |  |  | case 'y':                       /* vertical resolution */ | 
| 70 |  |  | if (badarg(argc-i-1,argv+i+1,"i")) | 
| 71 |  |  | goto userr; | 
| 72 |  |  | yres = atoi(argv[++i]); | 
| 73 |  |  | break; | 
| 74 |  |  | case 'o':                       /* output file specificaiton */ | 
| 75 |  |  | if (badarg(argc-i-1,argv+i+1,"s")) | 
| 76 |  |  | goto userr; | 
| 77 |  |  | outspec = argv[++i]; | 
| 78 |  |  | break; | 
| 79 | gwlarson | 3.5 | case 'r':                       /* random sampling */ | 
| 80 | gwlarson | 3.6 | if (badarg(argc-i-1,argv+i+1,"f")) | 
| 81 |  |  | goto userr; | 
| 82 |  |  | randfrac = atof(argv[++i]); | 
| 83 | gwlarson | 3.5 | break; | 
| 84 |  |  | case 's':                       /* smooth sampling */ | 
| 85 | gwlarson | 3.6 | randfrac = -1.; | 
| 86 | gwlarson | 3.5 | break; | 
| 87 | gwlarson | 3.1 | case 'S':                       /* sequence start */ | 
| 88 |  |  | if (badarg(argc-i-1,argv+i+1,"i")) | 
| 89 |  |  | goto userr; | 
| 90 |  |  | seqstart = atoi(argv[++i]); | 
| 91 |  |  | break; | 
| 92 |  |  | case 'v':                       /* view file */ | 
| 93 | gwlarson | 3.4 | if (argv[i][2]!='f' || badarg(argc-i-1,argv+i+1,"s")) | 
| 94 | gwlarson | 3.1 | goto userr; | 
| 95 |  |  | rval = viewfile(argv[++i], &myview, NULL); | 
| 96 |  |  | if (rval < 0) { | 
| 97 |  |  | sprintf(errmsg, "cannot open view file \"%s\"", | 
| 98 |  |  | argv[i]); | 
| 99 |  |  | error(SYSTEM, errmsg); | 
| 100 |  |  | } else if (rval == 0) { | 
| 101 |  |  | sprintf(errmsg, "bad view file \"%s\"", | 
| 102 |  |  | argv[i]); | 
| 103 |  |  | error(USER, errmsg); | 
| 104 |  |  | } | 
| 105 |  |  | break; | 
| 106 |  |  | default: | 
| 107 |  |  | goto userr; | 
| 108 |  |  | } | 
| 109 |  |  | } | 
| 110 |  |  | /* open holodeck file */ | 
| 111 | gwlarson | 3.3 | if (i != argc-1) | 
| 112 | gwlarson | 3.1 | goto userr; | 
| 113 | gwlarson | 3.3 | hdkfile = argv[i]; | 
| 114 | gwlarson | 3.1 | initialize(); | 
| 115 |  |  | /* render picture(s) */ | 
| 116 |  |  | if (seqstart <= 0) | 
| 117 |  |  | dopicture(0); | 
| 118 |  |  | else | 
| 119 |  |  | while (nextview(&myview, stdin) != EOF) | 
| 120 |  |  | dopicture(seqstart++); | 
| 121 |  |  | quit(0);                                /* all done! */ | 
| 122 |  |  | userr: | 
| 123 |  |  | fprintf(stderr, | 
| 124 | gwlarson | 3.6 | "Usage: %s [-w][-r rf][-pa pa][-pe ex][-x hr][-y vr][-S stfn][-o outp][view] input.hdk\n", | 
| 125 | gwlarson | 3.1 | progname); | 
| 126 |  |  | quit(1); | 
| 127 |  |  | } | 
| 128 |  |  |  | 
| 129 |  |  |  | 
| 130 |  |  | dopicture(fn)                   /* render view from holodeck */ | 
| 131 |  |  | int     fn; | 
| 132 |  |  | { | 
| 133 |  |  | char    *err; | 
| 134 |  |  | int     rval; | 
| 135 |  |  | BEAMLIST        blist; | 
| 136 |  |  |  | 
| 137 |  |  | if ((err = setview(&myview)) != NULL) { | 
| 138 |  |  | sprintf(errmsg, "%s -- skipping frame %d", err, fn); | 
| 139 |  |  | error(WARNING, errmsg); | 
| 140 |  |  | return; | 
| 141 |  |  | } | 
| 142 |  |  | startpicture(fn);               /* open output picture */ | 
| 143 |  |  | /* determine relevant beams */ | 
| 144 |  |  | viewbeams(&myview, hres, vres, &blist); | 
| 145 |  |  | /* render image */ | 
| 146 |  |  | if (blist.nb > 0) { | 
| 147 |  |  | render_frame(blist.bl, blist.nb); | 
| 148 | greg | 3.8 | free((void *)blist.bl); | 
| 149 | gwlarson | 3.1 | } else { | 
| 150 |  |  | sprintf(errmsg, "no section visible in frame %d", fn); | 
| 151 |  |  | error(WARNING, errmsg); | 
| 152 |  |  | } | 
| 153 |  |  | rval = endpicture();            /* write pixel values */ | 
| 154 |  |  | if (rval < 0) { | 
| 155 |  |  | sprintf(errmsg, "error writing frame %d", fn); | 
| 156 |  |  | error(SYSTEM, errmsg); | 
| 157 |  |  | } | 
| 158 | gwlarson | 3.3 | #ifdef DEBUG | 
| 159 | gwlarson | 3.1 | if (blist.nb > 0 & rval > 0) { | 
| 160 | gwlarson | 3.3 | sprintf(errmsg, "%d unrendered pixels in frame %d (%.1f%%)", | 
| 161 |  |  | rval, fn, 100.*rval/(hres*vres)); | 
| 162 | gwlarson | 3.1 | error(WARNING, errmsg); | 
| 163 |  |  | } | 
| 164 | gwlarson | 3.3 | #endif | 
| 165 | gwlarson | 3.1 | } | 
| 166 |  |  |  | 
| 167 |  |  |  | 
| 168 |  |  | render_frame(bl, nb)            /* render frame from beam values */ | 
| 169 |  |  | register PACKHEAD       *bl; | 
| 170 |  |  | int     nb; | 
| 171 |  |  | { | 
| 172 | greg | 3.12 | extern void     pixBeam(); | 
| 173 | gwlarson | 3.1 | register HDBEAMI        *bil; | 
| 174 |  |  | register int    i; | 
| 175 |  |  |  | 
| 176 |  |  | if (nb <= 0) return; | 
| 177 |  |  | if ((bil = (HDBEAMI *)malloc(nb*sizeof(HDBEAMI))) == NULL) | 
| 178 |  |  | error(SYSTEM, "out of memory in render_frame"); | 
| 179 |  |  | for (i = nb; i--; ) { | 
| 180 |  |  | bil[i].h = hdlist[bl[i].hd]; | 
| 181 |  |  | bil[i].b = bl[i].bi; | 
| 182 |  |  | } | 
| 183 | gwlarson | 3.2 | hdloadbeams(bil, nb, pixBeam); | 
| 184 | gwlarson | 3.6 | pixFinish(randfrac); | 
| 185 | greg | 3.8 | free((void *)bil); | 
| 186 | gwlarson | 3.1 | } | 
| 187 |  |  |  | 
| 188 |  |  |  | 
| 189 |  |  | startpicture(fn)                /* initialize picture for rendering & output */ | 
| 190 |  |  | int     fn; | 
| 191 |  |  | { | 
| 192 |  |  | extern char     VersionID[]; | 
| 193 |  |  | double  pa = pixaspect; | 
| 194 |  |  | char    fname[256]; | 
| 195 |  |  | /* compute picture resolution */ | 
| 196 |  |  | hres = xres; vres = yres; | 
| 197 |  |  | normaspect(viewaspect(&myview), &pa, &hres, &vres); | 
| 198 |  |  | /* prepare output */ | 
| 199 |  |  | if (outspec != NULL) { | 
| 200 |  |  | sprintf(fname, outspec, fn); | 
| 201 |  |  | if (freopen(fname, "w", stdout) == NULL) { | 
| 202 |  |  | sprintf(errmsg, "cannot open output \"%s\"", fname); | 
| 203 |  |  | error(SYSTEM, errmsg); | 
| 204 |  |  | } | 
| 205 |  |  | } | 
| 206 |  |  | /* write header */ | 
| 207 |  |  | newheader("RADIANCE", stdout); | 
| 208 |  |  | printf("SOFTWARE= %s\n", VersionID); | 
| 209 | gwlarson | 3.7 | printargs(gargc, gargv, stdout); | 
| 210 | gwlarson | 3.1 | if (fn) | 
| 211 |  |  | printf("FRAME=%d\n", fn); | 
| 212 |  |  | fputs(VIEWSTR, stdout); | 
| 213 |  |  | fprintview(&myview, stdout); | 
| 214 |  |  | fputc('\n', stdout); | 
| 215 | schorsch | 3.14 | if ((pa < 0.99) | (pa > 1.01)) | 
| 216 | gwlarson | 3.1 | fputaspect(pa, stdout); | 
| 217 | schorsch | 3.14 | if ((expval < 0.99) | (expval > 1.01)) | 
| 218 | gwlarson | 3.1 | fputexpos(expval, stdout); | 
| 219 |  |  | fputformat(COLRFMT, stdout); | 
| 220 |  |  | fputc('\n', stdout); | 
| 221 |  |  | /* write resolution (standard order) */ | 
| 222 |  |  | fprtresolu(hres, vres, stdout); | 
| 223 |  |  | /* prepare image buffers */ | 
| 224 | schorsch | 3.11 | memset((char *)mypixel, '\0', hres*vres*sizeof(COLOR)); | 
| 225 |  |  | memset((char *)myweight, '\0', hres*vres*sizeof(float)); | 
| 226 |  |  | memset((char *)mydepth, '\0', hres*vres*sizeof(float)); | 
| 227 | gwlarson | 3.1 | } | 
| 228 |  |  |  | 
| 229 |  |  |  | 
| 230 |  |  | int | 
| 231 |  |  | endpicture()                    /* finish and write out pixels */ | 
| 232 |  |  | { | 
| 233 | gwlarson | 3.4 | int     lastr = -1, nunrend = 0; | 
| 234 | greg | 3.10 | int32   lastp, lastrp; | 
| 235 |  |  | register int32  p; | 
| 236 | gwlarson | 3.1 | register double d; | 
| 237 |  |  | /* compute final pixel values */ | 
| 238 |  |  | for (p = hres*vres; p--; ) { | 
| 239 |  |  | if (myweight[p] <= FTINY) { | 
| 240 | schorsch | 3.13 | if (lastr >= 0) { | 
| 241 | gwlarson | 3.4 | if (p/hres == lastp/hres) | 
| 242 |  |  | copycolor(mypixel[p], mypixel[lastp]); | 
| 243 |  |  | else | 
| 244 |  |  | copycolor(mypixel[p], mypixel[lastrp]); | 
| 245 | schorsch | 3.13 | } | 
| 246 | gwlarson | 3.1 | nunrend++; | 
| 247 |  |  | continue; | 
| 248 |  |  | } | 
| 249 |  |  | d = expval/myweight[p]; | 
| 250 |  |  | scalecolor(mypixel[p], d); | 
| 251 | gwlarson | 3.4 | if ((lastp=p)/hres != lastr) | 
| 252 |  |  | lastr = (lastrp=p)/hres; | 
| 253 | gwlarson | 3.1 | } | 
| 254 |  |  | /* write each scanline */ | 
| 255 | gwlarson | 3.4 | for (p = vres; p--; ) | 
| 256 |  |  | if (fwritescan(mypixel+p*hres, hres, stdout) < 0) | 
| 257 | gwlarson | 3.1 | return(-1); | 
| 258 |  |  | if (fflush(stdout) == EOF) | 
| 259 |  |  | return(-1); | 
| 260 |  |  | return(nunrend); | 
| 261 |  |  | } | 
| 262 |  |  |  | 
| 263 |  |  |  | 
| 264 |  |  | initialize()                    /* initialize holodeck and buffers */ | 
| 265 |  |  | { | 
| 266 |  |  | int     fd; | 
| 267 |  |  | FILE    *fp; | 
| 268 |  |  | int     n; | 
| 269 | greg | 3.10 | int32   nextloc; | 
| 270 | gwlarson | 3.1 | /* open holodeck file */ | 
| 271 |  |  | if ((fp = fopen(hdkfile, "r")) == NULL) { | 
| 272 |  |  | sprintf(errmsg, "cannot open \"%s\" for reading", hdkfile); | 
| 273 |  |  | error(SYSTEM, errmsg); | 
| 274 |  |  | } | 
| 275 |  |  | /* check header format */ | 
| 276 |  |  | checkheader(fp, HOLOFMT, NULL); | 
| 277 |  |  | /* check magic number */ | 
| 278 |  |  | if (getw(fp) != HOLOMAGIC) { | 
| 279 |  |  | sprintf(errmsg, "bad magic number in holodeck file \"%s\"", | 
| 280 |  |  | hdkfile); | 
| 281 |  |  | error(USER, errmsg); | 
| 282 |  |  | } | 
| 283 |  |  | nextloc = ftell(fp);                    /* get stdio position */ | 
| 284 |  |  | fd = dup(fileno(fp));                   /* dup file descriptor */ | 
| 285 |  |  | fclose(fp);                             /* done with stdio */ | 
| 286 |  |  | for (n = 0; nextloc > 0L; n++) {        /* initialize each section */ | 
| 287 | greg | 3.8 | lseek(fd, (off_t)nextloc, 0); | 
| 288 | gwlarson | 3.1 | read(fd, (char *)&nextloc, sizeof(nextloc)); | 
| 289 |  |  | hdinit(fd, NULL); | 
| 290 |  |  | } | 
| 291 |  |  | /* allocate picture buffer */ | 
| 292 |  |  | mypixel = (COLOR *)bmalloc(xres*yres*sizeof(COLOR)); | 
| 293 |  |  | myweight = (float *)bmalloc(xres*yres*sizeof(float)); | 
| 294 | gwlarson | 3.2 | mydepth = (float *)bmalloc(xres*yres*sizeof(float)); | 
| 295 | schorsch | 3.14 | if ((mypixel == NULL) | (myweight == NULL) | (mydepth == NULL)) | 
| 296 | gwlarson | 3.1 | error(SYSTEM, "out of memory in initialize"); | 
| 297 |  |  | } | 
| 298 |  |  |  | 
| 299 |  |  |  | 
| 300 | greg | 3.8 | void | 
| 301 | gwlarson | 3.1 | eputs(s)                        /* put error message to stderr */ | 
| 302 |  |  | register char  *s; | 
| 303 |  |  | { | 
| 304 |  |  | static int  midline = 0; | 
| 305 |  |  |  | 
| 306 |  |  | if (!*s) | 
| 307 |  |  | return; | 
| 308 |  |  | if (!midline++) {       /* prepend line with program name */ | 
| 309 |  |  | fputs(progname, stderr); | 
| 310 |  |  | fputs(": ", stderr); | 
| 311 |  |  | } | 
| 312 |  |  | fputs(s, stderr); | 
| 313 |  |  | if (s[strlen(s)-1] == '\n') { | 
| 314 |  |  | fflush(stderr); | 
| 315 |  |  | midline = 0; | 
| 316 |  |  | } | 
| 317 |  |  | } |