forked from: Painting

by Dan0 forked from Painting (diff: 2)
画像を抽象絵画風に描画
♥0 | Line 241 | Modified 2009-12-01 09:59:24 | MIT License
play

ActionScript3 source code

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

// forked from chutaicho's Painting
/**
画像を抽象絵画風に描画
*/
package 
{
    import __AS3__.vec.Vector;
    
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.TimerEvent;
    import flash.geom.ColorTransform;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    import flash.utils.Timer; 
    
    [SWF(backgroundColor="0x000000", frameRate="40")]
    public class AbstractPainting extends Sprite
    {
        private const IMAGE_URL:String = "http://dan0.net/gallery/transmission_ltd/high/1.png"; 
        //-------------------------------------------------------
		//  const
		//-------------------------------------------------------
	    private const DOTS_MAX:Number = 50; // 1モーションで保持する頂点数		
	    private const FRICTION:Number = 0.98; 		
	    private const EDGE_COLOR:uint = 0x666666; // 太いラインのエッジカラー		
		
		//-------------------------------------------------------
		//  vars
		//-------------------------------------------------------
        private var _drawImage:BitmapData;
		private var _dotNumber:Number = 0;
		private var _dots:Vector.<Vertex>;
		private var _codeWidth:Number = 1;
		
		private var _startX:Number;
		private var _startY:Number;
		
		private var _layerA:Sprite; // 上のレイヤー(太いライン)
		private var _layerB:Sprite; // 下のレイヤー(細いライン)
		private var _drawTarget:Sprite; // ビットマップ描画するターゲット
		
        private var _canvas:BitmapData; // 描画先
		private var _holder:Sprite;     // 描画したビットマップのいれもの
		
        public function AbstractPainting()
        {
			init();
        }
        private function init():void
        {
        	var req:URLRequest = new URLRequest(IMAGE_URL);
        	var loader:Loader = new Loader();
        	loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);	
        	loader.load( req, new LoaderContext(true));
        	
        }
        private function loadComplete(e:Event):void
        {
        	e.target.removeEventListener(Event.COMPLETE, loadComplete);
                var sw:int = stage.stageWidth;
        	var sh:int = stage.stageHeight;
        	_startX = sw/2;
        	_startY = sh/2;
        	
        	var source:Bitmap = e.target.loader.content as Bitmap;
        	source.width  = sw;
        	source.height = sh;
        	
        	_drawImage = new BitmapData(sw,sh, false, 0x000);
        	_drawImage.draw(source);
      
        	_layerA = new Sprite();// 上のレイヤー
        	_layerB = new Sprite();// 下のレイヤー...ちょっとずらす
        	_layerB.x = 10;
        	_layerB.y = 10;
        	
                // 上のレイヤーだけちょっと色かえる
      		var colorTransform:ColorTransform = new ColorTransform(1,1,1,2,20,30,20,20);
        	_layerB.transform.colorTransform = colorTransform;
        	
        	_drawTarget = new Sprite();
        	_drawTarget.addChild(_layerA);
        	_drawTarget.addChild(_layerB);
        	
        	_holder = new Sprite();
        	_holder.x = sw/2;
        	_holder.z = 300;
        	addChild(_holder);
        	
        	_canvas = new BitmapData(sw,sh,false,0xEEEEEE);
        	var canvasBitmap:Bitmap = new Bitmap(_canvas,"auto",true);
        	canvasBitmap.x = -232;
        	_holder.addChild(canvasBitmap);

			_dots = new Vector.<Vertex>();
			
        	var timer:Timer = new Timer(30, 0);
			timer.addEventListener(TimerEvent.TIMER, createDot);
			timer.start();
			
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        }
        private function randomRange( min:Number, max:Number ):Number
		{
			return min + Math.random() * (max + 1 - min);
		}
        //-------------------------------------------------------
		//  Private Event Handler
		//-------------------------------------------------------
        private function createDot(e:TimerEvent):void 
        {
			var dot:Vertex = new Vertex();			
			var px:Number = _startX + randomRange(-40,40);
			var py:Number = _startY + randomRange(-40,40);
			
			// ステージからはみ出たら適当な場所へ戻す
			if(px > stage.stageWidth || py > stage.stageHeight || px < 0 || py < 0)
			{
				px = Math.random() * stage.stageWidth;
				py = Math.random() * stage.stageHeight;
				
				dot.ajust = true; // 位置変更フラグ
			}
			
			_startX = px;
			_startY = py;

                        dot.x = _startX;
			dot.y = _startY;
			
			
			
			_dots.push(dot);	
				
			if (_dotNumber >= DOTS_MAX) 
			{
				var target:Vertex = _dots.shift();
				target = null;
			}	
			_dotNumber ++;	
		}
		private function enterFrameHandler(e:Event):void
		{		
			_layerA.graphics.clear();
			_layerB.graphics.clear();
			
			var codeWidth:Number = 1; // layerBの線の太さ
			var brushThickness:Number = 4; // 線の太さ
			var pressure:Number = 0;       // 筆圧っぽさ
			var l:int = _dots.length;			
			
			// 一回まわして角度を計算しておく
			for(var i:int = l-1; i > 0; i-- )
			{
				if( i != l-1 )
				{
					var dot:Vertex = _dots[i];					
					var dotB:Vertex = _dots[i-1]; // 一つ前のポイント(基準値)
					var disX:Number = dotB.x - dot.x;
					var disY:Number = dotB.y - dot.y;
					// X:Yの角度から垂直になるポイントへの角度
					dot.angle = Math.atan2(disX, disY) + Math.PI / 2; 
				}
			}
			
			// 線の描画部分 
			for(var j:int = l-1; j > 0; j-- )
			{	
				dot = _dots[j];
				var color:uint = _drawImage.getPixel(dot.x, dot.y);				

				if (j>0)
				{
					brushThickness += 0.1;
					codeWidth += 0.01;
					pressure += 0.02;
				}
				else
				{
					brushThickness *= FRICTION;
					codeWidth *= FRICTION;
					pressure *= FRICTION;
				}
				
				if( j == l-1 )
				{
					// はみ出たポイントを戻すタイミングで円を書く
					if(dot.ajust)
					drawCircle(dot,color);
					
					_layerA.graphics.moveTo(dot.x, dot.y);
					_layerB.graphics.moveTo(dot.x, dot.y);
				}
				else
				{
					dotB = _dots[j-1];
					disX = dotB.x - dot.x;
					disY = dotB.y - dot.y;
					var mx:Number = dot.x + (disX)*0.4;
					var my:Number = dot.y + (disY)*0.4;
					var cosA:Number = brushThickness*Math.cos(dot.angle);
					var cosB:Number = brushThickness*Math.cos(dotB.angle);
					var sinA:Number = brushThickness*Math.sin(dot.angle);
					var sinB:Number = brushThickness*Math.sin(dotB.angle);
					
					// 上のレイヤー
					_layerB.graphics.lineStyle(codeWidth, color, pressure);
					_layerB.graphics.curveTo(dotB.x, dotB.y, mx, my);
					_layerB.graphics.lineTo(mx, my);

					// 下のレイヤー
					if(!dot.ajust)
					{
						_layerA.graphics.beginFill(color,0.4);
						_layerA.graphics.moveTo(mx,my);											
						_layerA.graphics.lineStyle(0.2, EDGE_COLOR, 0);
						_layerA.graphics.moveTo(dot.x + cosA, dot.y + sinA);
						_layerA.graphics.lineTo(dot.x - cosA, dot.y - sinA);
						_layerA.graphics.lineStyle(0.2, EDGE_COLOR, 0.2);					
						_layerA.graphics.lineTo(dotB.x - cosB, dotB.y - sinB);
						_layerA.graphics.lineStyle(0.2, EDGE_COLOR, 0);
						_layerA.graphics.lineTo(dotB.x + cosB, dotB.y + sinB);
						_layerA.graphics.lineStyle(0.2, EDGE_COLOR, 0.2);	
						_layerA.graphics.lineTo(dot.x + cosA, dot.y + sinA);
					
						_layerA.graphics.moveTo(mx, my);
					}
				}				
			}
			_canvas.draw(_drawTarget);
			
			var center:Number = stage.stageWidth/2;
			var p:Number = (center - mouseX)/center* -180;
                
        	SimpleTween.addTween(_holder, {rotationY:p});				
		}
		private function drawCircle(target:Vertex, color:uint):void
		{
			for(var i:int = 0; i<8; i++)
			{
				var px:Number = target.x + randomRange( -100, 100 );
				var py:Number = target.y + randomRange( -100, 100 );
				var r:Number = Math.random()* 4;
				_layerA.graphics.beginFill(color,1);
				_layerA.graphics.drawCircle(px,py,r);
			}
		}
		
    }
}
import flash.display.DisplayObject;
	
