Documentation

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

Contributing

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:

two space indent

no hard tabs

no trailing spaces at line endings

opening { on the same line as if/while etc

log_message usage where output is needed (eg: for debugging)

// comments not /* comments */, except for doxygen blocks

documentation should fit in 80 columns, code is free to go longer

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:

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.

Miscellaneous

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.

Rendering Overview

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):

find a central minibrot to use as a reference, or else the center pixel

repeat until 'find_ref' (called at end) reports done

for each slice

'fillc' creates a texture with coordinates (and the old iterations and error count at that pixel), which is copied to a vertex buffer

'init' processes that into a full structure for iteration calculations (non-erroneous escaped pixels are filtered out to avoid recomputation)

'approx' computes series approximation coefficients and sets the final values as uniforms, the shader updates the iteration calculation data to the skipped iterations

repeat until 'completion' reports done

'step' performs a block of calculations on each pixel in the buffer

'escaped' cooks any escaped pixels into a texture for colouring

'unescaped' compacts the unescaped pixels tightly in memory

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.

History

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.