Fractals/MandelMachine

Mandel Machine Mandel Machine is a highly efficient Mandelbrot set explorer developed by Botond Kósa.[1]


Description

edit

code

edit
  • the c++ part ( mm64.cpp ) is only to declare functions that are implemented in assembly language and the rest is in java.
  • FractalCanvas.java is the most important file


Algorithms

edit

color

edit

FractalCanvas.java line 1996 and further:

 if(itTransferFunction==1) ;
		else if(itTransferFunction==2) it = Math.sqrt(it+1);
	    else if(itTransferFunction==3) it = Math.cbrt(it+1);
	    else if(itTransferFunction==4) it = Math.sqrt(Math.sqrt(it+1));
	    else if(itTransferFunction==5) it = Math.log(it+1);
	    else if(itTransferFunction==6) it = Math.log(Math.log(it+1)+1);
	    else if(itTransferFunction==7) it = Math.atan(it);
		else it = -1;

Bump mapping

edit

"bump mapping. It allows fake-3D visualization of subtle details previously hidden by the slow gradients in the palette.

Bump mapping is controlled by 3 parameters:

  • Direction of lighting (in degrees): specifies the angle of the simulated lighting. Surfaces facing the light are highlighted, the ones blocked from lighting are darkened.
  • Depth: controls how much the structures emerge from the background of slow gradients. Shallow depth causes a relief/emboss-like look. Greater depth values result in deeper valleys between structures (see the examples below).
  • Strength: controls the amount of color shift caused by highlights and shadows.

The parameters are continuously adjustable to give instant feedback." [2]

Data format

edit

"The Mandel Machine MMIT compressed iteration data file format:

  • every datatype needs to be written in big endian notation.
  • The following streamed through a Deflater (raw zlib format)" Dinkydau[3]
<int 4 bytes> Program Version
<int 4 bytes> Canvas Width
<int 4 bytes> Canvas Height
<byte> Supersampling
<double> Magnification
<double> Rotation
<int 4 bytes> Number of coordinate digits represented by long ints
<long long array> array 2 times as long as the above int
<int 4 bytes> Iteration limit
<byte> Bytes per sample
<double> minimum iteration count
<double> granularity (equal to iterRange / (2^(bytes_per_sample*8) - 6), where iterRange is maxIt - minIt)
<int array> row by row encoded samples (one int value per pixel)

KFB to MMIT converter

edit

Source code (written in C) that depends on kfb.h and kfb.c from kf-extras:

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include "kfb.h"

void asserts(){
    assert(sizeof(char)==1);
    assert(sizeof(short)==2);
    assert(sizeof(int)==4);
    assert(sizeof(float)==4);
    assert(sizeof(double)==8);
    assert(sizeof(long)==4);
    assert(sizeof(long long)==8);
    return;
}

//data_size counts how large the mmit data is before zlib formatting
int data_size = 0;
const char one = 1;

union DoubleBytes {//to interpret double as char array and inverse byte order
   double d;
   char b[8];
};

union IntBytes {//to interpret int as char array
   int i;
   char b[4];
};

//functions to write data in big endian notation

int le_to_be_int(int input){
    int num = input;
    int b0,b1,b2,b3;
    int res;
    b0 = (num & 0x000000ff) << 24u;
    b1 = (num & 0x0000ff00) << 8u;
    b2 = (num & 0x00ff0000) >> 8u;
    b3 = (num & 0xff000000) >> 24u;
    res = b0 | b1 | b2 | b3;
    return res;
}

void write_be_int(int input, FILE *outfile){
    int res = le_to_be_int(input);
    fwrite(&res, 4, 1, outfile);
    data_size += 4;
}

void write_be_char(char input, FILE *outfile){
	fwrite(&input, 1, 1, outfile);
	data_size += 1;
}

void write_be_double(double input, FILE *outfile){
	union DoubleBytes doublebytes;
	doublebytes.d = input;
	for(int i=0; i<4; i++){//reverse byte order in the double with char array interpretation
		char temp = doublebytes.b[i];
		doublebytes.b[i] = doublebytes.b[7-i];
		doublebytes.b[7-i] = temp;
	}
	fwrite(&doublebytes.d, 8, 1, outfile);
	data_size += 8;
}

