Toggle navigation
Sign Up
Log In
Explore
Works
Folders
Tools
Collections
Artists
Groups
Groups
Topics
Tasks
Tasks
Jobs
Teams
Jobs
Recommendation
More Effects...
ActionScript
// somebody please optimize this code! // source code: http://github.com/mash/ContextFreeArt-AS3 // This software is a port of ContextFree.js to Actionscript3. // Context Free Art is http://www.contextfreeart.org/index.html // ContextFree.js is http://code.google.com/p/contextfree/ // some hints about implementation for improvement // ContextFree is a combination of resized primitive shapes: // Circle, Square, Triangle // in this implementation, every primitive shapes are // "children" of "ContextFreeArt", // which makes it slow to "addChild" and render // after there's already plenty of children. // I thought it would be faster if we draw each primitive when needed, // but bitmaps quality drops when resized // 誰か最適化してちょうだい! // ContextFreeはprimitiveな円と四角と三角形の組み合わせです // 今の実装では、ContextFreeにどんどんaddChildしていくので // 大量にaddChildした後にだんだんパフォーマンスが落ちていきます.. // 必要な時にbitmapdata.drawしていけばよいのでしょうが // リサイズ時に画質劣化が激しいので厳しいのでは,,(今ココ package { import flash.display.*; import flash.events.Event; import flash.events.MouseEvent; import flash.net.URLLoader; import flash.net.URLRequest; public class Tree extends Sprite{ public function Tree(){ var cfdg :String = <>>; start( cfdg ); } private function start( cfdg :String ) :void { var art :ContextFreeArt = new ContextFreeArt( cfdg, 465, 465 ); addChild( art ); stage.addEventListener( MouseEvent.CLICK, function(ev:MouseEvent) :void { art.tick(); }); } } } function log() :void {} //package jp.maaash { import flash.display.Sprite; ////////import jp.maaash.contextfreeart.Tokenizer; //import jp.maaash.contextfreeart.Compiler; //import jp.maaash.contextfreeart.Renderer; //public class ContextFreeArt extends Sprite { class ContextFreeArt extends Sprite { private var renderer :Renderer; public function ContextFreeArt( cfdg_text :String, width :Number = 640, height :Number = 480 ) { var t :Tokenizer = new Tokenizer; var tokens :Array = t.tokenize( cfdg_text ); var c :Compiler = new Compiler; var compiled :Object = c.compile( tokens ); logger("compiled: ",compiled); renderer = new Renderer( width, height ); renderer.clearQueue(); renderer.render( compiled, this ); } public function tick() :void { renderer.tick(); } private function logger(... args) :void { if ( 1 ) { return; } log.apply(null, (new Array("[ContextFreeArt]", this)).concat(args)); } } //} //package jp.maaash.contextfreeart { //import jp.maaash.contextfreeart.state.*; import flash.utils.getDefinitionByName; //public class Compiler{ class Compiler{ private const keywords :Array = [ "startshape", "rule", "background" ]; public var compiled :Object = {}; public var state :IState; private var curKey :String; private var curValues :Array; private var obj :Object; public function Compiler(){ } public function compile( tokens :Array ) :Object { state = new General; while ( tokens.length > 0 ) { var token :String = tokens.shift(); var nextState :Array = state.eat( token, this ); //logger("[compile]token: "+token+" nextState: "+nextState); if ( nextState ) { next( nextState ); } } return compiled; } private function next( state_and_args :Array ) :void { var className :String = state_and_args.shift(); // uppercase the 1st char className = className.substr(0,1).toUpperCase() + className.substr(1); switch( className ) { case "Startshape": state = new Startshape; break; case "General": state = new General; break; case "Background": state = new Background; break; case "Rule": state = new Rule; break; case "RuleWeight": state = new RuleWeight( state_and_args ); break; case "RuleDraw": state = new RuleDraw( state_and_args ); break; case "ShapeAdjustment": state = new ShapeAdjustment( state_and_args ); break; } // var classObject :Class = getDefinitionByName( className ) as Class; // // if ( state_and_args.length > 0 ) { // state = new classObject( state_and_args ); // } // else { // state = new classObject; // } } private var stateGeneral :General; private var stateStartshape :Startshape; private var stateBackground :Background; private var stateRule :Rule; private var stateRuleWeight :RuleWeight; private var stateRuleDraw :RuleDraw; private var stateShape :ShapeAdjustment; private function logger(... args) :void { if ( 1 ) { return; } log.apply(null, (new Array("[compiler]", this)).concat(args)); } } //} //package jp.maaash.contextfreeart { //public class Tokenizer{ class Tokenizer{ private var input :String; private const stopChars :Array = [" ", "{", "}", "\n", "\r", "\t"]; public function Tokenizer() { } // TODO: String comments // TODO: Handle ordered arguments (i.e., square brakets) // TODO: Handle the | operator public function tokenize( _input :String ) :Array { input = _input; // To make it easier to parse, we pad the brackets with spaces. input = input.replace( /([{}])/g, " $1"); var tokens :Array = new Array; var head :Object = { lastPos: 0 }; while( 1 ) { head = tokenizeNext( head.lastPos ); if ( head == null ) { break; } if ( head.token ) { tokens.push( head.token ); } } logger("[tokenize]tokens: ",tokens); return tokens; } private function tokenizeNext( pos :Number ) :Object { var stops :Array = new Array; var len :int = stopChars.length; for ( var i:int=0; i
0 ) { if ( queue.length > 0 ) { isRendering = true; var concurrent :int = Math.min( queue.length - 1, maxThreads ); for ( var i :int=0; i <= concurrent; i++ ) { var args :Array = queue.shift(); drawRule.apply( null, args ); } center(); } } private function center() :void { var rect :Rectangle = container.getRect( container ); // resize centeringScale = Math.min( width / rect.width, height / rect.height ) * 0.9; centeringMatrix.a = centeringMatrix.d = centeringScale; // centering centeringMatrix.tx = width /2 - (rect.left + rect.right ) / 2 * centeringScale; centeringMatrix.ty = height/2 - (rect.top + rect.bottom) / 2 * centeringScale; container.transform.matrix = centeringMatrix; //logger("[center]mtx,rect,container: ",centeringMatrix,rect,container); } private function draw() :void { var ruleName :String = compiled.startshape; var foregroundColor :Color = new Color; drawRule( ruleName, new Matrix, foregroundColor ); } private function drawRule( ruleName :String, mtx :Matrix, color :Color, priority :Number = 0 ) :void { //logger("[drawRule]ruleName: "+ruleName+" mtx: ",mtx); // When things get too small, we can stop rendering. // Too small, in this case, means less than a pixel. if( Math.abs( mtx.a ) * globalScale * centeringScale < 1 && Math.abs( mtx.b ) * globalScale * centeringScale < 1 ){ //logger("[drawRule]return"); return; } var shape :Object = chooseShape( ruleName ); drawShape( shape, mtx, color, priority ); } private function chooseShape( ruleName :String ) :Object { // Choose which rule to go with... //logger("[chooseShape]ruleName: "+ruleName); var choices :Array = compiled[ ruleName ]; if ( ! choices ) { throw("no rule found for "+ruleName); } var sum :Number = 0; for( var i :int=0; i
([ -globalScale * 0.5, Math.sqrt(3) * globalScale / 6, +globalScale * 0.5, Math.sqrt(3) * globalScale / 6, 0, - Math.sqrt(3) * globalScale / 3]), Vector.
([0,1,2]) ); sh.transform.matrix = transform; container.addChild( sh ); } private function drawBackground() :void { if ( compiled.background ) { var colorAdj :Adjustment = compiled.background; var backgroundColor :Color = new Color; backgroundColor.b = 1; // { h:0, s:0, b:1, a:1 }; var color :Color = adjustColor( colorAdj, backgroundColor ); var color_alpha :Array = colorToRgba( color ); logger("[drawBackground]color: ",color, backgroundColor,color_alpha); var bg :Shape = new Shape; bg.graphics.beginFill( color_alpha[0], color_alpha[1] ); bg.graphics.drawRect( 0, 0, width, height ); background.addChild( bg ); } } // order: move rotate scale private function adjustTransform( adjs :Adjustment, base :Matrix ) :Matrix { //logger("[adjustTransform][0]adjs: ",adjs," base: ",base); var mtx :Matrix = new Matrix; // Flip around a line through the origin; if ( adjs.flipDefined ){ var flip :Number = adjs.flip; // Flip 0 means to flip along the X axis. Flip 90 means to flip along the Y axis. // That's why the flip vector (vX, vY) is Pi/2 radians further along than expected. var vX :Number = Math.cos( -2*Math.PI * flip / 360 ); var vY :Number = Math.sin( -2*Math.PI * flip / 360 ); var norm :Number = 1/(vX*vX + vY*vY); //var flip :Matrix = new Matrix((vX*vX-vY*vY)/norm, 2*vX*vY/norm, 2*vX*vY/norm, (vY*vY-vX*vX)/norm, 0, 0); mtx.a = (vX*vX-vY*vY)/norm; mtx.b = 2*vX*vY/norm; mtx.c = 2*vX*vY/norm; mtx.d = (vY*vY-vX*vX)/norm; } // Scaling var sizeX :Number = adjs.sizeX; var sizeY :Number = adjs.sizeY; if ( sizeX || sizeY ) { mtx.scale( sizeX, sizeY ); } // Rotation var r :Number = adjs.rotate; if ( r != 0 ) { mtx.rotate( - Math.PI * r / 180 ); } // Tranalsation var x :Number = adjs.x; var y :Number = -adjs.y; if ( x != 0 || y != 0 ) { var point :Point = new Point( x * globalScale, y * globalScale ); mtx.translate( point.x, point.y ); } mtx.concat( base ); //logger("[adjustTransform][9]mtx: ",mtx); return mtx; } private function colorToRgba( color :Color ) :Array { return hsl2rgb( color.h, color.s, color.b, color.a ); } // hue, saturation, brightness, alpha // hue: [0,360) default 0 // saturation: [0,1] default 0 // brightness: [0,1] default 1 // alpha: [0,1] default 1 private function hsl2rgb(h :Number, s :Number, l :Number, a :Number) :Array { if (h == 360){ h = 0;} // // based on C code from http://astronomy.swin.edu.au/~pbourke/colour/hsl/ // while (h < 0){ h += 360; } while (h > 360){ h -= 360; } var r :Number, g :Number, b :Number; if (h < 120){ r = (120 - h) / 60; g = h / 60; b = 0; }else if (h < 240){ r = 0; g = (240 - h) / 60; b = (h - 120) / 60; }else{ r = (h - 240) / 60; g = 0; b = (360 - h) / 60; } r = Math.min(r, 1); g = Math.min(g, 1); b = Math.min(b, 1); r = 2 * s * r + (1 - s); g = 2 * s * g + (1 - s); b = 2 * s * b + (1 - s); if (l < 0.5){ r = l * r; g = l * g; b = l * b; }else{ r = (1 - l) * r + 2 * l - 1; g = (1 - l) * g + 2 * l - 1; b = (1 - l) * b + 2 * l - 1; } r = Math.ceil(r * 255); g = Math.ceil(g * 255); b = Math.ceil(b * 255); // Putting a semicolon at the end of an rgba definition // causes it to not work. //return "rgba(" + r + ", " + g + ", " + b + ", " + a + ")"; //
,
to do: graphics.beginFill.apply( null, color.split(',') ) return [ (r * 256*256 + g * 256 + b), a ]; } // hsba to hsba private function adjustColor( adjs :Adjustment, color :Color ) :Color { // See http://www.contextfreeart.org/mediawiki/index.php/Shape_adjustments var newColor :Color = new Color; newColor.h = color.h; newColor.s = color.s; newColor.b = color.b; newColor.a = color.a; // Add num to the drawing hue value, modulo 360 newColor.h += adjs.hue; newColor.h %= 360; // If adj<0 then change the drawing [blah] adj% toward 0. // If adj>0 then change the drawing [blah] adj% toward 1. if ( adjs.saturation != 0 ) { if( adjs.saturation > 0 ){ newColor.s += adjs.saturation * (1-color.s); } else { newColor.s += adjs.saturation * color.s; } } if ( adjs.brightness != 0 ) { if( adjs.brightness > 0 ){ newColor.b += adjs.brightness * (1-color.b); } else { newColor.b += adjs.brightness * color.b; } } if ( adjs.alpha != 0 ) { if( adjs.alpha > 0 ){ newColor.a += adjs.alpha * (1-color.a); } else { newColor.a += adjs.alpha * color.a; } } return newColor; } public function clearQueue() :void { queue = new Array; } private function logger(... args) :void { if ( 1 ) { return; } log.apply(null, (new Array("[Renderer]", this)).concat(args)); } } //} //package jp.maaash.contextfreeart { //public class Color { class Color { public var h :Number = 0; public var s :Number = 0; public var b :Number = 0; public var a :Number = 1; public function Color(){ } } //} //package jp.maaash.contextfreeart { //public class Adjustment{ class Adjustment{ public var name :String; public var flipDefined :Boolean = false; public var flip :Number; public var sizeX :Number = 1; public var sizeY :Number = 1; public var rotate :Number = 0; public var x :Number = 0; public var y :Number = 0; public var hue :Number = 0; public var saturation :Number = 0; public var brightness :Number = 0; public var alpha :Number = 0; public function Adjustment() { } public function fill( obj :Object ) :void { for( var key :String in obj ){ switch( key ) { case "f": case "flip": flipDefined = true; flip = obj[key]; break; case "s": case "size": var size :* = obj[key]; if ( typeof(size) == "number" ) { size = [size,size]; } sizeX = size[0]; sizeY = size[1]; break; case "r": rotate = obj[key]; break; case "h": hue = obj[key]; break; case "sat": saturation = obj[key]; break; case "b": brightness = obj[key]; break; case "a": alpha = obj[key]; break; case "rotate": case "x": case "y": case "hue": case "saturation": case "brightness": case "alpha": this[key] = obj[key]; break; default: throw("unsupported adjustment: "+key); } } } } //} //package jp.maaash.contextfreeart.state { //import jp.maaash.contextfreeart.Compiler; //public class Rule implements IState { class Rule implements IState { public function Rule(){ } public function eat( token :String, compiler :Compiler ) :Array { var ruleName :String = token; // Create a blank rule if it doesn't aleady exist if ( ! compiler.compiled[ ruleName ] ) { compiler.compiled[ ruleName ] = []; } return [ "ruleWeight", ruleName ]; } } //} //package jp.maaash.contextfreeart.state { //import jp.maaash.contextfreeart.Compiler; //public class RuleDraw implements IState { class RuleDraw implements IState { private var weight :Number = 1; private var ruleName :String; public function RuleDraw( args :Array ) { ruleName = args[0]; } public function eat( token :String, compiler :Compiler ) :Array { if( token == "}" ){ return [ "general" ]; } return [ "shapeAdjustment", token, ruleName ]; } } //} //package jp.maaash.contextfreeart.state { //import jp.maaash.contextfreeart.Compiler; //public class Startshape implements IState { class Startshape implements IState { public function Startshape() { } public function eat( token :String, compiler :Compiler ) :Array { // uppercase the 1st char compiler.compiled[ "startshape" ] = token; return [ "general" ]; } } //} //package jp.maaash.contextfreeart.state { //import jp.maaash.contextfreeart.Compiler; //public class AbstractArgument implements IState { class AbstractArgument implements IState { protected var curKey :String = null; protected var curValues :Array = []; protected var obj :Object = {}; protected var compiler :Compiler; public function AbstractArgument(){ } public function eat( token :String, _compiler :Compiler ) :Array { compiler = _compiler; switch ( token ) { case "}": flushKey(); return onDone( obj ); case "{": return null; } // If it's a keyword name... if( token.match(/[a-z_]+/i) ) { flushKey(); curKey = token; curValues = []; } // Otherwise it's a value (and hence a number) else { curValues.push( parseFloat(token) ); } return null; } protected function onDone( obj :Object ) :Array { return null; } // abstract protected function flushKey() :void { if ( curKey ) { // If there is only one value for the key, we don't need to wrap // it in an array. if ( curValues.length == 1 ) { obj[ curKey ] = curValues[0]; } else { obj[ curKey ] = curValues; } } } } //} //package jp.maaash.contextfreeart.state { //import jp.maaash.contextfreeart.Compiler; //import jp.maaash.contextfreeart.Adjustment; //public class Background extends AbstractArgument { class Background extends AbstractArgument { public function Background() { } override protected function onDone( obj :Object ) :Array { var adj :Adjustment = new Adjustment; adj.fill( obj ); compiler.compiled[ "background" ] = adj; compiler = null; return [ "general" ]; } } //} //package jp.maaash.contextfreeart.state { //import jp.maaash.contextfreeart.Compiler; //import jp.maaash.contextfreeart.Adjustment; //public class ShapeAdjustment extends AbstractArgument { class ShapeAdjustment extends AbstractArgument { private var name :String; private var ruleName :String; public function ShapeAdjustment( args :Array ) { name = args[0]; ruleName = args[1]; } override protected function onDone( obj :Object ) :Array { trace(this + ".onDone(obj :Object ) : " + obj ); var shape :Adjustment = new Adjustment(); shape.name = name; shape.fill( obj ); // We are always adding to the lastest rule we've created. var last :int = compiler.compiled[ ruleName ].length - 1; compiler.compiled[ ruleName ][ last ].draw.push( shape ) compiler = null; return [ "ruleDraw", ruleName ]; } } //} //package jp.maaash.contextfreeart.state { //import jp.maaash.contextfreeart.Compiler; //public interface IState { interface IState { function eat( token :String, compiler :Compiler ) :Array; } //} //package jp.maaash.contextfreeart.state { //import jp.maaash.contextfreeart.Compiler; //public class RuleWeight implements IState { class RuleWeight implements IState { private var weight :Number = 1; private var ruleName :String; public function RuleWeight( args :Array ) { ruleName = args[0]; } public function eat( token :String, compiler :Compiler ) :Array { if ( token != "{" ) { weight = parseFloat( token ); return null; } else { // "{" compiler.compiled[ ruleName ].push({ weight: weight, draw: [] }); return [ "ruleDraw", ruleName ]; } } } //} //package jp.maaash.contextfreeart.state { //import jp.maaash.contextfreeart.Compiler; //public class General implements IState { class General implements IState { public function General(){ } public function eat( token :String, compiler :Compiler ) :Array { return [ token ]; } } //}
Join Effecthub.com
Working with Global Gaming Artists and Developers!
Login
Sign Up
Or Login with Your Email Address:
Email
Password
Remember
Or Sign Up with Your Email Address:
Your Email
This field must contain a valid email
Set Password
Password should be at least 1 character
Stay informed via email