An interactive Mandelbrot set explorer, rendered in 256-color VESA SVGA mode (up to 1024x768). Features smooth iteration coloring, supersampling anti-aliasing, interactive zoom, and post-processing color normalization.
Written in C/C++ for DOS back in the 1990s. Compiled with Borland Turbo C++ 3.1, targeting 16-bit x86 real mode with the large memory model. Can be tested today using a DOS emulator like DOSBox or DOSBox-X. I've tested it in DOSBox.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
- Escape-time Mandelbrot set rendering with 255 maximum iterations.
- VESA SVGA output at 640x400, 640x480, 800x600, or 1024x768 (256 colors).
- Smooth iteration coloring using the normalized iteration count formula to eliminate color banding at iteration boundaries.
- Supersampling anti-aliasing (2x2 through 5x5) for spatial noise reduction in high-detail regions.
- Interactive zoom box overlay with keyboard-driven positioning, resizing, and 4:3 aspect ratio lock.
- Post-processing color normalization that remaps rendered indices to span the full palette range (1-254), maximizing contrast in deeply zoomed views.
- Customizable fractal palette gradient defined as RGB control vectors in
CONFIG.INI. Any number of control points (2-16) can be specified; palette indices are computed automatically by evenly spacing them across the palette range. Default gradient: Black, Blue, Cyan, Green, Yellow, Red, Magenta, Black. - Screenshot saving in Autodesk Animator CEL format with auto-incrementing filenames.
- INI-based configuration for resolution, rendering options, palette gradient, and UI color.
- Direct pixel rendering to VESA video memory (no intermediate framebuffer).
The Mandelbrot set
remains bounded as
Each iteration computes
yielding the component-wise update rules used by the renderer:
For points outside the Mandelbrot set, the sequence
For each pixel, the algorithm iterates until either the escape condition is met or the maximum iteration count is reached:
where
Each pixel
where the per-pixel scale factors are:
and
When the user selects a zoom region via the on-screen zoom box at pixel coordinates
The zoom box maintains a fixed
The discrete escape-time algorithm produces integer iteration counts, which create visible color banding at iteration boundaries. The normalized iteration count formula produces a continuous real-valued estimate
For a point that escapes at iteration
Since the code stores
This works because
Points inside the set (
The integer iteration count is mapped to a palette index using modular arithmetic:
This wraps the iteration count cyclically through palette indices
The continuous smooth value
where
For each pixel, an
for
where
After rendering, the color normalization pass remaps the fractal palette indices in video memory so they span the full range
Because the renderer uses modular arithmetic, a narrow band of iteration counts can wrap around the palette and produce a split distribution. For example, iterations
The algorithm operates in two passes:
Pass 1 -- Circular Band Detection. A histogram records which palette indices
Pass 2 -- Linear Remapping. Each used palette index is assigned an ordinal rank
This linearly stretches the
The 254-entry fractal palette is constructed by linearly interpolating between
The control vectors are evenly spaced across palette indices
For each palette index
and analogously for
The pre-compiled FRACTAL.EXE is included in the latest release. It is a 16-bit DOS executable and requires DOSBox or a compatible DOS emulator to run.
Download FRACTAL.EXE and CONFIG.INI from the latest release and place them in the same folder.
mount c c:\path\to\your\folder
c:
fractal
The Mandelbrot set will begin rendering immediately. Press ESC to exit.
- Press Tab to show the zoom box, use the arrow keys to position it, and press Enter to zoom in.
- Press A to toggle smooth coloring, or 2-5 to increase the supersampling level.
- Press S to save a screenshot.
Any DOS-compatible emulator that supports VESA VBE 1.2 SVGA graphics will work, including DOSBox-X and 86Box. Mount the directory containing FRACTAL.EXE and CONFIG.INI, then run FRACTAL.
To use a different configuration file:
fractal -config "path\settings.ini"
| Key | Action |
|---|---|
Tab |
Toggle zoom box |
| Arrow keys | Move zoom box |
= / - |
Resize zoom box (4:3 aspect ratio) |
Enter |
Zoom into selected region |
A |
Toggle smooth iteration coloring |
0-5 |
Set supersampling level (0 = off, 2-5 = NxN grid) |
S |
Save screenshot (CEL format). Use Desktop Animator to view .CEL files. |
Esc |
Exit (or abort render in progress) |
Building requires Borland Turbo C++ 3.1 (BCC.EXE) running inside DOSBox. The compiler is a 16-bit DOS program and cannot run on a modern OS directly.
- DOSBox (or DOSBox-X)
- Borland Turbo C++ 3.1 installed and accessible from within DOSBox
- Mount both the Borland compiler directory and the project source directory in DOSBox:
mount c c:\path\to\borland mount d d:\path\to\fractal-source set PATH=%PATH%;C:\BIN d: - Run the build script:
This compiles
buildVESA.C(C with inline assembly),INI.CPP,APP.CPP, andMAIN.CPP(C++), then links them intoFRACTAL.EXE. All output is logged toBUILD.LOG. - Run the program:
fractal
| Flag | Purpose |
|---|---|
-ml |
Large memory model (required for far pointers and farmalloc) |
-2 |
Enable 80286+ instructions |
- All source filenames follow the DOS 8.3 naming convention.
clean.batremoves build artifacts (.OBJ,.EXE, andBUILD.LOG).- Floating-point emulation is included automatically by the compiler when math functions are used.
FRACTAL2/
├─ main.cpp Entry point, parses -config flag, creates Application
├─ app.h Application class declaration, constants, key definitions
├─ app.cpp All rendering, zoom, palette, and file I/O logic
├─ ini.h INI file parser class declaration
├─ ini.cpp INI file parser implementation (sections, key-value pairs)
├─ vesa.h VESA SVGA graphics library header (C-callable)
├─ vesa.c VESA SVGA library (C with inline x86 assembly)
├─ CONFIG.INI Runtime configuration (resolution, rendering, UI color)
├─ build.bat Build script for BCC
├─ clean.bat Removes build artifacts
├─ run.bat Launches FRACTAL.EXE with debug flags│
└─ images/ Rendered fractal screenshots (CEL and PNG)
Pixels are rendered directly to VESA video memory via PutPixel() at segment A000h. The VESA library handles 64 KB bank switching transparently. No intermediate image buffer is used -- pixel values are read back from video memory via GetPixel() during post-processing and file save operations.
Smooth coloring applies the normalized iteration count formula to produce continuous real-valued color indices that eliminate the hard banding visible with integer iteration counts. See Smooth Iteration Count in the Mathematics section for the derivation.
For each pixel, an NxN grid of sub-samples is evaluated at evenly spaced offsets within the pixel's complex-plane footprint. The smooth iteration values of all escaped sub-samples are averaged to produce the final color index. See Supersampling Anti-Aliasing in the Mathematics section for the sampling geometry.
After rendering, a two-pass normalization algorithm detects the circular band of used palette indices and linearly remaps them to span the full range (1-254), maximizing contrast in deeply zoomed views. See Post-Processing Color Normalization in the Mathematics section for the remapping formula.
The 256-entry palette is partitioned as follows:
| Index | Purpose |
|---|---|
| 0 | Mandelbrot set interior (black) |
| 1-254 | Fractal escape-time colors (seven-ramp gradient) |
| 255 | UI overlay color (zoom box, scanline indicator) |
The fractal gradient follows eight control vectors: Black → Blue → Cyan → Green → Yellow → Red → Magenta → Black, linearly interpolated across indices 1-254.
Low-level SVGA graphics in C with inline x86 assembly. Supports VESA VBE 1.2 mode setting, pixel read/write with automatic 64 KB bank switching, rectangle fill and outline, BIOS ROM font text rendering, VGA DAC palette upload, and vertical retrace synchronization.
- CPU: Intel 80286+ (16-bit real mode, no FPU required -- software float emulation)
- Video: VESA VBE 1.2 compatible SVGA adapter
- Memory: Conventional DOS memory (large model, far-heap allocation)
All settings are in the [Settings] section of CONFIG.INI:
| Key | Values | Description |
|---|---|---|
width / height |
640x400, 640x480, 800x600, 1024x768 | VESA screen resolution |
antialiasing |
0, 1 | Smooth iteration coloring (toggle with A at runtime) |
supersampling |
0, 2, 3, 4, 5 | NxN supersampling grid size (set with 0-5 at runtime) |
normalize_color_range |
0, 1 | Post-processing color normalization |
image_path |
path string | Screenshot save directory |
ui_red / ui_green / ui_blue |
0-63 | UI overlay color (VGA DAC format) |
debug |
0, 1 | Show palette test display |
palette_control_vector_0 ... _N |
R,G,B |
Gradient control vectors (VGA DAC, 0-63 per channel) |
Control vectors are numbered sequentially (palette_control_vector_0, palette_control_vector_1, ...). Palette indices are computed automatically by evenly spacing them across 1-254. Minimum 2 required. Scanning stops at the first missing key; if fewer than 2 are found, the built-in default gradient is used.
This project is shared for educational and archival purposes.








