forked from: forked from: マンデルブロ高速化のやる気のない高速化
forked from forked from: マンデルブロ高速化のやる気のない高速化 (diff: 307)
view in fullscreen mode! @author kobayashi-taro @ kayac inc.
ActionScript3 source code
/**
* Copyright 9re ( http://wonderfl.net/user/9re )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/6zCM
*/
// forked from uwi's forked from: マンデルブロ高速化のやる気のない高速化
// forked from toyoshim's マンデルブロ高速化
// forked from toyoshim's マンデルブロ @ Frocessing
package
{
// view in fullscreen mode!
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.ShaderJob;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.ShaderEvent;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.utils.ByteArray;
import flash.utils.getTimer;
import flash.utils.setTimeout;
import org.libspark.betweenas3.BetweenAS3;
/**
* @author kobayashi-taro @ kayac inc.
*/
public class Mandelbrot extends Sprite
{
private const WONDERFL:int = 465;
private var _job:ShaderJob;
private var _bd:BitmapData;
private var _colors:ByteArray = new ByteArray;
private var _timer:int;
private var _kernel:MandelbrotRenderingKernel;
private var _images:Array;
private var _buffers:Array;
private var _lock:Boolean;
private var _jobSuspended:Boolean;
private var _bufferIndex:int = 0;
private var _basePoint:Point = new Point(-2.5, -2);
private var _rectLength:Number = 4.0;
private var _benchInfo:TextField;
private var _imageLayer:Sprite;
public function Mandelbrot()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
stage.addEventListener(Event.MOUSE_LEAVE, onMouseLeave);
addChild(_imageLayer = new Sprite);
addChild(_benchInfo = new TextField);
_benchInfo.defaultTextFormat = new TextFormat("_sans", 12, 0xffffff);
_benchInfo.mouseEnabled = _benchInfo.mouseWheelEnabled = _benchInfo.selectable = false;
_benchInfo.background = true;
_benchInfo.backgroundColor = 0;
buttonMode = true;
tabEnabled = false;
_images = [];
_buffers = [];
var image:Image;
var bd:BitmapData;
for (var i:int = 0; i < 2; ++i) {
_images.push(image = new Image);
_buffers.push(bd = new BitmapData(WONDERFL, WONDERFL));
image.bitmapData = bd;
}
var spMask:Sprite = new Sprite;
spMask.graphics.beginFill(0);
spMask.graphics.drawRect(0, 0, WONDERFL, WONDERFL);
spMask.graphics.endFill();
mask = spMask;
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
_bd = new BitmapData(WONDERFL, WONDERFL);
_kernel = new MandelbrotRenderingKernel;
_kernel.addEventListener(ShaderEvent.COMPLETE, onJobComplete);
doJob();
}
private function onJobComplete($event:ShaderEvent):void
{
var t:Number = getTimer() - _timer;
_benchInfo.text = "rendering time: " + t + " ms";
_benchInfo.width = _benchInfo.textWidth + 4;
_benchInfo.height = _benchInfo.textHeight + 4;
_lock = false;
var image:Image;
_bufferIndex = 1 - _bufferIndex;
image = getCurrentImage();
image.x = 0;
image.y = 0;
image.scaleX = image.scaleY = 1;
image.alpha = 0;
BetweenAS3.to(image, { alpha:1 }, 0.25).play();
setTimeout(clearBackBuffer, 250);
image.bitmapData = _bd;
_imageLayer.addChild(image);
}
private function clearBackBuffer():void
{
_images[1 - _bufferIndex].alpha = 0;
}
private function doJob():void {
if (_lock) return;
var image:Image = getCurrentImage();
_basePoint.x += -image.x * _rectLength / WONDERFL;
_basePoint.y += -image.y * _rectLength / WONDERFL;
var scale:Number = WONDERFL / _rectLength;
if (_kernel.baseX == _basePoint.x && _kernel.baseY == _basePoint.y && _kernel.scale == scale)
return;
image.alpha = 0;
_kernel.basePoint = _basePoint;
_kernel.scale = scale;
_kernel.target = _bd;
_lock = true;
_timer = getTimer();
_kernel.start();
}
private function onMouseWheel(e:MouseEvent):void
{
if (_lock) return;
var oldLength:Number = _rectLength;
var scale:Number = (e.delta > 0) ? 0.625 : 1.6;
_rectLength *= scale;
scale = (oldLength - _rectLength) / WONDERFL;
var image:Image = getCurrentImage();
image.alpha = 0;
_basePoint.x += scale * mouseX;
_basePoint.y += scale * mouseY;
doJob();
}
private function onMouseDown(e:MouseEvent):void
{
getCurrentImage().startDrag();
}
private function onMouseUp(e:MouseEvent):void
{
stopDragging();
}
private function onMouseLeave(e:Event):void
{
stopDragging();
}
private function stopDragging():void {
getCurrentImage().stopDrag();
doJob();
}
private function getCurrentImage():Image {
return _images[_bufferIndex];
}
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.ShaderEvent;
import flash.events.EventDispatcher;
import flash.geom.Point;
[Event(name = "complete", type = "flash.events.ShaderEvent")]
class MandelbrotRenderingKernel extends EventDispatcher {
private var _baseX:Number;
private var _baseY:Number;
private var _scale:Number;
private var _target:BitmapData;
private var _hsvs:Array = [
16711680, 16711723, 16711765, 16711808, 16711850, 16711892,
16711935, 13893887, 11141375, 8388863, 5570815, 2818303,
255, 11007, 22015, 33023, 43775, 54783,
65535, 65493, 65450, 65408, 65365, 65322,
65280, 2883328, 5635840, 8453888, 11206400, 13958912,
16776960, 16766208, 16755200, 16744448, 16733440, 16722432, 0];
public function MandelbrotRenderingKernel() {
}
public function set basePoint(value:Point):void {
_baseX = value.x;
_baseY = value.y;
}
public function start():void {
_target.lock();
var cx:Number, cy:Number;
var p:Number;
var test0:Number, test1:Number;
var w:int = _target.width;
var h:int = _target.height;
for (var y:int = 0; y < h; y++) {
for (var x:int = 0; x < w; x++) {
cx = _baseX + x / _scale;
cy = _baseY + y / _scale;
_target.setPixel(x, y, _hsvs[calcDepth(cx, cy)]);
}
}
_target.unlock();
dispatchEvent(new ShaderEvent(ShaderEvent.COMPLETE));
}
private function calcDepth(cx:Number, cy:Number):int {
// optimization technique
var p:Number = Math.sqrt((cx - 0.25) * (cx - 0.25) + cy * cy);
if (cx < (p - 2 * p * p + 0.25)) return 36;
if ((cx + 1) * (cx + 1) + cy * cy < 0.0625) return 36;
var r:Number = 0.0;
var i:Number = 0.0;
var n:int;
for (n = 0; n <= 36 && r * r + i * i <= 4; n++) {
var nr:Number = r * r - i * i + cx;
var ni:Number = 2.0 * r * i + cy;
r = nr;
i = ni;
}
return n;
}
public function set target(value:BitmapData):void {
_target = value;
}
public function set scale(value:Number):void
{
_scale = value;
}
public function get scale():Number { return _scale; }
public function get baseX():Number { return _baseX; }
public function get baseY():Number { return _baseY; }
}
class Image extends Sprite {
private var _bitmap:Bitmap;
public function Image() {
addChild(_bitmap = new Bitmap);
}
public function get bitmapData():BitmapData {
return _bitmap.bitmapData;
}
public function set bitmapData(value:BitmapData):void {
_bitmap.bitmapData = value;
}
}