Sunday, June 30, 2013

Animate3 - the commands (part 2)

This posting continues the explanation of Animate3 commands. See here for the first part of the Animate3 description, and here for the introductory text with a simple animation.

Here is an overview over this posting's contents:



< ... reading a parts file


Syntax:

< filename

Explanation


< is a non-blocking command. This command reads in a parts file. I have explained its syntax and semantics already in the first posting about Animate3.


~ ... controlling system effects (script output)


Syntax:

~ filename
or
~ +
or
~ –

Explanation


~ is a non-blocking command.
  • ~ + means that effects in the operating system take place.
For the current implementation, this means that corresponding commands are written into the output batch file. Other implementations might directly invoke the effects.
  • ~ – means that effects in the operating system are suppressed. However, all other computations (running actions, initializing and incrementing value generators) are done. This command is useful if one wants to debug a later part of an animation, as the previous, time-consuming ImageMagick calls are skipped.
  • ~ filename sets the name of the output batch file. Moreover, it also has the effect of ~ +.
By default, system effects are enabled (i.e., the batch script is written). The default output file in the current implementation is the standard output (/dev/stdout in AWK terminology).


| ... Executing parallel subactions


Syntax:


| [ . | framelimit ] [ action ]*
where action is
actionscriptfile [ repetitions | . ]
or
|


Valid parameters:


  • framelimit and repetitions are integral numbers or expressions—see this explanation of expressions for the latter.
  • actionscriptfile is the name of a script file.
The actions in the | command are called "actions mentioned by the | command."

Explanation


| is a blocking command.

Before the command is executed, all expressions are evaluated and interpolated into the command.

The first form of the command then continues with all the mentioned actions in the following manner:
  • If no action is mentioned (i.e., the command consists only of a bar and a dot or a number), the previous | command is re-executed, but with the given framelimit (be it . or a number), according to the following rules.
  • If a mentioned action is currently active with some blocking current command, it continues to execute with this command.
  • If a mentioned action is currently active, but is not at a blocking command, it must be at its end (otherwise, this action here could not be executing this | command). In this case, if the action has been executed fewer than repetition times since this | command had been started, or if a dot is given as repetitions, the action remains active, but its current command is reset to its first command.
  • If a mentioned action is currently not active, it is started: Its lines are read in from the given file, it becomes active, and its current command is set to its first command. By convention, the name of the file is also the name of the action.
  • If there was a previous | command in the same script where this | command is located, and there are still active actions from that previous | command that are not mentioned in this | command, those actions are made stopped: They are made inactive so that their state is forgotten.
The command finishes (i.e., allows the script to execute its next command) when one of the following happens:
  • Either all actions where an explicit repetition number is given (these are called "controlling actions" of this command) are no longer active.
  • Or a framelimit is present, and the actions mentioned in this | command have created or contributed to more than framelimit frames since the | command became the current command.
It is in error to put an action into a | command if the same action is currently active in another | command (of a concurrently executing action).

A | command is said to surround another command if that other command is in one of the scripts mentioned in the | command; or if a  | command in one of the mentioned scripts surrounds that other command.

The second form of the command deactivates all currently active actions and then stops the frame-generating loop. This is probably never used in normal script (except maybe for debugging), but it is necessary for finishing the outermost script that is created from the command line parameters: A call to the Animate3 compiler with script parameters script1.an3 ... scriptN.an3 is transformed into the following script (with internal name .):
| . script1.an3 1
...
| . scriptN.an3 1
|
This script is then made active, and finally, the frame-generating loop is started. When the script reaches the final | command, it will terminate that loop.


= ... defining the view of a scene


Syntax:


= [ . | framecount ] sceneX sceneY sceneW sceneH scenefile scenepixelW [ scenepixelH | . ]

Valid parameters:


  • scenefile is an arbitrary string (without white space) which can include value expressions.
  • All other parameters must be real numbers or value expressions—see this explanation of expressions for the latter.

Explanation:


= is a blocking command.

This command is a sort of "back end" for the & command: For a certain number of frames, it provides parameters for frame creation. The command remains active
  • indefinitely (but it can be deactivated by surrounding | commands—see| command) if no framecount is given.
  • for framecount loops of the frame-generating loop after is has become the current command of its script.
I have explained the semantics of this command already in the first Animate3 posting (more or less).


& ... creating frames from parts


Syntax:


& [ framecount | . ] [ piece with transformations ]*
where piece with transformations is
partname [ transformation ]*
where transformation is one of the following:
  • @ . . Angle
  • @ X Y Angle
  • > dX dY
  • ^ . . sX dX sY dY
  • ^ X Y sX dX sY dY
There is also an abbreviated form:
& framecount

Valid parameters:


  • partname must be the name of a part that is present in one of the parts files that have been read on before this command is encountered.
  • All other parameters must be real numbers or value expressions—see this explanation of expressions for the latter.

Explanation:


& is a blocking command.

The & command contributes to framecount frames by placing the mentioned parts with their transformations. The number of frames where the command actually contributes might be less than framecount if a surrounding | command is stopped short—see| command. If . is given instead of a numeric framecount, the command contributes to indefinitely many frames, until it is stopped short by a surrounding | command.

