Ajout de « Il pleut bergère ».
[minwii.git] / src / minwii / gradients.py
1 #Copyright 2006 DR0ID <dr0id@bluewin.ch> http://mypage.bluewin.ch/DR0ID
2 #
3 #
4 #
5 """
6 Allow to draw some gradients relatively easy.
7 """
8
9 __author__ = "$Author: DR0ID $"
10 __version__= "$Revision: 109 $"
11 __date__ = "$Date: 2007-08-09 20:33:32 +0200 (Do, 09 Aug 2007) $"
12
13 import pygame
14 import math
15
16 BLEND_MODES_AVAILABLE = False
17 vernum = pygame.vernum
18 if vernum[0]>=1 and vernum[1]>=8:
19 BLEND_MODES_AVAILABLE = True
20
21
22 class ColorInterpolator(object):
23 '''
24 ColorInterpolator(distance, color1, color2, rfunc, gfunc, bfunc, afunc)
25
26 interpolates a color over the distance using different functions for r,g,b,a
27 separately (a= alpha).
28 '''
29 def __init__(self, distance, color1, color2, rfunc, gfunc, bfunc, afunc):
30 object.__init__(self)
31
32 self.rInterpolator = FunctionInterpolator(color1[0], color2[0], distance, rfunc)
33 self.gInterpolator = FunctionInterpolator(color1[1], color2[1], distance, gfunc)
34 self.bInterpolator = FunctionInterpolator(color1[2], color2[2], distance, bfunc)
35 if len(color1)==4 and len(color2)==4:
36 self.aInterpolator = FunctionInterpolator(color1[3], color2[3], distance, afunc)
37 else:
38 self.aInterpolator = FunctionInterpolator(255, 255, distance, afunc)
39
40 def eval(self, x):
41 '''
42 eval(x) -> color
43
44 returns the color at the position 0<=x<=d (actually not bound to this interval).
45 '''
46 ## print "colorInterp x", x, self.rInterpolator.eval(x), self.gInterpolator.eval(x), self.bInterpolator.eval(x)
47 return [self.rInterpolator.eval(x),
48 self.gInterpolator.eval(x),
49 self.bInterpolator.eval(x),
50 self.aInterpolator.eval(x)]
51
52
53
54 class FunctionInterpolator(object):
55 '''
56 FunctionINterpolator(startvalue, endvalue, trange, func)
57
58 interpolates a function y=f(x) in the range trange with
59 startvalue = f(0)
60 endvalue = f(trange)
61 using the function func
62 '''
63 def __init__(self, startvalue, endvalue, trange, func):
64 object.__init__(self)
65 # function
66 self.func = func
67 # y-scaling
68 self.a = endvalue-startvalue
69 if self.a == 0:
70 self.a = 1.
71 # x-scaling
72 if trange!=0:
73 self.b = 1./abs(trange)
74 else:
75 self.b = 1.
76 # x-displacement
77 self.c = 0
78 # y-displacement
79 self.d = min(max(startvalue,0),255)
80
81 def eval(self, x):
82 '''
83 eval(x)->float
84
85 return value at position x
86 '''
87 # make sure that the returned value is in [0,255]
88 ## return int(round(min(max(self.a*self.func(self.b*(x+self.c))+self.d, 0), 255)))
89 return int(min(max(self.a*self.func(self.b*(x+self.c))+self.d, 0), 255))
90
91
92
93 ##def gradient(surface,
94 ## startpoint,
95 ## endpoint,
96 ## startcolor,
97 ## endcolor,
98 ## Rfunc = (lambda x:x),
99 ## Gfunc = (lambda x:x),
100 ## Bfunc = (lambda x:x),
101 ## Afunc = (lambda x:1),
102 ## type = "line",
103 ## mode = None ):
104 ## '''
105 ## surface : surface to draw on
106 ## startpoint: (x,y) point on surface
107 ## endpoint : (x,y) point on surface
108 ## startcolor: (r,g,b,a) color at startpoint
109 ## endcolor : (r,g,b,a) color at endpoint
110 ## Rfunc : function y = f(x) with startcolor =f(0) and endcolor = f(1) where 0 is at startpoint and 1 at endpoint
111 ## Gfunc : --- " ---
112 ## Bfunc : --- " ---
113 ## Afunc : --- " ---
114 ## these functions are evaluated in the range 0 <= x <= 1 and 0<= y=f(x) <= 1
115 ## type : "line", "circle" or "rect"
116 ## mode : "+", "-", "*", None (how the pixels are drawen)
117 ##
118 ## returns : surface with the color characteristics w,h = (d, 256) and d = length of endpoint-startpoint
119 ##
120 ## '''
121 ## dx = endpoint[0]-startpoint[0]
122 ## dy = endpoint[1]-startpoint[1]
123 ## d = int(round(math.hypot(dx, dy)))
124 ## angle = math.degrees( math.atan2(dy, dx) )
125 ##
126 ## color = ColorInterpolator(d, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc)
127 ##
128 ## if type=="line":
129 ## h = int(2.*math.hypot(*surface.get_size()))
130 ### bigSurf = pygame.Surface((d, h)).convert_alpha()
131 ## bigSurf = pygame.Surface((d, h), pygame.SRCALPHA)#.convert_alpha()
132 ### bigSurf = pygame.Surface((d, 1), pygame.SRCALPHA)#.convert_alpha()
133 ## bigSurf.lock()
134 ## bigSurf.fill((0,0,0,0))
135 ## bigSurf.set_colorkey((0,0,0,0))
136 ## for x in range(d):
137 ## pygame.draw.line(bigSurf, color.eval(x), (x,0), (x,h), 1)
138 ### for x in range(d):
139 ### bigSurf.set_at((x, 0), color.eval(x))
140 ### bigSurf = pygame.transform.scale(bigSurf, (d, h))
141 ##
142 ## bigSurf = pygame.transform.rotate(bigSurf, -angle) #rotozoom(bigSurf, -angle, 1)
143 ## bigSurf.set_colorkey((0,0,0, 0))
144 ## rect = bigSurf.get_rect()
145 ## srect = pygame.Rect(rect)
146 ## dx = d/2. * math.cos(math.radians(angle))
147 ## dy = d/2. * math.sin(math.radians(angle))
148 ## rect.center = startpoint
149 ## rect.move_ip(dx, dy)
150 ## bigSurf.unlock()
151 ##
152 ## elif type=="circle":
153 ## bigSurf = pygame.Surface((2*d, 2*d)).convert_alpha()
154 ## bigSurf.fill((0,0,0,0))
155 ## bigSurf.lock()
156 ## for x in range(d, 0, -1):
157 ## pygame.draw.circle(bigSurf, color.eval(x), (d,d), x)
158 ## bigSurf.unlock()
159 ## rect = bigSurf.get_rect()
160 ## srect = pygame.Rect(rect)
161 ## rect.center = (startpoint[0], startpoint[1])
162 ##
163 ## elif type=="rect":
164 ## bigSurf = pygame.Surface((2*d, 2*d)).convert_alpha()
165 ## bigSurf.fill((0,0,0,0))
166 ## c = bigSurf.get_rect().center
167 ## bigSurf.lock()
168 ## for x in range(d,-1,-1):
169 ## r = pygame.Rect(0,0,2*x,2*x)
170 ## r.center = c
171 ## pygame.draw.rect(bigSurf, color.eval(x), r)
172 ## bigSurf.unlock()
173 ## bigSurf = pygame.transform.rotozoom(bigSurf, -angle, 1)
174 ## bigSurf.set_colorkey((0,0,0, 0))
175 ##
176 ## rect = bigSurf.get_rect()
177 ## srect = pygame.Rect(rect)
178 ## rect.center = startpoint
179 ## else:
180 ## raise NameError("type must be one of \"line\",\"circle\" or \"rect\"")
181 ##
182 ## if mode is None:
183 ## surface.blit(bigSurf, rect, srect)
184 ## else:
185 ## if mode=="+":
186 ## cf = pygame.color.add
187 ## elif mode=="*":
188 ## cf = pygame.color.multiply
189 ## elif mode=="-":
190 ## cf = pygame.color.subtract
191 ## else:
192 ## raise NameError("type must be one of \"+\", \"*\", \"-\" or None")
193 ## irect = surface.get_clip().clip(rect)
194 ## surface.lock()
195 ## for x in range(irect.left, irect.left+irect.width):
196 ## for y in range(irect.top, irect.top+irect.height):
197 ## surface.set_at((x,y), cf(surface.get_at((x,y)), bigSurf.get_at((x-rect.left, y-rect.top)) ) )
198 ## surface.unlock()
199 ##
200 ## del bigSurf
201 ## char = pygame.Surface((d+1, 257))
202 ### char.fill((0,0,0))
203 ### ox = 0
204 ### oldcol = color.eval(0)
205 ### for x in range(d):
206 ### col = color.eval(x)
207 ### pygame.draw.line(char, (255,0,0), (x, 256-col[0]), (ox, 256-oldcol[0]))
208 ### pygame.draw.line(char, (0,255,0), (x, 256-col[1]), (ox, 256-oldcol[1]))
209 ### pygame.draw.line(char, (0,0,255), (x, 256-col[2]), (ox, 256-oldcol[2]))
210 ### pygame.draw.line(char, (255,255,255), (x, 256-col[3]), (ox, 256-oldcol[3]))
211 ### ox = x
212 ### oldcol = col
213 ###
214 ## return char
215
216
217
218
219 def vertical(size, startcolor, endcolor):
220 """
221 Draws a vertical linear gradient filling the entire surface. Returns a
222 surface filled with the gradient (numeric is only 2-3 times faster).
223 """
224 height = size[1]
225 bigSurf = pygame.Surface((1,height)).convert_alpha()
226 dd = 1.0/height
227 sr, sg, sb, sa = startcolor
228 er, eg, eb, ea = endcolor
229 rm = (er-sr)*dd
230 gm = (eg-sg)*dd
231 bm = (eb-sb)*dd
232 am = (ea-sa)*dd
233 for y in range(height):
234 bigSurf.set_at((0,y),
235 (int(sr + rm*y),
236 int(sg + gm*y),
237 int(sb + bm*y),
238 int(sa + am*y))
239 )
240 return pygame.transform.scale(bigSurf, size)
241
242
243 def horizontal(size, startcolor, endcolor):
244 """
245 Draws a horizontal linear gradient filling the entire surface. Returns a
246 surface filled with the gradient (numeric is only 2-3 times faster).
247 """
248 width = size[0]
249 bigSurf = pygame.Surface((width, 1)).convert_alpha()
250 dd = 1.0/width
251 sr, sg, sb, sa = startcolor
252 er, eg, eb, ea = endcolor
253 rm = (er-sr)*dd
254 gm = (eg-sg)*dd
255 bm = (eb-sb)*dd
256 am = (ea-sa)*dd
257 for y in range(width):
258 bigSurf.set_at((y,0),
259 (int(sr + rm*y),
260 int(sg + gm*y),
261 int(sb + bm*y),
262 int(sa + am*y))
263 )
264 return pygame.transform.scale(bigSurf, size)
265
266
267 def radial(radius, startcolor, endcolor):
268 """
269 Draws a linear raidal gradient on a square sized surface and returns
270 that surface.
271 """
272 bigSurf = pygame.Surface((2*radius, 2*radius)).convert_alpha()
273 bigSurf.fill((0,0,0,0))
274 dd = -1.0/radius
275 sr, sg, sb, sa = endcolor
276 er, eg, eb, ea = startcolor
277 rm = (er-sr)*dd
278 gm = (eg-sg)*dd
279 bm = (eb-sb)*dd
280 am = (ea-sa)*dd
281
282 draw_circle = pygame.draw.circle
283 for rad in range(radius, 0, -1):
284 draw_circle(bigSurf, (er + int(rm*rad),
285 eg + int(gm*rad),
286 eb + int(bm*rad),
287 ea + int(am*rad)), (radius, radius), rad)
288 return bigSurf
289
290 def squared(width, startcolor, endcolor):
291 """
292 Draws a linear sqared gradient on a square sized surface and returns
293 that surface.
294 """
295 bigSurf = pygame.Surface((width, width)).convert_alpha()
296 bigSurf.fill((0,0,0,0))
297 dd = -1.0/(width/2)
298 sr, sg, sb, sa = endcolor
299 er, eg, eb, ea = startcolor
300 rm = (er-sr)*dd
301 gm = (eg-sg)*dd
302 bm = (eb-sb)*dd
303 am = (ea-sa)*dd
304
305 draw_rect = pygame.draw.rect
306 for currentw in range((width/2), 0, -1):
307 pos = (width/2)-currentw
308 draw_rect(bigSurf, (er + int(rm*currentw),
309 eg + int(gm*currentw),
310 eb + int(bm*currentw),
311 ea + int(am*currentw)), pygame.Rect(pos, pos, 2*currentw, 2*currentw ))
312 return bigSurf
313
314
315 def vertical_func(size, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1)):
316 """
317 Draws a vertical linear gradient filling the entire surface. Returns a
318 surface filled with the gradient (numeric is only 2x faster).
319 Rfunc, Gfunc, Bfunc and Afunc are function like y = f(x). They define
320 how the color changes.
321 """
322 height = size[1]
323 bigSurf = pygame.Surface((1,height)).convert_alpha()
324 color = ColorInterpolator(height, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc)
325 for y in range(0, height):
326 bigSurf.set_at((0,y), color.eval(y+0.1))
327 return pygame.transform.scale(bigSurf, size)
328
329
330 def horizontal_func(size, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1)):
331 """
332 Draws a horizontal linear gradient filling the entire surface. Returns a
333 surface filled with the gradient (numeric is only 2x faster).
334 Rfunc, Gfunc, Bfunc and Afunc are function like y = f(x). They define
335 how the color changes.
336 """
337 width = size[0]
338 bigSurf = pygame.Surface((width, 1)).convert_alpha()
339 color = ColorInterpolator(width, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc)
340 for y in range(0, width):
341 bigSurf.set_at((y, 0), color.eval(y+0.1))
342 return pygame.transform.scale(bigSurf, size)
343
344 def radial_func(radius, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), colorkey=(0,0,0,0)):
345 """
346 Draws a linear raidal gradient on a square sized surface and returns
347 that surface.
348 """
349 bigSurf = pygame.Surface((2*radius, 2*radius)).convert_alpha()
350 if len(colorkey)==3:
351 colorkey += (0,)
352 bigSurf.fill(colorkey)
353 color = ColorInterpolator(radius, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc)
354 draw_circle = pygame.draw.circle
355 for rad in range(radius, 0, -1):
356 draw_circle(bigSurf, color.eval(rad), (radius, radius), rad)
357 return bigSurf
358
359 def radial_func_offset(radius, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), colorkey=(0,0,0,0), offset=(0,0)):
360 """
361 Draws a linear raidal gradient on a square sized surface and returns
362 that surface.
363 offset is the amount the center of the gradient is displaced of the center of the image.
364 Unfotunately this function ignores alpha.
365 """
366 bigSurf = pygame.Surface((2*radius, 2*radius))#.convert_alpha()
367
368 mask = pygame.Surface((2*radius, 2*radius), pygame.SRCALPHA)#.convert_alpha()
369 mask.fill(colorkey)
370 mask.set_colorkey((255,0,255))
371 pygame.draw.circle(mask, (255,0,255), (radius, radius), radius)
372
373 if len(colorkey)==3:
374 colorkey += (0,)
375 bigSurf.fill(colorkey)
376
377 color = ColorInterpolator(radius, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc)
378 draw_circle = pygame.draw.circle
379 radi = radius + int(math.hypot(offset[0], offset[1])+1)
380 for rad in range(radi, 0, -1):
381 draw_circle(bigSurf, color.eval(rad), (radius+offset[0], radius+offset[1]), rad)
382
383 bigSurf.blit(mask, (0,0))
384 bigSurf.set_colorkey(colorkey)
385 return bigSurf
386
387
388 def squared_func(width, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), offset=(0,0)):
389 """
390 Draws a linear sqared gradient on a square sized surface and returns
391 that surface.
392 """
393 bigSurf = pygame.Surface((width, width)).convert_alpha()
394 bigSurf.fill((0,0,0,0))
395 color = ColorInterpolator(width/2, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc)
396 draw_rect = pygame.draw.rect
397 widthh = width+2*int(max(abs(offset[0]),abs(offset[1])))
398 for currentw in range((widthh/2), 0, -1):
399 ## pos = (width/2)-currentw
400 rect = pygame.Rect(0, 0, 2*currentw, 2*currentw )
401 rect.center = (width/2+offset[0], width/2+offset[1])
402 draw_rect(bigSurf, color.eval(currentw), rect)
403 return bigSurf
404
405 def draw_gradient(surface, startpoint, endpoint, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), mode=0):
406 """
407 Instead of returning an Surface, this function draw it directy onto the
408 given Surface and returns the rect.
409 """
410 dx = endpoint[0]-startpoint[0]
411 dy = endpoint[1]-startpoint[1]
412 d = int(round(math.hypot(dx, dy)))
413 angle = math.degrees( math.atan2(dy, dx) )
414
415 h = int(2.*math.hypot(*surface.get_size()))
416
417 bigSurf = horizontal_func((d,h), startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc)
418
419 ## bigSurf = pygame.transform.rotate(bigSurf, -angle) #rotozoom(bigSurf, -angle, 1)
420 bigSurf = pygame.transform.rotozoom(bigSurf, -angle, 1)
421 ## bigSurf.set_colorkey((0,0,0, 0))
422 rect = bigSurf.get_rect()
423 srect = pygame.Rect(rect)
424 dx = d/2. * math.cos(math.radians(angle))
425 dy = d/2. * math.sin(math.radians(angle))
426 rect.center = startpoint
427 rect.move_ip(dx, dy)
428 if BLEND_MODES_AVAILABLE:
429 return surface.blit(bigSurf, rect, None, mode)
430 else:
431 return surface.blit(bigSurf, rect)
432
433
434 def draw_circle(surface, startpoint, endpoint, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), mode=0):
435 """
436 Instead of returning an Surface, this function draw it directy onto the
437 given Surface and returns the rect.
438 """
439 dx = endpoint[0]-startpoint[0]
440 dy = endpoint[1]-startpoint[1]
441 radius = int(round(math.hypot(dx, dy)))
442 pos = (startpoint[0]-radius, startpoint[1]-radius)
443 if BLEND_MODES_AVAILABLE:
444 return surface.blit(radial_func(radius, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc), pos, None, mode)
445 else:
446 return surface.blit(radial_func(radius, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc), pos)
447
448 def draw_squared(surface, startpoint, endpoint, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), mode=0):
449 """
450 Instead of returning an Surface, this function draw it directy onto the
451 given Surface and returns the rect.
452 """
453 dx = endpoint[0]-startpoint[0]
454 dy = endpoint[1]-startpoint[1]
455 angle = math.degrees( math.atan2(dy, dx) )
456 width = 2*int(round(math.hypot(dx, dy)))
457
458 bigSurf = squared_func(width, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc)
459
460 bigSurf = pygame.transform.rotozoom(bigSurf, -angle, 1)
461 ## bigSurf.set_colorkey((0,0,0, 0))
462 rect = bigSurf.get_rect()
463 rect.center = startpoint
464 if BLEND_MODES_AVAILABLE:
465 return surface.blit(bigSurf, rect, None, mode)
466 else:
467 return surface.blit(bigSurf, rect)
468
469
470 def chart(startpoint, endpoint, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), scale=None):
471 """
472 This returns a Surface where the change of the colors over the distance
473 (the width of the image) is showen as a line.
474 scale: a float, 1 is not scaling
475 """
476 dx = endpoint[0]-startpoint[0]
477 dy = endpoint[1]-startpoint[1]
478 distance = int(round(math.hypot(dx, dy)))
479 color = ColorInterpolator(distance, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc)
480 bigSurf = pygame.Surface((distance, 256))
481 bigSurf.fill((0,)*3)
482 oldcol = color.eval(0)
483 for x in range(distance):
484 r, g, b, a = color.eval(x)
485 pygame.draw.line(bigSurf, (255, 0, 0, 128), (x-1, oldcol[0]), (x, r))
486 pygame.draw.line(bigSurf, (0, 255, 0, 128), (x-1, oldcol[1]), (x, g))
487 pygame.draw.line(bigSurf, (0, 0, 255, 128), (x-1, oldcol[2]), (x, b))
488 pygame.draw.line(bigSurf, (255, 255, 255, 128), (x-1, oldcol[3]), (x, a))
489 oldcol = (r,g,b,a)
490 if scale:
491 ## return pygame.transform.scale(bigSurf, size)
492 return pygame.transform.rotozoom(bigSurf, 0, scale)
493 return pygame.transform.flip(bigSurf, 0, 1)
494 #------------------------------------------------------------------------------
495
496
497
498
499 def genericFxyGradient(surf, clip, color1, color2, func, intx, yint, zint=None):
500 """
501 genericFxyGradient(size, color1, color2,func, intx, yint, zint=None)
502
503 some sort of highfield drawer :-)
504
505 surf : surface to draw
506 clip : rect on surf to draw in
507 color1 : start color
508 color2 : end color
509 func : function z = func(x,y)
510 xint : interval in x direction where the function is evaluated
511 yint : interval in y direction where the function is evaluated
512 zint : if not none same as yint or xint, if None then the max and min value
513 of func is taken as z-interval
514
515 color = a*func(b*(x+c), d*(y+e))+f
516 """
517 # make shure that x1<x2 and y1<y2 and z1<z2
518 w,h = clip.size
519 x1 = min(intx)
520 x2 = max(intx)
521 y1 = min(yint)
522 y2 = max(yint)
523 if zint: # if user give us z intervall, then use it
524 z1 = min(zint)
525 z2 = max(zint)
526 else: # look for extrema of function (not best algorithme)
527 z1 = func(x1,y1)
528 z2 = z1
529 for i in range(w):
530 for j in range(h):
531 r = func(i,j)
532 z1 = min(z1, r)
533 z2 = max(z2, r)
534
535 x1 = float(x1)
536 x2 = float(x2)
537 y1 = float(y1)
538 y2 = float(y2)
539 z1 = float(z1)
540 z2 = float(z2)
541 if len(color1)==3:
542 color1 = list(color1)
543 color1.append(255)
544 if len(color2)==3:
545 color2 = list(color2)
546 color2.append(255)
547
548 # calculate streching and displacement variables
549 a = ((color2[0]-color1[0])/(z2-z1), \
550 (color2[1]-color1[1])/(z2-z1), \
551 (color2[2]-color1[2])/(z2-z1), \
552 (color2[3]-color1[3])/(z2-z1) ) # streching in z direction
553 b = (x2-x1)/float(w) # streching in x direction
554 d = (y2-y1)/float(h) # streching in y direction
555 f = ( color1[0]-a[0]*z1, \
556 color1[1]-a[1]*z1, \
557 color1[2]-a[2]*z1, \
558 color1[3]-a[3]*z1 )# z displacement
559 c = x1/b
560 e = y1/d
561
562 surff = pygame.surface.Surface((w,h)).convert_alpha()
563 # generate values
564 for i in range(h):
565 for j in range(w):
566 val = func(b*(j+c), d*(i+e))
567 #clip color
568 color = ( max(min(a[0]*val+f[0],255),0), \
569 max(min(a[1]*val+f[1],255),0), \
570 max(min(a[2]*val+f[2],255),0), \
571 max(min(a[3]*val+f[3],255),0) )
572 surff.set_at( (j,i), color )
573 surf.blit(surff, clip)
574
575
576