# $p0 ; period (in pixels)
# $p1 ; amplitude
# $p2 ; amplitude modulation cycles (0=none, number cycles during frame sequence)
# $p3 ; modulation type linear/sinusoidal (dropdown)
# $p4 ; direction (bool: horiz=0 vert=1)
# $p5 ; edge type (dropdown: smear, wrap, blank)
# $p6 ; sine wave  (radio group 1)
# $p7 ; triangle   (radio group 1)
# $p8 ; velocity (0=constant, else number of pixels shifted each frame)

# Note: GIMP's Ripple plug-in does not directly support either phase shifting
#       or negative amplitudes. To implement phase shifting, it is therefore
#       necessary to resize the drawable by the amount of the shift. To
#       accommodate negative amplitudes, the effect is also phase shifted
#       by half the period.
#
#       next-modulation and rfx-ripple-phase are each a pair containing
#       the current value and the increment amount. Both need to be defined
#       globally and therefore can not be defined within a lambda/let.
#
#       In the case of rfx-ripple-phase, the value is an offset in the 
#       range 0 <= X < period (period is in pixels). 
#
#       In the case of rfx-modulation, the value is an offset that is in the
#       range 0 <= X < 1. The script then determines the scaling of 
#       the actual ripple amplitude based upon the evaluation of either
#       the triangle or sinusoidal.
#
&rfx_sendmsg (
  qq{
    (begin
      (if (= $frame $start)
        (define next-modulation (make-progressor 0 (* $p2 (/ (succ (- $end $start)))) 1.0)) )
      (if (= $frame $start)
        (define next-phase (make-progressor 0 
                                            (if (> $p8 0)
                                              (- $p0 $p8) 
                                              (- $p8) )
                                            $p0 )) )
      (let ((period $p0)
            (amplitude $p1)
            (mod-cycles $p2)
            (mod-linear $p3)
            (direction $p4)
            (edge $p5)
            (sine $p6)
            (triangle $p7)
            (velocity (- $p8))
            (phase-offset (next-phase))
            (curr-modulation (next-modulation))
            )
        (let* ((input-file (string-append "$curtmpdir" DIR-SEPARATOR "$in"))
               (image (car (gimp-file-load RUN-NONINTERACTIVE input-file input-file)))
               (layer (car (gimp-image-get-active-layer image))) )
          ; calculate layer offfset owing to animated phase
          (set! amplitude 
            (* amplitude
              (if (zero? mod-cycles)
                1
                (let ((fract (- curr-modulation (truncate curr-modulation))))
                  (if mod-linear
                    (cond 
                      ((< fract 0.25)
                        (* amplitude fract 4) )
                      ((< fract 0.50)
                        (* amplitude (- 1 (* (- fract 0.25) 4))) )
                      ((< fract 0.75)
                        (* amplitude (- (* amplitude (- fract 0.5) 4))) )
                      (else
                        (- (* amplitude (- fract 0.75) 4) 1) )))
                    (sin (* 2 *pi* fract)) ))))
          (when (< amplitude 0)
            (set! phase-offset (+ phase-offset (/ period 2)))
            (if (>= phase-offset period)
              (set! phase-offset (- phase-offset period)) ))
          (set! amplitude (abs amplitude))
          (unless (zero? phase-offset)
            (if (zero? direction) 
              (gimp-layer-resize layer
                                 $width
                                 (+ phase-offset $height)
                                 0
                                 phase-offset )
              (gimp-layer-resize layer
                                 (+ phase-offset $width)
                                 $height
                                 phase-offset
                                 0 )))
          (plug-in-ripple RUN-NONINTERACTIVE image layer
                          period
                          amplitude
                          direction
                          edge
                          sine
                          TRUE  ; always use antialias
                          FALSE ; we don't need tilability
                          )
          (gimp-layer-resize-to-image-size layer)
          (rfx-save-frame image "$out") 
          )
        )
      )
    }
  );

