source files: [xc]03d.[ch]
(SEND <x03d> :GET :PER-FRAME-HOOK) (SEND <x03d> :SET :PER-FRAME-HOOK (function <fn>)) (SEND <x03d> :SET :PER-FRAME-HOOK (list (function <fn>) ... ))
The :PER-FRAME-HOOK provides a simple, decentralized facility for animating any Skandha4 object -- that is, for making any property of that object an arbitrary function of time.
If :per-frame-hook on an object is set to a function or a list of functions (taking zero arguments), then those function(s) will be called (at most) once per frame, the first time the object in question is touched. A 'frame' is defined as the time between :swap-buffers messages to any camera. If the object in question is not used in any way during the frame, the :per-frame-hook functions will not be invoked. (If you want to ensure that a given action takes place every frame, you should instead use the global variable xg.3d-per-frame-hook.)
As an example, if *TIME* is a time-dependent variable and TRANSFORM is a mat44 controlling some thing, the thing may be made to rotate by:
(let* ( (our-transform transform) ; Build a local binding for TRANSFORM ) (:set our-transform :per-frame-hook (lambda NIL ; Our 'lambda' will lock in OUR-TRANSFORM (send our-transform :ROTATE :DEGREES *TIME*) ) ) )
If *TIME* progresses linearly, the thing will rotate smoothly. (The :SCRIPT-TIME and :SCRIPT-RATE properties on cameras are the standard mechanism for specifying a smoothly varying time -- see ;GET ;SET etc cmr.)
Substituting (sin *TIME*) for *TIME* above would make the thing oscillate instead of rotate.
Again assuming that *TIME* is a time-dependent variable, and that GRL is a graphic relation containing :POINT-X :POINT-Y and :POINT-Z and :POINT-RED, :POINT-GREEN, :POINT-BLUE arrays, sinusoidal color waves travelling down the Z axis may be introduced by:
(let* ( (our-grl grl) ; Build a local binding for GRL ) (:set our-grl :per-frame-hook (lambda NIL ; Our 'lambda' will lock in OUR-GRL (:pointwise-eval grl '(setq :point-red (sin (+ :point-z *TIME* 1.0)))) (:pointwise-eval grl '(setq :point-green (sin (+ :point-z *TIME* 2.0)))) (:pointwise-eval grl '(setq :point-blue (sin (+ :point-z *TIME* 3.0)))) ) ) )
Assuming that THING is a thing of lines suitable for holding hershey text, THING may be set to visually display the count of frames generated by a hook expression like:
(let* ( (our-thing thing) ; Build a local binding for THING. (our-frame 0) ; Build a local binding in which to count frames. ) ;; Note that since things are just lisp lists, we can't attach a ;; :per-frame-hook value to the thing as such, so we attach ;; it to a component of the relation: (:set (:get our-thing :facet-relation) :per-frame-hook (lambda NIL ; Our 'lambda' will lock in our-thing, our-frame (xg.3d-empty-thing our-thing) ; Discard text from last frame (xg.3d-insert-hershey-string :thing our-thing :text (format nil "Frame ~S" (setq our-frame (1+ our-frame))) :x 0 :y 0 :z 0 :justify :center ) ) ) )