Age | Commit message (Collapse) | Author |
|
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.
|
|
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.
|
|
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.
|
|
Preparation for eliminating open_memstream() usage...
|
|
this is very early/unfinished, hence experimental flag
|
|
This makes TIL_MAXCPUS a proper thing
|
|
Finishes build/fs part of modules/rocket->modules/rkt rename
started in previous commit.
|
|
With taps more or less fully implemented, it seems appropriate to
get rid of the stubbed out knobs for now.
Taps don't express the same things about range and usage knobs
aspired towards, but they don't preclude adding such things
either. But it seems clear that the way knobs were stubbed won't
be complementing taps as things stand currently to add those
aspects.
|
|
This just stubs out a rocket meta module that renders with
another module.
Future commits will integrate GNU Rocket here.
When recursive settings formally lands you'll be able to nest as
much settings content as necessary for the underlying module
used, as part of the rocket settings. That should enable
describing stuff like complex compose scenarios for rocket to
sequence.
|
|
Preparatory commit for experimenting with a GNU Rocket
integration for controlling the stream pipes on a timeline.
Since rocket doesn't support things like arbitrary strings, it's
not a natural fit for rototiller where the obvious thing would be
to describe scene compositions as settings strings as if you were
invoking rototiller.
But a temporary hack might be to just tell a rocket module
up-front all the scenes as settings strings you provide to its
setup. Those get assigned numeric identifiers, then rocket
tracks can control when they come on/off numerically. It just
requires describing all the scenes up front rather than in the
pattern editor which is less than ideal.
Being able to experiment with this half-ass solution may prove
useful anyways, and shouldn't be too much work.
|
|
Until now there's just been a forward declared type for
til_fb_fragment_t.stream's type, and it's been completely unused.
The purpose of the stream is to provide a continous inter-frame
object where information can be stored pertaining to the stream
of frames.
Right now, that information is limited to emergent "pipes" formed
by using taps against a given stream. Taps at new paths in the
stream become added as pipes for those paths, with the
responsible tap hooked in as the driving tap. Taps at existing
paths become diverted to the driving taps, enabling potential for
external drivers for tapped variables.
This commit only adds the implementation, nothing is actually
using it yet.
|
|
Presently just for hashing paths and names
|
|
The previous commit implemented taps in a way requiring
allocations and cleanup. Let's experiment a bit and just make
them absolutely minimal named typed variable+indirection
bindings.
The helpers are retained, but converted to initializers rather
than new() style constructors. They provide type-checking of the
variable and indirection pointer, and prevent incorrect TIL_TYPE
values going in til_type_t.type for the supplied bound
elems+ptr.
|
|
The idea here is for modules to bind variables to names @ context
create time w/til_tap_new(). Pseudo-code sample:
```
typedef struct foo_context_t {
struct {
til_tap_t *position;
} taps;
struct {
v2f_t position;
} vars;
v2f_t *position;
} foo_context_t;
foo_context_t * foo_create_context(void)
{
foo_context_t *foo = malloc(sizeof(foo_context_t));
/* This creates an isolated (pipe-)tap binding our local position variable and pointer
* to a name for later "tapping" onto a stream.
*/
foo->taps.position = til_tap_new_v2f(&foo->position, "position", 1, &foo->vars.position);
return foo;
}
foo_render(foo_context_t *foo, til_fb_fragment_t *fragment)
{
if (!til_stream_tap(fragment->stream, &foo->pipes.position)) {
/* got nothing, we're driving */
foo->position->x = cosf(ticks);
foo->position->y = sinf(ticks);
} /* else { got something, just use foo->position as-is */
draw_stuff_using_position(foo->position);
}
```
Note til_stream_tap() doesn't exist yet, this commit only adds
the tap (til_tap_new()).
The stream will probably implement a hash table for looking up
the tap by name, verifying its type and nelems match if found,
and update the pointer to point at the instance actually driving
for the name. (in the example that's the foo_context_t.position
pointer which draw_stuff_using_position() then dereferences)
Also note that in the example, "position" alone is too simplistic
for handling complex real-life compositions where a given module
may recur in a given stream. That identifier would need to be
derived from the module's context/setup producing a distinctly
unique path to the tap. i.e.
"/compose/layers/checkers/fill_module/foo:position" or something,
to be dynamically generated. And the foo:position syntax isn't
set in stone either. Maybe foo/position would suffice, the whole
heirarchical syntax needs to be thought through and defined yet.
Since the absolute path to the tap would be setup-dependent, there
will have to be some glue tying together the setup used by the
context and the tap within that context. The stream may be the
natural place where that occurs.
This also currently is barebones in terms of the tap types
supported. The only higher-order types are rudimentary 2-4d
vectors and 4x4 matrices. There are no semantics associated
with the types, and it's likely in the future either the tap
types themselves will expand to be semantic. Think things like
a camera type, composed both a point and direction vector.
As-is the few higher-order types in til_tap.h are simply forward
declared, and at least in terms of the taps alone further type
visibility isn't necessary.
It may make more sense to build upon these bare taps with another
semantic layer bringing the higher-order types to the table in a
more concrete form. All those higher-order types would then be
composed from the bare taps.
There's some conceptual overlap with the knobs stubbed out in
til_knobs.h as well. I think this likely at least partially
replaces what's there, and what it doesn't will probably end up
somewhere else.
|
|
After reading about the Dreamachine[0], I wanted to experience
this phenomenon. The javascript-based web implementations
struggled to hold a steady 10Hz rate and would flicker like
crazy, so here we are.
Only setting right now is period=float_seconds, defaults to .1
for 10Hz.
One limitation in the current implementation is when the frame
rate can't keep up with the period the strobe will just stick on
without ever going off, because the period will always be
expired. There should probably be a setting to force turning off
for at least one frame when it can't keep up.
[0] https://en.wikipedia.org/wiki/Dreamachine
|
|
Now that there's the mem_fb backend, there's no need to disable
producing a rototiller binary in lieu of libdrm and libsdl2.
This commit also rejiggers some of the DEFAULT_VIDEO junk in
main.c to ensure it falls back on "mem" should there be no drm or
sdl2.
For now I'm going to leave the AM_CONDITIONAL junk surrounding
enabling rototiller in configure.ac, the define can just be
ignored for now.
|
|
The immediate impetus for adding this is to enable running
rototiller even on headless machines just for the sake of getting
some FPS measurements.
It'd be nice to get a sense for what FPS rototiller would
experience on larger modern machines like big EPYC or
Threadripper systems. But it seems most of those I can get
access to via others running them on work hardware or the like
can at most just run it over ssh without any display or risk of
disrupting the physical console.
But this is probably also useful for testing/debugging purposes,
especially since it doesn't bother to synchronize flips on
anything not even a timer. So a bunch of display complexity is
removed running with video=mem as well as letting the framerate
run unbounded.
Having said that, it might be nice to add an fps=N setting where
mem_fb uses a plain timer for scheduling the flips.
Currently the only setting is size=WxH identical to the sdl_fb
size= setting, defaulting to 640x480.
|
|
This introduces a very naive unoptimized moire interference
pattern module, it's rather slow complete with a sqrtf() per
pixel per center.
|
|
Preparatory commit for embedding a til type in the module
contexts, similar to til_setup_t for the module setups.
This will provide a convenient way to embed seed and n_cpus in
every module context, without having to implement that yourself.
But it also makes it so modules with no need for a context can
continue not implementing those methods, without obstructing
libtil from transparently doing it anyways with a bare
til_module_context_t.
This is kind of important as the current architecture made it
difficult to do things like create contexts with explicit n_cpus,
like in composite/meta modules which are already threaded and
wish to run embedded modules with n_cpus=1.
With this addition, n_cpus could be specified at context create
time, and it will always become remembered in the
til_module_context_t regardless of what the module implements.
That way it can definitely be carried into the prepare/render
methods, with no opportunity for disconnect between what was
passed to context create and what goes to the render methods.
Nothing is functionally changed in this commit alone, subsequent
commits will actually make use of it and realize what I've said
above.
|
|
Mostly for compositing purposes, here will be a corpus of 2D
shapes, parameterized/procedurally generated and able to rotate
and perhaps have other dynamics added.
What shapes are there presently I had started implementing in
checkers as "styles", before realizing they really should just be
a separate module checkers can call into.
Not terribly interesting by itself, but as blinds and checkers
demonstrated, these things deliver a lot of value in
compositional situations. They're creating the palette to draw
from.
|
|
This adds a voronoi diagram module, which when used as an overlay
produces a mosaic effect.
Some settings:
cells=N number of voronoi cells
randomize={on,off} randomizes the cell locations every frame
dirty={on,off} uses a faster sloppy/dithery-looking method
Some TODO items:
- use a more space efficient representation of the distance
buffer, maybe use uint16_t relative offsets into the cells
rather than pointers - capping their quantity to 64KiB
- anti-alias edges between cells
|
|
For use when setup functions allocate their private setup to
return in *res_setup.
They specify the size of their private setup, and supply the free
function to use. This may be libc's free() when it's a simple
setup struct, or a bespoke free function when deep/complex
freeing is required for cleanup.
It's expected that callers will be embedding til_setup_t at the
start of their private setup struct, and returning a pointer to
this in *res_setup which would be the same value as a pointer to
to their private setup struct.
|
|
Preparatory commit for providing a res_setup type to replace
void*.
The impetus for this isn't just pursuit of less void*, but
primarily implementing setup freeing by embedding this struct
into the private setup types.
An alternative method of adding setup freeing would have been to
introduce something like til_module_t.free_setup(). But that
would require having the til_module_t on hand, and the whole
setup machinery is more generalized than til_module_t anyways.
This way anything can simply embed the struct in their private
setup instance and return the pointer to that in *res_setup.
They should always be able to find their containing struct's
offset from the til_setup_t* they returned. Either by using
container_of(), or simply placing it at the start of the private
setup struct.
|
|
This adds a checkers style overlay module, it's not terribly
interesting but may be made more useful if modules start
differentiating themselves as substantial vs. overlay effects.
It'd be nice if rtv/compose could automagically apply and
randomize overlay modules atop others, which would make use of
this type of thing as well as encourage more small modules like
these be written.
|
|
This isn't super interesting but I might just start adding
simplistic overlay style modules for compositing/transition use.
|
|
Now that there's a decoupled libtil usable by alternative
frontends by vendoring rototiller, the build should support
fb-less rototiller-less configurations.
In lieu of this change glimmer's build requires sdl2 despite not
actually utilizing sdl_fb. Now that shouldn't be necessary,
should there be neither libdrm or sdl2 present we'll only produce
libtil and no rototiller binary at all.
|
|
This is totally opt-in for libtil callers, but is a step
towards enabling uniform cli invocations across frontends.
The help side of this is particularly janky, but since what's
appropriate there is directly related to the args parsing it
seems appropriate to bring along. The janky part is the
implicit output formatting assumptions being made, as-is it
doesn't really lend itself well to being augmented into broader
frontend help output. Alas, this is rototiller playground, so
let's just go easy and assume frontends will largely spit out
whatever this provides - or completely replace it if appropriate.
|
|
Largely mechanical rename of librototiller -> libtil, but
introducing a til_ prefix to all librototiller (now libtil)
functions and types where a rototiller prefix was absent.
This is just a step towards a more libized librototiller, and til
is just a nicer to type/read prefix than rototiller_.
|
|
This is a first approximation of separating the core modules and
threaded rendering from the cli-centric rototiller program and
its sdl+drm video backends.
Unfortunately this seemed to require switching over to libtool
archives (.la) to permit consolidating the per-lib and
per-module .a files into the librototiller.a and linking just
with librototiller.a to depend on the aggregate of
libs+modules+librototiller-glue in a simple fashion.
If an alternative to .la comes up I will switch over to it,
using libtool really slows down the build process.
Those are implementation/build system details though. What's
important in these changes is establishing something resembling a
librototiller API boundary, enabling creating alternative
frontends which vendor this tree as a submodule and link just to
librototiller.{la,a} for all the modules+threaded rendering of
them, while providing their own fb_ops_t for outputting into, and
their own settings applicators for driving the modules setup.
|
|
Just a fun little swarm based loosely on 80s-era boids
It would be interesting to make stuff like the # of particles
and the weights runtime configurable, or exposed as knobs.
Using a Z-buffer for occlusions and perhaps shading by depth might
make a significant improvement on the visual quality. It might also
be interesting to draw the particles as lines connecting their current
position with their previous, instead as pixels. Or fat pixels like
stars...
|
|
plato implements very simple software-rendered 3D models of
the five convex regular polyhedra / Platonic solids
Some TODO items:
- procedurally generate vertices at runtime
- add hidden surface removal setting (Z-buffer?)
- add flat shaded rendering setting
- add gouraud shading, maybe phong too?
- show dual polyhedra
This was more about slapping together a minimal 3D wireframe
software renderer than anything to do with polyhedra, convex
regular polyhedra just seemed like an excellent substrate since
they're so simple to model.
|
|
--module=compose,layers=first:second:third:...
this draws the named modules in the order listed, overdrawing the
output of the previous layers in a cumulative fashion.
|
|
This adds a small framework of sorts for creating and composing signal
generators.
Two generators are implemented at this time; sig_ops_sin and sig_ops_mult
sig_ops_sin accepts a hz variable and will produce a sine wave of that
frequency.
sig_ops_mult accepts two sig_t generators and multiplies their outputs
Callers may construct their own sig_ops_t ops structs and supply them to
sig_new(), but it's expected that libs/sig will grow a collection of
commonly used generators which can then be used by simply passing their
sig_ops_$foo to sig_new().
See the test code at the bottom of libs/sig/sig.c for some contrived
sample usage. Note by composing multiple sig_ops_sin generators with
a sig_ops_mult generator, one can already easily construct a synth-like
LFO generator.
Some obvious todos are to add triangle/sawtooth/square wave generators.
More compositional generators may be interesting as well, like additive
and subtractive for example. Those will need to implement clipping, as
it's expected that the generators *always* stay within unity (0-1).
No modules use this yet, but I expect to wire this up to rtv for driving
knobs.
|
|
This is intended for modules to expose bindings for floats affecting
rendering output that may be varied at runtime frame-to-frame.
See the comment in knobs.h for more information.
This commit only introduces the concept, no modules utilize it yet.
|
|
Using the new puddle lib throw some raindrops on the framebuffer
|
|
These were commonish in the 90s demo days, done as a library to encourage
use by different modules.
You can simply render this directly onto a frame buffer like the old days,
or sample it as a height map or density field for more complex compositions.
|
|
This commit adds a module that emulates a spirograph
|
|
|
|
This is somewhat unfinished as it uses the generic tiled fragmenter
that's not interested in appearances but prioritizes total coverage
and simplicity.
Montage should have its own tiler that can produce non-square and even
non-uniform tile dimensions, prioritizing filling the screen with
mostly-uniform tiles.
But that's a TODO item, this is good enough for now and exercises some
fragment details previously irrelevant and often ignored/broken in
modules.
The pixbounce module in particular seems completely broken with small
fragment sizes.
|
|
This maps a different Z-slice through the noise field to each color
channel. The slices are moved up and down through the field over
time, and the size of the area each color samples is tweaked a bit
to make them less coherent with the noise field cells.
It could be improved, but I think the output is already neat enough
to be worth sharing.
|
|
This is a 3D noise field addressed as a unit cube.
The caller supplies the resolution of the noise field in three
dimensions.
I've just pulled in my v3f.h here, but it probably makes sense to
later on move vector headers into libs/ and share them. Later.
It's called din as in noise, because it's shorter than perlin and
noise.
|
|
This is as basic as it gets, the only fanciness is it recognizes
newlines and supports horizontal and vertical justification.
As this is intended to be run from potentially threaded fragmenter
renderers, it receives a fragment and *frame* coordinates for the
text to be rendered. If the text doesn't land in the given fragment,
nothing gets drawn.
Currently this is not optimized at all. There's a stubbed out rect
overlap test function which could be used to avoid entering the
text rendering loop for fragments with zero overlap, that's an obvious
low-hanging fruit optimization. After that, skipping characters
that don't overlap would be another obvious thing.
As-is the text render loop is always entered and the bounds-checked
put pixel helper is used. So every fragment will incur the cost of
rendering the full string, even when it's not visible.
For the rtv captions this isn't a particularly huge deal, but stuff
to improve upon in the future.
|
|
The rtv module needs to show some captions, so I'm adding a minimal
bitmap ascii text renderer.
|
|
I wanted to add some noise to the rtv module and figured why not
just add a snow module and make rtv pass through it briefly when
switching modules.
It's not interesting by itself, but as more composite/meta modules
like rtv get made it might be handy beyond rtv.
|
|
This is sort of a meta renderer, as it simply renders other
modules in its prepare_frame() stage. They're still threaded
as the newly public rototiller_module_render() utilizes the
threading machinery, it just needs to be called from the serial
phase @ prepare_frame().
I'm pretty sure this module will leak memory every time it changes
modules, since the existing cleanup paths for the modules hasn't
needed to be thorough in the least. So that's something to fix
in a later commit, go through all the modules and make sure their
destroy_context() entrypoints actually cleans everything up.
See the source for some rtv-specific TODOs.
|
|
|
|
This implements near verbatim the code found in the paper titled:
Real-Time Fluid Dynamics for Games
By Jos Stam
It sometimes has the filename GDC03.PDF, or Stam_fluids_GDC03.pdf
The density field is rendered using simple linear interpolation of
the samples, in a grayscale palette. No gamma correction is being
performed.
There are three configurable defines of interest:
VISCOSITY, DIFFUSION, and ROOT.
This module is only threaded in the drawing stage, so basically the
linear interpolation uses multiple cores. The simulation itself is
not threaded, the implementation from the paper made no such
considerations.
It would be nice to reimplement this in a threaded fashion with a
good generalized API, then move it into libs. Something where a unit
square can be sampled for interpolated densities would be nice.
Then extend it into 3 dimensions for volumetric effects...
|
|
This module displays realtime battle for domination simulated
as 2D cellular automata.
This is just a test of the backend piece for a work-in-progress
multiplayer game idea. The visuals were kind of interesting to
watch so I figured may as well merge it as a module to share.
Enjoy!
PS: the results can vary a lot by tweaking the defines in submit.c
|
|
This is the first step of breaking out all the core rendering stuffs
into reusable libraries and making modules purely compositional,
consumers of various included rendering/effects libraries.
Expect multiple modules leveraging libray for a variety of scenes and
such. Also expect compositions mixing the various libraries for more
interesting visuals.
|
|
|