In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

seamless blur

The diff is useless due to reindentation.
The only difference from psyark's version is the seamlessBlur function (the normal blur was messing up at the texture edges).
/**
 * Copyright yonatan ( http://wonderfl.net/user/yonatan )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/4ccs
 */

// forked from psyark's せっかくなので、回します
// forked from psyark's ヘタをつけます
// forked from psyark's シェーディングを近づけます
// forked from psyark's アングルを近づけます
// forked from psyark's 背景を近づけます
// forked from psyark's 色を近づけます
// forked from psyark's 形を近づけます
// forked from psyark's 隣にお手本を表示します
// forked from psyark's flash on 2009-12-9
package {
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    import flash.geom.*;
    import flash.system.*;
    import flash.net.*;
    import flash.utils.*;
    
    [SWF(width=465,height=465,frameRate=60,backgroundColor=0x000000)]
    /**
    * このクラスでは、法線マップから簡単なライティングを行います。
    */
    public class Test21 extends Sprite {
        private var viewport:Shape;
        private var vertices:Vector.<Number>;
        private var uvtData:Vector.<Number>;
        private var indices:Vector.<int>;
        private var worldMatrix:Matrix3D;
        private var viewMatrix:Matrix3D;
        private var projection:PerspectiveProjection;
        private var texture:BitmapData;
        private var normalMap:BitmapData;
        
        // 一時計算用ビットマップ
        private var tmp1:BitmapData;
        private var tmp2:BitmapData;

        private var palette:Array;
        
        /**
        * コンストラクタ
        */
        public function Test21() {
            var bg:BitmapData = new BitmapData(465, 465, false);
            bg.perlinNoise(250, 250, 1, 0, false, true, 7, true);
            bg.colorTransform(bg.rect, new ColorTransform(2.8, 2.8, 2.8, 1, -0x140, -0x150, -0x160));
            addChild(new Bitmap(bg));

            
            Security.loadPolicyFile("http://farm1.static.flickr.com/crossdomain.xml");
            var loader:Loader = new Loader();
            loader.load(new URLRequest("http://farm1.static.flickr.com/242/522495023_2a2423ecac.jpg"), new LoaderContext(true));
            loader.x = 465;
            addChild(loader);
            
            // 描画対象となるShapeを作成し、表示リストに追加します。
            viewport = new Shape();
            viewport.x = 465 * 0.53;
            viewport.y = 465 * 0.55;
            addChild(viewport);
            
            createMesh();
            createNormalMap();
            
            worldMatrix = new Matrix3D();
            viewMatrix = new Matrix3D();
            viewMatrix.appendTranslation(0, 0, 800);
            projection = new PerspectiveProjection();
            projection.fieldOfView = 60;
            
            texture = new BitmapData(512, 512, false);
            texture.perlinNoise(20, 100, 5, 0, true, true, 7, true);
            texture.colorTransform(texture.rect, new ColorTransform(0.1, 0.1, 0.1, 1, 0x66, 0x99, 0x00));
            
            tmp1 = new BitmapData(512, 512, false);
            tmp2 = new BitmapData(512, 512, false);
            
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);

            var paletteFactor:int = 1;
            palette = [];
            var spec:Number = 0.96;
            for (var i:int=0; i<0x100; i++) {
                var t:Number = i / 0xFF;
                var value:Number = Math.pow(t, 6) * 0x99;
                if (t > spec) {
                    value += Math.pow((t - spec) / (1 - spec), 8) * 0x22;
                }
                palette[i] = gs(value);
            }
            function gs(v:int):int {
                return v << 16 | v << 8 | v;
            }
        }
        
        /**
        * 3D形状を作成します
        */
        private function createMesh():void {
            vertices = new Vector.<Number>();
            uvtData = new Vector.<Number>();
            indices = new Vector.<int>();
            
            var hDiv:int = 32;
            var vDiv:int = 16;
            var hRadius:Number = 200;
            var vRadius:Number = 200;
            var a:uint, b:uint, i:uint, j:uint, k:uint, o:uint, r:Number, s1:Number, s2:Number;

            for (i=0; i<=hDiv; i++) {
                s1 = Math.PI * 2 * i / hDiv;
                for (j=0; j<=vDiv; j++) {
                    s2 = Math.PI * 2 * j / vDiv;
                    r = Math.cos(s2) * vRadius + hRadius;
                    vertices.push(Math.cos(s1) * r, Math.sin(s1) * r, Math.sin(s2) * vRadius * Math.SQRT2);
                    uvtData.push(i / hDiv, j / vDiv, 1);
                    if (j < vDiv && i < hDiv) {
                        a =  i      * (vDiv + 1) + j;
                        b = (i + 1) * (vDiv + 1) + j;
                        indices.push(b, a + 1, a, a + 1, b, b + 1);
                    }
                }
            }
            
            
            o = vertices.length / 3;
            for (i=0; i<=hDiv; i++) {
                for (j=0; j<=vDiv; j++) {
                    s2 = Math.PI * 2 * j / vDiv;
                    vertices.push(Math.cos(s2) * 20, Math.sin(s2) * 20, i * -13);
                    uvtData.push(i / hDiv, j / vDiv, 1);
                    if (j < vDiv && i < hDiv) {
                        a =  i      * (vDiv + 1) + j + o;
                        b = (i + 1) * (vDiv + 1) + j + o;
                        indices.push(b, a + 1, a, a + 1, b, b + 1);
                    }
                }
            }
            o = vertices.length / 3;
            vertices.push(0, 0, i * -13);
            for (j=0; j<=vDiv; j++) {
                indices.push(o, o - j - 1, o - j - 2);
            }
            

        }
        
        /**
        * 法線マップを作成します
        */
        private function createNormalMap():void {
            normalMap = new BitmapData(512, 512, false, 0);
            var mtx:Matrix3D = new Matrix3D();
            for (var x:uint=0; x<normalMap.width; x++) {
                for (var y:uint=0; y<normalMap.height; y++) {
                    mtx.identity();
                    mtx.appendRotation(y / normalMap.height * -360, Vector3D.Y_AXIS);
                    mtx.appendRotation(x / normalMap.width  * +360, Vector3D.Z_AXIS);
                    var normal:Vector3D = mtx.transformVector(Vector3D.X_AXIS);
                    var color:uint = (normal.x / 2 + 0.5) * 0xFF << 16 |
                    (normal.y / 2 + 0.5) * 0xFF << 8 |
                    (normal.z / 2 + 0.5) * 0xFF;
                    normalMap.setPixel(x, y, color);
                }
            }
        }
        
        /**
        * フレームごとの処理
        */
        private function enterFrameHandler(event:Event):void {
            update();
            render();
        }
        
        /**
        * 更新
        */
        private function update():void {
            worldMatrix.identity();
            worldMatrix.appendRotation(-18, Vector3D.X_AXIS);
            worldMatrix.appendRotation(5, Vector3D.Y_AXIS);
            var r:Number = getTimer() * 0.0003;
            worldMatrix.appendRotation(Math.cos(r) * 10, Vector3D.X_AXIS);
            worldMatrix.appendRotation(Math.sin(r) * 10, Vector3D.Y_AXIS);
        }
        
        /**
        * 描画
        */
        private function render():void {
            // ライティング
            var light:Vector3D = new Vector3D();
            light.x = 0;
            light.y = 0;
            light.z = -Math.sqrt(1 - light.lengthSquared);
            var invertWorld:Matrix3D = worldMatrix.clone();
            invertWorld.invert();
            light = invertWorld.transformVector(light);
            // 法線マップと光線ベクトルを掛けて光量を得る
            tmp1.applyFilter(normalMap, normalMap.rect, new Point(), createLightingFilter(light));
            tmp1.paletteMap(tmp1, tmp1.rect, tmp1.rect.topLeft, palette, [], []);
            seamlessBlur(tmp1, new BlurFilter(8, 8, 3));
            // テクスチャと光量をハードライトブレンドして、ライティングが行われたテクスチャを得る
            tmp2.copyPixels(texture, texture.rect, texture.rect.topLeft);
            tmp2.draw(tmp1, null, null, BlendMode.HARDLIGHT);
            
            // World行列、View行列、Projection行列を結合して一つの行列にする
            var m:Matrix3D = new Matrix3D();
            m.append(worldMatrix);
            m.append(viewMatrix);
            m.append(projection.toMatrix3D());
            
            // 上記の行列を使って頂点座標を投影する
            var projected:Vector.<Number> = new Vector.<Number>();
            Utils3D.projectVectors(m, vertices, projected, uvtData);
            
            viewport.graphics.clear();
            viewport.graphics.beginBitmapFill(tmp2, null, false, true);
            viewport.graphics.drawTriangles(projected, getSortedIndices(), uvtData, TriangleCulling.POSITIVE);
            viewport.graphics.endFill();
        }

        private function seamlessBlur(bmd:BitmapData, filter:BlurFilter):void {
            var bx:Number = filter.blurX;
            var by:Number = filter.blurY;
            var bmdw:int = bmd.width;
            var bmdh:int = bmd.height;
            var tmp:BitmapData = new BitmapData(bmdw+bx*2, bmdh+by*2, bmd.transparent);
            var s:Shape = new Shape;
            var m:Matrix = new Matrix;
            m.translate(bx, by);
            s.graphics.beginBitmapFill(bmd, m);
            s.graphics.drawRect(0, 0, tmp.width, tmp.height);
            s.graphics.endFill();
            tmp.draw(s);
            var rect:Rectangle = new Rectangle(bx, by, bmdw, bmdh);
            tmp.applyFilter(tmp, tmp.rect, tmp.rect.topLeft, filter);
            bmd.copyPixels(tmp, rect, bmd.rect.topLeft);
        }
        
        /**
        * Zソートされたインデックスを返す
        */
        private function getSortedIndices():Vector.<int> {
            var triangles:Array = [];
            for (var i:int=0; i<indices.length; i+=3) {
                var i1:int = indices[i+0];
                var i2:int = indices[i+1];
                var i3:int = indices[i+2];
                var z:Number = Math.min(uvtData[i1 * 3 + 2], uvtData[i2 * 3 + 2], uvtData[i3 * 3 + 2]);
                if (z > 0) {
                    triangles.push({i1:i1, i2:i2, i3:i3, z:z});
                }
            }
            triangles = triangles.sortOn("z", Array.NUMERIC);
            
            var sortedIndices:Vector.<int> = new Vector.<int>(0, false);
            for each (var triangle:Object in triangles) {
                sortedIndices.push(triangle.i1, triangle.i2, triangle.i3);
            }
            return sortedIndices;
        }
        
        /**
        * 光の方向ベクトルからライティング用フィルタを作成
        */
        private function createLightingFilter(light:Vector3D):ColorMatrixFilter {
            return new ColorMatrixFilter([
                    2 * light.x, 2 * light.y, 2 * light.z, 0, (light.x + light.y + light.z) * -0xFF,
                    2 * light.x, 2 * light.y, 2 * light.z, 0, (light.x + light.y + light.z) * -0xFF,
                    2 * light.x, 2 * light.y, 2 * light.z, 0, (light.x + light.y + light.z) * -0xFF,
                    0,           0,           0,           1, 0
                ]);
        }
    }
}