//Plasma fractals
//Converted by dlb from http://bocoup.com/processing-js/docs/index.php?page=Plasma%20Fractals
//Which was converted by F1LT3R @ Hyper-Metrix.com from original at http://www.ic.sunysb.edu/Stu/jseyster/plasma/

mov #regHWClear,0; //Stop GPU clearing itself

dentrypoint 0,_draw; //Set the entry point for the draw loop
dentrypoint 4,_async; //Set the enty point for the async loop

mov #regAsyncFreq,2000000; //Make async run as fast as it can
mov #regAsyncClk,1; //Start async

dexit; //End init
_draw: //Start draw
dexit; //End draw

//Setup variables
color col;
vec2f pos;
vec2f size;
float gridSize, edge1, edge2, edge3, edge4, midPoint, newWidth, newHeight, width, height, noise;

_async: //Enter async

main(); //Run main function

while(1){idle} //Infinatly loop

void main(){ //Main function
    dsetbuf_spr; //Use sprite buffer

    setColor(255,255,255); //Set the colour to white
    rect(0,0,512,512); //Draw a large rectangle

    gridSize = 4; //How big each rectangle will be
    width = 512; //GPU Width
    height = 512; //GPU Height
    noise = 5; //How noisy it will be

    //Give initial corner values
    R1 = random(1);
    R2 = random(1);
    R3 = random(1);
    R4 = random(1);

    plasma(0,0,width,height,R1,R2,R3,R4) //Start recursive function
}

void plasma(float x, y, width, height, c1, c2, c3, c4){ //Plasma function

    //Setup local variables
    float edge1, edge2, edge3, edge4, midPoint;

    //Work out the size of the next segments
    float newWidth = width / 2;
    float newHeight = height / 2;

    if((width > gridSize)||(height > gridSize)){ //If it is still bigger than the rectangle size

        midPoint = (c1 + c2 + c3 + c4) / 4 + displace(newWidth + newHeight); //Randomly change the midpoint

        //Calculate edges by averaging the corners
        edge1 = (c1 + c2) / 2;
        edge2 = (c2 + c3) / 2;
        edge3 = (c3 + c4) / 2;
        edge4 = (c4 + c1) / 2;

        //Make sure it doesn't displace too far
        max midPoint,0;
        min midPoint,1;

        //Run on the newly calculated segments
        plasma(x, y, newWidth, newHeight, c1, edge1, midPoint, edge4);
        plasma(x + newWidth, y, newWidth, newHeight, edge1, c2, edge2, midPoint);
        plasma(x + newWidth, y + newHeight, newWidth, newHeight, midPoint, edge2, c3, edge3);
        plasma(x, y + newHeight, newWidth, newHeight, edge4, midPoint, edge3, c4);
    }else{ //Woo! It's the right size
        float c = (c1 + c2 + c3 + c4) / 4; //Average the corners

        float grey = c*255; //Multiply the corners by 255 to get a valid color

        setColor(grey,grey,grey); //Set the color to your new color based on the "height"
        rect(x,y,gridSize,gridSize); //Draw your rectangle
    }
}

float displace(float num){ //Displace function, it just works
    float m = num / (width + height) * (1/noise);
    R1 = random(1);
    return (R1-0.5) * m;
}

float random(float x){ //C version of the ASM rand opcode
    preserve EAX;
    rand EAX;
    return EAX*x;
}

void setColor(float r,float g,float b){ //C version of the dcolor opcode
    mov #col.r,r;
    mov #col.g,g;
    mov #col.b,b;

    dcolor col;
}

void rect(float x, float y, float width, float height){ //C version of the drectwh opcode
    mov #pos.x,x;
    mov #pos.y,y;

    mov #size.x,width;
    mov #size.y,height;

    drectwh pos, size;
    dswap; //dswap to make it show since we're drawing to the sprite buffer
}
