[Alternativa3D 7.5] test

by tencho
♥112 | Line 410 | Modified 2012-10-23 16:11:34 | MIT License
play

ActionScript3 source code

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

/**
 * Alternativa3D7.5の練習
 * Colladaモデルを読み込んでカメラを動かしているだけです
 * カメラの位置によってはエラーが出てしまうみたいで時々固まります。。
 */
package  {
	import alternativ7.engine3d.containers.BSPContainer;
	import alternativ7.engine3d.controllers.SimpleObjectController;
	import alternativ7.engine3d.core.Camera3D;
	import alternativ7.engine3d.core.Object3D;
	import alternativ7.engine3d.core.Sorting;
	import alternativ7.engine3d.core.View;
	import alternativ7.engine3d.loaders.events.LoaderErrorEvent;
	import alternativ7.engine3d.loaders.events.LoaderProgressEvent;
	import alternativ7.engine3d.loaders.MaterialLoader;
	import alternativ7.engine3d.loaders.ParserCollada;
	import alternativ7.engine3d.materials.FillMaterial;
	import alternativ7.engine3d.materials.TextureMaterial;
	import alternativ7.engine3d.objects.Mesh;
	import com.bit101.components.CheckBox;
	import com.bit101.components.Label;
	import com.bit101.components.Style;
	import com.bit101.components.VBox;
	import flash.display.*;
	import flash.events.*;
	import flash.geom.ColorTransform;
	import flash.geom.Vector3D;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	import flash.system.Security;
	import flash.utils.Dictionary;
	import net.hires.debug.Stats;
	import org.libspark.betweenas3.BetweenAS3;
	import org.libspark.betweenas3.easing.Quad;
	import org.libspark.betweenas3.tweens.ITween;
	import org.libspark.betweenas3.tweens.ITweenGroup;
	public class Alternativa3DTest extends Sprite {
		private var _autoCamera:Object3D = new Object3D();
		private var _userCamera:Object3D = new Object3D();
		private var _cameraMode:int = 0;
		private var _camera:Camera3D;
		private var _controller:SimpleObjectController;
		private var _scene:BSPContainer;
		private var _dragger:GlobeDragger;
		
		private var _stats:Stats;
		private var _bg:Sprite;
		private var _header:Sprite;
		private var _info:Label;
		private var _loadingTxt:Label;
		private var _wireMaterial:FillMaterial = new FillMaterial(0, 0, 0, 0xffffff);
		private var _rawTextures:Dictionary = new Dictionary();
		
		private var _loader:URLLoader;
		private var _parser:ParserCollada;
		private var _mloader:MaterialLoader;
		private var _isInitError:Boolean = false;
		
		private const PATH_POLICY:String = "http://shelter.s377.xrea.com/crossdomain.xml";
		private const PATH_DIR:String = "http://shelter.s377.xrea.com/assets/wonderfl/alt3dtest/";
		private const PATH_DAE:String = "model_wdfl.DAE";
		
		/**
		 * コンストラクタ
		 */
		public function Alternativa3DTest() {
			stage.frameRate = 60;
			stage.quality = StageQuality.LOW;
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.addEventListener(Event.RESIZE, onResize);
			
			_camera = new Camera3D();
			_camera.view = new View(465, 465);
			_camera.view.alpha = 0;
			_controller = new SimpleObjectController(stage, _camera, 1);
						
			_scene = new BSPContainer();
			_scene.addChild(_camera);
			
			//マウスドラッグで動かすカメラ用
			_dragger = new GlobeDragger(this, 45, 2, 320);
			_dragger.enabled = false;
			_dragger.wheelEnabled = false;
			_dragger.angleSpeed = _dragger.rotationSpeed = 0.75;
			_dragger.setAngleLimit( -7, 90);
			_dragger.setDistanceLimit(10, 420);
			
			var v:Vector3D = _dragger.position;
			_userCamera.x = v.x;
			_userCamera.y = v.z;
			_userCamera.z = v.y;
			
			//画面に配置するもの色々
			_bg = Painter.createColorRect(465, 465, 0x000000);
			_header = new Sprite();
			_header.addChild(Painter.createColorRect(465, 40, 0, 0.5));
			Style.LABEL_TEXT = 0x000000;
			new SwitchButton(_header, 10, 10, ["CAMERA : AUTO", "CAMERA : DRAG"], onSwitchCamera);
			new SwitchButton(_header, 120, 10, ["WIREFRAME : OFF", "WIREFRAME : ON"], onSwitchMaterial);
			Style.LABEL_TEXT = 0xFFFFFF;
			_info = new Label(_header, 230, 10, "");
			_loadingTxt = new Label(null, 10, 10, "LOADING COLLADA MODEL ...");
			_stats = new Stats( { bg:0x222222 } );
			Style.BACKGROUND = 0x444444;
			var vox:VBox = new VBox(_header);
			vox.x = 8;
			vox.y = 50;
			vox.spacing = 12;
			for (var i:int = 0; i < 3; i++) {
				var chk:CheckBox = new CheckBox(vox, 0, 0, ["VOLUME LIGHT", "REFLECTION", "BSP SORTING"][i], onClickCheckBox);
				chk.tag = i;
				chk.selected = true;
			}
			addChild(_bg);
			addChild(_loadingTxt);
			addChild(_camera.view);
			addChild(_header);
			addChild(_stats);
			
			_header.visible = false;
			
			onResize(null);
			startLoad();
		}
		private function onClickCheckBox(e:MouseEvent):void{
			var rb:CheckBox = e.currentTarget as CheckBox;
			switch(rb.tag) {
				case 0:
					_scene.getChildByName("volumelight").visible = rb.selected;
					break;
				case 1:
					_scene.getChildByName("floor").blendMode = (rb.selected)? BlendMode.ADD : BlendMode.NORMAL;
					break;
				case 2:
					setBSPEnabled(rb.selected);
					break;
			}
		}
		/**
		 * BSPソートとZソートを切り替える
		 * @param	enabled
		 */
		private function setBSPEnabled(enabled:Boolean):void{
			for (var i:int = 0; i < _scene.numChildren; i++) {
				var m:Mesh = _scene.getChildAt(i) as Mesh;
				if (!m) continue;
				if (["floor", "sunlight", "containerbox", "truss", "poles"].indexOf(m.name) != -1) {
					m.sorting = (enabled)? Sorting.DYNAMIC_BSP : Sorting.AVERAGE_Z;
				}
			}
		}
		/**
		 * カメラモード切り替え
		 */
		private function onSwitchCamera(e:MouseEvent, mode:int):void {
			_cameraMode = mode;
			_dragger.enabled = (_cameraMode == 1);
			onTick(null);
		}
		/**
		 * マテリアル張り替え
		 */
		private function onSwitchMaterial(e:MouseEvent, mode:int):void {
			for (var i:int = 0; i < _scene.numChildren; i++) {
				var o:Object3D = _scene.getChildAt(i);
				if (o is Mesh) {
					var m:Mesh = o as Mesh;
					m.setMaterialToAllFaces(mode? _wireMaterial : _rawTextures[m]);
				}
			}
			_camera.render();
		}
		/**
		 * 画面リサイズ時
		 */
		private function onResize(e:Event):void {
			var sw:Number = stage.stageWidth;
			var sh:Number = stage.stageHeight;
			_bg.width = sw;
			_bg.height = sh;
			_stats.y = sh - 100;
			_camera.view.width = sw;
			_camera.view.height = sh;
			_camera.render();
			_header.getChildAt(0).width = sw;
		}
		/**
		 * Collada読み込み開始
		 */
		private function startLoad():void {
			Security.loadPolicyFile(PATH_POLICY);
			_loader = new URLLoader();
			_loader.addEventListener(Event.COMPLETE, onLoadCollada);
			_loader.addEventListener(IOErrorEvent.IO_ERROR, onErrorAsset);
			_loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onErrorAsset);
			_loader.load(new URLRequest(PATH_DIR + PATH_DAE));
		}
		private function onErrorAsset(e:ErrorEvent):void {
			_loadingTxt.text = e.text;
			_loadingTxt.transform.colorTransform = new ColorTransform(0, 0, 0, 1, 0xFF, 0, 0);
			_isInitError = true;
		}		
		/**
		 * Colladaモデル読み込み完了時
		 * @param	e
		 */
		private function onLoadCollada(e:Event):void {
			//Colladaファイルをパース
			_parser = new ParserCollada();
			_parser.parse(new XML(_loader.data), PATH_DIR);
			
			//テクスチャ読み込み
			_mloader = new MaterialLoader();
			_mloader.addEventListener(LoaderErrorEvent.LOADER_ERROR, onErrorAsset);
			_mloader.addEventListener(LoaderProgressEvent.LOADER_PROGRESS, onProgressMaterial);
			_mloader.addEventListener(Event.COMPLETE, onCompleteMaterial);
			_mloader.load(_parser.textureMaterials, new LoaderContext(true));
		}
		private function onProgressMaterial(e:LoaderProgressEvent):void {
			if (_isInitError) return;
			var per:Number = e.totalProgress;
			_loadingTxt.text = "LOADING COLLADA MODEL ... " + int(per * 100) + "%";
		}
		/**
		 * テクスチャ読み込み完了時
		 * @param	e
		 */
		private function onCompleteMaterial(e:Event):void {
			//マテリアルの読み込みに失敗していたら処理停止
			if (_isInitError) return;
			addEventListener(Event.ENTER_FRAME, onTick);
			//黒画面からのフェードイン
			BetweenAS3.to(_camera.view, { alpha:1 }, 2, Quad.easeIn).play();
			_header.visible = true;
			_loadingTxt.visible = false;
			
			//全テクスチャのリピートをOFFにする
			for each(var tm:TextureMaterial in _parser.textureMaterials) tm.repeat = false;
			
			//天井からの光の筋
			_parser.getObjectByName("volumelight").blendMode = BlendMode.OVERLAY;
			//床
			_parser.getObjectByName("floor").blendMode = BlendMode.ADD;
			
			var totalFaceNum:int = 0;
			var cameras:Vector.<Object3D> = new Vector.<Object3D>();
			
			for each(var o:Object3D in _parser.objects) {
				if (!o.name) continue;
				_scene.addChild(o);
				if (o is Mesh) {
					var m:Mesh = o as Mesh;
					_rawTextures[m] = m.geometry.orderedFaces[0].material;
					totalFaceNum += m.geometry.orderedFaces.length;
				} else if (o.name.indexOf("Camera") != -1) {
					//カメラリストに追加
					cameras.push(o);
				}
			}
			setBSPEnabled(true);
			_info.text = "TOTAL FACES: " + totalFaceNum;
			//カメラリストを名前順にソート
			cameras.sort(function(a:Object3D, b:Object3D):int { return int(a.name > b.name) - int(a.name < b.name) } );
			
			//自動カメラの動きをBetweenAS3で設定する
			var list:Array = [];
			var leng:int = cameras.length;
			for (var i:int = 0; i < leng; i++) {
				var cf:Object3D = cameras[i];
				var ct:Object3D = cameras[(i + 1) % leng];
				var it:ITween = BetweenAS3.tween(
					_autoCamera,
					{ x:ct.x, y:ct.y, z:ct.z, rotationX:ct.rotationX, rotationY:ct.rotationY, rotationZ:ct.rotationZ },
					{ x:cf.x, y:cf.y, z:cf.z, 
						rotationX:Angle.toNearRadian(cf.rotationX, ct.rotationX),
						rotationY:Angle.toNearRadian(cf.rotationY, ct.rotationY),
						rotationZ:Angle.toNearRadian(cf.rotationZ, ct.rotationZ)
					},
					2.5,
					Quad.easeInOut
				);
				it = BetweenAS3.delay(it, 0.5, 0);
				list.push(it);
			}
			if (leng) {
				var itg:ITweenGroup = BetweenAS3.serialTweens(list);
				itg.stopOnComplete = false;
				itg.play();
			}
			
			onResize(null);
		}
		/**
		 * 毎フレーム処理
		 * @param	e
		 */
		private function onTick(e:Event):void {
			if (_cameraMode == 0) {
				//自動カメラモード
				_controller.setObjectPosXYZ(_autoCamera.x, _autoCamera.y, _autoCamera.z);
				_controller.lookAtXYZ(0, 0, 0);
				_camera.rotationX = _autoCamera.rotationX;
				_camera.rotationY = _autoCamera.rotationY;
				_camera.rotationZ = _autoCamera.rotationZ;
			} else {
				//ドラッグカメラモード
				var v:Vector3D = _dragger.position;
				_userCamera.x += (v.x - _userCamera.x) * 0.3;
				_userCamera.y += (v.z - _userCamera.y) * 0.3;
				_userCamera.z += (v.y - _userCamera.z) * 0.3;
				_controller.setObjectPosXYZ(_userCamera.x, _userCamera.y, _userCamera.z + 80);
				_controller.lookAtXYZ(0, 0, 80);
			}
			_camera.render();
		}
	}
}
import com.bit101.components.PushButton;
import flash.display.DisplayObjectContainer;
import flash.display.InteractiveObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Vector3D;
class Angle {
	static public const PI2:Number = Math.PI * 2;
	/**
	 * baseのラジアン度をnearに一番近くなるよう再設定(+Math.PI*2/-Math.PI*2)する
	 */
	static public function toNearRadian(base:Number, near:Number):Number {
		var rad:Number = base - near;
		rad = (rad % PI2 + PI2) % PI2;
		if (rad > Math.PI) rad -= PI2;
		return rad + near;
	}
}
/**
 * シーンをマウスでぐるぐる
 */