The abbreviated form repeats the command from the preceding & command. This is sometimes useful concept: One can set up a "model" in a large & command with framecount zero, using various variables. Then, using an interleaved sequence of variable commands and abbreviated &s, the model becomes animated. However, with the introduction of | commands, this is no longer that helpful.

A part can be used more than once in an & command. Each usage counts as a separate "piece" that is transformed independently of the other pieces, even those stemming from the same part. Each piece starts at the same position as it has in its layer file. If there are transformations given for a piece, they modify it in the given order as follows:
  • @ . . Angle rotates the piece around the part's pivot point by Angle degrees. A positive angle corresponds to a clockwise movement (in contrast to the mathematical convention, where positive angles are directed counterclockwise).
  • @ X Y Angle rotates the piece around the point (X,Y) by Angle degrees. Again, a positive angle corresponds to a clockwise movement.
  • > dX dY shifts the piece by (dX,dY).
  • ^ . . sX dX sY dY stretches the piece from its pivot point by factors 1 + dX/sX in x direction and 1 + dY/sY in y direction.
  • ^ X Y sX dX sY dY stretches the piece from center (X,Y) by factors 1 + dX/sX in x direction and 1 + dY/sY in y direction.


$ ... creating frames with shell commands


Syntax:


$ [ framecount | . ] any text to end of line

Valid parameters:



Explanation:


$ is a blocking command.

Besides the more advanced & command, there is still the old $ command from the first animation language. Of course, because of the & command, its usage has been greatly diminished. However, it is e.g. useful to add the final ffmpeg calls to the created scripts, or maybe add some file handling in between. And, of course, one can write exploratory tests with it that show only the working of the scheduler, i.e., the machinery interpreting the | commands, by simply replacing & with $.

The & command executes for framecount iterations of frame-generating loops. The number of iterations might be less than framecount if a surrounding | command is stopped short—see| command. If . is given instead of a numeric framecount, the command does not end by itself, but executes for indefinitely many iterations of the frame-generation loop until it is stopped short by a surrounding | command.


What is not in Animate3


At least the following concepts that appear valuable are missing from Animate3. Some of them I considered in the first draft, but then I opted for a smaller language, at least for the moment:
  • compound parts
  • local variables
  • cranks with sliders
  • non-affine transformations
  • fluids
  • color changes
  • 3D
Compound parts would allow something like "rotate part1, overlay it with part2, and then shift (or rotate, or stretch) these two together". ImageMagick can do this, either by using a stack or by using parentheses. However, I think that another abstraction concept is right now not the way to go—it might be a future feature.

The value generators (or "variables," if you like) in Animate3 are global objects. There is no "action scope" or the like associated with them: Any action can use any generator, and any action can redefine any value generator. This sounds bad. Still, it is useful to pass value generators around. If local variables were introduced, I would probably also have to introduce some concept of parameter passing between actions, and this is much work. Rather, I suggest (and try) to name variables according to the part and/or action where they are defined and used.
Maybe one clarification is needed here: In contrast to programming languages and maybe other, larger animation systems, Animate3 is not intended for building some sort of reusable action libraries or the like. The idea is to always start with a new CAD drawing (or set of drawings) which has all the parts at about the right places, and then get these parts moving around. Therefore, that much abstraction is not needed (and I doubt that the | operator will be used with more than a nesting depth of one or maybe two).
Slider-cranks-mechanisms are important elements in many mechanical devices. However, the motion of such a mechanism cannot be easily described with trigonometric formulas (the emphasis is on easily). It will probably soon be necessary to introduce some basic expressions in Animate3 that can compute a slider's displacement from the corresponding crank's angle and vice versa.

Some machine elements cannot be described by affine transformations. One example is a bending spring (such springs were often used in the striking mechanisms of old watch movements), but also diaphragms in pneumatic or hydraulic devices are of this sort. Such deformations can be described with higher-order tensors, and ImageMagick supports quite a few such transformations out of the box. However, these transformations do not interact well with keeping the origin of an image, which is needed for putting the deformed element back into the whole frame. At least, it should possible to pre-compute the deformed forms into files that can then be included in frames—this sounds like a feature with high priority.

When one starts to animate pneumatic or hydraulic devices, it is necessary to show the flow of some volume of gas or fluid through various pipes and holes and crevices. There is no support for this right now in Animate3 (and I do not yet know how such a flow can be described and then transformed into a sequence of image parts).

In the same vein, it should be possible to change the color of an element based on some value generators' values. At least fluids and gases should sometimes be shown in blue or red (for cold and hot; or low or high pressure).

Last (and least, I'd say), one could think about animations in 3D. However, our computer screens will, for a long time, remain 2D, and therefore an animation designer has to think about the 2D layout anyway: A technically perfect 3D animation where some pieces are hidden behind others will have a much lower explanation value than a well laid out 2D animation! Therefore, 3D is not really an important feature for the sort of tool that Animate3 wants to be.


This concludes my description of the Animate3 language. If someone is interested in the code of the compiler, maybe this diagram of its internal data structures is of some help. More explanations and comments must wait, because I will now concentrate on creating that "5007" animation with Animate3!

No comments:

Post a Comment