Age | Commit message (Collapse) | Author |
|
|
|
This module started out as a way to test a line drawing algorithm, but
ended up looking interesting enough to include as a module of it's own.
#ZephyrCommit #BirdwalkCommit
|
|
This module cycles through a set of modules referred to as pages.
Settings include:
pages={list,of,modules}
rate=float page flipping rate
direction=float page flipping direction
taps are exposed for controlling rate and direction real-time,
with the addition of an explicit page index tap for overriding
the automatic flipping normally influenced by rate and direction.
Note that when using rkt with these taps, it immediately becomes
limiting that there's no ability to specify NaN as a track value
for temporarily relinquishing control of the page idx. It'd be
very useful to let the automatic flipping run the show at
whatever rate the rkt tracks specify, until the page idx was
asserted to a specific page, then holding it on that page until a
NaN row for the page track was encountered, restoring automatic
flipping. This needs to get added in both the Rocket library and
RocketEditor to be supported, as well as getting wired up to the
rkt integration.
|
|
This is primarily intended for overlay use, but when not an
overlay uses a little builtin seed-derived tile as a fallback.
Currently the only settings are {x,y}=-1..1 for the direction
vector. Speed is currently fixed to 1, the vector is always
normalized.
Nothing terribly exciting.
|
|
This adds a new "meta" module which registers itself as a
pre-render context on the stream, to render whatever module is
specified as the "module=" setting.
The impetus for this is background music in rkt creations, so one
can avoid enduring the rigamarole of plugging something like a
"playit" instance into every scene.
With this "pre" builtin one can just use something like
"pre,module=playit,itfile=music.it" as a scene, and that will get
the playit module playing music.it hooked into the stream,
without the need to always have it present in every scene's
settings.
There's a TODO item noting the need for taps to control the
active/inactive state of the pre instance this adds. For now,
once you have a "pre", whatever module it contains will be
rendered before the main stream context set
w/til_stream_set_module_context() gets rendered. That's fine for
now, but there will need to be more control especially as more
complex productions happen involving multiple songs.
|
|
Like til_module_t.render_audio(), this hooks into the render path
without triggering the implicit fragment clearing of the usual
render_fragment/prepare_frame/finish_frame methods.
But unlike render_audio(), it receives the full suite of
parameters including the fragment pointer.
The impetus for this is implementing builtins that serve as a
sort of pass-thru or proxy to another module, like the "ref"
builtin (which should probably change to use this instead of its
current render_fragment() hook). Because sometimes the proxied
module isn't something drawing to the fragment, so the implicit
fragment clearing shouldn't occur. But if the proxied module
/does/ touch the fragment by implementing one of those methods,
then the proxy module's use of til_module_render() would still
trigger the implicit clear when appropriate.
|
|
Rudimentary .IT file music playback via libplayit.
When seekable=on, the file is 100% pre-rendered at context
create, then simply copied into the audio queue @ render_audio.
When seekable=off, the file is mixed incrementally per-frame @
render_audio in max of bufsize=N_frames increments. The bufsize
here basically just determines the maximum time spent rendering
audio in a single go, and how much tolerance of frame delays due
to slow rendering there will be before dropouts occur.
|
|
Simple audio rendering modules need a way to render their audio
without affecting the fragment's state. By providing a
til_module_t.render_audio() a module indicates it's only an audio
renderer, and its render won't trigger an implicit clear of the
frame's fragment.
There might be a new flag added to indicate when modules are
audio modules, but this is good enough for now.
|
|
Becomes til_rgb_to_uint32(). Nothing functionally changed, just
making this generally available for anything wanting to parse an
rgb hex string into a uint32 packed pixel in a setup_func.
|
|
Intended as a bootstrap for new module creation, particularly
aimed at new contributors. No module context, fragmenting, taps,
or settings are implemented, to keep things as simple as
possible.
|
|
This deviates from the established pattern of all built-in
modules being in til_builtins.c, but that's ok.
The main impetus for this is to just get asc out of rotation for
randomized compose layers, since it's so uninteresting. But it's
also valid as a built-in since it's primarily for diagnostic
purposes anyways.
|
|
This just binds the simple libs/txt/txt.c stuff to a rendering
module, exposing the minimal options as settings.
It's handy for testing libs/txt/txt.c, and introduces a module
requiring free-form strings potentially including newlines be
handled properly as settings values. This latter aspect is
important for improving settings syntax, any improvements must
handle these more complicated scenarios and now there's a good
test case for exercising those nuances.
I suppose there might also be use in the creative process if you
want a text element but haven't got around to hacking up a
prettier module for it yet. Just use this one temporarily.
See commit for some remaining TODO items.
|
|
This copies from checkers_value_to_pos() turning it into a libtil
helper. It's a common operation in setup_funcs to map a setting
value to a numeric position in the list of values.
|
|
Modules can now use the til_module_t.finish_frame() return value
to trigger re-rendering by returning 1, returning 0 finishes the
frame.
A smattering of til_module_t.finish_frame() implementations were
largely mechanically updated to match this change by returning 0,
since nothing actually uses multi-pass rendering yet.
The impetus for this is experimenting with the flow module doing
two passes of threaded rendering per frame. A first pass to
sample the flow field and update the elements, per-cpu, but
drawing nothing. Then a second pass to render the elements in a
tiled manner.
|
|
This is intended to perhaps be of use for threaded rendering that
don't actually produce pixels during their render phase, but
still need n_cpus fragments to dispatch the parallel work keying
off the fragment.number.
Such a renderer might then put its pixels on-screen serially @
finish_frame(), or maybe the rendering functions will get a
return value to trigger multi-pass rendering on the same tick.
|
|
til_module_create_contexts() currently supplies the til_module_t*
independent from the til_setup_t*, but since the addition of
til_setup_t.creator, we actually get the module from the setup as
well. So let's at least assert that they match, since it'd be a
real problem if a setup from a foreign creator somehow got here.
It's tempting to refactor to just derive the module from the
setup altogether and stop passing that around separately, but
that kind of sucks as-is because til_setup_t is used by more than
just rendering modules. It makes me lean towards deprecating
til_setup_t.creator and instead having the various til_setup_t
users subclass it with their own types like til_fb_setup_t and
til_module_setup_t which each get typed creators, then pass those
around. It's starting to smell like over-engineering, let's just
roll with the assert.
|
|
This is kind of a particle system, where the particles are pushed
around through a 3D vector space treated as a flow field.
No physics are being simulated here, it's just treating the flow
field as direction vectors that are trilinearly interpolated when
sampled to produce a single direction vector. That direction
vector gets applied to particles near it.
To keep things interesting the flow field evolves by having two
distinct flow fields which the simulation progressively
alternates sampling from. For every frame, both flow fields are
sampled for every particle, but how much weight is given to the
influence of one vs. the other varies by a triangle wave over
time. When the weight is biased enough to one of the flow fields
near a peak/valley in the triangle wave, the other gets
re-populated while its influence is negligible, also
interpolating its new values with 25% influence from the active
field.
The current flow field population routine is completely random.
Yet there's a surprising amount of emergent order despite being
totally randomized direction vectors.
Currently supported settings include:
size= the width of the 3D flow field cube in direction vectors
(the number of vectors is size*size*size)
count= the number of particles/elements
speed= how far a particle is moved along the current sample's
direction vector
This was first implemented in 2017, but sat unfinished in a topic
branch for myriad reasons. Now that rototiller has much more
robust settings infrastructure, among other things, it seemed
worth finishing this up and merging.
|
|
Mechanical rename for clarity reasons, primarily to better
differentiate from the setup_func style
til_module_setup()/til_module_setup_full() functions.
|
|
Mechanical rename for clarity reasons, primarily to better
differentiate from the setup_func style
til_module_setup()/til_module_setup_full() functions.
|
|
Stupid bug in untested/unused exclusions handling
|
|
Missed this in the last round of moving things to the
new raw_value() setter/getter api
This snippet of copy-n-pasta the few setup front-ends continue to
have should really be factored out into a libtil helper
|
|
Sometimes nested modules are optional, in those cases I've
usually been using the "none" module name to indicate this and
the ad-hoc setup stuff can easily bypass module setup on that.
This commit is a step towards having a "none" builtin that
provides a til_module_t.setup() which succeeds but only produces
a NULL res_setup when asked to finalize.
So if callers just handle a successful finalize case that writes
NULL at res_setup equivalent to "disabled", this all Just Works.
Currently that's not an expected thing, but future commits will
bring everything else on the same page.
For callers who want to require the module and not offer "none",
they can just put "none" in the explicit exclusions list passed
to til_module_setup_full().
|
|
Also move builtins to a separate listing while at it
For now this results in the builtins showing up in the modules
list alongside the actual rendering modules. Future work must
refine this UX, maybe by adding some metadata to the spec.values
for categorizing/prioritizing what's shown always vs. what's
present but hidden without asking to be shown hidden stuff or
whatever.
Just consolidating some junk and working towards every nested
module setup going through the same machinery, and always being
able to access the builtins.
|
|
Particularly with nested modules it's annoying to have to stow
the module separate from the setup during the setup process.
If the baked setup included the module pointer in the
non-module-specific-setup part of the setup, then nested settings
could finalize using the generic module setup wrapper and just
rely on this til_setup_t.creator pointer to contain the
appropriate module. Which should enable tossing out a bunch of
copy-n-pasta surrounding nested modules setup.
Note this has to be a void* since til_setup_t is a generic thing
used equally by both the fb code and the module code. Hence why
this is called "creator" and not "module", as well as the void*
as opposed to til_module_t*.
Also if rototiller ever grows a sound backend, the setup
machinery will be reused there as well, and it'll be yet another
creator handle that isn't an til_fb_ops_t or a til_module_t.
It's assumed that the callers producing these setups won't be
trying to pass them to the wrong places i.e. a module setup
getting passed to an fb backend and vice versa.
I'm mildly annoyed about having to move the various til_module_t
blocks to above the module's foo_setup(), but it seemed like the
least annoying option. This may be revisited.
|
|
When creating nested setting instances, just pass down the full
raw value so if there's any prefix on the value it can be
realized as a prefix for the first entry in the nested instance.
|
|
Now whenever a setting value/preferred input is derived from a
setting, it'll want to get the raw value to preserve any prefix.
|
|
The filter bypass was kind of a hack and resulted in unfiltered
module lists in rkt_scener edits.
Now that there's an explicit syntax for bypassing checks, the
user can just do that to access what's filtered. So get back to
appropriately consistent filtered results.
|
|
Playing with libs/sig in 2D, this isn't really an interesting
module by itself in terms of visual output. But it might have
utility as a diagnostic thing if libs/sig becomes a more used
thing.
At the very least, for now, it's useful for observing affects of
and iterating on libs/sig development. So I'm merging this, just
gated behind TIL_MODULE_EXPERIMENTAL so it's not in rtv rotation
or presented as something in the usual modules list.
|
|
This restores the original til_fragmenter_slice_per_cpu() while
adding an explicit x16 variant for what
til_fragmenter_slice_per_cpu() had become.
The impetus for this is realizing the x16 multiplier is terrible
for sparkler's crappy threading, and it really need strictly
n_cpus slices for the threading to be beneficial.
So I'm just getting rid of the hidden x16 in favor of making it
explicit in an _x16 variant.
Subsequent commit will pivot all the non-sparkler callers to
til_fragmenter_slice_per_cpu_x16().
|
|
Since "ref" renders using arbitrary foreign contexts, it must
explicitly limit their rendering concurrency to its own.
|
|
With the introduction of discoverable on-stream contexts, with
the intention of modules finding them at runtime for nested
rendering, relying exclusively on limiting n_cpus @
til_module_create_context() is no longer adequate.
When the nested rendering makes use of a context created
elsewhere, it can't make any assumptions about what its n_cpus
is, nor should it be attempting to change that value for its use.
So this variant just adds a max_cpus parameter for setting an
upper bound to whatever is found in the context's n_cpus.
The impetus for this is to fix the ref builtin, which you can
currently trick into deadlock by performing a nested threaded
render within a threaded render. What the ref module should be
doing is propagating its own context's n_cpus down as the upper
bound, via this new render variant.
|
|
When profiling compositions it's convenient to suppress some
modules in the settings to see how their omission affects the
FPS.
There's already a "blank" builtin which clears the fragment, but
there's no way to turn the cost to ~zero. This "noop" builtin
does just that, absolutely nothing - it won't even trigger the
implicit "til_fb_fragment_t.cleared = 1" update so whatever
rendering follows will still find an uncleared fragment if that's
what came into the noop.
|
|
This moves the core til_module_setup() functionality out into a
more composable helper with an eye towards all meta-modules using
it for doing their module setup instead of all the ad-hoc stuff
occurring presently.
Since til_module_setup_full() needs more paramaters to influence
its behavior, it's not directly usable as a "setup_func". But is
trivially wrapped into one, which is what til_module_setup() has
now become.
It's in the wrapper that users are expected to do specify what's
necessary for influencing til_module_setup_full() to do what's
appropriate for their needs.
|
|
just quick and nasty hacking to make win32 build again
|
|
This stows the duration (in ticks (which are ms for now)) of a
given module context's most recent, as well as tracking the max,
in til_module_context_t.
For now it's also added to --print-module-contexts output, but
this is still rather primitive and nearly inscrutible in
practice... that output is a flickery and unsorted mess during
playback. But this is just a start.
Ticks may need to move up to microseconds if it'll also be the
units for measuring timings. Right now things are slow enough
that the low-hanging fruit stand out as multiple if not dozens of
milliseconds so it's still useful for now.
|
|
Thin wrapper around gettimeofday(), prolly change the main ticks
stuff over to this too.
|
|
It was too coarse a condition filtering the list on !name.
This change actually looks up non-NULL names to verify it's a
resolvable module name before producing the unfiltered list.
Mostly just to prevent fat-fingered manual module inputs from
resulting in unexpectedly larger and potentially dangerous module
lists in interactive "invalid input" retries. Observed in the
WIP rkt_scener stuff...
|
|
It just happened to be tolerable that the first setting in these
randomized settings instances wasn't ever getting described...
due to the ad-hoc nature of how rtv used them.
But in preparation for rkt_scener which will have "randomize
scene" functionality, as well as interactive (re)configuring of
the scenes, these settings instances need to be more correct to
not break things.
It seems awkward to be duplicating this "Renderer module" desc
here however. But I just want to make progress on the scene
editor for rkt, I suspect this will be revisited in the future.
On a high-level it feels like til_module_setup() should be the
thing producing that desc, and the randomizer just picking the
random settings through that setup func.
|
|
When setting up a nested module, the HERMETIC modules shouldn't
be considered as eligible nor should one be the preffered option
(rtv).
This uses the presence of a parent on the settings as a heuristic
for if it's a nested scenario (no parent == root). When nested
the default changes to "compose" from "rtv", and HERMETIC modules
are omitted from the listed values.
|
|
This was assuming non-NULL res_setup which would assert in
til_module_setup_finalize() which doesn't expect a NULL
res_setup since that's its entire purpose.
It's not a bug that was actually triggered by any callers (yet)
|
|
Slight improvement of CPU utilization for fragmenters using this
strategy...
I noticed tile64 would give better FPS in some scenarios where it
seemed obvious slice_per_cpu() was the appropriate option. And
that turned out to just be by virtue of being able to give idle
threads something to do while busy ones finished what was on
their plate.
So just make the slices a bit more granular than n_cpus... this
may have to be revisited in the future to find the sweet spot,
and may need to be more sophisticated than just multiplying by a
constant factor.
|
|
And just maintain it as the last ticks value after rendering with
the context...
A couple modules were already doing this manually in an ad-hoc
fashion, just make it a general thing.
Updated those modules to reflect the new situation
Especially in a rkt world with modules::mixer doing fades, it
becomes common to render the same context twice in the same frame
for the blending. We need to prevent accelerated animations in
such situations. For now let's just rely on ticks in a delta-T
fashion to prevent animating the context when ticks is the same.
modules::stars in particular needs this fixed up, upcoming commit
|
|
Commit 24911280 made til_setup_t required, and most setup code
has already adopted til_module_setup_finalize() added in
c94e4683 for this purpose.
But til_module_setup()'s fall-through case when there's no
til_module_t.setup() on the module being setup was missed. This
broke running simple modules without a .setup() directly like
--module=roto, oops.
Fix is simple.
|
|
I thought the build was already using -Wall but that seems to not
be the case, maybe got lost somewhere along the line or messed up
in configure.ac
After forcing a build with -Wall -Werror, these showed up.
Fixed up in the obvious way, nothing too scary.
|
|
Module contexts are now discoverable via the stream a la
til_stream_find_module_contexts().
The current architecture has the stream adding a reference to all
the contexts registered. So even if they get unreferenced by
their creators, they will linger on-stream.
There's a gc mechanism til_stream_gc_module_contexts() which can
be used to trigger a cleanup of contexts _only_ referenced by the
stream.
It's unclear as of yet if this is the way to go long-term, but it
lets things work for now and allows some iterating and
experimentation to see where to go next.
|
|
This opens up the possibility of referencing contexts on-stream
by-path anywhere a module may be used:
ref,path=/path/to/existing/context
Currently the path lookup is performed @ render time, and a
reference is taken on the context found there on the first time
it's located. That reference is then held in the ref's context
until its context is destroyed.
There are more details to flesh out, and what probably needs to
happen is some til_stream API for maintaining the reference in
the event that the context at that path gets replaced. Due to
refcounting, the referenced context will persist even if the
stream-resident instance goes away, but there should probably be
a way for that replacement to invalidate the existing references
so they replace theirs with a fresh lookup at the path...
Either way this is a good start. With this addition you can
effectively implement scene transitions in rkt, via the mixer
module, something like (sans proper escaping):
mixer,a_module=ref\,path=/foo/previous/ctxt,b_module=ref\,path=/foo/next/ctxt
|
|
open_memstream() isn't implemented by windows (not even mingw)
|
|
this is very early/unfinished, hence experimental flag
|
|
checkers::fill_module is presently implemented via creating
n_cpus identical module contexts, each having n_cpus=1.
Establishing a set of cloned per-cpu contexts, allowing threaded
rendering using any fill_module, regardless of if that module
internally implements threaded rendering.
This works fine, but creates some awkwardness for a future where
contexts are registered and discoverable within the stream at
their respective setup's path. In the checkers::fill_module
case, there would be n_cpus contexts at the same path since they
share the same til_setup_t. Those need to be dealt with
gracefully, ideally making the clones available to another
potentially clone-needing module (imagine a checkers::fill_module
transitionining to another checkers::fill_module situation, where
the transitioned-to fill_module refers to the context by path, it
should get all the contexts out of the stream as-is)
In this commit I'm adding a more formalized method of creating
multiple contexts from the same set of parameters, in preparation
for a future where module contexts get registered on the stream
at their til_setup_t.path. By putting the cloned creates behind
the til API it should at least be relatively trivial to get the
on-stream context registration to capture the multiple contexts.
|
|
Rather than creating an orphaned settings instance private to
til_module_setup_randomize(), the function now requires the
settings instance be provided.
The one remaining caller of this function is modules::rtv. Now
that rtv is responsible for creating the settings beforehand, and
the settings may be created with a path prefix, rtv gets its
til_module_context_t->setup.path prefixed for all the channel
settings.
Another improvement is now the channel settings instance gets
created from the module name as the settings string. So while
it's not yet possible to sparsely specify settings with others
being randomized, at least now when log_channels=on is in effect,
the printed args include the top-level channel module.
Having proper complete paths for the rtv channel modules is
especially visible in --print-paths output FYI.
An interesting test for exercising all this is:
```
$ src/rototiller --module=rtv,duration=0,context_duration=0,snow_module=none,channels=all,log_channels=on --print-pipes --defaults --go 2>/tmp/channels
in another terminal:
$ tail -F /tmp/channels
```
watch the chaos unfold
|