Julia Eyes <3 Julia Mandelbrot + PixelBender test lespleen forked:0favorite:6lines:362license : MIT License modified : 2011-06-30 19:39:08 Embed Tweet package { import flash.display.*; import flash.events.*; import flash.geom.Rectangle; import flash.geom.Point; import flash.utils.*; import flash.filters.* import flash.events.* import flash.net.URLLoader; import flash.net.URLRequest; import flash.net.URLLoaderDataFormat; import flash.system.Security; import flash.filters.ShaderFilter; import flash.system.LoaderContext; import net.hires.debug.Stats; [SWF(width="400", height="400", frameRate="35", backgroundColor="#000000")] final public class Julia extends Sprite { private var fx:VolumetricPointLight; public var bmp:Bitmap; public var bd:BitmapData; public var COMPLEX_REAL:Number public var threshold:Number public var COMPLEX_IM:Number public var r:Number public var phase:Number private var sinLUT:TrigLUT; private var cosLUT:TrigLUT; private var W:int = 0 private var H:int = 0 private var pixels:Vector.<uint>; private var pjbLoader:URLLoader; private var shader:Shader private var filter:ShaderFilter; private const ZERO_POINT:Point = new Point(0,0) public function Julia() { super() stage ? init() : addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true); } private function init():void { Security.loadPolicyFile("http://www.spleen.noo.name/crossdomain.xml"); pjbLoader = new URLLoader(); pjbLoader.dataFormat = URLLoaderDataFormat.BINARY; pjbLoader.addEventListener(Event.COMPLETE,onLoadPjb,false,0,true); pjbLoader.load(new URLRequest("http://www.spleen.noo.name/pbj/FocusingLinearBlur.pbj")) } private function onLoadPjb(e:Event):void { pjbLoader.removeEventListener(Event.COMPLETE, onLoadPjb) W = stage.stageWidth H = stage.stageHeight stage.quality = "medium"; stage.align = "TL"; stage.scaleMode = "noScale"; sinLUT = new TrigLUT(3, Math.sin); cosLUT = new TrigLUT(3, Math.cos); shader= new Shader( pjbLoader.data ); //shader.data["amount"]["value"] = [0.2]; //shader.data["steps"]["value"] = [10]; filter = new ShaderFilter( shader ) pixels = new Vector.<uint>(W * H, true); bd = new BitmapData( W, H, false, 0); bmp = new Bitmap( bd); fx = new VolumetricPointLight(800, 600, bmp, [0xc08040, 0x4080c0, 0], [1, 1, 1], [0, 20, 30]); addChild( fx ); fx.srcX = W/2 fx.srcY = H/2 //fx.setViewportSize(W, H); fx.startRendering(); // addChild( new Stats()) COMPLEX_REAL = 0; COMPLEX_IM = 0; threshold = 50; r =100; phase = Math.random() * 2 * Math.PI; this.addEventListener(Event.ENTER_FRAME, run, false, 0, true); } private function run(e:Event) : void { //shader.data.center.value=[ mouseX, mouseY] r = sinLUT.val(getTimer() / 9173 + phase); COMPLEX_REAL = r * cosLUT.val( getTimer() / 2830) + (mouseX - 200) / 200; COMPLEX_IM = r * sinLUT.val( getTimer() / 1297) + (mouseY - 200) / 200;; draw(); } private function draw() : void { var passion:Number,love:Number var step:int = 0; var we:Number,are:Number bd.lock() bd.fillRect( bd.rect, 0xa0000000); var x:int = 0; var y:int = 0; while (x < W) { y= 0; while (y < H) { passion = (x - W/2) / 200; love = (y - H/2) / 200; step = 0; while (step< 80) { if (passion * passion + love * love > threshold) { pixels[y*H + x ] = 0xa0 << 24 | (255 * step / 20) << 16 | 0x0 << 8 | 0x0; break; } we = passion * passion - love * love + COMPLEX_REAL; are = ((passion * love)*2) + COMPLEX_IM; passion = we love = are step += 4; } y++; } x++; } bd.setVector(bd.rect, pixels) bd.applyFilter( bd, bd.rect, ZERO_POINT, filter) bd.unlock() }// end function } } /** * VolumetricPointLight creates a simple effect container with a gradient emission pattern. * The gradient's center is automatically moved to the (srcX, srcY) coordinates * and it's radius is adjusted to the length of the viewport's diagonal, so if you * set srcX and srcY to the viewport's center then only half of the gradient colors * will be used. * * <p>This should also perform a little better than EffectContainer.</p> */ import flash.display.*; import flash.events.*; import flash.filters.*; import flash.geom.*; class EffectContainer extends Sprite { public var blur:Boolean = false; public var colorIntegrity:Boolean = false; public var intensity:Number = 4; public var passes:uint = 6; public var rasterQuality:String = null; public var scale:Number = 2; public var smoothing:Boolean = true; public var srcX:Number; public var srcY:Number; protected var _blurFilter:BlurFilter = new BlurFilter(2, 2); protected var _emission:DisplayObject; protected var _occlusion:DisplayObject; protected var _ct:ColorTransform = new ColorTransform; protected var _halve:ColorTransform = new ColorTransform(0.5, 0.5, 0.5); protected var _occlusionLoResBmd:BitmapData; protected var _occlusionLoResBmp:Bitmap; protected var _baseBmd:BitmapData; protected var _bufferBmd:BitmapData; protected var _lightBmp:Bitmap = new Bitmap; protected var _bufferSize:uint = 0x8000; protected var _bufferWidth:uint; protected var _bufferHeight:uint; protected var _viewportWidth:uint; protected var _viewportHeight:uint; protected var _mtx:Matrix = new Matrix; /** * Creates a new effect container. * * @param width Viewport width in pixels. * @param height Viewport height in pixels. * @param emission A DisplayObject to which the effect will be applied. This object will be * added as a child of the container. When applying the effect the object's filters and color * matrix is ignored, if you want to use filters or a color matrix put your content in another * object and addChild it to this one instead. * @param occlusion An optional occlusion object, handled the same way as the emission object. */ public function EffectContainer(width:uint, height:uint, emission:DisplayObject, occlusion:DisplayObject = null) { if(!emission) throw(new Error("emission DisplayObject must not be null.")); addChild(_emission = emission); if(occlusion) addChild(_occlusion = occlusion); setViewportSize(width, height); _lightBmp.blendMode = BlendMode.ADD; addChild(_lightBmp); srcX = width / 2; srcY = height / 2; } /** * Sets the container's size. This method recreates internal buffers (slow), do not call this on * every frame. * * @param width Viewport width in pixels * @param height Viewport height in pixels */ public function setViewportSize(width:uint, height:uint):void { _viewportWidth = width; _viewportHeight = height; scrollRect = new Rectangle(0, 0, width, height); _updateBuffers(); } /** * Sets the approximate size (in pixels) of the effect's internal buffers. Smaller number means lower * quality and better performance. This method recreates internal buffers (slow), do not call this on * every frame. * * @param size Buffer size in pixels */ public function setBufferSize(size:uint):void { _bufferSize = size; _updateBuffers(); } protected function _updateBuffers():void { var aspect:Number = _viewportWidth / _viewportHeight; _bufferHeight = Math.max(1, Math.sqrt(_bufferSize / aspect)); _bufferWidth = Math.max(1, _bufferHeight * aspect); dispose(); _baseBmd = new BitmapData(_bufferWidth, _bufferHeight, false, 0); _bufferBmd = new BitmapData(_bufferWidth, _bufferHeight, false, 0); _occlusionLoResBmd = new BitmapData(_bufferWidth, _bufferHeight, true, 0); _occlusionLoResBmp = new Bitmap(_occlusionLoResBmd); } /** * Render a single frame. * * @param e In case you want to make this an event listener. */ public function render(e:Event = null):void { var savedQuality:String = stage.quality; if(rasterQuality) stage.quality = rasterQuality; var mul:Number = colorIntegrity ? intensity : intensity/(1<<passes); _ct.redMultiplier = _ct.greenMultiplier = _ct.blueMultiplier = mul; _drawLoResEmission(); if(_occlusion) _eraseLoResOcclusion(); if(rasterQuality) stage.quality = savedQuality; var s:Number = 1 + (scale-1) / (1 << passes); var tx:Number = srcX/_viewportWidth*_bufferWidth; var ty:Number = srcY/_viewportHeight*_bufferHeight; _mtx.identity(); _mtx.translate(-tx, -ty); _mtx.scale(s, s); _mtx.translate(tx, ty); _lightBmp.bitmapData = _applyEffect(_baseBmd, _bufferBmd, _mtx, passes); _lightBmp.width = _viewportWidth; _lightBmp.height = _viewportHeight; _lightBmp.smoothing = smoothing; } /** * Draws a scaled-down emission on _baseBmd. */ protected function _drawLoResEmission():void { _copyMatrix(_emission.transform.matrix, _mtx); _mtx.scale(_bufferWidth / _viewportWidth, _bufferHeight / _viewportHeight); _baseBmd.fillRect(_baseBmd.rect, 0); _baseBmd.draw(_emission, _mtx, colorIntegrity ? null : _ct); } /** * Draws a scaled-down occlusion on _occlusionLoResBmd and erases it from _baseBmd. */ protected function _eraseLoResOcclusion():void { _occlusionLoResBmd.fillRect(_occlusionLoResBmd.rect, 0); _copyMatrix(_occlusion.transform.matrix, _mtx); _mtx.scale(_bufferWidth / _viewportWidth, _bufferHeight / _viewportHeight); _occlusionLoResBmd.draw(_occlusion, _mtx); _baseBmd.draw(_occlusionLoResBmp, null, null, BlendMode.ERASE); } /** * Render the effect on every frame until stopRendering is called. */ public function startRendering():void { addEventListener(Event.ENTER_FRAME, render); } /** * Stop rendering on every frame. */ public function stopRendering():void { removeEventListener(Event.ENTER_FRAME, render); } /** * Low-level workhorse, applies the lighting effect to a bitmap. This function modifies the src and buffer * bitmaps and it's mtx argument. * * @param src The BitmapData to apply the effect on. * @param buffer Another BitmapData object for temporary storage. Must be the same size as src. * @param mtx Effect matrix. * @param passes Number of passes to make. * @return A processed BitmapData object (supllied in either src or buffer) with final effect output. */ protected function _applyEffect(src:BitmapData, buffer:BitmapData, mtx:Matrix, passes:uint):BitmapData { var tmp:BitmapData; while(passes--) { if(colorIntegrity) src.colorTransform(src.rect, _halve); buffer.copyPixels(src, src.rect, src.rect.topLeft); buffer.draw(src, mtx, null, BlendMode.ADD, null, true); mtx.concat(mtx); tmp = src; src = buffer; buffer = tmp; } if(colorIntegrity) src.colorTransform(src.rect, _ct); if(blur) src.applyFilter(src, src.rect, src.rect.topLeft, _blurFilter); return src; } /** * Dispose of all intermediate buffers. After calling this the EffectContainer object will be unusable. */ public function dispose():void { if(_baseBmd) _baseBmd.dispose(); if(_occlusionLoResBmd) _occlusionLoResBmd.dispose(); if(_bufferBmd) _bufferBmd.dispose(); _baseBmd = _occlusionLoResBmd = _bufferBmd = _lightBmp.bitmapData = null; } protected function _copyMatrix(src:Matrix, dst:Matrix):void { dst.a = src.a; dst.b = src.b; dst.c = src.c; dst.d = src.d; dst.tx = src.tx; dst.ty = src.ty; } } import flash.display.*; import flash.events.*; import flash.geom.*; class VolumetricPointLight extends EffectContainer { protected var _colors:Array; protected var _alphas:Array; protected var _ratios:Array; protected var _gradient:Shape = new Shape; protected var _gradientMtx:Matrix = new Matrix; protected var _gradientBmp:Bitmap = new Bitmap; protected var _lastSrcX:Number; protected var _lastSrcY:Number; protected var _lastIntensity:Number; protected var _lastColorIntegrity:Boolean = false; protected var _gradientLoResBmd:BitmapData; protected var _gradientLoResDirty:Boolean = true; /** * Creates a new effect container, with an emission created from the supplied color or gradient. * The constructor lets you use a shortcut syntax for creating simple single-color gradients. * @example The shortcut syntax: * <listing>new VolumetricPointLight(800, 600, occlusion, 0xc08040);</listing> * @example is equivalent to: * <listing>new VolumetricPointLight(800, 600, occlusion, [0xc08040, 0], [1, 1], [0, 255]);</listing> * * @param width Viewport width in pixels. * @param height Viewport height in pixels. * @param occlusion An occlusion object, will be overlayed above the lighting gradient and under the light effect bitmap. * @param colorOrGradient Either a gradient colors array, or a uint color value. * @param alphas Will only be used if colorOrGradient is an array. This will be passed to beginGradientFill. * If not provided alphas will all be 1. * @param ratios Will only be used if colorOrGradient is an array. This will be passed to * beginGradientFill. If colorOrGradient is an Array and ratios aren't provided default * ones will be created automatically. */ public function VolumetricPointLight(width:uint, height:uint, occlusion:DisplayObject, colorOrGradient:*, alphas:Array = null, ratios:Array = null) { if(colorOrGradient is Array) { _colors = colorOrGradient.concat(); if(!ratios) _ratios = colorOrGradient.map(function(item:*, i:int, arr:Array):int { return 0x100*i/(colorOrGradient.length+i-1) }); if(!alphas) _alphas = _colors.map(function(..._):Number { return 1 }); } else { _colors = [colorOrGradient, 0]; _ratios = [0, 255]; } super(width, height, _gradientBmp, occlusion); if(!occlusion) throw(new Error("An occlusion DisplayObject must be provided.")); if(!(colorOrGradient is Array || colorOrGradient is uint)) throw(new Error("colorOrGradient must be either an Array or a uint.")); } protected function _drawGradient():void { var size:Number = 2 * Math.sqrt(_viewportWidth*_viewportWidth + _viewportHeight*_viewportHeight); _gradientMtx.createGradientBox(size, size, 0, -size/2 + srcX, -size/2 + srcY); _gradient.graphics.clear(); _gradient.graphics.beginGradientFill(GradientType.RADIAL, _colors, _alphas, _ratios, _gradientMtx); _gradient.graphics.drawRect(0, 0, _viewportWidth, _viewportHeight); _gradient.graphics.endFill(); if(_gradientBmp.bitmapData) _gradientBmp.bitmapData.dispose(); _gradientBmp.bitmapData = new BitmapData(_viewportWidth, _viewportHeight, true, 0); _gradientBmp.bitmapData.draw(_gradient); } /** * Updates the lo-res gradient bitmap if neccesary and copies it to _baseBmd. */ override protected function _drawLoResEmission():void { if(_gradientLoResDirty) { super._drawLoResEmission(); _gradientLoResBmd.copyPixels(_baseBmd, _baseBmd.rect, _baseBmd.rect.topLeft); _gradientLoResDirty = false; } else { _baseBmd.copyPixels(_gradientLoResBmd, _baseBmd.rect, _baseBmd.rect.topLeft); } } /** @inheritDoc */ override protected function _updateBuffers():void { super._updateBuffers(); _gradientLoResBmd = new BitmapData(_bufferWidth, _bufferHeight, false, 0); _gradientLoResDirty = true; } /** @inheritDoc */ override public function setViewportSize(width:uint, height:uint):void { super.setViewportSize(width, height); _drawGradient(); _gradientLoResDirty = true; } /** @inheritDoc */ override public function render(e:Event = null):void { var srcChanged:Boolean = _lastSrcX != srcX || _lastSrcY != srcY; if(srcChanged) _drawGradient(); _gradientLoResDirty ||= srcChanged; _gradientLoResDirty ||= (!colorIntegrity && (_lastIntensity != intensity)); _gradientLoResDirty ||= (_lastColorIntegrity != colorIntegrity); _lastSrcX = srcX; _lastSrcY = srcY; _lastIntensity = intensity; _lastColorIntegrity = colorIntegrity; super.render(e); } } /** * A lookup table for trig values (e.g. sine, cosine) to improve on the * performance of the static functions found in the Math class * @author Jackson Dunstan */ class TrigLUT { /** 2 * PI, the number of radians in a circle*/ public static const TWO_PI:Number = 2.0 * Math.PI; /** The static TWO_PI cached as a non-static field*/ private const TWO_PI:Number = TrigLUT.TWO_PI; /** Table of trig function values*/ public var table:Vector.<Number>; /** 10^decimals of precision*/ public var pow:Number; /** * Make the look up table * @param numDigits Number of digits places of precision * @param mathFunc Math function to call to generate stored values. * Must be valid on [0,2pi). * @throws Error If mathFunc is null or invalid on [0,2pi) */ public function TrigLUT(numDigits:uint, mathFunc:Function) { var pow:Number = this.pow = Math.pow(10, numDigits); var round:Number = 1.0 / pow; var len:uint = 1 + this.TWO_PI*pow; var table:Vector.<Number> = this.table = new Vector.<Number>(len); var theta:Number = 0; for (var i:uint = 0; i < len; ++i) { table[i] = mathFunc(theta); theta += round; } } /** * Look up the value of the given number of radians * @param radians Radians to look up the value of * @return The value of the given number of radians */ public function val(radians:Number): Number { return radians >= 0 ? this.table[int((radians%this.TWO_PI)*this.pow)] : this.table[int((TWO_PI+radians%this.TWO_PI)*this.pow)]; } /** * Look up the value of the given number of radians * @param radians Radians to look up the value of. Must be positive. * @return The sine of the given number of radians * @throws RangeError If radians is not positive */ public function valPositive(radians:Number): Number { return this.table[int((radians%this.TWO_PI)*this.pow)]; } /** * Look up the value of the given number of radians * @param radians Radians to look up the value of. Must be on (-2pi,2pi). * @return The value of the given number of radians * @throws RangeError If radians is not on (-2pi,2pi) */ public function valNormalized(radians:Number): Number { return radians >= 0 ? this.table[int(radians*this.pow)] : this.table[int((this.TWO_PI+radians)*this.pow)]; } /** * Look up the value of the given number of radians * @param radians Radians to look up the value of. Must be on [0,2pi). * @return The value of the given number of radians * @throws RangeError If radians is not on [0,2pi) */ public function valNormalizedPositive(radians:Number): Number { return this.table[int(radians*this.pow)]; } } Code Fullscreen Preview Fullscreen gaziya tjoen dnddar bradsedito xor kleinschmidt.. fractal julia mandelbrot pixelbender table width size shader quality threshold Bitmap BitmapData Shader Matrix getTimer Error ShaderFilter filter smoothing topLeft dispose ColorTransform scale BlendMode.ERASE