Update the genome specs a bit

This commit is contained in:
Steven Robertson 2012-04-14 22:55:00 -07:00
parent ee2d571e9d
commit a4178c60fb
6 changed files with 58 additions and 62 deletions

View File

@ -118,7 +118,4 @@ class ColorClip(Filter, ClsMod):
filter_map = dict(bilateral=Bilateral, logscale=Logscale, haloclip=HaloClip, filter_map = dict(bilateral=Bilateral, logscale=Logscale, haloclip=HaloClip,
colorclip=ColorClip) colorclip=ColorClip)
def create(gprof): def create(gprof):
# TODO: redesign this (should not have to care about internals of return [filter_map[f]() for f in gprof.filter_order]
# use.Wrapper in order to find types from TypedList elements)
filts = gprof._val.get('filters') or gprof.spec['filters'].defaults
return [filter_map[f['type']]() for f in filts]

View File

@ -105,9 +105,7 @@ def convert_xforms(flame):
xfs.update(make_symm_xforms(float(flame['symmetry']), len(xfs))) xfs.update(make_symm_xforms(float(flame['symmetry']), len(xfs)))
return xfs return xfs
split_to_dict = lambda keys: lambda v: dict(zip(keys, map(float, v.split()))) pair = lambda v: dict(zip('xy', map(float, v.split())))
pair = split_to_dict('xy')
rgb_triple = split_to_dict('rgb')
xform_structure = ( xform_structure = (
('pre_affine', 'coefs', convert_affine), ('pre_affine', 'coefs', convert_affine),
@ -125,9 +123,9 @@ xform_structure = (
# (dst, cvt_dict) for properties that are built from multiple source keys. # (dst, cvt_dict) for properties that are built from multiple source keys.
# If a function returns 'None', its key is dropped from the result. # If a function returns 'None', its key is dropped from the result.
flame_structure = ( flame_structure = (
('info.author', 'nick', str), ('author.name', 'nick', str),
('info.author_url', 'url', lambda s: 'http://' + str(s)), ('author.url', 'url', lambda s: 'http://' + str(s)),
('info.name', 'name', str), ('name', 'name', str),
('camera.center', 'center', pair), ('camera.center', 'center', pair),
('camera.rotation', 'rotate', float), ('camera.rotation', 'rotate', float),
@ -135,12 +133,10 @@ flame_structure = (
('camera.scale', ('camera.scale',
lambda d: float(d['scale']) / float(d['size'].split()[0])), lambda d: float(d['scale']) / float(d['size'].split()[0])),
('filters.colorclip.gamma', 'filter', float), ('filters.colorclip.gamma', 'gamma', float),
('filters.colorclip.gamma_threshold', 'gamma_threshold', float), ('filters.colorclip.gamma_threshold', 'gamma_threshold', float),
('filters.colorclip.highlight_power', 'highlight_power', float), ('filters.colorclip.highlight_power', 'highlight_power', float),
('filters.colorclip.vibrance', 'vibrancy', float), ('filters.colorclip.vibrance', 'vibrancy', float),
# Not sure about putting this one on colorclip
('filters.colorclip.background', 'background', rgb_triple),
('filters.de.curve', 'estimator_curve', float), ('filters.de.curve', 'estimator_curve', float),
('filters.de.radius', 'estimator_radius', float), ('filters.de.radius', 'estimator_radius', float),
@ -149,6 +145,8 @@ flame_structure = (
float(d.get('estimator_radius', 11))) float(d.get('estimator_radius', 11)))
if 'estimator_minimum' in d else None), if 'estimator_minimum' in d else None),
('filters.logscale.brightness', 'brightness', float),
('palette', 'palette', util.palette_encode), ('palette', 'palette', util.palette_encode),
('xforms', convert_xforms), ('xforms', convert_xforms),
('final_xform', 'finalxform', convert_xform), ('final_xform', 'finalxform', convert_xform),

View File

@ -18,12 +18,16 @@ xform = (
, 'variations': var_params , 'variations': var_params
}) })
# Since the structure of the info element differs between anims, nodes and author = (
# edges, we pull out some of the common elements here { 'name': String("Human-readable name of author")
author = String('Attribution in the form: "Name [<email>][, url]"') , 'user': String("Email or other unique identifier")
name = String('A human-readable name for this entity') , 'url': String("Website or other link provided by author")
src = String('The identifier of the source node') })
dst = String('The identifier of the destination node')
link = (
{ 'src': String("Origin node ID and temporal offset")
, 'dst': String("Destination node ID and temporal offset")
})
filters = ( filters = (
{ 'bilateral': { 'bilateral':
@ -39,7 +43,7 @@ filters = (
, 'colorclip': , 'colorclip':
{ 'gamma': scalespline(4) { 'gamma': scalespline(4)
, 'gamma_threshold': spline(0.01, 0, 1) , 'gamma_threshold': spline(0.01, 0, 1)
, 'highlight_power': spline(-1, -1, 1) , 'highlight_power': spline(-1, -1)
, 'vibrance': scalespline() , 'vibrance': scalespline()
} }
, 'de': , 'de':
@ -65,37 +69,33 @@ time = (
}) })
base = ( base = (
{ 'camera': camera { 'name': String("Human-readable name of this work")
, 'camera': camera
, 'filters': filters , 'filters': filters
, 'palette': list_(Palette()) , 'palette': list_(Palette())
, 'xforms': map_(xform) , 'xforms': map_(xform)
, 'final_xform': xform , 'final_xform': xform
}) })
anim = dict(base)
anim.update(type='animation', time=time,
info=dict(authors=list_(author), name=name, src=src, dst=dst,
origin=string_()))
# TODO # TODO
node = dict(base) node = dict(base)
node.update(type='node', info=dict(author=author, author_url=string_(), node.update(type='node', blend=blend, author=author)
id=string_(), name=name))
# TODO # TODO
edge = dict(anim) edge = dict(base)
edge.update(type='edge', edge.update(type='edge', author=author, blend=blend, link=link, time=time,
info=dict(author=author, id=string_(), src=src, dst=dst),
xforms=dict(src=map_(xform), dst=map_(xform))) xforms=dict(src=map_(xform), dst=map_(xform)))
anim = dict(base)
anim.update(type='animation', authors=list_(author), link=link, time=time)
default_filters = ['bilateral', 'logscale', 'colorclip']
# Yeah, now I'm just messing around. # Yeah, now I'm just messing around.
prof_filters = dict([(fk, dict([(k, refscalar(1, '.'.join(['filters', fk, k]))) prof_filters = dict([(fk, dict([(k, refscalar(1, '.'.join(['filters', fk, k])))
for k in fv])) for fk, fv in filters.items()]) for k in fv])) for fk, fv in filters.items()])
# And here's a completely stupid hack to drag scale into the logscale filter # And here's a completely stupid hack to drag scale into the logscale filter
prof_filters['logscale']['scale'] = refscalar(1, 'camera.scale') prof_filters['logscale']['scale'] = refscalar(1, 'camera.scale')
default_filters = [{'type': k} for k in ['bilateral', 'logscale', 'colorclip']]
profile = ( profile = (
{ 'duration': RefScalar(30, 'time.duration', 'Base duration in seconds') { 'duration': RefScalar(30, 'time.duration', 'Base duration in seconds')
, 'fps': Scalar(24, 'Frames per second') , 'fps': Scalar(24, 'Frames per second')
@ -104,8 +104,8 @@ profile = (
, 'frame_width': refscalar(1, 'time.frame_width') , 'frame_width': refscalar(1, 'time.frame_width')
, 'spp': RefScalar(2000, 'camera.spp', 'Base samples per pixel') , 'spp': RefScalar(2000, 'camera.spp', 'Base samples per pixel')
, 'skip': Scalar(0, 'Skip this many frames between each rendered frame') , 'skip': Scalar(0, 'Skip this many frames between each rendered frame')
, 'filters': TypedList(prof_filters, default_filters, , 'filter_order': list_(enum(filters.keys()), default_filters)
'Ordered list of filters to apply') , 'filters': prof_filters
}) })
# Types recognized as independent units with a 'type' key # Types recognized as independent units with a 'type' key

View File

@ -3,13 +3,8 @@ from collections import namedtuple
Map = namedtuple('Map', 'type doc') Map = namedtuple('Map', 'type doc')
map_ = lambda type, d=None: Map(type, d) map_ = lambda type, d=None: Map(type, d)
List = namedtuple('List', 'type doc') List = namedtuple('List', 'type default doc')
list_ = lambda type, d=None: List(type, d) list_ = lambda type, default=(), d=None: List(type, default, d)
# A list as above, but where each element is a dict with a 'type' parameter
# corresponding to one of the specs listed in the 'types' dict on this spec.
TypedList = namedtuple('TypedList', 'types defaults doc')
typedlist = lambda types, defaults=[], d=None: TypedList(types, defaults, d)
Spline = namedtuple('Spline', 'default min max interp period doc var') Spline = namedtuple('Spline', 'default min max interp period doc var')
def spline(default=0, min=None, max=None, interp='linear', period=None, d=None): def spline(default=0, min=None, max=None, interp='linear', period=None, d=None):
@ -37,9 +32,11 @@ refscalar = lambda default, ref, d=None: RefScalar(default, ref, d)
String = namedtuple('String', 'doc') String = namedtuple('String', 'doc')
def string_(d=None): def string_(d=None):
return String(d) return String(d)
Enum = namedtuple('Enum', 'choices doc') Enum = namedtuple('Enum', 'choices default doc')
def enum(choices, d=None): def enum(choices, default=None, d=None):
"""Enum helper. 'choices' is a space-separated string.""" """Enum helper. 'choices' is a list or a space-separated string."""
return Enum(choices.split(), d) if isinstance(choices, basestring):
choices = choices.split()
return Enum(choices, default, d)
Palette = namedtuple('Palette', '') Palette = namedtuple('Palette', '')

View File

@ -1,18 +1,26 @@
import numpy as np import numpy as np
from spectypes import Spline, Scalar, RefScalar, Map, List, TypedList from spectypes import Enum, Spline, Scalar, RefScalar, Map, List
from specs import toplevels from specs import toplevels
class Wrapper(object): class Wrapper(object):
"""
Weird reverse visitor. Traversals of the tree are normally done externally
(via property accessors, in a lot of cases). This class alters the
returned representation of the underlying genome according to the provided
spec without imposing flow control.
"""
def __init__(self, val, spec=None, path=()): def __init__(self, val, spec=None, path=()):
if spec is None: if spec is None:
assert val.get('type') in toplevels, 'Unrecognized dict type'
spec = toplevels[val['type']] spec = toplevels[val['type']]
# plain 'val' would conflict with some variation property names # plain 'val' would conflict with some variation property names
self._val, self.spec, self.path = val, spec, path self._val, self.spec, self.path = val, spec, path
def wrap(self, name, spec, val): def wrap(self, name, spec, val):
# Oh, a visitor. How... pedestrian.
path = self.path + (name,) path = self.path + (name,)
if isinstance(spec, Enum):
return self.wrap_enum(path, spec, val)
if isinstance(spec, Spline): if isinstance(spec, Spline):
return self.wrap_spline(path, spec, val) return self.wrap_spline(path, spec, val)
elif isinstance(spec, Scalar): elif isinstance(spec, Scalar):
@ -25,13 +33,14 @@ class Wrapper(object):
return self.wrap_Map(path, spec, val) return self.wrap_Map(path, spec, val)
elif isinstance(spec, List): elif isinstance(spec, List):
return self.wrap_List(path, spec, val) return self.wrap_List(path, spec, val)
elif isinstance(spec, TypedList):
return self.wrap_TypedList(path, spec, val)
return self.wrap_default(path, spec, val) return self.wrap_default(path, spec, val)
def wrap_default(self, path, spec, val): def wrap_default(self, path, spec, val):
return val return val
def wrap_enum(self, path, spec, val):
return val or spec.default
def wrap_spline(self, path, spec, val): def wrap_spline(self, path, spec, val):
return val return val
@ -45,12 +54,8 @@ class Wrapper(object):
return self.wrap_dict(path, spec, val) return self.wrap_dict(path, spec, val)
def wrap_List(self, path, spec, val): def wrap_List(self, path, spec, val):
return [self.wrap(spec.type, v) for v in val] val = val if val is not None else spec.default
return [self.wrap(path, spec.type, v) for v in val]
def wrap_TypedList(self, path, spec, val):
val = val if val is not None else spec.defaults
return [self.wrap(path+(str(i),), spec.types[v['type']], v)
for i, v in enumerate(val)]
def get_spec(self, name): def get_spec(self, name):
if isinstance(self.spec, Map): if isinstance(self.spec, Map):
@ -73,7 +78,6 @@ class Wrapper(object):
def __getitem__(self, name): def __getitem__(self, name):
return getattr(self, str(name)) return getattr(self, str(name))
class RefWrapper(Wrapper): class RefWrapper(Wrapper):
""" """
Wrapper that handles RefScalars, as with profile objects. Wrapper that handles RefScalars, as with profile objects.

View File

@ -210,7 +210,6 @@ class Renderer(object):
del self._modrefs[:] del self._modrefs[:]
self._modrefs.append(self.mod) self._modrefs.append(self.mod)
# TODO: make these customizable
self.filts = filters.create(gprof) self.filts = filters.create(gprof)
self.out = output.PILOutput() self.out = output.PILOutput()
@ -359,7 +358,8 @@ class RenderManager(ClsMod):
self._iter(rdr, gnm, gprof, dim, tc) self._iter(rdr, gnm, gprof, dim, tc)
if self.copy_evt: if self.copy_evt:
self.stream_a.wait_for_event(self.copy_evt) self.stream_a.wait_for_event(self.copy_evt)
for filt, params in zip(rdr.filts, gprof.filters): for filt, name in zip(rdr.filts, gprof.filter_order):
params = getattr(gprof.filters, name)
filt.apply(self.fb, gprof, params, dim, tc, self.stream_a) filt.apply(self.fb, gprof, params, dim, tc, self.stream_a)
rdr.out.convert(self.fb, gprof, dim, self.stream_a) rdr.out.convert(self.fb, gprof, dim, self.stream_a)
self.filt_evt = cuda.Event().record(self.stream_a) self.filt_evt = cuda.Event().record(self.stream_a)