Advertisement
Guest User

Golly Python script to output meta-life animation

a guest
May 13th, 2012
5,282
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.88 KB | None | 0 0
  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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement