Merge "Use update object size in CalculateActorScreenPosition" into devel/master
authorHeeyong Song <heeyong.song@samsung.com>
Tue, 5 Apr 2022 11:19:43 +0000 (11:19 +0000)
committerGerrit Code Review <gerrit@review>
Tue, 5 Apr 2022 11:19:43 +0000 (11:19 +0000)
automated-tests/src/dali/utc-Dali-CameraActor.cpp
automated-tests/src/dali/utc-Dali-HitTestAlgorithm.cpp
dali/internal/event/actors/camera-actor-impl.cpp
dali/internal/event/events/hit-test-algorithm-impl.cpp
dali/internal/render/common/render-item.cpp
dali/internal/render/common/render-item.h
dali/internal/update/manager/render-instruction-processor.cpp
dali/internal/update/render-tasks/scene-graph-camera.cpp
dali/internal/update/render-tasks/scene-graph-camera.h

index 3352ee9..0ec0ccb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -186,7 +186,7 @@ int UtcDaliCameraActorNewDefaultPerspectiveProjection(void)
 
   // All the properties should still be the default values
   // Defaults taken from scene-graph-camera.cpp
-  DALI_TEST_EQUALS(4.0f / 3.0f, actor.GetProperty(CameraActor::Property::ASPECT_RATIO).Get<float>(), FLOAT_EPSILON, TEST_LOCATION);
+  DALI_TEST_EQUALS(800.0f / 480.0f, actor.GetProperty(CameraActor::Property::ASPECT_RATIO).Get<float>(), FLOAT_EPSILON, TEST_LOCATION);
   DALI_TEST_EQUALS(45.0f * (Math::PI / 180.0f), actor.GetProperty(CameraActor::Property::FIELD_OF_VIEW).Get<float>(), FLOAT_EPSILON, TEST_LOCATION);
   DALI_TEST_EQUALS(800.0f, actor.GetProperty(CameraActor::Property::NEAR_PLANE_DISTANCE).Get<float>(), FLOAT_EPSILON, TEST_LOCATION);
   DALI_TEST_EQUALS(3.0f * 800.0f, actor.GetProperty(CameraActor::Property::FAR_PLANE_DISTANCE).Get<float>(), FLOAT_EPSILON, TEST_LOCATION);
@@ -2118,3 +2118,118 @@ int UtcDaliCameraActorGetTypeNegative(void)
   }
   END_TEST;
 }
