******************************************************** DOCUMENTATION FOR AMIGA SCRIPT4D version 1.00 Jan 1991 Version 1.00 of the SCRIPT4D executable program is in the Public Domain. It may be freely copied and distributed provided that it is always accompanied by this document in it's original form and by the supplied example files. Bug reports, comments, suggested enhancements and constructive critisism of SCRIPT4D are most welcome - BY MAIL - to: Richard Swingwood 181 Bergholt Road Colchester Essex CO4 5AH England SCRIPT4D was developed using Lattice C V5.05. If I've used any trademarks in this document then I acknowledge that they belong to someone. =================================================================== INTRODUCTION =================================================================== SCRIPT4D was created to ease the pain of creating animated sequences using the SCULPT 3D/4D range of software. I don't wish to imply that those packages are, in themselves, the cause of any grief. Personally, I find them a pleasure to use when creating objects and scenes; the problem, for me, comes when doing key-frame animations of any complexity. It's a chore I can do without. What I envisaged was a method of taking my ideas about HOW & WHEN objects in a particular scene should move and have them converted into a SCULPT script file that would do the hard work for me. Assuming my ideas could be expressed in some sort of consise language then, if I made a pigs ear of the animation, rather than have to wade through umpteen key-frame scenes recalculating object positions and making changes I could simply change my definition of the motions - the AMIGA could then do the hard work! I haven't forgotten about the global animation facility in SCULPT, which can also take a lot of the hassle out of animation; I just find it unusable for complex motions that are not repetitive. As it happens, SCRIPT4D could well be put to other uses because it is not tied to SCULPT command syntax or file formats. So here's SCRIPT4D. It's by no means perfect or complete - I need your feedback! ================================================================== CONCEPTS ================================================================== SCRIPT4D takes a 'scripting program' (program from now on) as input an produces a file of SCUPLT script commands (script from now on) as output. The script is then used to drive SCULPT and produce the animation. It is executed from the CLI with a command of the form: SCRIPT4D scriptname eg. SCRIPT4D Eye.script A program has a basic layout of: FRAMES n ...declarations... ...procedures... ...controllers... END The 'FRAMES n' specifies the number of frames in the animation. Declarations are used to define arrays of values and 'smooth motion' information. Procedures generally contain, amongst other things, SCULPT script commands that will be ouptut to the script. Individual procedures can be either active or suspended. Controllers specify program actions to take place at specified frames in the sequence. Controllers are usually used to activate procedures at the required frames. Program execution occurs as follows: 1) An internal current-frame counter is set to 1 2) Any and all controllers that refer to the current frame are executed. 3) All active procedures are executed in the order they appear in the program. 4) The frame counter is incremented and, if it does not exceed the declared number of frames, execution continues at 2) above. A skeleton program would be.. FRAMES 50 TO blink /* procedure */ ...commands... END TO nod /* procedure */ ...commands... END AT 1 /* controller */ START nod END AT 5 25 /* controller */ START blink END END Thus the procedure 'nod' would be activated just before frame 1 and 'blink' would be activated just before frames 5 and 25. Each time they would remain active until explicitly suspended, either by itself, by another procedure or by a controller. Let's take a more detailed look at a procedure. As we'll see later this one will be used to make a modelled eye blink. The commands used will be more fully described in the COMMANDS section. TO blink SETUP blinkstep = 2 /* cos step 1 is 0 deg. */ closingtime = 0 END EXECUTE /* select next angle for smooth motion */ SMOOTH blinker blinkstep blinkangle 'DESELECT ALL' 'SELECT NAMED "Eye+Lid" ' /* script commands to.. */ 'WINDOW EAST' /* rotate the eyelid... */ 'ROTATE CLOCKWISE %d ' (i) blinkangle IF blinkstep = 7 /* handle eye-closed time */ FREEZE closingtime ENDIF blinkstep += 1 IF blinkstep > 12 SUSPEND blink 32000 /* ie. until reSTARTed */ ENDIF END END A procedure consists of two command blocks, SETUP & EXECUTE. Commands in the SETUP block are executed at the time the procedure is STARTed. Those in the EXECUTE block execute for each frame that the procedure is active. In our example the SETUP block is simply initializing two variables: 'blinkstep' is used to keep track of how far through the 'blink' we are, 'closingtime' will be used to keep the eye closed for a variable amount of time (zero extra frames by default.) Once 'blink' is active, the commands in the EXECUTE block are executed for each subsequent frame. The SMOOTH command will calculate a suitable angle through which the eyelid should be rotated at the current step in the blink. The necessary SCULPT script commands are then output. Once the eye is closed, at step 7, it is 'frozen' in that state for a variable number of frames, otherwise the step number is incremented. If the blink has completed then the procedure SUSPENDs itself. Note that SCRIPT4D still relies on you to specify the appropriate SCULPT script commands, but it then gives you flexible & programmable control over the content & occurrence of those commands in the output script. ================================================================== EXAMPLE PROGRAM ================================================================== For the purposes of this description, I'll assume we want to animate a blinking eye that floats up & down. This in itself isn't complex enough to warrant using SCRIPT4D but it provides a method of demonstrating how SCRIPT4D can be used. The approach we'll take is thus: a) The animation will be 50 frames b) A Take, named EYE has been created, all relevant options selected and details filled in. c) A global SCENE containing OBSERVER, TARGET & LAMP(S) has been defined for the Take. d) An scene, called EYEEYE, has been created and stored to disk. The scene contains a single object. This object is named as follows: ...Lid | Eye...| | |...Ball | | |...Socket The centre of the eye sits at (0,0,0) and it is looking south. The eyelid covers the top of the eyeball, tilted back about 45 degrees. The socket is simply a cube in which the eye sits. e) A scene will be created for every frame of the animation by loading in the 'base' Eyeeye object and then modifying it as required for that frame. All the relevant files should accompany this program. I suggest you have a quick peek at EYEEYE.SCENE so you can see what's what! Every frame of the Take will be a key-frame. With the computer doing the work there's no reason why not! In any case, with complex animations this usually needs to be the case. The program, listed below can be found in the file 'Eye.prog'. Use this to generate the script file with the command: SCRIPT4D Eye.script Path names, both in the above command & in the supplied 'Take' may need modifying depending on your system configuration. There is a certain amount of 'housekeeping' required in the program, resulting in something that appears too complicated for what we're trying to achieve. However, such housekeeping can be defined once in a 'template' program and subsequently reused (with minor changes.) Note that within the program comments are delimited by '/*' & '*/'. FRAMES 50 /* define a 7-step smooth motion for 0 thru 90 degrees */ SMOOTHER blinking 0 90 7 /* relative up/down motion in 10 steps */ SMOOTHER floating -400 400 10 TO init EXECUTE 'LOAD TAKE "EYE" ' SUSPEND init 32000 /* init suspended for 32000 frames! */ END END TO getscene /* gets base scene for each frame */ EXECUTE 'TAKE CURRENT FRAME %d' (i) frame 'ERASE ALL' '(0,0,0)' 'LOAD SCENE "Eyeeye.scene"' END END TO blink /* how to make the eye blink */ SETUP blinkstep = 2 /* 2 'cos 1st angle would be 0 */ closingtime = 0 END EXECUTE /* select next angle for smooth motion */ blinkangle @= blinking blinkstep /* alternative to SMOOTH */ 'DESELECT ALL' /* output script commands to.. */ 'SELECT NAMED "Eye+Lid"' /* ..rotate eyelid */ 'WINDOW EAST' 'ROTATE CLOCKWISE %d' (i) blinkangle IF blinkstep = 7 /* handle eye-closed time */ FREEZE closingtime ENDIF blinkstep += 1 /* ready for next frame */ IF blinkstep > 12 SUSPEND blink ENDIF END END TO float /* floating up & down */ SETUP floatstep = 1 END EXECUTE floatlevel @= floating floatstep 'SELECT ALL' 'GRABBER ON' '[0,0,%d]' (i) floatlevel 'GRABBER OFF' floatstep += 1 IF floatstep > 10 floatstep = 1 ENDIF END END TO savescene /* saves scene & makes key frame */ EXECUTE 'TAKE KEY YES' 'TAKE SAVE KEY FRAME SCENE' END END TO render /* final script command */ EXECUTE 'TAKE PREVIEW' /* OR 'TAKE RENDER ALL' */ END END AT 1 /* before anything else.. */ START init /* start once-off init */ START getscene /* start scene load.. */ START savescene /* ..and save procedures */ START float /* floating all the time */ END AT 50 /* when all scenes generated.. */ START render END AT 5 /* what to do at frame 5 */ START blink /* set it rolling */ END AT 25 /* what to do at frame 18 */ START blink /* longer blink this time.. */ closingtime = 7 /* ..by overriding default */ END END /* of program */ The 'housekeeping' is done by the init, getscene, savescene & render procedures. The output from this program (Eye.script) can be input to SCULPT via the 'LOAD SCRIPT' menu option. I feel it's worth reiterating on the idea of having one, or indeed a set of, base objects that are modified from scratch for each key- frame scene. Imagine that our Eye was installed in a Head and that we wanted the animation to show a blinking eye, wobbling in a nodding Head. By having a base object of Head, pointing along one of the SCULPT axes, containing Eye, also pointing along an axis, we have created a known starting position of the object(s) for each key-frame scene. If motions are performed from the bottom of the hierarchy upwards (ie. Eyelid/Ball, Eye and finally Head) then there is no conflict between them. Imagine twisting the Head to one side and then trying to blink the Eyelid (uummm.. rotate Eyelid about which axis...?). Such a situation could arise if we base key-frame scene N on key- frame scene N-1. Using SCRIPT4D we can code each motion in a separate procedure and then order the procedures within the program to match the hierarchy of the objects. The 'nodding, wobbling, blinking eye' would require a program structure of the form: FRAMES n TO blink ... END TO wobble ... END TO nod ... END etc... Different procedures could, of course, refer to the same part of an object. For example, you could have one procedure that blinked the eyelid and another that made it flutter! Either could then be activated as & when required. This approach is by no means definitive. After you have studied the avalable commands you may well decided on a better method. Again, tell me your ideas! When it comes to archiving your creations all you need to copy is the SCRIPT4D program, the TAKE and the Global & base SCENE. There's no need to keep a copy of all the key-frame scenes because, if they're needed again, they can be recreated automatically. The saving in disk space can be huge! ================================================================== COMMANDS & program structure ================================================================== The program file is free-form except that all 'tokens' must be separated by white-space. Case is not significant except within string variables. SCRIPT4D is fairly strict when it comes to syntax checking but there are bound to be a few howlers, so take care - this is version 1 after all! A variable, smoother & table can NOT have the same name. However a procedure can have the same name as any of these without causing any conflct. Literals Literals Three types of literal are recognised by SCRIPT4D: integers, floating-point & string (enclosed in double quotes.) For example: 1234 55.7 ":SCULPT/SCENES/" Variables Variables Most SCRIPT4D commands use named variables to supply or store values. Variable names are recognised by context when the program is translated. Names must begin with an alphabetic character and can be up to 20 characters in length. A variable can hold any of the three literal types and is not restricted to any one type during program execution. There are two pre-defined variables: frame holds the current frame number. This should be considered 'read-only'. nextframe can be assigned the number of the next frame to be processed. Useful if you don't want every frame to be a key-frame. In the following command descriptions 'variable' parameters are shown in the form of ''. From the command description it should be obvious which ones must be variables and which can be literals. Variables & literals are converted to the type required by the command when they are accessed. For example, if an integer was required then variables/literals with these values would all return an integer value of 34 : 34 34.1 "34fred" If a specific type of variable/literal MUST be used then the command description will make that clear. ************************************************************** The following commands can only appear at the outer level of a program. They can not appear within procedures or controllers. FRAMES FRAMES A FRAMES command should be the first of the program. It tells SCRIPT4D how many times it should loop through the program. Syntax: FRAMES Where must be an integer literal. TABLE TABLE TABLE commands declare an 'array' of values that can be accessed at run-time. Syntax: TABLE ... END must follow the rules for a variable name. As many s as required can be specified. Both literals and variables can be used. In the latter case the value contained in the variable when the table is accessed will be used. Example: TABLE table1 12 45.7 tiltangle "90" END See the CHOOSE command for more details. SMOOTHER SMOOTHER SMOOTHERs are used to declare a sequence of values that progress smoothly from one limit to another in a given number of steps. Syntax: SMOOTHER follows the rules for a variable name. & must be integer or floating-point, literals or variables. must be an integer literal or variable. Example: SMOOTHER twist -20 20 11 Via the SMOOTH command (see later) this would generate values that vary from -20 to 20 in 11 steps. The value at step 1 would be -20, that at step 6 would be 0 and at step 11 would be 20. Steps less than zero and beyond the number specified (11 in this case) can be used - see 'Using Smooth' later. TO / END TO / END TO & END are used to name and delimit a procedure. There are two command blocks within a procedure, SETUP & EXECUTE, either but not both of which are optional. Syntax: TO SETUP . .commands . END EXECUTE . .commands . END END must follow the rules for a variable name. See the 'START' command. AT / END AT / END AT & END delimit a controller block and specifies at which frame(s) the controller is executed. Syntax: AT ... . .commands . END must be an integer literal. More than one frame number can be specified. Example: AT 2 7 22 16 START kick END ************************************************************* The following commands can only appear within a procedure or controller. SCRIPT COMMAND SCRIPT COMMAND A SCULPT script command is generated by enclosing the command in single quotes. In fact, any string can be output by this method. Syntax: '...text...' ... Parameters enable value substitution within the text string. Such substitution occurs in the manner of a C language 'printf' function. For example, the following: param1 = 45 param2 = 1.23 param3 = "34fred" 'One %d Two %f Three %s' (i) param1 (f) param2 (s) param3 would result in an output of: One 45 Two 1.23 Three 34fred The %d, %f & %s formats will be those most commonly used. You can, however, use any legal conversion specification that may appear in a C 'printf' format string provided they match the supplied parameter type. Note that it's mandatory to force the type of the parameter to match the required format, whether or not it already has the appropriate type: (i) forces to integer (f) forces to floating-point (s) forces to string CHOOSE CHOOSE Selects a value from a table. Syntax: CHOOSE must be the name of a previously declared table. is a variable or literal that specifies which entry in the table to retrieve, starting at 1. is the variable that will take the selected value. Example: CHOOSE table1 4 tilt See 'Assignments' for another way of coding this command. SMOOTH SMOOTH Calculates a value from a sequence defined by a SMOOTHER declaration. Syntax: SMOOTH must be the name of a previously declared smoother. is a variable or literal that specifies the step for which a value will be calculated. is the variable that will take the value. Example: SMOOTH twist twiststep twistangle See 'Using Smooth' for more details. See 'Assignments' for another way of coding this command. Assignments Assignments A direct assignment is of the form: = must be a variable, can be a variable or literal of any type. Arithmetic assignments are of the form: += -= *= /= These perform the appropriate operation on & and put the result in . For example, the commands: size = 20 diff = 5 size /= diff would result in 'size' having a value of 4 ( 20/5 ). must be a numeric variable. can be a literal or variable but must be numeric. Note that always retains its type. Selection assignments are of the form: @= where is a TABLE or SMOOTHER name. takes the value of the th entry in the table or smoother. This is an alternative method of coding SMOOTH & CHOOSE commands. Example: tilt @= table1 4 JOIN JOIN Concatenated strings. Syntax: JOIN Both values are, if necessary, converted to strings and then is appended . The result is placed in . Example: JOIN "+Lid" object EXIT EXIT Used to immediately terminate execution of a procedure for the current frame. Syntax: EXIT START START Activates a procedure for subsequent execution. Syntax: START must be a procedure name. A START command will clear any suspended or frozen state of the named procedure and execute its SETUP block (if any). STARTs would normally be used within controllers. If however a procedure called A (say) STARTs procedure B then B will execute in the current frame if it appears after A in the program and will not execute until the next frame if it appears before A in the program. DO DO Executes a procedure immediately. Syntax: DO must be a procedure name. The EXECUTE block of the named procedure is executed. No notice is taken of any suspended state nor is it cleared. A frozen state could be cleared if execution of the procedure causes its freeze count to decrement to zero. SUSPEND SUSPEND Suspends a procedure for a given number of frames. Syntax: SUSPEND must be a procedure name. must be a numeric literal or variable. Before a procedure is executed a check is made to see if it is suspended. If so, the suspend count is decremented by 1 and if it has not reached zero execution of that procedure is skipped. Example: SUSPEND eyeroll 16 RESTART RESTART Activates a suspended procedure &/or thaws a frozen procedure. Syntax: RESTART Example: RESTART eyeroll FREEZE FREEZE FREEZE enables the procedure in which it occurs to be 'frozen' in a particular state for a given number of frames. Syntax: FREEZE is a numeric variable or literal. We'll use a modified version of the 'blink' procedure as an example: TO blink ... EXECUTE blinkangle @= blinking blinkstep /* ...commands to rotate eyelid by 'blinkangle'... */ IF blinkstep = 7 FREEZE 5 ENDIF blinkstep += 1 IF blinkstep > 12 SUSPEND blink ENDIF END END At the 7th step of the blink (ie. when the eye is closed) the procedure is frozen for 5 frames. Execution of FREEZE at this point causes the freeze-count to be set to 5 and the remaining commands of the procedure to be skipped. Thus blinkstep remains at 7. In subsequent frames, 'blink' is executed and, again, the eyelid is rotated to the closed position. The FREEZE command will execute and provided the freeze-count is zero then so will the rest of the procedure. Otherwise the freeze-count is decremented and the remaining commands of the procedure are skipped. By this method the rotation of the eyelid remains fixed because 'blinkstep' is not incremented while the procedure is frozen. Note that a RESTART will remove a FREEZE. IF / ELSE / ENDIF IF / ELSE / ENDIF These provide for basic conditional processing. Syntax: IF ...commands... ENDIF or IF ...commands... ELSE ...commands... ENDIF is a simple comparision of two variables/literals.: A < B less than A = B equal to A > B greater than A != B not equal to Example: IF longdelay = 1 FREEZE 12 ELSE FREEZE 4 ENDIF ================================================================== USING SMOOTH ================================================================== The idea of SMOOTHER & SMOOTH is to aid in the animation of objects that are to move in an apparently smooth manner from one state to another by simulating acceleration & deacceleration from & to rest. Note that this applies to both rotational as well a spatial movement. The following programs show three ways of using these commands to get different effects. You'll have to key these progs yourself! In each case execute the program with a command of the form: SCRIPT4D