Brush Pattern

by NewKrok
2d brush pattern for 2d games
♥0 | Line 229 | Modified 2014-05-06 04:25:59 | MIT License | (replaced)
play

Related images

ActionScript3 source code

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

package {
    
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    
    public class test extends Sprite {
        
        private const TEXTURE_URL:String = "http://assets.wonderfl.net/images/related_images/1/13/13f7/13f73c8fb2b8cd3e291c6c63c44c42ffa722ebe2m";
        private const TEST_MAP:String = "49<164<72<152&72<152<100<155&100<155<163<141&163<141<202<117&202<117<252<74&252<74<293<51&293<51<347<50&347<50<385<79&385<79<419<114&419<114<431<161&431<161<428<224&428<224<400<288&400<288<340<308&340<308<281<291&281<291<258<222&258<222<204<214&204<214<162<255&162<255<99<328&99<328<66<298&66<298<35<245&35<245<90<200&90<200<49<164";
       
        public function test () :void {
            loadImage ( TEXTURE_URL, loaded );
        }
        
        private function loadImage ( $url:String, $onComplete:Function ) :void {
            var imageLoader:Loader = new Loader ();
            imageLoader.contentLoaderInfo.addEventListener ( Event.COMPLETE, $onComplete );
            var image:URLRequest = new URLRequest ( $url );
            imageLoader.load ( image, new LoaderContext ( true ) );
        }
        
        private function loaded ( event:Event ) :void {
            var texture:BitmapData = new BitmapData ( event.currentTarget.content.width, event.currentTarget.content.height, true, 0x60 );
            texture.draw ( event.currentTarget.content );
            addChild ( new BrushPattern ( TEST_MAP, texture ) );
        }

    }

}


    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.display.TriangleCulling;
    import flash.geom.Point;
    import flash.events.Event;
    import flash.events.MouseEvent;

    class BrushPattern extends Sprite {

        private var linePoints:         Array = new Array();
        private var linePointsInput:    Array = new Array();
        private var holder:             Sprite = new Sprite();
        private var holderS:             Sprite = new Sprite();
        private var g:                     Graphics;
        private var _fillBack:            Sprite = new Sprite;
        private var vertices:            Vector.<Number>;
        private var indices:             Vector.<int> ;
        private var uvtData:             Vector.<Number>;
        private var terrainTexture:     BitmapData;
        private var lastLength:         Number = 0;
        private var segLength:             Number = 0;
        private var _view:                Bitmap;

        public function BrushPattern ( $map:String, $texture:BitmapData ) {
            terrainTexture = $texture;
            $map = renderPreProcess ( $map, 72, 72 );
            g = holderS.graphics;
            _fillBack.graphics.lineStyle ( 1, 0, 1 );
            holder.addChild ( _fillBack );
            holder.addChild ( holderS );
            var mapPieces:Array = $map.split ( "|" );
            for ( var j:uint = 0; j < mapPieces.length; j++ ) {
                var tmp:Array = mapPieces[j].split ( "&" );
                for ( var i:uint = 0; i < tmp.length; i++ ) {
                    var tmp2:Array = tmp[i].split ( "<" );
                    if ( i == 0 )
                        _fillBack.graphics.moveTo ( tmp2[0], tmp2[1] );
                    if ( j == 0 && i == 0 )
                        _fillBack.graphics.moveTo ( tmp2[0], tmp2[1] );
                    else if ( tmp2.length > 1 )
                        _fillBack.graphics.lineTo ( tmp2[0], tmp2[1] );
                    if ( i == 0 ) {
                        var lp:LinePoint = new LinePoint ( tmp2[0], tmp2[1] );
                        linePointsInput.push ( lp );
                    } else if ( tmp2.length > 1 ) {
                        lp = new LinePoint ( tmp2[0], tmp2[1], linePointsInput[linePointsInput.length - 1] );
                        linePointsInput.push ( lp );
                        calculate ();
                        render ();
                    }
                }
            }
            addChild ( _view = new Bitmap ( new BitmapData ( 450, 450, true, 0x60 ) ) );
            _view.smoothing = true;
            _view.bitmapData.draw ( holder, null, null, null, null, true );
            clear ();
        }
        
        private function renderPreProcess ( $map:String, $textureSize:Number = 72, $textureMaxWidth:Number = 100 ) :String {
            var blockSize:Number = $textureSize;
            var convertedMap:String = "";
            var mapPieces:Array = $map.split ( "|" );
            for ( var j:uint = 0; j < mapPieces.length; j++ ) {
                blockSize = $textureSize;
                var tmp:Array = mapPieces[j].split ( "&" );
                for ( var i:uint = 0; i < tmp.length - 1; i++ ) {
                    var tmp2:Array = tmp[i].split ( "<" );
                    tmp2[0] = Number ( tmp2[0] );
                    tmp2[1] = Number ( tmp2[1] );
                    tmp2[2] = Number ( tmp2[2] );
                    tmp2[3] = Number ( tmp2[3] );
                    var lineLength:Number = Math.sqrt ( Math.pow ( tmp2[2] - tmp2[0], 2 ) + Math.pow ( tmp2[3] - tmp2[1], 2 ) );
                    if ( lineLength < $textureMaxWidth )
                        convertedMap += tmp2[0] + "<" + tmp2[1] + "<" + tmp2[2] + "<" + tmp2[3] + "&";
                    else {
                        var angle:Number = Math.atan2 ( tmp2[3] - tmp2[1], tmp2[2] - tmp2[0] );
                        var pieces:uint = Math.ceil ( lineLength / $textureSize );
                        blockSize = lineLength / pieces;
                        var newX:Number = tmp2[0];
                        var newY:Number = tmp2[1];
                        for ( var k:uint = 1; k < pieces + 1; k++ ) {
                            var newX2:Number = tmp2[0] + blockSize * k * Math.cos ( angle );
                            var newY2:Number = tmp2[1] + blockSize * k * Math.sin ( angle );
                            convertedMap += newX + "<" + newY + "<" + newX2 + "<" + newY2 + "&";
                            newX = newX2;
                            newY = newY2;
                        }
                    }
                }
                convertedMap += "|"
            }
            return convertedMap;
        }

        private function calculate () :void {
            segLength = 1;
            lastLength = 0;
            linePoints = [];
            linePoints.push ( linePointsInput[0] );
            vertices = new Vector.<Number>;
            indices = new  Vector.<int>;
            uvtData = new Vector.<Number>;
            for ( var i:int = 1; i < linePointsInput.length; i++ ) {
                var lp : LinePoint = linePointsInput[i];
                if ( lp.currentLength > lastLength + segLength ) {
                    lastLength = lp.currentLength;
                    linePoints.push ( lp );
                }
            }
            var count:uint = 0;
            var uvStep:Number = .5;
            var currentUV:Number = 0
            for ( i = 0; i < linePoints.length; i += 2 ) {
                lp = linePoints[i];
                vertices.push ( lp.xL, lp.yL, lp.xR, lp.yR );
                if ( i == linePoints.length - 1 )
                    lp = linePoints[i];
                else
                    lp = linePoints[i + 1];
                vertices.push ( lp.xL, lp.yL, lp.xR, lp.yR );
                indices.push ( count, count + 1, count + 2, count + 1, count + 2, count + 3 );
                indices.push ( count + 2, count + 3, count + 4, count + 3, count + 4, count + 5 );
                uvtData.push ( currentUV, 0, currentUV, 1, currentUV + uvStep, 0, currentUV + uvStep, 1 );
                count += 4;
                currentUV += uvStep;
                currentUV += uvStep;
            }
        }

        private function render () :void {
            g.clear ();
            g.beginBitmapFill ( terrainTexture, null, true, true )
            g.drawTriangles ( vertices, indices, uvtData );
        }

        private function clear () :void {
            g.clear ();
            LinePoint.fullLength = 0;
            linePointsInput = [];
            linePoints = [];
        }
        
    }
    
     import flash.geom.Point;
     
     class LinePoint extends Point {
        
        public static var fullLength:    Number = 0;
        public var currentLength:        Number
        public var l:                     Number;
        public var xL:                     Number;
        public var yL:                     Number;
        public var xR:                     Number;
        public var yR:                     Number;
        public var angle:                 Number = 0;
        public var angleT:                 Number = 0;
        public var lw:                    Number = 15;
        public var prevPoint:            LinePoint;
        
        public function LinePoint ( xPos:Number, yPos:Number, prevPoint:LinePoint = null ) {
            super ( xPos, yPos );
            this.prevPoint = prevPoint;
            if ( prevPoint ) {
                l = Point.distance ( this, prevPoint );
                fullLength += l;
                currentLength = fullLength;
                angleT = Math.atan2 ( this.y - prevPoint.y, this.x - prevPoint.x );
                angle = angleT;
                var pR:Point = Point.polar ( lw, angle + Math.PI / 2 );
                xR = pR.x + x;
                yR = pR.y + y;
                var pL:Point = Point.polar ( lw, angle - Math.PI / 2 );
                xL = pL.x + x;
                yL = pL.y + y;
                if ( prevPoint.prevPoint )
                    prevPoint.setAngel ( this );
            } else {
                xR = x;
                yR = y;
                xL = x;
                yL = y;
            }
        }

        private function setAngel ( nextPoint:LinePoint ) :void {
            angle = Math.atan2 ( nextPoint.y - prevPoint.y, nextPoint.x - prevPoint.x );
            var ll:Number= l + prevPoint.l + nextPoint.l
            var pR:Point = Point.polar ( lw, angle + Math.PI / 2 );
            xR = pR.x + x;
            yR = pR.y + y;
            var pL:Point = Point.polar ( lw, angle - Math.PI / 2 );
            xL = pL.x + x;
            yL = pL.y + y;
        }

        private function intersect ( p1:Point, p2:Point, p3:Point, p4:Point ) :Boolean  {
            var nx:Number, ny:Number, dn:Number;
            var x4_x3:Number = p4.x - p3.x;
            var pre2:Number = p4.y - p3.y;
            var pre3:Number = p2.x - p1.x;
            var pre4:Number = p2.y - p1.y;
            var pre5:Number = p1.y - p3.y;
            var pre6:Number = p1.x - p3.x;
            nx = x4_x3 * pre5 - pre2 * pre6;
            ny = pre3 * pre5 - pre4 * pre6;
            dn = pre2 * pre3 - x4_x3 * pre4;
            nx /= dn;
            ny /= dn;
            if ( nx >= 0 && nx <= 1 && ny >= 0 && ny <= 1 )
                return true;
            return false;
        }        

    }