View difference between Paste ID: PbRVFXcT and 7crBgxGa
SHOW: | | - or go back to the newest paste.
1
; Implements
2
; http://learnfobia.com/category-Computers-47/tutorial-Painting-A-Spaceship-Hull-Texture-2126.html
3
(define (script-fu-render-greebles
4
    img drw
5
    layers size num
6
    aspect-limit change-factor smudge-density
7
    fuzz exposure)
8
  (list
9
    (loop 0 layers (lambda (x)
10
      (with-selection img (lambda ()
11
        (with-color (lambda ()
12
          (let*
13
            (
14
              (w (car (gimp-image-width img)))
15
              (h (car (gimp-image-height img))))
16
            (list
17
              (random-blend)
18
              (greeblestep
19
                img (list w h) drw
20
                (= x 0)
21
                (list size num aspect-limit (* (+ x 1) change-factor))
22
                smudge-density fuzz exposure)
23
              (gimp-drawable-update drw 0 0 w h)
24
              (gimp-displays-flush)))))))))))
25
(script-fu-register
26
  "script-fu-render-greebles"
27
  "G_reebles"
28
  "Renders greebles"
29
  "FeepingCreature"
30
  ""
31
  ""
32
  "*"
33
  SF-IMAGE	"The Image"	0
34
  SF-DRAWABLE	"The Layer"	0
35
  SF-VALUE	"Layers"	"2"
36
  SF-VALUE	"Base size"	"200"
37
  SF-VALUE	"numGreebles per layer"	"35"
38
  SF-VALUE	"Base aspect limiter"	"2"
39
  SF-VALUE	"Aspect change factor"	"3"
40
  SF-VALUE	"Smudge Density"	"7"
41
  SF-VALUE	"Edge Fuzz Spread"	"4"
42
  SF-VALUE	"Smudge Exposure"	"20")
43
(script-fu-menu-register "script-fu-render-greebles" "<Image>/Filters/Render")
44
45
; call f with numbers from 'from' to 'to', end-exclusive
46
(define loop (lambda (from to f)
47
  (while (< from to)
48
    (f from)
49
    (set! from (+ from 1)))))
50
; call f, then restore foreground/background color
51
(define with-color (lambda (f)
52
  (let*
53
    (
54
      (bg (car (gimp-context-get-background)))
55
      (fg (car (gimp-context-get-foreground))))
56
    (list
57
      (f)
58
      (gimp-context-set-background bg)
59
      (gimp-context-set-foreground fg)))))
60
; set context color to a random mix of foreground and background
61
(define random-blend (lambda ()
62
  (let*
63
    (
64
      (blend (blend (/ (random 1000) 1000)))
65
      (fg (car (gimp-context-get-foreground)))
66
      (bg (car (gimp-context-get-background))))
67
    (gimp-context-set-foreground (list
68
      (blend (car fg) (car bg))
69
      (blend (cadr fg) (cadr bg))
70
      (blend (caddr fg) (caddr bg)))))))
71
; generate a blender function that blends between two numbers with factor 'f'.
72
(define blend (lambda (f)
73
  (lambda (a b)
74
    (+
75
      (* a (- 1 f))
76
      (* b f)))))
