diff --git a/src/alternativa/engine3d/core/Camera3D.as b/src/alternativa/engine3d/core/Camera3D.as index 98b3e96..69b29f7 100644 --- a/src/alternativa/engine3d/core/Camera3D.as +++ b/src/alternativa/engine3d/core/Camera3D.as @@ -136,6 +136,11 @@ public class Camera3D extends Object3D { */ alternativa3d var raysLength:int = 0; + /** + * @private + */ + alternativa3d var globalMouseHandlingType:uint; + /** * @private */ @@ -230,19 +235,16 @@ public class Camera3D extends Object3D { } var excludedLightLength:int = root.excludedLights.length; - // Calculating the rays of mouse events - view.calculateRays(this); - for (i = origins.length; i < view.raysLength; i++) { - origins[i] = new Vector3D(); - directions[i] = new Vector3D(); - } - raysLength = view.raysLength; // Check if object of hierarchy is visible if (root.visible) { + globalMouseHandlingType = 0; + // Calculating the matrix to transform from the camera space to local space root.cameraToLocalTransform.combine(root.inverseTransform, localToGlobalTransform); // Calculating the matrix to transform from local space to the camera space root.localToCameraTransform.combine(globalToLocalTransform, root.transform); + + if (root.mouseEnabled) globalMouseHandlingType |= root.mouseHandlingType; // Checking the culling if (root.boundBox != null) { calculateFrustum(root.cameraToLocalTransform); @@ -308,7 +310,6 @@ public class Camera3D extends Object3D { // Shadows preparing if (light.shadow != null) { - // TODO: Need check by occluders light.shadow.process(this); } lights[j] = light; @@ -318,14 +319,25 @@ public class Camera3D extends Object3D { } lightsLength = j; lights.length = j; + + // Calculating the rays of mouse events + view.calculateRays(this, (globalMouseHandlingType & Object3D.MOUSE_HANDLING_MOVING) != 0, (globalMouseHandlingType & Object3D.MOUSE_HANDLING_PRESSING) != 0, (globalMouseHandlingType & Object3D.MOUSE_HANDLING_WHEEL) != 0); + for (i = origins.length; i < view.raysLength; i++) { + origins[i] = new Vector3D(); + directions[i] = new Vector3D(); + } + raysLength = view.raysLength; + + trace(raysLength, globalMouseHandlingType); + // Check getting in frustum and occluding if (root.culling >= 0 && (root.boundBox == null || occludersLength == 0 || !root.boundBox.checkOcclusion(occluders, occludersLength, root.localToCameraTransform))) { // Check if the ray crossing the bounding box - if (root.boundBox != null) { + if (globalMouseHandlingType > 0 && root.boundBox != null) { calculateRays(root.cameraToLocalTransform); root.listening = root.boundBox.checkRays(origins, directions, raysLength); } else { - root.listening = true; + root.listening = globalMouseHandlingType > 0; } // Check if object needs in lightning if (lightsLength > 0 && root.useLights) { @@ -370,11 +382,12 @@ public class Camera3D extends Object3D { } // Gather the draws for children root.collectChildrenDraws(this, lights, lightsLength, root.useShadow); + + // Mouse events prosessing + view.processMouseEvents(context3D, this); + // Render + renderer.render(context3D); } - // Mouse events prosessing - view.processMouseEvents(context3D, this); - // Render - renderer.render(context3D); // Output if (view._canvas == null) { context3D.present(); @@ -600,6 +613,7 @@ public class Camera3D extends Object3D { /** * @private + * Transform rays in object space. */ alternativa3d function calculateRays(transform:Transform3D):void { for (var i:int = 0; i < raysLength; i++) { diff --git a/src/alternativa/engine3d/core/Object3D.as b/src/alternativa/engine3d/core/Object3D.as index 460e642..42720c1 100644 --- a/src/alternativa/engine3d/core/Object3D.as +++ b/src/alternativa/engine3d/core/Object3D.as @@ -11,6 +11,7 @@ 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; @@ -125,6 +126,19 @@ package alternativa.engine3d.core { */ public class Object3D implements IEventDispatcher { + /** + * @private + */ + alternativa3d static const MOUSE_HANDLING_MOVING:uint = 1; + /** + * @private + */ + alternativa3d static const MOUSE_HANDLING_PRESSING:uint = 2; + /** + * @private + */ + alternativa3d static const MOUSE_HANDLING_WHEEL:uint = 4; + /** * Custom data available to store within Object3D by user. */ @@ -307,6 +321,11 @@ package alternativa.engine3d.core { */ alternativa3d var listening:Boolean; + /** + * @private + */ + alternativa3d var mouseHandlingType:uint = 0; + /** * @private */ @@ -662,8 +681,19 @@ package alternativa.engine3d.core { } var vector:Vector. = listeners[type]; if (vector == null) { + // There are not listeners of this type vector = new Vector.(); listeners[type] = vector; + + if (type == MouseEvent3D.MOUSE_MOVE || type == MouseEvent3D.MOUSE_OVER || type == MouseEvent3D.MOUSE_OUT || type == MouseEvent3D.ROLL_OVER || type == MouseEvent3D.ROLL_OUT) { + mouseHandlingType |= MOUSE_HANDLING_MOVING; + } + if (type == MouseEvent3D.MOUSE_DOWN || type == MouseEvent3D.MOUSE_UP || type == MouseEvent3D.CLICK || type == MouseEvent3D.DOUBLE_CLICK) { + mouseHandlingType |= MOUSE_HANDLING_PRESSING; + } + if (type == MouseEvent3D.MOUSE_WHEEL) { + mouseHandlingType |= MOUSE_HANDLING_WHEEL; + } } if (vector.indexOf(listener) < 0) { vector.push(listener); @@ -701,6 +731,15 @@ package alternativa.engine3d.core { bubbleListeners = null; } } + if (type == MouseEvent3D.MOUSE_MOVE || type == MouseEvent3D.MOUSE_OVER || type == MouseEvent3D.MOUSE_OUT || type == MouseEvent3D.ROLL_OVER || type == MouseEvent3D.ROLL_OUT) { + mouseHandlingType &= ~MOUSE_HANDLING_MOVING; + } + if (type == MouseEvent3D.MOUSE_DOWN || type == MouseEvent3D.MOUSE_UP || type == MouseEvent3D.CLICK || type == MouseEvent3D.DOUBLE_CLICK) { + mouseHandlingType &= ~MOUSE_HANDLING_PRESSING; + } + if (type == MouseEvent3D.MOUSE_WHEEL) { + mouseHandlingType &= ~MOUSE_HANDLING_WHEEL; + } } } } @@ -1295,6 +1334,8 @@ package alternativa.engine3d.core { child.cameraToLocalTransform.combine(child.inverseTransform, cameraToLocalTransform); // Calculating matrix for converting from local coordinates to camera coordinates child.localToCameraTransform.combine(localToCameraTransform, child.transform); + + if (child.mouseEnabled) camera.globalMouseHandlingType |= child.mouseHandlingType; // Culling checking if (child.boundBox != null) { camera.calculateFrustum(child.cameraToLocalTransform); diff --git a/src/alternativa/engine3d/core/View.as b/src/alternativa/engine3d/core/View.as index 96748ad..8df3705 100644 --- a/src/alternativa/engine3d/core/View.as +++ b/src/alternativa/engine3d/core/View.as @@ -370,11 +370,11 @@ package alternativa.engine3d.core { /** * @private */ - alternativa3d function calculateRays(camera:Camera3D):void { + alternativa3d function calculateRays(camera:Camera3D, processMoving:Boolean, processPressing:Boolean, processMouseWheel:Boolean):void { var i:int; var mouseEvent:MouseEvent; // Case of last coordinates fits in the view. - if (lastEvent != null) { + if (processMoving && lastEvent != null) { // Detecting mouse movement within the frame var mouseMoved:Boolean = false; for (i = 0; i < eventsLength; i++) { @@ -398,11 +398,32 @@ package alternativa.engine3d.core { } } + if (!processMoving) { + overedTarget = null; + overedTargetSurface = null; + } + if (!processPressing) { + pressedTarget = null; + clickedTarget = null; + } + // Creation of exclusive rays var mouseX:Number = 1e+22; var mouseY:Number = 1e+22; + var totalEvents:int = 0; for (i = 0; i < eventsLength; i++) { mouseEvent = events[i]; + // Filter events + if (!processMoving && (mouseEvent.type == MouseEvent.MOUSE_MOVE || mouseEvent.type == MouseEvent.MOUSE_OVER || mouseEvent.type == MouseEvent.MOUSE_OUT)) { + continue; + } + if (!processPressing && (mouseEvent.type == MouseEvent.MOUSE_DOWN || mouseEvent.type == MouseEvent.CLICK || mouseEvent.type == MouseEvent.DOUBLE_CLICK)) { + continue; + } + if (!processMouseWheel && mouseEvent.type == MouseEvent.MOUSE_WHEEL) { + continue; + } + if (mouseEvent.type != "mouseOut") { // Calculation of ray within the camera if (mouseEvent.localX != mouseX || mouseEvent.localY != mouseY) { @@ -450,11 +471,14 @@ package alternativa.engine3d.core { raysLength++; } // Considering event with the ray - indices[i] = raysLength - 1; + indices[totalEvents] = raysLength - 1; } else { - indices[i] = -1; + indices[totalEvents] = -1; } + events[totalEvents] = mouseEvent; + totalEvents++; } + eventsLength = totalEvents; } /** @@ -616,6 +640,7 @@ package alternativa.engine3d.core { } break; case "mouseOut": + // TODO: lastEvent not need change here. For example when MOUSE_OUT and MOUSE_MOVE exists in the one frame. lastEvent = null; target = null; targetSurface = null;