Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Added the python scripts for generating the precomputed textures.

  • Loading branch information...
commit 440bc25dc8a6a8211cc7a6ac373374f93a1bf0cd 1 parent 102b032
Jorge Jimenez authored

Showing 3 changed files with 732 additions and 0 deletions. Show diff stats Hide diff stats

  1. +3 0  .gitignore
  2. +602 0 Scripts/AreaTex.py
  3. +127 0 Scripts/SearchTex.py
3  .gitignore
@@ -13,3 +13,6 @@ Demo/DX10/Demo DX10.opensdf
13 13 Demo/DX10/Demo DX10.sdf
14 14 Demo/DX10/Demo DX10.suo
15 15 Demo/DX10/Demo.vcxproj.user
  16 +
  17 +Scripts/*.pyc
  18 +Scripts/*.tga
602 Scripts/AreaTex.py
... ... @@ -0,0 +1,602 @@
  1 +# -*- coding: UTF-8 -*-
  2 +#
  3 +# This texture allows to obtain the area for a certain pattern and distances
  4 +# to the left and to right of the line.
  5 +#
  6 +# Requires:
  7 +# - Python 2.7: http://www.python.org/
  8 +# - PIL: http://www.pythonware.com/products/pil/
  9 +
  10 +from PIL import Image
  11 +from multiprocessing import *
  12 +from math import *
  13 +from tempfile import *
  14 +import operator
  15 +
  16 +# Subsample offsets for orthogonal and diagonal areas:
  17 +SUBSAMPLE_OFFSETS_ORTHO = [0.0, -0.25, 0.25]
  18 +SUBSAMPLE_OFFSETS_DIAG = [0.0, -0.50, 0.50]
  19 +
  20 +# Texture sizes:
  21 +# (it's quite possible that this is not easily configurable)
  22 +SIZE_ORTHO = 16 # * 5 slots = 80
  23 +SIZE_DIAG = 20 # * 4 slots = 80
  24 +
  25 +# Number of samples for calculating areas in the diagonal textures:
  26 +# (diagonal areas are calculated using brute force sampling)
  27 +SAMPLES_DIAG = 30
  28 +
  29 +#------------------------------------------------------------------------------
  30 +# Misc Functions
  31 +
  32 +# Pixel layout for DirectX 9:
  33 +def la(v):
  34 + return v[0], v[0], v[0], v[1]
  35 +
  36 +# Pixel layout for DirectX 10:
  37 +def rgb(v):
  38 + return v[0], v[1], 0, 0
  39 +
  40 +# Coverts to 0..255 range:
  41 +def bytes(v):
  42 + return tuple([int(255.0 * a) for a in v])
  43 +
  44 +# Prints C++ code encoding a texture:
  45 +def cpp(image):
  46 + n = 0
  47 + last = 2 * (image.size[0] * image.size[1]) - 1
  48 +
  49 + print "static const unsigned char areaTexBytes[] = {"
  50 + print " ",
  51 + for y in range(image.size[1]):
  52 + for x in range(image.size[0]):
  53 + val = image.getpixel((x, y))
  54 +
  55 + if n < last: print "0x%02x," % val[0],
  56 + else: print "0x%02x" % val[0],
  57 + n += 1
  58 +
  59 + if n < last: print "0x%02x," % val[1],
  60 + else: print "0x%02x" % val[1],
  61 + n += 1
  62 +
  63 + if n % 12 == 0: print "\n ",
  64 + print
  65 + print "};"
  66 +
  67 +# A vector of two numbers:
  68 +class vec2(tuple):
  69 + def __new__(self, v1, v2):
  70 + return tuple.__new__(self, [v1, v2])
  71 + def __add__(self, other):
  72 + t1, t2 = map(operator.add, self, other)
  73 + return self.__class__(t1, t2)
  74 + def __mul__(self, other):
  75 + t1, t2 = map(operator.mul, self, other)
  76 + return self.__class__(t1, t2)
  77 + def __div__(self, other):
  78 + return self.__class__(self[0] / other, self[1] / other)
  79 + def __ne__(self, other):
  80 + return any([v1 != v2 for v1, v2 in zip(self, other)])
  81 +
  82 +#------------------------------------------------------------------------------
  83 +# Mapping Functions (for placing each pattern subtexture into its place)
  84 +
  85 +edgesortho = [ (0, 0), (3, 0), (0, 3), (3, 3), (1, 0), (4, 0), (1, 3), (4, 3),
  86 + (0, 1), (3, 1), (0, 4), (3, 4), (1, 1), (4, 1), (1, 4), (4, 4) ]
  87 +
  88 +edgesdiag = [ (0, 0), (1, 0), (0, 2), (1, 2), (2, 0), (3, 0), (2, 2), (3, 2),
  89 + (0, 1), (1, 1), (0, 3), (1, 3), (2, 1), (3, 1), (2, 3), (3, 3) ]
  90 +
  91 +#------------------------------------------------------------------------------
  92 +# Horizontal/Vertical Areas
  93 +
  94 +# Calculates the area for a given pattern and distances to the left and to the
  95 +# right, biased by an offset:
  96 +def areaortho(pattern, left, right, offset):
  97 +
  98 + # Calculates the area under the line p1->p2, for the pixel x..x+1:
  99 + def area(p1, p2, x):
  100 + d = p2[0] - p1[0], p2[1] - p1[1]
  101 + x1 = float(x)
  102 + x2 = x + 1.0
  103 + y1 = p1[1] + d[1] * (x1 - p1[0]) / d[0]
  104 + y2 = p1[1] + d[1] * (x2 - p1[0]) / d[0]
  105 +
  106 + inside = (x1 >= p1[0] and x1 < p2[0]) or (x2 > p1[0] and x2 <= p2[0])
  107 + if inside:
  108 + istrapezoid = (copysign(1.0, y1) == copysign(1.0, y2) or
  109 + abs(y1) < 1e-4 or abs(y2) < 1e-4)
  110 + if istrapezoid:
  111 + a = (y1 + y2) / 2
  112 + if a < 0.0:
  113 + return abs(a), 0.0
  114 + else:
  115 + return 0.0, abs(a)
  116 + else: # Then, we got two triangles:
  117 + x = -p1[1] * d[0] / d[1] + p1[0]
  118 + a1 = y1 * modf(x)[0] / 2.0 if x > p1[0] else 0.0
  119 + a2 = y2 * (1.0 - modf(x)[0]) / 2.0 if x < p2[0] else 0.0
  120 + a = a1 if abs(a1) > abs(a2) else -a2
  121 + if a < 0.0:
  122 + return abs(a1), abs(a2)
  123 + else:
  124 + return abs(a2), abs(a1)
  125 + else:
  126 + return 0.0, 0.0
  127 +
  128 + # o1 |
  129 + # .-------´
  130 + # o2 |
  131 + #
  132 + # <---d--->
  133 + d = left + right + 1
  134 +
  135 + o1 = 0.5 + offset
  136 + o2 = 0.5 + offset - 1.0
  137 +
  138 + if pattern == 0:
  139 + #
  140 + # ------
  141 + #
  142 + return 0.0, 0.0
  143 +
  144 + elif pattern == 1:
  145 + #
  146 + # .------
  147 + # |
  148 + #
  149 + # We only offset L patterns in the crossing edge side, to make it
  150 + # converge with the unfiltered pattern 0 (we don't want to filter the
  151 + # pattern 0 to avoid artifacts).
  152 + if left <= right:
  153 + return area(([0.0, o2]), ([d / 2.0, 0.0]), left)
  154 + else:
  155 + return 0.0, 0.0
  156 +
  157 + elif pattern == 2:
  158 + #
  159 + # ------.
  160 + # |
  161 + if left >= right:
  162 + return area(([d / 2.0, 0.0]), ([d, o2]), left)
  163 + else:
  164 + return 0.0, 0.0
  165 +
  166 + elif pattern == 3:
  167 + #
  168 + # .------.
  169 + # | |
  170 + a1 = area(([0.0, o2]), ([d / 2.0, 0.0]), left)
  171 + a2 = area(([d / 2.0, 0.0]), ([d, o2]), left)
  172 + return a1[0] + a2[0], a1[1] + a2[1], 0.0, 0.0
  173 +
  174 + elif pattern == 4:
  175 + # |
  176 + # `------
  177 + #
  178 + if left <= right:
  179 + return area(([0.0, o1]), ([d / 2.0, 0.0]), left)
  180 + else:
  181 + return 0.0, 0.0
  182 +
  183 + elif pattern == 5:
  184 + # |
  185 + # +------
  186 + # |
  187 + return 0.0, 0.0
  188 +
  189 + elif pattern == 6:
  190 + # |
  191 + # `------.
  192 + # |
  193 + #
  194 + # A problem of not offseting L patterns (see above), is that for certain
  195 + # max search distances, the pixels in the center of a Z pattern will
  196 + # detect the full Z pattern, while the pixels in the sides will detect a
  197 + # L pattern. To avoid discontinuities, we blend the full offsetted Z
  198 + # revectorization with partially offsetted L patterns.
  199 + if abs(offset) > 0.0:
  200 + a1 = vec2(*area(([0.0, o1]), ([d, o2]), left))
  201 + a2 = vec2(*area(([0.0, o1]), ([d / 2.0, 0.0]), left))
  202 + a2 += vec2(*area(([d / 2.0, 0.0]), ([d, o2]), left))
  203 + return (a1 + a2) / 2.0
  204 + else:
  205 + return area(([0.0, o1]), ([d, o2]), left)
  206 +
  207 + elif pattern == 7:
  208 + # |
  209 + # +------.
  210 + # | |
  211 + return area(([0.0, o1]), ([d, o2]), left)
  212 +
  213 + elif pattern == 8:
  214 + # |
  215 + # ------´
  216 + #
  217 + if left >= right:
  218 + return area(([d / 2.0, 0.0]), ([d, o1]), left)
  219 + else:
  220 + return 0.0, 0.0
  221 +
  222 + elif pattern == 9:
  223 + # |
  224 + # .------´
  225 + # |
  226 + if abs(offset) > 0.0:
  227 + a1 = vec2(*area(([0.0, o2]), ([d, o1]), left))
  228 + a2 = vec2(*area(([0.0, o2]), ([d / 2.0, 0.0]), left))
  229 + a2 += vec2(*area(([d / 2.0, 0.0]), ([d, o1]), left))
  230 + return (a1 + a2) / 2.0
  231 + else:
  232 + return area(([0.0, o2]), ([d, o1]), left)
  233 +
  234 + elif pattern == 10:
  235 + # |
  236 + # ------+
  237 + # |
  238 + return 0.0, 0.0
  239 +
  240 + elif pattern == 11:
  241 + # |
  242 + # .------+
  243 + # | |
  244 + return area(([0.0, o2]), ([d, o1]), left)
  245 +
  246 + elif pattern == 12:
  247 + # | |
  248 + # `------´
  249 + #
  250 + a1 = area(([0.0, o1]), ([d / 2.0, 0.0]), left)
  251 + a2 = area(([d / 2.0, 0.0]), ([d, o1]), left)
  252 + return a1[0] + a2[0], a1[1] + a2[1], 0.0, 0.0
  253 +
  254 + elif pattern == 13:
  255 + # | |
  256 + # +------´
  257 + # |
  258 + return area(([0.0, o2]), ([d, o1]), left)
  259 +
  260 + elif pattern == 14:
  261 + # | |
  262 + # `------+
  263 + # |
  264 + return area(([0.0, o1]), ([d, o2]), left)
  265 +
  266 + elif pattern == 15:
  267 + # | |
  268 + # +------+
  269 + # | |
  270 + return 0.0, 0.0
  271 +
  272 +#------------------------------------------------------------------------------
  273 +# Diagonal Areas
  274 +
  275 +# Calculates the area for a given pattern and distances to the left and to the
  276 +# right, biased by an offset:
  277 +def areadiag(pattern, left, right, offset):
  278 + # Calculates the area under the line p1->p2 for the pixel 'p' using brute
  279 + # force sampling:
  280 + # (quick and dirty solution, but it works)
  281 + def area1(p1, p2, p):
  282 + def inside(p):
  283 + if p1 != p2:
  284 + x, y = p
  285 + xm, ym = (p1 + p2) / 2.0
  286 + a = p2[1] - p1[1]
  287 + b = p1[0] - p2[0]
  288 + c = a * (x - xm) + b * (y - ym)
  289 + return c > 0
  290 + else:
  291 + return True
  292 +
  293 + a = 0.0
  294 + for x in range(SAMPLES_DIAG):
  295 + for y in range(SAMPLES_DIAG):
  296 + o = vec2(x, y) / float(SAMPLES_DIAG - 1)
  297 + a += inside(p + o)
  298 + return a / (SAMPLES_DIAG * SAMPLES_DIAG)
  299 +
  300 + # Calculates the area under the line p1->p2:
  301 + # (includes the pixel and its opposite)
  302 + def area(p1, p2, left, offset):
  303 + e1, e2 = edgesdiag[pattern]
  304 + p1 = p1 + vec2(0.0, offset) if e1 > 0 else p1
  305 + p2 = p2 + vec2(0.0, offset) if e2 > 0 else p2
  306 + a1 = area1(p1, p2, vec2(1.0, 0.0) + vec2(left, left))
  307 + a2 = area1(p1, p2, vec2(1.0, 1.0) + vec2(left, left))
  308 + return vec2(1.0 - a1, a2)
  309 +
  310 + d = left + right + 1
  311 +
  312 + # There is some Black Magic around diagonal area calculations. Unlike
  313 + # orthogonal patterns, the 'null' pattern (one without crossing edges) must be
  314 + # filtered, and the ends of both the 'null' and L patterns are not known: L
  315 + # and U patterns have different endings, and we don't know what is the
  316 + # adjacent pattern. So, what we do is calculate a blend of both possibilites.
  317 + #
  318 + # .-´
  319 + # .-´
  320 + # .-´
  321 + # .-´
  322 + # ´
  323 + #
  324 + if pattern == 0:
  325 + a1 = area(vec2(1.0, 1.0), vec2(1.0, 1.0) + vec2(d, d), left, offset) # 1st possibility
  326 + a2 = area(vec2(1.0, 0.0), vec2(1.0, 0.0) + vec2(d, d), left, offset) # 2nd possibility
  327 + return (a1 + a2) / 2.0 # Blend them
  328 +
  329 + #
  330 + # .-´
  331 + # .-´
  332 + # .-´
  333 + # .-´
  334 + # |
  335 + # |
  336 + elif pattern == 1:
  337 + a1 = area(vec2(1.0, 0.0), vec2(0.0, 0.0) + vec2(d, d), left, offset)
  338 + a2 = area(vec2(1.0, 0.0), vec2(1.0, 0.0) + vec2(d, d), left, offset)
  339 + return (a1 + a2) / 2.0
  340 +
  341 + #
  342 + # .----
  343 + # .-´
  344 + # .-´
  345 + # .-´
  346 + # ´
  347 + #
  348 + elif pattern == 2:
  349 + a1 = area(vec2(0.0, 0.0), vec2(1.0, 0.0) + vec2(d, d), left, offset)
  350 + a2 = area(vec2(1.0, 0.0), vec2(1.0, 0.0) + vec2(d, d), left, offset)
  351 + return (a1 + a2) / 2.0
  352 +
  353 + #
  354 + # .----
  355 + # .-´
  356 + # .-´
  357 + # .-´
  358 + # |
  359 + # |
  360 + elif pattern == 3:
  361 + return area(vec2(1.0, 0.0), vec2(1.0, 0.0) + vec2(d, d), left, offset)
  362 +
  363 + #
  364 + # .-´
  365 + # .-´
  366 + # .-´
  367 + # ----´
  368 + #
  369 + #
  370 + elif pattern == 4:
  371 + a1 = area(vec2(1.0, 1.0), vec2(0.0, 0.0) + vec2(d, d), left, offset)
  372 + a2 = area(vec2(1.0, 1.0), vec2(1.0, 0.0) + vec2(d, d), left, offset)
  373 + return (a1 + a2) / 2.0
  374 +
  375 + #
  376 + # .-´
  377 + # .-´
  378 + # .-´
  379 + # --.-´
  380 + # |
  381 + # |
  382 + elif pattern == 5:
  383 + a1 = area(vec2(1.0, 1.0), vec2(0.0, 0.0) + vec2(d, d), left, offset)
  384 + a2 = area(vec2(1.0, 0.0), vec2(1.0, 0.0) + vec2(d, d), left, offset)
  385 + return (a1 + a2) / 2.0
  386 +
  387 + #
  388 + # .----
  389 + # .-´
  390 + # .-´
  391 + # ----´
  392 + #
  393 + #
  394 + elif pattern == 6:
  395 + return area(vec2(1.0, 1.0), vec2(1.0, 0.0) + vec2(d, d), left, offset)
  396 +
  397 + #
  398 + # .----
  399 + # .-´
  400 + # .-´
  401 + # --.-´
  402 + # |
  403 + # |
  404 + elif pattern == 7:
  405 + a1 = area(vec2(1.0, 1.0), vec2(1.0, 0.0) + vec2(d, d), left, offset)
  406 + a2 = area(vec2(1.0, 0.0), vec2(1.0, 0.0) + vec2(d, d), left, offset)
  407 + return (a1 + a2) / 2.0
  408 +
  409 + # |
  410 + # |
  411 + # .-´
  412 + # .-´
  413 + # .-´
  414 + # ´
  415 + #
  416 + elif pattern == 8:
  417 + a1 = area(vec2(0.0, 0.0), vec2(1.0, 1.0) + vec2(d, d), left, offset)
  418 + a2 = area(vec2(1.0, 0.0), vec2(1.0, 1.0) + vec2(d, d), left, offset)
  419 + return (a1 + a2) / 2.0
  420 +
  421 + # |
  422 + # |
  423 + # .-´
  424 + # .-´
  425 + # .-´
  426 + # |
  427 + # |
  428 + elif pattern == 9:
  429 + return area(vec2(1.0, 0.0), vec2(1.0, 1.0) + vec2(d, d), left, offset)
  430 +
  431 + # |
  432 + # .----
  433 + # .-´
  434 + # .-´
  435 + # .-´
  436 + # ´
  437 + #
  438 + elif pattern == 10:
  439 + a1 = area(vec2(0.0, 0.0), vec2(1.0, 1.0) + vec2(d, d), left, offset)
  440 + a2 = area(vec2(1.0, 0.0), vec2(1.0, 0.0) + vec2(d, d), left, offset)
  441 + return (a1 + a2) / 2.0
  442 +
  443 + # |
  444 + # .----
  445 + # .-´
  446 + # .-´
  447 + # .-´
  448 + # |
  449 + # |
  450 + elif pattern == 11:
  451 + a1 = area(vec2(1.0, 0.0), vec2(1.0, 1.0) + vec2(d, d), left, offset)
  452 + a2 = area(vec2(1.0, 0.0), vec2(1.0, 0.0) + vec2(d, d), left, offset)
  453 + return (a1 + a2) / 2.0
  454 +
  455 + # |
  456 + # |
  457 + # .-´
  458 + # .-´
  459 + # ----´
  460 + #
  461 + #
  462 + elif pattern == 12:
  463 + return area(vec2(1.0, 1.0), vec2(1.0, 1.0) + vec2(d, d), left, offset)
  464 +
  465 + # |
  466 + # |
  467 + # .-´
  468 + # .-´
  469 + # --.-´
  470 + # |
  471 + # |
  472 + elif pattern == 13:
  473 + a1 = area(vec2(1.0, 1.0), vec2(1.0, 1.0) + vec2(d, d), left, offset)
  474 + a2 = area(vec2(1.0, 0.0), vec2(1.0, 1.0) + vec2(d, d), left, offset)
  475 + return (a1 + a2) / 2.0
  476 +
  477 + # |
  478 + # .----
  479 + # .-´
  480 + # .-´
  481 + # ----´
  482 + #
  483 + #
  484 + elif pattern == 14:
  485 + a1 = area(vec2(1.0, 1.0), vec2(1.0, 1.0) + vec2(d, d), left, offset)
  486 + a2 = area(vec2(1.0, 1.0), vec2(1.0, 0.0) + vec2(d, d), left, offset)
  487 + return (a1 + a2) / 2.0
  488 +
  489 + # |
  490 + # .----
  491 + # .-´
  492 + # .-´
  493 + # --.-´
  494 + # |
  495 + # |
  496 + elif pattern == 15:
  497 + a1 = area(vec2(1.0, 1.0), vec2(1.0, 1.0) + vec2(d, d), left, offset)
  498 + a2 = area(vec2(1.0, 0.0), vec2(1.0, 0.0) + vec2(d, d), left, offset)
  499 + return (a1 + a2) / 2.0
  500 +
  501 +#------------------------------------------------------------------------------
  502 +# Main Functions
  503 +
  504 +# Assembles 2D pattern subtextures into a 4D texture:
  505 +def assemble(tex4d, files, edges, pos, size, compress):
  506 +
  507 + # Open pattern textures created by the workers:
  508 + areas = [Image.open(file.name) for file in files]
  509 +
  510 + # Puts a pattern subtexture into its position in the 4D texture:
  511 + def putpattern(pattern):
  512 + for left in range(size):
  513 + for right in range(size):
  514 + p = vec2(left, right)
  515 + pp = pos + p + vec2(size, size) * vec2(*edges[pattern])
  516 + tex4d.putpixel(pp, rgb(areas[pattern].getpixel(compress(p))))
  517 +
  518 + # Put each pattern into its place:
  519 + for i in range(16):
  520 + putpattern(i)
  521 +
  522 + # Save the texture:
  523 + tex4d.save("AreaTexDX10.tga")
  524 +
  525 +# Creates a 2D orthogonal pattern subtexture:
  526 +def tex2dortho(args):
  527 + pattern, path, offset = args
  528 + size = (SIZE_ORTHO - 1)**2 + 1
  529 + tex2d = Image.new("RGBA", (size, size))
  530 + for y in range(size):
  531 + for x in range(size):
  532 + p = areaortho(pattern, x, y, offset)
  533 + p = p[0], p[1], 0.0, 0.0
  534 + tex2d.putpixel((x, y), bytes(p))
  535 + tex2d.save(path, "TGA")
  536 +
  537 +# Creates a 2D diagonal pattern subtexture:
  538 +def tex2ddiag(args):
  539 + pattern, path, offset = args
  540 + tex2d = Image.new("RGBA", (SIZE_DIAG, SIZE_DIAG))
  541 + for y in range(SIZE_DIAG):
  542 + for x in range(SIZE_DIAG):
  543 + p = areadiag(pattern, x, y, offset)
  544 + p = p[0], p[1], 0.0, 0.0
  545 + tex2d.putpixel((x, y), bytes(p))
  546 + tex2d.save(path, "TGA")
  547 +
  548 +# Calculate the orthogonal patterns 4D texture for a given offset:
  549 +def tex4dortho(tex4d, files, y, offset):
  550 +
  551 + # Build each pattern subtexture concurrently:
  552 + cores = max(1, cpu_count() - 1)
  553 + pool = Pool(processes=cores)
  554 + pool.map(tex2dortho, [(i, files[i].name, offset) for i in range(16)])
  555 +
  556 + # Then, assemble the 4D texture:
  557 + # (for orthogonal patterns, we compress the texture coordinates quadratically,
  558 + # to be able to reach longer distances for a given texture size)
  559 + pos = vec2(0, 5 * SIZE_ORTHO * y)
  560 + assemble(tex4d, files, edgesortho, pos, SIZE_ORTHO, lambda v: (v[0]**2, v[1]**2))
  561 +
  562 +# Calculate the diagonal patterns 4D texture for a given offset:
  563 +def tex4ddiag(tex4d, files, y, offset):
  564 +
  565 + # Build each pattern subtexture concurrently:
  566 + cores = max(1, cpu_count() - 1)
  567 + pool = Pool(processes=cores)
  568 + pool.map(tex2ddiag, [(i, files[i].name, offset) for i in range(16)])
  569 +
  570 + # Then, assemble the 4D texture:
  571 + pos = vec2(5 * SIZE_ORTHO, 4 * SIZE_DIAG * y)
  572 + assemble(tex4d, files, edgesdiag, pos, SIZE_DIAG, lambda v: v);
  573 +
  574 +#------------------------------------------------------------------------------
  575 +# Entry Point
  576 +
  577 +# Copy the texture to a DirectX 9 friendly format:
  578 +def dx9(tex4d):
  579 + tex4d_dx9 = Image.new("RGBA", tex4d.size)
  580 + for x in range(tex4d.size[0]):
  581 + for y in range(tex4d.size[1]):
  582 + p = tex4d.getpixel((x, y))
  583 + tex4d_dx9.putpixel((x, y), la(p))
  584 + tex4d_dx9.save("AreaTexDX9.tga")
  585 +
  586 +if __name__ == '__main__':
  587 + # Create temporal textures:
  588 + files = [NamedTemporaryFile(delete=False) for i in range(16)]
  589 +
  590 + # Create AreaTexDX10:
  591 + tex4d = Image.new("RGBA", (2 * 5 * SIZE_ORTHO, len(SUBSAMPLE_OFFSETS_ORTHO) * 5 * SIZE_ORTHO))
  592 + for y, offset in enumerate(SUBSAMPLE_OFFSETS_ORTHO):
  593 + tex4dortho(tex4d, files, y, offset)
  594 + for y, offset in enumerate(SUBSAMPLE_OFFSETS_DIAG):
  595 + tex4ddiag(tex4d, files, y, offset)
  596 + tex4d.save("AreaTexDX10.tga")
  597 +
  598 + # Convert to DX9 (AreaTexDX9):
  599 + dx9(tex4d)
  600 +
  601 + # Output C++ code:
  602 + cpp(tex4d)
127 Scripts/SearchTex.py
... ... @@ -0,0 +1,127 @@
  1 +# -*- coding: UTF-8 -*-
  2 +#
  3 +# This texture allows to know how many pixels we must advance in the last step
  4 +# of our line search algorithm, with a single fetch.
  5 +#
  6 +# Requires:
  7 +# - Python 2.7: http://www.python.org/
  8 +# - PIL: http://www.pythonware.com/products/pil/
  9 +
  10 +from PIL import Image
  11 +
  12 +# Interpolates between two values:
  13 +def lerp(v0, v1, p):
  14 + return v0 + (v1 - v0) * p
  15 +
  16 +# Calculates the bilinear fetch for a certain edge combination:
  17 +def bilinear(e):
  18 + # e[0] e[1]
  19 + #
  20 + # x <-------- Sample position: (-0.25,-0.125)
  21 + # e[2] e[3] <--- Current pixel [3]: ( 0.0, 0.0 )
  22 + a = lerp(e[0], e[1], 1.0 - 0.25)
  23 + b = lerp(e[2], e[3], 1.0 - 0.25)
  24 + return lerp(a, b, 1.0 - 0.125)
  25 +
  26 +# This dict returns which edges are active for a certain bilinear fetch:
  27 +# (it's the reverse lookup of the bilinear function)
  28 +edge = {
  29 + bilinear([0, 0, 0, 0]): [0, 0, 0, 0],
  30 + bilinear([0, 0, 0, 1]): [0, 0, 0, 1],
  31 + bilinear([0, 0, 1, 0]): [0, 0, 1, 0],
  32 + bilinear([0, 0, 1, 1]): [0, 0, 1, 1],
  33 +
  34 + bilinear([0, 1, 0, 0]): [0, 1, 0, 0],
  35 + bilinear([0, 1, 0, 1]): [0, 1, 0, 1],
  36 + bilinear([0, 1, 1, 0]): [0, 1, 1, 0],
  37 + bilinear([0, 1, 1, 1]): [0, 1, 1, 1],
  38 +
  39 + bilinear([1, 0, 0, 0]): [1, 0, 0, 0],
  40 + bilinear([1, 0, 0, 1]): [1, 0, 0, 1],
  41 + bilinear([1, 0, 1, 0]): [1, 0, 1, 0],
  42 + bilinear([1, 0, 1, 1]): [1, 0, 1, 1],
  43 +
  44 + bilinear([1, 1, 0, 0]): [1, 1, 0, 0],
  45 + bilinear([1, 1, 0, 1]): [1, 1, 0, 1],
  46 + bilinear([1, 1, 1, 0]): [1, 1, 1, 0],
  47 + bilinear([1, 1, 1, 1]): [1, 1, 1, 1],
  48 +}
  49 +
  50 +# Delta distance to add in the last step of searches to the left:
  51 +def deltaLeft(left, top):
  52 + d = 0
  53 +
  54 + # If there is an edge, continue:
  55 + if top[3] == 1:
  56 + d += 1
  57 +
  58 + # If we previously found an edge, there is another edge and no crossing
  59 + # edges, continue:
  60 + if d == 1 and top[2] == 1 and left[1] != 1 and left[3] != 1:
  61 + d += 1
  62 +
  63 + return d
  64 +
  65 +# Delta distance to add in the last step of searches to the right:
  66 +def deltaRight(left, top):
  67 + d = 0
  68 +
  69 + # If there is an edge, and no crossing edges, continue:
  70 + if top[3] == 1 and left[1] != 1 and left[3] != 1:
  71 + d += 1
  72 +
  73 + # If we previously found an edge, there is another edge and no crossing
  74 + # edges, continue:
  75 + if d == 1 and top[2] == 1 and left[0] != 1 and left[2] != 1:
  76 + d += 1
  77 +
  78 + return d
  79 +
  80 +# Prints the edges in a readable form:
  81 +def debug(dir, texcoord, val, left, top):
  82 + print dir, texcoord, val
  83 + print "|%s %s| |%s %s|" % (left[0], left[1], top[0], top[1])
  84 + print "|%s %s| |%s %s|" % (left[2], left[3], top[2], top[3])
  85 + print
  86 +
  87 +# Prints C++ code encoding a texture:
  88 +def cpp(image):
  89 + n = 0
  90 + print "static const unsigned char searchTexBytes[] = {"
  91 + print " ",
  92 + for y in range(image.size[1]):
  93 + for x in range(image.size[0]):
  94 + val = image.getpixel((x, y))[0]
  95 + if n < 66 * 33 - 1: print "0x%02x," % val,
  96 + else: print "0x%02x" % val,
  97 + n += 1
  98 + if n % 12 == 0: print "\n ",
  99 + print
  100 + print "};"
  101 +
  102 +# Calculate delta distances to the left:
  103 +image = Image.new("RGB", (66, 33))
  104 +for x in range(33):
  105 + for y in range(33):
  106 + texcoord = 0.03125 * x, 0.03125 * y
  107 + if edge.has_key(texcoord[0]) and edge.has_key(texcoord[1]):
  108 + edges = edge[texcoord[0]], edge[texcoord[1]]
  109 + val = deltaLeft(*edges)
  110 + image.putpixel((x, y), (val, val, val))
  111 + #debug("left: ", texcoord, val, *edges)
  112 +
  113 +# Calculate delta distances to the right:
  114 +for x in range(33):
  115 + for y in range(33):
  116 + texcoord = 0.03125 * x, 0.03125 * y
  117 + if edge.has_key(texcoord[0]) and edge.has_key(texcoord[1]):
  118 + edges = edge[texcoord[0]], edge[texcoord[1]]
  119 + val = deltaRight(*edges)
  120 + image.putpixel((33 + x, y), (val, val, val))
  121 + #debug("right: ", texcoord, val, *edges)
  122 +
  123 +# Save the texture:
  124 +image.save("SearchTex.tga")
  125 +
  126 +# And print the C++ code:
  127 +cpp(image)

0 comments on commit 440bc25

Please sign in to comment.
Something went wrong with that request. Please try again.