// Buddhabrot
// j.tarbell January, 2004
// Albuquerque, New Mexico
// complexification.net
// http://www.complexification.net/gallery/machines/buddhabrot/appletl/index.html
// based on code by Paul Bourke
// astronomy.swin.edu.au/~pbourke/
// Processing 0085 Beta syntax update
// j.tarbell April, 2005
#include <ILI9341_t3n.h> // Hardware-specific library
#include <SPI.h>
#include <ili9341_t3n_font_Arial.h>
#define ILI9341_RST 23
#define ILI9341_DC 9
#define ILI9341_CS 10
ILI9341_t3n tft = ILI9341_t3n(ILI9341_CS, ILI9341_DC, ILI9341_RST);
int dim = 240; // screen dimensions (square window)
int bailout = 200; // number of iterations before bail
int plots = 10000; // number of plots to execute per frame (x30 = plots per second)
// 2D array to hold exposure values
byte exposure[240*240];
int maxexposure; // maximum exposure value
int time = 0;
int exposures = 0;
boolean drawing;
void setup() {
Serial.begin(115200);
tft.begin();
tft.setRotation(3);
tft.setFont(Arial_9);
tft.fillScreen(ILI9341_BLACK);
tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
tft.setTextDatum(BL_DATUM);
}
void loop() {
plotPlots();
time++;
if (time % 30 == 0) {
// show progress every 2 seconds or so...
findMaxExposure();
renderBrot();
// show exposure value
tft.drawString("bailout: ",0,0);
tft.drawNumber(bailout, 0, 25);
tft.drawString("exposures: ",0,40);
tft.drawNumber(exposures, 0, 60);
}
}
void plotPlots() {
float x, y;
// iterate through some plots
for (int n=0;n<plots;n++) {
// Choose a random point in same range
x = randomFloat(-2.0,1.0);
y = randomFloat(-1.5,1.5);
if (iterate(x,y,false)) {
iterate(x,y,true);
exposures++;
}
}
}
// Iterate the Mandelbrot and return TRUE if the point exits
// Also handle the drawing of the exit points
boolean iterate(float x0, float y0, boolean drawIt) {
float x = 0;
float y = 0;
float xnew, ynew;
int ix,iy;
for (int i=0;i<bailout;i++) {
xnew = x * x - y * y + x0;
ynew = 2 * x * y + y0;
if (drawIt && (i > 3)) {
ix = int(dim * (xnew + 2.0) / 3.0);
iy = int(dim * (ynew + 1.5) / 3.0);
if (ix >= 0 && iy >= 0 && ix < dim && iy < dim) {
// rotate and expose point
exposure[ix*dim+iy]++;
}
}
if ((xnew*xnew + ynew*ynew) > 4) {
// escapes
return true;
}
x = xnew;
y = ynew;
}
// does not escape
return false;
}
void findMaxExposure() {
// assume no exposure
maxexposure=0;
// find the largest density value
for (int i=0;i<dim;i++) {
for (int j=0;j<dim;j++) {
maxexposure = max(maxexposure,exposure[i*dim+j]);
}
}
}
void renderBrot() {
// draw to screen
for (int i=0;i<dim;i++) {
for (int j=0;j<dim;j++) {
float ramp = exposure[i*dim+j] / (maxexposure / 2.5);
// blow out ultra bright regions
if (ramp > 3) {
ramp = 1;
}
uint16_t color = tft.color565(int(ramp*128), int(ramp*128), int(ramp*255));
tft.drawPixel(j+80, i, color);
//color c = color(int(ramp*255), int(ramp*255), int(ramp*255));
//set(j,i,c);
}
}
}
double randomFloat(float minf, float maxf)
{
return minf + random(1UL << 31) * (maxf - minf) / (1UL << 31); // use 1ULL<<63 for max double values)
}