Pixel Bender Mandelbrot: runtime loop unrolling

by yonatan forked from Pixel Bender Mandelbrot by subblue (diff: 149)
♥3 | Line 136 | Modified 2010-03-15 08:06:00 | MIT License
play

ActionScript3 source code

/**
 * Copyright yonatan ( http://wonderfl.net/user/yonatan )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/6GQX
 */

<?xml version="1.0" encoding="utf-8"?>
<!-- forked from makc3d's Pixel Bender Mandelbrot by subblue

The shader bytecode is spliced together by the buildShader 
function. The number of repeated loop bodies and endif opcodes 
is determined by the value of the maxIter slider.

Shader source (assembler at http://wonderfl.net/code/ff8dbc0a3468ef771745856eb977672e61cf0fdb):

; START:
texture  "src", t0
parameter "_OutCoord", float2, f0.rg, in
parameter "dst", float4, f1, out
parameter "size", float2, f0.ba, in
meta "defaultValue", 512, 512
meta "minValue", 100, 100
meta "maxValue", 1000, 1000
parameter "center", float2, f2.rg, in
meta "defaultValue", -0.5, 0
meta "minValue", -2, -1
meta "maxValue", 2, 1
parameter "zoomMajor", float, f3.r, in
meta "defaultValue", 0
meta "minValue", 0
meta "maxValue", 20

set f1, 0
set f10.a, 0
set f10.b, 1
set f10.g, 2
set f10.r, 4
div f0.rg, f0.ba ; f0.rg = pos / size
set f4.rg, 0.5
sub f0.rg, f4.rg
set f4.rg, 4
mul f0.rg, f4.rg
exp f4.r, f3.r ;zoom
div f0.r, f4.r
div f0.g, f4.r
add f0.rg, f2.rg ; centering
mov f4.rg, f0.rg

; ITERATION:
mov f4.ba, f4.rg ; f4.ba = old x, old y
mul f4.rg, f4.rg ;f4.rg = x*x, y*y
mov f5.b, f4.r
add f5.b, f4.g ;f5.b = x*x+y*y
ltn f5.b, f10.r
if i0.r ;if x*x+y*y < 4
add f10.a, f10.b ;iteration_counter++
mul f4.a, f4.b
add f4.a, f4.a ; f4.a = 2xy
sub f4.r, f4.g ; f4.r = x*x - y*y
mov f4.g, f4.a
add f4.rg, f0.rg ; f4.rg = x*x - y*y + pixel_x, 2xy + pixel_y

; ENDIF:
end

; FINISH:
tan f4.r, f4.g
abs f4.r, f4.r
mov f1.r, f4.r
mov f1.g, f4.r
mov f1.b, f4.r
set f1.a, 1

-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:fd="flash.display.*"
    horizontalAlign="left" paddingLeft="0" verticalAlign="top" paddingTop="0"
    creationComplete="init()">
    <fd:Bitmap id="bmp" />
    <mx:UIComponent id="uic" />
        <mx:Spacer height="100%"/>
    <mx:VBox backgroundColor="0xFFFFFF" backgroundAlpha="0.4">
    <mx:HSlider id="maxIter" toolTip="max iterations" minimum="2" maximum="150" width="440" labels="['MaxIter: 2','150']" change="buildShader();draw();" value="20" />
    <mx:HSlider id="centerX" toolTip="center.x" minimum="-2" maximum="2" width="440" labels="['Re: -2','+2']" change="draw()" value="-1.673497088962531" />
    <mx:HSlider id="centerY" toolTip="center.y" minimum="-1" maximum="1" width="440" labels="['Im: -1','+1']" change="draw()" value="-0.0003318667941149705" />
    <mx:HSlider id="zoomMaj" toolTip="zoom" minimum="0" maximum="10" width="440" labels="['Zoom:']" change="draw()" value="5.5" />
    </mx:VBox>
    <mx:Script>
    <![CDATA[
import flash.display.Shader;
import flash.display.ShaderJob;
import flash.display.BitmapData;
import flash.utils.clearTimeout;
import flash.utils.setTimeout;
import mx.utils.Base64Decoder;
public var j:ShaderJob;
public var s:Shader;
public var t:uint;
public function init ():void {
    bmp.bitmapData = new BitmapData (465, 465, false, 0); uic.addChild (bmp);

    buildShader();
    draw ();
}

public function buildShader():void {
    function decode(str:String):ByteArray {
        var decoder:Base64Decoder = new Base64Decoder;
        decoder.decode(str);
        return decoder.drain();
    }
    
    var start:ByteArray = decode("owAEc3JjAKEBAgAADF9PdXRDb29yZAChAgQBAA9kc3QAoQECAAADc2l6ZQCiAmRlZmF1bHRWYWx1ZQBEAAAARAAAAKICbWluVmFsdWUAQsgAAELIAACiAm1heFZhbHVlAER6AABEegAAoQECAgAMY2VudGVyAKICZGVmYXVsdFZhbHVlAL8AAAAAAAAAogJtaW5WYWx1ZQDAAAAAv4AAAKICbWF4VmFsdWUAQAAAAD+AAAChAQEDAAh6b29tTWFqb3IAogFkZWZhdWx0VmFsdWUAAAAAAKIBbWluVmFsdWUAAAAAAKIBbWF4VmFsdWUAQaAAADIBAPAAAAAAMgoAEAAAAAAyCgAgP4AAADIKAEBAAAAAMgoAgECAAAAFAADBAACwADIEAMA/AAAAAgAAwQQAEAAyBADAQIAAAAMAAMEEABAAEgQAgAMAAAAFAACABAAAAAUAAEAEAAAAAQAAwQIAEAAdBADBAAAQAA==");
    var iteration:ByteArray = decode("HQQAMQQAEAADBADBBAAQAB0FACAEAAAAAQUAIAQAQAAqBQAgCgAAADQAAAAAgAAAAQoAEAoAgAADBAAQBACAAAEEABAEAMAAAgQAgAQAQAAdBABABADAAAEEAMEAABAA");
    var endifInsn:ByteArray = decode("NgAAAAAAAAA=");
    var finish:ByteArray = decode("DgQAgAQAQAAYBACABAAAAB0BAIAEAAAAHQEAQAQAAAAdAQAgBAAAADIBABA/gAAA");
    var bytecode:ByteArray = new ByteArray;
    var i:uint;
    
    bytecode.writeBytes(start, 0, start.length);
    for(i=0; i < maxIter.value; i++) bytecode.writeBytes(iteration, 0, iteration.length);
    for(i=0; i < maxIter.value; i++) bytecode.writeBytes(endifInsn, 0, endifInsn.length);
    bytecode.writeBytes(finish, 0, finish.length);
    
    s = new Shader(bytecode);
    s.data.src.input = bmp.bitmapData.clone ();
    s.data ["size"] ["value"] = [465, 465];
}

public function draw ():void {
    clearTimeout (t);
    if (j != null) {
        j.cancel ();
        drawCheckerBoard ();
        // apparently cancelling takes some time...
        t = setTimeout (startShaderJob, 2000);
    } else {
        drawCheckerBoard ();
        startShaderJob ();
    }
}
public function startShaderJob ():void {
    s.data ["zoomMajor"] ["value"] = [zoomMaj.value];
    s.data ["center"] ["value"] = [centerX.value, centerY.value];
    j = new ShaderJob (s, bmp.bitmapData);
    j.start ();
}
public function drawCheckerBoard ():void {
    var b:BitmapData = bmp.bitmapData;
    b.lock ();
    for (var i:int = 0; i < 465; i++)
    for (var j:int = 0; j < 465; j++)
    b.setPixel (i, j, ((int (i / 4) % 2 + int (j / 4) % 2) % 2) * 0x303030 + 0xcfcfcf);
    b.unlock ();
}
]]>
    </mx:Script>
</mx:Application>