# MegaFractal

A minimal C++ + OpenCL renderer for Ultra Fractal `.upr` parameter files.
Parses UF formula language, JIT-translates it to OpenCL C, and renders on
the GPU. Two front-ends: a CLI and an SDL2 + ImGui preview.

## Build

Requires CMake 3.16+, a C++17 compiler, an OpenCL ICD, and zlib. SDL2
(optional) enables the GUI.

```sh
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
```

| Option | Default | |
|---|---|---|
| `SAFE_MODE` | `ON` | Bound formula loops to prevent GPU hangs |
| `BUILD_GUI` | `ON` | Build the SDL2 + ImGui preview |

## Formula cache

Most demo scenes pull in third-party formulas from the public
[UF formula database](http://formulas.ultrafractal.com/) plus UF's bundled
`Standard.{ucl,ufm,uxf}`. Run one of these once before rendering, to
populate `UF_formulas/`:

```sh
python scripts/fetch_formulas.py                                    # any OS
powershell -ExecutionPolicy Bypass -File scripts\fetch_formulas.ps1 # Windows, no Python
```

Both scripts copy the bundled `Standard.*` stubs from `scripts/standard_stub/`
and download ~77 third-party `.ucl`/`.ufm`/`.uxf` files into `UF_formulas/`.
Pass `--force` (Python) or `-Force` (PowerShell) to overwrite. If a UPR
references an entry not in the stub, paste your real `Standard.ucl` from
your UF install over the stubbed copy.

## Render a still

```sh
build/mf <input.upr> [output.png] [options]
```

| Flag | |
|---|---|
| `-v` | Print the generated OpenCL kernel source |
| `-double` | Use FP64 (requires `cl_khr_fp64`) |
| `-sl N` | Supersample at `2^N` samples/pixel |
| `-spp N` | Samples per kernel pass (default: device-driven) |
| `-tile N` | Tile edge `2^N` (default: TDR-probe-driven) |
| `-device NAME` | Prefer a named OpenCL device |
| `-list-devices` | List OpenCL devices and exit |

If no output path is given, writes `<input>_rendered.png` next to the UPR.

## Render an animation

UPRs can store keyframes as `magn="1@#0SS1.7e9@#159840E"`. MegaFractal
parses these and supports either single-frame interpolation or PNG-sequence
output:

```sh
build/mf input.upr out.png -frame 30        # render 1-indexed frame 30
build/mf input.upr out.png --frames 1:240   # render 240 frames as out_0001.png ..
build/mf input.upr out.png --frames 1:240:5 # every 5th frame in [1..240]
```

Time inside the kernel is `(frame - 1) * 160` ticks (UF convention).
Encode the sequence with ffmpeg:

```sh
ffmpeg -framerate 30 -i out_%04d.png -pix_fmt yuv420p out.mp4
```

## GUI preview

```sh
build/mf_gui            # blank window — drop a UPR path in the load box
```

Live progressive accumulation, exposure / contrast / sl sliders, device
picker, and an animation timeline scrubber.

## Tests

```sh
python scripts/run_tests.py [-d DEVICE]
```

Per-test: render the UPR under `tests/UF_params/<name>/`, RMSE against
`reference.png`. The translator unit tests (`build/translator_tests`) gate
the generated OpenCL — they run in the same harness.

## Layout

```
src/                  parser, translator, kernel_gen, renderer, anim, main, gui
third_party/imgui/    vendored, only the files we link
tests/translator/     T1: golden-substring tests on translator output
tests/UF_params/      T2 / T4: rendered scenes vs UF reference PNGs
tests/animation/      T6: animated-UPR smoke tests
scripts/run_tests.py  test driver
web/                  static one-page site + gallery
```

See `CONTINUE.md` for architecture rationale, current build state, and
the next-session mandate.

## Credits

Multi-set test corpora under `tests/UF_params/00*` are courtesy of
Phillip Scheffknecht ("baeldin"), originally collected for
[uf2opencl](https://codeberg.org/baeldin/uf2opencl).
