Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

Golly Python script to output meta-life animation

By: a guest on May 13th, 2012  |  syntax: Python  |  size: 3.88 KB  |  views: 546  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. from __future__ import division
  2.  
  3. import golly as g
  4. from math import floor, ceil, log
  5. from os import system, unlink
  6.  
  7. resx, resy = 1920, 1080 # woo 1080p
  8. osa = 3 # 3x3 oversampling
  9. framerate = 30
  10. #resx, resy = 160, 90
  11. #osa = 2
  12. #framerate = 5
  13. framecount = framerate*90 # 90 seconds long seems reasonable
  14. outputmask = "/home/phlip/lifeanim/%08d.%s" # outputmask % (frameno, extension)
  15. cellsize = osa # make cells larger by a full pixel in each direction, to cut down on moire effects
  16.  
  17. centrex, centrey = 114500, 4365
  18. initw, inith = 96, 54
  19. finalscale = 11.0 # so that we scale out by a factor of 2**11 over the animation
  20. finalratefact = 17.0  # so that we speed up by a factor of 2**17 over the animation (the metapixels animate at about 2**-15 of the speed)
  21. initrate = 1 # initially approx one step per second
  22. initrateadj = initrate * framecount/framerate/(finalratefact*log(2)) # magic calculation to make it so that d/dt of setframe(t) at 0 is initrate
  23.  
  24. curstep = 0
  25. def setstep(n):
  26.         global curstep
  27.         n = int(round(n))
  28.         if n < curstep:
  29.                 return
  30.         g.run(n - curstep)
  31.         curstep = n
  32.  
  33. def setframe(t):
  34.         setstep(initrateadj * 2**(finalratefact * t))
  35.  
  36. class Rect:
  37.         def __init__(self, l, t, w, h):
  38.                 self.left = l
  39.                 self.top = t
  40.                 self.width = w
  41.                 self.height = h
  42.  
  43. def calcscale(t):
  44.         if t < 3*framerate/framecount:
  45.                 t = 3*framerate/framecount # don't zoom out for the first 3 seconds
  46.         w = initw * 2**(finalscale * t)
  47.         h = inith * 2**(finalscale * t)
  48.         l = centrex - w / 2.0
  49.         t = centrey - h / 2.0
  50.         return Rect(l,t,w,h)
  51.  
  52. def clamp(x,minim,maxim):
  53.         if x < minim:
  54.                 return minim
  55.         if x > maxim:
  56.                 return maxim
  57.         return x
  58.  
  59. def doframe(n):
  60.         t = n/framecount
  61.         setframe(t)
  62.         sc = calcscale(t)
  63.         # get all the cells in the view area
  64.         cells = g.getcells([sc.left, sc.top, sc.width, sc.height])
  65.         # generate a large image (for oversampling)
  66.         output = [[0 for x in xrange(resx * osa)] for y in xrange(resy * osa)]
  67.         # draw all the live cells on the image
  68.         for i in xrange(0, len(cells), 2):
  69.                 cellx, celly = cells[i:i+2]
  70.                 # find the bounds of this cell on the screen
  71.                 xmin = int(floor(((cellx - sc.left) / sc.width) * resx * osa))
  72.                 xmax = int(floor(((cellx - sc.left + 1) / sc.width) * resx * osa)) + 1
  73.                 ymin = int(floor(((celly - sc.top) / sc.height) * resy * osa))
  74.                 ymax = int(floor(((celly - sc.top + 1) / sc.height) * resy * osa)) + 1
  75.                 # make the cells slightly larger and overlapping, to reduce the moire effects
  76.                 xmin -= cellsize
  77.                 ymin -= cellsize
  78.                 xmax += cellsize
  79.                 ymax += cellsize
  80.                 # draw the cell on the image
  81.                 xmin = clamp(xmin, 0, resx * osa)
  82.                 xmax = clamp(xmax, 0, resx * osa)
  83.                 ymin = clamp(ymin, 0, resy * osa)
  84.                 ymax = clamp(ymax, 0, resy * osa)
  85.                 for y in xrange(ymin, ymax):
  86.                         output[y][xmin:xmax] = [1] * (xmax - xmin)
  87.         # Scale down the oversampled image to the target size, by averaging
  88.         if osa > 1:
  89.                 output = [[sum(output[i][j] for i in xrange(y*osa,(y+1)*osa) for j in xrange(x*osa,(x+1)*osa)) for x in xrange(resx)] for y in xrange(resy)]
  90.         # Save the image as a PGM, and then use ImageMagick to convert it to PNG
  91.         with open(outputmask % (n, "pgm"), 'w') as fp:
  92.                 fp.write("P2\n%d %d\n%d\n" % (resx, resy, osa*osa))
  93.                 sc = calcscale(t)
  94.                 for row in output:
  95.                         fp.write(' '.join(map(str,row)))
  96.                         fp.write('\n')
  97.         system("convert %s -depth 8 %s" % (outputmask % (n, "pgm"), outputmask % (n, "png")))
  98.         unlink(outputmask % (n, "pgm"))
  99.  
  100. # Parameters so that I can run several instances of Golly and have them render separate slices of the frames
  101. # and thus make use of my multicore CPU...
  102. def main(step=1,start=0):
  103.         global curstep
  104.         g.reset()
  105.         curstep = 0
  106.         for i in xrange(start,framecount,step):
  107.                 g.show("Frame %d of %d..." % (i+1, framecount));
  108.                 doframe(i)
  109.  
  110. main()
  111. # or, make copies of the script and have each copy have one of, eg:
  112. #main(3,0)
  113. #main(3,1)
  114. #main(3,2)
  115. # and then run three instances of Golly and have each run a different copy of the script
clone this paste RAW Paste Data