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

forked from: Stage3D vs. BitmapData.copyPixels()

Rendering in batches for the GPU. Slightly faster for me now than with BitmapData.copyPixels().
/**
 * Copyright runo ( http://wonderfl.net/user/runo )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/dsfj
 */

package {
    import com.bit101.components.PushButton;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.display.Stage3D;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.filters.GlowFilter;
    import flash.text.TextField;
    import net.hires.debug.Stats;
/*    import ore.orelib.commons.Key;
    import ore.orelib.commons.Labeler;
*/    
    [SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "0x000000")]
    public class Main extends Sprite {
        private var _stage3D:Stage3D;
        private var _ore2D:Ore2D;
        private var _particles:Vector.<Particle>;
        private var _particlePool:Vector.<Particle>;
        private var _image:BitmapData;
        private var _screen:BitmapData;
        private var _numParticlesLabel:TextField;
        private var _renderingMode:Boolean;
        
        public function Main() {
            _stage3D = stage.stage3Ds[0];
            _stage3D.addEventListener(Event.CONTEXT3D_CREATE, init);
            _stage3D.requestContext3D();
        }
        
        private function init(event:Event):void {
            event.currentTarget.removeEventListener(event.type, arguments.callee);
            
            _ore2D = new Ore2D(_stage3D, 233, 233);
            _particles = new Vector.<Particle>();
            _particlePool = new Vector.<Particle>();
            
            _image = createImage();
            _ore2D.upload(new <BitmapData>[_image]);
            
            addChild(new Bitmap(_screen = new BitmapData(465, 465, true, 0x00FFFFFF)));
            addChild(_numParticlesLabel = new Labeler()
                .align(Labeler.BOTTOM_RIGHT).filters([new GlowFilter(0x000000, 1, 4, 4)])
                .fontColor(0xFFFFFF).pos(365, 0).size(100, 20).build("")
            );
            new PushButton(this, 360, 20, "change", function(event:MouseEvent):void {
                _renderingMode = !_renderingMode;
            });
            _renderingMode = true;
            addChild(new Stats());
            
            Key.init(this);
            addEventListener(Event.ENTER_FRAME, update);
        }
        
        private function createImage():BitmapData {
            var result:BitmapData = new BitmapData(16, 16, true, 0x00FFFFFF);
            var sp:Sprite = new Sprite();
            var g:Graphics = sp.graphics;
            g.beginFill(0xFFFFFF); g.drawCircle(8, 8, 4); g.endFill();
            sp.filters = [new GlowFilter(0xFFFF00, 1, 4, 4)];
            result.draw(sp);
            return result;
        }
        
        private function update(event:Event):void {
            if (Key.isDown(Key.MOUSE_LEFT)) { emitParticles(stage.mouseX, stage.mouseY); }
            
            _ore2D.startFrame();
            
            _stage3D.context3D.clear();
            _screen.fillRect(_screen.rect, 0x00FFFFFF);
            for (var i:int = _particles.length - 1; i >= 0; i--) {
                var particle:Particle = _particles[i];
                particle.update();
                
                if (0 < particle.pos.x && particle.pos.x < 465 && 0 < particle.pos.y && particle.pos.y < 465) {
                    (_renderingMode) ? _ore2D.draw(particle.image, particle.dest) : _screen.copyPixels(particle.image, particle.image.rect, particle.dest, null, null, true);
                } else {
                    _particles.splice(i, 1);
                    _particlePool.push(particle);
                }
            }
            
            _ore2D.endFrame();
            
            _stage3D.context3D.present();
            
            _numParticlesLabel.text = ((_renderingMode) ? "GPU" : "CPU") + ": " + _particles.length.toString();
        }
        
        private function emitParticles(x:Number, y:Number):void {
            var a:Number = Math.PI / 60;
            for (var i:int = 0; i < 120; i++) {
                var particle:Particle = (_particlePool.length) ? _particlePool.pop() : new Particle();
                particle.init(x, y, 3 * Math.cos(a * i), 3 * Math.sin(a * i), _image);
                _particles.push(particle);
            }
        }
    }
}
//package {
    import com.adobe.utils.AGALMiniAssembler;
    import flash.display.BitmapData;
    import flash.display.Stage3D;
    import flash.display3D.Context3D;
    import flash.display3D.Context3DBlendFactor;
    import flash.display3D.Context3DProgramType;
    import flash.display3D.Context3DTextureFormat;
    import flash.display3D.Context3DVertexBufferFormat;
    import flash.display3D.IndexBuffer3D;
    import flash.display3D.Program3D;
    import flash.display3D.textures.Texture;
    import flash.display3D.VertexBuffer3D;
    import flash.events.Event;
    import flash.geom.Point;
    import flash.utils.ByteArray;
    import flash.utils.Dictionary;
    
    //public 
    class Ore2D {
        private const BUFFER_SIZE:int = 128;
        
        private var _context3D:Context3D;
        private var _backBufferHalfSize:Point;
        private var _vertexData:Vector.<Number>;
        private var _vertexBuffer:VertexBuffer3D;
        private var _indexBuffer:IndexBuffer3D;
        private var _vertexProgram:ByteArray;
        private var _fragmentProgram:ByteArray;
        private var _bitmapDataToTexture:Dictionary;
        
        private var index:int;
        
        public function Ore2D(stage3D:Stage3D, backBufferHalfWidth:int, backBufferHalfHeight:int) {
            _context3D = stage3D.context3D;
            
            _backBufferHalfSize = new Point(backBufferHalfWidth, backBufferHalfHeight);
            _vertexData = new Vector.<Number>(8, true);
            var assembler:AGALMiniAssembler = new AGALMiniAssembler();
            _vertexProgram = assembler.assemble(Context3DProgramType.VERTEX, 
            [
                "mov v0,va0.xy",
                "mult vt0.xy, va0.xy, vc[va0.z].xy", // width and height
                "add vt0, vt0.xy, vc[va0.z].zw", // offset x, y
                "mov vt0.zw, vc0.zw", //  set z = 0, w = 1
                "mov op, vt0",
            ].join("\n"));
            _fragmentProgram = assembler.assemble(Context3DProgramType.FRAGMENT, 
            [
                "tex oc, v0, fs0<2d, clamp, nearest, nomip>", //sample texture
            ].join('\n'));
            _bitmapDataToTexture = new Dictionary();
            
            onContext3DCreated();
            stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreated);
        }
        
        private function onContext3DCreated(event:Event = null):void {
            if (event) { _context3D = event.currentTarget.context3D; }
            _context3D.configureBackBuffer(_backBufferHalfSize.x * 2, _backBufferHalfSize.y * 2, 0, false);
            
            var _indexesFull:Vector.<uint> = new Vector.<uint>();
            var _vertexFull:Vector.<Number> = new Vector.<Number>();
            for (var i:int = 0; i < BUFFER_SIZE; i++) {
                _indexesFull.push(
                0 + i * 4,
                1 + i * 4,
                2 + i * 4,
                0 + i * 4,
                2 + i * 4,
                3 + i * 4);
                
                // uv, index (to look up in vertex constants)
                _vertexFull.push(
                0,1,i+1,
                0,0,i+1,
                1,0,i+1,
                1,1,i+1
                );
            }
            
            
            _indexBuffer = _context3D.createIndexBuffer(BUFFER_SIZE*6);
            _indexBuffer.uploadFromVector(_indexesFull, 0, BUFFER_SIZE * 6);
            
            _vertexBuffer = _context3D.createVertexBuffer(BUFFER_SIZE*4, 3);
            _vertexBuffer.uploadFromVector(_vertexFull, 0, BUFFER_SIZE * 4);
            
            // program
            var program3D:Program3D = _context3D.createProgram();
            program3D.upload(_vertexProgram, _fragmentProgram);
            _context3D.setProgram(program3D);
            
            // texture
            for (var bitmapData:Object in _bitmapDataToTexture) {
                uploadFromBitmapData(bitmapData as BitmapData);
            }
            // blend
            _context3D.setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);
        }
        
        public function upload(bitmapDataList:Vector.<BitmapData>):void {
            for (var i:int = 0; i < bitmapDataList.length; i++) {
                uploadFromBitmapData(bitmapDataList[i]);
            }
        }
        
        private function uploadFromBitmapData(bitmapData:BitmapData):void {
            var texture:Texture = _context3D.createTexture(bitmapData.width, bitmapData.height, Context3DTextureFormat.BGRA, false);
            texture.uploadFromBitmapData(bitmapData);
            _bitmapDataToTexture[bitmapData] = texture;
        }
        
        public var lastTex:BitmapData = null;
        public function startFrame():void {
            index = 0;
            
            // vertex buffer
            _context3D.setVertexBufferAt(0, _vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3); // uv, index
            
            _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 0, Vector.<Number>([0,0,0,1]));
            
        }
        
        private var v:Vector.<Number> = new Vector.<Number>(4);
        public function draw(source:BitmapData, dest:Point):void {
            if(lastTex != source){
                _context3D.setTextureAt(0, _bitmapDataToTexture[source]);
            }
            
            v[0] = source.width / _backBufferHalfSize.x;
            v[1] = -source.height / _backBufferHalfSize.y;
            v[2] = dest.x / _backBufferHalfSize.x - 1;
            v[3] = -dest.y / _backBufferHalfSize.y + 1;
            
            
            _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, index+1, v);
            
            index++;
            if (index + 1 >= BUFFER_SIZE) {
                _context3D.drawTriangles(_indexBuffer, 0, 2 * index);
                index = 0;
            }
        }
        
        public function endFrame():void {
            if (index > 0) {
                _context3D.drawTriangles(_indexBuffer, 0, 2 * index);
            }
        }
        
    }
