ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/ranimate.c
Revision: 2.46
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.45: +15 -11 lines
Log Message:
Continued ANSIfication.

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: ranimate.c,v 2.45 2004/02/15 06:21:01 greg Exp $";
3 #endif
4 /*
5 * Radiance animation control program
6 *
7 * The main difference between this program and ranimove is that
8 * we have many optimizations here for camera motion in static
9 * environments, calling rpict and pinterp on multiple processors,
10 * where ranimove puts its emphasis on object motion, and does
11 * not use any external programs for image generation.
12 *
13 * See the ranimate(1) man page for further details.
14 */
15
16 #include "copyright.h"
17
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <sys/stat.h>
21 #include <time.h>
22 #include <signal.h>
23
24 #include "platform.h"
25 #include "paths.h"
26 #include "rtio.h"
27 #include "rterror.h"
28 #include "rtmisc.h"
29 #include "view.h"
30 #include "vars.h"
31 #include "netproc.h"
32 /* default blur samples */
33 #ifndef DEF_NBLUR
34 #define DEF_NBLUR 5
35 #endif
36 /* default remote shell */
37 #define REMSH "rsh"
38 /* input variables (alphabetical by name) */
39 #define ANIMATE 0 /* animation command */
40 #define ARCHIVE 1 /* archiving command */
41 #define BASENAME 2 /* output image base name */
42 #define DIRECTORY 3 /* working (sub)directory */
43 #define DISKSPACE 4 /* how much disk space to use */
44 #define END 5 /* ending frame number */
45 #define EXPOSURE 6 /* how to compute exposure */
46 #define HOST 7 /* rendering host machine */
47 #define INTERP 8 /* # frames to interpolate */
48 #define MBLUR 9 /* motion blur parameters */
49 #define NEXTANIM 10 /* next animation file */
50 #define OCTREE 11 /* octree file name */
51 #define OVERSAMP 12 /* # times to oversample image */
52 #define PFILT 13 /* pfilt options */
53 #define PINTERP 14 /* pinterp options */
54 #define RENDER 15 /* rendering options */
55 #define RESOLUTION 16 /* desired final resolution */
56 #define RIF 17 /* rad input file */
57 #define RSH 18 /* remote shell script or program */
58 #define RTRACE 19 /* use rtrace with pinterp? */
59 #define START 20 /* starting frame number */
60 #define TRANSFER 21 /* frame transfer command */
61 #define VIEWFILE 22 /* animation frame views */
62
63 int NVARS = 23; /* total number of variables */
64
65 VARIABLE vv[] = { /* variable-value pairs */
66 {"ANIMATE", 2, 0, NULL, onevalue},
67 {"ARCHIVE", 2, 0, NULL, onevalue},
68 {"BASENAME", 3, 0, NULL, onevalue},
69 {"DIRECTORY", 3, 0, NULL, onevalue},
70 {"DISKSPACE", 3, 0, NULL, fltvalue},
71 {"END", 2, 0, NULL, intvalue},
72 {"EXPOSURE", 3, 0, NULL, onevalue},
73 {"host", 4, 0, NULL, NULL},
74 {"INTERPOLATE", 3, 0, NULL, intvalue},
75 {"MBLUR", 2, 0, NULL, onevalue},
76 {"NEXTANIM", 3, 0, NULL, onevalue},
77 {"OCTREE", 3, 0, NULL, onevalue},
78 {"OVERSAMPLE", 2, 0, NULL, fltvalue},
79 {"pfilt", 2, 0, NULL, catvalues},
80 {"pinterp", 2, 0, NULL, catvalues},
81 {"render", 3, 0, NULL, catvalues},
82 {"RESOLUTION", 3, 0, NULL, onevalue},
83 {"RIF", 3, 0, NULL, onevalue},
84 {"RSH", 3, 0, NULL, onevalue},
85 {"RTRACE", 2, 0, NULL, boolvalue},
86 {"START", 2, 0, NULL, intvalue},
87 {"TRANSFER", 2, 0, NULL, onevalue},
88 {"VIEWFILE", 2, 0, NULL, onevalue},
89 };
90
91 #define SFNAME "STATUS" /* status file name */
92
93 struct {
94 char host[64]; /* control host name */
95 int pid; /* control process id */
96 char cfname[128]; /* control file name */
97 int rnext; /* next frame to render */
98 int fnext; /* next frame to filter */
99 int tnext; /* next frame to transfer */
100 } astat; /* animation status */
101
102 char *progname; /* our program name */
103 char *cfname; /* our control file name */
104
105 int nowarn = 0; /* turn warnings off? */
106 int silent = 0; /* silent mode? */
107 int noaction = 0; /* take no action? */
108
109 char *remsh; /* remote shell program/script */
110 char rendopt[2048]; /* rendering options */
111 char rresopt[32]; /* rendering resolution options */
112 char fresopt[32]; /* filter resolution options */
113 int pfiltalways; /* always use pfilt? */
114
115 char arcargs[10240]; /* files to archive */
116 char *arcfirst, *arcnext; /* pointers to first and next argument */
117
118 struct pslot {
119 int pid; /* process ID (0 if empty) */
120 int fout; /* output frame number */
121 int (*rcvf)(); /* recover function */
122 } *pslot; /* process slots */
123 int npslots; /* number of process slots */
124
125 #define phostname(ps) ((ps)->hostname[0] ? (ps)->hostname : astat.host)
126 PSERVER *lastpserver; /* last process server with error */
127
128 static struct pslot * findpslot(int pid);
129 static void checkdir(void);
130 static VIEW * getview(int n);
131
132 static char * dirfile(char *df, register char *path);
133 static char * getexp(int n);
134 static int getblur(double *bf);
135 static int getastat(void);
136 static void getradfile(char *rfargs);
137 static void badvalue(int vc);
138 static int rmfile(char *fn);
139 static int runcom(char *cs);
140 static int pruncom(char *com, char *ppins, int maxcopies);
141 static void bwait(int ncoms);
142 static int bruncom(char *com, int fout, int (*rf)());
143 static int serverdown(void);
144 static pscompfunc donecom;
145 static int countviews(void);
146 static int dofilt(int frame, int rvr);
147 static void archive(void);
148 static int frecover(int frame);
149 static int recover(int frame);
150 static void sethosts(void);
151 static void walkwait(int first, int last, char *vfn);
152 static void animrend(int frame, VIEW *vp);
153 static void transferframes(void);
154 static void filterframes(void);
155 static void renderframes(int nframes);
156 static void animate(void);
157 static void setdefaults(void);
158 static void putastat(void);
159
160
161 int
162 main(
163 int argc,
164 char *argv[]
165 )
166 {
167 int explicate = 0;
168 int i;
169
170 progname = argv[0]; /* get arguments */
171 for (i = 1; i < argc && argv[i][0] == '-'; i++)
172 switch (argv[i][1]) {
173 case 'e': /* print variables */
174 explicate++;
175 break;
176 case 'w': /* turn off warnings */
177 nowarn++;
178 break;
179 case 's': /* silent mode */
180 silent++;
181 break;
182 case 'n': /* take no action */
183 noaction++;
184 break;
185 default:
186 goto userr;
187 }
188 if (i != argc-1)
189 goto userr;
190 cfname = argv[i];
191 /* load variables */
192 loadvars(cfname);
193 /* check variables */
194 checkvalues();
195 /* did we get DIRECTORY? */
196 checkdir();
197 /* check status */
198 if (getastat() < 0) {
199 fprintf(stderr, "%s: exiting\n", progname);
200 quit(1);
201 }
202 /* pfilt always if options given */
203 pfiltalways = vdef(PFILT);
204 /* load RIF if any */
205 if (vdef(RIF))
206 getradfile(vval(RIF));
207 /* set defaults */
208 setdefaults();
209 /* print variables */
210 if (explicate)
211 printvars(stdout);
212 /* set up process servers */
213 sethosts();
214 /* run animation */
215 animate();
216 /* all done */
217 if (vdef(NEXTANIM)) {
218 argv[i] = vval(NEXTANIM); /* just change input file */
219 if (!silent)
220 printargs(argc, argv, stdout);
221 if ((argv[0] = getpath(progname,getenv("PATH"),X_OK)) == NULL)
222 fprintf(stderr, "%s: command not found\n", progname);
223 else
224 execv(progname, argv);
225 quit(1);
226 }
227 quit(0);
228 return 0; /* pro forma return */
229 userr:
230 fprintf(stderr, "Usage: %s [-s][-n][-w][-e] anim_file\n", progname);
231 quit(1);
232 return 1; /* pro forma return */
233 }
234
235
236 static int
237 getastat(void) /* check/set animation status */
238 {
239 char sfname[256];
240 FILE *fp;
241
242 sprintf(sfname, "%s/%s", vval(DIRECTORY), SFNAME);
243 if ((fp = fopen(sfname, "r")) == NULL) {
244 if (errno != ENOENT) {
245 perror(sfname);
246 return(-1);
247 }
248 astat.rnext = astat.fnext = astat.tnext = 0;
249 goto setours;
250 }
251 if (fscanf(fp, "Control host: %s\n", astat.host) != 1)
252 goto fmterr;
253 if (fscanf(fp, "Control PID: %d\n", &astat.pid) != 1)
254 goto fmterr;
255 if (fscanf(fp, "Control file: %s\n", astat.cfname) != 1)
256 goto fmterr;
257 if (fscanf(fp, "Next render: %d\n", &astat.rnext) != 1)
258 goto fmterr;
259 if (fscanf(fp, "Next filter: %d\n", &astat.fnext) != 1)
260 goto fmterr;
261 if (fscanf(fp, "Next transfer: %d\n", &astat.tnext) != 1)
262 goto fmterr;
263 fclose(fp);
264 if (astat.pid != 0) { /* thinks it's still running */
265 if (strcmp(myhostname(), astat.host)) {
266 fprintf(stderr,
267 "%s: process %d may still be running on host %s\n",
268 progname, astat.pid, astat.host);
269 return(-1);
270 }
271 if (kill(astat.pid, 0) != -1 || errno != ESRCH) {
272 fprintf(stderr, "%s: process %d is still running\n",
273 progname, astat.pid);
274 return(-1);
275 }
276 /* assume it is dead */
277 }
278 if (strcmp(cfname, astat.cfname) && astat.pid != 0) { /* other's */
279 fprintf(stderr, "%s: unfinished job \"%s\"\n",
280 progname, astat.cfname);
281 return(-1);
282 }
283 /* check control file mods. */
284 if (!nowarn && fdate(cfname) > fdate(sfname))
285 fprintf(stderr,
286 "%s: warning - control file modified since last run\n",
287 progname);
288 setours: /* set our values */
289 strcpy(astat.host, myhostname());
290 astat.pid = getpid();
291 strcpy(astat.cfname, cfname);
292 return(0);
293 fmterr:
294 fprintf(stderr, "%s: format error in status file \"%s\"\n",
295 progname, sfname);
296 fclose(fp);
297 return(-1);
298 }
299
300
301 static void
302 putastat(void) /* put out current status */
303 {
304 char buf[256];
305 FILE *fp;
306
307 if (noaction)
308 return;
309 sprintf(buf, "%s/%s", vval(DIRECTORY), SFNAME);
310 if ((fp = fopen(buf, "w")) == NULL) {
311 perror(buf);
312 quit(1);
313 }
314 fprintf(fp, "Control host: %s\n", astat.host);
315 fprintf(fp, "Control PID: %d\n", astat.pid);
316 fprintf(fp, "Control file: %s\n", astat.cfname);
317 fprintf(fp, "Next render: %d\n", astat.rnext);
318 fprintf(fp, "Next filter: %d\n", astat.fnext);
319 fprintf(fp, "Next transfer: %d\n", astat.tnext);
320 fclose(fp);
321 }
322
323
324 static void
325 checkdir(void) /* make sure we have our directory */
326 {
327 struct stat stb;
328
329 if (!vdef(DIRECTORY)) {
330 fprintf(stderr, "%s: %s undefined\n",
331 progname, vnam(DIRECTORY));
332 quit(1);
333 }
334 if (stat(vval(DIRECTORY), &stb) == -1) {
335 if (errno == ENOENT && mkdir(vval(DIRECTORY), 0777) == 0)
336 return;
337 perror(vval(DIRECTORY));
338 quit(1);
339 }
340 if (!(stb.st_mode & S_IFDIR)) {
341 fprintf(stderr, "%s: not a directory\n", vval(DIRECTORY));
342 quit(1);
343 }
344 }
345
346
347 static void
348 setdefaults(void) /* set default values */
349 {
350 extern char *atos();
351 int decades;
352 char buf[256];
353
354 if (vdef(ANIMATE)) {
355 vval(OCTREE) = NULL;
356 vdef(OCTREE) = 0;
357 } else if (!vdef(OCTREE)) {
358 fprintf(stderr, "%s: either %s or %s must be defined\n",
359 progname, vnam(OCTREE), vnam(ANIMATE));
360 quit(1);
361 }
362 if (!vdef(VIEWFILE)) {
363 fprintf(stderr, "%s: %s undefined\n", progname, vnam(VIEWFILE));
364 quit(1);
365 }
366 if (!vdef(HOST)) {
367 vval(HOST) = LHOSTNAME;
368 vdef(HOST)++;
369 }
370 if (!vdef(START)) {
371 vval(START) = "1";
372 vdef(START)++;
373 }
374 if (!vdef(END)) {
375 sprintf(buf, "%d", countviews()+vint(START)-1);
376 vval(END) = savqstr(buf);
377 vdef(END)++;
378 }
379 if (vint(END) < vint(START)) {
380 fprintf(stderr, "%s: ending frame less than starting frame\n",
381 progname);
382 quit(1);
383 }
384 if (!vdef(BASENAME)) {
385 decades = (int)log10((double)vint(END)) + 1;
386 if (decades < 3) decades = 3;
387 sprintf(buf, "%s/frame%%0%dd", vval(DIRECTORY), decades);
388 vval(BASENAME) = savqstr(buf);
389 vdef(BASENAME)++;
390 }
391 if (!vdef(RESOLUTION)) {
392 vval(RESOLUTION) = "640";
393 vdef(RESOLUTION)++;
394 }
395 if (!vdef(OVERSAMP)) {
396 vval(OVERSAMP) = "2";
397 vdef(OVERSAMP)++;
398 }
399 if (!vdef(INTERP)) {
400 vval(INTERP) = "0";
401 vdef(INTERP)++;
402 }
403 if (!vdef(MBLUR)) {
404 vval(MBLUR) = "0";
405 vdef(MBLUR)++;
406 }
407 if (!vdef(RTRACE)) {
408 vval(RTRACE) = "F";
409 vdef(RTRACE)++;
410 }
411 if (!vdef(DISKSPACE)) {
412 if (!nowarn)
413 fprintf(stderr,
414 "%s: warning - no %s setting, assuming 100 Mbytes available\n",
415 progname, vnam(DISKSPACE));
416 vval(DISKSPACE) = "100";
417 vdef(DISKSPACE)++;
418 }
419 if (!vdef(RSH)) {
420 vval(RSH) = REMSH;
421 vdef(RSH)++;
422 }
423 /* locate remote shell program */
424 atos(buf, sizeof(buf), vval(RSH));
425 if ((remsh = getpath(buf, getenv("PATH"), X_OK)) != NULL)
426 remsh = savqstr(remsh);
427 else
428 remsh = vval(RSH); /* will generate error if used */
429
430 /* append rendering options */
431 if (vdef(RENDER))
432 sprintf(rendopt+strlen(rendopt), " %s", vval(RENDER));
433 }
434
435
436 static void
437 sethosts(void) /* set up process servers */
438 {
439 extern char *iskip();
440 char buf[256], *dir, *uname;
441 int np;
442 register char *cp;
443 int i;
444
445 npslots = 0;
446 if (noaction)
447 return;
448 for (i = 0; i < vdef(HOST); i++) { /* add each host */
449 dir = uname = NULL;
450 np = 1;
451 strcpy(cp=buf, nvalue(HOST, i)); /* copy to buffer */
452 cp = sskip(cp); /* skip host name */
453 while (isspace(*cp))
454 *cp++ = '\0';
455 if (*cp) { /* has # processes? */
456 np = atoi(cp);
457 if ((cp = iskip(cp)) == NULL || (*cp && !isspace(*cp)))
458 badvalue(HOST);
459 while (isspace(*cp))
460 cp++;
461 if (*cp) { /* has directory? */
462 dir = cp;
463 cp = sskip(cp); /* skip dir. */
464 while (isspace(*cp))
465 *cp++ = '\0';
466 if (*cp) { /* has user? */
467 uname = cp;
468 if (*sskip(cp))
469 badvalue(HOST);
470 }
471 }
472 }
473 if (addpserver(buf, dir, uname, np) == NULL) {
474 if (!nowarn)
475 fprintf(stderr,
476 "%s: cannot execute on host \"%s\"\n",
477 progname, buf);
478 } else
479 npslots += np;
480 }
481 if (npslots == 0) {
482 fprintf(stderr, "%s: no working process servers\n", progname);
483 quit(1);
484 }
485 pslot = (struct pslot *)calloc(npslots, sizeof(struct pslot));
486 if (pslot == NULL) {
487 perror("malloc");
488 quit(1);
489 }
490 }
491
492 static void
493 getradfile(char *rfargs) /* run rad and get needed variables */
494 {
495 static short mvar[] = {OCTREE,PFILT,RESOLUTION,EXPOSURE,-1};
496 char combuf[256];
497 register int i;
498 register char *cp;
499 char *pippt = NULL;
500 /* create rad command */
501 sprintf(rendopt, " @%s/render.opt", vval(DIRECTORY));
502 sprintf(combuf,
503 "rad -v 0 -s -e -w %s OPTFILE=%s | egrep '^[ \t]*(NOMATCH",
504 rfargs, rendopt+2);
505 cp = combuf;
506 while (*cp) {
507 if (*cp == '|') pippt = cp;
508 cp++;
509 } /* match unset variables */
510 for (i = 0; mvar[i] >= 0; i++)
511 if (!vdef(mvar[i])) {
512 *cp++ = '|';
513 strcpy(cp, vnam(mvar[i]));
514 while (*cp) cp++;
515 pippt = NULL;
516 }
517 if (pippt != NULL)
518 strcpy(pippt, "> " NULL_DEVICE); /* nothing to match */
519 else {
520 sprintf(cp, ")[ \t]*=' > %s/radset.var", vval(DIRECTORY));
521 cp += 11; /* point to file name */
522 }
523 system(combuf); /* ignore exit code */
524 if (pippt == NULL) { /* load variables and remove file */
525 loadvars(cp);
526 unlink(cp);
527 }
528 }
529
530
531 static void
532 animate(void) /* run animation */
533 {
534 int xres, yres;
535 float pa, mult;
536 int frames_batch;
537 register int i;
538 double d1, d2;
539 /* compute rpict resolution */
540 i = sscanf(vval(RESOLUTION), "%d %d %f", &xres, &yres, &pa);
541 mult = vflt(OVERSAMP);
542 if (i == 3) {
543 sprintf(rresopt, "-x %d -y %d -pa %.3f", (int)(mult*xres),
544 (int)(mult*yres), pa);
545 sprintf(fresopt, "-x %d -y %d -pa %.3f", xres, yres, pa);
546 } else if (i) {
547 if (i == 1) yres = xres;
548 sprintf(rresopt, "-x %d -y %d", (int)(mult*xres),
549 (int)(mult*yres));
550 sprintf(fresopt, "-x %d -y %d -pa 1", xres, yres);
551 } else
552 badvalue(RESOLUTION);
553 /* consistency checks */
554 if (vdef(ANIMATE)) {
555 if (vint(INTERP)) {
556 if (!nowarn)
557 fprintf(stderr,
558 "%s: resetting %s=0 for animation\n",
559 progname, vnam(INTERP));
560 vval(INTERP) = "0";
561 }
562 if (strcmp(vval(MBLUR),"0")) { /* can't handle this */
563 if (!nowarn)
564 fprintf(stderr,
565 "%s: resetting %s=0 for animation\n",
566 progname, vnam(MBLUR));
567 vval(MBLUR) = "0";
568 }
569 }
570 /* figure # frames per batch */
571 d1 = mult*xres*mult*yres*4; /* space for orig. picture */
572 if ((i=vint(INTERP)) || getblur(NULL) > 1)
573 d1 += mult*xres*mult*yres*sizeof(float); /* Z-buffer */
574 d2 = xres*yres*4; /* space for final picture */
575 frames_batch = (i+1)*(vflt(DISKSPACE)*1048576.-d1)/(d1+i*d2);
576 if (frames_batch < i+2) {
577 fprintf(stderr, "%s: insufficient disk space allocated\n",
578 progname);
579 quit(1);
580 }
581 /* initialize archive argument list */
582 i = vdef(ARCHIVE) ? strlen(vval(ARCHIVE))+132 : 132;
583 arcnext = arcfirst = arcargs + i;
584 /* initialize status file */
585 if (astat.rnext == 0)
586 astat.rnext = astat.fnext = astat.tnext = vint(START);
587 putastat();
588 /* render in batches */
589 while (astat.tnext <= vint(END)) {
590 renderframes(frames_batch);
591 filterframes();
592 transferframes();
593 }
594 /* mark status as finished */
595 astat.pid = 0;
596 putastat();
597 /* close open files */
598 getview(0);
599 getexp(0);
600 }
601
602
603 static void
604 renderframes(int nframes) /* render next nframes frames */
605 {
606 static char vendbuf[16];
607 VIEW *vp;
608 FILE *fp = NULL;
609 char vfname[128];
610 int lastframe;
611 register int i;
612
613 if (astat.tnext < astat.rnext) /* other work to do first */
614 return;
615 /* create batch view file */
616 if (!vdef(ANIMATE)) {
617 sprintf(vfname, "%s/anim.vf", vval(DIRECTORY));
618 if ((fp = fopen(vfname, "w")) == NULL) {
619 perror(vfname);
620 quit(1);
621 }
622 }
623 /* bound batch properly */
624 lastframe = astat.rnext + nframes - 1;
625 if ((lastframe-1) % (vint(INTERP)+1)) /* need even interval */
626 lastframe += vint(INTERP)+1 - ((lastframe-1)%(vint(INTERP)+1));
627 if (lastframe > vint(END)) /* check for end */
628 lastframe = vint(END);
629 /* render each view */
630 for (i = astat.rnext; i <= lastframe; i++) {
631 if ((vp = getview(i)) == NULL) {
632 if (!nowarn)
633 fprintf(stderr,
634 "%s: ran out of views before last frame\n",
635 progname);
636 sprintf(vval(END)=vendbuf, "%d", i-1);
637 lastframe = i - 1;
638 break;
639 }
640 if (vdef(ANIMATE)) /* animate frame */
641 animrend(i, vp);
642 else { /* else record it */
643 fputs(VIEWSTR, fp);
644 fprintview(vp, fp);
645 putc('\n', fp);
646 }
647 }
648 if (vdef(ANIMATE)) /* wait for renderings to finish */
649 bwait(0);
650 else { /* else if walk-through */
651 fclose(fp); /* close view file */
652 walkwait(astat.rnext, lastframe, vfname); /* walk it */
653 unlink(vfname); /* remove view file */
654 }
655 astat.rnext = i; /* update status */
656 putastat();
657 }
658
659
660 static void
661 filterframes(void) /* catch up with filtering */
662 {
663 register int i;
664
665 if (astat.tnext < astat.fnext) /* other work to do first */
666 return;
667 /* filter each view */
668 for (i = astat.fnext; i < astat.rnext; i++)
669 dofilt(i, 0);
670
671 bwait(0); /* wait for filter processes */
672 archive(); /* archive originals */
673 astat.fnext = i; /* update status */
674 putastat();
675 }
676
677
678 static void
679 transferframes(void) /* catch up with picture transfers */
680 {
681 char combuf[10240], *fbase;
682 register char *cp;
683 register int i;
684
685 if (astat.tnext >= astat.fnext) /* nothing to do, yet */
686 return;
687 if (!vdef(TRANSFER)) { /* no transfer function -- leave 'em */
688 astat.tnext = astat.fnext;
689 putastat(); /* update status */
690 return;
691 }
692 strcpy(combuf, "cd "); /* start transfer command */
693 fbase = dirfile(cp = combuf+3, vval(BASENAME));
694 if (*cp) {
695 while (*++cp) ;
696 *cp++ = ';'; *cp++ = ' ';
697 } else
698 cp = combuf;
699 strcpy(cp, vval(TRANSFER));
700 while (*cp) cp++;
701 /* make argument list */
702 for (i = astat.tnext; i < astat.fnext; i++) {
703 *cp++ = ' ';
704 sprintf(cp, fbase, i);
705 while (*cp) cp++;
706 strcpy(cp, ".pic");
707 cp += 4;
708 }
709 if (runcom(combuf)) { /* transfer frames */
710 fprintf(stderr, "%s: error running transfer command\n",
711 progname);
712 quit(1);
713 }
714 astat.tnext = i; /* update status */
715 putastat();
716 }
717
718
719 static void
720 animrend( /* start animation frame */
721 int frame,
722 VIEW *vp
723 )
724 {
725 char combuf[2048];
726 char fname[128];
727
728 sprintf(fname, vval(BASENAME), frame);
729 strcat(fname, ".unf");
730 if (access(fname, F_OK) == 0)
731 return;
732 sprintf(combuf, "%s %d | rpict%s%s -w0 %s > %s", vval(ANIMATE), frame,
733 rendopt, viewopt(vp), rresopt, fname);
734 bruncom(combuf, frame, recover); /* run in background */
735 }
736
737
738 static void
739 walkwait( /* walk-through frames */
740 int first,
741 int last,
742 char *vfn
743 )
744 {
745 double blurf;
746 int nblur = getblur(&blurf);
747 char combuf[2048];
748 register char *inspoint;
749 register int i;
750
751 if (!noaction && vint(INTERP)) /* create dummy frames */
752 for (i = first; i <= last; i++)
753 if (i < vint(END) && (i-1) % (vint(INTERP)+1)) {
754 sprintf(combuf, vval(BASENAME), i);
755 strcat(combuf, ".unf");
756 close(open(combuf, O_RDONLY|O_CREAT, 0666));
757 }
758 /* create command */
759 sprintf(combuf, "rpict%s%s -w0", rendopt,
760 viewopt(getview(first>1 ? first-1 : 1)));
761 inspoint = combuf;
762 while (*inspoint) inspoint++;
763 if (nblur) {
764 sprintf(inspoint, " -pm %.3f", blurf/nblur);
765 while (*inspoint) inspoint++;
766 }
767 if (nblur > 1 || vint(INTERP)) {
768 sprintf(inspoint, " -z %s.zbf", vval(BASENAME));
769 while (*inspoint) inspoint++;
770 }
771 sprintf(inspoint, " -o %s.unf %s -S %d",
772 vval(BASENAME), rresopt, first);
773 while (*inspoint) inspoint++;
774 sprintf(inspoint, " %s < %s", vval(OCTREE), vfn);
775 /* run in parallel */
776 i = (last-first+1)/(vint(INTERP)+1);
777 if (i < 1) i = 1;
778 if (pruncom(combuf, inspoint, i)) {
779 fprintf(stderr, "%s: error rendering frames %d through %d\n",
780 progname, first, last);
781 quit(1);
782 }
783 if (!noaction && vint(INTERP)) /* remove dummy frames */
784 for (i = first; i <= last; i++)
785 if (i < vint(END) && (i-1) % (vint(INTERP)+1)) {
786 sprintf(combuf, vval(BASENAME), i);
787 strcat(combuf, ".unf");
788 unlink(combuf);
789 }
790 }
791
792
793 static int
794 recover(int frame) /* recover the specified frame */
795 {
796 static int *rfrm; /* list of recovered frames */
797 static int nrfrms = 0;
798 double blurf;
799 int nblur = getblur(&blurf);
800 char combuf[2048];
801 char fname[128];
802 register char *cp;
803 register int i;
804 /* check to see if recovered already */
805 for (i = nrfrms; i--; )
806 if (rfrm[i] == frame)
807 return(0);
808 /* build command */
809 sprintf(fname, vval(BASENAME), frame);
810 if (vdef(ANIMATE))
811 sprintf(combuf, "%s %d | rpict%s -w0",
812 vval(ANIMATE), frame, rendopt);
813 else
814 sprintf(combuf, "rpict%s -w0", rendopt);
815 cp = combuf;
816 while (*cp) cp++;
817 if (nblur) {
818 sprintf(cp, " -pm %.3f", blurf/nblur);
819 while (*cp) cp++;
820 }
821 if (nblur > 1 || vint(INTERP)) {
822 sprintf(cp, " -z %s.zbf", fname);
823 while (*cp) cp++;
824 }
825 sprintf(cp, " -ro %s.unf", fname);
826 while (*cp) cp++;
827 if (!vdef(ANIMATE)) {
828 *cp++ = ' ';
829 strcpy(cp, vval(OCTREE));
830 }
831 if (runcom(combuf)) /* run command */
832 return(1);
833 /* add frame to recovered list */
834 if (nrfrms)
835 rfrm = (int *)realloc((void *)rfrm, (nrfrms+1)*sizeof(int));
836 else
837 rfrm = (int *)malloc(sizeof(int));
838 if (rfrm == NULL) {
839 perror("malloc");
840 quit(1);
841 }
842 rfrm[nrfrms++] = frame;
843 return(0);
844 }
845
846
847 static int
848 frecover(int frame) /* recover filtered frame */
849 {
850 if (dofilt(frame, 2) && dofilt(frame, 1))
851 return(1);
852 return(0);
853 }
854
855
856 static void
857 archive(void) /* archive and remove renderings */
858 {
859 #define RMCOML (sizeof(rmcom)-1)
860 static char rmcom[] = "rm -f";
861 char basedir[128];
862 int dlen, alen;
863 register int j;
864
865 if (arcnext == arcfirst)
866 return; /* nothing to do */
867 dirfile(basedir, vval(BASENAME));
868 dlen = strlen(basedir);
869 if (vdef(ARCHIVE)) { /* run archive command */
870 alen = strlen(vval(ARCHIVE));
871 if (dlen) {
872 j = alen + dlen + 5;
873 strncpy(arcfirst-j, "cd ", 3);
874 strncpy(arcfirst-j+3, basedir, dlen);
875 (arcfirst-j)[dlen+3] = ';'; (arcfirst-j)[dlen+4] = ' ';
876 } else
877 j = alen;
878 strncpy(arcfirst-alen, vval(ARCHIVE), alen);
879 if (runcom(arcfirst-j)) {
880 fprintf(stderr, "%s: error running archive command\n",
881 progname);
882 quit(1);
883 }
884 }
885 if (dlen) {
886 j = RMCOML + dlen + 5;
887 strncpy(arcfirst-j, "cd ", 3);
888 strncpy(arcfirst-j+3, basedir, dlen);
889 (arcfirst-j)[dlen+3] = ';'; (arcfirst-j)[dlen+4] = ' ';
890 } else
891 j = RMCOML;
892 /* run remove command */
893 strncpy(arcfirst-RMCOML, rmcom, RMCOML);
894 runcom(arcfirst-j);
895 arcnext = arcfirst; /* reset argument list */
896 #undef RMCOML
897 }
898
899
900 static int
901 dofilt( /* filter frame */
902 int frame,
903 int rvr
904 )
905 {
906 static int iter = 0;
907 double blurf;
908 int nblur = getblur(&blurf);
909 VIEW *vp = getview(frame);
910 char *ep = getexp(frame);
911 char fnbefore[128], fnafter[128], *fbase;
912 char combuf[1024], fname0[128], fname1[128];
913 int usepinterp, usepfilt, nora_rgbe;
914 int frseq[2];
915 /* check what is needed */
916 if (vp == NULL) {
917 fprintf(stderr,
918 "%s: unexpected error reading view for frame %d\n",
919 progname, frame);
920 quit(1);
921 }
922 usepinterp = (nblur > 1);
923 usepfilt = pfiltalways | (ep==NULL);
924 if (ep != NULL && !strcmp(ep, "1"))
925 ep = "+0";
926 nora_rgbe = strcmp(vval(OVERSAMP),"1") || ep==NULL ||
927 *ep != '+' || *ep != '-' || !isint(ep);
928 /* compute rendered views */
929 frseq[0] = frame - ((frame-1) % (vint(INTERP)+1));
930 frseq[1] = frseq[0] + vint(INTERP) + 1;
931 fbase = dirfile(NULL, vval(BASENAME));
932 if (frseq[1] > vint(END))
933 frseq[1] = vint(END);
934 if (frseq[1] == frame) { /* pfilt only */
935 frseq[0] = frseq[1];
936 usepinterp = 0; /* update what's needed */
937 usepfilt |= nora_rgbe;
938 } else if (frseq[0] == frame) { /* no interpolation needed */
939 if (!rvr && frame > 1+vint(INTERP)) { /* archive previous */
940 *arcnext++ = ' ';
941 sprintf(arcnext, fbase, frame-vint(INTERP)-1);
942 while (*arcnext) arcnext++;
943 strcpy(arcnext, ".unf");
944 arcnext += 4;
945 if (usepinterp || vint(INTERP)) { /* and Z-buf */
946 *arcnext++ = ' ';
947 sprintf(arcnext, fbase, frame-vint(INTERP)-1);
948 while (*arcnext) arcnext++;
949 strcpy(arcnext, ".zbf");
950 arcnext += 4;
951 }
952 }
953 if (!usepinterp) /* update what's needed */
954 usepfilt |= nora_rgbe;
955 } else /* interpolation needed */
956 usepinterp++;
957 if (frseq[1] >= astat.rnext) /* next batch unavailable */
958 frseq[1] = frseq[0];
959 sprintf(fnbefore, vval(BASENAME), frseq[0]);
960 sprintf(fnafter, vval(BASENAME), frseq[1]);
961 if (rvr == 1 && recover(frseq[0])) /* recover before frame? */
962 return(1);
963 /* generate command */
964 if (usepinterp) { /* using pinterp */
965 if (rvr == 2 && recover(frseq[1])) /* recover after? */
966 return(1);
967 if (nblur > 1) { /* with pmblur */
968 sprintf(fname0, "%s/vw0%c", vval(DIRECTORY),
969 'a'+(iter%26));
970 sprintf(fname1, "%s/vw1%c", vval(DIRECTORY),
971 'a'+(iter%26));
972 if (!noaction) {
973 FILE *fp; /* motion blurring */
974 if ((fp = fopen(fname0, "w")) == NULL) {
975 perror(fname0); quit(1);
976 }
977 fputs(VIEWSTR, fp);
978 fprintview(vp, fp);
979 putc('\n', fp); fclose(fp);
980 if ((vp = getview(frame+1)) == NULL) {
981 fprintf(stderr,
982 "%s: unexpected error reading view for frame %d\n",
983 progname, frame+1);
984 quit(1);
985 }
986 if ((fp = fopen(fname1, "w")) == NULL) {
987 perror(fname1); quit(1);
988 }
989 fputs(VIEWSTR, fp);
990 fprintview(vp, fp);
991 putc('\n', fp); fclose(fp);
992 }
993 sprintf(combuf,
994 "(pmblur %.3f %d %s %s; rm -f %s %s) | pinterp -B -a",
995 blurf, nblur,
996 fname0, fname1, fname0, fname1);
997 iter++;
998 } else /* no blurring */
999 strcpy(combuf, "pinterp");
1000 strcat(combuf, viewopt(vp));
1001 if (vbool(RTRACE))
1002 sprintf(combuf+strlen(combuf), " -ff -fr '%s -w0 %s'",
1003 rendopt+1, vval(OCTREE));
1004 if (vdef(PINTERP))
1005 sprintf(combuf+strlen(combuf), " %s", vval(PINTERP));
1006 if (usepfilt)
1007 sprintf(combuf+strlen(combuf), " %s", rresopt);
1008 else
1009 sprintf(combuf+strlen(combuf), " -a %s -e %s",
1010 fresopt, ep);
1011 sprintf(combuf+strlen(combuf), " %s.unf %s.zbf",
1012 fnbefore, fnbefore);
1013 if (frseq[1] != frseq[0])
1014 sprintf(combuf+strlen(combuf), " %s.unf %s.zbf",
1015 fnafter, fnafter);
1016 if (usepfilt) { /* also pfilt */
1017 if (vdef(PFILT))
1018 sprintf(combuf+strlen(combuf), " | pfilt %s",
1019 vval(PFILT));
1020 else
1021 strcat(combuf, " | pfilt");
1022 if (ep != NULL)
1023 sprintf(combuf+strlen(combuf), " -1 -e %s %s",
1024 ep, fresopt);
1025 else
1026 sprintf(combuf+strlen(combuf), " %s", fresopt);
1027 }
1028 } else if (usepfilt) { /* pfilt only */
1029 if (rvr == 2)
1030 return(1);
1031 if (vdef(PFILT))
1032 sprintf(combuf, "pfilt %s", vval(PFILT));
1033 else
1034 strcpy(combuf, "pfilt");
1035 if (ep != NULL)
1036 sprintf(combuf+strlen(combuf), " -1 -e %s %s %s.unf",
1037 ep, fresopt, fnbefore);
1038 else
1039 sprintf(combuf+strlen(combuf), " %s %s.unf",
1040 fresopt, fnbefore);
1041 } else { /* else just check it */
1042 if (rvr == 2)
1043 return(1);
1044 sprintf(combuf, "ra_rgbe -e %s -r %s.unf", ep, fnbefore);
1045 }
1046 /* output file name */
1047 sprintf(fname0, vval(BASENAME), frame);
1048 sprintf(combuf+strlen(combuf), " > %s.pic", fname0);
1049 if (rvr) /* in recovery */
1050 return(runcom(combuf));
1051 bruncom(combuf, frame, frecover); /* else run in background */
1052 return(0);
1053 }
1054
1055
1056 static VIEW *
1057 getview(int n) /* get view number n */
1058 {
1059 static FILE *viewfp = NULL; /* view file pointer */
1060 static int viewnum = 0; /* current view number */
1061 static VIEW curview = STDVIEW; /* current view */
1062 char linebuf[256];
1063
1064 if (n == 0) { /* signal to close file and clean up */
1065 if (viewfp != NULL) {
1066 fclose(viewfp);
1067 viewfp = NULL;
1068 viewnum = 0;
1069 curview = stdview;
1070 }
1071 return(NULL);
1072 }
1073 if (viewfp == NULL) { /* open file */
1074 if ((viewfp = fopen(vval(VIEWFILE), "r")) == NULL) {
1075 perror(vval(VIEWFILE));
1076 quit(1);
1077 }
1078 } else if (n > 0 && n < viewnum) { /* rewind file */
1079 if (viewnum == 1 && feof(viewfp))
1080 return(&curview); /* just one view */
1081 if (fseek(viewfp, 0L, 0) == EOF) {
1082 perror(vval(VIEWFILE));
1083 quit(1);
1084 }
1085 curview = stdview;
1086 viewnum = 0;
1087 }
1088 if (n < 0) { /* get next view */
1089 register int c = getc(viewfp);
1090 if (c == EOF)
1091 return((VIEW *)NULL); /* that's it */
1092 ungetc(c, viewfp);
1093 n = viewnum + 1;
1094 }
1095 while (n > viewnum) { /* scan to desired view */
1096 if (fgets(linebuf, sizeof(linebuf), viewfp) == NULL)
1097 return(viewnum==1 ? &curview : (VIEW *)NULL);
1098 if (isview(linebuf) && sscanview(&curview, linebuf) > 0)
1099 viewnum++;
1100 }
1101 return(&curview); /* return it */
1102 }
1103
1104
1105 static int
1106 countviews(void) /* count views in view file */
1107 {
1108 int n;
1109
1110 if (getview(n=1) == NULL)
1111 return(0);
1112 while (getview(-1) != NULL)
1113 n++;
1114 return(n);
1115 }
1116
1117
1118 static char *
1119 getexp(int n) /* get exposure for nth frame */
1120 {
1121 extern char *fskip();
1122 static char expval[32];
1123 static FILE *expfp = NULL;
1124 static long *exppos;
1125 static int curfrm;
1126 register char *cp;
1127
1128 if (n == 0) { /* signal to close file */
1129 if (expfp != NULL) {
1130 fclose(expfp);
1131 free((void *)exppos);
1132 expfp = NULL;
1133 }
1134 return(NULL);
1135 } else if (n > vint(END)) /* request past end (error?) */
1136 return(NULL);
1137 if (!vdef(EXPOSURE)) /* no setting (auto) */
1138 return(NULL);
1139 if (isflt(vval(EXPOSURE))) /* always the same */
1140 return(vval(EXPOSURE));
1141 if (expfp == NULL) { /* open exposure file */
1142 if ((expfp = fopen(vval(EXPOSURE), "r")) == NULL) {
1143 fprintf(stderr,
1144 "%s: cannot open exposure file \"%s\"\n",
1145 progname, vval(EXPOSURE));
1146 quit(1);
1147 }
1148 curfrm = vint(END) + 1; /* init lookup tab. */
1149 exppos = (long *)malloc(curfrm*sizeof(long *));
1150 if (exppos == NULL) {
1151 perror(progname);
1152 quit(1);
1153 }
1154 while (curfrm--)
1155 exppos[curfrm] = -1L;
1156 curfrm = 0;
1157 }
1158 /* find position in file */
1159 if (n-1 != curfrm && n != curfrm && exppos[n-1] >= 0 &&
1160 fseek(expfp, exppos[curfrm=n-1], 0) == EOF) {
1161 fprintf(stderr, "%s: seek error on exposure file\n", progname);
1162 quit(1);
1163 }
1164 while (n > curfrm) { /* read exposure */
1165 if (exppos[curfrm] < 0)
1166 exppos[curfrm] = ftell(expfp);
1167 if (fgets(expval, sizeof(expval), expfp) == NULL) {
1168 fprintf(stderr, "%s: too few exposures\n",
1169 vval(EXPOSURE));
1170 quit(1);
1171 }
1172 curfrm++;
1173 cp = fskip(expval); /* check format */
1174 if (cp != NULL)
1175 while (isspace(*cp))
1176 *cp++ = '\0';
1177 if (cp == NULL || *cp) {
1178 fprintf(stderr,
1179 "%s: exposure format error on line %d\n",
1180 vval(EXPOSURE), curfrm);
1181 quit(1);
1182 }
1183 }
1184 return(expval); /* return value */
1185 }
1186
1187
1188 static struct pslot *
1189 findpslot(int pid) /* find or allocate a process slot */
1190 {
1191 register struct pslot *psempty = NULL;
1192 register int i;
1193
1194 for (i = 0; i < npslots; i++) { /* look for match */
1195 if (pslot[i].pid == pid)
1196 return(pslot+i);
1197 if (psempty == NULL && pslot[i].pid == 0)
1198 psempty = pslot+i;
1199 }
1200 return(psempty); /* return emtpy slot (error if NULL) */
1201 }
1202
1203
1204 static int
1205 donecom( /* clean up after finished process */
1206 PSERVER *ps,
1207 int pn,
1208 int status
1209 )
1210 {
1211 register NETPROC *pp;
1212 register struct pslot *psl;
1213
1214 pp = ps->proc + pn;
1215 if (pp->elen) { /* pass errors */
1216 if (ps->hostname[0])
1217 fprintf(stderr, "%s: ", ps->hostname);
1218 fprintf(stderr, "Error output from: %s\n", pp->com);
1219 fputs(pp->errs, stderr);
1220 fflush(stderr);
1221 if (ps->hostname[0])
1222 status = 1; /* because rsh doesn't return status */
1223 }
1224 lastpserver = NULL;
1225 psl = findpslot(pp->pid); /* check for bruncom() slot */
1226 if (psl->pid) {
1227 if (status) {
1228 if (psl->rcvf != NULL) /* attempt recovery */
1229 status = (*psl->rcvf)(psl->fout);
1230 if (status) {
1231 fprintf(stderr,
1232 "%s: error rendering frame %d\n",
1233 progname, psl->fout);
1234 quit(1);
1235 }
1236 lastpserver = ps;
1237 }
1238 psl->pid = 0; /* free process slot */
1239 } else if (status)
1240 lastpserver = ps;
1241 freestr(pp->com); /* free command string */
1242 return(status);
1243 }
1244
1245
1246 static int
1247 serverdown(void) /* check status of last process server */
1248 {
1249 if (lastpserver == NULL || !lastpserver->hostname[0])
1250 return(0);
1251 if (pserverOK(lastpserver)) /* server still up? */
1252 return(0);
1253 delpserver(lastpserver); /* else delete it */
1254 if (pslist == NULL) {
1255 fprintf(stderr, "%s: all process servers are down\n",
1256 progname);
1257 quit(1);
1258 }
1259 return(1);
1260 }
1261
1262
1263 static int
1264 bruncom( /* run a command in the background */
1265 char *com,
1266 int fout,
1267 int (*rf)()
1268 )
1269 {
1270 int pid;
1271 register struct pslot *psl;
1272
1273 if (noaction) {
1274 if (!silent)
1275 printf("\t%s\n", com); /* echo command */
1276 return(0);
1277 }
1278 com = savestr(com); /* else start it when we can */
1279 while ((pid = startjob(NULL, com, donecom)) == -1)
1280 bwait(1);
1281 if (!silent) { /* echo command */
1282 PSERVER *ps;
1283 int psn = pid;
1284 ps = findjob(&psn);
1285 printf("\t%s\n", com);
1286 printf("\tProcess started on %s\n", phostname(ps));
1287 fflush(stdout);
1288 }
1289 psl = findpslot(pid); /* record info. in appropriate slot */
1290 psl->pid = pid;
1291 psl->fout = fout;
1292 psl->rcvf = rf;
1293 return(pid);
1294 }
1295
1296
1297 static void
1298 bwait(int ncoms) /* wait for batch job(s) to finish */
1299 {
1300 int status;
1301
1302 if (noaction)
1303 return;
1304 while ((status = wait4job(NULL, -1)) != -1) {
1305 serverdown(); /* update server status */
1306 if (--ncoms == 0)
1307 break; /* done enough */
1308 }
1309 }
1310
1311
1312 static int
1313 pruncom( /* run a command in parallel over network */
1314 char *com,
1315 char *ppins,
1316 int maxcopies
1317 )
1318 {
1319 int retstatus = 0;
1320 int hostcopies;
1321 char buf[10240], *com1, *s;
1322 int status;
1323 int pfd;
1324 register int n;
1325 register PSERVER *ps;
1326
1327 if (!silent)
1328 printf("\t%s\n", com); /* echo command */
1329 if (noaction)
1330 return(0);
1331 fflush(stdout);
1332 /* start jobs on each server */
1333 for (ps = pslist; ps != NULL; ps = ps->next) {
1334 hostcopies = 0;
1335 if (maxcopies > 1 && ps->nprocs > 1 && ppins != NULL) {
1336 strcpy(com1=buf, com); /* build -PP command */
1337 sprintf(com1+(ppins-com), " -PP %s/%s.persist",
1338 vval(DIRECTORY), phostname(ps));
1339 unlink(com1+(ppins-com)+5);
1340 strcat(com1, ppins);
1341 } else
1342 com1 = com;
1343 while (maxcopies > 0) {
1344 s = savestr(com1);
1345 if (startjob(ps, s, donecom) != -1) {
1346 sleep(20);
1347 hostcopies++;
1348 maxcopies--;
1349 } else {
1350 freestr(s);
1351 break;
1352 }
1353 }
1354 if (!silent && hostcopies) {
1355 if (hostcopies > 1)
1356 printf("\t%d duplicate processes", hostcopies);
1357 else
1358 printf("\tProcess");
1359 printf(" started on %s\n", phostname(ps));
1360 fflush(stdout);
1361 }
1362 }
1363 /* wait for jobs to finish */
1364 while ((status = wait4job(NULL, -1)) != -1)
1365 retstatus += status && !serverdown();
1366 /* terminate parallel rpict's */
1367 for (ps = pslist; ps != NULL; ps = ps->next) {
1368 sprintf(buf, "%s/%s.persist", vval(DIRECTORY), phostname(ps));
1369 if ((pfd = open(buf, O_RDONLY)) >= 0) {
1370 n = read(pfd, buf, sizeof(buf)-1); /* get PID */
1371 buf[n] = '\0';
1372 close(pfd);
1373 for (n = 0; buf[n] && !isspace(buf[n]); n++)
1374 ;
1375 /* terminate */
1376 sprintf(buf, "kill -ALRM %d", atoi(buf+n));
1377 wait4job(ps, startjob(ps, buf, NULL));
1378 }
1379 }
1380 return(retstatus);
1381 }
1382
1383
1384 static int
1385 runcom(char *cs) /* run a command locally and wait for it */
1386 {
1387 if (!silent) /* echo it */
1388 printf("\t%s\n", cs);
1389 if (noaction)
1390 return(0);
1391 fflush(stdout); /* flush output and pass to shell */
1392 return(system(cs));
1393 }
1394
1395
1396 static int
1397 rmfile(char *fn) /* remove a file */
1398 {
1399 if (!silent)
1400 #ifdef _WIN32
1401 printf("\tdel %s\n", fn);
1402 #else
1403 printf("\trm -f %s\n", fn);
1404 #endif
1405 if (noaction)
1406 return(0);
1407 return(unlink(fn));
1408 }
1409
1410
1411 static void
1412 badvalue(int vc) /* report bad variable value and exit */
1413 {
1414 fprintf(stderr, "%s: bad value for variable '%s'\n",
1415 progname, vnam(vc));
1416 quit(1);
1417 }
1418
1419
1420 static char *
1421 dirfile( /* separate path into directory and file */
1422 char *df,
1423 register char *path
1424 )
1425 {
1426 register int i;
1427 int psep;
1428
1429 for (i = 0, psep = -1; path[i]; i++)
1430 if (path[i] == '/')
1431 psep = i;
1432 if (df != NULL) {
1433 if (psep == 0) {
1434 df[0] = '/';
1435 df[1] = '\0';
1436 } else if (psep > 0) {
1437 strncpy(df, path, psep);
1438 df[psep] = '\0';
1439 } else
1440 df[0] = '\0';
1441 }
1442 return(path+psep+1);
1443 }
1444
1445
1446 static int
1447 getblur(double *bf) /* get # blur samples (and fraction) */
1448 {
1449 double blurf;
1450 int nblur;
1451 char *s;
1452
1453 if (!vdef(MBLUR)) {
1454 if (bf != NULL)
1455 *bf = 0.0;
1456 return(0);
1457 }
1458 blurf = atof(vval(MBLUR));
1459 if (blurf < 0.0)
1460 blurf = 0.0;
1461 if (bf != NULL)
1462 *bf = blurf;
1463 if (blurf <= FTINY)
1464 return(0);
1465 s = sskip(vval(MBLUR));
1466 if (!*s)
1467 return(DEF_NBLUR);
1468 nblur = atoi(s);
1469 if (nblur <= 0)
1470 return(1);
1471 return(nblur);
1472 }