From: Eunki, Hong Date: Fri, 2 Sep 2022 06:08:48 +0000 (+0900) Subject: (Scene3D) Allow/Block model view's children hit-test events X-Git-Tag: dali_2.1.43~5^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=edf9447f9c57d5b6daafe4e2384940eac34d72f2 (Scene3D) Allow/Block model view's children hit-test events Most of model has a lot of children as Actor format. If we don't setup something on the model view, hit-test always try to access this child tree. For optimization, we need to make some flag to ignore this traversal. Change-Id: I189dfe9138c883ee43d84804dda6fa1663556dd5 Signed-off-by: Eunki, Hong --- diff --git a/automated-tests/src/dali-scene3d/utc-Dali-Model.cpp b/automated-tests/src/dali-scene3d/utc-Dali-Model.cpp index d6a73d8..c18924b 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-Model.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-Model.cpp @@ -20,6 +20,9 @@ #include #include +#include +#include + #include using namespace Dali; @@ -37,6 +40,7 @@ void model_cleanup(void) namespace { +const bool DEFAULT_MODEL_CHILDREN_SENSITIVE = false; /** * For the AnimatedCube.gltf and its Assets * Donated by Norbert Nopper for glTF testing. @@ -72,6 +76,14 @@ const char* TEST_DLI_FILE_NAME = TEST_RESOURCE_DIR "/arc.dli"; */ const char* TEST_DIFFUSE_TEXTURE = TEST_RESOURCE_DIR "/forest_irradiance.ktx"; const char* TEST_SPECULAR_TEXTURE = TEST_RESOURCE_DIR "/forest_radiance.ktx"; + +bool gTouchCallBackCalled = false; +bool TestTouchCallback(Actor, const TouchEvent&) +{ + gTouchCallBackCalled = true; + return true; +} + } // namespace // Negative test case for a method @@ -116,7 +128,7 @@ int UtcDaliModelDownCast(void) tet_infoline(" UtcDaliModelDownCast"); Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME); - BaseHandle handle(model); + BaseHandle handle(model); Scene3D::Model model2 = Scene3D::Model::DownCast(handle); DALI_TEST_CHECK(model); @@ -416,6 +428,165 @@ int UtcDaliModelImageBasedFactor(void) END_TEST; } +int UtcDaliModelChildrenSensitive01(void) +{ + ToolkitTestApplication application; + + Scene3D::Model view = Scene3D::Model::New(TEST_GLTF_FILE_NAME); + view.SetProperty(Dali::Actor::Property::SIZE, Vector3(100, 100, 100)); + view.SetProperty(Dali::Actor::Property::POSITION, Vector3(0, 0, 0)); + view.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + view.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + + // Get default vaule. + DALI_TEST_EQUALS(view.GetChildrenSensitive(), DEFAULT_MODEL_CHILDREN_SENSITIVE, TEST_LOCATION); + + // Allow children actor's event before on scene. + view.SetChildrenSensitive(true); + DALI_TEST_EQUALS(view.GetChildrenSensitive(), true, TEST_LOCATION); + + application.GetScene().Add(view); + + application.SendNotification(); + application.Render(); + + Actor meshActor = view.FindChildByName("AnimatedCube"); + DALI_TEST_CHECK(meshActor); + + // connect hit-test signal + gTouchCallBackCalled = false; + meshActor.TouchedSignal().Connect(TestTouchCallback); + + Vector2 sceneSize = application.GetScene().GetSize(); + + // Try to touch center of scene. + Dali::Integration::Point point; + point.SetState(PointState::DOWN); + point.SetScreenPosition(sceneSize * 0.5f); + Dali::Integration::TouchEvent event; + event.AddPoint(point); + + // flush the queue and render once + application.SendNotification(); + application.Render(); + + // Not touched yet. + DALI_TEST_CHECK(!gTouchCallBackCalled); + application.ProcessEvent(event); + // Touched. + DALI_TEST_CHECK(gTouchCallBackCalled); + + // Clear + gTouchCallBackCalled = false; + + // Block children actor's event + view.SetChildrenSensitive(false); + DALI_TEST_EQUALS(view.GetChildrenSensitive(), false, TEST_LOCATION); + + // flush the queue and render once + application.SendNotification(); + application.Render(); + + // Not touched yet. + DALI_TEST_CHECK(!gTouchCallBackCalled); + application.ProcessEvent(event); + // Also not touched. + DALI_TEST_CHECK(!gTouchCallBackCalled); + + // Clear + gTouchCallBackCalled = false; + + // Allow again + view.SetChildrenSensitive(true); + DALI_TEST_EQUALS(view.GetChildrenSensitive(), true, TEST_LOCATION); + + // flush the queue and render once + application.SendNotification(); + application.Render(); + + // Not touched yet. + DALI_TEST_CHECK(!gTouchCallBackCalled); + application.ProcessEvent(event); + // Touched. + DALI_TEST_CHECK(gTouchCallBackCalled); + + // Clear + gTouchCallBackCalled = false; + + END_TEST; +} + +int UtcDaliModelChildrenSensitive02(void) +{ + ToolkitTestApplication application; + + Scene3D::Model view = Scene3D::Model::New(TEST_GLTF_FILE_NAME); + view.SetProperty(Dali::Actor::Property::SIZE, Vector3(100, 100, 100)); + view.SetProperty(Dali::Actor::Property::POSITION, Vector3(0, 0, 0)); + view.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + view.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + + // Get vaule. + DALI_TEST_EQUALS(view.GetChildrenSensitive(), DEFAULT_MODEL_CHILDREN_SENSITIVE, TEST_LOCATION); + + // Block children actor's event before on scene. + view.SetChildrenSensitive(false); + DALI_TEST_EQUALS(view.GetChildrenSensitive(), false, TEST_LOCATION); + + application.GetScene().Add(view); + + application.SendNotification(); + application.Render(); + + Actor meshActor = view.FindChildByName("AnimatedCube"); + DALI_TEST_CHECK(meshActor); + + // connect hit-test signal + gTouchCallBackCalled = false; + meshActor.TouchedSignal().Connect(TestTouchCallback); + + Vector2 sceneSize = application.GetScene().GetSize(); + + // Try to touch center of scene. + Dali::Integration::Point point; + point.SetState(PointState::DOWN); + point.SetScreenPosition(sceneSize * 0.5f); + Dali::Integration::TouchEvent event; + event.AddPoint(point); + + // flush the queue and render once + application.SendNotification(); + application.Render(); + + // Not touched yet. + DALI_TEST_CHECK(!gTouchCallBackCalled); + application.ProcessEvent(event); + // Also not touched. + DALI_TEST_CHECK(!gTouchCallBackCalled); + + // Clear + gTouchCallBackCalled = false; + + // Allow again + view.SetChildrenSensitive(true); + DALI_TEST_EQUALS(view.GetChildrenSensitive(), true, TEST_LOCATION); + + // flush the queue and render once + application.SendNotification(); + application.Render(); + + // Not touched yet. + DALI_TEST_CHECK(!gTouchCallBackCalled); + application.ProcessEvent(event); + // Touched. + DALI_TEST_CHECK(gTouchCallBackCalled); + + // Clear + gTouchCallBackCalled = false; + + END_TEST; +} + int UtcDaliModelAnimation01(void) { ToolkitTestApplication application; @@ -473,25 +644,25 @@ int UtcDaliModelAnimation02(void) namespace { static bool gOnRelayoutCallBackCalled = false; -void OnRelayoutCallback(Actor actor) +void OnRelayoutCallback(Actor actor) { gOnRelayoutCallBackCalled = true; } static bool gResourceReadyCalled = false; -void OnResourceReady(Control control) +void OnResourceReady(Control control) { gResourceReadyCalled = true; } -} +} // namespace int UtcDaliModelResourceReady(void) { ToolkitTestApplication application; gOnRelayoutCallBackCalled = false; - gResourceReadyCalled = false; - Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_ANIMATION_TEST_FILE_NAME); + gResourceReadyCalled = false; + Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_ANIMATION_TEST_FILE_NAME); model.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); model.OnRelayoutSignal().Connect(OnRelayoutCallback); model.ResourceReadySignal().Connect(OnResourceReady); diff --git a/dali-scene3d/internal/controls/model/model-impl.cpp b/dali-scene3d/internal/controls/model/model-impl.cpp index ed5d3bd..24e7af5 100644 --- a/dali-scene3d/internal/controls/model/model-impl.cpp +++ b/dali-scene3d/internal/controls/model/model-impl.cpp @@ -22,14 +22,15 @@ #include #include #include +#include #include #include #include #include // INTERNAL INCLUDES -#include #include +#include #include #include #include @@ -65,6 +66,8 @@ static constexpr uint32_t OFFSET_FOR_SPECULAR_CUBE_TEXTURE = 1u; static constexpr Vector3 Y_DIRECTION(1.0f, -1.0f, 1.0f); +static constexpr bool DEFAULT_MODEL_CHILDREN_SENSITIVE = false; + static constexpr std::string_view KTX_EXTENSION = ".ktx"; static constexpr std::string_view OBJ_EXTENSION = ".obj"; static constexpr std::string_view GLTF_EXTENSION = ".gltf"; @@ -179,6 +182,7 @@ Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUr mNaturalSize(Vector3::ZERO), mModelPivot(AnchorPoint::CENTER), mIblScaleFactor(1.0f), + mModelChildrenSensitive(DEFAULT_MODEL_CHILDREN_SENSITIVE), mModelResourceReady(false), mIBLResourceReady(true) { @@ -206,9 +210,26 @@ const Actor Model::GetModelRoot() const return mModelRoot; } +void Model::SetChildrenSensitive(bool enable) +{ + if(mModelChildrenSensitive != enable) + { + mModelChildrenSensitive = enable; + if(mModelRoot) + { + mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive); + } + } +} + +bool Model::GetChildrenSensitive() const +{ + return mModelChildrenSensitive; +} + void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor) { - mIBLResourceReady = false; + mIBLResourceReady = false; Texture diffuseTexture = Dali::Scene3D::Loader::LoadCubeMap(diffuseUrl); Texture specularTexture = Dali::Scene3D::Loader::LoadCubeMap(specularUrl); SetImageBasedLightTexture(diffuseTexture, specularTexture, scaleFactor); @@ -237,7 +258,6 @@ void Model::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Textur mIblScaleFactor = scaleFactor; UpdateImageBasedLightScaleFactor(); } - } } @@ -483,6 +503,8 @@ void Model::LoadModel() FitModelPosition(); ScaleModel(); + mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive); + Self().Add(mModelRoot); Self().SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); diff --git a/dali-scene3d/internal/controls/model/model-impl.h b/dali-scene3d/internal/controls/model/model-impl.h index 7e97977..3db9c57 100644 --- a/dali-scene3d/internal/controls/model/model-impl.h +++ b/dali-scene3d/internal/controls/model/model-impl.h @@ -22,8 +22,8 @@ #include #include #include -#include #include +#include // INTERNAL INCLUDES #include @@ -58,6 +58,16 @@ public: const Actor GetModelRoot() const; /** + * @copydoc Model::SetChildrenSensitive() + */ + void SetChildrenSensitive(bool enable); + + /** + * @copydoc Model::GetChildrenSensitive() + */ + bool GetChildrenSensitive() const; + + /** * @copydoc Model::SetImageBasedLightSource() */ void SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor); @@ -182,6 +192,7 @@ private: Vector3 mNaturalSize; Vector3 mModelPivot; float mIblScaleFactor; + bool mModelChildrenSensitive; bool mModelResourceReady; bool mIBLResourceReady; }; diff --git a/dali-scene3d/public-api/controls/model/model.cpp b/dali-scene3d/public-api/controls/model/model.cpp index e315cb9..69029d9 100644 --- a/dali-scene3d/public-api/controls/model/model.cpp +++ b/dali-scene3d/public-api/controls/model/model.cpp @@ -67,6 +67,16 @@ const Actor Model::GetModelRoot() const return GetImpl(*this).GetModelRoot(); } +void Model::SetChildrenSensitive(bool enable) +{ + GetImpl(*this).SetChildrenSensitive(enable); +} + +bool Model::GetChildrenSensitive() const +{ + return GetImpl(*this).GetChildrenSensitive(); +} + void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor) { GetImpl(*this).SetImageBasedLightSource(diffuseUrl, specularUrl, scaleFactor); diff --git a/dali-scene3d/public-api/controls/model/model.h b/dali-scene3d/public-api/controls/model/model.h index 6678d9f..104e054 100644 --- a/dali-scene3d/public-api/controls/model/model.h +++ b/dali-scene3d/public-api/controls/model/model.h @@ -23,8 +23,8 @@ // EXTERNAL INCLUDES #include -#include #include +#include namespace Dali { @@ -50,6 +50,7 @@ class Model; * * By default, The loaded model has its own position and size which are defined in vertex buffer regardless of the Control size. * + * @SINCE_2_1.41 * @code * * Model model = Model::New(modelUrl); @@ -69,6 +70,8 @@ class DALI_SCENE3D_API Model : public Dali::Toolkit::Control public: /** * @brief Create an initialized Model. + * + * @SINCE_2_1.41 * @param[in] modelUrl model file path.(e.g., glTF, and DLI). * @param[in] resourceDirectoryUrl resource file path that includes binary, image etc. * @note If resourceDirectoryUrl is empty, the parent directory path of modelUrl is used for resource path. @@ -81,6 +84,8 @@ public: * * Only derived versions can be instantiated. Calling member * functions with an uninitialized Dali::Object is not allowed. + * + * @SINCE_2_1.41 */ Model(); @@ -88,11 +93,15 @@ public: * @brief Destructor. * * This is non-virtual since derived Handle types must not contain data or virtual methods. + * + * @SINCE_2_1.41 */ ~Model(); /** * @brief Copy constructor. + * + * @SINCE_2_1.41 * @param[in] model Handle to an object */ Model(const Model& model); @@ -100,12 +109,15 @@ public: /** * @brief Move constructor * + * @SINCE_2_1.41 * @param[in] rhs A reference to the moved handle */ Model(Model&& rhs); /** * @brief Assignment operator. + * + * @SINCE_2_1.41 * @param[in] model Handle to an object * @return reference to this */ @@ -114,6 +126,7 @@ public: /** * @brief Move assignment * + * @SINCE_2_1.41 * @param[in] rhs A reference to the moved handle * @return A reference to this */ @@ -125,6 +138,7 @@ public: * If handle points to a Model, the downcast produces valid handle. * If not, the returned handle is left uninitialized. * + * @SINCE_2_1.41 * @param[in] handle Handle to an object * @return Handle to a Model or an uninitialized handle */ @@ -132,12 +146,40 @@ public: /** * @brief Retrieves model root Actor. + * + * @SINCE_2_1.41 * @return Root Actor of the model. */ const Actor GetModelRoot() const; /** + * @brief Whether allow this model's children actor to use events. + * + * Usually, 3D Model might have a lot of actors. And most of them don't need to check events. + * To optimize traversal, we need to setup some flag that this model don't allow (or allow) to traversal + * children so that child can use events. + * + * @SINCE_2_1.43 + * @note Even if we set children sensitive as false, model itself's sensitive + * is depend on it's property. + * @note If we don't call this API, default is false. (Allow to traversal model's children during hit-test) + * + * @param[in] enable True to enable model's children can use events. + */ + void SetChildrenSensitive(bool enable); + + /** + * @brief Gets whether this Model allow model's children actor to use events or not. + * + * @SINCE_2_1.43 + * @return bool True if this Model allow model children sensitive. + */ + bool GetChildrenSensitive() const; + + /** * @brief Changes Image Based Light as the input textures. + * + * @SINCE_2_1.41 * @param[in] diffuseUrl cube map that can be used as a diffuse IBL source. * @param[in] specularUrl cube map that can be used as a specular IBL source. * @param[in] scaleFactor scale factor that controls light source intensity in [0.0f, 1.0f]. Default value is 1.0f. @@ -147,6 +189,7 @@ public: /** * @brief Sets Image Based Light Texture. * + * @SINCE_2_1.41 * @param[in] diffuseTexture cube map texture that can be used as a diffuse IBL source. * @param[in] specularTexture cube map texture that can be used as a specular IBL source. * @param[in] scaleFactor scale factor that controls light source intensity in [0.0f, 1.0f]. Default value is 1.0f. @@ -158,6 +201,7 @@ public: /** * @brief Sets Scale Factor of Image Based Light Source. * + * @SINCE_2_1.41 * @note If SetImageBasedLightSource() or SetImageBasedLightTexture() method is called after this method, scaleFactor is overrided. * * @param[in] scaleFactor scale factor that controls light source intensity in [0.0f, 1.0f]. @@ -168,12 +212,15 @@ public: * @brief Gets Scale Factor of Image Based Light Source. * Default value is 1.0f. * + * @SINCE_2_1.41 * @return scale factor that controls light source intensity. */ float GetImageBasedLightScaleFactor() const; /** * @brief Gets number of animations those loaded from model file. + * + * @SINCE_2_1.41 * @return The number of loaded animations. * @note This method should be called after Model load finished. */ @@ -181,6 +228,8 @@ public: /** * @brief Gets animation at the index. + * + * @SINCE_2_1.41 * @param[in] index Index of animation to be retrieved. * @return Animation at the index. * @note This method should be called after Model load finished. @@ -189,6 +238,8 @@ public: /** * @brief Retrieves animation with the given name. + * + * @SINCE_2_1.41 * @param[in] name string name of animation to be retrieved. * @return Animation that has the given name. * @note This method should be called after Model load finished. diff --git a/dali-scene3d/public-api/controls/scene-view/scene-view.h b/dali-scene3d/public-api/controls/scene-view/scene-view.h index b1923c3..fce3b19 100644 --- a/dali-scene3d/public-api/controls/scene-view/scene-view.h +++ b/dali-scene3d/public-api/controls/scene-view/scene-view.h @@ -85,6 +85,7 @@ class SceneView; * * And since SceneView is a Control, it can be placed together with other 2D UI components in the DALi window. * + * @SINCE_2_1.38 * @code * * Dali::Scene3D::SceneView sceneView = Dali::Scene3D::SceneView::New(); @@ -104,6 +105,8 @@ class DALI_SCENE3D_API SceneView : public Dali::Toolkit::Control public: /** * @brief Create an initialized SceneView. + * + * @SINCE_2_1.38 * @return A handle to a newly allocated Dali resource */ static SceneView New(); @@ -113,6 +116,8 @@ public: * * Only derived versions can be instantiated. Calling member * functions with an uninitialized Dali::Object is not allowed. + * + * @SINCE_2_1.38 */ SceneView(); @@ -120,11 +125,15 @@ public: * @brief Destructor. * * This is non-virtual since derived Handle types must not contain data or virtual methods. + * + * @SINCE_2_1.38 */ ~SceneView(); /** * @brief Copy constructor. + * + * @SINCE_2_1.38 * @param[in] sceneView Handle to an object */ SceneView(const SceneView& sceneView); @@ -132,12 +141,15 @@ public: /** * @brief Move constructor * + * @SINCE_2_1.38 * @param[in] rhs A reference to the moved handle */ SceneView(SceneView&& rhs); /** * @brief Assignment operator. + * + * @SINCE_2_1.38 * @param[in] sceneView Handle to an object * @return reference to this */ @@ -146,6 +158,7 @@ public: /** * @brief Move assignment * + * @SINCE_2_1.38 * @param[in] rhs A reference to the moved handle * @return A reference to this */ @@ -157,6 +170,7 @@ public: * If handle points to a SceneView, the downcast produces valid handle. * If not, the returned handle is left uninitialized. * + * @SINCE_2_1.38 * @param[in] handle Handle to an object * @return Handle to a SceneView or an uninitialized handle */ @@ -166,6 +180,7 @@ public: * @brief Adds a CameraActor to the SceneView * The CameraActor can be used as a selected camera to render the scene by using SelectCamera(uint32_t) or SelectCamera(std::string) * + * @SINCE_2_1.38 * @note * AspectRatio property of CameraActor will be changed depending on the Size of this SceneView. * @@ -183,6 +198,8 @@ public: /** * @brief Removes a CameraActor from this SceneView. + * + * @SINCE_2_1.38 * @note If removed CameraActor is selected CameraActor, * first camera in the list is set to selected CameraActor. * @@ -193,6 +210,7 @@ public: /** * @brief Retrieves the number of cameras. * + * @SINCE_2_1.38 * @return Number of cameras those currently the SceneView contains. */ uint32_t GetCameraCount() const; @@ -200,6 +218,7 @@ public: /** * @brief Retrieves selected CameraActor. * + * @SINCE_2_1.38 * @return CameraActor currently used in SceneView as a selected CameraActor */ CameraActor GetSelectedCamera() const; @@ -207,6 +226,7 @@ public: /** * @brief Retrieves a CameraActor of the index. * + * @SINCE_2_1.38 * @param[in] index Index of CameraActor to be retrieved. * * @return CameraActor of the index @@ -216,6 +236,7 @@ public: /** * @brief Retrieves a CameraActor of the name. * + * @SINCE_2_1.38 * @param[in] name string keyword of CameraActor to be retrieved. * * @return CameraActor that has the name as a Dali::Actor::Property::NAME @@ -225,6 +246,7 @@ public: /** * @brief Makes SceneView use a CameraActor of index as a selected camera. * + * @SINCE_2_1.38 * @param[in] index Index of CameraActor to be used as a selected camera. */ void SelectCamera(uint32_t index); @@ -232,6 +254,7 @@ public: /** * @brief Makes SceneView use a CameraActor of a name as a selected camera. * + * @SINCE_2_1.38 * @param[in] name string keyword of CameraActor to be used as a selected camera. */ void SelectCamera(const std::string& name); @@ -239,6 +262,7 @@ public: /** * @brief Sets Image Based Light Source to apply it on the all Models those added on this SceneView. * + * @SINCE_2_1.38 * @note If any Models already have IBL, they are batch-overridden with the SceneView's IBL. * If SceneView has IBL, IBL of newly added Model is also overridden. * To set indivisual IBL for each Model, the Model's IBL should be set after the SceneView's IBL. @@ -252,6 +276,7 @@ public: /** * @brief Sets Scale Factor of Image Based Light Source. * + * @SINCE_2_1.41 * @note If SetImageBasedLightSource() or SetImageBasedLightTexture() method is called after this method, scaleFactor is overriden. * @note Default value is 1.0f. * @@ -263,6 +288,7 @@ public: * @brief Gets Scale Factor of Image Based Light Source. * Default value is 1.0f. * + * @SINCE_2_1.41 * @return scale factor that controls light source intensity. */ float GetImageBasedLightScaleFactor() const; @@ -273,6 +299,7 @@ public: * If useFramebuffer is false, each item in SceneView is rendered on window directly. * Default is false. * + * @SINCE_2_1.38 * @note If useFramebuffer is true, it could decrease performance but entire rendering order is satisfied. * If useFramebuffer is false, performance is become better but SceneView is rendered on top of the other 2D Actors regardless tree order. * @@ -283,6 +310,7 @@ public: /** * @brief Gets whether this SceneView uses Framebuffer or not. * + * @SINCE_2_1.38 * @return bool True if this SceneView uses Framebuffer. */ bool IsUsingFramebuffer() const;