//}
//package {
    import flash.display.BitmapData;
    import flash.geom.Point;
    
    //public
    class Particle {
        private var _pos:Point;
        private var _velocity:Point;
        private var _image:BitmapData;
        private var _dest:Point;
        
        public function Particle() {
            _pos = new Point();
            _velocity = new Point();
            _dest = new Point();
        }
        
        public function init(x:Number, y:Number, vx:Number, vy:Number, image:BitmapData):void {
            _pos.setTo(x, y);
            _velocity.setTo(vx, vy);
            _image = image;
            _dest.setTo(x - (image.width >> 1), y - (image.height >> 1));
        }
        
        public function update():void {
           _pos.offset(_velocity.x, _velocity.y);
           _dest.offset(_velocity.x, _velocity.y);
        }
        
        public function get pos():Point { return _pos; }
        public function get image():BitmapData { return _image; }
        public function get dest():Point { return _dest; }
    }
//}
//package ore.orelib.commons {
    import flash.display.Sprite;
    import flash.display.Stage;
    import flash.events.ContextMenuEvent;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.ui.ContextMenu;
    
    //public 
    class Key {
        private static var _stage:Stage;
        private static var _currentStates:Vector.<Boolean>;
        private static var _previousStates:Vector.<Boolean>;
        
        public static const MOUSE_LEFT:uint = 0;
        public static const MOUSE_RIGHT:uint = 255;
        
        public static function init(documentClass:Sprite):void {
            _stage = documentClass.stage;
            _currentStates = new Vector.<Boolean>(256, true);
            _previousStates = new Vector.<Boolean>(256, true);
            
            _stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
            _stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
            _stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            _stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
            _stage.addEventListener(Event.EXIT_FRAME, update);
            _stage.addEventListener(Event.DEACTIVATE, clear);
            
            var contextMenu:ContextMenu = new ContextMenu();
            contextMenu.hideBuiltInItems();
            contextMenu.addEventListener(ContextMenuEvent.MENU_SELECT, clear);
            documentClass.contextMenu = contextMenu;
        }
        
        private static function keyDownHandler(event:KeyboardEvent):void { _currentStates[event.keyCode] = true; }
        private static function keyUpHandler(event:KeyboardEvent):void { _currentStates[event.keyCode] = false; }
        private static function mouseDownHandler(event:MouseEvent):void { _currentStates[Key.MOUSE_LEFT] = true; }
        private static function mouseUpHandler(event:MouseEvent):void { _currentStates[Key.MOUSE_LEFT] = false; }
        
        private static function update(event:Event):void {
            for (var i:int = 0; i < 256; i++) {
                _previousStates[i] = _currentStates[i];
            }
        }
        
        private static function clear(event:Event):void {
            for (var i:int = 0; i < 256; i++) {
                _currentStates[i] = false;
            }
        }
        
        public static function isDown(keyCode:uint):Boolean { return _stage.focus == null && _currentStates[keyCode]; }
        public static function pressed(keyCode:uint):Boolean { return Key.isDown(keyCode) && !_previousStates[keyCode]; }
    }
