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

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

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 反転の修正
Get Adobe Flash player
by Aquioux 22 Oct 2009
/**
 * Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/13dD
 */

/**
 * 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;
		}
		
	}