﻿use ui,array as a, math as m,graph as g

/*
simpel mandelbrot generator
by magnus bjerkeng.
1.dec.2007

Important parameters
sens sets solid guessing sensitivity
sene:big=high sensitivity
sene:small=low sensitivity

detail, set max number of iterations for escapetime, low=fast and bad
high=slow but good.

todo:
zoom out
periodicity checking
boundry following
symmetry check
*/

sens=0.5;
detail=400;

function mandelguess(sx,ex,sy,ey,det,cola,colc,psize,pri,show,tab)

sizex=g.size()[0];
sizey=g.size()[1];

if isboolean(tab) then
tab=a.create(sizex,0);
for i=0 to len(tab)-1 do
tab[i]=a.create(sizey,0);
end;
end;

//for all pixels given resolution
key=ui.cmd(0);
key=null;
for j=0 to (sizey-1) by psize do

if show then
g.show();
end;
if ui.cmd(0)=167 then
return [tab,-1];
end;

for i=0 to (sizex-1) by psize do

//linear map of the coplex plane to pixels,point in the middle of
//rect,(i,j)=top left,(x,y)=middle pixel

iter=0;

if pri[i][j]=0 then
x0=ex-(ex-sx)/sizex* (i+psize/2);
y0=ey-(ey-sy)/sizey*(j+psize/2);

//flip axis
temp=y0;
y0=x0;
x0=temp;

x=x0;
y=y0;
maxiter=det;

//interior check
//small circle
if (x+1)*(x+1)+y*y<0.0625 then
iter =maxiter;
end;
//big cardioide
d=256*(x*x+y*y)*(x*x+y*y)-96*(x*x+y*y)+32*x-3;
if d<=0 then
iter=maxiter;
end;
//interior check finished

//escape time algorithm
while ((x*x +y*y<4) and 
(iter<maxiter)) do
xt=x*x-y*y+x0;
yt=2*x*y +y0;
x=xt;
y=yt;
iter++;
end;

//coloring routine
if iter=maxiter then
color=0;
coltemp=0;
else  
coltemp=(iter+(m.log(m.log(2))-m.log(m.log(m.sqrt(x*x+y*y))))/m.log(2));

if coltemp>0 then
color=cola[(coltemp*colc)%(255*6)];
else
color=0;
coltemp=0;
end;

end;

//drawing routine
if show then
g.pen(color);
g.brush(color);
g.rect(i,j,psize,psize);
end;


//fill in the pixel tab
for k=j to j+psize-1 do
for m=i to i+psize-1 do
if k<len(tab[0]) then
tab[m][k]=coltemp;
end;

end;
end;
//g.show();
end;
end;
end;
//finished for all pixel
g.show();
//generate priority

if psize>1 then
tab2=a.create(sizex,0);
for i=0 to len(tab2)-1 do
tab2[i]=a.create(sizey,1000);
end;

for k=0 to len(tab)-1 by psize do
for m=0 to len(tab[0])-1 by psize do
if pri[k][m]=0 then
//for all areas in priority region

big=0;
eq=a.create(8,0);


if m<(len(tab)-psize) then
eq[0]=m.round(m.abs(0.5*tab[k][m+psize]-0.5*tab[k][m]));
if eq[0]>big then
big=eq[0];
end;
end;

if k>0 and m<(len(tab)-psize) then
eq[1]=m.round(m.abs(.sens*tab[k-psize][m+psize]-.sens*tab[k][m]));
if eq[1]>big then
big=eq[1];
end;
end;

if k<(len(tab)-psize) and m<(len(tab)-psize) then
eq[2]=m.round(m.abs(.sens*tab[k+psize][m+psize]-.sens*tab[k][m]));
if eq[2]>big then
big=eq[2];
end;
end;

if k<(len(tab)-psize) then
eq[3]=m.round(m.abs(.sens*tab[k+psize][m]-.sens*tab[k][m]));
if eq[3]>big then
big=eq[3];
end;
end;

