ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rpiece.c
Revision: 2.43
Committed: Fri Mar 26 21:36:20 2004 UTC (20 years, 1 month ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.42: +68 -37 lines
Log Message:
Continued ANSIfication.

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rpiece.c,v 2.42 2003/10/20 16:01:55 greg Exp $";
3 #endif
4 /*
5 * Generate sections of a picture.
6 */
7
8
9 #include <stdio.h>
10 #include <signal.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13
14 #include "platform.h"
15 #include "rtio.h"
16 #include "rtmisc.h"
17 #include "color.h"
18 #include "view.h"
19 #include "rtprocess.h"
20
21 #ifndef F_SETLKW
22
23 int
24 main(
25 int argc,
26 char *argv[]
27 )
28 {
29 fprintf(stderr, "%s: no NFS lock manager on this machine\n", argv[0]);
30 exit(1);
31 }
32
33 #else
34
35 #ifndef NFS
36 #define NFS 1
37 #endif
38 /* set the following to 0 to forgo forking */
39 #ifndef MAXFORK
40 #if NFS
41 #define MAXFORK 3 /* allotment of duped processes */
42 #else
43 #define MAXFORK 0
44 #endif
45 #endif
46 /* protection from SYSV signals(!) */
47 #if defined(sgi)
48 #define guard_io() sighold(SIGALRM)
49 #define unguard() sigrelse(SIGALRM)
50 #endif
51 #ifndef guard_io
52 #define guard_io()
53 #define unguard()
54 #endif
55
56 extern char *strerror();
57
58 /* rpict command */
59 char *rpargv[128] = {"rpict", "-S", "1"};
60 int rpargc = 3;
61 FILE *torp, *fromrp;
62 COLR *pbuf;
63 /* our view parameters */
64 VIEW ourview = STDVIEW;
65 double pixaspect = 1.0;
66 int hres = 1024, vres = 1024, hmult = 4, vmult = 4;
67 /* output file */
68 char *outfile = NULL;
69 int outfd;
70 long scanorig;
71 FILE *syncfp = NULL; /* synchronization file pointer */
72 int synclst = F_UNLCK; /* synchronization file lock status */
73 int nforked = 0;
74
75 #define sflock(t) if ((t)!=synclst) dolock(fileno(syncfp),synclst=t)
76
77 char *progname;
78 int verbose = 0;
79 unsigned timelim = 0;
80 int rvrlim = -1;
81
82 int gotalrm = 0;
83 void onalrm(int i) { gotalrm++; }
84
85 static void dolock(int fd, int ltyp);
86 static void init(int ac, char **av);
87 static int nextpiece(int *xp, int *yp);
88 static int rvrpiece(int *xp, int *yp);
89 static int cleanup(int rstat);
90 static void rpiece(void);
91 static int putpiece(int xpos, int ypos);
92 static void filerr(char *t);
93
94
95 int
96 main(
97 int argc,
98 char *argv[]
99 )
100 {
101 register int i, rval;
102
103 progname = argv[0];
104 for (i = 1; i < argc; i++) {
105 /* expand arguments */
106 while ((rval = expandarg(&argc, &argv, i)) > 0)
107 ;
108 if (rval < 0) {
109 fprintf(stderr, "%s: cannot expand '%s'",
110 argv[0], argv[i]);
111 exit(1);
112 }
113 if (argv[i][0] == '-')
114 switch (argv[i][1]) {
115 case 'v':
116 switch (argv[i][2]) {
117 case '\0': /* verbose option */
118 verbose = !verbose;
119 continue;
120 case 'f': /* view file */
121 if (viewfile(argv[++i], &ourview, NULL) <= 0) {
122 fprintf(stderr,
123 "%s: not a view file\n", argv[i]);
124 exit(1);
125 }
126 continue;
127 default: /* view option? */
128 rval = getviewopt(&ourview, argc-i, argv+i);
129 if (rval >= 0) {
130 i += rval;
131 continue;
132 }
133 break;
134 }
135 break;
136 case 'p': /* pixel aspect ratio? */
137 if (argv[i][2] != 'a' || argv[i][3])
138 break;
139 pixaspect = atof(argv[++i]);
140 continue;
141 case 'T': /* time limit (hours) */
142 if (argv[i][2])
143 break;
144 timelim = atof(argv[++i])*3600. + .5;
145 break;
146 case 'x': /* overall x resolution */
147 if (argv[i][2])
148 break;
149 hres = atoi(argv[++i]);
150 continue;
151 case 'y': /* overall y resolution */
152 if (argv[i][2])
153 break;
154 vres = atoi(argv[++i]);
155 continue;
156 case 'X': /* horizontal multiplier */
157 if (argv[i][2])
158 break;
159 hmult = atoi(argv[++i]);
160 continue;
161 case 'Y': /* vertical multiplier */
162 if (argv[i][2])
163 break;
164 vmult = atoi(argv[++i]);
165 continue;
166 case 'R': /* recover */
167 if (argv[i][2])
168 break;
169 rvrlim = 0;
170 /* fall through */
171 case 'F': /* syncronization file */
172 if (argv[i][2])
173 break;
174 if ((syncfp =
175 fdopen(open(argv[++i],O_RDWR|O_CREAT,0666),"r+")) == NULL) {
176 fprintf(stderr, "%s: cannot open\n",
177 argv[i]);
178 exit(1);
179 }
180 continue;
181 case 'z': /* z-file ist verbotten */
182 fprintf(stderr, "%s: -z option not allowed\n",
183 argv[0]);
184 exit(1);
185 case 'o': /* output file */
186 if (argv[i][2])
187 break;
188 outfile = argv[++i];
189 continue;
190 } else if (i >= argc-1)
191 break;
192 rpargv[rpargc++] = argv[i];
193 }
194 if (i >= argc) {
195 fprintf(stderr, "%s: missing octree argument\n", argv[0]);
196 exit(1);
197 }
198 if (outfile == NULL) {
199 fprintf(stderr, "%s: missing output file\n", argv[0]);
200 exit(1);
201 }
202 init(argc, argv);
203 rpiece();
204 exit(cleanup(0));
205 }
206
207
208 static void
209 dolock( /* lock or unlock a file */
210 int fd,
211 int ltyp
212 )
213 {
214 static struct flock fls; /* static so initialized to zeroes */
215
216 fls.l_type = ltyp;
217 if (fcntl(fd, F_SETLKW, &fls) < 0) {
218 fprintf(stderr, "%s: cannot lock/unlock file: %s\n",
219 progname, strerror(errno));
220 exit(1);
221 }
222 }
223
224
225 static void
226 init( /* set up output file and start rpict */
227 int ac,
228 char **av
229 )
230 {
231 static char hrbuf[16], vrbuf[16];
232 extern char VersionID[];
233 char *err;
234 FILE *fp;
235 int hr, vr;
236 SUBPROC rpd; /* since we don't close_process(), this can be local */
237 /* set up view */
238 if ((err = setview(&ourview)) != NULL) {
239 fprintf(stderr, "%s: %s\n", progname, err);
240 exit(1);
241 }
242 if (syncfp != NULL) {
243 sflock(F_RDLCK);
244 fscanf(syncfp, "%d %d", &hmult, &vmult);
245 sflock(F_UNLCK);
246 }
247 /* compute piece size */
248 hres /= hmult;
249 vres /= vmult;
250 normaspect(viewaspect(&ourview)*hmult/vmult, &pixaspect, &hres, &vres);
251 sprintf(hrbuf, "%d", hres);
252 rpargv[rpargc++] = "-x"; rpargv[rpargc++] = hrbuf;
253 sprintf(vrbuf, "%d", vres);
254 rpargv[rpargc++] = "-y"; rpargv[rpargc++] = vrbuf;
255 rpargv[rpargc++] = "-pa"; rpargv[rpargc++] = "0";
256 rpargv[rpargc++] = av[ac-1];
257 rpargv[rpargc] = NULL;
258 /* open output file */
259 if ((outfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0666)) >= 0) {
260 dolock(outfd, F_WRLCK);
261 if ((fp = fdopen(dup(outfd), "w")) == NULL)
262 goto filerr;
263 newheader("RADIANCE", fp); /* create header */
264 printargs(ac, av, fp);
265 fprintf(fp, "SOFTWARE= %s\n", VersionID);
266 fputs(VIEWSTR, fp);
267 fprintview(&ourview, fp);
268 putc('\n', fp);
269 if (pixaspect < .99 || pixaspect > 1.01)
270 fputaspect(pixaspect, fp);
271 fputformat(COLRFMT, fp);
272 putc('\n', fp);
273 fprtresolu(hres*hmult, vres*vmult, fp);
274 } else if ((outfd = open(outfile, O_RDWR)) >= 0) {
275 dolock(outfd, F_RDLCK);
276 if ((fp = fdopen(dup(outfd), "r+")) == NULL)
277 goto filerr;
278 getheader(fp, NULL, NULL); /* skip header */
279 if (!fscnresolu(&hr, &vr, fp) || /* check resolution */
280 hr != hres*hmult || vr != vres*vmult) {
281 fprintf(stderr, "%s: resolution mismatch on file \"%s\"\n",
282 progname, outfile);
283 exit(1);
284 }
285 } else {
286 fprintf(stderr, "%s: cannot open file \"%s\"\n",
287 progname, outfile);
288 exit(1);
289 }
290 scanorig = ftell(fp); /* record position of first scanline */
291 if (fclose(fp) == -1) /* done with stream i/o */
292 goto filerr;
293 dolock(outfd, F_UNLCK);
294 /* start rpict process */
295 if (open_process(&rpd, rpargv) <= 0) {
296 fprintf(stderr, "%s: cannot start %s\n", progname, rpargv[0]);
297 exit(1);
298 }
299 if ((fromrp = fdopen(rpd.r, "r")) == NULL ||
300 (torp = fdopen(rpd.w, "w")) == NULL) {
301 fprintf(stderr, "%s: cannot open stream to %s\n",
302 progname, rpargv[0]);
303 exit(1);
304 }
305 if ((pbuf = (COLR *)bmalloc(hres*vres*sizeof(COLR))) == NULL) {
306 fprintf(stderr, "%s: out of memory\n", progname);
307 exit(1);
308 }
309 signal(SIGALRM, onalrm);
310 if (timelim)
311 alarm(timelim);
312 return;
313 filerr:
314 fprintf(stderr, "%s: i/o error on file \"%s\"\n", progname, outfile);
315 exit(1);
316 }
317
318
319 static int
320 nextpiece( /* get next piece assignment */
321 int *xp,
322 int *yp
323 )
324 {
325 if (gotalrm) /* someone wants us to quit */
326 return(0);
327 if (syncfp != NULL) { /* use sync file */
328 /*
329 * So we don't necessarily have to lock and unlock the file
330 * multiple times (very slow), we establish an exclusive
331 * lock at the beginning on our synchronization file and
332 * maintain it in the subroutine rvrpiece().
333 */
334 sflock(F_WRLCK);
335 fseek(syncfp, 0L, 0); /* read position */
336 if (fscanf(syncfp, "%*d %*d %d %d", xp, yp) < 2) {
337 *xp = hmult-1;
338 *yp = vmult;
339 }
340 if (rvrlim == 0) /* initialize recovery limit */
341 rvrlim = *xp*vmult + *yp;
342 if (rvrpiece(xp, yp)) { /* do stragglers first */
343 sflock(F_UNLCK);
344 return(1);
345 }
346 if (--(*yp) < 0) { /* decrement position */
347 *yp = vmult-1;
348 if (--(*xp) < 0) { /* all done */
349 sflock(F_UNLCK);
350 return(0);
351 }
352 }
353 fseek(syncfp, 0L, 0); /* write new position */
354 fprintf(syncfp, "%4d %4d\n%4d %4d\n\n", hmult, vmult, *xp, *yp);
355 fflush(syncfp);
356 sflock(F_UNLCK); /* release sync file */
357 return(1);
358 }
359 return(scanf("%d %d", xp, yp) == 2); /* use stdin */
360 }
361
362
363 static int
364 rvrpiece( /* check for recoverable pieces */
365 register int *xp,
366 register int *yp
367 )
368 {
369 static char *pdone = NULL; /* which pieces are done */
370 static long readpos = -1; /* how far we've read */
371 register int i;
372 /*
373 * This routine is called by nextpiece() with an
374 * exclusive lock on syncfp and the file pointer at the
375 * appropriate position to read in the finished pieces.
376 */
377 if (rvrlim < 0)
378 return(0); /* only check if asked */
379 if (pdone == NULL) /* first call */
380 pdone = calloc(hmult*vmult, sizeof(char));
381 if (pdone == NULL) {
382 fprintf(stderr, "%s: out of memory\n", progname);
383 exit(1);
384 }
385 if (readpos != -1) /* mark what's been done */
386 fseek(syncfp, readpos, 0);
387 while (fscanf(syncfp, "%d %d", xp, yp) == 2)
388 pdone[*xp*vmult+*yp] = 1;
389 if (!feof(syncfp)) {
390 fprintf(stderr, "%s: format error in sync file\n", progname);
391 exit(1);
392 }
393 readpos = ftell(syncfp);
394 i = hmult*vmult; /* find an unaccounted for piece */
395 while (i-- > rvrlim)
396 if (!pdone[i]) {
397 *xp = i / vmult;
398 *yp = i % vmult;
399 pdone[i] = 1; /* consider it done */
400 return(1);
401 }
402 rvrlim = -1; /* nothing left to recover */
403 free(pdone);
404 pdone = NULL;
405 return(0);
406 }
407
408
409 static int
410 cleanup( /* close rpict process and clean up */
411 int rstat
412 )
413 {
414 int status;
415
416 bfree((char *)pbuf, hres*vres*sizeof(COLR));
417 fclose(torp);
418 fclose(fromrp);
419 while (wait(&status) != -1)
420 if (rstat == 0)
421 rstat = status>>8 & 0xff;
422 return(rstat);
423 }
424
425
426 static void
427 rpiece(void) /* render picture piece by piece */
428 {
429 VIEW pview;
430 int xorg, yorg;
431 /* compute view parameters */
432 pview = ourview;
433 switch (ourview.type) {
434 case VT_PER:
435 pview.horiz = 2.*180./PI*atan(
436 tan(PI/180./2.*ourview.horiz)/hmult );
437 pview.vert = 2.*180./PI*atan(
438 tan(PI/180./2.*ourview.vert)/vmult );
439 break;
440 case VT_PAR:
441 case VT_ANG:
442 pview.horiz = ourview.horiz / hmult;
443 pview.vert = ourview.vert / vmult;
444 break;
445 case VT_CYL:
446 pview.horiz = ourview.horiz / hmult;
447 pview.vert = 2.*180./PI*atan(
448 tan(PI/180./2.*ourview.vert)/vmult );
449 break;
450 case VT_HEM:
451 pview.horiz = 2.*180./PI*asin(
452 sin(PI/180./2.*ourview.horiz)/hmult );
453 pview.vert = 2.*180./PI*asin(
454 sin(PI/180./2.*ourview.vert)/vmult );
455 break;
456 default:
457 fprintf(stderr, "%s: unknown view type '-vt%c'\n",
458 progname, ourview.type);
459 exit(cleanup(1));
460 }
461 /* render each piece */
462 while (nextpiece(&xorg, &yorg)) {
463 pview.hoff = ourview.hoff*hmult + xorg - 0.5*(hmult-1);
464 pview.voff = ourview.voff*vmult + yorg - 0.5*(vmult-1);
465 fputs(VIEWSTR, torp);
466 fprintview(&pview, torp);
467 putc('\n', torp);
468 fflush(torp); /* assigns piece to rpict */
469 putpiece(xorg, yorg); /* place piece in output */
470 }
471 }
472
473
474 static int
475 putpiece( /* get next piece from rpict */
476 int xpos,
477 int ypos
478 )
479 {
480 struct flock fls;
481 int pid, status;
482 int hr, vr;
483 register int y;
484 /* check bounds */
485 if ((xpos < 0) | (ypos < 0) | (xpos >= hmult) | (ypos >= vmult)) {
486 fprintf(stderr, "%s: requested piece (%d,%d) out of range\n",
487 progname, xpos, ypos);
488 exit(cleanup(1));
489 }
490 /* check header from rpict */
491 guard_io();
492 getheader(fromrp, NULL, NULL);
493 if (!fscnresolu(&hr, &vr, fromrp) || (hr != hres) | (vr != vres)) {
494 fprintf(stderr, "%s: resolution mismatch from %s\n",
495 progname, rpargv[0]);
496 exit(cleanup(1));
497 }
498 if (verbose) { /* notify caller */
499 printf("%d %d begun\n", xpos, ypos);
500 fflush(stdout);
501 }
502 unguard();
503 /* load new piece into buffer */
504 for (y = 0; y < vr; y++) {
505 guard_io();
506 if (freadcolrs(pbuf+y*hr, hr, fromrp) < 0) {
507 fprintf(stderr, "%s: read error from %s\n",
508 progname, rpargv[0]);
509 exit(cleanup(1));
510 }
511 unguard();
512 }
513 #if MAXFORK
514 /* fork so we don't slow rpict down */
515 if ((pid = fork()) > 0) {
516 if (++nforked >= MAXFORK) {
517 wait(&status); /* reap a child */
518 if (status)
519 exit(cleanup(status>>8 & 0xff));
520 nforked--;
521 }
522 return(pid);
523 }
524 #else
525 pid = -1; /* no forking */
526 #endif
527 fls.l_start = scanorig +
528 ((long)(vmult-1-ypos)*vres*hmult+xpos)*hres*sizeof(COLR);
529 #if NFS
530 fls.l_len = ((long)(vres-1)*hmult+1)*hres*sizeof(COLR);
531 /* lock file section so NFS doesn't mess up */
532 fls.l_whence = 0;
533 fls.l_type = F_WRLCK;
534 if (fcntl(outfd, F_SETLKW, &fls) < 0)
535 filerr("lock");
536 #endif
537 /* write new piece to file */
538 if (lseek(outfd, (off_t)fls.l_start, SEEK_SET) < 0)
539 filerr("seek");
540 if (hmult == 1) {
541 if (writebuf(outfd, (char *)pbuf,
542 vr*hr*sizeof(COLR)) != vr*hr*sizeof(COLR))
543 filerr("write");
544 } else
545 for (y = 0; y < vr; y++) {
546 if (writebuf(outfd, (char *)(pbuf+y*hr),
547 hr*sizeof(COLR)) != hr*sizeof(COLR))
548 filerr("write");
549 if (y < vr-1 && lseek(outfd,
550 (off_t)(hmult-1)*hr*sizeof(COLR),
551 SEEK_CUR) < 0)
552 filerr("seek");
553 }
554 #if NFS
555 fls.l_type = F_UNLCK; /* release lock */
556 if (fcntl(outfd, F_SETLKW, &fls) < 0)
557 filerr("lock");
558 #endif
559 if (verbose) { /* notify caller */
560 printf("%d %d done\n", xpos, ypos);
561 fflush(stdout);
562 }
563 if (syncfp != NULL) { /* record what's been done */
564 sflock(F_WRLCK);
565 fseek(syncfp, 0L, 2); /* append index */
566 fprintf(syncfp, "%4d %4d\n", xpos, ypos);
567 fflush(syncfp);
568 /*** Unlock not necessary, since
569 sflock(F_UNLCK); _exit() or nextpiece() is next ***/
570 }
571 if (pid == -1) /* didn't fork or fork failed */
572 return(0);
573 _exit(0); /* else exit child process (releasing locks) */
574 }
575
576
577 static void
578 filerr( /* report file error and exit */
579 char *t
580 )
581 {
582 fprintf(stderr, "%s: %s error on file \"%s\": %s\n",
583 progname, t, outfile, strerror(errno));
584 _exit(1);
585 }
586
587 #endif