//}
//package ore.orelib.commons {
    import flash.geom.Point;
    import flash.text.AntiAliasType;
    import flash.text.GridFitType;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;
    import flash.text.TextFormatAlign;
    
    //public 
    class Labeler {
        private var _hAlign:String;
        private var _autoSize:String;
        private var _vAlign:String;
        private var _background:Boolean;
        private var _backgroundColor:uint;
        private var _filters:Array;
        private var _fontName:String;
        private var _sharpness:Number;
        private var _thickness:Number;
        private var _fontColor:uint;
        private var _fontSize:int;
        private var _position:Point;
        private var _selectable:Boolean;
        private var _size:Point;
        private var _wordWrap:Boolean;
        
        public static const NONE:String = "none";
        public static const TOP_LEFT:String = "top_left";
        public static const MIDDLE_CENTER:String = "middle_center";
        public static const BOTTOM_RIGHT:String = "bottom_right";
        
        public function Labeler() {
            _hAlign = TextFormatAlign.LEFT;
            _autoSize = TextFieldAutoSize.NONE;
            _vAlign = Labeler.TOP_LEFT;
            _background = false;
            _backgroundColor = 0xFFFFFF;
            _filters = [];
            _fontName = "_sans";
            _sharpness = _thickness = 0;
            _fontColor = 0x000000;
            _fontSize = 12;
            _position = new Point(0, 0);
            _size = new Point(100, 100);
            _selectable = _wordWrap = false;
        }
        
        public function align(value:String = Labeler.TOP_LEFT):Labeler {
            switch(value) {
                case Labeler.MIDDLE_CENTER: { _hAlign = TextFormatAlign.CENTER; break; }
                case Labeler.BOTTOM_RIGHT: { _hAlign = TextFormatAlign.RIGHT; break; }
                case Labeler.TOP_LEFT: default: { _hAlign = TextFormatAlign.LEFT; break; }
            }
            return this;
        }
        
        public function autoSize(horizontal:String = Labeler.NONE, vertical:String = Labeler.TOP_LEFT):Labeler {
            switch(horizontal) {
                case Labeler.TOP_LEFT: { _autoSize = TextFieldAutoSize.LEFT; break; }
                case Labeler.MIDDLE_CENTER: { _autoSize = TextFieldAutoSize.CENTER; break; }
                case Labeler.BOTTOM_RIGHT: { _autoSize = TextFieldAutoSize.RIGHT; break; }
                case Labeler.NONE: default: { _autoSize = TextFieldAutoSize.NONE; break; }
            }
            _vAlign = vertical;
            return this;
        }
        
        public function background(enabled:Boolean = true, color:uint = 0xFF0000):Labeler { _background = enabled; _backgroundColor = color; return this; }
        public function filters(value:Array):Labeler { _filters = value; return this; }
        public function font(name:String, sharpness:Number = 0, thickness:Number = 0):Labeler { _fontName = name; _sharpness = sharpness; _thickness = thickness; return this; }
        public function fontColor(value:uint):Labeler { _fontColor = value; return this; }
        public function fontSize(value:int):Labeler { _fontSize = value; return this; }
        public function offset(x:Number, y:Number):Labeler { _position.offset(x, y); return this; }
        public function pos(x:Number, y:Number):Labeler { _position.setTo(x, y); return this; }
        public function selectable(enabled:Boolean = true):Labeler { _selectable = enabled; return this; }
        public function size(width:Number, height:Number):Labeler { _size.setTo(width, height); return this; }
        public function wordWrap(enabled:Boolean = true):Labeler { _wordWrap = enabled; return this; }
        
        public function build(text:String):TextField {
            var result:TextField = new TextField();
            result.x = _position.x; result.width = _size.x; result.height = _size.y;
            result.autoSize = _autoSize;
            result.background = _background; result.backgroundColor = _backgroundColor;
            result.filters = _filters;
            result.mouseEnabled = result.selectable = _selectable;
            result.wordWrap = _wordWrap;
            result.defaultTextFormat = new TextFormat(_fontName, _fontSize, _fontColor, null, null, null, null, null, _hAlign);
            if (_fontName != "_sans") {
                result.embedFonts = true;
                result.antiAliasType = AntiAliasType.ADVANCED;
                result.gridFitType = (_hAlign == TextFormatAlign.LEFT) ? GridFitType.PIXEL : GridFitType.SUBPIXEL;
                result.sharpness = _sharpness; result.thickness = _thickness;
            }
            result.text = text;
            switch(_vAlign) {
                case Labeler.MIDDLE_CENTER: { result.y = _position.y + (_size.y - result.height) / 2; break; }
                case Labeler.BOTTOM_RIGHT: { result.y = _position.y + (_size.y - result.height); break; }
                case Labeler.TOP_LEFT: default: { result.y = _position.y; break; }
            }
            return result;
        }
    }
//}