if m>0 then
eq[4]=m.round(m.abs(.sens*tab[k][m-psize]-.sens*tab[k][m]));
if eq[4]>big then
big=eq[4];
end;
end;

if k>0 then
eq[5]=m.round(m.abs(.sens*tab[k-psize][m]-.sens*tab[k][m]));
if eq[5]>big then
big=eq[5];
end;
end;

if  k>0 and m>0 then
eq[6]=m.round(m.abs(.sens*tab[k-psize][m-psize]-.sens*tab[k][m]));
if eq[6]>big then
big=eq[6];
end;
end;

if m>0 and k<(len(tab)-psize) then
eq[7]=m.round(m.abs(.sens*tab[k+psize][m-psize]-.sens*tab[k][m]));
if eq[7]>big then
big=eq[7];
end;
end;


isequal=0;
if eq[0]=eq[1] and eq[0]=eq[1] and eq[0]=eq[2] and eq[0]=eq[3] and eq[0]=eq[4] and eq[0]=eq[5] and eq[0]=eq[6] and eq[0]=eq[7] then
isequal=1000;
//this is an uninteresting region
end;

pri[k/psize][m/psize]=isequal;

//fill in full tab

for j=k to j+psize-1 do
for i=m to i+psize-1 do

if i<len(tab2[0]) then
tab2[j][i]=pri[k/psize][m/psize];
end;

end;
end;

end;
end;
end;

//tab2 now contain priority for interesting regions
end;
g.brush(false);

/*
DEBUG, shows how solid guessing works

try 
if show then
for f=0 to len(tab2)-1 do
for g=0 to len(tab2[0])-1 do
g.put(f,g,tab2[f][g]);
end;
end;
//g.show();
end;
catch e by
end;

END DEBUG
*/

return([tab,tab2]);
end;
//mandelbrot finished

colk=1;//color constant
anim=0;//animation state
nz=4;//number of zooms, if you get outOfMemoryErr, decrese this
animtab=a.create(nz,0);
aindex=0;
recttab=a.create(nz,0);
rectind=0;
numz=0;
nameid=0;


colc=1600*m.log(detail/3)/detail;

gokey=167;
star=42;
hash=127;
up=0;down=0;left=0;right=0;
one=0;three=0;
upkey=16;downkey=17;leftkey=14;rightkey=15;
onekey=49;twokey=50;threekey=51;sevenkey=55;
eightkey=56;fourkey=52;sixkey=54;
xr=50;yr=50;wr=24;hr=24*4/3;
sx=-1.5;ex=1.5;sy=-2.5;ey=1.5;

g.full(true);
g.size(g.full()[0],g.full()[1]);
sizex=g.size()[0];
sizey=g.size()[1];

pridef=a.create(sizex,0);
for i=0 to len(pridef)-1 do
pridef[i]=a.create(sizey,0);
end;

cs=1;//color step size

cola=a.create(255*6,0)

ind=0;col=0;
for b=1 to 255 by cs do
col+=1;
cola[ind]=col;ind++;
end
for g=1 to 255 by cs do
col+=256;
cola[ind]=col;ind++;
end;
for r=1 to 255 by cs do
col+=65536;
cola[ind]=col;ind++;
end;
for b=255 to 1 by -cs do
col-=1;
cola[ind]=col;ind++;
end;
for g=255 to 1 by -cs do
col-=256;
cola[ind]=col;ind++;
end;
for r=255 to 1 by -cs do
col-=65536;
cola[ind]=col;ind++;
end;

//for drawing inside zoombox, without solid guessing 
function mandellocal(sx,ex,sy,ey,det,cola,xr,yr,w,h,tab,colc)

sizex=g.size()[0];
sizey=g.size()[1];
key=ui.cmd(0);

for j=yr+1 to yr+h-1 do
if ui.cmd(0)=167 then
return tab;
end;
for i=xr+1 to xr+w-2 do

