gradients.py (11188B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\client\script\graphics\resourceConstructors\gradients.py 2 import blue 3 import trinity 4 import struct 5 import math 6 from functools import reduce 7 8 def isVector(a): 9 return hasattr(a, '__iter__') 10 11 12 def Lerp(a, b, u): 13 14 def LerpValue(x, y): 15 return x * (1.0 - u) + y * u 16 17 if not isVector(a): 18 return LerpValue(a, b) 19 else: 20 return map(LerpValue, a, b) 21 22 23 def Cosine(a, b, u): 24 25 def CosValue(x, y): 26 cosU = math.cos(u * math.pi * 0.5) 27 return x * cosU * cosU + y * (1.0 - cosU * cosU) 28 29 if not isVector(a): 30 return CosValue(a, b) 31 else: 32 return map(CosValue, a, b) 33 34 35 def v_op(a, b, op): 36 if isVector(a): 37 if isVector(b): 38 return map(op, a, b) 39 return map(lambda x: op(x, b), a) 40 elif isVector(b): 41 return map(lambda x: op(a, x), b) 42 else: 43 return op(a, b) 44 45 46 def v_add(a, b): 47 return v_op(a, b, lambda x, y: x + y) 48 49 50 def v_sub(a, b): 51 return v_op(a, b, lambda x, y: x - y) 52 53 54 def v_mul(a, b): 55 return v_op(a, b, lambda x, y: x * y) 56 57 58 def v_div(a, b): 59 return v_op(a, b, lambda x, y: x / y) 60 61 62 def v_dot(a, b): 63 return reduce(lambda x, y: x + y, v_mul(a, b)) 64 65 66 def v_len(a): 67 if isVector(a): 68 return math.sqrt(v_dot(a, a)) 69 return a 70 71 72 def v_unit(a): 73 l = v_len(a) 74 if -1e-05 < abs(l) < 1e-05: 75 l = 1.0 76 return v_div(a, l) 77 78 79 def Bezier(a, b, c, d, u): 80 inVal = v_sub(b, a) 81 tweenVal = v_sub(c, b) 82 outVal = v_sub(d, c) 83 tanIn = v_mul(v_add(inVal, tweenVal), 0.5) 84 tanOut = v_mul(v_add(tweenVal, outVal), 0.5) 85 b1 = v_add(b, v_mul(tanIn, 0.33)) 86 c1 = v_sub(c, v_mul(tanOut, 0.33)) 87 v = 1.0 - u 88 return v_add(v_add(v_mul(b, math.pow(v, 3)), v_mul(b1, u * 3.0 * math.pow(v, 2))), v_add(v_mul(c1, v * 3.0 * math.pow(u, 2)), v_mul(c, math.pow(u, 3)))) 89 90 91 def SampleGradient(divs, points, x, interpMode = 'linear'): 92 if x < divs[0]: 93 return points[0] 94 elif x >= divs[-1]: 95 return points[-1] 96 n = len(points) 97 minX, maxX = (0, 1) 98 index = 0 99 for i, xPrev, xNext in zip(range(n), divs, divs[1:]): 100 if xPrev <= x < xNext: 101 minX = xPrev 102 maxX = xNext 103 index = i 104 break 105 minX = xPrev 106 index = 1 107 108 u = (x - minX) / (maxX - minX) if maxX != minX else 0.0 109 110 def fetch(i): 111 return points[min(n - 1, max(0, i))] 112 113 if interpMode == 'bezier': 114 return Bezier(fetch(index - 1), fetch(index), fetch(index + 1), fetch(index + 2), u) 115 elif interpMode == 'cosine': 116 return Cosine(fetch(index), fetch(index + 1), u) 117 else: 118 return Lerp(fetch(index), fetch(index + 1), u) 119 120 121 def ColourByteClamp(r, g, b, a): 122 r = int(min(255, max(0, r * 255))) 123 g = int(min(255, max(0, g * 255))) 124 b = int(min(255, max(0, b * 255))) 125 a = int(min(255, max(0, a * 255))) 126 return (r, 127 g, 128 b, 129 a) 130 131 132 def Gradient(paramString): 133 params = {'rgbInterp': 'linear', 134 'rgbDivs': [0.0, 135 0.33, 136 0.66, 137 1.0], 138 'rgbPoints': [(0, 0, 1), 139 (0, 1, 0), 140 (1, 0, 0), 141 (0, 0.5, 0.5)], 142 'alphaInterp': 'linear', 143 'alphaDivs': [0, 1], 144 'alphaPoints': [1.0, 1.0], 145 'textureSize': 256} 146 if paramString.endswith('}atlas'): 147 paramString = paramString[:-5] 148 try: 149 if paramString: 150 params.update(eval(paramString)) 151 except: 152 pass 153 154 textureSize = params['textureSize'] 155 texture = trinity.textureAtlasMan.atlases[0].CreateTexture(textureSize, 1) 156 locked = texture.LockBufferAndMargin(None, False) 157 if locked: 158 buf = locked[0] 159 width = locked[1] 160 height = locked[2] 161 pitch = locked[3] 162 margin = locked[4] 163 try: 164 for y in range(height): 165 for xi in range(width): 166 x = (xi - margin) / float(textureSize - 1) 167 x = max(0.0, min(1.0, x)) 168 r, g, b = SampleGradient(params['rgbDivs'], params['rgbPoints'], x, params['rgbInterp']) 169 a = SampleGradient(params['alphaDivs'], params['alphaPoints'], x, params['alphaInterp']) 170 r, g, b, a = ColourByteClamp(r, g, b, a) 171 buf[y * pitch + xi * 4 + 0] = struct.pack('B', b) 172 buf[y * pitch + xi * 4 + 1] = struct.pack('B', g) 173 buf[y * pitch + xi * 4 + 2] = struct.pack('B', r) 174 buf[y * pitch + xi * 4 + 3] = struct.pack('B', a) 175 176 finally: 177 texture.UnlockBuffer() 178 179 return texture 180 181 182 def GradientRadial(paramString): 183 params = {'toCorners': True, 184 'rgbInterp': 'linear', 185 'rgbDivs': [0.0, 186 0.33, 187 0.66, 188 1.0], 189 'rgbPoints': [(0, 0, 1), 190 (0, 1, 0), 191 (1, 0, 0), 192 (0, 0.5, 0.5)], 193 'alphaInterp': 'linear', 194 'alphaDivs': [0, 1], 195 'alphaPoints': [1.0, 1.0], 196 'textureSize': (256, 256)} 197 if paramString.endswith('}atlas'): 198 paramString = paramString[:-5] 199 try: 200 if paramString: 201 params.update(eval(paramString)) 202 except: 203 pass 204 205 textureSize = params['textureSize'] 206 if not hasattr(textureSize, '__iter__'): 207 textureSize = (textureSize, textureSize) 208 texture = trinity.textureAtlasMan.atlases[0].CreateTexture(textureSize[0], textureSize[1]) 209 locked = texture.LockBufferAndMargin(None, False) 210 if locked: 211 buf = locked[0] 212 width = locked[1] 213 height = locked[2] 214 pitch = locked[3] 215 margin = locked[4] 216 try: 217 for yi in range(height): 218 y = 2.0 * ((yi - margin) / float(height - 1) - 0.5) 219 y = max(-1.0, min(y, 1.0)) 220 for xi in range(width): 221 x = 2.0 * ((xi - margin) / float(width - 1) - 0.5) 222 x = max(-1.0, min(x, 1.0)) 223 rad = math.sqrt(x * x + y * y) 224 if params['toCorners']: 225 rad /= 1.41421 226 r, g, b = SampleGradient(params['rgbDivs'], params['rgbPoints'], rad, params['rgbInterp']) 227 a = SampleGradient(params['alphaDivs'], params['alphaPoints'], rad, params['alphaInterp']) 228 r, g, b, a = ColourByteClamp(r, g, b, a) 229 buf[yi * pitch + xi * 4 + 0] = struct.pack('B', b) 230 buf[yi * pitch + xi * 4 + 1] = struct.pack('B', g) 231 buf[yi * pitch + xi * 4 + 2] = struct.pack('B', r) 232 buf[yi * pitch + xi * 4 + 3] = struct.pack('B', a) 233 234 finally: 235 texture.UnlockBuffer() 236 237 return texture 238 239 240 def SampleGradient2D(subdivsX, subdivsY, pointsX, pointsY, x, y, interpMode = 'linear'): 241 indexX, indexY = (0, 0) 242 minX, minY, maxX, maxY = (0, 0, 1, 1) 243 found = False 244 for idx, xCurr, xNext in zip(range(len(subdivsX)), subdivsX, subdivsX[1:]): 245 if xCurr <= x < xNext: 246 indexX = idx 247 minX = xCurr 248 maxX = xNext 249 found = True 250 break 251 252 if found: 253 u = (x - minX) / (maxX - minX) 254 else: 255 indexX = len(pointsX) - 1 256 u = 1 257 found = False 258 for idx, yCurr, yNext in zip(range(len(subdivsY)), subdivsY, subdivsY[1:]): 259 if yCurr <= y < yNext: 260 indexY = idx 261 minY = yCurr 262 maxY = yNext 263 found = True 264 break 265 266 if found: 267 v = (y - minY) / (maxY - minY) 268 else: 269 indexY = len(pointsY) - 1 270 v = 1 271 272 def fetch(i, points): 273 i = min(len(points) - 1, max(0, i)) 274 return points[i] 275 276 if interpMode == 'bezier': 277 colorX = Bezier(fetch(indexX - 1, pointsX), fetch(indexX, pointsX), fetch(indexX + 1, pointsX), fetch(indexX + 2, pointsX), u) 278 colorY = Bezier(fetch(indexY - 1, pointsY), fetch(indexY, pointsY), fetch(indexY + 1, pointsY), fetch(indexY + 2, pointsY), v) 279 elif interpMode == 'cosine': 280 colorX = Cosine(fetch(indexX, pointsX), fetch(indexX + 1, pointsX), u) 281 colorY = Cosine(fetch(indexY, pointsY), fetch(indexY + 1, pointsY), v) 282 else: 283 colorX = Lerp(fetch(indexX, pointsX), fetch(indexX + 1, pointsX), u) 284 colorY = Lerp(fetch(indexY, pointsY), fetch(indexY + 1, pointsY), v) 285 if isVector(colorX): 286 color = (colorX[0] * colorY[0], colorX[1] * colorY[1], colorX[2] * colorY[2]) 287 else: 288 color = colorX * colorY 289 return color 290 291 292 def Gradient2D(paramString): 293 params = {'rgbHorizontal': [0, 1], 294 'rgbVertical': [0, 1], 295 'rgbDataHorizontal': [(1, 1, 1), (0, 0, 0)], 296 'rgbDataVertical': [(1, 1, 1), (0, 0, 0)], 297 'alphaHorizontal': [0, 1], 298 'alphaVertical': [0, 1], 299 'alphaDataHorizontal': [1, 0], 300 'alphaDataVertical': [1, 0], 301 'textureSize': (256, 256), 302 'rgbInterp': 'linear', 303 'alphaInterp': 'linear'} 304 if paramString.endswith('}atlas'): 305 paramString = paramString[:-5] 306 try: 307 if paramString: 308 params.update(eval(paramString)) 309 except: 310 pass 311 312 textureSize = params['textureSize'] 313 if not hasattr(textureSize, '__iter__'): 314 textureSize = (textureSize, textureSize) 315 texture = trinity.textureAtlasMan.atlases[0].CreateTexture(textureSize[0], textureSize[1]) 316 locked = texture.LockBufferAndMargin(None, False) 317 if locked: 318 buf = locked[0] 319 width = locked[1] 320 height = locked[2] 321 pitch = locked[3] 322 margin = locked[4] 323 try: 324 rgbHorizontal = params['rgbHorizontal'] 325 rgbVertical = params['rgbVertical'] 326 rgbDataHorizontal = params['rgbDataHorizontal'] 327 rgbDataVertical = params['rgbDataVertical'] 328 rgbInterp = params['rgbInterp'] 329 alphaHorizontal = params['alphaHorizontal'] 330 alphaVertical = params['alphaVertical'] 331 alphaDataHorizontal = params['alphaDataHorizontal'] 332 alphaDataVertical = params['alphaDataVertical'] 333 alphaInterp = params['alphaInterp'] 334 for yi in xrange(height): 335 y = (yi - margin) / float(textureSize[1] - 1) 336 y = max(0.0, min(y, 1.0)) 337 for xi in xrange(width): 338 x = (xi - margin) / float(textureSize[0] - 1) 339 x = max(0.0, min(x, 1.0)) 340 r, g, b = SampleGradient2D(rgbHorizontal, rgbVertical, rgbDataHorizontal, rgbDataVertical, x, y, rgbInterp) 341 a = SampleGradient2D(alphaHorizontal, alphaVertical, alphaDataHorizontal, alphaDataVertical, x, y, alphaInterp) 342 r, g, b, a = ColourByteClamp(r, g, b, a) 343 buf[yi * pitch + xi * 4 + 0] = struct.pack('B', b) 344 buf[yi * pitch + xi * 4 + 1] = struct.pack('B', g) 345 buf[yi * pitch + xi * 4 + 2] = struct.pack('B', r) 346 buf[yi * pitch + xi * 4 + 3] = struct.pack('B', a) 347 348 finally: 349 texture.UnlockBuffer() 350 351 return texture