import {EventDispatcher} from "awayjs-core/lib/events/EventDispatcher";
import {ColorTransform} from "awayjs-core/lib/geom/ColorTransform";
import {Matrix} from "awayjs-core/lib/geom/Matrix";
import {Matrix3D} from "awayjs-core/lib/geom/Matrix3D";
import {Matrix3DUtils} from "awayjs-core/lib/geom/Matrix3DUtils";
import {Rectangle} from "awayjs-core/lib/geom/Rectangle";
import {Vector3D} from "awayjs-core/lib/geom/Vector3D";
import {PerspectiveProjection} from "awayjs-core/lib/projections/PerspectiveProjection";
import {DisplayObject} from "../display/DisplayObject";
import {TransformEvent} from "../events/TransformEvent";
/**
* The Transform class provides access to color adjustment properties and two-
* or three-dimensional transformation objects that can be applied to a
* display object. During the transformation, the color or the orientation and
* position of a display object is adjusted(offset) from the current values
* or coordinates to new values or coordinates. The Transform class also
* collects data about color and two-dimensional matrix transformations that
* are applied to a display object and all of its parent objects. You can
* access these combined transformations through the
* concatenatedColorTransform and concatenatedMatrix
* properties.
*
*
To apply color transformations: create a ColorTransform object, set the
* color adjustments using the object's methods and properties, and then
* assign the colorTransformation property of the
* transform property of the display object to the new
* ColorTransformation object.
To apply two-dimensional transformations: create a Matrix object, set
* the matrix's two-dimensional transformation, and then assign the
* transform.matrix property of the display object to the new
* Matrix object.
To apply three-dimensional transformations: start with a
* three-dimensional display object. A three-dimensional display object has a
* z property value other than zero. You do not need to create
* the Matrix3D object. For all three-dimensional objects, a Matrix3D object
* is created automatically when you assign a z value to a
* display object. You can access the display object's Matrix3D object through
* the display object's transform property. Using the methods of
* the Matrix3D class, you can add to or modify the existing transformation
* settings. Also, you can create a custom Matrix3D object, set the custom
* Matrix3D object's transformation elements, and then assign the new Matrix3D
* object to the display object using the transform.matrix
* property.
To modify a perspective projection of the stage or root object: use the
* transform.matrix property of the root display object to gain
* access to the PerspectiveProjection object. Or, apply different perspective
* projection properties to a display object by setting the perspective
* projection properties of the display object's parent. The child display
* object inherits the new properties. Specifically, create a
* PerspectiveProjection object and set its properties, then assign the
* PerspectiveProjection object to the perspectiveProjection
* property of the parent display object's transform property.
* The specified projection transformation then applies to all the display
* object's three-dimensional children.
Since both PerspectiveProjection and Matrix3D objects perform * perspective transformations, do not assign both to a display object at the * same time. Use the PerspectiveProjection object for focal length and * projection center changes. For more control over the perspective * transformation, create a perspective projection Matrix3D object.
*/ export class Transform extends EventDispatcher { private _concatenatedColorTransform:ColorTransform; private _concatenatedMatrix:Matrix; private _pixelBounds:Rectangle; private _colorTransform:ColorTransform; private _matrix3D:Matrix3D = new Matrix3D(); private _matrix3DDirty:boolean; private _rotation:Vector3D = new Vector3D(); private _skew:Vector3D = new Vector3D(); private _scale:Vector3D = new Vector3D(1, 1, 1); private _components:ArrayIf the matrix property is set to a value(not
* null), the matrix3D property is
* null. And if the matrix3D property is set to a
* value(not null), the matrix property is
* null.
If the matrix property is set to a value(not
* null), the matrix3D property is
* null. And if the matrix3D property is set to a
* value(not null), the matrix property is
* null.
Based on the field of view and aspect ratio(dimensions) of the stage, * a default PerspectiveProjection object is assigned to the root object.
*/ public perspectiveProjection:PerspectiveProjection; /** * A Rectangle object that defines the bounding rectangle of the display * object on the stage. */ public get pixelBounds():Rectangle { return this._pixelBounds; } /** * Defines the position of the 3d object, relative to the local coordinates of the parentObjectContainer3D.
*/
public get position():Vector3D
{
return this._matrix3D.position;
}
/**
*
*/
public get rightVector():Vector3D
{
return Matrix3DUtils.getRight(this.matrix3D);
}
/**
* Defines the rotation of the 3d object, relative to the local coordinates of the parent ObjectContainer3D.
*/
public get rotation():Vector3D
{
if (this._componentsDirty)
this._updateComponents();
return this._rotation;
}
/**
* Rotates the 3d object directly to a euler angle
*
* @param ax The angle in degrees of the rotation around the x axis.
* @param ay The angle in degrees of the rotation around the y axis.
* @param az The angle in degrees of the rotation around the z axis.
*/
public rotateTo(ax:number, ay:number, az:number):void
{
if (this._componentsDirty)
this._updateComponents();
this._rotation.x = ax;
this._rotation.y = ay;
this._rotation.z = az;
this.invalidateMatrix3D();
}
/**
* Defines the scale of the 3d object, relative to the local coordinates of the parent ObjectContainer3D.
*/
public get scale():Vector3D
{
if (this._componentsDirty)
this._updateComponents();
return this._scale;
}
public scaleTo(sx:number, sy:number, sz:number):void
{
if (this._componentsDirty)
this._updateComponents();
this._scale.x = sx;
this._scale.y = sy;
this._scale.z = sz;
this.invalidateMatrix3D();
}
/**
* Defines the scale of the 3d object, relative to the local coordinates of the parent ObjectContainer3D.
*/
public get skew():Vector3D
{
if (this._componentsDirty)
this._updateComponents();
return this._skew;
}
public skewTo(sx:number, sy:number, sz:number):void
{
if (this._componentsDirty)
this._updateComponents();
this._skew.x = sx;
this._skew.y = sy;
this._skew.z = sz;
this.invalidateMatrix3D();
}
/**
*
*/
public get upVector():Vector3D
{
return Matrix3DUtils.getUp(this.matrix3D);
}
constructor()
{
super();
// Cached vector of transformation components used when
// recomposing the transform matrix in updateTransform()
this._components = new ArraygetRelativeMatrix3D() method to move one
* three-dimensional display object relative to another three-dimensional
* display object.
*
* @param relativeTo The display object relative to which the transformation
* occurs. To get a Matrix3D object relative to the stage,
* set the parameter to the root or
* stage object. To get the world-relative
* matrix of the display object, set the parameter to a
* display object that has a perspective transformation
* applied to it.
* @return A Matrix3D object that can be used to transform the space from the
* relativeTo display object to the current display
* object space.
*/
public getRelativeMatrix3D(relativeTo:DisplayObject):Matrix3D
{
return new Matrix3D(); //TODO
}
/**
* Moves the 3d object forwards along it's local z axis
*
* @param distance The length of the movement
*/
public moveForward(distance:number):void
{
this.translateLocal(Vector3D.Z_AXIS, distance);
}
/**
* Moves the 3d object backwards along it's local z axis
*
* @param distance The length of the movement
*/
public moveBackward(distance:number):void
{
this.translateLocal(Vector3D.Z_AXIS, -distance);
}
/**
* Moves the 3d object backwards along it's local x axis
*
* @param distance The length of the movement
*/
public moveLeft(distance:number):void
{
this.translateLocal(Vector3D.X_AXIS, -distance);
}
/**
* Moves the 3d object forwards along it's local x axis
*
* @param distance The length of the movement
*/
public moveRight(distance:number):void
{
this.translateLocal(Vector3D.X_AXIS, distance);
}
/**
* Moves the 3d object forwards along it's local y axis
*
* @param distance The length of the movement
*/
public moveUp(distance:number):void
{
this.translateLocal(Vector3D.Y_AXIS, distance);
}
/**
* Moves the 3d object backwards along it's local y axis
*
* @param distance The length of the movement
*/
public moveDown(distance:number):void
{
this.translateLocal(Vector3D.Y_AXIS, -distance);
}
/**
* Moves the 3d object directly to a point in space
*
* @param dx The amount of movement along the local x axis.
* @param dy The amount of movement along the local y axis.
* @param dz The amount of movement along the local z axis.
*/
public moveTo(dx:number, dy:number, dz:number):void
{
this._matrix3D.rawData[12] = dx;
this._matrix3D.rawData[13] = dy;
this._matrix3D.rawData[14] = dz;
this.invalidatePosition();
}
/**
* Rotates the 3d object around it's local x-axis
*
* @param angle The amount of rotation in degrees
*/
public pitch(angle:number):void
{
this.rotate(Vector3D.X_AXIS, angle);
}
/**
* Rotates the 3d object around it's local z-axis
*
* @param angle The amount of rotation in degrees
*/
public roll(angle:number):void
{
this.rotate(Vector3D.Z_AXIS, angle);
}
/**
* Rotates the 3d object around it's local y-axis
*
* @param angle The amount of rotation in degrees
*/
public yaw(angle:number):void
{
this.rotate(Vector3D.Y_AXIS, angle);
}
/**
* Rotates the 3d object around an axis by a defined angle
*
* @param axis The vector defining the axis of rotation
* @param angle The amount of rotation in degrees
*/
public rotate(axis:Vector3D, angle:number):void
{
this.matrix3D.prependRotation(angle, axis);
this.invalidateComponents();
}
/**
* Moves the 3d object along a vector by a defined length
*
* @param axis The vector defining the axis of movement
* @param distance The length of the movement
*/
public translate(axis:Vector3D, distance:number):void
{
var x:number = axis.x, y:number = axis.y, z:number = axis.z;
var len:number = distance/Math.sqrt(x*x + y*y + z*z);
this.matrix3D.appendTranslation(x*len, y*len, z*len);
this.invalidatePosition();
}
/**
* Moves the 3d object along a vector by a defined length
*
* @param axis The vector defining the axis of movement
* @param distance The length of the movement
*/
public translateLocal(axis:Vector3D, distance:number):void
{
var x:number = axis.x, y:number = axis.y, z:number = axis.z;
var len:number = distance/Math.sqrt(x*x + y*y + z*z);
this.matrix3D.prependTranslation(x*len, y*len, z*len);
this.invalidatePosition();
}
public clearMatrix3D():void
{
this._matrix3D.identity();
this.invalidateComponents();
}
public clearColorTransform():void
{
if (!this._colorTransform)
return;
this._colorTransform.clear();
this.invalidateColorTransform();
}
/**
* Invalidates the 3D transformation matrix, causing it to be updated upon the next request
*
* @private
*/
public invalidateMatrix3D():void
{
this._matrix3DDirty = true;
this.dispatchEvent(new TransformEvent(TransformEvent.INVALIDATE_MATRIX3D, this));
}
public invalidateComponents():void
{
this.invalidatePosition();
this._componentsDirty = true;
}
/**
*
*/
public invalidatePosition():void
{
this._matrix3D.invalidatePosition();
this.dispatchEvent(new TransformEvent(TransformEvent.INVALIDATE_MATRIX3D, this));
}
public invalidateColorTransform():void
{
this.dispatchEvent(new TransformEvent(TransformEvent.INVALIDATE_COLOR_TRANSFORM, this));
}
/**
*
*/
private _updateMatrix3D():void
{
this._matrix3D.recompose(this._components);
this._matrix3DDirty = false;
}
private _updateComponents():void
{
var elements:Array