Tips for hacking on mightmandel.
There are some source code comments formatted for the doxygen tool. To extract the documentation (include the user documentation) to HTML:
make -C doc
A good place to start browsing is then:
doc/mightymandel/index.html
Read man gittutorial
first if you're not familiar with git.
How to contribute your changes (bug fixes, new features, ...):
git checkout master git pull git checkout -b my-new-stuff # edit files, make changes git add your-changed-files git commit # write a short description, the first line is the most important git format-patch master # then email the patches as attachments
Try to split each distinct set of changes into different commits (eg: a bug fix in one file and a new feature in another file should be two commits). On the other hand, changes in multiple files for the same bug-fix or feature should be in one commit. Make sure it compiles before you commit, and preferably make sure it runs and does the right things without breaking other stuff.
Alternatively to git format-patch
and emailing, make your repository available online. https://gitorious.org has tools for forking repositories and submitting merge requests, though I've not used them much so can't offer any tips.
Try to keep to the code style of the rest of the code:
And unlike the rest of the code (so far), try to add descriptive comments: high-level things, like what the function does, not low level things like "add a to b giving c" - admittedly mpfr can be somewhat asm-like, but better to group a few lines together with a single comment with an expression.
See the BUGS and TODO files for ideas of things that could be worked on. Some things are quite easy, like adding translation support:
https://gitorious.org/maximus/mightymandel/commit/7f11b163b4be64f4f3c24a523b45a142c80e6fb1
Some things are more involved, like adding rotation support (it would require a lot of small changes in a lot of files, all needing to be consistent). And other things are really hard, like making de/no-de switching work at runtime.
Use <stdbool.h> for bool
instead of int
where appropriate.
Add a D;
after each line with an OpenGL call. This macro is defined in mightymandel.h and logs any OpenGL errors, with flood control.
Before release, or after large changes, run the test suite and (if releasing) update the TESTING file.
Program components:
component | description |
---|---|
mightymandel | main program GUI using glfw3 |
startup | parse command line arguments |
parse | parse parameter file formats |
render | higher-level details of rendering |
record | image output |
interact | everything to make GUI user input work |
tiling | handle state for tiled rendering |
zoom | handle state for zoom sequence rendering |
OpenGL rendering:
component | description |
---|---|
fp32 | plain rendering with single precision floating point |
fp64 | plain rendering with double precision floating point |
fpxx | perturbation rendering with double precision floating point |
colour | take the raw results data and colour it to rgb |
fillc | fill an image with initial coordinates and copy to VBO |
init | set up initial in-progress data from initial coordinates |
approx | series approximation initialization |
step | perform some iteration calculations on in-progress data |
escaped | filter in-progress data and emit escapees as raw results |
unescaped | filter in-progress data and emit non-escapees |
Glitch Correction:
component | description |
---|---|
atom | find periods and atoms (hyperbolic components, minibrots) |
blob_set | store a collection of blobs (glitched regions) |
find_ref | detect glitched regions and find new reference points |
ref_set | store a collection of reference points |
Utilities:
component | description |
---|---|
complex | simple wrappers around mpfr for easier complex arithmetic |
logging | don't use printf for debugging or output, use this instead |
shader | compile shaders from GLSL and link them into programs |
utility | misc stuff |
The high-level process is slightly confused in the code due to a callback system in render.c (which is a legacy from old versions using gtk but still there to maintain user interface responsiveness). It looks like this for fpxx (fp32 and fp64 are broadly similar with some steps removed):
Most of the computation uses a ping-pong technique between VBOs with transform feedback. The final step (to display the image) uses the 'colour' module, which uses a fragment shader to colour each pixel in the raw iteration texture.
v15 fixed a few bugs in the ping-pong VBO handling (the extra approx step was confusing things and made it tricky to get all of fp32/fp64/fpxx working at the same time), and also a stupid bug where the active count (number of unescaped pixels being iterated) wasn't updated correctly leading to massive corruption.
Previously (v14 and earlier) mightymandel had a lot of shared mutable global state. This meant programming required keeping track of which bits were used where, and when it was safe (or even expected) to modify them, together with a lot of undocumented invariants that when messed up would cause weird issues.
This was hell.
After v14 I refactored the code to use much less shared mutable global state. This does mean copying state from one place to another more often, but it's now done in a controlled way at specific points in the control flow, which makes it a lot safe and easier to understand.
Structures are generally visible in headers, but consider them read-only apart from in code within the corresponding implementation file. Visible structures allow other headers to make composite structures, and if used read-only avoids having to write a bunch of getter function boilerplate.
Previously (v14 and earlier) mightymandel control flow was mostly based on a callback architecture. When one task was done it would set an idle function pointer to the next task, and the main loop would just call the idle pointer repeatedly. This lead to obvious headaches working out what was going on, and the GUI needed to set flags to let the idle function tasks know that data it used had changed and the task was no longer needed. Part of this is a legacy from earlier versions implemented using glut and gtk, and the other part is that tasks need to be broken up into small chunks to keep the GUI responsive to user input.
After v14 the main loop is a lot saner. Callbacks from user interface interactions modify a data structure in interact.c. After the main loop polls for events (which makes glfw3 call callbacks), it checks the "updated" flag in the data structure, which determines if rendering should be restarted with new viewing parameters. It also copies the visualisation parameters at this point which don't need rendering to be restarted (things like glitch visualisation and colouring weight).
There are also distinct modes of operation ( –one-shot –tile –zoom etc), in place of the previous mess of different flags in different structures and tests all over the place.