ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/ranimove.c
Revision: 3.19
Committed: Mon Jul 20 15:54:29 2020 UTC (3 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 3.18: +4 -2 lines
Log Message:
fix(mkillum, rcontrib, rtrace, ranimove, rsensor): stall under macOS 10.15
due to broken flockfile() implementation -- workaround is better, anyway

File Contents

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