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 list = Stage::GetCurrent().GetRenderTaskList();
98 [[maybe_unused]] auto taskCount = list.GetTaskCount();
99 renderTask = list.GetTask(list.GetTaskCount() - 1);
101 if(HitTestAlgorithm::BuildPickingRay(renderTask, result, origin, direction))
103 for(auto& mesh : meshData)
105 // Set transform for the collider mesh
106 const_cast<Dali::Scene3D::Algorithm::ColliderMesh&>(mesh.colliderMesh).SetSceneTransform(mesh.worldMatrix);
107 auto res = mesh.colliderMesh.RayFaceIntersect(origin, direction);
108 if(res != Dali::Scene3D::Algorithm::NavigationMesh::NULL_FACE)
110 Scene3D::Model model = mesh.model;
111 Scene3D::Internal::Model& modelImpl = GetImpl(model);
112 retVal = modelImpl.EmitMeshHitSignal(mesh.modelNode);
122 } // unnamed namespace
124 ColliderMeshProcessor::ColliderMeshProcessor()
126 Adaptor::Get().RegisterProcessor(*this, true);
129 ColliderMeshProcessor::~ColliderMeshProcessor()
131 if(Adaptor::IsAvailable())
133 Adaptor::Get().UnregisterProcessor(*this, true);
137 void ColliderMeshProcessor::ColliderMeshChanged(Scene3D::Model model)
139 if(model.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
141 AddSceneViewParentToProcessingQueue(model);
145 // TODO: Check if signal already connected
146 model.OnSceneSignal().Connect(this, &ColliderMeshProcessor::ModelOnScene);
150 void ColliderMeshProcessor::ModelOnScene(Actor actor)
152 Scene3D::Model model = Scene3D::Model::DownCast(actor);
155 AddSceneViewParentToProcessingQueue(model);
157 model.OnSceneSignal().Disconnect(this, &ColliderMeshProcessor::ModelOnScene);
160 void ColliderMeshProcessor::AddSceneViewParentToProcessingQueue(Scene3D::Model model)
165 actor = actor.GetParent();
166 Scene3D::SceneView sceneView(Scene3D::SceneView::DownCast(actor));
169 mSceneViewsToProcess.push_back(sceneView);
175 void ColliderMeshProcessor::Process(bool /* postProcess */)
177 // Remove any duplicates
178 std::sort(mSceneViewsToProcess.begin(), mSceneViewsToProcess.end());
179 mSceneViewsToProcess.erase(std::unique(mSceneViewsToProcess.begin(), mSceneViewsToProcess.end()), mSceneViewsToProcess.end());
181 for(auto& sceneView : mSceneViewsToProcess)
183 std::vector<ColliderMeshData> meshData;
184 IterateThroughChildren(sceneView, meshData);
188 // TODO: Get SceneView Camera parameters and calculate bounding box
189 // for now, it's a pass-thru algorthm
190 if(std::find(mConnectedSceneViews.begin(), mConnectedSceneViews.end(), sceneView) == mConnectedSceneViews.end())
192 mConnectedSceneViews.push_back(sceneView);
193 // TODO: Consider passing in camera parameters and meshData into SceneViewTouchHandler
194 sceneView.TouchedSignal().Connect(this, SceneViewTouchHandler());
198 mSceneViewsToProcess.clear();
201 } // namespace Dali::Scene3D::Internal