//linear map 
x0=ex-(ex-sx)/sizex* i;
y0=ey-(ey-sy)/sizey*j;
//flip axis
temp=y0;y0=x0;x0=temp;

x=x0;y=y0;iter=0;
maxiter=det;

//interior check
//small circle
if (x+1)*(x+1)+y*y<0.0625 then
iter =maxiter;
end;
//big cardioide
d=256*(x*x+y*y)*(x*x+y*y)-96*(x*x+y*y)+32*x-3;
if d<=0 then
iter=maxiter;
end;
//interior check finished


while ((x*x +y*y<4) and (iter<maxiter)) do
xt=x*x-y*y+x0;yt=2*x*y +y0;
x=xt;y=yt;iter++;
end;

if iter=maxiter then
color=g.black;
coltemp=0;
else 
coltemp=(iter+(m.log(m.log(2))-m.log(m.log(m.sqrt(x*x+y*y))))/m.log(2));
if coltemp*10>0 then
color=cola[(coltemp*colc)%(255*6)];
else
color=cola[0];
end;
end;

g.show();
g.put(i,j,color);
//tab[i][j]=color;
if coltemp>0 then
tab[i][j]=coltemp;
end;
g.show();
end;
end;
//end;
return tab;
end;
//mandellocal finished

//replaces the zoombox when moved
function replaceRect(x,y,w,h,animtab,aindex,cola,colc)
aindex--;
//color=cola[(coltemp*colc)%(255*6)];
for i=x to x+w do
g.put(i,y,cola[(animtab[aindex][i][y]*colc)%(255*6)]);
end;
for i=x to x+w do
g.put(i,y+h-1,cola[(animtab[aindex][i][y+h-1]*colc)%(255*6)]);
end;
for i=y to y+h do
g.put(x,i,cola[(animtab[aindex][x][i]*colc)%(255*6)]);
end;
for i=y to y+h do
g.put(x+w-1,i,cola[(animtab[aindex][x+w-1][i]*colc)%(255*6)]);
end;
end

g.bg(g.black);
g.clear();
draw=1;
ui.keys(true);


//main loop
while true do

keyac=ui.cmd(0);
g.rect(xr,yr,wr,hr);
g.show();

//keyhandling


if keyac=fourkey then
colc=colc*2;
for j=0 to (sizey-1) do
for i=0 to (sizex-1) do
g.put(i,j,cola[(animtab[aindex-1][i][j]*colc)%(255*6)]);
end;
end;
g.show();
print colc;
end;

if keyac=sixkey then
colc=colc/2;
print colc;
for j=0 to (sizey-1) do
for i=0 to (sizex-1) do
g.put(i,j,cola[(animtab[aindex-1][i][j]*colc)%(255*6)]);
end;
end;
g.show();
end;

if keyac=sevenkey then
seven=1;
end;
if keyac=-sevenkey then
seven=0;
end;
if keyac=sevenkey then
seven=1;
end;
if keyac=-sevenkey then
seven=0;
end;
if keyac=onekey then
one=1;
end;
if keyac=-onekey then
one=0;
end;
if keyac=threekey then
three=1;
end;
if keyac=-threekey then
three=0;
end;

if keyac=53 then
mandellocal(sx,ex,sy,ey,detail*6,cola,xr,yr,wr,hr,animtab[aindex-1],colc);
end;
if keyac=eightkey then
mandellocal(sx,ex,sy,ey,detail,cola,0,0,sizex,sizey,animtab[aindex-1],colc);
end;

if keyac=upkey then
up=1;
end;
if keyac=-upkey then
up=0;
end;
if keyac=downkey then
down=1;
end;
if keyac=-downkey then
down=0;
end;
if keyac=leftkey then
left=1;
end;
if keyac=-leftkey then
left=0;
end;
if keyac=rightkey then
right=1;
end;
if keyac=-rightkey then
right=0;
end;

