User:Pedro Oval/GIMP Layers to SL Animated Texture
Jump to navigation
Jump to search
Development version
<scheme>
- Layers to SL Texture Animation, version 2.0pre1
- Written by Pedro Oval, 2010-12-04.
- Donated to the public domain.
- Thanks to Digital Dharma for the suggestions.
(define (script-fu-layers-to-sl-anim curimg curdrawable xframes yframes showscript fps)
; Read the layer IDs and the total number of layers from the original image. (define layerset (gimp-image-get-layers curimg)) (define numframes (car layerset)) (set! layerset (cadr layerset))
; The frame size X and Y is the size of the original image. (define framesizex (car (gimp-image-width curimg))) (define framesizey (car (gimp-image-height curimg)))
; Get the image type; indexed images need special treatment. (define imgtype (car (gimp-image-base-type curimg)))
; Check if the given number of horizontal x vertical frames matches
; the number of layers in the original image. If yes, proceed; if not,
; show an error message.
(if (= numframes (* xframes yframes))
(begin
; New image
(define img (car (gimp-image-new (* framesizex xframes) (* framesizey yframes) imgtype)))
; We don't touch the original image, so we start a new undo group
; for the new image instead.
(gimp-image-undo-group-start img)
(if (= imgtype INDEXED)
(begin
; Indexed images need the palette to be copied to the new image.
(define palette (gimp-image-get-colormap curimg))
(gimp-image-set-colormap img (car palette) (cadr palette))))
; Loop betwen 0 and numframes - 1.
(define frame 0)
(while (< frame numframes)
; For each layer/frame:
(begin
; Show progress as the current frame relative to the number of frames.
(gimp-progress-update (/ frame numframes))
; Read the individual layer ID, starting from the bottom.
(define oldlayer (vector-ref layerset (- numframes frame 1)))
; Create new layer as a copy of this one and add it to the image.
(define newlayer (car (gimp-layer-new-from-drawable oldlayer img)))
(gimp-image-add-layer img newlayer -1)
; Add alpha if the layer doesn't have it.
(if (= (car (gimp-drawable-has-alpha newlayer)) FALSE)
(gimp-layer-add-alpha newlayer))
; Calculate the offsets and crop size.
(define offsets (gimp-drawable-offsets oldlayer))
(define newsizex (car (gimp-drawable-width oldlayer)))
(define newsizey (car (gimp-drawable-height oldlayer)))
(define offsetx (car offsets))
(define offsety (cadr offsets))
(if (< offsetx 0)
(begin
(set! newsizex (+ newsizex offsetx))
(set! offsetx 0)))
(if (< offsety 0)
(begin
(set! newsizey (+ newsizey offsety))
(set! offsety 0)))
(if (> (+ offsetx newsizex) framesizex)
(set! newsizex (- framesizex offsetx)))
(if (> (+ offsety newsizey) framesizey)
(set! newsizey (- framesizey offsety)))
; Calculate frame position X and Y.
(define framey (truncate (/ frame xframes)))
(define framex (- frame (* framey xframes)))
(set! framex (* framex framesizex))
(set! framey (* framey framesizey))
; Resize and place the layer.
(gimp-layer-resize newlayer
newsizex
newsizey
(- (car offsets) offsetx)
(- (cadr offsets) offsety))
(gimp-layer-set-offsets newlayer (+ framex offsetx) (+ framey offsety))
; Force it visible.
(gimp-drawable-set-visible newlayer TRUE)
; All done. Next loop iteration.
(set! frame (+ frame 1))))
; Progress 100%
(gimp-progress-update 1.0)
; Merge visible layers (all are visible now).
(define mergedlayer (car (gimp-image-merge-visible-layers img CLIP-TO-IMAGE)))
; Make the new layer the size of the image.
(gimp-layer-resize-to-image-size mergedlayer)
; Convert the image to RGB if it is not already.
(if (not (= imgtype RGB))
(gimp-image-convert-rgb img))
; Detect alpha by converting it to a selection.
(gimp-selection-layer-alpha mergedlayer)
; If there is no useful alpha, the selection should cover the whole image.
; Invert it, and if it becomes empty, then it means that alpha was not
; in use: the whole image was covered with 100% opacity.
(gimp-selection-invert img)
(define hasalpha (car (gimp-selection-bounds img)))
(gimp-selection-none img)
; If it didn't have any alpha, remove the alpha mask from the layer.
(if (= hasalpha FALSE)
(gimp-layer-flatten mergedlayer))
; All done - close the undo group and add a display window for the new image.
(gimp-image-undo-group-end img)
(gimp-display-new img)
; Show the script if requested
(if (= showscript TRUE)
(gimp-message (string-append "default\n{\n state_entry()\n {\n"
" llSetTextureAnim(ANIM_ON | LOOP, "
(number->string xframes)
", "
(number->string yframes)
", 0.0, "
(number->string (* xframes yframes))
".0, "
(number->string fps)
");\n }\n}\n"))))
; If the frame counts didn't match... (gimp-message "Error: Number of layers doesn't match horizontal x vertical frames")))
- Register the function.
(script-fu-register "script-fu-layers-to-sl-anim"
_"<Image>/Script-Fu/SecondLife/Frames to texture..."
_"Convert a set of layers (frames) to a texture suitable for llSetTextureAnim."
"Pedro Oval"
_"Public Domain"
"2010-12-04"
"RGB*, GRAY*, INDEXED*"
SF-IMAGE "Image" 0
SF-DRAWABLE "Drawable" 0
SF-ADJUSTMENT _"# of horizontal frames" '(2 1 1024 1 10 0 1)
SF-ADJUSTMENT _"# of vertical frames" '(2 1 1024 1 10 0 1)
SF-TOGGLE _"Generate LSL script?" TRUE
SF-VALUE _"Frames per second (for script):" "10.0")
</scheme>
New in this version with respect to the stable one:
- Add progress indicator.
- Clip each layer to its rectangle.
- Respect the original offsets of layers.
- Do the merge down in the correct order.
- Add alpha to the layers that lack it.
- Set the final layer's size to the image's size.
- Extensively commented.
- Generate the LSL script.
- Automatically remove alpha from the final image if not needed.
TODO list
- Perhaps change the strategy to use gimp-image-duplicate to simplify the process.
- Add the opposite conversion: given an animated texture, split it into layers.
- Read the layer name to see if it includes the word "(combine)", and if so, combine it, as the Unoptimize filter does.