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

forked from: ドット地球儀・リファクタリング

http://wonderfl.net/code/38309e41fd7854c73d87729156be1e53a10b6e49 のリファクタリング
*
* 一番大きな変更点は以下の2点。
* (1) Matrix3D 計算を個々のパーティクルにおいて matrix3D.transformVector でおこなっていたのを、Model クラスにおいて Utils3D.projectVectors でおこなうようにした。
* (2) パーティクルを zsort することにより、描画 BitmapData を一つにした。
* 
* (2) については以下を参考にさせていただきました。
* http://wonderfl.net/code/cc3d98ef63c1b65bb96dcda9c560f84dd8f6a90c
*
* その他、ムダにムリヤリ MVC に当て嵌めたクラス構成しています。

2009/10/23 反転の修正
/**
 * Copyright mymail22 ( http://wonderfl.net/user/mymail22 )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/agCP
 */

// forked from Aquioux's ドット地球儀・リファクタリング
/**
 * http://wonderfl.net/code/38309e41fd7854c73d87729156be1e53a10b6e49 のリファクタリング
 *
 * 一番大きな変更点は以下の2点。
 * (1) Matrix3D 計算を個々のパーティクルにおいて matrix3D.transformVector でおこなっていたのを、Model クラスにおいて Utils3D.projectVectors でおこなうようにした。
 * (2) パーティクルを zsort することにより、描画 BitmapData を一つにした。
 * 
 * (2) については以下を参考にさせていただきました。
 * http://wonderfl.net/code/cc3d98ef63c1b65bb96dcda9c560f84dd8f6a90c
 *
 * その他、ムダにムリヤリ MVC に当て嵌めたクラス構成しています。
 */

 /**
 * 2009/10/23 反転の修正
 */
