Alternativa3D / Object3D drag with gizmo.
forked from Alternativa3D / Object3D drag on ground (diff: 390)
Drag box with gizmo ala 3D studio max style!
ActionScript3 source code
/**
* Copyright Glidias ( http://wonderfl.net/user/Glidias )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/62i5
*/
// forked from liquid.cow's Alternativa3D / Object3D drag on ground
// forked from narutohyper's Object3D Drag [Alternativa3D 7.5.1 TIPS]
// forked from narutohyper's Alternativa3D 7.5 Template
package
{
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.materials.TextureMaterial;
import alternativ7.engine3d.primitives.Box;
import alternativ7.engine3d.core.MouseEvent3D;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.View;
import alternativ7.engine3d.core.RayIntersectionData;
import alternativ7.engine3d.objects.Sprite3D;
import alternativ7.engine3d.core.Object3D;
import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.controllers.SimpleObjectController;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.Shape;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Vector3D;
import flash.text.TextField;
/**
*
* Alternativa3D 7.6
*
* Object3DのDrag;
*
* ...
* @author narutohyper
*/
[SWF(backgroundColor="#FFFFFF", frameRate="100", width="800", height="600")]
public class Main extends Sprite
{
private const RADIAN:Number = Math.PI / 180;
public function Main():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private var textfield:TextField;
private function init(e:Event=null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
//AlternativaTemplate作成
var scene:AlternativaTemplate = new AlternativaTemplate(this,null);
//Materialの作成
//星パーティクル
var stars:Vector.<Sprite3D> = new Vector.<Sprite3D>(500, true);
var circle:Shape = new Shape();
circle.graphics.beginFill(0x0000ff);
circle.graphics.drawCircle(0, 0, 2);
var bmd:BitmapData = new BitmapData(2, 2, true, 0);
bmd.draw(circle);
var material:TextureMaterial = new TextureMaterial(bmd);
var angle:Number;
var length:Number;
for (var i:int = 0; i < 200; i++)
{
stars[i] = new Sprite3D(5, 5, material);
scene.container.addChild(stars[i]);
angle = Math.random() * 360 * RADIAN;
length = Math.random() * 4000 - 2000;
stars[i].x = Math.cos(angle) * length;
stars[i].y = 0;
angle = Math.random() * 360 * RADIAN;
length = Math.random() * 4000 - 2000;
stars[i].z = Math.sin(angle) * length;
}
var material2:FillMaterial = new FillMaterial(0xFFFFFF, 1, 0,0x0);
//Box
box = new Box(400, 40, 800, 1, 1, 1);
box.setMaterialToAllFaces(material2);
scene.container.addChild(box);
//カメラの調整
//カメラはControllerに関連付けている為、x,y,zで直接位置を指定できないので
//SimpleController.setObjectPosXYZを使用
camera = scene.camera;
cameraContainer = new Object3DContainer();
cameraContainer.addChild(camera);
scene.container.addChild(cameraContainer);
//cameraController = new SimpleObjectController(stage, cameraContainer, 100);
// cameraController.mouseSensitivity = 1;
//cameraController.unbindAll();
scene.cameraController.setObjectPosXYZ(0, 1000, -1000);
scene.cameraController.lookAtXYZ(0, 0, 0);
scene.cameraController.mouseSensitivity = 1;
//scene.cameraController.unbindAll();
scene.cameraController.update();
view = scene.view;
gizmoDragger = new GizmoDrag(scene.container, camera);
// ensure controller is locked while dragging
gizmoDragger.registerController(scene.cameraController);
// Note: you can register multiple objects to be draggable!
gizmoDragger.registerObject(box);
camera.render();
//ObjectControllerの作成
//MouseDragで、Objectを回転させる為のController
//var objectController:SimpleObjectController = new SimpleObjectController(stage,box,100)
//objectController.unbindAll()
//描画開始
scene.startRendering();
scene.onPreRender = function():void {
//objectController.update();
//cameraController.lookAtXYZ(0, 0, 0);
// cameraController.update();
}
textfield = new TextField();
textfield.width = 400;
textfield.text = 'Click on the box to drag it with gizmo.';
addChild(textfield);
}
private var gizmoDragger:GizmoDrag;
private var view:View;
private var cameraContainer:Object3DContainer;
//private var cameraController:SimpleObjectController;
private var camera:Camera3D;
private var box:Box;
private var distance:Number;
}
}
/**
* BasicTemplate for Alternativa3D 7.5
* Alternativa3D 7.5を扱いやすくするためのテンプレートです
* @author narutohyper & clockmaker
*
*/
import alternativ7.engine3d.containers.BSPContainer;
import alternativ7.engine3d.containers.ConflictContainer;
import alternativ7.engine3d.containers.DistanceSortContainer;
import alternativ7.engine3d.containers.KDContainer;
import alternativ7.engine3d.containers.LODContainer;
import alternativ7.engine3d.controllers.SimpleObjectController;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.core.View;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
class AlternativaTemplate extends Sprite
{
/**
* 子オブジェクトを最適な方法でソートするコンテナ
* (ConflictContainer)
*/
public static const CONFLICT:String = 'conflict';
/**
* 子オブジェクトをBSP(バイナリ空間分割法)によってソートするコンテナ
* (BSPContainer)
*/
public static const BSP:String = 'bsp';
/**
* 子オブジェクトをカメラからのZ値でソートするコンテナ
* (DistanceSortContainer)
*/
public static const ZSORT:String = 'zsort';
/**
* KDツリー(http://ja.wikipedia.org/wiki/Kd%E6%9C%A8)によってソートするコンテナ
* (KDContainer)
*/
public static const KD:String = 'kd';
/**
* detalizationと子オブジェクトの距離でソートするコンテナ(詳細は調査中)
* (LODContainer)
*/
public static const LOD:String = 'lod';
/**
* 3dオブジェクト格納するコンテナインスタンス。
*/
public var container:Object3DContainer;
/**
* ビューインスタンスです。
*/
public var view:View;
/**
* カメラインスタンスです。
*/
public var camera:Camera3D;
/**
* カメラコントローラーです。
*/
public var cameraController:SimpleObjectController;
private var _mc:DisplayObjectContainer;
private var _viewWidth:int;
private var _viewHeight:int;
private var _scaleToStage:Boolean;
private var _containerType:String;
/**
* 新しい Alternativa3DTemplate インスタンスを作成します。
* @param mc
* @param containerType
* @param viewWidth
* @param viewHeight
* @param scaleToStage
*/
public function AlternativaTemplate(mc:DisplayObjectContainer,containerType:String=CONFLICT,viewWidth:int=640, viewHeight:int=480, scaleToStage:Boolean = true)
{
_mc = mc;
_mc.addChild(this);
_containerType = containerType;
_viewWidth = viewWidth;
_viewHeight = viewHeight;
_scaleToStage = scaleToStage;
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
/**
* 初期化されたときに実行されるイベントです。
* 初期化時に実行したい処理をオーバーライドして記述します。
*/
protected function atInit():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング前に実行したい処理をオーバーライドして記述します。
*/
protected function atPreRender():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング前に実行したい処理をオーバーライドして記述します。
*/
private var _onPreRender:Function = function():void{};
public function get onPreRender():Function { return _onPreRender; }
public function set onPreRender(value:Function):void
{
_onPreRender = value;
}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング後に実行したい処理をオーバーライドして記述します。
*/
protected function atPostRender():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング後に実行したい処理を記述します。
*/
private var _onPostRender:Function = function():void{};
public function get onPostRender():Function { return _onPostRender; }
public function set onPostRender(value:Function):void
{
_onPostRender = value;
}
/**
* レンダリングを開始します。
*/
public function startRendering():void
{
addEventListener(Event.ENTER_FRAME, onRenderTick);
}
/**
* レンダリングを停止します。
*/
public function stopRendering():void
{
removeEventListener(Event.ENTER_FRAME, onRenderTick);
}
/**
* シングルレンダリング(レンダリングを一回だけ)を実行します。
*/
public function singleRender():void
{
onRenderTick();
}
/**
* @private
*/
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.HIGH;
//Root objectの作成
if (_containerType == CONFLICT) {
container = new ConflictContainer();
} else if (_containerType == BSP) {
container = new BSPContainer();
} else if (_containerType == ZSORT) {
container = new DistanceSortContainer();
} else if (_containerType == KD) {
container = new KDContainer();
} else if (_containerType == LOD) {
container = new LODContainer();
}
else {
container = new Object3DContainer();
}
//Viewの作成
view = new View(stage.stageWidth, stage.stageHeight);
_mc.addChild(view);
//cameraの作成
camera = new Camera3D();
camera.view = view;
camera.x = 0;
camera.y = -500;
camera.z = 0;
container.addChild(camera);
// Camera controller
cameraController = new SimpleObjectController(stage, camera, 10);
cameraController.mouseSensitivity = 0;
cameraController.unbindAll();
cameraController.lookAtXYZ(0, 0, 0);
onResize();
stage.addEventListener(Event.RESIZE, onResize);
atInit();
}
/**
* @private
*/
private function onResize(e:Event = null):void
{
if (_scaleToStage)
{
view.width = stage.stageWidth;
view.height = stage.stageHeight;
}
else
{
view.width = _viewWidth;
view.height = _viewHeight;
}
}
/**
* @private
*/
private function onRenderTick(e:Event = null):void
{
atPreRender();
_onPreRender();
cameraController.update();
camera.render();
atPostRender();
_onPostRender();
}
}
//package utils.editor
//{
import alternativ7.engine3d.controllers.SimpleObjectController;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.MouseEvent3D;
import alternativ7.engine3d.core.Object3D;
import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.core.RayIntersectionData;
import alternativ7.engine3d.core.View;
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.primitives.Box;
import alternativ7.engine3d.primitives.Plane;
import flash.display.Stage;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Vector3D;
/**
* This gizmo is to support drag moving of objects in root global coordinate space.
*
* For rotation, pretty pointless, would rather use numeric stepper instead.
*
* @author Glenn Ko
*/
//public
class GizmoDrag extends Object3DContainer
{
private var _rootContainer:Object3DContainer;
private var box:Object3D;
private var camera:Camera3D;
private var startPoint:Vector3D;
private var _dragPlane:Vector3D;
private static const AXIS_X:Vector3D = new Vector3D(1, 0, 0);
private static const AXIS_Y:Vector3D = new Vector3D(0, 1, 0);
private static const AXIS_Z:Vector3D = new Vector3D(0, 0, 1);
private var _lockX:Boolean = false;
private var _lockY:Boolean = false;
private var _lockZ:Boolean = false;
private var _curPlane:Vector3D = AXIS_Z;
public static const START_DRAG:String = "startDrag";
public static const STOP_DRAG:String = "stopDrag";
public static const DRAG:String = "drag";
public static const SELECT:String = "select";
public function get currentPlaneNormal():Vector3D {
return _curPlane.clone();
}
public function get currentItem():Object3D {
return box;
}
public function GizmoDrag(rootContainer:Object3DContainer, camera:Camera3D)
{
this._rootContainer = rootContainer;
this.camera = camera;
createControls();
}
private static const RED_FILL:FillMaterial = new FillMaterial(0xFF0000, 1);
private static const GREEN_FILL:FillMaterial = new FillMaterial(0x00FF00, 1);
private static const BLUE_FILL:FillMaterial = new FillMaterial(0x0000FF, 1);
private static const RED_LINE:FillMaterial = new FillMaterial(0xFF0000, .3, 1, 0xFF0000);
private static const GREEN_LINE:FillMaterial = new FillMaterial(0x00FF00,.3, 1, 0x00FF00);
private static const BLUE_LINE:FillMaterial = new FillMaterial(0x0000FF, .3, 1, 0x0000FF);
private static const GRAY_LINE:FillMaterial = new FillMaterial(0x888888, .3, 1, 0x888888);
private var _controller:SimpleObjectController;
public function registerController(controller:SimpleObjectController):void {
this._controller = controller;
addEventListener(START_DRAG, freezeController);
addEventListener(STOP_DRAG, unfreezeController);
}
private function unfreezeController(e:Event):void
{
_controller.enable();
//_controller.startMouseLook();
}
private function freezeController(e:Event):void
{
_controller.disable();
//_controller.stopMouseLook();
}
private function createControls():void {
var boxer:Box;
var plane:Plane;
// movement gizmo
plane = new Plane(80,80,1,1,true);
plane.name = "xy";
plane.x = 40;
plane.y = 40;
plane.setMaterialToAllFaces(RED_LINE);
putControl(plane);
plane = new Plane(80,80,1,1,true);
plane.name = "xz";
plane.x = 40;
plane.z = 40;
plane.rotationX = 90 * Math.PI / 180;
plane.setMaterialToAllFaces(GREEN_LINE);
putControl(plane);
plane = new Plane(80,80,1,1,true);
plane.name = "yz";
plane.y = 40;
plane.z = 40;
plane.rotationY = 90 * Math.PI / 180;
plane.setMaterialToAllFaces(BLUE_LINE);
putControl(plane);
boxer= new Box(100,20,20);
boxer.name = "x";
boxer.x = 50;
boxer.setMaterialToAllFaces(RED_FILL);
putControl(boxer);
boxer = new Box(20,100,20);
boxer.name = "y";
boxer.y = 50;
boxer.setMaterialToAllFaces(GREEN_FILL);
putControl(boxer);
boxer = new Box(20,20,100);
boxer.name = "z";
boxer.z = 50;
boxer.setMaterialToAllFaces(BLUE_FILL);
putControl(boxer);
}
private function putControl(obj:Object3D):void {
addChild(obj);
obj.useHandCursor = true;
obj.addEventListener(MouseEvent3D.MOUSE_DOWN, onControlClick, false , 0, true);
}
private function onControlClick(e:MouseEvent3D):void
{
var namer:String = e.target.name;
var data:RayIntersectionData = intersectRay(e.localOrigin, e.localDirection);
if (data == null) return;
startPoint = localToGlobal(data.point);
//startPoint = globalToLocal(startPoint);
//startPoint = new Vector3D();
//throw new Error(namer);
_lockX = true;
_lockY = true;
_lockZ = true;
switch(namer) {
case "x":
_curPlane = AXIS_Z; // z or other shouldn't matter
_lockX = false;
break;
case "y":
_curPlane = AXIS_Z; // z or other shouldn't matter
_lockY = false;
break;
case "z":
_curPlane = AXIS_X; // x or y shouldn't matter
_lockZ = false;
break;
case "xy":
_curPlane = AXIS_Z;
_lockX = false;
_lockY = false;
break;
case "xz":
_curPlane = AXIS_Y;
_lockX = false;
_lockZ = false;
break;
case "yz":
_curPlane = AXIS_X;
_lockY = false;
_lockZ = false;
break;
default:return;
}
dispatchEvent( new Event(START_DRAG) );
camera.view.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
camera.view.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
public function registerObject(obj:Object3D):void {
obj.useHandCursor = true;
obj.addEventListener(MouseEvent3D.CLICK, onObjClick, false , 0, true);
}
private function onObjClick(e:MouseEvent3D):void
{
box = e.target as Object3D;
visible = true;
x = box.x;
y = box.y;
z = box.z;
_rootContainer.addChild(this);
dispatchEvent( new Event(SELECT));
}
private function onMouseUp(e:MouseEvent):void
{
camera.view.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
camera.view.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
dispatchEvent( new Event(STOP_DRAG) );
}
private function onMouseMove(e:MouseEvent):void
{
var origin:Vector3D = new Vector3D;
var directionA:Vector3D = new Vector3D;
var directionB:Vector3D = new Vector3D;
var direction:Vector3D = new Vector3D;
//Object3Dまでの距離を、cameraViewのCENTERまで並行移動させた距離をドラッグ先まで並行移動
camera.calculateRay(origin, directionA, camera.view.width/2, camera.view.height/2);
camera.calculateRay(origin, directionB, camera.view.mouseX, camera.view.mouseY);
var pos:Vector3D = intersectionPoint(origin, directionB, new Vector3D(startPoint.x, startPoint.y, startPoint.z), _curPlane);
// somehow, startPoint offset seems wrong for this case!
if (!_lockX) box.x = pos.x;// - startPoint.x;
if (!_lockY) box.y = pos.y; //- startPoint.y;
if (!_lockZ) box.z = pos.z; //- startPoint.z;
dispatchEvent( new Event(DRAG) );
x = box.x;
y = box.y;
z = box.z;
}
public static function intersectionPoint(lineStart:Vector3D, lineDirection:Vector3D, planePosition:Vector3D, planeNormal:Vector3D):Vector3D {
var result:Vector3D = new Vector3D();
var w:Vector3D = lineStart.subtract(planePosition);
var d:Number = planeNormal.dotProduct(lineDirection);
var n:Number = -planeNormal.dotProduct(w);
if (Math.abs(d) < 0.0000001) return result;
var sI:Number = n / d;
result.x = lineStart.x + (lineDirection.x * sI);
result.y = lineStart.y + (lineDirection.y * sI);
result.z = lineStart.z + (lineDirection.z * sI);
return result;
}
public function unregisterObject(obj:Object3D):void {
obj.useHandCursor = false;
obj.removeEventListener(MouseEvent.CLICK, onObjClick);
//obj.removeEventListener(MouseEvent.MOUSE_DOWN, onObj
}
public function refreshPosition():void
{
if (box == null) return;
x = box.x;
y = box.y;
z = box.z;
}
public function selectNone():void
{
box = null;
visible = false;
}
}
//}