Age | Commit message (Collapse) | Author |
|
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.
|
|
|
|
Fixes silly cosmetic error in configure output for checking libdrm...
|
|
With fb backends entirely abstracted behind fb_ops_t, this is
no longer necessary.
|
|
This uses a simple fixed 640x480 windowed mode (for now).
The SDL2 Renderer & Texture API is used for vsync-synchronized presents.
There's probably excessive copying going on because the rototiller fb
code manages pages and flips but SDL2 doesn't really expose low-level
control of such things.
This backend is quite useful for development purposes, allowing quick
iteration in a windowed environment.
Note this is just the backend implementation, it's dormant code but
trivially activated.
|
|
This should probably be split into multiple commits, but
for simplicity sake it's all cut over at once.
drm_fb.c sees major changes, migrating the remaining drm-specific bits
from drmsetup into it, behind the settings API.
rototiller.c sees a bunch of scaffolding surrounding the settings API
and wiring it up into the commandline handling and renderers and video
backends.
fb.[ch] see minor changes as settings get plumbed to the backend
drmsetup.[ch] goes bye bye
|
|
Preliminary means for interactively configuring settings and defaults
|
|
Settings will be used to express configurable parameters in the
rendering modules and fb backends.
The goal is to address both commandline argument setting of parameters,
automatic use of defaults, as well as interactive configuration
including the outputting of the resulting settings in a form usable as
a commandline for future reuse.
Since settings can be numerous and highly varied from one module or
backend to another, a form similar to the Linux kernel's cmdline or
QEMU's approach has been adopted.
For example, a complete DRM backend, card selection and config would be:
rototiller --video=drm,dev=/dev/dri/card0,connector=LVDS-1,mode=1024x768@60
If any of the above were omitted, then the missing settings would be
interactively configured.
If you added --defaults, then any omissions would be automatically
filled in with the defaults.
i.e.
rototiller --video=drm,dev=/dev/dri/card4 --defaults
would use the preferred connector and mode for that card.
rototiller --video=drm --defaults
would do the same but also default to the /dev/dri/card0 path.
for brevity, I omitted rendering modules from above, but the same
approach applies simply to --module=:
rototiller --module=sparkler --video=drm --defaults
If you ran rototiller without any arguments, then a fully interactive
setup would ensue for module and video.
If you ran rototiller with just --defaults, then everything is
defaulted for you. A default rendering module will be used (the
original roto renderer, probably).
Note that this commit only adds scaffolding to make this possible,
none of this is wired up yet.
|
|
Largely mechanical copying of the drm code into the new fb_ops_t
abstraction. Dormant for now.
|
|
This is a simple worker thread implementation derived from the ray_threads
code in the ray module. The ray_threads code should be discarded in a
future commit now that rototiller can render fragments using threads.
If a module supplies a prepare_frame() method, then it is called
per-frame to prepare a rototiller_frame_t which specifies how to divvy
up the page into fragments. Those fragments are then dispatched to a
thread per CPU which call the module's rendering function in parallel.
There is no coupling of the number of fragments in a frame to the number of
threads/CPUs. Some modules may benefit from the locality of tile-based
rendering, so the fragments are simply dispatched across the available CPUs
in a striped fashion.
Helpers will be added later to the fb interface for tiling fragments, which
modules desiring tiled rendering may utilize in their prepare_frame()
methods.
This commit does not modify any modules to become threaded, it only adds
the scaffolding.
|
|
This is unoptimized, with a palette slapped together in vim, but still
pretty neat!
|
|
|
|
Restoring some organizational sanity since adopting autotools.
|