In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Symbolic AGAL experiment

probably has a few bugs
/**
 * Copyright yonatan ( http://wonderfl.net/user/yonatan )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/tAJf
 */

// forked from 9re's toon shader test
package 
{
    import flash.display.*;
    import flash.geom.*;
    import com.adobe.utils.*;
    import flash.display3D.*;
    import flash.display3D.textures.*;
    import flash.events.*;
    import flash.utils.*;
    import com.bit101.components.*;
    /**
    * @author 9re
    */
    [SWF(width="465", height="465")]
    public class main extends Sprite
    {
        private static const R0:Number = 5;
        private static const N0:int = 72;
        private static const R1:Number = 1.8;
        private static const N1:int = 64;
        private static const K:int = N0 * N1;
        private var _stage3D:Stage3D;
        private var _context3D:Context3D;
        private var _agalSugar:AGALSugar;
        private var _projection:PerspectiveMatrix3D;
        private var _model:Matrix3D;
        private var _world:Matrix3D;
        private var _width:int;
        private var _height:int;
        private var _indecesBuffer:IndexBuffer3D;
        private var _timer:int = -1;

        private var _vertexMasm:TA;
        private var _fragmentMasm:TA;
        private var _vertexAsm:TA;
        private var _fragmentAsm:TA;
        private var _status:TA;
        private var _updateBtn:PushButton;

        private var _constants:String =  "lightDirection: 4, world: 16, model: 16";
        private var _attributes:String = "position: 3, normal: 3";
        private var _varying:String =    "intensity: 1";
        private var _samplers:String =   "colors";
        private var _vCode:String = <><![CDATA[// Edit and click 'Update program'
m44 op, $position, $world
dp3 vt0.x, $normal, $model:0
dp3 vt0.y, $normal, $model:1
dp3 vt0.z, $normal, $model:2
mov vt0.w, $model:3.w
dp3 vt0, $lightDirection, vt0
mov $intensity, vt0]]></>;
        private var _fCode:String = <><![CDATA[// Edit and click 'Update program'
mul ft0, $intensity, $2
sub ft0, ft0, $1
tex ft0, ft0, $colors <2d,clamp,linear>
mov oc, ft0]]></>;
        
        public function main() 
        {
            Wonderfl.disable_capture();
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(event:Event = null):void {
            if (event) removeEventListener(Event.ADDED_TO_STAGE, init);
            
            stage.align = StageAlign.TOP_LEFT;
            // stage.scaleMode = StageScaleMode.NO_SCALE;
            var sw:int = stage.stageWidth;
            var sh:int = stage.stageHeight;

            with(_vertexMasm =   new TA(this, 0, 20, _vCode, true))       { setSize(sw/8*3-4, sh/3*2-24) };
            with(_fragmentMasm = new TA(this, 0, sh/3*2+20, _fCode, true)){ setSize(sw/8*3-4, sh/3-24) };
            with(_vertexAsm =    new TA(this, sw/8*3, 20))        { setSize(sw/8*3-4, sh/3*2-24); };
            with(_fragmentAsm =  new TA(this, sw/8*3, sh/3*2+20)) { setSize(sw/8*3-4, sh/3-24); };
            with(_status =       new TA(this, sw/8*6, 20))        { setSize(sw/4-4, sh-50); textField.wordWrap=true; };
            _updateBtn = new PushButton(this, sw/8*6, sh-24, "Update program", updateProgram);
            new Label(this, 0, 0, "Vertex program");
            new Label(this, 0, sh/3*2, "Fragment program");
            new Label(this, sw/8*3, 0, "Preprocessed vertex program");
            new Label(this, sw/8*3, sh/3*2, "Preprocessed fragment program");
            new Label(this, sw/8*6, 0, "Status");
            stage.addEventListener(MouseEvent.MOUSE_MOVE, function(e:*):void { visible = true; });
            stage.addEventListener(Event.MOUSE_LEAVE, function(e:*):void { visible = false; });
            
            _width = stage.stageWidth & ~1;
            _height = stage.stageHeight & ~1;
            
            _stage3D = stage.stage3Ds[0];
            _stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
            _stage3D.requestContext3D(Context3DRenderMode.AUTO);
            //_stage3D.viewPort = new Rectangle(0, 0, _width, _height);
        }
        
        private function onContext3DCreate(e:Event):void 
        {
            _context3D = _stage3D.context3D;
            _context3D.enableErrorChecking = true;
            _context3D.setDepthTest(true, Context3DCompareMode.LESS);
            //_context3D.setCulling(Context3DTriangleFace.FRONT_AND_BACK);
            _context3D.configureBackBuffer(_width, _height, 2, true);
            
            initTorus();
            initAGAL();
            
            var texture:Texture = _context3D.createTexture(64, 64, Context3DTextureFormat.BGRA, true);
            var textureData:BitmapData = new BitmapData(64, 64);
            var heights:Array = [8, 4, 20, 22, 10];
            var colors:Array = [0, 0x661100, 0xff7f00, 0xffd400, 0xffff66];
            var len:int = colors.length;
            var rect:Rectangle = new Rectangle(0, 0, 64);
            var yPos:int = 0, h:int;
            for (var i:int = 0; i < len; ++i) {
                rect.height = h = heights[i];
                rect.y = yPos;
                yPos += h;
                textureData.fillRect(rect, colors[i] | 0xff000000);
            }
            
            //textureData.perlinNoise(64, 64, 8, 0, true, true);
            texture.uploadFromBitmapData(textureData);
            // _context3D.setTextureAt(0, texture);
            _agalSugar.setSampler(_context3D, "colors", texture);
            //addChild(new Bitmap(textureData)).y = 40;
            
            _model = new Matrix3D;
            _world = new Matrix3D;
            _projection = new PerspectiveMatrix3D();
            _projection.perspectiveFieldOfViewRH(42.7, stage.stageWidth / stage.stageHeight, 1.0, 40.0);
            
            updateProgram();
            
            // _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 12, new Vector.<Number>([  light.x, light.y, light.z, 1.0]));
            // _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 13, new Vector.<Number>([  eye.x, eye.y, eye.z, 0.0]));
            // _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 14, new Vector.<Number>([  0.0, 0.0, 0.0,  0.0]));
            // _context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, new Vector.<Number>([  1.0, 1.0, 1.0,  0.0]));
            
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
        }
        
        private function initAGAL():void {
            _agalSugar = new AGALSugar(
                _constants,
                _attributes,
                _varying,
                _samplers,
                _vertexMasm.text,
                _fragmentMasm.text
            );
            _vertexAsm.text   = _agalSugar.asm.v;
            _fragmentAsm.text = _agalSugar.asm.f;
        }

        private var program:Program3D;
        private function updateProgram(e:MouseEvent = null):void {
            try {
                initAGAL();
                if(!program) program = _context3D.createProgram();
                program.upload(
                    _agalSugar.bytecode.v,
                    _agalSugar.bytecode.f
                );
                _status.text = "No errors. Symbol table:\n\n";
                for(var name:String in _agalSugar._symbols) _status.text += _agalSugar._symbols[name] + "\n";
                _context3D.setProgram(program);
                //_agalSugar.initLiterals(_context3D);
                _agalSugar.setParams(_context3D, { lightDirection: [0.0, 0.0, 1.0, 0.0] }); // initializes literals too            
            } catch(e:Error) {
                _status.text = e.message;
            }
        }
        
        private function initTorus():void {
            var i:int, j:int, k:int, m:int;
            var phi:Number, psi:Number;
            var verticies:Vector.<Number> = new Vector.<Number>(6 * K, true);
            for (i = 0; i < N0; ++i) {
                for (j = 0; j < N1; ++j) {
                    phi = i * 2 * Math.PI / N0;
                    psi = j * 2 * Math.PI / N1;
                    k = (j + N1 * i) * 6;
                    verticies[k]     = (R0 + R1 * Math.cos(psi)) * Math.cos(phi);
                    verticies[k + 1] = (R0 + R1 * Math.cos(psi)) * Math.sin(phi);
                    verticies[k + 2] = R1                        * Math.sin(psi);

                    verticies[k + 3] = (R0 + (1+R1) * Math.cos(psi)) * Math.cos(phi);
                    verticies[k + 4] = (R0 + (1+R1) * Math.cos(psi)) * Math.sin(phi);
                    verticies[k + 5] = (1+R1)                        * Math.sin(psi);

                    for (m = 0; m < 3; ++m) {
                        verticies[k + m + 3] -= verticies[k + m];
                    }
                }
            }
            var verticiesBuffer:VertexBuffer3D = _context3D.createVertexBuffer(K, 6);
            verticiesBuffer.uploadFromVector(verticies, 0, K);
            _context3D.setVertexBufferAt(0, verticiesBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
            _context3D.setVertexBufferAt(1, verticiesBuffer, 3, Context3DVertexBufferFormat.FLOAT_3);
            
            var indeces:Vector.<uint> = new Vector.<uint>(6 * K, true);
            for (i = 0; i < N0; ++i) {
                for (j = 0; j < N1; ++j) {
                    k = j + i * N1;
                    m = 6 * k;
                    indeces[m]     = k;
                    indeces[m + 1] = (k + N1)     % K;
                    indeces[m + 2] = (k + 1)      % K;
                    indeces[m + 3] = (k + N1 + 1) % K;
                    indeces[m + 4] = (k + 1)      % K;
                    indeces[m + 5] = (k + N1)     % K;
                }
            }
            _indecesBuffer = _context3D.createIndexBuffer(indeces.length);
            _indecesBuffer.uploadFromVector(indeces, 0, indeces.length);
        }
        
        private var _pitch:Number = 0.0;
        private var _yaw:Number = 0.0;
        private var _s:BitmapData;
        private function onEnterFrame(event:Event):void {
            _context3D.clear(1, 1, 1);
            _model.identity();
            _model.appendRotation(_pitch += 0.3, Vector3D.X_AXIS);
            _model.appendRotation(_yaw += 0.2, Vector3D.Y_AXIS);
            _model.appendTranslation(0, 0, -12);
            
            _world.identity();
            _world.append(_model);
            _world.append(_projection);

            _agalSugar.setConstant(_context3D, "world", _world);
            _agalSugar.setConstant(_context3D, "model", _model);
            // _context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _world, true);
            // _context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 4, _model, true);

            _context3D.drawTriangles(_indecesBuffer);
            // if(!_s){_s=new BitmapData(stage.stageWidth&~1,stage.stageHeight&~1,false,0);addChildAt(new Bitmap(_s),0);_context3D.drawToBitmapData(_s)};
             _context3D.present();
        }
    }
}

import com.bit101.components.*;
import flash.display.*;

class TA extends TextArea {
	public function TA(parent:DisplayObjectContainer=null, xpos:Number=0, ypos:Number=0, text:String="", editable:Boolean = false) {
		super(parent, xpos, ypos, text);
        textField.wordWrap = false;
        _panel.alpha = 0.5;
        if(!(this.editable = editable)) textField.alpha = 0.7;
	}
}

import com.bit101.components.*;
Style.LABEL_TEXT = 0;

import com.adobe.utils.AGALMiniAssembler;
import flash.geom.*;
import flash.display3D.*;
import flash.display3D.textures.*;

class AGALSugar {
    public var _symbols:Object = {};
    protected var _literals:Object = {};
    protected var _assembler:AGALMiniAssembler = new AGALMiniAssembler();
    public var asm:Object = { v: "", f: "" };
    public var bytecode:Object = {};

    public function AGALSugar(constants:String, attributes:String, varying:String, samplers:String, vp:String, fp:String) {
        var regIdx:int;
        var name:String;
        var decl:Decl;
        var sym:Symbol;
        var shader:String; // "v" or "f"
        var masm:Object = { v: _cleanCode(vp), f: _cleanCode(fp) };

        constants  = _cleanDecls(constants);
        attributes = _cleanDecls(attributes);
        varying    = _cleanDecls(varying);
        samplers   = _cleanSamplerDecls(samplers);

        // create all declared symbols
        for each(name in _declNames([samplers, constants, attributes, varying].filter(function(...a):*{return a[0]!="";}).join(","))) _newSymbol(name);
        // allocate vertex shader registers for attribute decls
        regIdx = 0;
        for each(decl in _declObjects(attributes)) {
            sym = _getSymbol(decl.name);
            sym.vr = new RegAlloc("va", decl.size, sym, regIdx, null);
            regIdx += decl.size+3>>2;
        }
        // allocate vertex and fragment regs for varying decls
        regIdx = 0;
        for each(decl in _declObjects(varying)) {
            sym = _getSymbol(decl.name);
            sym.fr = sym.vr = new RegAlloc("v", decl.size, sym, regIdx, null);
            regIdx += decl.size+3>>2;
        }
        // automatically copy vertex attributes to varying registers (when used in fragment program)
        for each(name in _referencedNames(masm.f)) {
            sym = _getSymbol(name);
            if(sym.vr && sym.vr.type == "va") {
                sym.fr = new RegAlloc("v", sym.vr.data32, sym, regIdx, null);
                for(var i:int=0; i<((sym.vr.data32+3)>>2); i++) {
                    masm.v += "mov v" + regIdx + ", va" + (sym.vr.regIdx+i) + "\n";
                    regIdx++;
                }
            }
        }
        // allocate fragment samplers
        regIdx = 0;
        for each(name in _split(samplers)) {
            sym = _getSymbol(name);
            sym.fr = new RegAlloc("fs", 0, sym, regIdx++, null);
        }
        // allocate vertex and fragment constant regs
        for each(shader in ["v", "f"]) {
            regIdx = 0;
            for each(name in _referencedNames(masm[shader])) {
                sym = _getSymbol(name);
                if((decl = _findDecl(name, constants))) {
                    sym[shader+"r"] = new RegAlloc(shader+"c", decl.size, sym, regIdx, null);
                    regIdx += decl.size+3>>2;
                }
            }
            // create literals (autogenerated constants)
            var comp:int = 0;
            _literals[shader] = new LiteralData(regIdx);
            for each(var literal:Number in _referencedLiterals(masm[shader])) {
                sym = _symbols[String(literal)] || _newSymbol(String(literal));
                sym.isLiteral = true;
                sym[shader+"r"] = new RegAlloc(shader+"c", 1, sym, regIdx, "xyzw".charAt(comp));
                _literals[shader].data.push(literal);
                if(++comp == 4) {
                    comp = 0;
                    regIdx++;
                }
            }
            while(comp++ & 3) _literals[shader].data.push(0); // padding
        }
        // preprocess programs, replace symbols with registers, assemble bytecode
        for each(shader in ["v", "f"]) {
            var rex:RegExp = /\$([a-zA-Z_][a-zA-Z0-9_]+|[0-9-\.]+)(:([0-9]+))?/g; // exec result: [0] full match, [1] symbol name, [3] offset (or null)
            var res:Array, lastMatchEnd:int = 0;
            while(res = rex.exec(masm[shader])) {
                asm[shader] += masm[shader].substring(lastMatchEnd, res.index);
                sym = _getSymbol(res[1]);
                var reg:RegAlloc = sym[shader+"r"]; 
                asm[shader] += reg.type + int(reg.regIdx + int(res[3]));
                if(reg.component) asm[shader] += "." + reg.component;
                lastMatchEnd = res.index + res[0].length;
            }
            asm[shader] += masm[shader].substr(lastMatchEnd);
            bytecode[shader] = _assembler.assemble(shader == "v" ? "vertex" : "fragment", asm[shader]);
            if(_assembler.error != "") throw(new Error(_assembler.error));
        }
    }

    // Set several shader constants/textures from name-value properties (in params argument).
    // literalsToo specifies whether to setup const regs for numeric literals as well.
    public function setParams(ctx:Context3D, params:Object, literalsToo:Boolean = true, transposeMatrices:Boolean = true):void {
        for(var name:String in params) {
            if(_getSymbol(name).isSampler) setSampler(ctx, name, params[name]);
            else setConstant(ctx, name, params[name], transposeMatrices);
        }
        if(literalsToo) initLiterals(ctx);
    }

    public function setConstant(ctx:Context3D, name:String, value:*, transposeMatrices:Boolean = true):void {
        var sym:Symbol = _getSymbol(name);
        for each(var reg:RegAlloc in [sym.vr, sym.fr]) {
            if(reg) {
                var size:int = (reg.data32+3) >> 2; // number of regs to set
                if(value is Vector.<Number>) ctx.setProgramConstantsFromVector(reg.shaderType, reg.regIdx, value as Vector.<Number>, size);
                else if(value is Matrix3D && reg.data32 == 16) ctx.setProgramConstantsFromMatrix(reg.shaderType, reg.regIdx, value as Matrix3D, transposeMatrices);
                else if(value is Array) ctx.setProgramConstantsFromVector(reg.shaderType, reg.regIdx, Vector.<Number>(value as Array), size);
                else if(value is Number && reg.data32 == 1) ctx.setProgramConstantsFromVector(reg.shaderType, reg.regIdx, Vector.<Number>([Number(value)]), size);
                else throw(new Error("Failed to set " + reg.shaderType + " constant " + name + " to " + value + " (bad value type)"));
            }
        }
    }

    public function setSampler(ctx:Context3D, name:String, texture:TextureBase):void {
        var sym:Symbol = _getSymbol(name);
        if(sym.fr && sym.fr.type == "fs") ctx.setTextureAt(sym.fr.regIdx, texture);
        else throw(new Error(name + " is not a texture sampler"));
    }

    public function initLiterals(ctx:Context3D, vs:Boolean = true, fs:Boolean = true):void {
        if(vs) ctx.setProgramConstantsFromVector("vertex", _literals.v.offset, _literals.v.data);
        if(fs) ctx.setProgramConstantsFromVector("fragment", _literals.f.offset, _literals.f.data);
    }

    protected function _cleanDecls(decls:String):String { return decls.replace(/\s*/g, "") }; // TODO: validation
    protected function _cleanSamplerDecls(decls:String):String { return decls.replace(/\s*/g, "") }; // TODO: validation

    protected function _cleanCode(decls:String):String {
        decls = decls.replace(/\s*\/\/.*$/gm, ""); // strip comments
        decls = decls.replace(/^\s*/gm, ""); // strip whitespace at BOL
        return decls;
    }

    protected function _declNames(decls:String):Array { return _split(decls.replace(/:[^,]*/g, "")); }

    protected function _declObjects(decls:String):Array {
        return _split(decls).map(function (decl:String, ..._):Object {
                var a:Array = decl.split(":");
                return new Decl(a[0], a[1]);
            });
    }

    protected function _findDecl(name:String, decls:String):Decl {
        for each(var decl:Decl in _declObjects(decls)) if(decl.name == name) return decl;
        return null;
    }

    protected function _newSymbol(name:String):Symbol {
        if(_symbols[name]) throw(new Error("Duplicate symbol definition: " + name));
        var sym:Symbol = new Symbol;
        sym.name = name;
        return(_symbols[name] = sym);
    }

    protected function _getSymbol(name:String):Symbol {
        if(!isNaN(Number(name))) name = String(Number(name));
        if(!_symbols[name]) throw(new Error("Undefined symbol: " + name));
        return _symbols[name];
    }

    protected function _referencedNames(masm:String):Vector.<String> {
        var ret:Vector.<String> = new Vector.<String>;
        for each(var name:String in masm.match(/\$[a-zA-Z_][a-zA-Z0-9_]*/g)) {
            if(ret.indexOf(name.substr(1)) == -1) ret.push(name.substr(1));
        }
        return ret;
    }

    protected function _referencedLiterals(masm:String):Vector.<Number> {
        var ret:Vector.<Number> = new Vector.<Number>;
        for each(var lit:String in masm.match(/\$[-0-9\.][0-9\.]*/g)) {
            var n:Number = Number(lit.substr(1));
            if(isNaN(n)) throw(new Error("Bad symbol/number: " + lit));
            if(ret.indexOf(n) == -1) ret.push(n);
        }
        return ret;
    }

    // splits on ",", returns empty array for empty string!
    protected function _split(s:String):Array { return s == "" ? [] : s.split(",") }
}

class Decl {
    public var name:String;
    public var size:int;
    public function Decl(name:String, size:int) {
        this.name = name
        this.size = size
    }
}

class Symbol {
    public var name:String;
    public var vr:RegAlloc;
    public var fr:RegAlloc;
    public var isLiteral:Boolean = false;
    public function get isConstant():Boolean { return((fr && fr.type == "fc") || (vr && vr.type == "vc")); }
    public function get isSampler():Boolean { return(fr && fr.type == "fs"); }
    public function toString():String {
        return(name + " - " + (isLiteral?"literal ":"") + (isConstant?"constant ":"") + (isSampler?"sampler ":"") + (vr?"\n  "+vr:"") + (fr?"\n  "+fr:""));
    }
}

class RegAlloc {
    public var type:String; // vc, va, v, fc, fs
    public var data32:int; // size (in components)
    public var symbol:Symbol;
    public var regIdx:int;
    public var component:String; // literals only
    public function RegAlloc(type:String, data32:int, symbol:Symbol, regIdx:int, component:String) {
        this.type = type;
        this.data32 = data32;
        this.symbol = symbol;
        this.regIdx = regIdx;
        this.component = component;
    }
    public function get shaderType():String { return(type.charAt(0) == "v" ? "vertex" : "fragment"); }
    public function toString():String { return(type + regIdx + (component ? ("."+component) : "")); }
}

class LiteralData {
    public var offset:int;
    public var data:Vector.<Number> = new Vector.<Number>;
    public function LiteralData(offset:int) { this.offset = offset; }
}