Age | Commit message (Collapse) | Author |
|
The existing simulation would always accumulate, eventually
filling the volume with density.
This adds a decay to diminish the density, with the default less
quickly filling the volume vs. before.
|
|
These are making it into the settings strings, it's benign only
because regexps aren't currently being enforced. Fix it up
anyways.
|
|
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 manifests in the current unconfigured rtv glimmer shows, since
the default is a the "none" module when no settings are applied.
But it turns out this isn't just a glimmer problem, "none" is advertised
in the settings as a blanking alternative to snow. So it's actually
broken in rototiller as well.
This fixes it by detecting the nil "none" module's lack of any
prepare_frame or render_fragment methods, and open coding the blanker
with a fb_fragment_zero() inline.
|
|
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.
|
|
These modules are meta modules, and the only place this
information is presented currently is in the rtv module captions
overlaying the visual output of unrelated modules.
So it's rather misleading to put the meta module's author and
license on-screen when what's being shown is arguably just a tiny
fraction of the meta module's contribution.
Rather than bother with constructing license and author lists at
runtime from the modules incorporated by these meta modules,
let's instead adopt a policy of meta modules omit any declaration
of license or authorship outside of the source. This is a simple
solution for now, it can be revisited later if necessary.
Changing the .author member of rototiller_module_t to an
.authors() function pointer wouldn't be difficult. But it does
open up something of a can of worms when considering recursive
dependencies and needing to construct unique authors and licenses
lists from things like nested meta modules. Obviously there
can't be infinite recursion as that would manifest in the
rendering path as well, but what I'm more concerned about is
properly handling potentialy quite long lists. It's already
annoying when rtv has to deal with a long settings string, which
I believe currently is just truncated. The same would have to be
done with long authors/licenses I guess.
In any case, I think it's probably fine to just leave authorship
and license ambiguous when a meta module is shown in rtv. It's
certainly preferable to vcaputo@pengaru.com getting credit for
everything shown in the three meta modules currently implemented,
or more specifically, the two shown in rtv; compose and montage.
Note this required making rtv tolerante of NULL .license and
.author rototiller_module_t members.
|
|
Minor cosmetic consistency fixup
|
|
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...
|
|
This is a quick and dirty jab at normalizing the plasma size to
be independent of the frame size.
I kind of hate this module as-is, it's tempting to discard all
the fixed point stuff and just redo it using floats.. the plasma
itself isn't that attractive as-is either.
But I have other things to work on currently, just wanted to make
it so the plasma doesn't look like a solid color in the montage
tile.
|
|
- move LUT initialization to context create
- minor syntactic changes
|
|
- switch puddle_sample() to 0..1 coordinates to avoid
some pointless extra arithmetic on every pixel
- avoid redundant ->w multiplies in puddle_sample()
- avoid multiplies in inner loops of drizzle_render_fragment()
by accumulating coordinates w/addition instead
I noticed full-screen 'compose' was struggling to keep a full
frame rate on my laptop when testing with the new 'plato' layer.
valgrind profiles showed drizzle as the big hog, mostly the
puddle_sample() function. These changes help but it's still not
great, getting much better will likely become invasive and
crufty. It would be nice to cache the vertical lerp results and
reuse them across puddle_sample() calls when valid, that might be
a useful TODO.
The runner-up is spiro, prolly some low-hanging fruit there as
well, I haven't looked yet.
|
|
now: "drizzle:stars:spiro:plato"
|
|
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.
|
|
In case some code path creates module contexts and renders without
applying settings, it's important to ensure there are defaults.
As-is this would have crashed compose because compose_layers would
have been NULL, and compose_create_context() assumed compose_layers
always contained something useful.
Montage would have been an example of this, though for other reasons
montage has had compose disabled so I don't think anything currently
would have triggered this.
|
|
The threaded rendering backend isn't reentrant and compose could
hypothetically have montage as a layer triggering infinite
recursion.
For now use a big hammer and block compose module from montage.
|
|
Once upon a time montage had to skip stars and pixbouce because
they crashed. That has since been corrected, but the commit which
removed the skips didn't remove the lookups.
This removes the leftover lookups.
|
|
This module needs some love, but it already always supplies 1 to
the open-coded rendering for the tiles. It never should have been
supplying the real num_cpus to module.create_context(), then only
supplying 1 for rendering.
|
|
--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 bit flag for tracking if the fragment has been zeroed
since its last flip/present.
When a fresh frame comes back from flipping, its zeroed state is
reset to false.
When fb_fragment_zero() is called, it checks if zeroed is true,
and skips the zeroing if so.
If zeroed is false, fb_fragment_zero() will zero the fragment and
set the zeroed flag to 1.
This change is preparatory for layering the output of modules in
a compositing fashion. Not all modules are amenable to being
used as upper layers, since they inherently fill the screen with
new pixels every frame. Those modules make good bottom or bg
layers. Other modules perform fb_fragment_zero() every frame
and add relatively few pixels atop a clean slate. These modules
make good candidates for upper layers where this change becomes
relevant.
|
|
This takes a module name or "none", to use the specified module or
do nothing during the channel switching snow_duration.
The default is "snow" like before.
|
|
This renames rtv_channel_t to rtv_module_t and modules to
channels in various places, which arguably should have been in a
separate commit but I'm not up for separating that out at the
moment.
Fundamentally what's happening is every channel is getting its
own context which may persist across channel switches, this
allows watching a variety of channels in a stateful manner before
they get their contexts recreated with re-randomized settings.
For modules without settings it's not terribly interesting, and
I'm thinking modules should probably start deriving some of their
state more directly from the global ticks rather than their own
per-context counters and timers. That way even when their
contexts get recreated with re-randomized settings, there can be
some continuity for ticks-derived state. Deriving position for
instance mathematically from ticks would allow things to be
located continuously despite having their contexts and even
settings changed, which may be interesting.
Anyhow, if you want the previous behavior where contexts are
always recreated on channel switch, just set the value to be
contxt_duration equal to duration.
|
|
Ticket is unnecessarily abstract/opaque of a name for this, it's
simply the sort order. No point making the reader grok whatever
model I was thinking when I wrote it at the time, i.e. tickets at
a butcher counter.
|
|
time() only changes every second, so this had the effect of freezing
the seed a second at a time, affecting all rand() users, when spiro's
create_context() was called more frequently than 1HZ.
When using rtv with channels=spiro,duration=0 the create_context() gets
called every other frame, and the visual results were very broken with
the spiro only actually reseeding every second and the snow between each
frame being static since it too uses rand() for seeding itself.
This whole situation suggests no module should be calling srand(), and
instead rototiller should probably call srand() once at startup and any
modules that wish to use rand with a different seed should use rand_r(),
and maybe rand() just for acquiring the seed like modules/snow does.
|
|
Purely cosmetic change renaming to
rtv_should_skip_module() since the function doesn't actually
skip anything, it just determines the skip.
|
|
This adds a colon-separated channels setting, with a
setting of "all" for the existing all-modules behavior.
Colon was used since comma is already taken by the settings
separator, maybe in the future comma escaping can be added
everywhere relevant but for now just keep it simple.
The immediate value of this setting is telling rtv to limit
itself to a single module, and using its setting randomizer
to automatically observe a variety of the available settings
in action on a specific module, especially during development.
If knobs ever get added in the future I expect this will become
even more interesting for watching specific modules under their
various settings permutations in combination with their knobs
being twisted - especially if rtv reconstructs random signal
generator chains for the "knob-twisters" on every channel switch.
An immediately interesting TODO complementing this particular
change would be optionally preserving module contexts across
channel switches, so when the same module is revisited it resumes
where it was last seen. But this conflicts with settings changes
on channel switching, since contexts should probably always be
recreated when settings change - but that's probably a
module-specific detail that modules should just be robust enough
to tolerate as in they'd safely ignore settings changes without a
context recreate, or apply them if they safely can without a
context recreate... TODO.
|
|
This adds three rtv settings:
duration, caption_duration, snow_duration
|
|
This commit adds a few settings for visualizing the octree BSP:
show_bsp_leafs (on/off):
Draw wireframe cubes around octree leaf nodes
show_bsp_leafs_min_depth (0,4,6,8,10):
Set minimum octree depth for leaf nodes displayed
show_bsp_matches (on/off):
Draw lines connecting BSP search matches
show_bsp_matches_affected_only (on/off):
Limit drawn BSP search matches to only matches actually
affected by the simulation
The code implementing this stuff is a bit crufty, fb_fragment_t
had to be pulled down to the sim ops for example and whether that
actually results in drawing occurring during the sim phase
depends on the config used and how the particle implementations
react to the config... it's just gross. This matters because the
caller used to know only the draw phase touched fb_fragment_t,
and because of that the fragment was zeroed after sim and before
draw in parallel. But now the caller needs to know if the config
would make sim do some drawing, and do the fragment zeroing
before sim instead, and skip the zero before draw to not lose
what sim drew. It's icky, but I'll leave it for now, at least
it's isolated to the sparkler.
|
|
These don't actually do anything yet
|
|
Just stubbed out for now, wanting to restore some octree overlays like
the old standalone sparkler had. Those can be wired up to settings so
rtv can occasionally show the spatial partition and matched particles.
|
|
My current version of mingw in debian 9.11 doesn't seem to have
rand_r(), so let's just use plain rand() and lose the improved
parallelization on win builds.
|
|
Modulo ticks by 2*M_PI to preserve precision by constraining the float
to 2*M_PI radians.
|
|
Most modules find themselves wanting some kind of "t" value increasing
with time or frames rendered. It's common for them to create and
maintain this variable locally, incrementing it with every frame
rendered.
It may be interesting to introduce a global notion of ticks since
rototiller started, and have all modules derive their "t" value from
this instead of having their own private versions of it.
In future modules and general innovations it seems likely that playing
with time, like jumping it forwards and backwards to achieve some
visual effects, will be desirable. This isn't applicable to all
modules, but for many their entire visible state is derived from their
"t" value, making them entirely reversible.
This commit doesn't change any modules functionally, it only adds the
plumbing to pull a ticks value down to the modules from the core.
A ticks offset has also been introduced in preparation for supporting
dynamic shifting of the ticks value, though no API is added for doing
so yet.
It also seems likely an API will be needed for disabling the
time-based ticks advancement, with functions for explicitly setting
its value. If modules are created for incorporating external
sequencers and music coordination, they will almost certainly need to
manage the ticks value explicitly. When a sequencer jumps
forwards/backwards in the creative process, the module glue
responsible will need to keep ticks synchronized with the
sequencer/editor tool.
Before any of this can happen, we need ticks as a first-class core
thing shared by all modules.
Future commits will have to modify existing modules to use the ticks
appropriately, replacing their bespoke variants.
|
|
This commit adds some fun features to the starfield:
- normalize aspect ratio to fragment size
- rolling viewport
- rotating viewport (with rate option)
|
|
The existing code conflated the rendered frame dimensions with
what's essentially the virtual camera's film dimensions. That
resulted in a viewing frustum depending on the rendered frame
dimensions. Smaller frames (like in the montage module) would
show a smaller viewport into the same scene.
Now the view into the scene always shows the same viewport in
terms of the frustum dimensions for a given combination of
focal_length and film_{width,height}.
The rendered frame is essentially a sampling of the 2D plane
(the virtual film) intersecting the frustum.
Nothing is done to try enforce a specific aspect ratio or any
such magic. The caller is expected to manage this for now, or
just ignore it and let the output be stretched when the aspect
ratio of the output doesn't match the virtual film's aspect
ratio.
In the future it might be interesting to support letter boxing or
such things for preserving the film's aspect ratio.
For now the ray module just lets things be stretched, with
hard-coded film dimensions of something approximately consistent
with the past viewport.
The ray module could make some effort to fit the hard-coded film
dimensions to the runtime aspect ratio for the frame to be
rendered, tweaking things as needed but generally preserving the
general hard-coded dimensions. Allowing the frustum to be
minimally adjusted to fit the circumstances... that might also be
worth shoving into libray. Something of a automatic fitting
mode for the camera.
|
|
|
|
Using the new puddle lib throw some raindrops on the framebuffer
|
|
Switch to working through the set of modules in a random order,
randomizing the order once per cycle.
This way no modules get starved for display, which was pretty common
in the old method.
|
|
draw stars as circles that get larger as the approach the camera
|
|
This commit adds a module that emulates a spirograph
|
|
Ideally the number of modules can tile without leaving gaps, but
as rototiller evolves over time modules are added piecemeal so
try accomodate those awkward layouts.
|
|
|
|
- fix bug for square fragments
- use create and destroy context hooks instead of globals
- refactor to allow fragment resizing
- handle extremely small fragments gracefully
|
|
- use a context not globals
- use floats and a "unit cube" to simulate the starfield
|
|
Since 7a77cc1a landed this is no longer true, the .random member
will be used to support randomizing non multiple-choice settings.
|
|
While the montage doesn't deeply thread the per-tile/module rendering,
the per-frame rendering is threaded with a work unit granularity of
every module's tile.
Meaning every module renders its tile in a single thread, but the
tiles are all rendered in parallel.
For the most part this works, and will only work better as more modules
are added to rototiller increasing the granularity. In the mean time
it's a bit coarse and some modules can be a lot more costly to render
than others, and there can be a shortage of modules to schedule on idle
CPUs.
It would be an interesting task to try make each module's tile get
subfragmented elastically. I didn't make any attempt to do that, but
it might even be worthwhile on hidpi screens where even those small
tiles may have a whole lot of pixels, especially on manycore CPUs.
|
|
|
|
This requires a forward declaration of v3f_t and changing din()
to take a v3f_t *.
The swab module needed updating to supply a pointer type and a
v3f_t definition.
This is being done so din.h users can have their own v3f
implementations. I might consolidate all the duplicated vector
code scattered throughout the libs and modules, but for now I'm
carrying on with the original intention of having modules be
largely self-contained. Though the introduction of libs like
ray and din has certainly violated that a bit already.
|
|
Since snow_context_t needs another member anyways, stick n_cpus in there
to inform the fragmenter of precisely how many fragments to make.
This renderer doesn't benefit from tiling or any such locality, so it uses
the slice fragmenter and really only benefits from as many fragments as there
are CPUs. Any additional fragments is just wasted fragmenting overhead.
|
|
Snow was already threaded, but used a global seed with rand_r() meaning
the CPUs were hammering on the same address. There wasn't any locking or
atomics, as it isn't terribly critical when generating white noise if the
seed access is racy. But the writes still caused cache lines to ping-pong.
This commit gives a ~15.5% speedup in my measurements on an i7-2640M.
Note without the padded union, using just an array of ints, zero gain
is realized. I used a padding of 256 just to have some headroom, x86
is 64 but other CPUs vary, POWER9 is 128 for example.
|
|
This repurposes the generic fb_fragment_tile_single() to better fit
the montage use case.
Partially covered areas are simply skipped, and tiles no longer need
to be square.
In determining the tile width and height, I'm just using the sqrt of
the number of modules and dividing the frame width and height. But
when the sqrt has a fraction, it's rounded up on the width divide
and rounded down on the height divide. So the width gets the extra
column of tiles, and the height just throws away the fraction.
I think it's OK for now, until someone gets a bug up their ass and
wants to avoid having vacant tiles in the bottom right corner when
the number of modules doesn't cooperate.
One problem with the just skipping partially covered areas is they
don't get zeroed out - no fragment is ever generated for them.
To fix that there will prolly have to be a fb_fragment_zero() of
the frame @ prepare :(. I guess it wouldn't be the end of the
world if the fragmenter itself zeroed out skipped regions. It's
kind of an ugly layering violation but this is a private montage-
specific fragmenter.
|