; merge-anim.scm - Merge the bg or top layer of an image with all other layers.
; Copyright (C) 1998 Raphael Quinet
; 
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.  
; 
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
; 
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
;
; --- Description ---
; This script allows you to add a background to an existing animation,
; or to add some object on top of all frames.   You can optionally add
; fade-in/fade-out effects or some movement by varying the opacity and
; position of the merged layers.
; The script does nothing more than repeatedly copying the new layer
; and merging it with each of the other layers.  You could also do this
; by hand, but this is a boring task.  That's why I wrote this script.
;
; --- Change log ---
; 1.0 - 1998-08-10
;       First public release.
; 1.1 - 1998-08-11
;       Merged 'merge-bg.scm' and 'merge-top.scm' into a single script
;       named 'merge-anim.scm'.  Someone should write 'merge-scm.scm'...
; 1.2 - 1998-08-11
;       Added GRAYA to the list of supported image types (RGB and GRAY
;       without alpha would not work because we need two layers).

(define (script-fu-merge-anim image drawable
			      src-is-bg visible-only delete-src
			      i-opacity f-opacity
			      transform-anim
			      i-offset-x i-offset-y
			      f-offset-x f-offset-y)
  (let* ((layers (gimp-image-get-layers image))
	 (num-layers (car layers))
	 (layer-array (cadr layers))
	 (diff-opacity (- i-opacity f-opacity))
	 (diff-offset-x (- i-offset-x f-offset-x))
	 (diff-offset-y (- i-offset-y f-offset-y)))
 
    (if (> num-layers 1)
	(let* ((visi-array (cons-array num-layers))
	       (num-vlayers (- num-layers 1))
	       (src-layer (aref layer-array (if (= src-is-bg TRUE)
						num-vlayers
						0))))
	  
	  (gimp-image-disable-undo image)

	  ; hide all layers (visi-array keeps track of which ones were visible)
	  (set! layer-count (- num-layers 1))
	  (while (>= layer-count 0)
		 (let* ((layer (aref layer-array layer-count))
			(visible (car (gimp-layer-get-visible layer))))
		   (aset visi-array layer-count visible)
		   (if (and (= visible-only TRUE)
			    (= visible FALSE))
		       (set! num-vlayers (- num-vlayers 1)))
		   (gimp-layer-set-visible layer FALSE))
		 (set! layer-count (- layer-count 1)))

	  (set! vlayer-count num-vlayers)
	  (set! layer-count (- num-layers (if (= src-is-bg TRUE) 2 1)))

	  (if (> num-vlayers 0)
	      (while (>= layer-count (if (= src-is-bg TRUE) 0 1))
		     (let* ((layer (aref layer-array layer-count))
			    (was-visible (aref visi-array layer-count)))

		       (if (or (= visible-only FALSE)
			       (= was-visible TRUE))
			   (let* ((new-layer (car (gimp-layer-copy src-layer
								   TRUE)))
				  (new-name (car (gimp-layer-get-name layer)))
				  (opacity (+ f-opacity
					      (/ (* diff-opacity
						    vlayer-count)
						 num-vlayers)))
				  (offset-x (+ f-offset-x
					       (/ (* diff-offset-x
						     vlayer-count)
						  num-vlayers)))
				  (offset-y (+ f-offset-y
					       (/ (* diff-offset-y
						     vlayer-count)
						  num-vlayers)))
				  (offset-layer (if (= transform-anim TRUE)
						    layer
						    new-layer)))
			     ; add the copy of the source layer
			     (gimp-image-add-layer image new-layer
						   (+ layer-count
						      (if (= src-is-bg TRUE)
							  1 0)))
			     ; make both layers visible
			     (gimp-layer-set-visible new-layer TRUE)
			     (gimp-layer-set-visible layer TRUE)
			     ; change the opacity of the top layer
			     (gimp-layer-set-opacity (if (= src-is-bg TRUE)
							 layer
							 new-layer)
						     opacity)
			     ; if specified, move one of the layers
			     (if (not (and (= offset-x 0) (= offset-y 0)))
				 (gimp-channel-ops-offset image offset-layer
							  TRUE 0
							  offset-x offset-y))
			     ; merge them
			     (set! merged-layer
				   (car (gimp-image-merge-visible-layers 
					 image CLIP-TO-IMAGE)))
			     (aset layer-array layer-count merged-layer)
			     (gimp-layer-set-name merged-layer new-name)
			     ; hide the result
			     (gimp-layer-set-visible merged-layer FALSE)
			     (set! vlayer-count (- vlayer-count 1)))))
		     (set! layer-count (- layer-count 1)))

	      ; ...else num-vlayers <= 0
	      (gimp-message "There are no visible layers in the image!"))

	  ; restore the visibility of all layers
	  (set! layer-count (- num-layers 1))
	  (while (>= layer-count 0)
		 (let* ((layer (aref layer-array layer-count))
			(visible (aref visi-array layer-count)))
		   (gimp-layer-set-visible layer visible))
		 (set! layer-count (- layer-count 1)))

	  (if (and (= delete-src TRUE) (> num-vlayers 0))
	      (gimp-image-remove-layer image
				       (aref layer-array
					     (if (= src-is-bg TRUE) 
						 (- num-layers 1)
						 0))))
	  ; that's all, folks!
	  (gimp-image-enable-undo image)
	  (gimp-displays-flush))

	; ...else num-layers <= 1
	(gimp-message "The source image must have at least two layers"))))


(script-fu-register
	"script-fu-merge-anim"
	"<Image>/Script-Fu/Animators/Merge layer with others"
	"Merge the background or top layer with all other layers in the image"
	"Raphael Quinet <quinet@gamers.org>"
	"Raphael Quinet"
	"1998-08-11"
	"RGBA GRAYA"
	SF-IMAGE "Input Image" 0
	SF-DRAWABLE "Input Drawable" 0
	SF-TOGGLE "Merge with bg (else top)?" TRUE
	SF-TOGGLE "Visible layers only?" TRUE
	SF-TOGGLE "Delete bg/top after merge?" TRUE
	SF-VALUE "Initial opacity (%)" "100.0"
	SF-VALUE "Final opacity (%)" "100.0"
	SF-TOGGLE "Offset anim instead of bg/top?" FALSE
	SF-VALUE "Initial X offset" "0"
	SF-VALUE "Initial Y offset" "0"
	SF-VALUE "Final X offset" "0"
	SF-VALUE "Final Y offset" "0"
)
