From: Heeyong Song Date: Tue, 5 Apr 2022 11:19:43 +0000 (+0000) Subject: Merge "Use update object size in CalculateActorScreenPosition" into devel/master X-Git-Tag: dali_2.1.17~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ec1ba420b9ab11417be827d57173583ca0a003c5;hp=b80e67cb48104646dc91a546cb0733b2c22700e0;p=platform%2Fcore%2Fuifw%2Fdali-core.git Merge "Use update object size in CalculateActorScreenPosition" into devel/master --- diff --git a/automated-tests/src/dali/utc-Dali-CameraActor.cpp b/automated-tests/src/dali/utc-Dali-CameraActor.cpp index 3352ee9..0ec0ccb 100644 --- a/automated-tests/src/dali/utc-Dali-CameraActor.cpp +++ b/automated-tests/src/dali/utc-Dali-CameraActor.cpp @@ -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_EPSILON, TEST_LOCATION); + DALI_TEST_EQUALS(800.0f / 480.0f, actor.GetProperty(CameraActor::Property::ASPECT_RATIO).Get(), FLOAT_EPSILON, TEST_LOCATION); DALI_TEST_EQUALS(45.0f * (Math::PI / 180.0f), actor.GetProperty(CameraActor::Property::FIELD_OF_VIEW).Get(), FLOAT_EPSILON, TEST_LOCATION); DALI_TEST_EQUALS(800.0f, actor.GetProperty(CameraActor::Property::NEAR_PLANE_DISTANCE).Get(), FLOAT_EPSILON, TEST_LOCATION); DALI_TEST_EQUALS(3.0f * 800.0f, actor.GetProperty(CameraActor::Property::FAR_PLANE_DISTANCE).Get(), 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(), 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(), 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; +} diff --git a/automated-tests/src/dali/utc-Dali-HitTestAlgorithm.cpp b/automated-tests/src/dali/utc-Dali-HitTestAlgorithm.cpp index 2229015..cea3e03 100644 --- a/automated-tests/src/dali/utc-Dali-HitTestAlgorithm.cpp +++ b/automated-tests/src/dali/utc-Dali-HitTestAlgorithm.cpp @@ -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(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(Actor::Property::NAME).c_str() : "NULL")); + DALI_TEST_CHECK(results.actor == rootLayer); + + END_TEST; +} + int UtcDaliHitTestAlgorithmOverlay(void) { TestApplication application; diff --git a/dali/internal/event/actors/camera-actor-impl.cpp b/dali/internal/event/actors/camera-actor-impl.cpp index 97affa3..d69462a 100644 --- a/dali/internal/event/actors/camera-actor-impl.cpp +++ b/dali/internal/event/actors/camera-actor-impl.cpp @@ -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(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, diff --git a/dali/internal/event/events/hit-test-algorithm-impl.cpp b/dali/internal/event/events/hit-test-algorithm-impl.cpp index 267c1ff..0ed24be 100644 --- a/dali/internal/event/events/hit-test-algorithm-impl.cpp +++ b/dali/internal/event/events/hit-test-algorithm-impl.cpp @@ -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); diff --git a/dali/internal/render/common/render-item.cpp b/dali/internal/render/common/render-item.cpp index 5fb838d..4a4733f 100644 --- a/dali/internal/render/common/render-item.cpp +++ b/dali/internal/render/common/render-item.cpp @@ -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(floor(aabb.x)); + int y = static_cast(floor(aabb.y)); + int z = static_cast(ceilf(aabb.z)); + int w = static_cast(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: diff --git a/dali/internal/render/common/render-item.h b/dali/internal/render/common/render-item.h index d89ab22..66d7158 100644 --- a/dali/internal/render/common/render-item.h +++ b/dali/internal/render/common/render-item.h @@ -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 diff --git a/dali/internal/update/manager/render-instruction-processor.cpp b/dali/internal/update/manager/render-instruction-processor.cpp index 1ff28a8..0365d5b 100644 --- a/dali/internal/update/manager/render-instruction-processor.cpp +++ b/dali/internal/update/manager/render-instruction-processor.cpp @@ -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) diff --git a/dali/internal/update/render-tasks/scene-graph-camera.cpp b/dali/internal/update/render-tasks/scene-graph-camera.cpp index f7b2b1c..c6e9973 100644 --- a/dali/internal/update/render-tasks/scene-graph-camera.cpp +++ b/dali/internal/update/render-tasks/scene-graph-camera.cpp @@ -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); diff --git a/dali/internal/update/render-tasks/scene-graph-camera.h b/dali/internal/update/render-tasks/scene-graph-camera.h index 4b37ce4..23e1c54 100644 --- a/dali/internal/update/render-tasks/scene-graph-camera.h +++ b/dali/internal/update/render-tasks/scene-graph-camera.h @@ -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; + + // 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;