class GlobeDragger extends EventDispatcher {
	public var zoomSpeed:Number = 1.2;
	public var rotationSpeed:Number = 1;
	public var angleSpeed:Number = 1;
	public var distanceMin:Number = NaN;
	public var distanceMax:Number = NaN;
	public var rotationMin:Number = NaN;
	public var rotationMax:Number = NaN;
	public var angleMin:Number = NaN;
	public var angleMax:Number = NaN;
	public var wheelEnabled:Boolean = false;
	
	private var _distance:Number;
	private var _rotation:Number;
	private var _angle:Number;
	private var _enabled:Boolean = true;
	private var _eventObj:InteractiveObject;
	private var _saveRotation:Number;
	private var _saveAngle:Number;
	private var _saveMousePos:Point;
	private var _position:Vector3D = new Vector3D();
	
	public var onMoveCamera:Function;
	
	public function get position():Vector3D { return _position; }
	public function get enabled():Boolean { return _enabled; }
	public function set enabled(value:Boolean):void {
		onMsUp();
		_enabled = value;
	}
	
	/**
	 * @param	obj	マウスイベントを登録する場所
	 * @param	rotation	初期の横方向角度
	 * @param	angle	初期の縦方向角度
	 * @param	distance	初期の中心点からの距離
	 */
	public function GlobeDragger(obj:InteractiveObject, rotation:Number = 0, angle:Number = 30, distance:Number = 1000) {
		_distance = distance;
		_angle = angle;
		_rotation = rotation;
		_eventObj = obj;
		_eventObj.addEventListener(MouseEvent.MOUSE_DOWN, onMsDown);
		_eventObj.stage.addEventListener(MouseEvent.MOUSE_WHEEL, onMsWheel);
	}
	private function dispose():void {
		_eventObj.removeEventListener(MouseEvent.MOUSE_DOWN, onMsDown);
		_eventObj.stage.removeEventListener(MouseEvent.MOUSE_UP, onMsUp);
		_eventObj.stage.removeEventListener(MouseEvent.MOUSE_WHEEL, onMsWheel);
		_eventObj.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMsMove);
	}
	private function onMsWheel(e:MouseEvent):void {
		if (!_enabled || !wheelEnabled) return;
		var vec:int = (e.delta < 0)? -1 : 1;
		_distance *= Math.pow(zoomSpeed, -vec);
		_distance = checkLimit(_distance, distanceMin, distanceMax);
		updatePosition();
	}
	public function dispatch():void {
		dispatchEvent(new Event(Event.CHANGE));
		if (onMoveCamera != null) onMoveCamera.apply(null, [_position]);
	}
	public function setDistanceLimit(min:Number, max:Number):void {
		distanceMin = min;
		distanceMax = max;
	}
	public function setAngleLimit(min:Number, max:Number):void {
		angleMin = min;
		angleMax = max;
	}
	public function setRotationLimit(min:Number, max:Number):void {
		rotationMin = min;
		rotationMax = max;
	}
	private function onMsDown(e:MouseEvent):void {
		if (!_enabled) return;
		_eventObj.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMsMove);
		_eventObj.stage.addEventListener(MouseEvent.MOUSE_UP, onMsUp);
		_saveRotation = _rotation;
		_saveAngle = _angle;
		_saveMousePos = new Point(_eventObj.mouseX, _eventObj.mouseY);
	}
	private function onMsMove(e:MouseEvent):void {
		if (!_enabled) return;
		var dragOffset:Point = new Point(_eventObj.mouseX, _eventObj.mouseY).subtract(_saveMousePos);
		_rotation = _saveRotation - dragOffset.x * rotationSpeed;
		_rotation = checkLimit(_rotation, rotationMin, rotationMax);
		_angle = Math.max(-89, Math.min(89, _saveAngle + dragOffset.y * angleSpeed));
		_angle = checkLimit(_angle, angleMin, angleMax);
		updatePosition();
	}
	private function checkLimit(num:Number, min:Number, max:Number):Number {
		if (!isNaN(min) && num < min) num = min;
		if (!isNaN(max) && num > max) num = max;
		return num;
	}
	private function onMsUp(...rest):void {
		_eventObj.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMsMove);
		_eventObj.stage.removeEventListener(MouseEvent.MOUSE_UP, onMsUp);
		updatePosition();
	}
	private function updatePosition():void {
		var per:Number = Math.cos(Math.PI / 180 * _angle);
		var px:Number = Math.cos(Math.PI / 180 * _rotation) * _distance * per;
		var py:Number = Math.sin(Math.PI / 180 * _angle) * _distance;
		var pz:Number = Math.sin(Math.PI / 180 * _rotation) * _distance * per;
		_position = new Vector3D(px, py, pz)
		dispatch();
	}
}
/**
 * クリックでラベルが切り替わるボタン
 */
