くるくるグラフィックジェネレーター
先日wonderflにポストしたくるくるカール(forked from: Draw worm by mouse gesture)に少し機能を追加して、簡単にコンピュテーションアート風のグラフィックを作成できるジェネレーター(?)を作ってみました。
くるくるグラフィックジェネレーター
操作方法は、マウスダウンで描画開始・マウスアップで描画停止・FULLSCREENボタンで全画面表示・CLEARボタンで全削除・SAVEボタンで背景が黒の画像保存・SAVE(Alpha)ボタンで背景が透明の画像保存です。
このアプリケーションを作るにあたってはwonderflの Draw worm by mouse gesture. をForkさせていただきましたので、オリジナルコードのライセンスに基づき以下に全ソースを公開します。
またこのコードのライセンスもオリジナルのライセンスを継承します。
// forked from nutsu's Worm matrix based. // forked from nutsu's Draw worm by mouse gesture. : http://wonderfl.net/c/9os2 /** LOVE MATRIX. a study for drawing curl curve. license under the GNU Lesser General Public License. */ package { import com.adobe.images.PNGEncoder; import com.bit101.components.PushButton; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.display.StageDisplayState; import flash.display.StageScaleMode; import flash.events.*; import flash.net.FileReference; import flash.net.URLRequest; import flash.net.navigateToURL; import flash.utils.ByteArray; [SWF(width = "1280", height = "800", frameRate = "60", backgroundColor = "0")] public class Main extends Sprite { private var _canvas:WormMatrix; private var _fr:FileReference = new FileReference(); public function Main() { _canvas = new WormMatrix(); addChild(_canvas); // var bt1:PushButton = new PushButton ( this, 10 , 10, "CANVAS CLEAR" , _canvas.canvasClear) ; var bt2:PushButton = new PushButton ( this, 115 , 10, "SAVE IMAGE", onSave ) ; var bt3:PushButton = new PushButton ( this, 220 , 10, "SAVE IMAGE (Alpha)", onSaveAlpha ) ; var bt4:PushButton = new PushButton ( this, 350 , 10, "SOURCE CODE", function():void{navigateToURL(new URLRequest("https://www.digifie.jp/blog/archives/397"))} ) ; var bt5:PushButton = new PushButton ( this, 1280 - 110 , 10, "FULL SCREEN" , fullScreen) ; // var isFullScreen:Boolean; function fullScreen():void { if(!isFullScreen){ stage.scaleMode = StageScaleMode.NO_SCALE; stage.displayState = StageDisplayState.FULL_SCREEN; isFullScreen = true; bt4.label = "NOMAL SCREEN" }else{ stage.displayState = StageDisplayState.NORMAL; isFullScreen = false; bt4.label = "FULL SCREEN" } } } private function onSave(e:MouseEvent):void { var bmd:BitmapData = new BitmapData(1280, 800, false, 0); bmd.draw(_canvas); fileSave(bmd); // bmd.dispose(); } private function onSaveAlpha(e:MouseEvent):void { var bmd:BitmapData = new BitmapData(1280, 800, true, 0x00000000); bmd.draw(_canvas); fileSave(bmd); // bmd.dispose(); } private function fileSave(bmd:BitmapData):void { var png:ByteArray = PNGEncoder.encode(bmd); _fr.addEventListener(Event.OPEN, open); _fr.addEventListener(ProgressEvent.PROGRESS, progress); _fr.addEventListener(Event.COMPLETE, complete); _fr.addEventListener(Event.CANCEL, cancel); _fr.addEventListener(Event.SELECT, select); _fr.addEventListener(IOErrorEvent.IO_ERROR, ioError); var date:Date = new Date; _fr.save(png, "export_image_" + date.getTime() + ".png"); // function open(e:Event):void { // } function progress(e:ProgressEvent):void { // } function complete(e:Event):void { removedEventListener(); } function cancel(e:Event):void { removedEventListener(); } function select(e:Event):void { // } function ioError(e:IOErrorEvent):void { removedEventListener(); } // function removedEventListener():void { _fr.removeEventListener(Event.OPEN, open) _fr.removeEventListener(ProgressEvent.PROGRESS, progress) _fr.removeEventListener(Event.COMPLETE, complete) _fr.removeEventListener(Event.CANCEL, cancel); _fr.removeEventListener(Event.SELECT, select); _fr.removeEventListener(IOErrorEvent.IO_ERROR, ioError) } } } } //package { import flash.events.MouseEvent; import frocessing.color.ColorHSV; import frocessing.display.F5MovieClip2DBmp; import frocessing.geom.FMatrix2D; internal class WormMatrix extends F5MovieClip2DBmp { private var vms:Array; private var MAX_NUM:int = 150; private var N:Number = 120; private var px:Number; private var py:Number; private var t:Number = 0; public function WormMatrix () { super( true, 0 ); vms = []; } public function check():void { var x0:Number = mouseX; var y0:Number = mouseY; var vx:Number = x0 - px; var vy:Number = y0 - py; var len:Number = min( mag( vx, vy ), 50 ); if( len<10 ) return; var mtx:FMatrix2D = new FMatrix2D(); mtx.rotate( atan2( vy, vx ) ); mtx.translate( x0, y0 ); createObj( mtx, len ); px = x0; py = y0; } public function createObj( mtx:FMatrix2D, len:Number ):void { var angle:Number = random(PI/180, PI/2); if( Math.random() > 0.5 ) angle *= -1; var tmt:FMatrix2D = new FMatrix2D(); tmt.scale( 0.95, 0.95 ); tmt.rotate( angle ); tmt.translate( len, 0 ); var w:Number = 0.5; var obj:WormObject = new WormObject(); obj.c1x = obj.p1x = -w * mtx.c + mtx.tx; obj.c1y = obj.p1y = -w * mtx.d + mtx.ty; obj.c2x = obj.p2x = w * mtx.c + mtx.tx; obj.c2y = obj.p2y = w * mtx.d + mtx.ty; obj.vmt = mtx; obj.tmt = tmt; obj.r = angle; obj.w = len * .1; obj.count = 0; vms.push( obj ); if( vms.length > MAX_NUM ) vms.shift(); } public function setup():void { size( 1280, 800 ); background(0, 0); noStroke(); px = mouseX; py = mouseY; } public function canvasClear(e:MouseEvent):void { background(0, 0); vms = []; } public function draw():void { stroke(0xFFFFFFFF, .4); var len:int = vms.length; for( var i:int=0; i<len; i++ ) { var o:WormObject = vms[i]; if( o.count<N && isMousePressed){ drawWorm( o ); o.count++; }else{ len--; vms.splice( i, 1 ); i--; } } check(); } public function drawWorm( obj:WormObject ):void { var color:ColorHSV = new ColorHSV(t, 0.6, 1, 0.1); t += 0.1; if( Math.random()>0.9 ){ obj.tmt.rotate( -obj.r*2 ); obj.r *= -1; } obj.vmt.prepend( obj.tmt ); var cc1x:Number = -obj.w*obj.vmt.c + obj.vmt.tx; var cc1y:Number = -obj.w*obj.vmt.d + obj.vmt.ty; var pp1x:Number = (obj.c1x+cc1x)/2; var pp1y:Number = (obj.c1y+cc1y)/2; var cc2x:Number = obj.w*obj.vmt.c + obj.vmt.tx; var cc2y:Number = obj.w*obj.vmt.d + obj.vmt.ty; var pp2x:Number = (obj.c2x+cc2x)/2; var pp2y:Number = (obj.c2y+cc2y)/2; beginFill( uint(color), .7 ); moveTo( obj.p1x, obj.p1y ); curveTo( obj.c1x, obj.c1y, pp1x, pp1y ); lineTo( pp2x, pp2y ); curveTo( obj.c2x, obj.c2y, obj.p2x, obj.p2y ); closePath(); endFill(); obj.c1x = cc1x; obj.c1y = cc1y; obj.p1x = pp1x; obj.p1y = pp1y; obj.c2x = cc2x; obj.c2y = cc2y; obj.p2x = pp2x; obj.p2y = pp2y; } } //} import frocessing.geom.FMatrix2D; internal class WormObject{ public var c1x:Number; public var c1y:Number; public var c2x:Number; public var c2y:Number; public var p1x:Number; public var p1y:Number; public var p2x:Number; public var p2y:Number; public var w:Number; public var r:Number; public var count:int; public var vmt:FMatrix2D; public var tmt:FMatrix2D; }
描いた絵はPNG画像として保存できますので、ぜひ遊んでみてください。