int main(int argc, char **argv) {
    //Check and load KFB file-----------------------------------------------------------------------------------
    asserts();
    if (argc < 2)
    {
  	    printf("This program converts a given KFB file to MMIT. Program version: 1.0
");
  	    printf("Usage: "); printf(argv[0]); printf(" path_to_KFB [path_to_MMIT]
");
  	    printf("Default for path_to_MMIT: MMIT-convert.mmit
");
        return 1;
    }
    printf("Loading KFB file...
");
    kfb *in = kfb_load(argv[1]);
    if (! in) { printf("Loading KFB file failed.
"); return 1; }
    int width = kfb_width(in);
    int height = kfb_height(in);
  
    //Writing all relevant mmit data to tempoutfile without zlib format--------------------------------------------

    FILE *tempoutfile;
    tempoutfile=fopen("tempoutfile", "wb");
    
    //Get min and max iteration values present in KFB
	double max_iters = 0;
	double min_iters = 800100100;
	for(int i=0; i<height; i++){
    	for(int j=0; j<width; j++){
    		double ij = kfb_get(in, j, i);
    		if(ij<min_iters) min_iters = ij;
    		if(ij>max_iters) max_iters = ij;
    	}
    }
    printf("Lowest iteration count: %lf
", min_iters);
    printf("Highest iteration count: %lf
", max_iters);
    
    //Parameters and settings
    write_be_int(one, tempoutfile); //Program version
    write_be_int(width, tempoutfile); //Canvas width
    write_be_int(height, tempoutfile); //Canvas height
    char supersampling = 0; write_be_char(supersampling, tempoutfile); //Supersampling (Always 0 for no supersampling)
    double magnification = 512; write_be_double(magnification, tempoutfile); //Fake magnification default to arbitrary value;
    double rotation = 256; write_be_double(rotation, tempoutfile); //Fake rotation default to arbitrary value;
    int coord_digits = 11; write_be_int(coord_digits, tempoutfile); //Fake number of coordinate digits
    int coords[44] = {-1, -1, -1, -1, -1768346623, 1239184185, -1450836726, -1610156628, -1160793342, 1122682978, 1750969101, 1468815386, -86691575, -319241320, -141699069, 731720154, -1302511102, 2092147506, 1358717447, -121412270, -362838523, 1906712988, 218032387, 147395776, 1528659973, -1874890155, 1817790991, 431114295, 1763611407, -389200653, 1363516937, 1455562147, 707986444, -847133922, 1130970381, 1568324293, 1567881485, -580086891, 1843248142, 1016614712, 1950251523, -75377623, -1674907892, 1914116203};
    for(int i=0; i<44; i++){ //Fake array of coordinate digits
	    fwrite(&coords[i], 4, 1, tempoutfile);
		data_size += 4;
	}
    
	int iteration_limit = 799999999; write_be_int(iteration_limit, tempoutfile); //default one below MM's 800M limit, seems safe
	char bytesPerSample = 4; write_be_char(bytesPerSample, tempoutfile); //always 4 (the max) for simplicity
	write_be_double(min_iters, tempoutfile); //minimum number of iterations in the data
	double granularity = (799999999 - min_iters)/4294967290; write_be_double(granularity, tempoutfile); //(equal to iterRange / 4294967290, where iterRange is maxIt - minIt)	
	
	printf("Writing iteration data...
");
	//Iteration data
    double granRec = 0; if(granularity != 0) granRec = 1/granularity;
    long long prevEncoded = 0;
    char buffer[width*4];
    union IntBytes intbytes;
    for(int row=0; row<height; row++){
    	for(int col=0; col<width; col++){
    		double it = kfb_get(in, col, row);
    		long long encoded;
    		if (it == max_iters) encoded = 3; //Point inside minibrot
    		else encoded = round((it-min_iters)*granRec) + 5; //encodeSample
    		int diff = encoded - prevEncoded;
    		//writeSample:
    		intbytes.i = diff;
    		buffer[col+3*width] = intbytes.b[3];
			buffer[col+2*width] = intbytes.b[2];
			buffer[col+width] = intbytes.b[1];
			buffer[col] = intbytes.b[0];
			//
    		prevEncoded = encoded;
    	}
    	fwrite(&buffer, width*4, 1, tempoutfile);
    	data_size += width*4;
    }
  
    fclose(tempoutfile);
    kfb_free(in);
    
    printf ("Total data size: %d
", data_size);

    //read uncompressed MMIT data into array a---------------------------------------------------------------------
    char* a = malloc(data_size);
    if(a==NULL){ printf ("Allocation of memory failed.
"); return 1;}
    FILE *readbackfile;
    readbackfile=fopen("tempoutfile", "rb");
    fread(a, data_size, 1, readbackfile);
  
    printf("Writing zlib format...
");
    //Convert to zlib format and write to file---------------------------------------------------------------------
    FILE *outfile;
    if(argc > 2) outfile=fopen(argv[2], "wb");
    else outfile=fopen("MMIT-convert.mmit", "wb");
  
    int bytes_written = 0;
	char header_more[] = {0, 86, 129, 169, 126}; // hardcoded zlib header for a block size of 33110;
    while(bytes_written<data_size)
    {
    	if(data_size - bytes_written > 33110)
  	    { //not the last block header
  		    fwrite(&header_more, 5, 1, outfile);
  		    for(int j=0; j<33110; j++)
  		    {
  			    fwrite(&a[bytes_written+j], 1, 1, outfile);
  		    }
  		    bytes_written += 33110;
	    }
	    else
	    { //the last block header
		    short to_go = data_size - bytes_written;
  		    short complement = 65535 - to_go;
  		    fwrite(&one, 1, 1, outfile);
  		    fwrite(&to_go, 2, 1, outfile);
  		    fwrite(&complement, 2, 1, outfile);
  		    for(int j=0; j<to_go; j++)
  		    {
  			    fwrite(&a[bytes_written+j], 1, 1, outfile);
  		    }
  		    bytes_written += to_go;
	    }
    }
  
    //-----------------------------------------------------------------------------------
  
    fclose(readbackfile);
    if(remove("tempoutfile") != 0) printf("Deleting the temporary file failed.");

    printf ("Done");

    return 0;
}

References

edit
  1. Mandel Machine by Botond Kósa.
  2. fractalforums : mandel-machine -bump-mapping-and-improved-histogram-coloring-v1-3-10-is-available/
  3. fractalforums kfb-to-mmit-converter