2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-scene3d/internal/event/collider-mesh-processor-impl.h>
22 #include <dali/devel-api/actors/actor-devel.h>
23 #include <dali/devel-api/events/hit-test-algorithm.h>
24 #include <dali/integration-api/adaptor-framework/adaptor.h>
25 #include <dali/public-api/events/touch-event.h>
26 #include <dali/public-api/render-tasks/render-task-list.h>
30 #include <dali-scene3d/internal/controls/model/model-impl.h>
31 #include <dali-scene3d/internal/controls/scene-view/scene-view-impl.h>
32 #include <dali-scene3d/public-api/controls/scene-view/scene-view.h>
34 namespace Dali::Scene3D::Internal
38 struct ColliderMeshData
41 Scene3D::ModelNode modelNode;
42 const Dali::Scene3D::Algorithm::ColliderMesh& colliderMesh;
43 Matrix worldMatrix{false};
45 using ColliderMeshDataContainer = std::vector<ColliderMeshData>;
47 void IterateThroughChildren(Actor actor, ColliderMeshDataContainer& meshData)
51 const auto childCount = actor.GetChildCount();
52 for(auto i = 0u; i < childCount; ++i)
54 Actor child = actor.GetChildAt(i);
55 Scene3D::Model model = Scene3D::Model::DownCast(child);
58 const Model::ColliderMeshContainer& colliderMeshes = GetImpl(model).GetNodeColliderMeshContainer();
59 for(const auto& colliderMeshItem : colliderMeshes)
61 // If actor name is empty, then assume the mesh if for the model itself
62 [[maybe_unused]] int actorId = colliderMeshItem.first;
63 Dali::Scene3D::ModelNode modelNode = colliderMeshItem.second;
66 meshData.push_back({model, modelNode, GetImplementation(modelNode).GetColliderMesh(), DevelActor::GetWorldTransform(modelNode)});
70 IterateThroughChildren(child, meshData);
75 class SceneViewTouchHandler
78 bool operator()(Actor actor, const TouchEvent& touchEvent)
80 Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(actor);
84 // Get nav-mesh information for the children
85 std::vector<ColliderMeshData> meshData;
86 IterateThroughChildren(sceneView, meshData);
88 auto renderTask = touchEvent.GetRenderTask();
89 auto cameraActor = renderTask.GetCameraActor();
91 const auto& result = touchEvent.GetScreenPosition(0);
92 float x = 0.0f, y = 0.0f;
95 cameraActor.ScreenToLocal(x, y, result.x, result.y);
97 auto sceneViewRenderTask = GetImpl(sceneView).GetRenderTask();
99 if(sceneViewRenderTask && HitTestAlgorithm::BuildPickingRay(sceneViewRenderTask, result, origin, direction))
101 for(auto& mesh : meshData)
103 // Set transform for the collider mesh
104 const_cast<Dali::Scene3D::Algorithm::ColliderMesh&>(mesh.colliderMesh).SetSceneTransform(mesh.worldMatrix);
105 auto res = mesh.colliderMesh.RayFaceIntersect(origin, direction);
106 if(res != Dali::Scene3D::Algorithm::NavigationMesh::NULL_FACE)
108 Scene3D::Model model = mesh.model;
109 Scene3D::Internal::Model& modelImpl = GetImpl(model);
110 retVal = modelImpl.EmitMeshHitSignal(mesh.modelNode);
120 } // unnamed namespace
122 ColliderMeshProcessor::ColliderMeshProcessor()
124 Adaptor::Get().RegisterProcessor(*this, true);
127 ColliderMeshProcessor::~ColliderMeshProcessor()
129 if(Adaptor::IsAvailable())
131 Adaptor::Get().UnregisterProcessor(*this, true);
135 void ColliderMeshProcessor::ColliderMeshChanged(Scene3D::Model model)
137 if(model.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
139 AddSceneViewParentToProcessingQueue(model);
143 // TODO: Check if signal already connected
144 model.OnSceneSignal().Connect(this, &ColliderMeshProcessor::ModelOnScene);
148 void ColliderMeshProcessor::ModelOnScene(Actor actor)
150 Scene3D::Model model = Scene3D::Model::DownCast(actor);
153 AddSceneViewParentToProcessingQueue(model);
155 model.OnSceneSignal().Disconnect(this, &ColliderMeshProcessor::ModelOnScene);
158 void ColliderMeshProcessor::AddSceneViewParentToProcessingQueue(Scene3D::Model model)
163 actor = actor.GetParent();
164 Scene3D::SceneView sceneView(Scene3D::SceneView::DownCast(actor));
167 mSceneViewsToProcess.push_back(sceneView);
173 void ColliderMeshProcessor::Process(bool /* postProcess */)
175 // Remove any duplicates
176 std::sort(mSceneViewsToProcess.begin(), mSceneViewsToProcess.end());
177 mSceneViewsToProcess.erase(std::unique(mSceneViewsToProcess.begin(), mSceneViewsToProcess.end()), mSceneViewsToProcess.end());
179 for(auto& sceneView : mSceneViewsToProcess)
181 std::vector<ColliderMeshData> meshData;
182 IterateThroughChildren(sceneView, meshData);
186 // TODO: Get SceneView Camera parameters and calculate bounding box
187 // for now, it's a pass-thru algorthm
188 if(std::find(mConnectedSceneViews.begin(), mConnectedSceneViews.end(), sceneView) == mConnectedSceneViews.end())
190 mConnectedSceneViews.push_back(sceneView);
191 // TODO: Consider passing in camera parameters and meshData into SceneViewTouchHandler
192 sceneView.TouchedSignal().Connect(this, SceneViewTouchHandler());
196 mSceneViewsToProcess.clear();
199 } // namespace Dali::Scene3D::Internal