ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/ranimove.c
Revision: 3.1
Committed: Sat Feb 22 02:07:30 2003 UTC (21 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Changes and check-in for 3.5 release
Includes new source files and modifications not recorded for many years
See ray/doc/notes/ReleaseNotes for notes between 3.1 and 3.5 release

File Contents

# User Rev Content
1 greg 3.1 #ifndef lint
2     static const char RCSid[] = "$Id$";
3     #endif
4     /*
5     * Radiance object animation program
6     *
7     * Main program and control file handling.
8     *
9     * See ranimove.h and the ranimove(1) man page for details.
10     */
11    
12     /* ====================================================================
13     * The Radiance Software License, Version 1.0
14     *
15     * Copyright (c) 1990 - 2002 The Regents of the University of California,
16     * through Lawrence Berkeley National Laboratory. All rights reserved.
17     *
18     * Redistribution and use in source and binary forms, with or without
19     * modification, are permitted provided that the following conditions
20     * are met:
21     *
22     * 1. Redistributions of source code must retain the above copyright
23     * notice, this list of conditions and the following disclaimer.
24     *
25     * 2. Redistributions in binary form must reproduce the above copyright
26     * notice, this list of conditions and the following disclaimer in
27     * the documentation and/or other materials provided with the
28     * distribution.
29     *
30     * 3. The end-user documentation included with the redistribution,
31     * if any, must include the following acknowledgment:
32     * "This product includes Radiance software
33     * (http://radsite.lbl.gov/)
34     * developed by the Lawrence Berkeley National Laboratory
35     * (http://www.lbl.gov/)."
36     * Alternately, this acknowledgment may appear in the software itself,
37     * if and wherever such third-party acknowledgments normally appear.
38     *
39     * 4. The names "Radiance," "Lawrence Berkeley National Laboratory"
40     * and "The Regents of the University of California" must
41     * not be used to endorse or promote products derived from this
42     * software without prior written permission. For written
43     * permission, please contact [email protected].
44     *
45     * 5. Products derived from this software may not be called "Radiance",
46     * nor may "Radiance" appear in their name, without prior written
47     * permission of Lawrence Berkeley National Laboratory.
48     *
49     * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
50     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
51     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
52     * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR
53     * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54     * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
56     * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
57     * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
58     * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
59     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60     * SUCH DAMAGE.
61     * ====================================================================
62     *
63     * This software consists of voluntary contributions made by many
64     * individuals on behalf of Lawrence Berkeley National Laboratory. For more
65     * information on Lawrence Berkeley National Laboratory, please see
66     * <http://www.lbl.gov/>.
67     */
68    
69     #include "ranimove.h"
70     #include <sys/time.h>
71     #include <ctype.h>
72    
73     int NVARS = NV_INIT; /* total number of variables */
74    
75     VARIABLE vv[] = VV_INIT; /* variable-value pairs */
76    
77     extern int nowarn; /* don't report warnings? */
78     int silent = 0; /* run silently? */
79    
80     int quickstart = 0; /* time initial frame as well? */
81    
82     int nprocs = 1; /* number of rendering processes */
83    
84     int rtperfrm = 60; /* seconds to spend per frame */
85    
86     double ndthresh = 2.; /* noticeable difference threshold */
87     int ndtset = 0; /* user threshold -- stop when reached? */
88    
89     int fbeg = 1; /* starting frame */
90     int fend = 0; /* ending frame */
91     int fcur; /* current frame being rendered */
92    
93     char lorendoptf[32]; /* low quality options file */
94     RAYPARAMS lorendparams; /* low quality rendering parameters */
95     char hirendoptf[32]; /* high quality options file */
96     RAYPARAMS hirendparams; /* high quality rendering parameters */
97     RAYPARAMS *curparams; /* current parameter settings */
98     int twolevels; /* low and high quality differ */
99    
100     double mblur; /* vflt(MBLUR) */
101     double rate; /* vflt(RATE) */
102    
103     char objtmpf[32]; /* object temporary file */
104    
105     struct ObjMove *obj_move; /* object movements */
106    
107     int haveprio = 0; /* high-level saliency specified */
108    
109     int gargc; /* global argc for printargs */
110     char **gargv; /* global argv for printargs */
111    
112    
113     int
114     main(argc, argv)
115     int argc;
116     char *argv[];
117     {
118     int explicate = 0;
119     char *cfname;
120     int i;
121    
122     progname = argv[0]; /* get arguments */
123     gargc = argc;
124     gargv = argv;
125     for (i = 1; i < argc && argv[i][0] == '-'; i++)
126     switch (argv[i][1]) {
127     case 't': /* seconds per frame */
128     rtperfrm = atoi(argv[++i]);
129     break;
130     case 'd': /* noticeable difference */
131     ndthresh = atof(argv[++i]);
132     ndtset = 1;
133     break;
134     case 'e': /* print variables */
135     explicate++;
136     break;
137     case 's': /* silent running */
138     silent++;
139     break;
140     case 'q': /* start quickly */
141     quickstart++;
142     break;
143     case 'w': /* turn off warnings */
144     nowarn++;
145     break;
146     case 'f': /* frame range */
147     switch (sscanf(argv[++i], "%d,%d", &fbeg, &fend)) {
148     case 2:
149     if ((fbeg <= 0 | fend < fbeg))
150     goto userr;
151     break;
152     case 1:
153     if (fbeg <= 0)
154     goto userr;
155     fend = 0;
156     break;
157     default:
158     goto userr;
159     }
160     break;
161     case 'n': /* number of processes */
162     nprocs = atoi(argv[++i]);
163     break;
164     default:
165     goto userr;
166     }
167     if (rtperfrm <= 0) {
168     if (!ndtset)
169     error(USER, "specify -d jnd with -t 0");
170     rtperfrm = 7*24*3600;
171     }
172     if (i != argc-1)
173     goto userr;
174     cfname = argv[i];
175     /* load variables */
176     loadvars(cfname);
177     /* check variables */
178     checkvalues();
179     /* load RIF if any */
180     if (vdef(RIF))
181     getradfile(vval(RIF));
182     /* set defaults */
183     setdefaults();
184     /* print variables */
185     if (explicate)
186     printvars(stdout);
187     /* run animation */
188     if (nprocs > 0)
189     animate();
190     /* all done */
191     if (lorendoptf[0])
192     unlink(lorendoptf);
193     if (hirendoptf[0])
194     unlink(hirendoptf);
195     if (objtmpf[0])
196     unlink(objtmpf);
197     return(0);
198     userr:
199     fprintf(stderr,
200     "Usage: %s [-n nprocs][-f beg,end][-t sec][-d jnd][-s][-w][-e] anim_file\n",
201     progname);
202     quit(1);
203     }
204    
205    
206     void
207     eputs(s) /* put string to stderr */
208     register char *s;
209     {
210     static int midline = 0;
211    
212     if (!*s)
213     return;
214     if (!midline++) {
215     fputs(progname, stderr);
216     fputs(": ", stderr);
217     }
218     fputs(s, stderr);
219     if (s[strlen(s)-1] == '\n') {
220     fflush(stderr);
221     midline = 0;
222     }
223     }
224    
225    
226     void
227     setdefaults() /* set default values */
228     {
229     int nviews;
230     int decades;
231     char buf[256];
232     int i;
233    
234     if (!vdef(OCTREEF)) {
235     sprintf(errmsg, "%s or %s must be defined",
236     vnam(OCTREEF), vnam(RIF));
237     error(USER, errmsg);
238     }
239     if (!vdef(VIEWFILE)) {
240     sprintf(errmsg, "%s must be defined", vnam(VIEWFILE));
241     error(USER, errmsg);
242     }
243     nviews = countviews();
244     if (!nviews)
245     error(USER, "no views in view file");
246     if (!vdef(END)) {
247     if (nviews == 1) {
248     sprintf(errmsg, "%s must be defined for single view",
249     vnam(END));
250     error(USER, errmsg);
251     }
252     sprintf(buf, "%d", nviews);
253     vval(END) = savqstr(buf);
254     vdef(END)++;
255     }
256     if (!fend)
257     fend = vint(END);
258     if (fbeg > fend)
259     error(USER, "begin after end");
260     if (!vdef(BASENAME)) {
261     decades = (int)log10((double)vint(END)) + 1;
262     if (decades < 3) decades = 3;
263     sprintf(buf, "frame%%0%dd", decades);
264     vval(BASENAME) = savqstr(buf);
265     vdef(BASENAME)++;
266     }
267     if (!vdef(RATE)) {
268     vval(RATE) = "8";
269     vdef(RATE)++;
270     }
271     rate = vflt(RATE);
272     if (!vdef(RESOLUTION)) {
273     vval(RESOLUTION) = "640";
274     vdef(RESOLUTION)++;
275     }
276     if (!vdef(MBLUR)) {
277     vval(MBLUR) = "0";
278     vdef(MBLUR)++;
279     }
280     mblur = vflt(MBLUR);
281     if (mblur > 1.)
282     mblur = 1.;
283     /* set up objects */
284     if (vdef(MOVE)) {
285     obj_move = (struct ObjMove *)malloc(
286     sizeof(struct ObjMove)*vdef(MOVE) );
287     if (obj_move == NULL)
288     error(SYSTEM, "out of memory in setdefaults");
289     for (i = 0; i < vdef(MOVE); i++)
290     setmove(&obj_move[i], nvalue(MOVE, i));
291     }
292     /* set up high quality options */
293     setrendparams(hirendoptf, vval(HIGHQ));
294     ray_save(&hirendparams);
295     /* set up low quality options */
296     setrendparams(lorendoptf, vval(LOWQ));
297     ray_save(&lorendparams);
298     curparams = &lorendparams;
299     twolevels = bcmp(&lorendparams, &hirendparams, sizeof(RAYPARAMS));
300     }
301    
302    
303     void
304     setmove(om, ms) /* assign a move object from spec. */
305     struct ObjMove *om;
306     char *ms;
307     {
308     char parname[128];
309     char *cp;
310    
311     ms = nextword(parname, sizeof(parname), ms);
312     if (!parname[0])
313     goto badspec;
314     for (cp = parname; *cp; cp++)
315     if (isspace(*cp))
316     *cp = '_';
317     for (om->parent = (om - obj_move); om->parent--; )
318     if (!strcmp(parname, obj_move[om->parent].name))
319     break;
320     if (om->parent < 0 &&
321     strcmp(parname, ".") && strcmp(parname, VOIDID)) {
322     sprintf(errmsg, "undefined parent object '%s'", parname);
323     error(USER, errmsg);
324     }
325     ms = nextword(om->name, sizeof(om->name), ms);
326     if (!om->name[0])
327     goto badspec;
328     for (cp = om->name; *cp; cp++)
329     if (isspace(*cp))
330     *cp = '_';
331     ms = nextword(om->xf_file, sizeof(om->xf_file), ms);
332     if (!strcmp(om->xf_file, "."))
333     om->xf_file[0] = '\0';
334     if (!om->xf_file[0]) {
335     om->xfs[0] = '\0';
336     } else if (om->xf_file[0] == '-') {
337     strcpy(om->xfs, om->xf_file);
338     om->xf_file[0] = '\0';
339     }
340     ms = nextword(om->spec, sizeof(om->spec), ms);
341     if (om->spec[0]) {
342     if (!strcmp(om->spec, ".") || !strcmp(om->spec, VOIDID))
343     om->spec[0] = '\0';
344     ms = nextword(om->prio_file, sizeof(om->prio_file), ms);
345     } else
346     om->prio_file[0] = '\0';
347     if (om->prio_file[0]) {
348     if (isflt(om->prio_file)) {
349     om->prio = atof(om->prio_file);
350     om->prio_file[0] = '\0';
351     haveprio |= (om->prio < 0.95 | om->prio > 1.05);
352     } else
353     haveprio = 1;
354     } else
355     om->prio = 1.;
356     om->cfm = -1;
357     return;
358     badspec:
359     error(USER, "bad object specification");
360     }
361    
362    
363     void
364     setrendparams(optf, qval) /* set global rendering parameters */
365     char *optf;
366     char *qval;
367     {
368     char *argv[1024];
369     char **av = argv;
370     int ac, i, rval;
371    
372     av[ac=0] = NULL;
373     /* load options from file, first */
374     if (optf != NULL && *optf) {
375     ac = wordfile(av, optf);
376     if (ac < 0) {
377     sprintf(errmsg, "cannot load options file \"%s\"",
378     optf);
379     error(SYSTEM, errmsg);
380     }
381     }
382     /* then from options string */
383     if (qval != NULL && qval[0] == '-')
384     ac += wordstring(av+ac, qval);
385    
386     /* start with default parameters */
387     ray_defaults(NULL);
388     /* set what we have */
389     for (i = 0; i < ac; i++) {
390     while ((rval = expandarg(&ac, &av, i)) > 0)
391     ;
392     if (rval < 0) {
393     sprintf(errmsg, "cannot expand '%s'", av[i]);
394     error(SYSTEM, errmsg);
395     }
396     if (!strcmp(av[i], "-w")) {
397     nowarn++;
398     continue;
399     }
400     rval = getrenderopt(ac-i, av+i);
401     if (rval >= 0) {
402     i += rval;
403     continue;
404     }
405     sprintf(errmsg, "bad render option at '%s'", av[i]);
406     error(USER, errmsg);
407     }
408     }
409    
410    
411     void
412     getradfile(rfargs) /* run rad and get needed variables */
413     char *rfargs;
414     {
415     static short mvar[] = {OCONV,OCTREEF,RESOLUTION,EXPOSURE,-1};
416     char combuf[256];
417     register int i;
418     register char *cp;
419     char *pippt;
420     /* create rad command */
421     strcpy(lorendoptf, "ranim0.opt");
422     sprintf(combuf,
423     "rad -v 0 -s -e -w %s %s oconv=-f OPTFILE=%s | egrep '^[ \t]*(NOMATCH",
424     rfargs,
425     (vdef(LOWQ) && vval(LOWQ)[0]!='-') ? vval(LOWQ) : "",
426     lorendoptf);
427     cp = combuf;
428     while (*cp) {
429     if (*cp == '|') pippt = cp;
430     cp++;
431     } /* match unset variables */
432     for (i = 0; mvar[i] >= 0; i++)
433     if (!vdef(mvar[i])) {
434     *cp++ = '|';
435     strcpy(cp, vnam(mvar[i]));
436     while (*cp) cp++;
437     pippt = NULL;
438     }
439     if (pippt != NULL)
440     strcpy(pippt, "> /dev/null"); /* nothing to match */
441     else {
442     strcpy(cp, ")[ \t]*=' > ranimove.var");
443     cp += 11; /* point to file name */
444     }
445     system(combuf); /* ignore exit code */
446     if (pippt == NULL) { /* load variables and remove file */
447     loadvars(cp);
448     unlink(cp);
449     }
450     if (!vdef(HIGHQ) || vval(HIGHQ)[0]=='-') {
451     strcpy(hirendoptf, lorendoptf);
452     return;
453     }
454     /* get high quality options */
455     strcpy(hirendoptf, "ranim1.opt");
456     sprintf(combuf, "rad -v 0 -s -w %s %s OPTFILE=%s",
457     rfargs, vval(HIGHQ), hirendoptf);
458     system(combuf);
459     }
460    
461    
462     void
463     animate() /* run through animation */
464     {
465     int rpass;
466    
467     if (fbeg > 1) /* synchronize transforms */
468     getoctspec(fbeg-1);
469    
470     for (fcur = fbeg; fcur <= fend; fcur++) {
471     if (!silent)
472     printf("Frame %d:\n", fcur);
473     /* base rendering */
474     init_frame();
475     /* refinement */
476     for (rpass = 0; refine_frame(rpass); rpass++)
477     ;
478     /* final filter pass */
479     filter_frame();
480     /* output frame */
481     send_frame();
482     }
483     /* free resources */
484     free_frame();
485     if (nprocs > 1)
486     ray_pdone(1);
487     else
488     ray_done(1);
489     getview(0);
490     getexp(0);
491     }
492    
493    
494     VIEW *
495     getview(n) /* get view number n */
496     int n;
497     {
498     static FILE *viewfp = NULL; /* view file pointer */
499     static int viewnum = 0; /* current view number */
500     static VIEW curview = STDVIEW; /* current view */
501     char linebuf[256];
502    
503     if (n == 0) { /* signal to close file and clean up */
504     if (viewfp != NULL) {
505     fclose(viewfp);
506     viewfp = NULL;
507     viewnum = 0;
508     copystruct(&curview, &stdview);
509     }
510     return(NULL);
511     }
512     if (viewfp == NULL) { /* open file */
513     if ((viewfp = fopen(vval(VIEWFILE), "r")) == NULL) {
514     perror(vval(VIEWFILE));
515     quit(1);
516     }
517     } else if (n > 0 && n < viewnum) { /* rewind file */
518     if (viewnum == 1 && feof(viewfp))
519     return(&curview); /* just one view */
520     if (fseek(viewfp, 0L, 0) == EOF) {
521     perror(vval(VIEWFILE));
522     quit(1);
523     }
524     copystruct(&curview, &stdview);
525     viewnum = 0;
526     }
527     if (n < 0) { /* get next view */
528     register int c = getc(viewfp);
529     if (c == EOF)
530     return(NULL); /* that's it */
531     ungetc(c, viewfp);
532     n = viewnum + 1;
533     }
534     while (n > viewnum) { /* scan to desired view */
535     if (fgets(linebuf, sizeof(linebuf), viewfp) == NULL)
536     return(viewnum==1 ? &curview : (VIEW *)NULL);
537     if (isview(linebuf) && sscanview(&curview, linebuf) > 0)
538     viewnum++;
539     }
540     return(&curview); /* return it */
541     }
542    
543    
544     int
545     countviews() /* count views in view file */
546     {
547     int n;
548    
549     if (getview(n=1) == NULL)
550     return(0);
551     while (getview(-1) != NULL)
552     n++;
553     return(n);
554     }
555    
556    
557     char *
558     getexp(n) /* get exposure for nth frame */
559     int n;
560     {
561     extern char *fskip();
562     static char expval[32];
563     static FILE *expfp = NULL;
564     static int curfrm = 0;
565     register char *cp;
566    
567     if (n == 0) { /* signal to close file */
568     if (expfp != NULL) {
569     fclose(expfp);
570     expfp = NULL;
571     }
572     return(NULL);
573     }
574     if (!vdef(EXPOSURE)) /* no setting (auto) */
575     return(NULL);
576     if (isflt(vval(EXPOSURE))) /* always the same */
577     return(vval(EXPOSURE));
578     if (expfp == NULL) { /* open exposure file */
579     if ((expfp = fopen(vval(EXPOSURE), "r")) == NULL) {
580     sprintf(errmsg, "cannot open exposure file \"%s\"",
581     vval(EXPOSURE));
582     error(SYSTEM, errmsg);
583     }
584     curfrm = 0;
585     }
586     if (curfrm > n) { /* rewind if necessary */
587     rewind(expfp);
588     curfrm = 0;
589     }
590     while (n > curfrm) { /* read to line */
591     if (fgets(expval, sizeof(expval), expfp) == NULL) {
592     sprintf(errmsg, "%s: too few exposures",
593     vval(EXPOSURE));
594     error(USER, errmsg);
595     }
596     if (strlen(expval) == sizeof(expval)-1)
597     goto formerr;
598     curfrm++;
599     }
600     cp = fskip(expval); /* check format */
601     if (cp != NULL)
602     while (isspace(*cp))
603     *cp++ = '\0';
604     if (cp == NULL || *cp)
605     goto formerr;
606     return(expval); /* return value */
607     formerr:
608     sprintf(errmsg, "%s: exposure format error on line %d",
609     vval(EXPOSURE), curfrm);
610     error(USER, errmsg);
611     }
612    
613    
614     double
615     expspec_val(s) /* get exposure value from spec. */
616     char *s;
617     {
618     double expval;
619    
620     if (s == NULL || !*s)
621     return(1.0);
622    
623     expval = atof(s);
624     if ((s[0] == '+' | s[0] == '-'))
625     return(pow(2.0, expval));
626     return(expval);
627     }
628    
629    
630     char *
631     getoctspec(n) /* get octree for the given frame */
632     int n;
633     {
634     static char combuf[1024];
635     int cfm = 0;
636     int uses_inline;
637     FILE *fp;
638     int i;
639     /* is octree static? */
640     if (!vdef(MOVE))
641     return(vval(OCTREEF));
642     /* done already */
643     if (n == cfm)
644     return(combuf);
645     /* else create object file */
646     strcpy(objtmpf, "movinobj.rad");
647     fp = fopen(objtmpf, "w");
648     if (fp == NULL) {
649     sprintf(errmsg, "cannot write to moving objects file '%s'",
650     objtmpf);
651     error(SYSTEM, errmsg);
652     }
653     uses_inline = 0;
654     for (i = 0; i < vdef(MOVE); i++) {
655     int inlc = (obj_move[i].spec[0] == '!');
656     if (!obj_move[i].spec[0])
657     continue;
658     if (inlc)
659     fprintf(fp, "%s %d \\\n\t| xform",
660     obj_move[i].spec, n);
661     else
662     fputs("!xform", fp);
663     fprintf(fp, " -n %s", getobjname(&obj_move[i]));
664     fputs(getxf(&obj_move[i], n), fp);
665     if (!inlc)
666     fprintf(fp, " %s\n", obj_move[i].spec);
667     else
668     fputc('\n', fp);
669     uses_inline |= inlc;
670     }
671     if (fclose(fp) == EOF)
672     error(SYSTEM, "error writing moving objects file");
673     if (uses_inline)
674     sprintf(combuf, "!oconv %s -f -i '%s' %s",
675     vdef(OCONV) ? vval(OCONV) : "",
676     vval(OCTREEF), objtmpf);
677     else
678     sprintf(combuf, "!xform -f %s | oconv -f -i '%s' -",
679     objtmpf, vval(OCTREEF));
680     return(combuf);
681     }
682    
683    
684     char *
685     getobjname(om) /* get fully qualified object name */
686     register struct ObjMove *om;
687     {
688     static char objName[512];
689     register char *cp = objName;
690    
691     strcpy(cp, om->name);
692     while (om->parent >= 0) {
693     while (*cp) cp++;
694     *cp++ = '@';
695     om = &obj_move[om->parent];
696     strcpy(cp, om->name);
697     }
698     return(objName);
699     }
700    
701    
702     char *
703     getxf(om, n) /* get total transform for object */
704     register struct ObjMove *om;
705     int n;
706     {
707     static char xfsbuf[4096];
708     char *xfp;
709     int framestep = 0;
710     XF oxf;
711     FILE *fp;
712     char abuf[512];
713     char *av[64];
714     int ac;
715     int i;
716     register char *cp;
717     /* get parent transform, first */
718     if (om->parent >= 0)
719     xfp = getxf(&obj_move[om->parent], n);
720     else
721     *(xfp = xfsbuf + sizeof(xfsbuf)-1) = '\0';
722     /* get transform spec. & priority */
723     if (om->cfm != n) {
724     if (om->xf_file[0]) {
725     fp = fopen(om->xf_file, "r");
726     if (fp == NULL) {
727     sprintf(errmsg,
728     "cannot open transform file '%s'",
729     om->xf_file);
730     error(SYSTEM, errmsg);
731     }
732     for (i = 0; i < n; i++)
733     if (fgetline(om->xfs, sizeof(om->xfs), fp)
734     == NULL) {
735     sprintf(errmsg,
736     "too few transforms in file '%s'",
737     om->xf_file);
738     error(USER, errmsg);
739     }
740     fclose(fp);
741     }
742     strcpy(cp=abuf, om->xfs);
743     ac = 0;
744     for ( ; ; ) {
745     while (isspace(*cp))
746     *cp++ = '\0';
747     if (!*cp)
748     break;
749     av[ac++] = cp;
750     while (*++cp && !isspace(*cp))
751     ;
752     }
753     av[ac] = NULL;
754     if (xf(&oxf, ac, av) != ac ||
755     fabs(oxf.sca) <= FTINY) {
756     sprintf(errmsg, "bad transform args: %s",
757     om->xfs);
758     error(USER, errmsg);
759     }
760     copymat4(om->xfm, oxf.xfm);
761     if (om->prio_file[0]) {
762     fp = fopen(om->prio_file, "r");
763     if (fp == NULL) {
764     sprintf(errmsg,
765     "cannot open priority file '%s'",
766     om->prio_file);
767     error(SYSTEM, errmsg);
768     }
769     for (i = 0; i < n; i++)
770     if (fgets(abuf, sizeof(abuf), fp)
771     == NULL) {
772     sprintf(errmsg,
773     "too few priorities in file '%s'",
774     om->prio_file);
775     error(USER, errmsg);
776     }
777     fclose(fp);
778     cp = fskip(abuf);
779     if (cp != NULL)
780     while (isspace(*cp))
781     *cp++ = '\0';
782     if (cp == NULL || *cp) {
783     sprintf(errmsg,
784     "priority '%s' in file '%s' not a number",
785     abuf, om->prio_file);
786     error(USER, errmsg);
787     }
788     om->prio = atof(abuf);
789     }
790     framestep = (n == om->cfm + 1);
791     om->cfm = n;
792     }
793     /* prepend to parent transform */
794     if (om->xfs[0]) {
795     i = strlen(om->xfs);
796     if (xfp - i <= xfsbuf)
797     error(INTERNAL, "transform too long in getxf");
798     cp = om->xfs + i;
799     while (i--)
800     *--xfp = *--cp;
801     *--xfp = ' ';
802     }
803     if (framestep)
804     copymat4(oxf.xfm, om->cxfm);
805     if (om->parent >= 0) {
806     multmat4(om->cxfm, om->xfm, obj_move[om->parent].cxfm);
807     om->cprio = obj_move[om->parent].cprio * om->prio;
808     } else {
809     copymat4(om->cxfm, om->xfm);
810     om->cprio = om->prio;
811     }
812     /* XXX bxfm relies on call order */
813     if (framestep)
814     if (invmat4(om->bxfm, om->cxfm))
815     multmat4(om->bxfm, om->bxfm, oxf.xfm);
816     else
817     setident4(om->bxfm);
818     /* all done */
819     return(xfp);
820     }
821    
822    
823     int
824     getmove(obj) /* find matching move object */
825     OBJECT obj;
826     {
827     static int lasti;
828     static OBJECT lasto = OVOID;
829     char *onm, *objnm;
830     int len, len2;
831     register int i;
832    
833     if (obj == OVOID)
834     return(-1);
835     if (obj == lasto)
836     return(lasti);
837     /* look for matching object */
838     onm = objptr(obj)->oname;
839     for (i = vdef(MOVE); i--; ) {
840     objnm = obj_move[i].name;
841     len = strlen(objnm);
842     if (!strncmp(onm, objnm, len)) {
843     if ((obj_move[i].parent < 0 & onm[len] == '.'))
844     break;
845     objnm = getobjname(&obj_move[i]) + len;
846     len2 = strlen(objnm);
847     if (!strncmp(onm+len, objnm, len2) && onm[len+len2] == '.')
848     break;
849     }
850     }
851     lasto = obj; /* cache what we found */
852     return(lasti = i);
853     }
854    
855    
856     double
857     obj_prio(obj) /* return priority for object */
858     OBJECT obj;
859     {
860     int moi;
861    
862     if (obj == OVOID || (moi = getmove(obj)) < 0)
863     return(1.0);
864     return(obj_move[moi].cprio);
865     }
866    
867    
868     double
869     getTime() /* get current time (CPU or real) */
870     {
871     struct timeval time_now;
872     /* return CPU time if one process */
873     if (nprocs == 1)
874     return((double)clock()*(1.0/(double)CLOCKS_PER_SEC));
875     /* otherwise, return wall time */
876     gettimeofday(&time_now, NULL);
877     return((double)time_now.tv_sec + 1e-6*(double)time_now.tv_usec);
878     }