class SwitchButton extends PushButton {
	private var _mode:int = 0;
	private var _labels:Array = [];
	private var _switchFunc:Function;
	public function get mode():int { return _mode; }
	public function SwitchButton(parent:DisplayObjectContainer = null, x:Number = 0, y:Number = 0, labels:Array = null, clickFunc:Function = null) {
		_switchFunc = clickFunc;
		_labels = (labels == null)? [""] : labels.concat();
		if (_labels.length == 0) _labels = [""];
		super(parent, x, y, _labels[0], onClick);
	}
	public function setMode(mode:int):void {
		_mode = mode;
		label = _labels[mode];
	}
	private function onClick(e:MouseEvent):void {
		setMode(++_mode % _labels.length);
		//引数の数が足りない場合は処理を振り分ける
		if (_switchFunc != null) {
			try {
				_switchFunc.apply(null, [e, _mode]);
			} catch (error:Error) {
				try {
					_switchFunc.apply(null, [e]);
				} catch (error:Error) {
					_switchFunc.apply(null, []);
				}
			}
		}
	}
}
class Painter {
	/**
	 * べた塗りスプライト生成
	 */
	static public function createColorRect(width:Number, height:Number, color:uint = 0x000000, alpha:Number = 1, x:Number = 0, y:Number = 0):Sprite {
		var sp:Sprite = new Sprite();
		sp.graphics.beginFill(color, alpha);
		sp.graphics.drawRect(0, 0, width, height);
		sp.graphics.endFill();
		sp.x = x;
		sp.y = y;
		return sp;
	}
}

Forked