if up=1  and yr>0 then
replaceRect(xr,yr,wr,hr,animtab,aindex,cola,colc);
yr=yr-1;
end;
if down=1 and yr+hr< sizey-2 then
replaceRect(xr,yr,wr,hr,animtab,aindex,cola,colc);
yr=yr+1;
end;
if left=1 and xr>0 then
replaceRect(xr,yr,wr,hr,animtab,aindex,cola,colc);
xr=xr-1;
end;
if right=1 and xr+wr<sizex-2 then
replaceRect(xr,yr,wr,hr,animtab,aindex,cola,colc);
xr=xr+1;
end;
if seven=1 then
replaceRect(xr,yr,wr,hr,animtab,aindex,cola,colc);
name='aamandelfrac'+nameid+'.jpg';
nameid++;
g.save(name);
end;

if one=1 and (xr+wr+3)<sizex and (yr+hr+4)<sizey then
replaceRect(xr,yr,wr,hr,animtab,aindex,cola,colc);
wr=wr+3;
hr=(wr*4/3);
sleep(5);
end;

if three=1 then
replaceRect(xr,yr,wr,hr,animtab,aindex,cola,colc);
if hr>3 and wr>3 then
wr=(wr-3);
hr=wr*4/3;
sleep(5);
end;
end;

if keyac=twokey then
g.clear();
g.show();
anim=1;//run animation
end;

if keyac=gokey then

pridef=a.create(sizex,0);
for i=0 to len(pridef)-1 do
pridef[i]=a.create(sizey,0);
end;
g.clear();
g.show();
numz=numz+4;
//calculate mapping for zoom
ext=ex;sxt=sx;eyt=ey;syt=sy;
ex=ext-(ext-sxt)/sizex*(xr);
ey=eyt-(eyt-syt)/sizey*yr;
sx=ext-(ext-sxt)/sizex*(xr+wr);
sy=eyt-(eyt-syt)/sizey*(yr+hr);
recttab[rectind]=[xr,yr,wr,hr];
rectind++;
draw=1;
end;
//keyhandling done

//state machine
if anim=1 then
//state for animation
anim=0;
f=0;
for v in animtab do
if v=0 then break;end;

for j=0 to (sizey-1) do
for i=0 to (sizex-1) do
g.put(i,j,cola[(v[i][j]*colc)%(255*6)]);
end;
g.show();
end;
g.pen(g.white);
try
g.rect(recttab[f][0],recttab[f][1],recttab[f][2],recttab[f][3]);
catch e by
end;
f++;
sleep(1000);
end;

g.pen(g.green);
g.rect(xr,yr,wr,hr);
g.show();

end;


if draw=1 then
//state for drawing new fractal
//remove first if impending out of mem
if animtab[nz-1]#0 then
for i=0 to len(animtab)-2 do
animtab[i]=animtab[i+1];
recttab[i]=recttab[i+1];
end;
aindex--;
rectind--;
recttab[nz-1]=0;
end;
detail=m.trunc(detail+numz);

ret=mandelguess(sx,ex,sy,ey,detail,cola,colc,8,pridef,true,false);
animtab[aindex]=ret[0];

if isarray(ret[1]) then
pridef=ret[1];
ret=mandelguess(sx,ex,sy,ey,detail,cola,colc,4,pridef,true,animtab[aindex]);
end;

animtab[aindex]=ret[0];
if isarray(ret[1]) then
pridef=ret[1];
ret=mandelguess(sx,ex,sy,ey,detail,cola,colc,1,pridef,true,animtab[aindex]);
end;


animtab[aindex]=ret[0];
if isarray(ret[1]) then
animtab[aindex]=ret[0];
pridef=ret[1];
end;

g.brush(false);
aindex++;

g.pen(g.green);
g.rect(xr,yr,wr,hr);
g.show();
draw=0;
end;
end;

