cuburn/main.py

189 lines
6.6 KiB
Python
Raw Normal View History

2012-04-18 13:21:10 -04:00
#!/usr/bin/env python2
2010-08-27 12:28:02 -04:00
#
2011-12-17 21:25:15 -05:00
# cuburn, one of a surprisingly large number of ports of the fractal flame
2010-08-27 12:28:02 -04:00
# algorithm to NVIDIA GPUs.
#
# This one is copyright 2010-2012, Steven Robertson <steven@strobe.cc>
# and Erik Reckase <e.reckase@gmail.com>.
2010-08-27 12:28:02 -04:00
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later
# as published by the Free Software Foundation.
import os
import sys
import time
2011-12-17 21:25:15 -05:00
import json
import warnings
import argparse
2011-06-13 23:20:18 -04:00
from subprocess import Popen
from itertools import ifilter
2010-08-27 12:28:02 -04:00
import numpy as np
2011-05-03 17:12:12 -04:00
2012-04-16 04:45:34 -04:00
sys.path.insert(0, os.path.dirname(__file__))
2012-05-20 16:03:27 -04:00
from cuburn import render, filters, output, profile
2012-04-15 01:58:04 -04:00
from cuburn.genome import convert, use, db
2011-05-03 13:02:15 -04:00
2012-07-22 18:53:38 -04:00
def save(output_module, name, rendered_frame):
out, log = output_module.encode(rendered_frame)
for suffix, file_like in out.items():
with open(name + suffix, 'w') as fp:
fp.write(file_like.read())
for key, val in log:
print '\n=== %s ===' % key
print val
def pyglet_preview(args, gprof, itr):
import pyglet
import pyglet.gl as gl
2012-04-18 11:59:01 -04:00
w, h = gprof.width, gprof.height
window = pyglet.window.Window(w, h, vsync=False)
image = pyglet.image.CheckerImagePattern().create_image(w, h)
tex = image.texture
label = pyglet.text.Label('Rendering first frame', x=5, y=h-5,
width=w, anchor_y='top', font_size=16,
bold=True, multiline=True)
@window.event
def on_draw():
window.clear()
tex.blit(0, 0, 0)
label.draw()
@window.event
def on_key_press(sym, mod):
if sym == pyglet.window.key.Q:
pyglet.app.exit()
@window.event
def on_mouse_motion(x, y, dx, dy):
pass
last_time = [time.time()]
def poll(dt):
2012-07-22 18:53:38 -04:00
out = next(itr, False)
if out is False:
if args.pause:
label.text = "Done. ('q' to quit)"
else:
pyglet.app.exit()
elif out is not None:
2012-07-22 18:53:38 -04:00
name, buf = out
real_dt = time.time() - last_time[0]
last_time[0] = time.time()
2012-07-22 18:53:38 -04:00
if buf.dtype == np.uint8:
fmt = gl.GL_UNSIGNED_BYTE
2012-07-22 18:53:38 -04:00
elif buf.dtype == np.uint16:
fmt = gl.GL_UNSIGNED_SHORT
else:
2012-07-22 18:53:38 -04:00
label.text = 'Unsupported format: ' + buf.dtype
return
2012-07-22 18:53:38 -04:00
h, w, ch = buf.shape
gl.glEnable(tex.target)
gl.glBindTexture(tex.target, tex.id)
gl.glTexImage2D(tex.target, 0, gl.GL_RGB8, w, h, 0, gl.GL_RGBA,
2012-07-22 18:53:38 -04:00
fmt, buf.tostring())
gl.glDisable(tex.target)
2012-07-22 18:53:38 -04:00
label.text = '%s (%g fps)' % (name, 1./real_dt)
else:
label.text += '.'
2012-07-22 18:53:38 -04:00
pyglet.clock.set_fps_limit(20)
pyglet.clock.schedule_interval(poll, 1/20.)
pyglet.app.run()
2012-07-22 18:53:38 -04:00
def main(args, prof):
gdb = db.connect(args.genomedb)
gnm, basename = gdb.get_anim(args.flame, args.half)
if getattr(args, 'print'):
print convert.to_json(gnm)
return
gprof = profile.wrap(prof, gnm)
if args.name is not None:
basename = args.name
prefix = os.path.join(args.dir, basename)
if args.subdir:
if not os.path.isdir(prefix):
os.mkdir(prefix)
prefix_plus = prefix + '/'
else:
prefix_plus = prefix + '_'
frames = [('%s%05d%s' % (prefix_plus, i, args.suffix), t)
for i, t in profile.enumerate_times(gprof)]
# We don't initialize a CUDA context until here. This keeps other
# functions like --help and --print snappy.
import pycuda.autoinit
rmgr = render.RenderManager()
rdr = render.Renderer(gnm, gprof)
def render_iter():
m = os.path.getmtime(args.flame)
first = True
for name, times in frames:
if args.resume:
fp = name + rdr.out.suffix
2015-02-14 20:51:13 -05:00
if os.path.isfile(fp) and m < os.path.getmtime(fp):
2012-07-22 18:53:38 -04:00
continue
2015-02-14 20:51:13 -05:00
for idx, t in enumerate(times):
2012-07-22 18:53:38 -04:00
evt, buf = rmgr.queue_frame(rdr, gnm, gprof, t, first)
first = False
while not evt.query():
time.sleep(0.01)
yield None
save(rdr.out, name, buf)
if args.rawfn:
try:
buf.tofile(args.rawfn + '.tmp')
os.rename(args.rawfn + '.tmp', args.rawfn)
except e:
print 'Failed to write %s: %s' % (args.rawfn, e)
2015-02-14 20:51:13 -05:00
print '%s (%3d/%3d), %dms' % (name, idx, len(times), evt.time())
2012-07-22 18:53:38 -04:00
yield name, buf
save(rdr.out, name, None)
if args.gfx:
pyglet_preview(args, gprof, render_iter())
else:
for i in render_iter(): pass
2010-08-27 12:28:02 -04:00
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Render fractal flames.')
2012-04-15 01:58:04 -04:00
parser.add_argument('flame', metavar='ID', type=str,
help="Filename or flame ID of genome to render")
parser.add_argument('-g', action='store_true', dest='gfx',
help="Show output in OpenGL window")
parser.add_argument('-n', metavar='NAME', type=str, dest='name',
help="Prefix to use when saving files (default is basename of input)")
2012-01-31 12:14:05 -05:00
parser.add_argument('--suffix', metavar='NAME', type=str, dest='suffix',
help="Suffix to use when saving files (default '')", default='')
parser.add_argument('-o', metavar='DIR', type=str, dest='dir',
help="Output directory", default='.')
2011-10-15 22:21:49 -04:00
parser.add_argument('--resume', action='store_true', dest='resume',
2012-01-03 11:24:42 -05:00
help="Don't overwrite output files that are newer than the input")
2012-01-03 12:03:32 -05:00
parser.add_argument('--pause', action='store_true',
help="Don't close the preview window after rendering is finished")
2012-07-05 02:05:09 -04:00
parser.add_argument('-d', '--genomedb', metavar='PATH', type=str,
2012-04-15 01:58:04 -04:00
help="Path to genome database (file or directory, default '.')",
default='.')
2012-07-05 02:05:09 -04:00
parser.add_argument('--subdir', action='store_true',
help="Use basename as subdirectory of out dir, instead of prefix")
parser.add_argument('--raw', metavar='PATH', type=str, dest='rawfn',
help="Target file for raw buffer, to enable previews.")
2012-05-20 16:03:27 -04:00
parser.add_argument('--half', action='store_true',
help='Use half-loops when converting nodes to animations')
2012-07-05 03:14:44 -04:00
parser.add_argument('--print', action='store_true',
help="Print the blended animation and exit.")
2012-05-20 16:03:27 -04:00
profile.add_args(parser)
2012-04-15 01:58:04 -04:00
2011-12-17 21:25:15 -05:00
args = parser.parse_args()
2012-05-20 16:03:27 -04:00
pname, prof = profile.get_from_args(args)
2011-12-17 21:25:15 -05:00
main(args, prof)