mirror of
https://github.com/MapMakersAndProgrammers/Alternativa3D.git
synced 2025-10-26 18:09:14 -07:00
1749 lines
57 KiB
ActionScript
1749 lines
57 KiB
ActionScript
/**
|
|
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
* If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.
|
|
* You may add additional accurate notices of copyright ownership.
|
|
*
|
|
* It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/
|
|
* */
|
|
|
|
package alternativa.engine3d.core {
|
|
|
|
import alternativa.engine3d.alternativa3d;
|
|
import alternativa.engine3d.collisions.EllipsoidCollider;
|
|
import alternativa.engine3d.core.events.Event3D;
|
|
import alternativa.engine3d.core.events.MouseEvent3D;
|
|
import alternativa.engine3d.materials.compiler.Linker;
|
|
import alternativa.engine3d.materials.compiler.Procedure;
|
|
import alternativa.engine3d.objects.Surface;
|
|
|
|
import flash.events.Event;
|
|
import flash.events.EventPhase;
|
|
import flash.events.IEventDispatcher;
|
|
import flash.geom.Matrix3D;
|
|
import flash.geom.Vector3D;
|
|
import flash.utils.Dictionary;
|
|
import flash.utils.getQualifiedClassName;
|
|
|
|
use namespace alternativa3d;
|
|
|
|
/**
|
|
* Dispatches when an <code>Object3D</code> is added as a child to another <code>Object3D</code>.
|
|
* Following methods generate this event: <code>Object3D.addChild()</code>, <code>Object3D.addChildAt()</code>.
|
|
*
|
|
* @see #addChild()
|
|
* @see #addChildAt()
|
|
*
|
|
* @eventType alternativa.engine3d.core.events.Event3D.ADDED
|
|
*/
|
|
[Event(name="added",type="alternativa.engine3d.core.events.Event3D")]
|
|
|
|
/**
|
|
* Dispatched when a <code>Object3D</code> is about to be removed from the children list.
|
|
* Following methods generate this event: <code>Object3D.removeChild()</code> and <code>Object3D.removeChildAt()</code>.
|
|
*
|
|
* @see #removeChild()
|
|
* @see #removeChildAt()
|
|
* @eventType alternativa.engine3d.core.events.Event3D.REMOVED
|
|
*/
|
|
[Event(name="removed",type="alternativa.engine3d.core.events.Event3D")]
|
|
|
|
/**
|
|
* Dispatched when a user presses and releases the main button
|
|
* of the user's pointing device over the same <code>Object3D</code>.
|
|
* Any other evens can occur between pressing and releasing the button.
|
|
*
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.CLICK
|
|
*/
|
|
[Event (name="click", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when a user presses and releases the main button of
|
|
* a pointing device twice in rapid succession over the same <code>Object3D</code>.
|
|
*
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.DOUBLE_CLICK
|
|
*/
|
|
[Event (name="doubleClick", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when a user presses and releases the middle button
|
|
* of the user's pointing device over the same <code>Object3D</code>.
|
|
* Any other evens can occur between pressing and releasing the button.
|
|
*
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.MIDDLE_CLICK
|
|
*/
|
|
[Event (name="middleClick", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when a user presses the middle pointing device button over an <code>Object3D</code> instance.
|
|
* Any other evens can occur between pressing and releasing the button.
|
|
*
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.MIDDLE_MOUSE_DOWN
|
|
*/
|
|
[Event (name="middleMouseDown", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when a user releases the pointing device button over an <code>Object3D</code> instance.
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.MIDDLE_MOUSE_UP
|
|
*/
|
|
[Event (name="middleMouseUp", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when a user presses the pointing device button over an <code>Object3D</code> instance.
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.MOUSE_DOWN
|
|
*/
|
|
[Event (name="mouseDown", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when a user moves the pointing device while it is over an <code>Object3D</code>.
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.MOUSE_MOVE
|
|
*/
|
|
[Event (name="mouseMove", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when a user releases the pointing device button over an <code>Object3D</code> instance.
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.MOUSE_UP
|
|
*/
|
|
[Event (name="mouseUp", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when the user moves a pointing device away from an <code>Object3D</code> instance.
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.MOUSE_OUT
|
|
*/
|
|
[Event (name="mouseOut", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when the user moves a pointing device over an <code>Object3D</code> instance.
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.MOUSE_OVER
|
|
*/
|
|
[Event (name="mouseOver", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when a mouse wheel is spun over an <code>Object3D</code> instance.
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.MOUSE_WHEEL
|
|
*/
|
|
[Event (name="mouseWheel", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when a user presses and releases the right button
|
|
* of the user's pointing device over the same <code>Object3D</code>.
|
|
* Any other evens can occur between pressing and releasing the button.
|
|
*
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.CLICK
|
|
*/
|
|
[Event (name="rightClick", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when a user presses the right pointing device button over an <code>Object3D</code> instance.
|
|
* Any other evens can occur between pressing and releasing the button.
|
|
*
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.CLICK
|
|
*/
|
|
[Event (name="rightMouseDown", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when a user releases the pointing device button over an <code>Object3D</code> instance.
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.MOUSE_UP
|
|
*/
|
|
[Event (name="rightMouseUp", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when the user moves a pointing device over an <code>Object3D</code> instance.
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.ROLL_OVER
|
|
*/
|
|
[Event (name="rollOver", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* Dispatched when the user moves a pointing device away from an <code>Object3D</code> instance.
|
|
* @eventType alternativa.engine3d.events.MouseEvent3D.ROLL_OUT
|
|
*/
|
|
[Event (name="rollOut", type="alternativa.engine3d.core.events.MouseEvent3D")]
|
|
|
|
/**
|
|
* <code>Object3D</code> class ia a base class for all 3D objects. Any <code>Object3D</code> has a property
|
|
* of transformation that defines its position in space, the property <code>boundBox</code>,
|
|
* which describes the rectangular parallelepiped into which fits this 3D object.
|
|
* The last feature of this class is the one place in the 3d hierarchy like
|
|
* <code>DisplayObject</code> has its own place in Display List.
|
|
* Unlike the previous version Alternativa3D, an instance of this class can contain many children,
|
|
* so it can act as a container. This also applies to all the inheritors <code>Object3D</code> .
|
|
*
|
|
* @see alternativa.engine3d.objects.Mesh
|
|
* @see alternativa.engine3d.core.BoundBox
|
|
*/
|
|
public class Object3D implements IEventDispatcher {
|
|
|
|
// Mouse moving
|
|
private static const MOUSE_MOVE_BIT:uint = 1;
|
|
private static const MOUSE_OVER_BIT:uint = 2;
|
|
private static const MOUSE_OUT_BIT:uint = 4;
|
|
private static const ROLL_OVER_BIT:uint = 0x8;
|
|
private static const ROLL_OUT_BIT:uint = 0x10;
|
|
private static const USE_HAND_CURSOR_BIT:uint = 0x20;
|
|
|
|
// Mouse pressing
|
|
private static const MOUSE_DOWN_BIT:uint = 0x40;
|
|
private static const MOUSE_UP_BIT:uint = 0x80;
|
|
private static const CLICK_BIT:uint = 0x100;
|
|
private static const DOUBLE_CLICK_BIT:uint = 0x200;
|
|
|
|
// Mouse wheel
|
|
private static const MOUSE_WHEEL_BIT:uint = 0x400;
|
|
|
|
// Mouse middle button
|
|
private static const MIDDLE_CLICK_BIT:uint = 0x800;
|
|
private static const MIDDLE_MOUSE_DOWN_BIT:uint = 0x1000;
|
|
private static const MIDDLE_MOUSE_UP_BIT:uint = 0x2000;
|
|
|
|
// Mouse right button
|
|
private static const RIGHT_CLICK_BIT:uint = 0x4000;
|
|
private static const RIGHT_MOUSE_DOWN_BIT:uint = 0x8000;
|
|
private static const RIGHT_MOUSE_UP_BIT:uint = 0x10000;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d static const MOUSE_HANDLING_MOVING:uint = MOUSE_MOVE_BIT | MOUSE_OVER_BIT | MOUSE_OUT_BIT | ROLL_OVER_BIT | ROLL_OUT_BIT | USE_HAND_CURSOR_BIT;
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d static const MOUSE_HANDLING_PRESSING:uint = MOUSE_DOWN_BIT | MOUSE_UP_BIT | CLICK_BIT | DOUBLE_CLICK_BIT;
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d static const MOUSE_HANDLING_WHEEL:uint = MOUSE_WHEEL_BIT;
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d static const MOUSE_HANDLING_MIDDLE_BUTTON:uint = MIDDLE_CLICK_BIT | MIDDLE_MOUSE_DOWN_BIT | MIDDLE_MOUSE_UP_BIT;
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d static const MOUSE_HANDLING_RIGHT_BUTTON:uint = RIGHT_CLICK_BIT | RIGHT_MOUSE_DOWN_BIT | RIGHT_MOUSE_UP_BIT;
|
|
|
|
/**
|
|
* Custom data available to store within <code>Object3D</code> by user.
|
|
*/
|
|
public var userData:Object;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
public var useShadow:Boolean = true;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var _excludedLights:Vector.<Light3D> = new Vector.<Light3D>();
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d static const trm:Transform3D = new Transform3D();
|
|
|
|
/**
|
|
* Name of the object.
|
|
*/
|
|
public var name:String;
|
|
|
|
/**
|
|
* Whether or not the display object is visible.
|
|
*/
|
|
public var visible:Boolean = true;
|
|
|
|
/**
|
|
* Specifies whether this object receives mouse, or other user input, messages.
|
|
* The default value is <code>true</code>.
|
|
*
|
|
* The behaviour is consistent with behaviour of <code>flash.display.InteractiveObject</code>.
|
|
*
|
|
*/
|
|
public var mouseEnabled:Boolean = true;
|
|
|
|
/**
|
|
* Determines whether or not the children of the object are mouse, or user input device, enabled.
|
|
* In case of <code>false</code>, the value of <code>target</code> property of the event
|
|
* will be the self <code>Object3D</code> wether mouse pointed on it or on its child.
|
|
* The default value is <code>true</code>.
|
|
*/
|
|
public var mouseChildren:Boolean = true;
|
|
|
|
/**
|
|
* Specifies whether the object receives <code>doubleClick</code> events.
|
|
* The default value is false, which means that by default an Object3D
|
|
* instance does not receive <code>doubleClick</code> events.
|
|
*
|
|
* The <code>doubleClickEnabled</code> property of current <code>stage</code> also should be <code>true</code>.
|
|
*/
|
|
public var doubleClickEnabled:Boolean = false;
|
|
|
|
/**
|
|
* Bounds of the object described as rectangular parallelepiped.
|
|
*/
|
|
public var boundBox:BoundBox;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var _x:Number = 0;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var _y:Number = 0;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var _z:Number = 0;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var _rotationX:Number = 0;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var _rotationY:Number = 0;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var _rotationZ:Number = 0;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var _scaleX:Number = 1;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var _scaleY:Number = 1;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var _scaleZ:Number = 1;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var _parent:Object3D;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var childrenList:Object3D;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var next:Object3D;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var transform:Transform3D = new Transform3D();
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var inverseTransform:Transform3D = new Transform3D();
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var transformChanged:Boolean = true;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var cameraToLocalTransform:Transform3D = new Transform3D();
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var localToCameraTransform:Transform3D = new Transform3D();
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var localToGlobalTransform:Transform3D = new Transform3D();
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var globalToLocalTransform:Transform3D = new Transform3D();
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var localToLightTransform:Transform3D = new Transform3D();
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var lightToLocalTransform:Transform3D = new Transform3D();
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var culling:int;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var listening:Boolean;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var mouseHandlingType:uint = 0;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var distance:Number;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var bubbleListeners:Object;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var captureListeners:Object;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var transformProcedure:Procedure;
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d var deltaTransformProcedure:Procedure;
|
|
|
|
/**
|
|
* X coordinate.
|
|
*/
|
|
public function get x():Number {
|
|
return _x;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
public function set x(value:Number):void {
|
|
if (_x != value) {
|
|
_x = value;
|
|
transformChanged = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Y coordinate.
|
|
*/
|
|
public function get y():Number {
|
|
return _y;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
public function set y(value:Number):void {
|
|
if (_y != value) {
|
|
_y = value;
|
|
transformChanged = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Z coordinate.
|
|
*/
|
|
public function get z():Number {
|
|
return _z;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
public function set z(value:Number):void {
|
|
if (_z != value) {
|
|
_z = value;
|
|
transformChanged = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The angle of rotation of <code>Object3D</code> around the X-axis expressed in radians.
|
|
*/
|
|
public function get rotationX():Number {
|
|
return _rotationX;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
public function set rotationX(value:Number):void {
|
|
if (_rotationX != value) {
|
|
_rotationX = value;
|
|
transformChanged = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The angle of rotation of <code>Object3D</code> around the Y-axis expressed in radians.
|
|
*/
|
|
public function get rotationY():Number {
|
|
return _rotationY;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
public function set rotationY(value:Number):void {
|
|
if (_rotationY != value) {
|
|
_rotationY = value;
|
|
transformChanged = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The angle of rotation of <code>Object3D</code> around the Z-axis expressed in radians.
|
|
*/
|
|
public function get rotationZ():Number {
|
|
return _rotationZ;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
public function set rotationZ(value:Number):void {
|
|
if (_rotationZ != value) {
|
|
_rotationZ = value;
|
|
transformChanged = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The scale of the <code>Object3D</code> along the X-axis.
|
|
*/
|
|
public function get scaleX():Number {
|
|
return _scaleX;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
public function set scaleX(value:Number):void {
|
|
if (_scaleX != value) {
|
|
_scaleX = value;
|
|
transformChanged = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The scale of the <code>Object3D</code> along the Y-axis.
|
|
*/
|
|
public function get scaleY():Number {
|
|
return _scaleY;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
public function set scaleY(value:Number):void {
|
|
if (_scaleY != value) {
|
|
_scaleY = value;
|
|
transformChanged = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The scale of the <code>Object3D</code> along the Z-axis.
|
|
*/
|
|
public function get scaleZ():Number {
|
|
return _scaleZ;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
public function set scaleZ(value:Number):void {
|
|
if (_scaleZ != value) {
|
|
_scaleZ = value;
|
|
transformChanged = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The <code>matrix</code> property represents a transformation matrix that determines the position
|
|
* and orientation of an <code>Object3D</code>.
|
|
*/
|
|
public function get matrix():Matrix3D {
|
|
if (transformChanged) composeTransforms();
|
|
return new Matrix3D(Vector.<Number>([transform.a, transform.e, transform.i, 0, transform.b, transform.f, transform.j, 0, transform.c, transform.g, transform.k, 0, transform.d, transform.h, transform.l, 1]));
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
public function set matrix(value:Matrix3D):void {
|
|
var v:Vector.<Vector3D> = value.decompose();
|
|
var t:Vector3D = v[0];
|
|
var r:Vector3D = v[1];
|
|
var s:Vector3D = v[2];
|
|
_x = t.x;
|
|
_y = t.y;
|
|
_z = t.z;
|
|
_rotationX = r.x;
|
|
_rotationY = r.y;
|
|
_rotationZ = r.z;
|
|
_scaleX = s.x;
|
|
_scaleY = s.y;
|
|
_scaleZ = s.z;
|
|
transformChanged = true;
|
|
}
|
|
|
|
/**
|
|
* A Boolean value that indicates whether the pointing hand (hand cursor)
|
|
* appears when the pointer rolls over a <code>Object3D</code>.
|
|
*/
|
|
public function get useHandCursor():Boolean {
|
|
return (mouseHandlingType & USE_HAND_CURSOR_BIT) != 0;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
public function set useHandCursor(value:Boolean):void {
|
|
if (value) {
|
|
mouseHandlingType |= USE_HAND_CURSOR_BIT;
|
|
} else {
|
|
mouseHandlingType &= ~USE_HAND_CURSOR_BIT;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Searches for the intersection of an <code>Object3D</code> and given ray, defined by <code>origin</code> and <code>direction</code>.
|
|
*
|
|
* @param origin Origin of the ray.
|
|
* @param direction Direction of the ray.
|
|
* @return The result of searching given as <code>RayIntersectionData</code>. <code>null</code> will returned in case of intersection was not found.
|
|
* @see RayIntersectionData
|
|
* @see alternativa.engine3d.objects.Sprite3D
|
|
* @see alternativa.engine3d.core.Camera3D#calculateRay()
|
|
*/
|
|
public function intersectRay(origin:Vector3D, direction:Vector3D):RayIntersectionData {
|
|
return intersectRayChildren(origin, direction);
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function intersectRayChildren(origin:Vector3D, direction:Vector3D):RayIntersectionData {
|
|
var minTime:Number = 1e22;
|
|
var minData:RayIntersectionData = null;
|
|
var childOrigin:Vector3D;
|
|
var childDirection:Vector3D;
|
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
|
if (child.transformChanged) child.composeTransforms();
|
|
if (childOrigin == null) {
|
|
childOrigin = new Vector3D();
|
|
childDirection = new Vector3D();
|
|
}
|
|
childOrigin.x = child.inverseTransform.a*origin.x + child.inverseTransform.b*origin.y + child.inverseTransform.c*origin.z + child.inverseTransform.d;
|
|
childOrigin.y = child.inverseTransform.e*origin.x + child.inverseTransform.f*origin.y + child.inverseTransform.g*origin.z + child.inverseTransform.h;
|
|
childOrigin.z = child.inverseTransform.i*origin.x + child.inverseTransform.j*origin.y + child.inverseTransform.k*origin.z + child.inverseTransform.l;
|
|
childDirection.x = child.inverseTransform.a*direction.x + child.inverseTransform.b*direction.y + child.inverseTransform.c*direction.z;
|
|
childDirection.y = child.inverseTransform.e*direction.x + child.inverseTransform.f*direction.y + child.inverseTransform.g*direction.z;
|
|
childDirection.z = child.inverseTransform.i*direction.x + child.inverseTransform.j*direction.y + child.inverseTransform.k*direction.z;
|
|
var data:RayIntersectionData = child.intersectRay(childOrigin, childDirection);
|
|
if (data != null && data.time < minTime) {
|
|
minData = data;
|
|
minTime = data.time;
|
|
}
|
|
}
|
|
return minData;
|
|
}
|
|
|
|
/**
|
|
* A <code>Matrix3D</code> object representing the combined transformation matrices of the <code>Object3D</code>
|
|
* and all of its parent objects, back to the root level.
|
|
*/
|
|
public function get concatenatedMatrix():Matrix3D {
|
|
if (transformChanged) composeTransforms();
|
|
trm.copy(transform);
|
|
var root:Object3D = this;
|
|
while (root.parent != null) {
|
|
root = root.parent;
|
|
if (root.transformChanged) root.composeTransforms();
|
|
trm.append(root.transform);
|
|
}
|
|
return new Matrix3D(Vector.<Number>([trm.a, trm.e, trm.i, 0, trm.b, trm.f, trm.j, 0, trm.c, trm.g, trm.k, 0, trm.d, trm.h, trm.l, 1]));
|
|
}
|
|
|
|
/**
|
|
* Converts the <code>Vector3D</code> object from the <code>Object3D</code>'s own (local) coordinates to the root <code>Object3D</code> (global) coordinates.
|
|
* @param point Point in local coordinates of <code>Object3D</code>.
|
|
* @return Point in coordinates of root <code>Object3D</code>.
|
|
*/
|
|
public function localToGlobal(point:Vector3D):Vector3D {
|
|
if (transformChanged) composeTransforms();
|
|
trm.copy(transform);
|
|
var root:Object3D = this;
|
|
while (root.parent != null) {
|
|
root = root.parent;
|
|
if (root.transformChanged) root.composeTransforms();
|
|
trm.append(root.transform);
|
|
}
|
|
var res:Vector3D = new Vector3D();
|
|
res.x = trm.a*point.x + trm.b*point.y + trm.c*point.z + trm.d;
|
|
res.y = trm.e*point.x + trm.f*point.y + trm.g*point.z + trm.h;
|
|
res.z = trm.i*point.x + trm.j*point.y + trm.k*point.z + trm.l;
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Converts the <code>Vector3D</code> object from the root <code>Object3D</code> (global) coordinates to the local <code>Object3D</code>'s own coordinates.
|
|
* @param point Point in coordinates of root <code>Object3D</code>.
|
|
* @return Point in local coordinates of <code>Object3D</code>.
|
|
*/
|
|
public function globalToLocal(point:Vector3D):Vector3D {
|
|
if (transformChanged) composeTransforms();
|
|
trm.copy(inverseTransform);
|
|
var root:Object3D = this;
|
|
while (root.parent != null) {
|
|
root = root.parent;
|
|
if (root.transformChanged) root.composeTransforms();
|
|
trm.prepend(root.inverseTransform);
|
|
}
|
|
var res:Vector3D = new Vector3D();
|
|
res.x = trm.a*point.x + trm.b*point.y + trm.c*point.z + trm.d;
|
|
res.y = trm.e*point.x + trm.f*point.y + trm.g*point.z + trm.h;
|
|
res.z = trm.i*point.x + trm.j*point.y + trm.k*point.z + trm.l;
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function get useLights():Boolean {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Calculates object's bounds in its own coordinates
|
|
*/
|
|
public function calculateBoundBox():void {
|
|
if (boundBox != null) {
|
|
boundBox.reset();
|
|
} else {
|
|
boundBox = new BoundBox();
|
|
}
|
|
// Fill values of th boundBox
|
|
updateBoundBox(boundBox, null);
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function updateBoundBox(boundBox:BoundBox, transform:Transform3D = null):void {
|
|
}
|
|
|
|
/**
|
|
* Registers an event listener object with an EventDispatcher object
|
|
* so that the listener receives notification of an event.
|
|
* @param type The type of event.
|
|
* @param listener The listener function that processes the event.
|
|
* @param useCapture Determines whether the listener works in the capture phase or the target and bubbling phases.
|
|
* @param priority The priority level of the event listener.
|
|
* @param useWeakReference Does not used.
|
|
*/
|
|
public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void {
|
|
if (listener == null) throw new TypeError("Parameter listener must be non-null.");
|
|
var listeners:Object;
|
|
if (useCapture) {
|
|
if (captureListeners == null) captureListeners = new Object();
|
|
listeners = captureListeners;
|
|
} else {
|
|
if (bubbleListeners == null) bubbleListeners = new Object();
|
|
listeners = bubbleListeners;
|
|
}
|
|
var vector:Vector.<Function> = listeners[type];
|
|
if (vector == null) {
|
|
// There are not listeners of this type
|
|
vector = new Vector.<Function>();
|
|
listeners[type] = vector;
|
|
|
|
// update mouseHandlingType bits
|
|
switch (type) {
|
|
case MouseEvent3D.MOUSE_MOVE:
|
|
mouseHandlingType |= MOUSE_MOVE_BIT;
|
|
break;
|
|
case MouseEvent3D.MOUSE_OVER:
|
|
mouseHandlingType |= MOUSE_OVER_BIT;
|
|
break;
|
|
case MouseEvent3D.MOUSE_OUT:
|
|
mouseHandlingType |= MOUSE_OUT_BIT;
|
|
break;
|
|
case MouseEvent3D.ROLL_OVER:
|
|
mouseHandlingType |= ROLL_OVER_BIT;
|
|
break;
|
|
case MouseEvent3D.ROLL_OUT:
|
|
mouseHandlingType |= ROLL_OUT_BIT;
|
|
break;
|
|
case MouseEvent3D.MOUSE_DOWN:
|
|
mouseHandlingType |= MOUSE_DOWN_BIT;
|
|
break;
|
|
case MouseEvent3D.MOUSE_UP:
|
|
mouseHandlingType |= MOUSE_UP_BIT;
|
|
break;
|
|
case MouseEvent3D.CLICK:
|
|
mouseHandlingType |= CLICK_BIT;
|
|
break;
|
|
case MouseEvent3D.DOUBLE_CLICK:
|
|
mouseHandlingType |= DOUBLE_CLICK_BIT;
|
|
break;
|
|
case MouseEvent3D.MOUSE_WHEEL:
|
|
mouseHandlingType |= MOUSE_WHEEL_BIT;
|
|
break;
|
|
case MouseEvent3D.MIDDLE_CLICK:
|
|
mouseHandlingType |= MIDDLE_CLICK_BIT;
|
|
break;
|
|
case MouseEvent3D.MIDDLE_MOUSE_DOWN:
|
|
mouseHandlingType |= MIDDLE_MOUSE_DOWN_BIT;
|
|
break;
|
|
case MouseEvent3D.MIDDLE_MOUSE_UP:
|
|
mouseHandlingType |= MIDDLE_MOUSE_UP_BIT;
|
|
break;
|
|
case MouseEvent3D.RIGHT_CLICK:
|
|
mouseHandlingType |= RIGHT_CLICK_BIT;
|
|
break;
|
|
case MouseEvent3D.RIGHT_MOUSE_DOWN:
|
|
mouseHandlingType |= RIGHT_MOUSE_DOWN_BIT;
|
|
break;
|
|
case MouseEvent3D.RIGHT_MOUSE_UP:
|
|
mouseHandlingType |= RIGHT_MOUSE_UP_BIT;
|
|
break;
|
|
}
|
|
}
|
|
if (vector.indexOf(listener) < 0) {
|
|
vector.push(listener);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes a listener from the EventDispatcher object.
|
|
* @param type The type of event.
|
|
* @param listener The listener object to remove.
|
|
* @param useCapture Specifies whether the listener was registered for the capture phase or the target and bubbling phases.
|
|
*/
|
|
public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void {
|
|
if (listener == null) throw new TypeError("Parameter listener must be non-null.");
|
|
var listeners:Object = useCapture ? captureListeners : bubbleListeners;
|
|
if (listeners != null) {
|
|
var vector:Vector.<Function> = listeners[type];
|
|
if (vector != null) {
|
|
var i:int = vector.indexOf(listener);
|
|
if (i >= 0) {
|
|
var length:int = vector.length;
|
|
for (var j:int = i + 1; j < length; j++,i++) {
|
|
vector[i] = vector[j];
|
|
}
|
|
if (length > 1) {
|
|
vector.length = length - 1;
|
|
} else {
|
|
// update mouseHandlingType bits
|
|
var noListeners:Boolean;
|
|
if (listeners == captureListeners) {
|
|
noListeners = (bubbleListeners == null || bubbleListeners[type] == null);
|
|
} else {
|
|
noListeners = (captureListeners == null || captureListeners[type] == null);
|
|
}
|
|
if (noListeners) {
|
|
switch (type) {
|
|
case MouseEvent3D.MOUSE_MOVE:
|
|
mouseHandlingType &= ~MOUSE_MOVE_BIT;
|
|
break;
|
|
case MouseEvent3D.MOUSE_OVER:
|
|
mouseHandlingType &= ~MOUSE_OVER_BIT;
|
|
break;
|
|
case MouseEvent3D.MOUSE_OUT:
|
|
mouseHandlingType &= ~MOUSE_OUT_BIT;
|
|
break;
|
|
case MouseEvent3D.ROLL_OVER:
|
|
mouseHandlingType &= ~ROLL_OVER_BIT;
|
|
break;
|
|
case MouseEvent3D.ROLL_OUT:
|
|
mouseHandlingType &= ~ROLL_OUT_BIT;
|
|
break;
|
|
case MouseEvent3D.MOUSE_DOWN:
|
|
mouseHandlingType &= ~MOUSE_DOWN_BIT;
|
|
break;
|
|
case MouseEvent3D.MOUSE_UP:
|
|
mouseHandlingType &= ~MOUSE_UP_BIT;
|
|
break;
|
|
case MouseEvent3D.CLICK:
|
|
mouseHandlingType &= ~CLICK_BIT;
|
|
break;
|
|
case MouseEvent3D.DOUBLE_CLICK:
|
|
mouseHandlingType &= ~DOUBLE_CLICK_BIT;
|
|
break;
|
|
case MouseEvent3D.MOUSE_WHEEL:
|
|
mouseHandlingType &= ~MOUSE_WHEEL_BIT;
|
|
break;
|
|
case MouseEvent3D.MIDDLE_CLICK:
|
|
mouseHandlingType &= ~MIDDLE_CLICK_BIT;
|
|
break;
|
|
case MouseEvent3D.MIDDLE_MOUSE_DOWN:
|
|
mouseHandlingType &= ~MIDDLE_MOUSE_DOWN_BIT;
|
|
break;
|
|
case MouseEvent3D.MIDDLE_MOUSE_UP:
|
|
mouseHandlingType &= ~MIDDLE_MOUSE_UP_BIT;
|
|
break;
|
|
case MouseEvent3D.RIGHT_CLICK:
|
|
mouseHandlingType &= ~RIGHT_CLICK_BIT;
|
|
break;
|
|
case MouseEvent3D.RIGHT_MOUSE_DOWN:
|
|
mouseHandlingType &= ~RIGHT_MOUSE_DOWN_BIT;
|
|
break;
|
|
case MouseEvent3D.RIGHT_MOUSE_UP:
|
|
mouseHandlingType &= ~RIGHT_MOUSE_UP_BIT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
delete listeners[type];
|
|
|
|
var key:*;
|
|
for (key in listeners) break;
|
|
if (!key) {
|
|
if (listeners == captureListeners) {
|
|
captureListeners = null;
|
|
} else {
|
|
bubbleListeners = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks whether the EventDispatcher object has any listeners registered for a specific type of event.
|
|
* @param type The type of event.
|
|
* @return A value of true if a listener of the specified type is registered; false otherwise.
|
|
*/
|
|
public function hasEventListener(type:String):Boolean {
|
|
return captureListeners != null && captureListeners[type] || bubbleListeners != null && bubbleListeners[type];
|
|
}
|
|
|
|
/**
|
|
* Checks whether an event listener is registered with this EventDispatcher object or any of its ancestors for the specified event type.
|
|
* @param type The type of event.
|
|
* @return A value of true if a listener of the specified type will be triggered; false otherwise.
|
|
*/
|
|
public function willTrigger(type:String):Boolean {
|
|
for (var object:Object3D = this; object != null; object = object._parent) {
|
|
if (object.captureListeners != null && object.captureListeners[type] || object.bubbleListeners != null && object.bubbleListeners[type]) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Dispatches an <code>event</code> into the event flow. In case of dispatched event extends <code>Event</code> class, properties <code>target</code> and <code>currentTarget</code>
|
|
* will not be set. They will be set if dispatched event extends <code>Event3D</code> oe subclasses.
|
|
* @param event The <code>Event</code> object that is dispatched into the event flow.
|
|
* @return A value of <code>true</code> if the event was successfully dispatched. Otherwise returns <code>false</code>.
|
|
*/
|
|
public function dispatchEvent(event:Event):Boolean {
|
|
if (event == null) throw new TypeError("Parameter event must be non-null.");
|
|
var event3D:Event3D = event as Event3D;
|
|
if (event3D != null) {
|
|
event3D._target = this;
|
|
}
|
|
var branch:Vector.<Object3D> = new Vector.<Object3D>();
|
|
var branchLength:int = 0;
|
|
var object:Object3D;
|
|
var i:int;
|
|
var j:int;
|
|
var length:int;
|
|
var vector:Vector.<Function>;
|
|
var functions:Vector.<Function>;
|
|
for (object = this; object != null; object = object._parent) {
|
|
branch[branchLength] = object;
|
|
branchLength++;
|
|
}
|
|
// capture phase
|
|
for (i = branchLength - 1; i > 0; i--) {
|
|
object = branch[i];
|
|
if (event3D != null) {
|
|
event3D._currentTarget = object;
|
|
event3D._eventPhase = EventPhase.CAPTURING_PHASE;
|
|
}
|
|
|
|
if (object.captureListeners != null) {
|
|
vector = object.captureListeners[event.type];
|
|
if (vector != null) {
|
|
length = vector.length;
|
|
functions = new Vector.<Function>();
|
|
for (j = 0; j < length; j++) functions[j] = vector[j];
|
|
for (j = 0; j < length; j++) (functions[j] as Function).call(null, event);
|
|
}
|
|
}
|
|
}
|
|
if (event3D != null) {
|
|
event3D._eventPhase = EventPhase.AT_TARGET;
|
|
}
|
|
// target + bubbles phases
|
|
for (i = 0; i < branchLength; i++) {
|
|
object = branch[i];
|
|
if (event3D != null) {
|
|
event3D._currentTarget = object;
|
|
if (i > 0) {
|
|
event3D._eventPhase = EventPhase.BUBBLING_PHASE;
|
|
}
|
|
}
|
|
if (object.bubbleListeners != null) {
|
|
vector = object.bubbleListeners[event.type];
|
|
if (vector != null) {
|
|
length = vector.length;
|
|
functions = new Vector.<Function>();
|
|
for (j = 0; j < length; j++) functions[j] = vector[j];
|
|
for (j = 0; j < length; j++) (functions[j] as Function).call(null, event);
|
|
}
|
|
}
|
|
if (!event.bubbles) break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* <code>Object3D</code>, to which this object was added as a child.
|
|
*/
|
|
public function get parent():Object3D {
|
|
return _parent;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function removeFromParent():void {
|
|
if (_parent != null) {
|
|
_parent.removeFromList(this);
|
|
_parent = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds given <code>Object3D</code> instance as a child to the end of this <code>Object3D</code>'s children list.
|
|
* If the given object was added to another <code>Object3D</code> already, it removes from it's old place.
|
|
* @param child The <code>Object3D</code> instance to add.
|
|
* @return The <code>Object3D</code> instance that you pass in the <code>child</code> parameter.
|
|
*/
|
|
public function addChild(child:Object3D):Object3D {
|
|
// Error checking
|
|
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
|
if (child == this) throw new ArgumentError("An object cannot be added as a child of itself.");
|
|
for (var container:Object3D = _parent; container != null; container = container._parent) {
|
|
if (container == child) throw new ArgumentError("An object cannot be added as a child to one of it's children (or children's children, etc.).");
|
|
}
|
|
// Adding
|
|
if (child._parent != this) {
|
|
// Removing from old place
|
|
if (child._parent != null) child._parent.removeChild(child);
|
|
// Adding
|
|
addToList(child);
|
|
child._parent = this;
|
|
// Dispatching the event
|
|
if (child.willTrigger(Event3D.ADDED)) child.dispatchEvent(new Event3D(Event3D.ADDED, true));
|
|
} else {
|
|
child = removeFromList(child);
|
|
if (child == null) throw new ArgumentError("Cannot add child.");
|
|
// Adding
|
|
addToList(child);
|
|
}
|
|
return child;
|
|
}
|
|
|
|
/**
|
|
* Removes the specified child <code>Object3D</code> instance from the child list of the
|
|
* this <code>Object3D</code> instance. The <code>parent</code> property of the removed child is set to <code>null</code>.
|
|
*
|
|
* @param child The <code>Object3D</code> instance to remove.
|
|
* @return The <code>Object3D</code> instance that you pass in the <code>child</code> parameter.
|
|
*/
|
|
public function removeChild(child:Object3D):Object3D {
|
|
// Error checking
|
|
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
|
if (child._parent != this) throw new ArgumentError("The supplied Object3D must be a child of the caller.");
|
|
child = removeFromList(child);
|
|
if (child == null) throw new ArgumentError("Cannot remove child.");
|
|
// Dispatching the event
|
|
if (child.willTrigger(Event3D.REMOVED)) child.dispatchEvent(new Event3D(Event3D.REMOVED, true));
|
|
child._parent = null;
|
|
return child;
|
|
}
|
|
|
|
/**
|
|
* Adds a child <code>Object3D</code> instance to this <code>Object3D</code> instance. The child is added at the index position specified.
|
|
* @param child The <code>Object3D</code> instance to add as a child of this <code>Object3D</code> instance.
|
|
* @param index The index position to which the child is added.
|
|
* @return The <code>Object3D</code> instance that you pass in the child parameter.
|
|
*/
|
|
public function addChildAt(child:Object3D, index:int):Object3D {
|
|
// Error checking
|
|
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
|
if (child == this) throw new ArgumentError("An object cannot be added as a child of itself.");
|
|
if (index < 0) throw new RangeError("The supplied index is out of bounds.");
|
|
for (var container:Object3D = _parent; container != null; container = container._parent) {
|
|
if (container == child) throw new ArgumentError("An object cannot be added as a child to one of it's children (or children's children, etc.).");
|
|
}
|
|
// Search for element by index
|
|
var current:Object3D = childrenList;
|
|
for (var i:int = 0; i < index; i++) {
|
|
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
|
current = current.next;
|
|
}
|
|
// Adding
|
|
if (child._parent != this) {
|
|
// Removing from old parent
|
|
if (child._parent != null) child._parent.removeChild(child);
|
|
// Adding
|
|
addToList(child, current);
|
|
child._parent = this;
|
|
// Dispatching the event
|
|
if (child.willTrigger(Event3D.ADDED)) child.dispatchEvent(new Event3D(Event3D.ADDED, true));
|
|
} else {
|
|
child = removeFromList(child);
|
|
if (child == null) throw new ArgumentError("Cannot add child.");
|
|
// Adding
|
|
addToList(child, current);
|
|
}
|
|
return child;
|
|
}
|
|
|
|
/**
|
|
* Removes a child <code>Object3D</code> from the specified index position in the child list of
|
|
* the <code>Object3D</code>. The parent property of the removed child is set to <code>null</code>.
|
|
*
|
|
* @param index The child index of the <code>Object3D</code> to remove.
|
|
* @return The <code>Object3D</code> instance that was removed.
|
|
*/
|
|
public function removeChildAt(index:int):Object3D {
|
|
// Error checking
|
|
if (index < 0) throw new RangeError("The supplied index is out of bounds.");
|
|
// Search for element by index
|
|
var child:Object3D = childrenList;
|
|
for (var i:int = 0; i < index; i++) {
|
|
if (child == null) throw new RangeError("The supplied index is out of bounds.");
|
|
child = child.next;
|
|
}
|
|
if (child == null) throw new RangeError("The supplied index is out of bounds.");
|
|
// Removing
|
|
removeFromList(child);
|
|
// Dispatching the event
|
|
if (child.willTrigger(Event3D.REMOVED)) child.dispatchEvent(new Event3D(Event3D.REMOVED, true));
|
|
child._parent = null;
|
|
return child;
|
|
}
|
|
|
|
/**
|
|
* Removes child objects in given range of indexes.
|
|
* @param beginIndex Index, starts from which objects should be removed.
|
|
* @param endIndex Index, till which objects should be removed.
|
|
*/
|
|
public function removeChildren(beginIndex:int = 0, endIndex:int = 2147483647):void {
|
|
// Error checking
|
|
if (beginIndex < 0) throw new RangeError("The supplied index is out of bounds.");
|
|
if (endIndex < beginIndex) throw new RangeError("The supplied index is out of bounds.");
|
|
var i:int = 0;
|
|
var prev:Object3D = null;
|
|
var begin:Object3D = childrenList;
|
|
while (i < beginIndex) {
|
|
if (begin == null) {
|
|
if (endIndex < 2147483647) {
|
|
throw new RangeError("The supplied index is out of bounds.");
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
prev = begin;
|
|
begin = begin.next;
|
|
i++;
|
|
}
|
|
if (begin == null) {
|
|
if (endIndex < 2147483647) {
|
|
throw new RangeError("The supplied index is out of bounds.");
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
var end:Object3D = null;
|
|
if (endIndex < 2147483647) {
|
|
end = begin;
|
|
while (i <= endIndex) {
|
|
if (end == null) throw new RangeError("The supplied index is out of bounds.");
|
|
end = end.next;
|
|
i++;
|
|
}
|
|
}
|
|
if (prev != null) {
|
|
prev.next = end;
|
|
} else {
|
|
childrenList = end;
|
|
}
|
|
// Removing
|
|
while (begin != end) {
|
|
var next:Object3D = begin.next;
|
|
begin.next = null;
|
|
if (begin.willTrigger(Event3D.REMOVED)) begin.dispatchEvent(new Event3D(Event3D.REMOVED, true));
|
|
begin._parent = null;
|
|
begin = next;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the child <code>Object3D</code> instance that exists at the specified index.
|
|
* @param index Position of wished child.
|
|
* @return Child object at given position.
|
|
*/
|
|
public function getChildAt(index:int):Object3D {
|
|
// Error checking
|
|
if (index < 0) throw new RangeError("The supplied index is out of bounds.");
|
|
// Search for element by index
|
|
var current:Object3D = childrenList;
|
|
for (var i:int = 0; i < index; i++) {
|
|
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
|
current = current.next;
|
|
}
|
|
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
|
return current;
|
|
}
|
|
|
|
/**
|
|
* Returns index of given child <code>Object3D</code> instance.
|
|
* @param child Child <code>Object3D</code> instance.
|
|
* @return Index of given child <code>Object3D</code> instance.
|
|
*/
|
|
public function getChildIndex(child:Object3D):int {
|
|
// Error checking
|
|
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
|
if (child._parent != this) throw new ArgumentError("The supplied Object3D must be a child of the caller.");
|
|
// Search for index
|
|
var index:int = 0;
|
|
for (var current:Object3D = childrenList; current != null; current = current.next) {
|
|
if (current == child) return index;
|
|
index++;
|
|
}
|
|
throw new ArgumentError("Cannot get child index.");
|
|
}
|
|
|
|
/**
|
|
* Sets index for child <code>Object3D</code> instance.
|
|
* @param child Child <code>Object3D</code> instance.
|
|
* @param index Index should be set.
|
|
*/
|
|
public function setChildIndex(child:Object3D, index:int):void {
|
|
// Error checking
|
|
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
|
if (child._parent != this) throw new ArgumentError("The supplied Object3D must be a child of the caller.");
|
|
if (index < 0) throw new RangeError("The supplied index is out of bounds.");
|
|
// Search for element by index
|
|
var current:Object3D = childrenList;
|
|
for (var i:int = 0; i < index; i++) {
|
|
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
|
current = current.next;
|
|
}
|
|
// Removing
|
|
child = removeFromList(child);
|
|
if (child == null) throw new ArgumentError("Cannot set child index.");
|
|
// Adding
|
|
addToList(child, current);
|
|
}
|
|
|
|
/**
|
|
* Swaps index positions of two specified child objects.
|
|
* @param child1 The first object to swap.
|
|
* @param child2 The second object to swap.
|
|
*/
|
|
public function swapChildren(child1:Object3D, child2:Object3D):void {
|
|
// Error checking
|
|
if (child1 == null || child2 == null) throw new TypeError("Parameter child must be non-null.");
|
|
if (child1._parent != this || child2._parent != this) throw new ArgumentError("The supplied Object3D must be a child of the caller.");
|
|
// Swapping
|
|
if (child1 != child2) {
|
|
if (child1.next == child2) {
|
|
child2 = removeFromList(child2);
|
|
if (child2 == null) throw new ArgumentError("Cannot swap children.");
|
|
addToList(child2, child1);
|
|
} else if (child2.next == child1) {
|
|
child1 = removeFromList(child1);
|
|
if (child1 == null) throw new ArgumentError("Cannot swap children.");
|
|
addToList(child1, child2);
|
|
} else {
|
|
var count:int = 0;
|
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
|
if (child == child1) count++;
|
|
if (child == child2) count++;
|
|
if (count == 2) break;
|
|
}
|
|
if (count < 2) throw new ArgumentError("Cannot swap children.");
|
|
var nxt:Object3D = child1.next;
|
|
removeFromList(child1);
|
|
addToList(child1, child2);
|
|
removeFromList(child2);
|
|
addToList(child2, nxt);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Swaps index positions of two child objects by its index.
|
|
* @param index1 Index of the first object to swap.
|
|
* @param index2 Index of the second object to swap.
|
|
*/
|
|
public function swapChildrenAt(index1:int, index2:int):void {
|
|
// Error checking
|
|
if (index1 < 0 || index2 < 0) throw new RangeError("The supplied index is out of bounds.");
|
|
// Swapping
|
|
if (index1 != index2) {
|
|
// Search for element by index
|
|
var i:int;
|
|
var child1:Object3D = childrenList;
|
|
for (i = 0; i < index1; i++) {
|
|
if (child1 == null) throw new RangeError("The supplied index is out of bounds.");
|
|
child1 = child1.next;
|
|
}
|
|
if (child1 == null) throw new RangeError("The supplied index is out of bounds.");
|
|
var child2:Object3D = childrenList;
|
|
for (i = 0; i < index2; i++) {
|
|
if (child2 == null) throw new RangeError("The supplied index is out of bounds.");
|
|
child2 = child2.next;
|
|
}
|
|
if (child2 == null) throw new RangeError("The supplied index is out of bounds.");
|
|
if (child1 != child2) {
|
|
if (child1.next == child2) {
|
|
removeFromList(child2);
|
|
addToList(child2, child1);
|
|
} else if (child2.next == child1) {
|
|
removeFromList(child1);
|
|
addToList(child1, child2);
|
|
} else {
|
|
var nxt:Object3D = child1.next;
|
|
removeFromList(child1);
|
|
addToList(child1, child2);
|
|
removeFromList(child2);
|
|
addToList(child2, nxt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns child <code>Object3D</code> instance with given <code>name</code>.
|
|
* In case of there are several objects with same name, the first of them will returned.
|
|
* If there are no objects with given name, <code>null</code> will returned.
|
|
*
|
|
* @param name The name of child object.
|
|
* @return Child Object3D with given name.
|
|
*/
|
|
public function getChildByName(name:String):Object3D {
|
|
// Error checking
|
|
if (name == null) throw new TypeError("Parameter name must be non-null.");
|
|
// Search for object
|
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
|
if (child.name == name) return child;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Check if given object is child of this <code>Object3D</code>.
|
|
* @param child Child <code>Object3D</code> instance.
|
|
* @return <code>true</code> if given instance is this <code>Object3D</code> or one of its children or <code>false</code> otherwise.
|
|
*/
|
|
public function contains(child:Object3D):Boolean {
|
|
// Error checking
|
|
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
|
// Search for object
|
|
if (child == this) return true;
|
|
for (var object:Object3D = childrenList; object != null; object = object.next) {
|
|
if (object.contains(child)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns the number of children of this object.
|
|
*/
|
|
public function get numChildren():int {
|
|
var num:int = 0;
|
|
for (var current:Object3D = childrenList; current != null; current = current.next) num++;
|
|
return num;
|
|
}
|
|
|
|
private function addToList(child:Object3D, item:Object3D = null):void {
|
|
child.next = item;
|
|
if (item == childrenList) {
|
|
childrenList = child;
|
|
} else {
|
|
for (var current:Object3D = childrenList; current != null; current = current.next) {
|
|
if (current.next == item) {
|
|
current.next = child;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function removeFromList(child:Object3D):Object3D {
|
|
var prev:Object3D;
|
|
for (var current:Object3D = childrenList; current != null; current = current.next) {
|
|
if (current == child) {
|
|
if (prev != null) {
|
|
prev.next = current.next;
|
|
} else {
|
|
childrenList = current.next;
|
|
}
|
|
current.next = null;
|
|
return child;
|
|
}
|
|
prev = current;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Gather the resources of this <code>Object3D</code>. This resources should be uploaded in the <code>Context3D</code> in order to <code>Object3D</code> can be rendered.
|
|
*
|
|
* @param hierarchy If <code>true</code>, the resources of all children will be gathered too.
|
|
* @param resourceType If defined, only resources of this type will be gathered.
|
|
* @return Vector consists of gathered resources
|
|
* @see flash.display.Stage3D
|
|
*/
|
|
public function getResources(hierarchy:Boolean = false, resourceType:Class = null):Vector.<Resource> {
|
|
var res:Vector.<Resource> = new Vector.<Resource>();
|
|
var dict:Dictionary = new Dictionary();
|
|
var count:int = 0;
|
|
fillResources(dict, hierarchy, resourceType);
|
|
for (var key:* in dict) {
|
|
res[count++] = key as Resource;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function fillResources(resources:Dictionary, hierarchy:Boolean = false, resourceType:Class = null):void {
|
|
if (hierarchy) {
|
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
|
child.fillResources(resources, hierarchy, resourceType);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function composeTransforms():void {
|
|
// Matrix
|
|
var cosX:Number = Math.cos(_rotationX);
|
|
var sinX:Number = Math.sin(_rotationX);
|
|
var cosY:Number = Math.cos(_rotationY);
|
|
var sinY:Number = Math.sin(_rotationY);
|
|
var cosZ:Number = Math.cos(_rotationZ);
|
|
var sinZ:Number = Math.sin(_rotationZ);
|
|
var cosZsinY:Number = cosZ*sinY;
|
|
var sinZsinY:Number = sinZ*sinY;
|
|
var cosYscaleX:Number = cosY*_scaleX;
|
|
var sinXscaleY:Number = sinX*_scaleY;
|
|
var cosXscaleY:Number = cosX*_scaleY;
|
|
var cosXscaleZ:Number = cosX*_scaleZ;
|
|
var sinXscaleZ:Number = sinX*_scaleZ;
|
|
transform.a = cosZ*cosYscaleX;
|
|
transform.b = cosZsinY*sinXscaleY - sinZ*cosXscaleY;
|
|
transform.c = cosZsinY*cosXscaleZ + sinZ*sinXscaleZ;
|
|
transform.d = _x;
|
|
transform.e = sinZ*cosYscaleX;
|
|
transform.f = sinZsinY*sinXscaleY + cosZ*cosXscaleY;
|
|
transform.g = sinZsinY*cosXscaleZ - cosZ*sinXscaleZ;
|
|
transform.h = _y;
|
|
transform.i = -sinY*_scaleX;
|
|
transform.j = cosY*sinXscaleY;
|
|
transform.k = cosY*cosXscaleZ;
|
|
transform.l = _z;
|
|
// Inverse matrix
|
|
var sinXsinY:Number = sinX*sinY;
|
|
cosYscaleX = cosY/_scaleX;
|
|
cosXscaleY = cosX/_scaleY;
|
|
sinXscaleZ = -sinX/_scaleZ;
|
|
cosXscaleZ = cosX/_scaleZ;
|
|
inverseTransform.a = cosZ*cosYscaleX;
|
|
inverseTransform.b = sinZ*cosYscaleX;
|
|
inverseTransform.c = -sinY/_scaleX;
|
|
inverseTransform.d = -inverseTransform.a*_x - inverseTransform.b*_y - inverseTransform.c*_z;
|
|
inverseTransform.e = sinXsinY*cosZ/_scaleY - sinZ*cosXscaleY;
|
|
inverseTransform.f = cosZ*cosXscaleY + sinXsinY*sinZ/_scaleY;
|
|
inverseTransform.g = sinX*cosY/_scaleY;
|
|
inverseTransform.h = -inverseTransform.e*_x - inverseTransform.f*_y - inverseTransform.g*_z;
|
|
inverseTransform.i = cosZ*sinY*cosXscaleZ - sinZ*sinXscaleZ;
|
|
inverseTransform.j = cosZ*sinXscaleZ + sinY*sinZ*cosXscaleZ;
|
|
inverseTransform.k = cosY*cosXscaleZ;
|
|
inverseTransform.l = -inverseTransform.i*_x - inverseTransform.j*_y - inverseTransform.k*_z;
|
|
transformChanged = false;
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function calculateVisibility(camera:Camera3D):void {
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function calculateChildrenVisibility(camera:Camera3D):void {
|
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
|
// Checking visibility flag
|
|
if (child.visible) {
|
|
// Compose matrix and inverse matrix
|
|
if (child.transformChanged) child.composeTransforms();
|
|
// Calculating matrix for converting from camera coordinates to local coordinates
|
|
child.cameraToLocalTransform.combine(child.inverseTransform, cameraToLocalTransform);
|
|
// Calculating matrix for converting from local coordinates to camera coordinates
|
|
child.localToCameraTransform.combine(localToCameraTransform, child.transform);
|
|
|
|
camera.globalMouseHandlingType |= child.mouseHandlingType;
|
|
// Culling checking
|
|
if (child.boundBox != null) {
|
|
camera.calculateFrustum(child.cameraToLocalTransform);
|
|
child.culling = child.boundBox.checkFrustumCulling(camera.frustum, 63);
|
|
} else {
|
|
child.culling = 63;
|
|
}
|
|
// Calculating visibility of the self content
|
|
if (child.culling >= 0) child.calculateVisibility(camera);
|
|
// Calculating visibility of children
|
|
if (child.childrenList != null) child.calculateChildrenVisibility(camera);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function collectDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function collectChildrenDraws(camera:Camera3D, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean):void {
|
|
var i:int;
|
|
var light:Light3D;
|
|
|
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
|
// Checking visibility flag
|
|
if (child.visible) {
|
|
// Check getting in frustum and occluding
|
|
if (child.culling >= 0 && (child.boundBox == null || camera.occludersLength == 0 || !child.boundBox.checkOcclusion(camera.occluders, camera.occludersLength, child.localToCameraTransform))) {
|
|
// Check if the ray crossing the bounding box
|
|
if (child.boundBox != null) {
|
|
camera.calculateRays(child.cameraToLocalTransform);
|
|
child.listening = child.boundBox.checkRays(camera.origins, camera.directions, camera.raysLength);
|
|
} else {
|
|
child.listening = true;
|
|
}
|
|
// Check if object needs in lightning
|
|
var excludedLightLength:int = child._excludedLights.length;
|
|
if (lightsLength > 0 && child.useLights) {
|
|
// Pass the lights to children and calculate appropriate transformations
|
|
var childLightsLength:int = 0;
|
|
var j:int;
|
|
if (child.boundBox != null) {
|
|
for (i = 0; i < lightsLength; i++) {
|
|
light = lights[i];
|
|
// Checking object for existing in excludedLights
|
|
j = 0;
|
|
while (j<excludedLightLength && child._excludedLights[j]!=light) j++;
|
|
if (j<excludedLightLength) continue;
|
|
|
|
light.lightToObjectTransform.combine(child.cameraToLocalTransform, light.localToCameraTransform);
|
|
// Detect influence
|
|
if (light.boundBox == null || light.checkBound(child)) {
|
|
camera.childLights[childLightsLength] = light;
|
|
childLightsLength++;
|
|
}
|
|
}
|
|
} else {
|
|
// Calculate transformation from light space to object space
|
|
for (i = 0; i < lightsLength; i++) {
|
|
light = lights[i];
|
|
// Проверка источника света на отсутствие в excludedLights
|
|
j = 0;
|
|
while (j<excludedLightLength && child._excludedLights[j]!=light) j++;
|
|
if (j<excludedLightLength) continue;
|
|
light.lightToObjectTransform.combine(child.cameraToLocalTransform, light.localToCameraTransform);
|
|
camera.childLights[childLightsLength] = light;
|
|
childLightsLength++;
|
|
}
|
|
}
|
|
child.collectDraws(camera, camera.childLights, childLightsLength, useShadow&&child.useShadow);
|
|
} else {
|
|
child.collectDraws(camera, null, 0, useShadow&&child.useShadow);
|
|
}
|
|
// Debug the boundbox
|
|
if (camera.debug && child.boundBox != null && (camera.checkInDebug(child) & Debug.BOUNDS)) Debug.drawBoundBox(camera, child.boundBox, child.localToCameraTransform);
|
|
}
|
|
// Gather the draws for children
|
|
if (child.childrenList != null) child.collectChildrenDraws(camera, lights, lightsLength, useShadow && child.useShadow);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function collectGeometry(collider:EllipsoidCollider, excludedObjects:Dictionary):void {
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function collectChildrenGeometry(collider:EllipsoidCollider, excludedObjects:Dictionary):void {
|
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
|
if (excludedObjects == null || !excludedObjects[child]) {
|
|
// Compose matrix and inverse matrix if it needed
|
|
if (child.transformChanged) child.composeTransforms();
|
|
// Calculating matrix for converting from collider coordinates to local coordinates
|
|
child.globalToLocalTransform.combine(child.inverseTransform, globalToLocalTransform);
|
|
// Check boundbox intersecting
|
|
var intersects:Boolean = true;
|
|
if (child.boundBox != null) {
|
|
collider.calculateSphere(child.globalToLocalTransform);
|
|
intersects = child.boundBox.checkSphere(collider.sphere);
|
|
}
|
|
// Adding the geometry of self content
|
|
if (intersects) {
|
|
// Calculating matrix for converting from local coordinates to callider coordinates
|
|
child.localToGlobalTransform.combine(localToGlobalTransform, child.transform);
|
|
child.collectGeometry(collider, excludedObjects);
|
|
}
|
|
// Check for children
|
|
if (child.childrenList != null) child.collectChildrenGeometry(collider, excludedObjects);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
alternativa3d function setTransformConstants(drawUnit:DrawUnit, surface:Surface, vertexShader:Linker, camera:Camera3D):void {
|
|
}
|
|
|
|
|
|
/**
|
|
* Disables lighting of the object by given <code>light</code>.
|
|
*
|
|
* @param light Light which should not affect to the object
|
|
* @param updateChildren If <code>true</code> all children of this object will be also shielded from the given light.
|
|
* @see #excludedLights()
|
|
* @see #clearExcludedLights()
|
|
*/
|
|
public function excludeLight(light:Light3D, updateChildren:Boolean = false):void{
|
|
if (_excludedLights.indexOf(light) < 0) {
|
|
_excludedLights.push(light);
|
|
}
|
|
if (updateChildren) {
|
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
|
child.excludeLight(light, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns excluded lights list of current object.
|
|
*/
|
|
public function get excludedLights():Vector.<Light3D> {
|
|
return _excludedLights.slice();
|
|
}
|
|
|
|
/**
|
|
* Resets list of lights excluded from lighting this object.
|
|
*/
|
|
public function clearExcludedLights(updateChildren:Boolean = false):void {
|
|
_excludedLights.length = 0;
|
|
if (updateChildren) {
|
|
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
|
child.clearExcludedLights(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a copy of object.
|
|
* @return A copy of this <code>Object3D</code>.
|
|
*/
|
|
public function clone():Object3D {
|
|
var res:Object3D = new Object3D();
|
|
res.clonePropertiesFrom(this);
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Copies basic properties of <code>Object3D</code>. This method calls from <code>clone()</code> method.
|
|
* @param source <code>Object3D</code>, properties of which will be copied.
|
|
*/
|
|
protected function clonePropertiesFrom(source:Object3D):void {
|
|
userData = source.userData;
|
|
|
|
name = source.name;
|
|
visible = source.visible;
|
|
mouseEnabled = source.mouseEnabled;
|
|
mouseChildren = source.mouseChildren;
|
|
doubleClickEnabled = source.doubleClickEnabled;
|
|
useHandCursor = source.useHandCursor;
|
|
boundBox = source.boundBox ? source.boundBox.clone() : null;
|
|
_x = source._x;
|
|
_y = source._y;
|
|
_z = source._z;
|
|
_rotationX = source._rotationX;
|
|
_rotationY = source._rotationY;
|
|
_rotationZ = source._rotationZ;
|
|
_scaleX = source._scaleX;
|
|
_scaleY = source._scaleY;
|
|
_scaleZ = source._scaleZ;
|
|
for (var child:Object3D = source.childrenList, lastChild:Object3D; child != null; child = child.next) {
|
|
var newChild:Object3D = child.clone();
|
|
if (childrenList != null) {
|
|
lastChild.next = newChild;
|
|
} else {
|
|
childrenList = newChild;
|
|
}
|
|
lastChild = newChild;
|
|
newChild._parent = this;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the string representation of the specified object.
|
|
* @return The string representation of the specified object.
|
|
*/
|
|
public function toString():String {
|
|
var className:String = getQualifiedClassName(this);
|
|
return "[" + className.substr(className.indexOf("::") + 2) + " " + name + "]";
|
|
}
|
|
|
|
}
|
|
}
|