// renders the well known Mu Molecule (aka Mandelbrot set)

// TODO: replace with
//	Plotter			[ DONE ]
//	Coordinate / BasicCoordinate

#include <iostream>
#include <fstream>
#include <math.h>
#include "plotter.h"

#define NUMBER_OF_ITERATIONS 1000	// if it hasn't escaped by this number
					// of iterations, get out
#define MAGNITUDE_LIMIT      2		// mandelbrot limit

// output file data
#define XSIZE 1024
#define YSIZE 768

// input data
#define X_START -2
#define X_END 0.9
#define Y_START -1.4
#define Y_END 1.4
#define COLOR_LOW 0
#define COLOR_HIGH 255

// program specific (optimization)
#define realMagLimit	     MAGNITUDE_LIMIT*MAGNITUDE_LIMIT

void calculate(double & x, double & y, double C_real, double C_imaginary) {

	double old_x = x;

	// x is real part, y is imaginary
	// (denote the complex number x + yi = z
	//  then we are iterating z^2 + C

	x = (old_x*old_x) - (y*y) + C_real;
	y = 2*old_x*y + C_imaginary;
}

double get_magnitude(double x, double y) {
	        // radius
	        return(sqrt((x*x)+(y*y)));
}

bool magnitude_greater(double x, double y, double limit_squared) {
	        // optimized trick, but makes code unreadable
	        return ( ((x*x)+(y*y)) > limit_squared);
}

double getCount(double x, double y, double max) {
	// this does the hard part
	// set C = (x,y), then start iterating with x0,y0 = (0,0)
	// if we escape, return the number of iterations if less than max
	// (otherwise return max). if we don't, return 0.

	double xn = 0, yn = 0;

	for (int counter = 0; counter < NUMBER_OF_ITERATIONS; counter++) {
		
		if (magnitude_greater(xn, yn, realMagLimit)) {
			if (counter < max)	return(counter);
			else			return(max);
		}

		calculate(xn, yn, x, y);
	}

	// magnitude was not greater. return zero.
	return(0);
}

// fix later
double kludge(double input) {
	// approximates logarithmic by making low end values more important
	/*if (input > 100) {
		return ( 220+((input-100)/3));
	} else {
		return(input*4);
	}*/
	double CONST = 0.045;
	return(1 - exp(input * CONST)  *  255);
		
}


main() {

	double incrementX; // X amount in source space that corresponds to one
			   // pixel to the right in output space
	double incrementY; // ditto, but with Y and down, respectively

	double xpos, ypos; // counters

	// clean up array
	double * output = new double [XSIZE*YSIZE];
	for (int ix = 0; ix < (XSIZE*YSIZE); ix++) output[ix] = 0;

	Plotter tool;

	// set required plotter parameters
	tool.setSourceBoundaries(X_START, Y_START, X_END, Y_END);
	tool.setTargetBoundaries(0, 0, XSIZE, YSIZE);
	tool.setTargetArray(output);
	
	incrementX = tool.getStepsX(XSIZE);	// get X increment rate
	incrementY = tool.getStepsY(YSIZE);	// get Y increment rate

	// iterate for all (x,y)
	
	for (ypos = Y_START; ypos < Y_END; ypos += incrementY) {
		
		cout << ypos << "\n";
		
		for (xpos = X_START; xpos < X_END; xpos += incrementX) 
			tool.plot(xpos, ypos, kludge(getCount(xpos, ypos, 255)));
		
	}

	// dump plot

	ofstream outputFile("qnd.raw");

	for (int counter = 0; counter < XSIZE*YSIZE; counter++) {
		outputFile << (char)output[counter];
	}

	outputFile.close();
			
}
