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

Neon Sphere

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

package {
    import flash.display.Sprite;
    import flash.events.Event;
    [SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#000000")]
    /**
     * Neon Sphere
     * @author YOSHIDA, Akio(Aquioux)
     */
    public class Main extends Sprite {
        private var viewer_:Viewer;        // ビューア
        
        public function Main() {
            setup();
            addEventListener(Event.ENTER_FRAME, update);
        }
        
        // セットアップ
        private function setup():void {
            // ステージサイズ
            var w:int = stage.stageWidth;
            var h:int = stage.stageHeight;
            
            // 球座標の経度緯度それぞれの分割数
            var longitude:int = 36;
            var latitude:int  = longitude * 2;
            
            // 座標データ生成クラス初期化
            CreateData.setup(longitude, latitude, 150);

            // プロジェクションクラス初期化
            Projection.offsetX = w / 2;
            Projection.offsetY = h / 2;
            Projection.offsetZ = 500;
            Projection.longitude = longitude;
            Projection.latitude  = latitude;
            Projection.setup(CreateData.data);
            
            // マウス挙動クラス初期化
            MouseBehavior.setup(this);
            
            // ビューアの作成
            viewer_ = new Viewer(w, h);
            viewer_.buttonMode = true;
            addChild(viewer_);
        }
        
        // アップデート
        private function update(e:Event):void {
            MouseBehavior.update();
            viewer_.update(Projection.update(MouseBehavior.moveX, MouseBehavior.moveY));
        }
    }
}

//package {
    /**
     * 座標データ生成クラス
     * @author YOSHIDA, Akio(Aquioux)
     */
    /*public*/ class CreateData {
        /**
         * 座標データ Vector
         */ 
        static public function get data():Vector.<Number> { return _data; }
        static private var _data:Vector.<Number>;
        
        /**
         * セットアップ
         */
        static public function setup(longitude:int, latitude:int, scale:int):void {
            _data = new Vector.<Number>();
            var xRadian:Number = Math.PI * 2 / longitude;
            latitude++;    // 極点を省くため
            var yRadian:Number = Math.PI     / latitude;
            for (var y:int = 1; y < latitude; y++) {
                for (var x:int = 0; x < longitude; x++) {
                    var px:Number = scale * Math.sin(yRadian * y) * Math.cos(xRadian * x);
                    var py:Number = scale * Math.cos(yRadian * y);
                    var pz:Number = scale * Math.sin(yRadian * y) * Math.sin(xRadian * x);
                    _data.push(px, py, pz);
                }
            }
            _data.fixed = true;
        }
    }
//}

//package {
    //import aquioux.display.colorUtil.CycleRGB;
    import flash.geom.Matrix3D;
    import flash.geom.PerspectiveProjection;
    import flash.geom.Utils3D;
    import flash.geom.Vector3D;
    /**
     * 三次元座標を二次元座標に投射する
     * @author YOSHIDA, Akio(Aquioux)
     */
    /*public*/ class Projection {
        /**
         * X座標オフセット値
         */
        static public function get offsetX():Number { return _offsetX; }
        static public function set offsetX(value:Number):void { _offsetX = value; }
        static private var _offsetX:Number = 0;
        /**
         * Y座標オフセット値
         */
        static public function get offsetY():Number { return _offsetY; }
        static public function set offsetY(value:Number):void { _offsetY = value; }
        static private var _offsetY:Number = 0;
        /**
         * Z座標オフセット値
         */
        static public function get offsetZ():Number { return _offsetZ; }
        static public function set offsetZ(value:Number):void {
            _offsetZ = value;
            zLevel_  = 1 / value;
        }
        static private var _offsetZ:Number = 500;
        
        /**
         * 経度方向分割数
         */
        static public function get longitude():int { return _longitude; }
        static public function set longitude(value:int):void {
            _longitude = value;
            //colorOffset_ = 360 / (value + 1);
        }
        static private var _longitude:int;
        
        /**
         * 経度方向分割数
         */
        static public function get latitude():int { return _latitude; }
        static public function set latitude(value:int):void {
            _latitude = value;
            colorOffset_ = 360 / (value + 2);
        }
        static private var _latitude:int;
        

        // 座標 Vecotr
        static private var verts_:Vector.<Number>;            // 三次元座標
        static private var projectedVerts_:Vector.<Number>;    // 二次元投射後
        static private var uvts_:Vector.<Number>;            // uvts
        static private var data_:Vector.<Number>;            // #update の返値
        // パースペクティブ・プロジェクション
        static private var projection_:PerspectiveProjection;
        static private var projectionMatrix3D_:Matrix3D;
        // 回転計算用マトリクス
        static private var matrix_:Matrix3D;
        
        // 移動量保持
        static private var vx_:Number = 0;
        static private var vy_:Number = 0;
        
        // 色関連
        static private var colorOffset_:Number = 360 / (_longitude + 1);
        static private var colorShift_:int = 0;
        
        // z座標関連
        static private var zLevel_:Number = 1 / _offsetZ;


        /**
         * セットアップ
         * @param    data    三次元座標データ
         */
        static public function setup(verts:Vector.<Number>):void {
            // 座標 Vecotr
            verts_ = verts;
            var n:uint = verts_.length;
            projectedVerts_ = new Vector.<Number>(n * 2 / 3, true);
            uvts_ = new Vector.<Number>(n, true);
            data_ = new Vector.<Number>(n, true);
            
            // パースペクティブ・プロジェクション
            projection_ = new PerspectiveProjection();
            projectionMatrix3D_ = projection_.toMatrix3D();
            
            // 回転計算用マトリクス
            matrix_ = new Matrix3D();
        }

        /**
         * アップデート
         * @param    moveX    移動量(X軸方向)
         * @param    moveY    移動量(Y軸方向)
         * @return    三次元座標を投射した二次元座標データ
         */
        static public function update(moveX:Number, moveY:Number):Vector.<Number> {
            // 外部からの移動量 moveX、moveY を内部の移動量変数 vx_、vy_ に加算
            vx_ -= moveX;
            vy_ += moveY;
            
            // マトリクス計算
            matrix_.identity();
            matrix_.appendRotation(vy_, Vector3D.X_AXIS);
            matrix_.appendRotation(vx_, Vector3D.Y_AXIS);
            matrix_.appendTranslation(0, 0, _offsetZ);
            matrix_.append(projectionMatrix3D_);

            // 座標データに回転を適用
            Utils3D.projectVectors(matrix_, verts_, projectedVerts_, uvts_);
            
            // sort
            var array:Array = [];
            var currentLongitude:int = 0;
            var currentLatitude:int  = 0;
            var len:int = projectedVerts_.length / 2;
            for (var i:int = 0; i < len; i++) {
                var vertex:Vertex = new Vertex();
                vertex.x = projectedVerts_[i * 2]     + _offsetX;
                vertex.y = projectedVerts_[i * 2 + 1] + _offsetY;
                vertex.z = uvts_[i * 3 + 2];
                vertex.longitude = currentLongitude;
                vertex.latitude  = currentLatitude;
                array[i] = vertex;
                currentLongitude++;
                currentLongitude %= _longitude;
                if (currentLongitude == 0) currentLatitude++;
            }
            array.sortOn("z", Array.NUMERIC);
            
            // 返値生成
            data_.fixed = false;
            data_.length = 0;
            colorShift_ += 5;
            len = i;
            for (i = 0; i < len; i++) {
                vertex = array[i];
                var alpha:uint = vertex.z < zLevel_ ? 0x33 : 0xFF;
                //var c:uint = CycleRGB.getColor(vertex.longitude * colorOffset_ + colorShift_);
                var c:uint = CycleRGB.getColor(vertex.latitude * colorOffset_ +colorShift_);
                var color:uint = alpha << 24 | c;
                data_.push(vertex.x, vertex.y, Number(color));
            }
            data_.fixed = true;
            
            return data_;
        }
    }
//}

//package {
    import flash.display.DisplayObject;
    import flash.events.MouseEvent;
    /**
     * ビューア
     * @author YOSHIDA, Akio(Aquioux)
     */
    /*public*/ class MouseBehavior {
        // MOUSW_MOVE による移動量
        static public function get moveX():Number { return _moveX; }
        static private var _moveX:Number = 0;

        static public function get moveY():Number { return _moveY; }
        static private var _moveY:Number = 0;


        // 前回の MOUSW_MOVE 時のマウス座標
        static private var prevMouseX_:Number = 0;
        static private var prevMouseY_:Number = 0;
        
        // マウスをダウンしているか否か
        static private var isMouseDown_:Boolean = false;
        
        // 摩擦係数
        static private var friction_:Number = 0.98;

        // マウスイベントを addEvent する対象
        static private var target_:DisplayObject;


        /**
         * セットアップ
         */
        static public function setup(target:DisplayObject):void {
            target_ = target;
            target.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            target.addEventListener(MouseEvent.MOUSE_UP,   mouseUpHandler);
            target.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
        }
        // マウスハンドラ
        static private function mouseDownHandler(e:MouseEvent):void {
            isMouseDown_ = true;
        }
        static private function mouseUpHandler(e:MouseEvent):void {
            isMouseDown_ = false;
        }
        static private function mouseMoveHandler(e:MouseEvent):void {
            if (!isMouseDown_) {
                prevMouseX_ = target_.mouseX;
                prevMouseY_ = target_.mouseY;
            }
        }
        
        /**
         * アップデート
         */
        static public function update():void {
            if (isMouseDown_) {
                _moveX = target_.mouseX - prevMouseX_;
                _moveY = target_.mouseY - prevMouseY_;
                prevMouseX_ = target_.mouseX;
                prevMouseY_ = target_.mouseY;
            } else {
                _moveX *= friction_;
                _moveY *= friction_;
            }
        }
    }
//}

//package {
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.filters.BitmapFilterQuality;
    import flash.filters.BlurFilter;
    import flash.geom.ColorTransform;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    /**
     * ビューア
     * @author YOSHIDA, Akio(Aquioux)
     */
    /*public*/ class Viewer extends Sprite {
        //フェードアウトのための定義
        private const FADE:ColorTransform = new ColorTransform(0.999, 0.999, 0.999);
        private const BLUR:BlurFilter     = new BlurFilter(4, 4, BitmapFilterQuality.HIGH);
        
        // BitmapData 関連
        private var bmd_:BitmapData;            // 表示 BitmapData
        private var bufferBmd_:BitmapData;        // バッファ
        private var rect_:Rectangle;            // ColorTransform, Blur 共用
        private const ZERO_POINT:Point = new Point(0, 0);
        
        private var start_:int = 0;
        
        
        /**
         * コンストラクタ
         * @param    sw    ステージ幅
         * @param    sh    ステージ高
         */
        public function Viewer(sw:int, sh:int) {
            // BitmapData 関連
            bufferBmd_ = new BitmapData(sw, sh, true, 0xFF000000);
            bmd_  = bufferBmd_.clone();
            rect_ = bmd_.rect;
            addChild(new Bitmap(bmd_));
        }
        
        /**
         * アップデート
         * @param    data    描画座標データ
         */
        public function update(data:Vector.<Number>):void {
            // bufferBmd_ の更新
            bufferBmd_.lock();
            bufferBmd_.fillRect(bufferBmd_.rect, 0x00000000);
            
            var len:uint = data.length;
            for (var i:int = 0; i < len; i += 3) {
                var px:int    = data[i]     >> 0;
                var py:int    = data[i + 1] >> 0;
                var color:int = data[i + 2] >> 0;
                bufferBmd_.setPixel32(px, py, color);
            }
            bufferBmd_.unlock();
            
            // bmd_ の更新
            bmd_.lock();
            bmd_.colorTransform(rect_, FADE);
            bmd_.applyFilter(bmd_, rect_, ZERO_POINT, BLUR);
            bmd_.draw(bufferBmd_);
            bmd_.unlock();
        }
    }
//}

//package {
    /**
     * 座標
     * @author YOSHIDA, Akio (Aquioux)
     */
    /*public*/ class Vertex {
        // X座標値
        public function get x():Number { return _x; }
        public function set x(value:Number):void { _x = value; }
        private var _x:Number;
        // Y座標値
        public function get y():Number { return _y; }
        public function set y(value:Number):void { _y = value; }
        private var _y:Number;
        // Z座標値
        public function get z():Number { return _z; }
        public function set z(value:Number):void { _z = value; }
        private var _z:Number;
        // 経度上の位置
        public function get longitude():int { return _longitude; }
        public function set longitude(value:int):void { _longitude = value; }
        private var _longitude:int;
        // 緯度上の位置
        public function get latitude():int { return _latitude; }
        public function set latitude(value:int):void { _latitude = value; }
        private var _latitude:int;
        
        public function Vertex() { }
    }
//}

//package aquioux.display.colorUtil {
    /**
     * コサインカーブで色相環的な RGB を計算
     * @author Aquioux(YOSHIDA, Akio)
     */
    /*public*/ class CycleRGB {
        /**
         * 32bit カラーのためのアルファ値(0~255)
         */
        static public function get alpha():uint { return _alpha; }
        static public function set alpha(value:uint):void {
            _alpha = (value > 0xFF) ? 0xFF : value;
        }
        private static var _alpha:uint = 0xFF;
    
        private static const PI:Number = Math.PI;        // 円周率
        private static const DEGREE120:Number  = PI * 2 / 3;    // 120度(弧度法形式)
        
        /**
         * 角度に応じた RGB を得る
         * @param    angle    HSV のように角度(度数法)を指定
         * @return    色(0xNNNNNN)
         */
        public static function getColor(angle:Number):uint {
            var radian:Number = angle * PI / 180;
            var r:uint = (Math.cos(radian)             + 1) * 0xFF >> 1;
            var g:uint = (Math.cos(radian + DEGREE120) + 1) * 0xFF >> 1;
            var b:uint = (Math.cos(radian - DEGREE120) + 1) * 0xFF >> 1;
            return r << 16 | g << 8 | b;
        }
        
        /**
         * 角度に応じた RGB を得る(32bit カラー)
         * @param    angle    HSV のように角度(度数法)を指定
         * @return    色(0xNNNNNNNN)
         */
        public static function getColor32(angle:Number):uint {
            return _alpha << 24 | getColor(angle);
        }
    }
//}