package {
    
    import flash.display.Sprite;
    import flash.events.Event;
    import net.hires.debug.Stats;
    [SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "#000000")]
    
    public class Main extends Sprite {
        
        public function Main() {
            // 外部データの読込
            // (画像ファイルのロードとピクセル分解)
            var URL_OF_IMAGEFILE:String = "http://assets.wonderfl.net/images/related_images/6/6f/6fb0/6fb075e04102b2f4409a896f17acac4597f3f423";
            
            var data1:DataFactory1 = new DataFactory1(URL_OF_IMAGEFILE);
            data1.addEventListener(Event.COMPLETE, completeHandler1);
            data1.start();
        }
        private function completeHandler1(event:Event):void {
            // 読み込んだ外部データの解析
            // (分解した各ピクセルに座標設定)
            var RADIUS_OF_SPHERE:Number = 150.0;
            
            var data2:DataFactory2 = new DataFactory2(event.target.pixelizer, RADIUS_OF_SPHERE);
            data2.addEventListener(Event.COMPLETE, completeHandler2);
            data2.start();
        }
            
        private function completeHandler2(event:Event):void {
            // Model を生成
            var model:Model = new Model(event.target.verts.concat());
            model.offsetX = stage.stageWidth / 2;
            model.offsetY = stage.stageHeight / 2;
            model.offsetZ = 500;
            model.speed = 0.025;
            model.fieldOfView = 55;

            // View を生成
            var view:View = new View(model);
            addChild(view);
            
            // Controller を生成
            var controller:Controller = new Controller(model);
            controller.setup(stage);
            
            addChild(new Stats());
        }
        
    }
    
}


    import flash.display.Bitmap;
    import flash.display.Loader;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    
    
    class DataFactory1 extends EventDispatcher {

        // 外部に渡すデータ
        public function get pixelizer():Pixelizer { return _pixelizer; }
        private var _pixelizer:Pixelizer;
        

        private var url:String;
        public function DataFactory1(url:String) {
            this.url = url;
        }
        
        internal function start():void {
            var loader:Loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadCompleteHandler);
            loader.load(new URLRequest(url), new LoaderContext(true));
        }
        private function loadCompleteHandler(event:Event):void {
            _pixelizer = new Pixelizer();
            _pixelizer.addEventListener(Event.COMPLETE, scanCompleteHandler);
            _pixelizer.scan(Bitmap(event.target.loader.content).bitmapData);
        }
        private function scanCompleteHandler(event:Event):void {
            dispatchEvent(new Event(Event.COMPLETE));
        }
        
    }


    import flash.display.Loader;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    
    
    class DataFactory2 extends EventDispatcher {
        
        // 外部に渡すデータ
        public function get verts():Vector.<Number> { return _verts; }
        private var _verts:Vector.<Number> = new Vector.<Number>();
        

        private var pixelizer:Pixelizer;
        private var radius:Number;
        public function DataFactory2(pixelizer:Pixelizer, radius:Number) {
            this.pixelizer = pixelizer;
            this.radius    = radius;
        }
        
        internal function start():void{
            var iter:PixelizerIterator = pixelizer.iterator;
            var vNum:uint = iter.height;
            var hNum:uint = iter.width;
            
            // theta:シータ(θ)は緯度、phi:ファイ(φ)は経度
            var theta:Number = Math.PI / vNum;
            var phi:Number   = Math.PI * 2 / hNum;
            while (iter.hasNext()) {
                var color:uint = iter.next();
                var alpha:uint = ColorMath.getAlpha(color);
                if (alpha > 0x7F){
                    var px:Number = radius * Math.sin(theta * iter.y) * Math.cos(phi * iter.x);
                    var py:Number = radius * Math.cos(theta * iter.y);
                    var pz:Number = radius * Math.sin(theta * iter.y) * Math.sin(phi * iter.x);
                    _verts.push(px, -py, pz);
                }
            }
            _verts.fixed = true;

            dispatchEvent(new Event(Event.COMPLETE));
        }
        
    }


    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.geom.Matrix3D;
    import flash.geom.PerspectiveProjection;
    import flash.geom.Vector3D;
    import flash.geom.Utils3D;
    
    class Model extends EventDispatcher {
        
        // 外部へ渡すデータ
        public function get viewData():Array { return _viewData; }
        private var _viewData:Array;
        
        public function get zLevel():Number { return _zLevel; }
        private var _zLevel:Number = 1 / _offsetZ;


        // 外部から受けるデータ
        
        // 引数として受ける
        private var verts:Vector.<Number>;

        // セッターで受ける
        public function set offsetX(value:Number):void {
            _offsetX = value;
        }
        private var _offsetX:Number = 0;

        public function set offsetY(value:Number):void {
            _offsetY = value;
        }
        private var _offsetY:Number = 0;
        
        public function set offsetZ(value:Number):void {
            _offsetZ = value;
            _zLevel = 1 / _offsetZ;
        }
        private var _offsetZ:Number = 500;
        
        public function set speed(value:Number):void {
            _speed = value;
        }
        private var _speed:Number = 0.025;
        
        public function set fieldOfView(value:Number):void {
            projection.fieldOfView = value;
            projectionMatrix3D = projection.toMatrix3D();
        }
        private var _fieldOfView:Number;
        
        
        private var vx:Number = 0;
        private var vy:Number = 0;
        // Controller から呼び出される
        internal function update(valueX:Number, valueY:Number):void {
            // Controller から渡された値を加工
            vx += (_offsetX - valueX) * _speed;
            vy -= (_offsetY - valueY) * _speed;
            
            // Controller から渡された値を回転に変換
            m.identity();
            m.appendRotation(vy, Vector3D.X_AXIS);
            m.appendRotation(vx, Vector3D.Y_AXIS);
            m.appendTranslation(0, 0, _offsetZ);
            m.append(projectionMatrix3D);

            // 外部データに回転を適用
            Utils3D.projectVectors(m, verts, projectedVerts, uvts);
            
            // 回転を適用した外部データを zsort
            var n:uint = projectedVerts.length / 2;
            for (var i:int = 0; i < n; i++) {
                var vertex:Vertex = _viewData[i];
                vertex.x = projectedVerts[i * 2]     + _offsetX;
                vertex.y = projectedVerts[i * 2 + 1] + _offsetY;
                vertex.z = uvts[i * 3 + 2];
            }
            _viewData.sortOn("z", Array.NUMERIC);
            
            // リスナー(View)へ通知
            notifyListeners();
        }
        
        
        private var projectedVerts:Vector.<Number>;
        private var uvts:Vector.<Number>;
        private var projection:PerspectiveProjection;
        private var projectionMatrix3D:Matrix3D;
        private var m:Matrix3D;
        public function Model(verts:Vector.<Number>) {
            // 外部から受けるデータを引数として受ける
            this.verts = verts;

            // 内部でのみ使用する Vector の初期化
            var n:uint = verts.length / 3;
            projectedVerts = new Vector.<Number>(n * 2, true);
            uvts           = new Vector.<Number>(n * 3, true)
            
            // 外部へ渡すデータの初期化
            _viewData = [];
            for (var i:int = 0; i < n; i++) {
                _viewData.push(new Vertex());
            }

            // PerspectiveProjection の Matrix3D を取得
            projection = new PerspectiveProjection();
            projectionMatrix3D = projection.toMatrix3D();
            
            // 外部データに適用する Matrix3D
            m = new Matrix3D();
        }
        
        // View へ伝える
        private function notifyListeners():void {
            dispatchEvent(new Event(Event.CHANGE));
        }
        
    }


    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Vector3D;

    class View extends Sprite {
        
        private function changeHandler(event:Event):void {
            // Model からデータを受ける
            var data:Array    = model.viewData;
            var zLevel:Number = model.zLevel;

            // 描画
            canvas.lock();
            canvas.fillRect(canvas.rect, 0xFF000000);
            var n:uint = data.length;
            for (var i:int = 0; i < n; i++) {
                var v:Vertex = data[i];
                var posX:Number = v.x;
                var posY:Number = v.y;
                var color:uint = v.z > zLevel ? 0xFFFFCC00 : 0xFF0033FF;
                canvas.setPixel32(posX, posY, color);
            }
            canvas.unlock();
        }

        private var model:Model;
        public function View(model:Model) {
            this.model = model;
            this.model.addEventListener(Event.CHANGE, changeHandler);
            addEventListener(Event.ADDED_TO_STAGE, setup);
        }
        private var canvas:BitmapData;
        private function setup(event:Event):void {
            removeEventListener(Event.ADDED_TO_STAGE, setup);
            canvas = new BitmapData(stage.stageWidth, stage.stageHeight);
            addChild(new Bitmap(canvas));
        }
        
    }


    import flash.display.Sprite;
    import flash.display.Stage;
    import flash.events.Event;

    class Controller {

        private var stage:Stage;
        internal function setup(stage:Stage):void {
            this.stage = stage;
            stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        }
        
        private function enterFrameHandler(event:Event):void {
            model.update(stage.mouseX, stage.mouseY);
        }

        private var model:Model;
        public function Controller(model:Model) {
            this.model = model;
        }
        
    }


    class Vertex {
        
        public var x:Number;
        public var y:Number;
        public var z:Number;
        
        public function Vertex() {}
    }


    import flash.display.BitmapData;
    import flash.events.Event;
    import flash.events.EventDispatcher;

    class Pixelizer extends EventDispatcher {
        
        // イテレータ
        public function get iterator():PixelizerIterator {
            return new PixelizerIterator(width, height, data);
        }
        

        private var width:uint  = 0;
        private var height:uint = 0;
        private var data:Vector.<uint>;
        // スキャン
        public function scan(bmd:BitmapData):void {
            width  = bmd.width;
            height = bmd.height;
            data   = bmd.getVector(bmd.rect);
            dispatchEvent(new Event(Event.COMPLETE));
        }
        

        public function Pixelizer() {}

    }


    class PixelizerIterator {
        
        // モードフラグ
        public static const NEXT:String = "next";    // 正順
        public static const PREV:String = "prev";    // 逆順

        // next()、nextCol() で取得したデータのX座標
        public function get x():int { return positionX; }
        private var positionX:int = 0;
        // next()、nextRow() で取得したデータのY座標
        public function get y():int { return positionY; }
        private var positionY:int = 0;

        // スキャンサイズ(幅)
        public function get width():uint { return _width; }
        private var _width:uint;
        // スキャンサイズ(高)
        public function get height():uint { return _height; }
        private var _height:uint;


        // 現在のイテレートモード
        private var mode:String = "next";
        // イテレーションカウンター
        private var position:int = 0;
        
        // データ格納 Vector
        private var data:Vector.<uint>;


        public function PixelizerIterator(width:uint, height:uint, data:Vector.<uint>) {
            _width  = width;
            _height = height;
            this.data = data;
        }
        

        // データの操作(1個ずつデータを呼び出す)
        // 外部から呼び出せる hasNext
        public function hasNext():Boolean {
            return (mode == "prev") ? _hasPrev() : _hasNext();
        }
        // 外部から呼び出せる next
        public function next():uint {
            return (mode == "prev") ? _prev() : _next();
        }

        // データの同一列(横)の操作(同一列の全てのデータを呼び出す)
        // 外部から呼び出せる hasNext
        public function hasNextRow():Boolean {
            return (mode == "prev") ? _hasPrevRow() : _hasNextRow();
        }
        // 外部から呼び出せる next
        public function nextRow():Vector.<uint> {
            return (mode == "prev") ? _prevRow() : _nextRow();
        }

        // データの同一行(縦)の操作(同一行のすべてのデータを呼び出す)
        // 外部から呼び出せる hasNext
        public function hasNextCol():Boolean {
            return (mode == "next") ? _hasNextCol() : _hasPrevCol();
        }
        // 外部から呼び出せる next
        public function nextCol():Vector.<uint> {
            return (mode == "next") ? _nextCol() : _prevCol();
        }

        // リセット
        public function reset(mode:String = "next"):void {
            this.mode = mode;
            var offset:uint = (mode == "next") ? 0 : 1;
            position  = (data.length - 1) * offset;
            positionX = (_width  - 1) * offset;
            positionY = (_height - 1) * offset;
        }


        // データの操作(1個ずつデータを呼び出す)
        // mode = "next" 時の hasNext
        private function _hasNext():Boolean {
            return position < data.length;
        }
        // mode = "prev" 時の hasNext
        private function _hasPrev():Boolean {
            return position > 0;
        }
        // mode = "next" 時の next
        private function _next():uint {
            positionX = position % _width;
            positionY = position / _width;
            return getData(position++);
        }
        // mode = "prev" 時の next
        private function _prev():uint {
            positionX = position % _width;
            positionY = position / _width;
            return getData(position--);
        }
        private function getData(idx:uint):uint {
            if (idx >= data.length) {
                throw new Error("getData#配列範囲外:" + idx + " length:" + data.length);
            }
            return data[idx];
        }
        
        // データの同一列(横)の操作(同一列の全てのデータを呼び出す)
        // mode = "next" 時の hasNext
        private function _hasNextRow():Boolean {
            return positionY < _height;
        }
        // mode = "prev" 時の hasNext
        private function _hasPrevRow():Boolean {
            return positionY > -1;
        }
        // mode = "next" 時の next
        private function _nextRow():Vector.<uint> {
            return getRow(positionY++);
        }
        // mode = "prev" 時の next
        private function _prevRow():Vector.<uint> {
            return getRow(positionY--);
        }
        // next の実体
        private function getRow(val:uint):Vector.<uint> {
            if (val >= _height) {
                throw new Error("getRow#配列範囲外:" + val + " _height:" + _height);
            }
            return data.slice(val * _width, (val + 1) * _width);
        }
        
        // データの同一行(縦)の操作(同一行のすべてのデータを呼び出す)
        // mode = "next" 時の hasNext
        private function _hasNextCol():Boolean {
            return positionX < _width;
        }
        // mode = "prev" 時の hasNext
        private function _hasPrevCol():Boolean {
            return positionX > -1;
        }
        // mode = "next" 時の next
        private function _nextCol():Vector.<uint> {
            return getCol(positionX++);
        }
        // mode = "prev" 時の next
        private function _prevCol():Vector.<uint> {
            return getCol(positionX--);
        }
        // next の実体
        private function getCol(idx:uint):Vector.<uint> {
            if (idx >= _width) {
                throw new Error("getCol#配列範囲外:" + idx + " _width:" + _width);
            }
            var vector:Vector.<uint> = new Vector.<uint>(_height, true);
            for (var i:uint = 0; i < _height; i++) {
                vector[i] = data[_width * i + idx];
            }
            return vector;
        }
        
    }

    
    class ColorMath {

        public function ColorMath() {}


        // RGB → 0xNNNNNN
        public static function rgbToHex(r:uint, g:uint, b:uint):uint {
            r = adjust(r);
            g = adjust(g);
            b = adjust(b);

            return r << 16 | g << 8 | b;
        }
        // 0xNNNNNN → RGB
        public static function hexToRgb(hex:uint):Object {
            var r:uint = (hex >> 16) & 0xFF;
            var g:uint = (hex >>  8) & 0xFF;
            var b:uint =  hex        & 0xFF;

            return {r:r, g:g, b:b};
        }


        // ARGB → 0xNNNNNNNN
        public static function argbToHex(a:uint, r:uint, g:uint, b:uint):uint {
            a = adjust(a);
            r = adjust(r);
            g = adjust(g);
            b = adjust(b);

            return a<<24 | r<<16 | g<<8 | b;
        }
        // 0xNNNNNNNN → ARGB
        public static function hexToArgb(hex:uint):Object {
            var a:uint = (hex >> 24) & 0xFF;
            var r:uint = (hex >> 16) & 0xFF;
            var g:uint = (hex >>  8) & 0xFF;
            var b:uint =  hex        & 0xFF;

            return {a:a, r:r, g:g, b:b};
        }


        // RGB 各要素調整用関数
        // 255 を超えていた場合は 255 に切り捨てる
        private static function adjust(val:uint):uint {
            return Math.min(val, 0xFF);
        }

        // 32 bit color のアルファ値を取得
        public static function getAlpha(color:uint):uint {
            return (color >> 24) & 0xFF;
        }
        
    }