+
+int UtcDaliCameraActorNewDefaultOrthogonalProjection01(void)
+{
+  TestApplication application;
+  tet_infoline("Test that changing to orthogonal projection and then adding to scene calculates the right defaults");
+
+  CameraActor actor = CameraActor::New();
+  DALI_TEST_CHECK(actor);
+
+  actor.SetProjectionMode(Camera::ORTHOGRAPHIC_PROJECTION);
+  application.GetScene().Add(actor);
+
+  // Test application screen size is 480x800
+  // Check that the properties match to that screen size
+  float value;
+  actor.GetProperty(CameraActor::Property::ASPECT_RATIO).Get(value);
+  DALI_TEST_EQUALS(800.0f / 480.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+
+  actor.GetProperty(CameraActor::Property::NEAR_PLANE_DISTANCE).Get(value);
+  DALI_TEST_EQUALS(800.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+
+  actor.GetProperty(CameraActor::Property::FAR_PLANE_DISTANCE).Get(value);
+  DALI_TEST_EQUALS(4895.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+
+  actor.GetProperty(CameraActor::Property::LEFT_PLANE_DISTANCE).Get(value);
+  DALI_TEST_EQUALS(-240.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+  actor.GetProperty(CameraActor::Property::RIGHT_PLANE_DISTANCE).Get(value);
+  DALI_TEST_EQUALS(240.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+
+  actor.GetProperty(CameraActor::Property::TOP_PLANE_DISTANCE).Get(value);
+  DALI_TEST_EQUALS(400.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+  actor.GetProperty(CameraActor::Property::BOTTOM_PLANE_DISTANCE).Get(value);
+  DALI_TEST_EQUALS(-400.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(1600.0f, actor.GetProperty(Actor::Property::POSITION_Z).Get<float>(), TEST_LOCATION);
+
+  DALI_TEST_EQUALS(actor.GetProjectionMode(), Dali::Camera::ORTHOGRAPHIC_PROJECTION, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliCameraActorNewDefaultOrthogonalProjection02(void)
+{
+  TestApplication application;
+  tet_infoline("Test that changing to orthogonal projection and then adding to scene calculates the right defaults");
+
+  CameraActor actor = CameraActor::New();
+  DALI_TEST_CHECK(actor);
+
+  actor.SetOrthographicProjection(Vector2::ZERO);
+  DALI_TEST_EQUALS(actor.GetProjectionMode(), Dali::Camera::ORTHOGRAPHIC_PROJECTION, TEST_LOCATION);
+  application.GetScene().Add(actor);
+
+  // Test application screen size is 480x800
+  // Check that the properties match to that screen size
+  float value;
+  actor.GetProperty(CameraActor::Property::ASPECT_RATIO).Get(value);
+  DALI_TEST_EQUALS(800.0f / 480.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+
+  actor.GetProperty(CameraActor::Property::NEAR_PLANE_DISTANCE).Get(value);
+  DALI_TEST_EQUALS(800.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+
+  actor.GetProperty(CameraActor::Property::FAR_PLANE_DISTANCE).Get(value);
+  DALI_TEST_EQUALS(4895.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+
+  actor.GetProperty(CameraActor::Property::LEFT_PLANE_DISTANCE).Get(value);
+  DALI_TEST_EQUALS(-240.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+  actor.GetProperty(CameraActor::Property::RIGHT_PLANE_DISTANCE).Get(value);
+  DALI_TEST_EQUALS(240.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+
+  actor.GetProperty(CameraActor::Property::TOP_PLANE_DISTANCE).Get(value);
+  DALI_TEST_EQUALS(400.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+  actor.GetProperty(CameraActor::Property::BOTTOM_PLANE_DISTANCE).Get(value);
+  DALI_TEST_EQUALS(-400.0f, value, FLOAT_EPSILON, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(1600.0f, actor.GetProperty(Actor::Property::POSITION_Z).Get<float>(), TEST_LOCATION);
+
+  DALI_TEST_EQUALS(actor.GetProjectionMode(), Dali::Camera::ORTHOGRAPHIC_PROJECTION, TEST_LOCATION);
+  END_TEST;
+}
+
+// Add tests for culling:
+//   add large actor just outside canvas, & rotate it 45% - should still be rendered
+//   Rotate back to 0, should be culled.
+
+int UtcDaliCameraActorCulling01(void)
+{
+  TestApplication application;
+  auto&           gfx = application.GetGraphicsController();
+
+  tet_infoline("Create a renderable actor and position it slightly to the left of the scene");
+  tet_infoline("The actor should not be rendered");
+
+  Actor a = CreateRenderableActor(CreateTexture(TextureType::TEXTURE_2D, Pixel::Format::RGBA8888, 200, 200));
+
+  a[Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER_LEFT;
+  a[Actor::Property::ANCHOR_POINT]  = ParentOrigin::CENTER_RIGHT;
+  a[Actor::Property::POSITION]      = Vector3(-10.0f, 0.0f, 0.0f);
+
+  application.GetScene().Add(a);
+
+  application.SendNotification();
+  application.Render();
+
+  auto& cmdStack = gfx.mCommandBufferCallStack;
+  DALI_TEST_CHECK(!cmdStack.FindMethod("Draw") && !cmdStack.FindMethod("DrawIndexed"));
+
+  tet_infoline("Rotate the actor 45 degrees, the actor should now be rendered");
+  a[Actor::Property::ORIENTATION] = Quaternion(Dali::ANGLE_45, Vector3::ZAXIS);
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(cmdStack.FindMethod("Draw") || cmdStack.FindMethod("DrawIndexed"));
+
+  END_TEST;
+}
index 2229015..cea3e03 100644 (file)
@@ -324,6 +324,70 @@ int UtcDaliHitTestAlgorithmClippingActor(void)
   END_TEST;
 }
 
+int UtcDaliHitTestAlgorithmClippingActorStress(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm with many many stencil");
+
+  Stage stage     = Stage::GetCurrent();
+  Actor rootLayer = stage.GetRootLayer();
+  rootLayer.SetProperty(Actor::Property::NAME, "RootLayer");
+
+  // Create a layer
+  Layer layer = Layer::New();
+  layer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  layer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  layer.SetProperty(Actor::Property::NAME, "layer");
+  stage.Add(layer);
+
+  // Create a clipping actor and add it to the layer.
+  Actor clippingActor = CreateRenderableActor();
+  clippingActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  clippingActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  clippingActor.SetProperty(Actor::Property::SIZE, Vector2(220.0f, 220.0f));
+  clippingActor.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX);
+  clippingActor.SetProperty(Actor::Property::NAME, "clippingActor");
+  layer.Add(clippingActor);
+
+  // Create a renderable actor and add it to the clipping actor.
+  Actor     latestActor = clippingActor;
+  const int depthMax    = 100;
+  for(int i = 0; i < depthMax; i++)
+  {
+    char tmp[29];
+    sprintf(tmp, "depth%03d", i);
+
+    Actor childActor = CreateRenderableActor();
+    childActor.SetProperty(Actor::Property::SIZE, Vector2(220.0f, 220.0f));
+    childActor.SetProperty(Actor::Property::POSITION, Vector2(200.0f / depthMax, 200.0f / depthMax));
+    childActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+    childActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+    childActor.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX);
+    childActor.SetProperty(Actor::Property::NAME, tmp);
+
+    latestActor.Add(childActor);
+    latestActor = childActor;
+  }
+  // NOTE : latestActor's TOP_LEFT position become 200.f, 200.0f
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Hit within clippingActor and latestActor.
+  HitTestAlgorithm::Results results;
+  HitTest(stage, Vector2(201.0f, 201.0f), results, &DefaultIsActorTouchableFunction);
+  tet_printf("Hit: %s\n", (results.actor ? results.actor.GetProperty<std::string>(Actor::Property::NAME).c_str() : "NULL"));
+  DALI_TEST_CHECK(results.actor == latestActor);
+
+  // Hit within childActor but outside of clippingActor, should hit the root-layer instead.
+  HitTest(stage, Vector2(221.0f, 221.0f), results, &DefaultIsActorTouchableFunction);
+  tet_printf("Hit: %s\n", (results.actor ? results.actor.GetProperty<std::string>(Actor::Property::NAME).c_str() : "NULL"));
+  DALI_TEST_CHECK(results.actor == rootLayer);
+
+  END_TEST;
+}
+
 int UtcDaliHitTestAlgorithmOverlay(void)
 {
   TestApplication application;
index 97affa3..d69462a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -197,19 +197,26 @@ void CameraActor::OnInitialize()
 
 void CameraActor::OnSceneConnectionInternal()
 {
-  // If the canvas size has not been set, then use the size of the scene we've been added to to set up the perspective projection
+  // If the canvas size has not been set, then use the size of the scene to which we've been added
+  // in order to set up the current projection
   if((mCanvasSize.width < Math::MACHINE_EPSILON_1000) || (mCanvasSize.height < Math::MACHINE_EPSILON_1000))
   {
-    SetPerspectiveProjection(GetScene().GetSize());
+    if(mProjectionMode == Dali::Camera::ORTHOGRAPHIC_PROJECTION)
+    {
+      SetOrthographicProjection(GetScene().GetSize());
+    }
+    else //if(mProjectionMode == Dali::Camera::PERSPECTIVE_PROJECTION)
+    {
+      SetPerspectiveProjection(GetScene().GetSize());
+    }
   }
 }
 
 void CameraActor::SetReflectByPlane(const Vector4& plane)
 {
-  SceneGraph::Camera* cam = const_cast<SceneGraph::Camera*>(GetCamera());
-  if(cam)
+  if(mSceneObject)
   {
-    cam->SetReflectByPlane(plane);
+    SetReflectByPlaneMessage(GetEventThreadServices(), *mSceneObject, plane);
   }
 }
 
@@ -386,6 +393,7 @@ bool CameraActor::GetInvertYAxis() const
 
 void CameraActor::SetPerspectiveProjection(const Size& size)
 {
+  SetProjectionMode(Dali::Camera::PERSPECTIVE_PROJECTION);
   mCanvasSize = size;
 
   if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
@@ -425,34 +433,56 @@ void CameraActor::SetPerspectiveProjection(const Size& size)
   const float aspectRatio = width / height;
 
   // sceneObject is being used in a separate thread; queue a message to set
-  SetProjectionMode(Dali::Camera::PERSPECTIVE_PROJECTION);
   SetFieldOfView(fieldOfView);
   SetNearClippingPlane(nearClippingPlane);
   SetFarClippingPlane(farClippingPlane);
+  SetLeftClippingPlane(width * -0.5f);
+  SetRightClippingPlane(width * 0.5f);
+  SetTopClippingPlane(height * 0.5f);     // Top is +ve to keep consistency with orthographic values
+  SetBottomClippingPlane(height * -0.5f); // Bottom is -ve to keep consistency with orthographic values
   SetAspectRatio(aspectRatio);
   SetZ(cameraZ);
 }
 
 void CameraActor::SetOrthographicProjection(const Vector2& size)
 {
+  SetProjectionMode(Dali::Camera::ORTHOGRAPHIC_PROJECTION);
+  mCanvasSize = size;
+
+  if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
+  {
+    // If the size given is invalid, i.e. ZERO, then check if we've been added to a scene
+    if(OnScene())
+    {
+      // We've been added to a scene already, set the canvas size to the scene's size
+      mCanvasSize = GetScene().GetSize();
+    }
+    else
+    {
+      // We've not been added to a scene yet, so just return.
+      // We'll set the canvas size when we get added to a scene later
+      return;
+    }
+  }
+
   // Choose near, far and Z parameters to match the SetPerspectiveProjection above.
   float nearClippingPlane;
   float farClippingPlane;
   float cameraZ;
   CalculateClippingAndZ(size.width, size.height, nearClippingPlane, farClippingPlane, cameraZ);
-  SetOrthographicProjection(-size.x * 0.5f, size.x * 0.5f, size.y * 0.5f, -size.y * 0.5f, nearClippingPlane, farClippingPlane);
+  SetOrthographicProjection(-size.x * 0.5f, size.x * 0.5f, size.y * 0.5f, size.y * -0.5f, nearClippingPlane, farClippingPlane);
   SetZ(cameraZ);
 }
 
 void CameraActor::SetOrthographicProjection(float left, float right, float top, float bottom, float near, float far)
 {
+  SetProjectionMode(Dali::Camera::ORTHOGRAPHIC_PROJECTION);
   SetLeftClippingPlane(left);
   SetRightClippingPlane(right);
   SetTopClippingPlane(top);
   SetBottomClippingPlane(bottom);
   SetNearClippingPlane(near);
   SetFarClippingPlane(far);
-  SetProjectionMode(Dali::Camera::ORTHOGRAPHIC_PROJECTION);
 }
 
 bool CameraActor::BuildPickingRay(const Vector2&  screenCoordinates,
index 267c1ff..0ed24be 100644 (file)
@@ -167,8 +167,6 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
                             const bool&                                overlayed,
                             bool&                                      overlayHit,
                             bool                                       layerIs3d,
-                            uint32_t                                   clippingDepth,
-                            uint32_t                                   clippingBitPlaneMask,
                             const RayTest&                             rayTest,
                             const Integration::Point&                  point,
                             const uint32_t                             eventTime)
@@ -180,17 +178,11 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
     return hit;
   }
 
-  // For clipping, regardless of whether we have hit this actor or not,
-  // we increase the clipping depth if we have hit a clipping actor.
+  // For clipping, regardless of whether we have hit this actor or not.
   // This is used later to ensure all nested clipped children have hit
   // all clipping actors also for them to be counted as hit.
-  uint32_t newClippingDepth = clippingDepth;
-  bool     clippingActor    = actor.GetClippingMode() != ClippingMode::DISABLED;
-  bool     overlayedActor   = overlayed || actor.IsOverlay();
-  if(clippingActor)
-  {
-    ++newClippingDepth;
-  }
+  bool clippingActor  = actor.GetClippingMode() != ClippingMode::DISABLED;
+  bool overlayedActor = overlayed || actor.IsOverlay();
 
   // If we are a clipping actor or hittable...
   if(clippingActor || hitCheck.IsActorHittable(&actor))
@@ -215,13 +207,6 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
         // Check if cameraDepthDistance is between clipping plane
         if(cameraDepthDistance >= nearClippingPlane && cameraDepthDistance <= farClippingPlane)
         {
-          // If the hit has happened on a clipping actor, then add this clipping depth to the mask of hit clipping depths.
-          // This mask shows all the actors that have been hit at different clipping depths.
-          if(clippingActor)
-          {
-            clippingBitPlaneMask |= 1u << clippingDepth;
-          }
-
           if(overlayHit && !overlayedActor)
           {
             // If we have already hit an overlay and current actor is not an overlay ignore current actor.
@@ -233,34 +218,8 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
               overlayHit = true;
             }
 
-            // At this point we have hit an actor.
-            // Now perform checks for clipping.
-            // Assume we have hit the actor first as if it is not clipped this would be the case.
-            bool haveHitActor = true;
-
-            // Check if we are performing clipping. IE. if any actors so far have clipping enabled - not necessarily this one.
-            // We can do this by checking the clipping depth has a value 1 or above.
-            if(newClippingDepth >= 1u)
-            {
-              // Now for us to count this actor as hit, we must have also hit
-              // all CLIPPING actors up to this point in the hierarchy as well.
-              // This information is stored in the clippingBitPlaneMask we updated above.
-              // Here we calculate a comparison mask by setting all the bits up to the current depth value.
-              // EG. a depth of 4 (10000 binary) = a mask of 1111 binary.
-              // This allows us a fast way of comparing all bits are set up to this depth.
-              // Note: If the current Actor has clipping, that is included in the depth mask too.
-              uint32_t clippingDepthMask = (1u << newClippingDepth) - 1u;
-
-              // The two masks must be equal to be a hit, as we are already assuming a hit
-              // (for non-clipping mode) then they must be not-equal to disqualify the hit.
-              if(clippingBitPlaneMask != clippingDepthMask)
-              {
-                haveHitActor = false;
-              }
-            }
-
             // If the hit actor does not want to hit, the hit-test continues.
-            if(haveHitActor && hitCheck.ActorRequiresHitResultCheck(&actor, point, hitPointLocal, eventTime))
+            if(hitCheck.ActorRequiresHitResultCheck(&actor, point, hitPointLocal, eventTime))
             {
               hit.actor       = &actor;
               hit.hitPosition = hitPointLocal;
@@ -288,6 +247,12 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
     }
   }
 
+  // If current actor is clipping, and hit failed, We should not checkup child actors. Fast return
+  if(clippingActor && !(hit.actor))
+  {
+    return hit;
+  }
+
   // Find a child hit, until we run out of actors in the current layer.
   HitActor childHit;
   if(actor.GetChildCount() > 0)
@@ -316,8 +281,6 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
                                                overlayedActor,
                                                overlayHit,
                                                layerIs3d,
-                                               newClippingDepth,
-                                               clippingBitPlaneMask,
                                                rayTest,
                                                point,
                                                eventTime));
@@ -505,8 +468,6 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
                                        overlayHit,
                                        overlayHit,
                                        layer->GetBehavior() == Dali::Layer::LAYER_3D,
-                                       0u,
-                                       0u,
                                        rayTest,
                                        results.point,
                                        results.eventTime);
@@ -525,8 +486,6 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
                                        overlayHit,
                                        overlayHit,
                                        layer->GetBehavior() == Dali::Layer::LAYER_3D,
-                                       0u,
-                                       0u,
                                        rayTest,
                                        results.point,
                                        results.eventTime);
index 5fb838d..4a4733f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -55,6 +55,57 @@ RenderItem::RenderItem()
 
 RenderItem::~RenderItem() = default;
 
+ClippingBox RenderItem::CalculateTransformSpaceAABB(const Matrix& transformMatrix, const Vector3& size)
+{
+  // Calculate extent vector of the AABB:
+  const float halfActorX = size.x * 0.5f;
+  const float halfActorY = size.y * 0.5f;
+
+  // To transform the actor bounds to the transformed space, We do a fast, 2D version of a matrix multiply optimized for 2D quads.
+  // This reduces float multiplications from 64 (16 * 4) to 12 (4 * 3).
+  // We create an array of 4 corners and directly initialize the first 3 with the matrix multiplication result of the respective corner.
+  // This causes the construction of the vector arrays contents in-place for optimization.
+  // We place the coords into the array in clockwise order, so we know opposite corners are always i + 2 from corner i.
+  // We skip the 4th corner here as we can calculate that from the other 3, bypassing matrix multiplication.
+  // Note: The below transform methods use a fast (2D) matrix multiply (only 4 multiplications are done).
+  Vector2 corners[4]{Transform2D(transformMatrix, -halfActorX, -halfActorY),
+                     Transform2D(transformMatrix, halfActorX, -halfActorY),
+                     Transform2D(transformMatrix, halfActorX, halfActorY)};
+
+  // As we are dealing with a rectangle, we can do a fast calculation to get the 4th corner from knowing the other 3 (even if rotated).
+  corners[3] = Vector2(corners[0] + (corners[2] - corners[1]));
+
+  // Calculate the AABB:
+  // We use knowledge that opposite corners will be the max/min of each other. Doing this reduces the normal 12 branching comparisons to 3.
+  // The standard equivalent min/max code of the below would be:
+  //       Vector2 AABBmax( std::max( corners[0].x, std::max( corners[1].x, std::max( corners[3].x, corners[2].x ) ) ),
+  //                        std::max( corners[0].y, std::max( corners[1].y, std::max( corners[3].y, corners[2].y ) ) ) );
+  //       Vector2 AABBmin( std::min( corners[0].x, std::min( corners[1].x, std::min( corners[3].x, corners[2].x ) ) ),
+  //                        std::min( corners[0].y, std::min( corners[1].y, std::min( corners[3].y, corners[2].y ) ) ) );
+  unsigned int smallestX = 0u;
+  // Loop 3 times to find the index of the smallest X value.
+  // Note: We deliberately do NOT unroll the code here as this hampers the compilers output.
+  for(unsigned int i = 1u; i < 4u; ++i)
+  {
+    if(corners[i].x < corners[smallestX].x)
+    {
+      smallestX = i;
+    }
+  }
+
+  // As we are dealing with a rectangle, we can assume opposite corners are the largest.
+  // So without doing min/max branching, we can fetch the min/max values of all the remaining X/Y coords from this one index.
+  Vector4 aabb(corners[smallestX].x, corners[(smallestX + 3u) % 4].y, corners[(smallestX + 2u) % 4].x, corners[(smallestX + 1u) % 4].y);
+
+  // Round outwards from center
+  int x = static_cast<int>(floor(aabb.x));
+  int y = static_cast<int>(floor(aabb.y));
+  int z = static_cast<int>(ceilf(aabb.z));
+  int w = static_cast<int>(ceilf(aabb.w));
+
+  return ClippingBox(x, y, z - x, fabsf(w - y));
+}
+
 ClippingBox RenderItem::CalculateViewportSpaceAABB(const Matrix& modelViewMatrix, const Vector3& size, const int viewportWidth, const int viewportHeight)
 {
   // Calculate extent vector of the AABB:
index d89ab22..66d7158 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_SCENE_GRAPH_RENDER_ITEM_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -52,6 +52,15 @@ struct RenderItem
   ~RenderItem();
 
   /**
+   * Produce a 2D AABB in transformed space
+   * See below for caveats.
+   *
+   * @param[in]    transformMatrix   The matrix for converting to a different space
+   * @param[in]    size              The size of the render item
+   */
+  static ClippingBox CalculateTransformSpaceAABB(const Matrix& transformMatrix, const Vector3& size);
+
+  /**
    * @brief This method is an optimized calculation of a viewport-space AABB (Axis-Aligned-Bounding-Box).
    *
    * We use the model-view-matrix, but we do not use projection. Therefore we assume Z = 0.
@@ -60,6 +69,8 @@ struct RenderItem
    *
    * Note: We pass in the viewport dimensions rather than allow the caller to modify the raw AABB in order to optimally generate the final result.
    *
+   * Note: ASSUMES THAT THE VIEWPORT COVERS THE SCREEN AND THAT THE CANVAS SIZE AND VIEWPORT SIZE ARE THE SAME!!!!!  (Not the case for magnifier)
+   *
    * @param[in]    modelViewMatrix   The model view matrix
    * @param[in]    size              The size of the render item
    * @param[in]    viewportWidth     The width of the viewport to calculate for
index 1ff28a8..0365d5b 100644 (file)
@@ -208,19 +208,25 @@ inline void AddRendererToRenderList(BufferIndex         updateBufferIndex,
       SetNodeUpdateSize(node, isLayer3d, nodeWorldMatrix, nodeSize, nodeUpdateSize);
       nodeUpdateSizeSet = true;
 
-      const Vector3& scale    = node->GetWorldScale(updateBufferIndex);
-      const Vector3& halfSize = nodeUpdateSize * scale * 0.5f;
-      float          radius(halfSize.Length());
+      const Vector3& scale = node->GetWorldScale(updateBufferIndex);
+      const Vector3& size  = nodeUpdateSize * scale;
 
-      if(radius > Math::MACHINE_EPSILON_1000)
+      if(size.LengthSquared() > Math::MACHINE_EPSILON_1000)
       {
         Matrix::Multiply(nodeModelViewMatrix, nodeWorldMatrix, viewMatrix);
         nodeModelViewMatrixSet = true;
 
-        ClippingBox clippingBox = RenderItem::CalculateViewportSpaceAABB(nodeModelViewMatrix, nodeUpdateSize, viewport.width, viewport.height);
-        inside                  = clippingBox.Intersects(viewport);
+        // Assume actors are at z=0, compute AABB in view space & test rect intersection
+        // against z=0 plane boundaries for frustum. (NOT viewport). This should take into account
+        // magnification due to FOV etc.
+        ClippingBox boundingBox = RenderItem::CalculateTransformSpaceAABB(nodeModelViewMatrix, nodeUpdateSize);
+        ClippingBox clippingBox(camera.mLeftClippingPlane, camera.mBottomClippingPlane, camera.mRightClippingPlane - camera.mLeftClippingPlane, fabsf(camera.mBottomClippingPlane - camera.mTopClippingPlane));
+        inside = clippingBox.Intersects(boundingBox);
       }
     }
+    /*
+     * Note, the API Camera::CheckAABBInFrustum() can be used to test if a bounding box is (partially/fully) inside the view frustum.
+     */
   }
 
   if(inside)
index f7b2b1c..c6e9973 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -144,7 +144,7 @@ const Dali::Camera::Type           Camera::DEFAULT_TYPE(Dali::Camera::FREE_LOOK)
 const Dali::Camera::ProjectionMode Camera::DEFAULT_MODE(Dali::Camera::PERSPECTIVE_PROJECTION);
 const bool                         Camera::DEFAULT_INVERT_Y_AXIS(false);
 const float                        Camera::DEFAULT_FIELD_OF_VIEW(45.0f * (Math::PI / 180.0f));
-const float                        Camera::DEFAULT_ASPECT_RATIO(4.0f / 3.0f);
+const float                        Camera::DEFAULT_ASPECT_RATIO(800.0f / 480.0f);
 const float                        Camera::DEFAULT_LEFT_CLIPPING_PLANE(-240.0f);
 const float                        Camera::DEFAULT_RIGHT_CLIPPING_PLANE(240.0f);
 const float                        Camera::DEFAULT_TOP_CLIPPING_PLANE(-400.0f);
index 4b37ce4..23e1c54 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_SCENE_GRAPH_CAMERA_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -461,6 +461,17 @@ inline void SetFarClippingPlaneMessage(EventThreadServices& eventThreadServices,
   new(slot) LocalType(&camera, &Camera::SetFarClippingPlane, parameter);
 }
 
+inline void SetReflectByPlaneMessage(EventThreadServices& eventThreadServices, const Camera& camera, const Vector4& plane)
+{
+  using LocalType = MessageValue1<Camera, Vector4>;
+
+  // Reserve some memory inside the message queue
+  uint32_t* slot = eventThreadServices.ReserveMessageSlot(sizeof(LocalType));
+
+  // Construct message in the message queue memory; note that delete should not be called on the return value
+  new(slot) LocalType(&camera, &Camera::SetReflectByPlane, plane);
+}
+
 inline void SetTargetPositionMessage(EventThreadServices& eventThreadServices, const Camera& camera, const Vector3& parameter)
 {
   using LocalType = MessageValue1<Camera, Vector3>;