1 /*
2  * $Id: movie.i,v 1.1 2005-09-18 22:06:01 dhmunro Exp $
3  * Support functions for making animated sequences.
4  */
5 /* Copyright (c) 2005, The Regents of the University of California.
6  * All rights reserved.
7  * This file is part of yorick (http://yorick.sourceforge.net).
8  * Read the accompanying LICENSE file for details.
9  */
10 
movie(draw_frame,time_limit,min_interframe,bracket_time)11 func movie(draw_frame, time_limit, min_interframe, bracket_time)
12 /* DOCUMENT movie, draw_frame
13          or movie, draw_frame, time_limit
14          or movie, draw_frame, time_limit, min_interframe
15      runs a movie based on the given DRAW_FRAME function.  The movie
16      stops after a total elapsed time of TIME_LIMIT seconds, which
17      defaults to 60 (one minute), or when the DRAW_FRAME function
18      returns zero.
19 
20      func draw_frame(i)
21      {
22        // Input argument i is the frame number.
23        // draw_frame should return non-zero if there are more
24        // frames in this movie.  A zero return will stop the
25        // movie.
26        // draw_frame must NOT include any fma command if the
27        // making_movie variable is set (movie sets this variable
28        // before calling draw_frame)
29      }
30 
31      If MIN_INTERFRAME is specified, a pauses will be added as
32      necessary to slow down the movie.  MIN_INTERFRAME is a time
33      in seconds (default 0).
34 
35      The keyword bracket_time= (again a time in seconds) can be
36      used to adjust the duration of the pauses after the first
37      and last frames.  It may also be a two element array [beg, end].
38      If the pause at the end is greater than five seconds, you will
39      be prompted to explain that hitting <RETURN> will abort the final
40      pause.
41 
42      If every frame of your movie has the same limits, use the
43      limits command to fix the limits before you call movie.
44 
45    BUG:  If you hit <RETURN> to start a movie early, it will not
46          pause at the end of the movie at all.  You probably should
47          not use long initial pauses.
48 
49    SEE ALSO: movie_stats
50  */
51 {
52   if (is_void(time_limit)) time_limit= 60.0;
53   if (is_void(min_interframe)) min_interframe= 0.0;
54   if (is_void(bracket_time)) bracket_time= [2.,2.];
55   else if (numberof(bracket_time)<2) bracket_time= array(bracket_time,2);
56 
57   elapsed= this_frame= array(0.0, 3);
58 
59   window, wait=1;  /* make sure window is ready to draw */
60   fma;             /* clear out any existing picture */
61   animate, 1;
62   making_movie= 1;
63 
64   i= 0;
65   timer, elapsed;
66   elapsed0= elapsed;
67   more= draw_frame(++i);
68   fma;
69   timer, elapsed, this_frame;
70   wait= bracket_time(1)-this_frame(3);
71   waited= waited0= 0.0;
72   if (wait>0) {
73     if (wait>5)
74       write,
75         format="Movie starts in %.0f secs, or when you hit <RETURN>\n", wait;
76     pause, long(1000.*wait);
77     waited0+= wait;
78   } else {
79     wait= min_interframe-this_frame(3);
80     if (wait>0) {
81       pause, long(1000.*wait);
82       waited+= wait;
83     }
84   }
85 
86   while (more) {
87     this_frame()= 0.0;
88     more= draw_frame(++i);
89     fma;
90     timer, elapsed, this_frame;
91     if (!more || (elapsed(3)-elapsed0(3))>time_limit) break;
92     wait= min_interframe-this_frame(3);
93     if (wait>0) {
94       pause, long(1000.*wait);
95       waited+= wait;
96     }
97   }
98 
99   wait= bracket_time(2)-this_frame(3);
100   if (wait>0) {
101     if (wait>5) {
102       write,
103         format="Holding last frame for %.0f secs, or hit <RETURN>\n", wait;
104       pause, 100;  /* huh? */
105     }
106     pause, long(1000.*wait);
107     waited0+= wait;
108   }
109   timer, elapsed;
110 
111   animate, 0;
112 
113   extern movie_timing;
114   movie_timing= grow(elapsed-elapsed0, i, waited, waited0);
115 }
116 
movie_stats(timing)117 func movie_stats(timing)
118 /* DOCUMENT movie_stats
119          or movie_stats, timing
120      prints statistics from the last movie command, or from the
121      command which produced TIMING.  TIMING is the contents of the
122      movie_timing external variable after the movie command completes.
123 
124    SEE ALSO: movie
125  */
126 {
127   if (is_void(timing)) timing= movie_timing;
128   cpu= timing(1)+timing(2);
129   wall= timing(3);
130   nframes= long(timing(4));
131   waited= timing(5)+timing(6);
132   wait= timing(5);
133 
134   write, format="  Wall(sec)  Wait(sec)  CPU(sec)%s\n", "";
135   write, format="  %9.3f  %9.3f  %8.3f   %ld frames\n",
136          wall, waited, cpu, nframes;
137   write, format="  %9.3f  %9.3f  %8.3f   per frame\n",
138          (wall-waited)/nframes, wait/(nframes>1?nframes-1:1), cpu/nframes;
139 }
140