/sandy/as3/branches/1.5/sandy/view/Camera3D.as
ActionScript | 535 lines | 289 code | 44 blank | 202 comment | 8 complexity | 27294095071e7350f0930631383eb943 MD5 | raw file
- ///////////////////////////////////////////////////////////
- // Camera3D.as
- // Macromedia ActionScript Implementation of the Class Camera3D
- // Generated by Enterprise Architect
- // Created on: 26-VII-2006 13:46:04
- // Original author: Thomas Pfeiffer - kiroukou
- ///////////////////////////////////////////////////////////
-
- package sandy.view
- {
- import sandy.core.data.Matrix4;
- import sandy.core.data.Vector;
- import sandy.view.IScreen;
- import sandy.core.transform.Interpolator3D;
- import sandy.events.InterpolationEvent;
- import sandy.math.Matrix4Math;
- import sandy.math.VectorMath;
- import sandy.core.transform.TransformType;
-
- import flash.display.Sprite;
- import flash.geom.Rectangle;
- /**
- * Camera3D
- * @author Thomas Pfeiffer - kiroukou
- * @version 1.0
- * @date 05.08.2006
- * @created 26-VII-2006 13:46:04
- */
- public class Camera3D
- {
- private var _compiled: Boolean;// boolean allowing kind of cache matrix computation
- private var _mp: Matrix4;// projection Matrix4
- private var _mt: Matrix4;// Matrix4 of tranformations
- private var _mv: Matrix4;// ViewPort matrix
- private var _nFocal: Number;// Nodal Distance of camera ( and not Focal )
- private var _nRoll: Number;// current roll value
- private var _nTilt: Number;// current tilt value
- private var _nYaw: Number;// current yaw value
- private var _p: Vector;// Position of camera ( a Vector )
- private var _rDim: Rectangle;// screen size useful to create an offset
- private var _vOut: Vector;// Camera view Orientation Vector
- private var _vSide: Vector;// Camera Side Orientation Vector
- private var _vUp: Vector;// Camera up Orientation Vector
- private var _screen:IScreen;// associated screen
- private var _oInt:Interpolator3D;// The interpolator
-
- /**
- * Camera's name
- */
- public var name:String;
-
- /**
- * Camera's angle
- */
- public var _angle:Vector;
-
-
- /**
- * final Matrix4 which is the result of the transformation and projection matrix's
- * multiplication.
- */
- public var matrix:Matrix4;
-
- /**
- * Create a new Camera3D.
- *
- * @param nFoc The focal of the Camera3D
- * @param s the screen associated to the camera
- */
- public function Camera3D( nFoc:Number, s:IScreen, nm:String = "Camera" )
- {
- name = nm;
- _p = new Vector();
- _screen = s;
- _nFocal = nFoc;
- // --
- _vOut = new Vector( 0, 0, 1 );
- _vSide = new Vector( 1, 0, 0 );
- _vUp = new Vector( 0, 1 ,0 );
- // --
- _nRoll = 0;
- _nTilt = 0;
- _nYaw = 0;
- // --
- _screen.setCamera ( this );
- _rDim = _screen.getSize();
- _mt = _mp = matrix = _mv = Matrix4.createIdentity();
- _compiled = false;
- __loadSimpleProjection();
- _oInt = null;
- }
-
- public function getScreen():IScreen
- {
- return _screen;
- }
-
- public function moveAroundY(pos:Vector,angle:Number,diatance:Number):void
- {
- _compiled=false;
- _angle.y+=angle;
- _p.x=pos.x+diatance*Math.sin(_angle.y);
- _p.z=pos.z+diatance*Math.cos(_angle.y);
- this.lookAt(pos.x,pos.y,pos.z);
-
- }
-
-
- /**
- * Allow the camera to translate along its side vector.
- * If you imagine yourself in a game, it would be a step on your right or on your left
- * @param d Number Move the camera along its side vector
- */
- public function moveSideways( d : Number ):void
- {
- _compiled = false;
- _p.x += _vSide.x * d;
- _p.y += _vSide.y * d;
- _p.z += _vSide.z * d;
- }
-
- /**
- * Allow the camera to translate along its up vector.
- * If you imagine yourself in a game, it would be a jump on the direction of your body (so not always the vertical!)
- * @param d Number Move the camera along its up vector
- */
- public function moveUpwards( d : Number ):void
- {
- _compiled = false;
- _p.x += _vUp.x * d;
- _p.y += _vUp.y * d;
- _p.z += _vUp.z * d;
- }
-
- /**
- * Allow the camera to translate along its view vector.
- * If you imagine yourself in a game, it would be a step in the direction you look at. If you look the sky
- * you will translate upwards ! So be careful with its use.
- * @param d Number Move the camera along its viw vector
- */
- public function moveForward( d : Number ):void
- {
- _compiled = false;
- _p.x += _vOut.x * d;
- _p.y += _vOut.y * d;
- _p.z += _vOut.z * d;
- }
-
- /**
- * Allow the camera to translate horizontally
- * If you imagine yourself in a game, it would be a step in the direction you look at but without changing
- * your altitude.
- * @param d Number Move the camera horizontally
- */
- public function moveHorizontally( d:Number ):void
- {
- _compiled = false;
- _p.x += _vOut.x * d;
- _p.z += _vOut.z * d;
- }
-
- /**
- * Allow the camera to translate vertically
- * If you imagine yourself in a game, it would be a jump strictly vertical.
- * @param d Number Move the camera vertically
- */
- public function moveVertically( d:Number ):void
- {
- _compiled = false;
- _p.y -= d;
- }
-
- /**
- * Translate the camera from it's actual position with the offset values pased in parameters
- *
- * @param px x offset that will be added to the x coordinate of the camera
- * @param py y offset that will be added to the y coordinate position of the camera
- * @param pz z offset that will be added to the z coordinate position of the camera
- */
- public function translate( px:Number, py:Number, pz:Number ):void
- {
- _compiled = false;
- // we must consider the screen y-axis inversion
- _p.x += px;
- _p.y -= py;
- _p.z += pz;
- }
-
-
- /**
- * Allow the camera to translate lateraly
- * If you imagine yourself in a game, it would be a step on the right with a positiv parameter and to the left
- * with a negative parameter
- * @param d Number Move the camera lateraly
- */
- public function moveLateraly( d:Number ):void
- {
- _compiled = false;
- _p.x += d;
- }
-
- /**
- * Rotate the camera around a specific axis by an angle passed in parameter
- * @param ax Number The x coordinate of the axis
- * @param ay Number The y coordinate of the axis
- * @param az Number The z coordinate of the axis
- * @param nAngle Number The amount of rotation. This angle is in degrees.
- */
- public function rotateAxis( ax:Number, ay:Number, az:Number, nAngle:Number ):void
- {
- _compiled = false;
- nAngle = (nAngle + 360)%360;
- var n:Number = Math.sqrt( ax*ax + ay*ay + az*az );
- var m : Matrix4 = Matrix4Math.axisRotation( ax/n, ay/n, az/n, nAngle );
- Matrix4Math.vectorMult3x3( m, _vSide);
- Matrix4Math.vectorMult3x3( m, _vUp);
- Matrix4Math.vectorMult3x3( m, _vOut);
- }
-
- /**
- * Make the camera look at a specific position. Useful to follow a moving object or a static object while the camera is moving.
- * @param px Number The x position to look at
- * @param py Number The y position to look at
- * @param pz Number The z position to look at
- */
- public function lookAt( px:Number, py:Number, pz:Number ):void
- {
- _compiled = false;
- _vOut = VectorMath.sub( new Vector(px, -py, pz), _p );
- VectorMath.normalize( _vOut );
- _vSide = VectorMath.cross( _vOut, new Vector(0, -1, 0) );
- VectorMath.normalize( _vSide );
- _vUp = VectorMath.cross( _vOut, _vSide );
- VectorMath.normalize( _vUp );
- }
-
- /**
- * RotateX - Rotation around the global X axis of the camera frame
- * @param nAngle Number The angle of rotation in degree.
- * @return Void
- */
- public function rotateX ( nAngle:Number ):void
- {
- _compiled = false;
- nAngle = (nAngle + 360)%360;
- var m:Matrix4 = Matrix4Math.axisRotation ( 1, 0, 0, nAngle );
- Matrix4Math.vectorMult3x3( m, _vUp);
- Matrix4Math.vectorMult3x3( m, _vSide);
- Matrix4Math.vectorMult3x3( m, _vOut);
- }
-
- /**
- * rotateY - Rotation around the global Y axis of the camera frame
- * @param nAngle Number The angle of rotation in degree.
- * @return Void
- */
- public function rotateY ( nAngle:Number ):void
- {
- _compiled = false;
- nAngle = (nAngle + 360)%360;
- var m:Matrix4 = Matrix4Math.axisRotation ( 0, 1, 0, nAngle );
- Matrix4Math.vectorMult3x3( m, _vUp);
- Matrix4Math.vectorMult3x3( m, _vSide);
- Matrix4Math.vectorMult3x3( m, _vOut);
- }
-
- /**
- * rotateZ - Rotation around the global Z axis of the camera frame
- * @param nAngle Number The angle of rotation in degree between : [ -180; 180 ].
- * @return
- */
- public function rotateZ ( nAngle:Number ):void
- {
- _compiled = false;
- nAngle = (nAngle + 360)%360;
- var m:Matrix4 = Matrix4Math.axisRotation ( 0, 0, 1, nAngle );
- Matrix4Math.vectorMult3x3( m, _vUp);
- Matrix4Math.vectorMult3x3( m, _vSide);
- Matrix4Math.vectorMult3x3( m, _vOut);
- }
-
- /**
- * Tilt - Rotation around the local X axis of the camera frame
- * Range from -90 to +90 where 0 = Horizon, +90 = straight up and –90 = straight down.
- * @param nAngle Number The angle of rotation in degree.
- * @return Void
- */
- public function tilt ( nAngle:Number ):void
- {
- //_nTilt = NumberUtil.constrain( _nTilt + nAngle, -90, 90 );
- //if( _nTilt == -90 || _nTilt == 90 ) return;
- _compiled = false;
- nAngle = (nAngle + 360)%360;
- var m:Matrix4 = Matrix4Math.axisRotation ( _vSide.x, _vSide.y, _vSide.z, nAngle );
- Matrix4Math.vectorMult3x3( m, _vUp);
- Matrix4Math.vectorMult3x3( m, _vOut);
- }
-
- /**
- * Pan - Rotation around the local Y axis of the camera frame
- * Range from 0 to 360 where 0=North, 90=East, 180=South and 270=West.
- * @param nAngle Number The angle of rotation in degree.
- * @return Void
- */
- public function pan ( nAngle:Number ):void
- {
- _compiled = false;
- nAngle = (nAngle + 360)%360;
- //_nYaw = NumberUtil.constrain( (_nYaw + nAngle)%360, 0, 360 );
- var m:Matrix4 = Matrix4Math.axisRotation ( _vUp.x, _vUp.y, _vUp.z, nAngle );
- Matrix4Math.vectorMult3x3( m, _vSide);
- Matrix4Math.vectorMult3x3( m, _vOut);
- }
-
- /**
- * roll - Rotation around the local Z axis of the camera frame
- * Range from -180 to +180 where 0 means the plane is aligned with the horizon,
- * +180 = Full roll right and –180 = Full roll left. In both cases, when the roll is 180 and –180,
- * the plane is flipped on its back.
- * @param nAngle Number The angle of rotation in degree.
- * @return
- */
- public function roll ( nAngle:Number ):void
- {
- //_nRoll = NumberUtil.constrain( _nRoll + nAngle, -180, 180 );
- //if( _nRoll == -180 || _nRoll == 180 ) return;
- _compiled = false;
- nAngle = (nAngle + 360)%360;
- var m:Matrix4 = Matrix4Math.axisRotation ( _vOut.x, _vOut.y, _vOut.z, nAngle );
- Matrix4Math.vectorMult3x3( m, _vSide);
- Matrix4Math.vectorMult3x3( m, _vUp);
- }
-
-
- /**
- * Set the position of the camera. Basically apply a translation.
- * @param x x position of the camera
- * @param y y position of the camera
- * @param z z position of the camera
- */
- public function setPosition( x : Number, y : Number, z : Number ):void
- {
- _compiled = false;
- // we must consider the screen y-axis inversion
- _p.x = x;
- _p.y = -y;
- _p.z = z;
- }
-
- /**
- * Get the offset of the screen of the camera along axis.
- * @return a Number corresponding to the offset
- */
- public function getXOffset():Number
- {
- return _rDim.width / 2;
- }
-
- /**
- * Get the offset of the screen of the camera along Y axis.
- * @return a Number corresponding to the offset
- */
- public function getYOffset():Number
- {
- return _rDim.height / 2;
- }
-
- /**
- * Get the position of the camera.
- * @return the position of the camera as a Vector
- */
- public function getPosition():Vector
- {
- return new Vector(_p.x, - _p.y, _p.z );
- }
-
- /**
- * Set the screen of the camera.
- * @param {code s} the Screen instance
- */
- public function setScreen( s:IScreen ):void
- {
- _screen = s;
- _rDim = _screen.getSize();
- _screen.setCamera ( this );
- }
-
- /**
- * Set the nodal distance of the camera.
- * @param n the nodal distance
- */
- public function setFocal( n:Number ):void
- {
- _compiled = false;
- _nFocal = n;
- __loadSimpleProjection();
- }
-
- /**
- * Return the nodal distance of the camera.
- * @return a Number as the nodal distance
- */
- public function getFocal():Number
- {
- return _nFocal;
- }
-
- /**
- * Set an interpolator to the camera. Currently the camera handles only a Path interpolator or a Position interpolation.
- * @param i Interpolator3D The interpolator you want to apply to the camera. It must be a Path interpolator or a Position interpolation
- * @return Boolean True is the operation goes well, false otherwise
- */
- public function setInterpolator( i:Interpolator3D ):Boolean
- {
- if( i.getType() == TransformType.PATH_INTERPOLATION || i.getType() == TransformType.TRANSLATION_INTERPOLATION )
- {
- removeInterpolator();
- _oInt = i;
- _oInt.addEventListener( InterpolationEvent.onProgressEVENT, __onInterpolation );
- return true;
- }
- else
- {
- return false;
- }
- }
-
- /**
- * REmove the interpolator is exist. remove also the listeners.
- * @param Void
- * @return Boolean True is the operation goes well, false otherwise.
- */
- public function removeInterpolator():Boolean
- {
- if( null == _oInt )
- {
- return false;
- }
- else
- {
- _oInt.removeEventListener( InterpolationEvent.onProgressEVENT, __onInterpolation );
- _oInt = null;
- return true;
- }
- }
-
- /**
- * This method helps you to know if something has changed in the camera, and if you need to compile it again to take care about the modifications.
- * @param Void
- * @return Boolean True value is returned if something has changed, false otherwise.
- */
- public function isModified():Boolean
- {
- return (_compiled == false);
- }
-
- /**
- * Compile the camera transformations by multiplicating the matrix together.
- * Be carefull to call isModified method before to save computations.
- */
- public function compile():void
- {
- if(! _compiled )
- {
- // we set up the rotation matrix from euler's angle
- _mt = __updateRotationMatrix();
- // we add the translation effect
- _mt = Matrix4Math.multiply ( _mt, Matrix4Math.translation( -_p.x, - _p.y, -_p.z ) );
- matrix = Matrix4Math.multiply ( _mp, _mt );
- _compiled = true;
- }
- }
-
- /**
- * Return the projection matrix.
- *
- * @return Matrix4
- */
- public function getProjectionMatrix():Matrix4
- {
- return _mp;
- }
-
- /**
- * Return the transformation matrix.
- *
- * @return Matrix4
- */
- public function getTransformMatrix():Matrix4
- {
- return _mt;
- }
- //
- // PRIVATE
- //
- /**
- * __loadProjection (private)
- *
- * <p>Compute the projection matrix</p>
- *
- */
- private function __loadSimpleProjection():void
- {
- _mp.n12 = _mp.n13 = _mp.n14 = _mp.n21 = _mp.n23 = _mp.n24 = _mp.n31 = _mp.n32 = _mp.n34 = _mp.n41 = _mp.n42 = _mp.n44 = 0;
- _mp.n11 = _mp.n22 = _mp.n33 = _nFocal;
- _mp.n43 = 1;
- }
-
- private function __updateRotationMatrix ():Matrix4
- {
- return new Matrix4( _vSide.x, _vSide.y, _vSide.z, 0,
- _vUp.x, _vUp.y, _vUp.z, 0,
- _vOut.x, _vOut.y, _vOut.z, 0,
- 0, 0, 0, 1 );
- }
-
- /**
- * On an interpolation event, we compute the correct position, and update the camera.
- * @param e
- */
- private function __onInterpolation( e:InterpolationEvent ):void
- {
- var m:Matrix4 = (e.target as Interpolator3D).getMatrix();
- _p.x = m.n14;
- _p.y = m.n24;
- _p.z = m.n34;
- _compiled = false;
- }
-
- public function toString():String
- {
- return "Camera3D: " + name;
- }
- }//end Camera3D
- }