1#############################################################################
2# Author:                                                                   #
3# ------                                                                    #
4#  Anton Kokalj                                  Email: Tone.Kokalj@ijs.si  #
5#  Department of Physical and Organic Chemistry  Phone: x 386 1 477 3523    #
6#  Jozef Stefan Institute                          Fax: x 386 1 477 3811    #
7#  Jamova 39, SI-1000 Ljubljana                                             #
8#  SLOVENIA                                                                 #
9#                                                                           #
10# Source: $XCRYSDEN_TOPDIR/Tcl/scriptingMakeMovie.tcl
11# ------                                                                    #
12# Copyright (c) 1996-2003 by Anton Kokalj                                   #
13#############################################################################
14
15
16# ------------------------------------------------------------------------
17#****c* Scripting/scripting::makeMovie
18#
19# NAME
20# scripting::makeMovie
21#
22# PURPOSE
23
24# This namespace provide the scripting interface for making
25# MPEG/Animated-GIF movies. The scripting::makeMovie namespace
26# interface is kind of state machine. The "init" command initializes
27# the process, and then the movie creation is encapsulated between
28# "begin" and "end" commands. Every movie frame is created within the
29# "begin" and "end" commands with "makeFrame" command. One can create
30# several movies within one scripting file. Make sure the sequence of
31# makeMovie calls will have the following order:
32#
33# init
34# begin
35#   makeFrame
36#   makeFrame
37#   ...
38# end
39#
40# init
41# begin
42#   makeFrame
43#   makeFrame
44#   ...
45# end
46#
47#
48# COMMANDS
49
50# -- scripting::makeMovie::init
51
52# Initializes the movie creation process. It must be called before
53# making movie. One passes several configuration options to init call.
54
55
56#
57# -- scripting::makeMovie::begin
58
59# Marks the begining of movie creation.
60
61#
62# -- scripting::makeMovie::makeFrame
63
64# Makes one movie frame, that is, saves (i.e. prints to file) the
65# content of the currently displayed object.
66
67#
68# -- scripting::makeMovie::end
69
70# Finishes the movie creation and encodes the movie.
71#
72#****
73# ------------------------------------------------------------------------
74
75namespace eval scripting::makeMovie {
76    variable movie
77
78    set movie(makeMovie) 0
79    set movie(movieFile) ""
80    set movie(notificationMovie) ""
81}
82
83
84# ------------------------------------------------------------------------
85#****f* Scripting/scripting::makeMovie::init
86#
87# NAME
88# scripting::makeMovie::init
89#
90# USAGE
91# scripting::makeMovie::init -option value ?-option value? ...
92#
93# PURPOSE
94
95# This proc initializes the movie creation processes. One can pass several
96# configuration options, which determine the technical details of the
97# movie.
98
99#
100# ARGUMENTS
101# args -- various configuration "-option value" pairs
102#
103# OPTIONS
104# ------------------------------------------------------------------------
105#  OPTION               ALLOWED-VALUES + DESCRIPTION
106# ------------------------------------------------------------------------
107#
108#  -gif_transp          0|1 --> make oblique|transparent animated-GIF
109#
110#  -gif_minimize        0|1 --> don't-minimize|minimize animateg-GIF
111#
112#  -gif_global_colormap 0|1 --> don't-use|use global colormap for animated-GIF
113#
114#  -movieformat         avi|mpeg|gif --> create AVI|MPEG|Animated-GIF
115#
116#  -dir                 tmp|pwd --> put temporary (i.e. frame) files to
117#                                   scratch(tmp) or current working
118#                                   directory(pwd)
119#
120#  -frameformat         PPM|PNG|JPEG --> format of the frame-files
121#
122#  -firstframe          positive-integer --> repeat first frame n-times
123#
124#  -lastframe           positive-integer --> repeat first frame n-times
125#
126#  -delay               positive-integer --> time dalay between frames
127#                                            in 1/100 sec
128#  -loop                repeat in movie animation number of times (0=forever)
129#
130#  -save_to_file        file --> if specified the movie will be saved to file
131#                                otherwise the filename will be queried
132#
133#
134# RETURN VALUE
135# Undefined.
136#
137# EXAMPLE
138# scripting::makeMovie::init \
139#    -movieformat mpeg \
140#    -dir         tmp \
141#    -frameformat PPM \
142#    -firstframe  10 \
143#    -lastframe   10 \
144#    -delay       0
145#
146#****
147# ------------------------------------------------------------------------
148
149proc scripting::makeMovie::init {args} {
150    variable movie
151    global   gifAnim
152
153    if { $movie(makeMovie) } {
154	error "makeMovie::init called within makeMovie::begin/makeMovie::end, should be called before makeMovie::begin"
155    }
156
157    # load defaults
158
159    set gifAnim(gif_transp)          0
160    set gifAnim(gif_minimize)        0
161    set gifAnim(gif_global_colormap) 0
162    set gifAnim(edit_param)          1
163    set gifAnim(movie_format)        mpeg
164    set gifAnim(temp_files_dir)      tmp
165    set gifAnim(frame_files_format)  PPM
166    set gifAnim(ntime_first_frame)   1
167    set gifAnim(ntime_last_frame)    1
168    set gifAnim(delay)               0
169    set gifAnim(loop)                0
170
171    set movie(movieFile)             ""
172
173    set i 0
174    foreach option $args {
175	incr i
176
177	if { $i%2 } {
178            set tag $option
179	} else {
180            switch -glob -- $tag {
181		"-gif_transp" -
182		"-gif_minimize" -
183		"-gif_global_colormap" -
184		"-edit_param" {
185		    set tag [string trimleft $tag -]
186		    switch $option {
187			1 - on - yes { set gifAnim($tag) 1 }
188			0 - off - no { set gifAnim($tag) 0 }
189			default {
190			    ErrorDialog "wrong value $option for $tag option, should be 0 or 1"
191			}
192		    }
193		}
194		"-movieformat" {
195		    set option [string tolower $option]
196		    switch $option {
197			mpeg - gif { set gifAnim(movie_format) $option }
198			avi { set gifAnim(movie_format) mpeg }
199			default {
200			    ErrorDialog "wrong value $option for $tag option, should be \"mpeg\" or \"gif\""
201			}
202		    }
203		}
204
205		"-dir" {
206		    switch $option {
207			tmp - pwd { set gifAnim(temp_files_dir) $option }
208			default {
209			    ErrorDialog "wrong value $option for $tag option, should be \"tmp\" or \"pwd\""
210			}
211		    }
212		}
213
214		"-frameformat" {
215		    set option [string toupper $option]
216		    switch $option {
217			PPM - PNG - JPEG { set gifAnim(frame_files_format) $option }
218			default {
219			    ErrorDialog "wrong value $option for $tag option, should be \"PPM\" or \"JPEG\""
220			}
221		    }
222		}
223		"-ntime_first_frame" -
224		"-firstframe" {
225		    if { [nonnegativeInteger $option] } {
226			set gifAnim(ntime_first_frame) $option
227		    } else {
228			ErrorDialog "expected integer, but got $option for $tag option"
229		    }
230		}
231		"-ntime_last_frame" -
232		"-lastframe" {
233		    if { [nonnegativeInteger $option] } {
234			set gifAnim(ntime_last_frame) $option
235		    } else {
236			ErrorDialog "expected integer, but got $option for $tag option"
237		    }
238		}
239		"-delay" -
240		"-loop" {
241		    if { [nonnegativeInteger $option] } {
242			set elem [string trimleft $tag -]
243			set gifAnim($elem) $option
244		    } else {
245			ErrorDialog "expected integer, but got $option for $tag option"
246		    }
247		}
248		"-save_to_file" {
249		    set movie(movieFile) $option
250		}
251	    }
252	}
253    }
254    if { $i%2 } {
255	ErrorDialog "scripting::makeMovie::init called with an odd number of arguments !!!"
256    }
257}
258
259
260
261# ------------------------------------------------------------------------
262#****f* Scripting/scripting::makeMovie::begin
263#
264# NAME
265# scripting::makeMovie::begin
266#
267# USAGE
268# scripting::makeMovie::begin
269#
270# PURPOSE
271#
272# This proc marks the beginning of movie creation.
273#
274# RETURN VALUE
275# Undefined.
276#
277# EXAMPLE
278# scripting::makeMovie::begin
279#
280#****
281# ------------------------------------------------------------------------
282
283
284proc scripting::makeMovie::begin {} {
285    variable movie
286    global gifAnim
287
288    set movie(makeMovie) 1
289
290    if { $gifAnim(movie_format) == "mpeg" } {
291	set fmt MPEG
292    } else {
293	set fmt Animated-GIF
294    }
295    set movie(notificationMovie) [DisplayUpdateWidget "Recording" "Recording $fmt movie."]
296    set gifAnim(make_gifAnim) 0
297    gifAnimMake .mesa
298}
299
300
301
302# ------------------------------------------------------------------------
303#****f* Scripting/scripting::makeMovie::makeFrame
304#
305# NAME
306# scripting::makeMovie::makeFrame
307#
308# USAGE
309# scripting::makeMovie::makeFrame
310#
311# PURPOSE
312
313# This proc makes one movie frame, that is, it flushes (i.e. prints
314# to file) the content of the currently displayed object.
315
316#
317# WARNINGS
318
319# Note that this proc should be called within scripting::makeMovie::begin
320# and scripting::makeMovie::end calls. The scripting::makeMovie::init
321# should be called before "begin; makeFrame; ...; end" sequence.
322
323#
324# RETURN VALUE
325# Undefined.
326#
327# EXAMPLE
328# scripting::makeMovie::makeFrame
329#
330#****
331# ------------------------------------------------------------------------
332
333proc scripting::makeMovie::makeFrame {} {
334    variable movie
335
336    if { $movie(makeMovie) } {
337	gifAnimPrintCurrent .mesa
338    } else {
339	error "makeMovie::makeFrame called outside makeMovie::begin/makeMovie::end"
340    }
341}
342
343
344# ------------------------------------------------------------------------
345#****f* Scripting/scripting::makeMovie::end
346#
347# NAME
348# scripting::makeMovie::end
349#
350# USAGE
351# scripting::makeMovie::end
352#
353# PURPOSE
354# This proc finishes the movie creation and encodes the movie.
355#
356# RETURN VALUE
357# Undefined.
358#
359# EXAMPLE
360# scripting::makeMovie::end
361#
362#****
363# ------------------------------------------------------------------------
364
365proc scripting::makeMovie::end {} {
366    variable movie
367    global gifAnim
368
369    if { [winfo exists $movie(notificationMovie)] } {
370	destroy $movie(notificationMovie)
371    }
372    if { $gifAnim(filelist) == "" } { return }
373
374    if { $movie(makeMovie) } {
375	if { $movie(movieFile) == "" } {
376	    gifAnimMake .mesa
377	} else {
378	    gifAnimMake .mesa {} {} $movie(movieFile)
379	}
380	set movie(makeMovie) 0
381    } else {
382	error "makeMovie::end called before makeMovie::begin"
383    }
384}
385