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