mirror of
https://github.com/stevenrobertson/cuburn.git
synced 2025-02-05 11:40:04 -05:00
Another incompatible update to the genome format
This commit is contained in:
parent
ed885534d6
commit
c80b8a07a7
@ -11,7 +11,7 @@ _CODE = '''
|
|||||||
#include<math_constants.h>
|
#include<math_constants.h>
|
||||||
|
|
||||||
__global__
|
__global__
|
||||||
void colorclip(float4 *pixbuf, float gamma, float vibrancy, float highpow,
|
void colorclip(float4 *pixbuf, float gamma, float vibrance, float highpow,
|
||||||
float linrange, float lingam, float3 bkgd,
|
float linrange, float lingam, float3 bkgd,
|
||||||
int fbsize, int blend_background_color) {
|
int fbsize, int blend_background_color) {
|
||||||
int i = threadIdx.x + blockDim.x * (blockIdx.x + gridDim.x * blockIdx.y);
|
int i = threadIdx.x + blockDim.x * (blockIdx.x + gridDim.x * blockIdx.y);
|
||||||
@ -42,7 +42,7 @@ void colorclip(float4 *pixbuf, float gamma, float vibrancy, float highpow,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float ls = vibrancy * alpha / pix.w;
|
float ls = vibrance * alpha / pix.w;
|
||||||
alpha = fminf(1.0f, fmaxf(0.0f, alpha));
|
alpha = fminf(1.0f, fmaxf(0.0f, alpha));
|
||||||
|
|
||||||
float maxc = fmaxf(pix.x, fmaxf(pix.y, pix.z));
|
float maxc = fmaxf(pix.x, fmaxf(pix.y, pix.z));
|
||||||
@ -71,9 +71,9 @@ void colorclip(float4 *pixbuf, float gamma, float vibrancy, float highpow,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pix.x += (1.0f - vibrancy) * powf(opix.x, gamma);
|
pix.x += (1.0f - vibrance) * powf(opix.x, gamma);
|
||||||
pix.y += (1.0f - vibrancy) * powf(opix.y, gamma);
|
pix.y += (1.0f - vibrance) * powf(opix.y, gamma);
|
||||||
pix.z += (1.0f - vibrancy) * powf(opix.z, gamma);
|
pix.z += (1.0f - vibrance) * powf(opix.z, gamma);
|
||||||
|
|
||||||
pix.x += (1.0f - alpha) * bkgd.x;
|
pix.x += (1.0f - alpha) * bkgd.x;
|
||||||
pix.y += (1.0f - alpha) * bkgd.y;
|
pix.y += (1.0f - alpha) * bkgd.y;
|
||||||
@ -318,7 +318,7 @@ class Filtering(object):
|
|||||||
|
|
||||||
# TODO: implement integration over cubic splines?
|
# TODO: implement integration over cubic splines?
|
||||||
gam = f32(1 / gnm.color.gamma(tc))
|
gam = f32(1 / gnm.color.gamma(tc))
|
||||||
vib = f32(gnm.color.vibrancy(tc))
|
vib = f32(gnm.color.vibrance(tc))
|
||||||
hipow = f32(gnm.color.highlight_power(tc))
|
hipow = f32(gnm.color.highlight_power(tc))
|
||||||
lin = f32(gnm.color.gamma_threshold(tc))
|
lin = f32(gnm.color.gamma_threshold(tc))
|
||||||
lingam = f32(lin ** (gam-1.0) if lin > 0 else 0)
|
lingam = f32(lin ** (gam-1.0) if lin > 0 else 0)
|
||||||
|
BIN
cuburn/code/primes.bin
Normal file
BIN
cuburn/code/primes.bin
Normal file
Binary file not shown.
@ -7,6 +7,8 @@ import tempita
|
|||||||
|
|
||||||
def crep(s):
|
def crep(s):
|
||||||
"""Escape for PTX assembly"""
|
"""Escape for PTX assembly"""
|
||||||
|
if isinstance(s, unicode):
|
||||||
|
s = s.encode('utf-8')
|
||||||
return '"%s"' % s.encode("string_escape")
|
return '"%s"' % s.encode("string_escape")
|
||||||
|
|
||||||
class Template(tempita.Template):
|
class Template(tempita.Template):
|
||||||
|
114
cuburn/genome.py
114
cuburn/genome.py
@ -1,7 +1,8 @@
|
|||||||
import json
|
|
||||||
import base64
|
import base64
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
from code.util import crep
|
||||||
|
|
||||||
class SplEval(object):
|
class SplEval(object):
|
||||||
_mat = np.matrix([[1.,-2, 1, 0], [2,-3, 0, 1],
|
_mat = np.matrix([[1.,-2, 1, 0], [2,-3, 0, 1],
|
||||||
[1,-1, 0, 0], [-2, 3, 0, 0]])
|
[1,-1, 0, 0], [-2, 3, 0, 0]])
|
||||||
@ -80,14 +81,12 @@ class SplEval(object):
|
|||||||
return list(self.knots.T.flat)
|
return list(self.knots.T.flat)
|
||||||
|
|
||||||
class Palette(object):
|
class Palette(object):
|
||||||
"""Wafer-thin wrapper around palettes. For the future!"""
|
def __init__(self, datastrs):
|
||||||
def __init__(self, datastr, fmt='rgb8'):
|
if datastrs[0] != 'rgb8':
|
||||||
if fmt != 'rgb8':
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
if len(datastr) != 768:
|
|
||||||
raise ValueError("Unsupported palette width")
|
|
||||||
self.width = 256
|
self.width = 256
|
||||||
pal = np.reshape(np.fromstring(datastr, np.uint8), (256, 3))
|
raw = base64.b64decode(''.join(datastrs[1:]))
|
||||||
|
pal = np.reshape(np.fromstring(raw, np.uint8), (256, 3))
|
||||||
self.data = np.ones((256, 4), np.float32)
|
self.data = np.ones((256, 4), np.float32)
|
||||||
self.data[:,:3] = pal / 255.0
|
self.data[:,:3] = pal / 255.0
|
||||||
|
|
||||||
@ -106,36 +105,61 @@ class _AttrDict(dict):
|
|||||||
return dct
|
return dct
|
||||||
|
|
||||||
class Genome(_AttrDict):
|
class Genome(_AttrDict):
|
||||||
|
"""
|
||||||
|
Load a genome description, wrapping all data structures in _AttrDicts,
|
||||||
|
converting lists of numbers to splines, and deriving some values. Derived
|
||||||
|
values are stored as instance properties, rather than replacing the
|
||||||
|
original values, such that JSON-encoding this structure should always
|
||||||
|
print a valid genome.
|
||||||
|
"""
|
||||||
# For now, we base the Genome class on an _AttrDict, letting its structure
|
# For now, we base the Genome class on an _AttrDict, letting its structure
|
||||||
# be defined implicitly by the way it is used in device code. More formal
|
# be defined implicitly by the way it is used in device code, except for
|
||||||
# unpacking will happen soon.
|
# these derived properties.
|
||||||
def __init__(self, gnm, base_den):
|
def __init__(self, gnm):
|
||||||
super(Genome, self).__init__(gnm)
|
super(Genome, self).__init__(gnm)
|
||||||
for k, v in self.items():
|
for k, v in self.items():
|
||||||
|
if not isinstance(v, dict):
|
||||||
|
continue
|
||||||
v = _AttrDict(v)
|
v = _AttrDict(v)
|
||||||
|
# These two properties must be handled separately
|
||||||
if k not in ('info', 'time'):
|
if k not in ('info', 'time'):
|
||||||
_AttrDict._wrap(v)
|
_AttrDict._wrap(v)
|
||||||
self[k] = v
|
self[k] = v
|
||||||
# TODO: this is a hack, figure out how to solve it more elegantly
|
|
||||||
self.spp = SplEval(self.camera.density.knotlist)
|
self.decoded_palettes = map(Palette, self.palettes)
|
||||||
self.spp.knots[1] *= base_den
|
print self.color
|
||||||
# TODO: decide how to handle palettes. For now, it's the caller's
|
pal = self.color.palette_times
|
||||||
# responsibility to replace this list with actual palettes.
|
|
||||||
pal = self.color.palette
|
|
||||||
if isinstance(pal, basestring):
|
if isinstance(pal, basestring):
|
||||||
self.color.palette = [(0.0, pal), (1.0, pal)]
|
self.palette_times = [(0.0, int(pal)), (1.0, int(pal))]
|
||||||
elif isinstance(pal, list):
|
else:
|
||||||
self.color.palette = zip(pal[::2], pal[1::2])
|
self.palette_times = zip(pal[::2], map(int, pal[1::2]))
|
||||||
|
|
||||||
# TODO: caller also needs to call set_timing()
|
self.adj_frame_width, self.spp = None, None
|
||||||
self.adj_frame_width = None
|
self.canonical_right = not (self.get('link') and
|
||||||
self.canonical_right = (not self.get('link') or not self.link == 'self'
|
(self.link == 'self' or self.link.get('right')))
|
||||||
or not self.link.get('right'))
|
|
||||||
|
|
||||||
def set_timing(self, base_dur, fps, offset=0.0, err_spread=True):
|
def set_profile(self, prof, offset=0.0, err_spread=True):
|
||||||
"""
|
"""
|
||||||
Set frame timing. Must be called at least once prior to rendering.
|
Sets the instance props which are dependent on a profile. Also
|
||||||
|
calculates timing information, which is returned instead of being
|
||||||
|
attached to the genome. May be called multiple times to set different
|
||||||
|
options.
|
||||||
|
|
||||||
|
``prof`` is a profile dictionary. ``offset`` is the time in seconds
|
||||||
|
that the first frame's effective presentation time should be offset
|
||||||
|
from the natural presentation time. ``err_spread`` will spread the
|
||||||
|
rounding error in this frame across all frames, such that PTS+(1/FPS)
|
||||||
|
is exactly equal to the requested duration.
|
||||||
|
|
||||||
|
Returns ``(err, times)``, where ``err`` is the rounding error in
|
||||||
|
seconds (taking ``offset`` into account), and ``times`` is a list of
|
||||||
|
the central time of each frame in the animation in relative-time
|
||||||
|
coordinates. Also sets the ``spp`` and ``adj_frame_width`` properties.
|
||||||
"""
|
"""
|
||||||
|
self.spp = SplEval(self.camera.density.knotlist)
|
||||||
|
self.spp.knots[1] *= prof['quality']
|
||||||
|
fps, base_dur = prof['fps'], prof['duration']
|
||||||
|
|
||||||
# TODO: test!
|
# TODO: test!
|
||||||
dur = self.time.duration
|
dur = self.time.duration
|
||||||
if isinstance(dur, basestring):
|
if isinstance(dur, basestring):
|
||||||
@ -162,3 +186,43 @@ class Genome(_AttrDict):
|
|||||||
epts = np.linspace(-2*np.pi, 2*np.pi, nframes)
|
epts = np.linspace(-2*np.pi, 2*np.pi, nframes)
|
||||||
times = times + 0.5 * err * (np.tanh(epts) + 1)
|
times = times + 0.5 * err * (np.tanh(epts) + 1)
|
||||||
return err, times
|
return err, times
|
||||||
|
|
||||||
|
def json_encode_genome(obj, indent=0):
|
||||||
|
"""
|
||||||
|
Encode an object into JSON notation. This serializer only works on the
|
||||||
|
subset of JSON used in genomes.
|
||||||
|
"""
|
||||||
|
# TODO: test, like so many other things
|
||||||
|
isnum = lambda v: isinstance(v, (float, int, np.number))
|
||||||
|
|
||||||
|
def wrap(pairs, delims):
|
||||||
|
do, dc = delims
|
||||||
|
i = ' ' * indent
|
||||||
|
out = ''.join([do, ', '.join(pairs), dc])
|
||||||
|
if '\n' not in out and len(out) + indent < 70:
|
||||||
|
return out
|
||||||
|
return ''.join(['\n', i, do, ' ', ('\n'+i+', ').join(pairs),
|
||||||
|
'\n', i, dc])
|
||||||
|
|
||||||
|
if isinstance(obj, dict):
|
||||||
|
if not obj:
|
||||||
|
return '{}'
|
||||||
|
ks, vs = zip(*sorted(obj.items()))
|
||||||
|
if ks == ('b', 'g', 'r'):
|
||||||
|
ks, vs = reversed(ks), reversed(vs)
|
||||||
|
ks = [crep('%.8g' % k if isnum(k) else str(k)) for k in ks]
|
||||||
|
vs = [json_encode_genome(v, indent+2) for v in vs]
|
||||||
|
return wrap(['%s: %s' % p for p in zip(ks, vs)], '{}')
|
||||||
|
elif isinstance(obj, list):
|
||||||
|
vs = [json_encode_genome(v, indent+2) for v in obj]
|
||||||
|
if vs and len(vs) % 2 == 0 and isnum(obj[0]):
|
||||||
|
vs = map(', '.join, zip(vs[::2], vs[1::2]))
|
||||||
|
return wrap(vs, '[]')
|
||||||
|
elif isinstance(obj, SplEval):
|
||||||
|
return json_encode_genome(obj.knotlist, indent)
|
||||||
|
elif isinstance(obj, basestring):
|
||||||
|
return crep(obj)
|
||||||
|
elif isnum(obj):
|
||||||
|
return '%.8g' % obj
|
||||||
|
raise TypeError("Don't know how to serialize %s of type %s" %
|
||||||
|
(obj, type(obj)))
|
||||||
|
@ -250,15 +250,13 @@ class Renderer(object):
|
|||||||
info_size = 4 * len(self._iter.packer) * ntemporal_samples
|
info_size = 4 * len(self._iter.packer) * ntemporal_samples
|
||||||
d_infos = cuda.mem_alloc(info_size)
|
d_infos = cuda.mem_alloc(info_size)
|
||||||
|
|
||||||
pals = genome.color.palette
|
ptimes, pidxs = zip(*genome.palette_times)
|
||||||
if isinstance(pals, basestring):
|
|
||||||
pals = [0.0, pals, 1.0, pals]
|
|
||||||
palint_times = np.empty(len(genome_times[0]), f32)
|
palint_times = np.empty(len(genome_times[0]), f32)
|
||||||
palint_times.fill(100.0)
|
palint_times.fill(1e10)
|
||||||
palint_times[:len(pals)] = [p[0] for p in pals]
|
palint_times[:len(ptimes)] = ptimes
|
||||||
d_palint_times = cuda.to_device(palint_times)
|
d_palint_times = cuda.to_device(palint_times)
|
||||||
d_palint_vals = cuda.to_device(
|
pvals = [genome.decoded_palettes[i].data for i in pidxs]
|
||||||
np.concatenate([p[1].data for p in pals]))
|
d_palint_vals = cuda.to_device(np.concatenate(pvals))
|
||||||
|
|
||||||
if self.acc_mode in ('deferred', 'atomic'):
|
if self.acc_mode in ('deferred', 'atomic'):
|
||||||
palette_fun = self.mod.get_function("interp_palette_hsv_flat")
|
palette_fun = self.mod.get_function("interp_palette_hsv_flat")
|
||||||
|
Loading…
Reference in New Issue
Block a user