/**
頂点クラス
*/   
class Vertex
{
    private const GRAVITY:Number  = 0.5; // 重力
	private const FRICTION:Number = 0.98; // 減速抵抗
    
    public var x:Number;
    public var y:Number;
    public var rad:Number = 2;
    public var color:uint;
    public var randonNum:Number;
    public var angle:Number;
    public var ajust:Boolean = false;
    
    private var speedX:Number;
    private var speedY:Number;
        
    public function Vertex()
    {
    	init();
    }
    private function init():void
    {
		var angle:Number = Math.random()*Math.PI*2;
        randonNum = Math.random() * 4;
		speedX = Math.cos(angle) * randonNum;
		speedY = Math.sin(angle) * randonNum;   	
    }
    public function upDate():void
    {			
		speedX *= FRICTION;
		speedY *= FRICTION;
		
		x += speedX;
		y += speedY;
    }
}

/**
TWEEN用 あとで使うかも。いまのとこ一回しか使ってない。
*/
class SimpleTween
{
	private static const EASE_VALUE:Number = 0.2;
	
	public static function addTween( target:Object, obj:Object ):void
	{	
		for(var istr:String in obj)
		{
			var a:Number = target[istr];
			var b:Number = obj[istr];
			target[istr] = a + (b-a) * EASE_VALUE;
		}		
	}
	
}