77
; adds one layer of greebles
78
(define greeblestep (lambda (img img-size drawable overwrite-background select-args steps fuzz exposure)
79
  ((with-undo-group img (lambda ()
80
    (with-selection img (lambda ()
81
      (list
82
        ; build our random-rectangles selection
83
        (apply (curry reselect img img-size) select-args)
84
        ; paint the foreground/background
85
        (swap-and-do drawable img
86
          (combine
87
            (curry2 gimp-edit-fill FOREGROUND-FILL)
88
            (curry (thing-it drawable (curry2 gimp-dodgeburn exposure BURN MIDTONES)) steps))
89
          (combine
90
            (if overwrite-background (curry2 gimp-edit-fill BACKGROUND-FILL) (lambda (d) #t))
91
            (curry (thing-it drawable (curry2 gimp-dodgeburn exposure DODGE MIDTONES)) steps)))
92
        ; grab the border of our selection
93
        (border-select img fuzz)
94
        (with-color (lambda ()
95
          (list
96
            (gimp-context-set-foreground (list 0 0 0)) ; draw border in black
97
            (gimp-edit-fill drawable FOREGROUND-FILL))))))))))))
98
; treats f as a single undo group
99
(define with-undo-group (lambda (img f)
100
  (guard
101
    (curry gimp-image-undo-group-start img)
102
    (curry gimp-image-undo-group-end img)
103
    f)))
104
; executes 'first', then 'f', then 'last'. TODO: make error safe.
105
(define guard (lambda (first last f)
106
  (lambda x
107
    (list (first) (apply f x) (last)))))
108
; partial application
109
(define (curry fun . args) (lambda x
110
  (apply fun (append args x))))
111
; 2.6 compatibility stub
112
(define rectselect (if
113
  (string=? (substring (car (gimp-version)) 0 3) "2.6")
114-
    (lambda (image operation x y width height) (gimp-rect-select img x y width height operation 0 0))
114+
    (lambda (image operation x y width height) (gimp-rect-select image x y width height operation 0 0))
115
    gimp-image-select-rectangle))
116
; select a bunch of rectangles at random
117
(define reselect (lambda (img img-size size num range ratio)
118
  (let*
119
    (
120
      (ch (car (gimp-selection-save img))))
121
    (list
122
      (gimp-selection-none img)
123
      (loop 0 num (lambda (x)
124
        (let*
125
          (
126
            (x (random (car img-size)))
127
            (y (random (cadr img-size)))
128
            (pair (random-one ratio)))
129
          (my-select-rectangle-helper
130
            x
131
            y
132
            (/ (random2n (/ size range) size) (car pair))
133
            (/ (random2n (/ size range) size) (cadr pair))
134
            (curry rectselect img CHANNEL-OP-ADD)))))
135
      (script-fu-channel-grab img ch CHANNEL-OP-INTERSECT)))))
136
; randomly append or prepend a 1.
137
; used for vertical or horizontally scaled rectangles.
138
(define random-one (lambda (n)
139
  (if (= (random 2) 0)
140
    (list n 1)
141
    (list 1 n))))
142
; a select-rectangle wrapper that handles negative width/height
143
(define my-select-rectangle-helper (lambda (x y w h f)
144
  (let*
145
    (
146
      (xx (if (< w 0) (+ x w) x))
147
      (yy (if (< h 0) (+ y h) y)))
148
    (f xx yy (abs w) (abs h)))))
149
; random number from [-to..-from], [from..to]
150
(define random2n (lambda (from to)
151
  (let*
152
    (
153
      (tmp (+ (random (- to from)) from)))
154
    (if (= (random 2) 0)
155
      tmp
156
      (- 0 tmp)))))
157
; execute f1, invert selection, execute f2, invert selection
158
(define swap-and-do (lambda (d img f1 f2)
159
  (let*
160
    (
161
      (w (car (gimp-drawable-width d)))
162
      (h (car (gimp-drawable-height d))))
163
    (list
164
      (f1 d)
165
      (gimp-selection-invert img)
166
      (f2 d)
167
      (gimp-selection-invert img)))))
168
; takes a bunch of functions and combines them into one that has the
169
; same arguments as each of them and calls them in turn
170
(define combine (lambda x
171
  (lambda y
172
    (if (= (length x) 0)
173
      ()
174
      (append
175
        (list (apply (car x) y))
176
        (apply (apply combine (cdr x)) y))))))
177
; like curry, except it keeps the first argument
178
(define (curry2 fun . args) (lambda x
179
  (apply fun (append (list (car x)) args (cdr x)))))
180
; execute some action 'fn' over the entire image in subdivisions of 'divs'.
181
(define thing-it (lambda (d fn)
182
  (lambda (divs)
183
    ((with-undo-group
184
      (car (gimp-item-get-image d))
185
      (lambda ()
186
        (let*
187
          (
188
            (w (car (gimp-drawable-width d)))
189
            (h (car (gimp-drawable-height d))))
190
          (loop 0 (+ divs 1) (lambda (y)
191
            (loop 0 (+ divs 1) (lambda (x)
192
              (fn
193
                d
194
                2
195
                (floatarray (* (/ w divs) y) (* (/ h divs) x))))))))))))))
196
; source for floatarray:
197
; http://www.math.grinnell.edu/~rebelsky/Glimmer/Summer2006/GIMP/sam.scm
198
; coerce a list into a float-array
199
(define floatarray (lambda floats
200
  (let*
201
    (
202
      (len (length floats))
203
      (vec (cons-array len 'double)))
204
    (letrec
205
      ((kernel (lambda (pos rest)
206
        (if
207
          (= pos len)
208
          vec
209
          (begin
210
            (vector-set! vec pos (car rest))
211
            (kernel (+ pos 1) (cdr rest)))))))
212
      (kernel 0 floats)))))
213
; saves/restores active selection after 'f' is executed
214
(define with-selection (lambda (img f)
215
  (let*
216
    (
217
      (ch (car (gimp-selection-save img))))
218
    (list
219
      (f)
220
      (script-fu-channel-grab img ch CHANNEL-OP-REPLACE)))))
221
; select the border of our selection using feather
222
(define border-select (lambda (img fuzz)
223
  (let*
224
    (
225
      (ch1 (car (gimp-selection-save img))))
226
    (list
227
      (gimp-selection-feather img fuzz)
228
      (let*
229
        (
230
          (ch2 (car (gimp-selection-save img))))
231
        (list
232
          (script-fu-channel-grab img ch1 CHANNEL-OP-REPLACE)
233
          (gimp-selection-invert img)
234
          (gimp-selection-feather img fuzz)
235
          (script-fu-channel-grab img ch2 CHANNEL-OP-INTERSECT)))))))
236
; remove a (temporary) channel after applying it as a selection
237
(define script-fu-channel-grab (lambda (img ch op)
238
  (list
239
    (gimp-image-select-item img op ch)
240
    (gimp-image-remove-channel img ch))))