2f3fbf3230c90bcae5fc1a7e0d5f07cc5037a226
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / controls / scene-view / scene-view-impl.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-scene3d/internal/controls/scene-view/scene-view-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali-toolkit/dali-toolkit.h>
23 #include <dali-toolkit/devel-api/controls/control-devel.h>
24 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
25 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
26 #include <dali-toolkit/public-api/image-loader/image-url.h>
27 #include <dali-toolkit/public-api/image-loader/image.h>
28 #include <dali/devel-api/actors/camera-actor-devel.h>
29 #include <dali/devel-api/adaptor-framework/window-devel.h>
30 #include <dali/devel-api/common/stage.h>
31 #include <dali/integration-api/debug.h>
32 #include <dali/public-api/object/type-registry-helper.h>
33 #include <dali/public-api/object/type-registry.h>
34
35 // INTERNAL INCLUDES
36 #include <dali-scene3d/internal/controls/model/model-impl.h>
37 #include <dali-scene3d/public-api/loader/cube-map-loader.h>
38
39 #include <dali/integration-api/debug.h>
40
41 using namespace Dali;
42
43 namespace Dali
44 {
45 namespace Scene3D
46 {
47 namespace Internal
48 {
49 namespace
50 {
51 BaseHandle Create()
52 {
53   return Scene3D::SceneView::New();
54 }
55
56 // Setup properties, signals and actions using the type-registry.
57 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::SceneView, Toolkit::Control, Create);
58 DALI_TYPE_REGISTRATION_END()
59
60 Property::Index   RENDERING_BUFFER    = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1;
61 constexpr int32_t DEFAULT_ORIENTATION = 0;
62
63 } // anonymous namespace
64
65 SceneView::SceneView()
66 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
67   mWindowOrientation(DEFAULT_ORIENTATION)
68 {
69 }
70
71 SceneView::~SceneView() = default;
72
73 Dali::Scene3D::SceneView SceneView::New()
74 {
75   SceneView* impl = new SceneView();
76
77   Dali::Scene3D::SceneView handle = Dali::Scene3D::SceneView(*impl);
78
79   // Second-phase init of the implementation
80   // This can only be done after the CustomActor connection has been made...
81   impl->Initialize();
82
83   return handle;
84 }
85
86 void SceneView::AddCamera(CameraActor camera)
87 {
88   if(camera)
89   {
90     if(mCameras.empty())
91     {
92       UpdateCamera(camera);
93     }
94     mCameras.push_back(camera);
95   }
96 }
97
98 void SceneView::RemoveCamera(CameraActor camera)
99 {
100   if(camera == mDefaultCamera)
101   {
102     DALI_LOG_ERROR("Default Camera cannot removed.\n");
103     return;
104   }
105
106   if(camera)
107   {
108     for(uint32_t i = 0; i < mCameras.size(); ++i)
109     {
110       if(mCameras[i] == camera)
111       {
112         mCameras.erase(mCameras.begin() + i);
113         break;
114       }
115     }
116
117     if(mSelectedCamera == camera)
118     {
119       CameraActor newCurrentCamera = *mCameras.begin();
120       UpdateCamera(newCurrentCamera);
121     }
122   }
123 }
124
125 uint32_t SceneView::GetCameraCount() const
126 {
127   return mCameras.size();
128 }
129
130 CameraActor SceneView::GetSelectedCamera() const
131 {
132   return mSelectedCamera;
133 }
134
135 CameraActor SceneView::GetCamera(uint32_t index) const
136 {
137   if(index < mCameras.size())
138   {
139     return mCameras[index];
140   }
141   DALI_LOG_ERROR("Input index is out of bounds\n");
142   return CameraActor();
143 }
144
145 CameraActor SceneView::GetCamera(const std::string& name) const
146 {
147   CameraActor returnCamera;
148   for(auto&& camera : mCameras)
149   {
150     if(camera.GetProperty<std::string>(Actor::Property::NAME) == name)
151     {
152       returnCamera = camera;
153       break;
154     }
155   }
156   return returnCamera;
157 }
158
159 void SceneView::SelectCamera(uint32_t index)
160 {
161   UpdateCamera(GetCamera(index));
162 }
163
164 void SceneView::SelectCamera(const std::string& name)
165 {
166   UpdateCamera(GetCamera(name));
167 }
168
169 void SceneView::RegisterModel(Scene3D::Model model)
170 {
171   if(model)
172   {
173     model.SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
174     mModels.push_back(model);
175   }
176 }
177
178 void SceneView::UnregisterModel(Scene3D::Model model)
179 {
180   if(model)
181   {
182     for(uint32_t i = 0; i < mModels.size(); ++i)
183     {
184       if(mModels[i] == model)
185       {
186         mModels.erase(mModels.begin() + i);
187         break;
188       }
189     }
190   }
191 }
192
193 void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
194 {
195   mIBLResourceReady      = false;
196   Texture diffuseTexture = Dali::Scene3D::Loader::LoadCubeMap(diffuseUrl);
197   if(diffuseTexture)
198   {
199     Texture specularTexture = Dali::Scene3D::Loader::LoadCubeMap(specularUrl);
200     if(specularTexture)
201     {
202       mDiffuseTexture  = diffuseTexture;
203       mSpecularTexture = specularTexture;
204       mIblScaleFactor  = scaleFactor;
205
206       for(auto&& model : mModels)
207       {
208         if(model)
209         {
210           model.SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
211         }
212       }
213     }
214   }
215   mIBLResourceReady = true;
216   Control::SetResourceReady(false);
217 }
218
219 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
220 {
221   mIblScaleFactor = scaleFactor;
222   for(auto&& model : mModels)
223   {
224     if(model)
225     {
226       model.SetImageBasedLightScaleFactor(scaleFactor);
227     }
228   }
229 }
230
231 float SceneView::GetImageBasedLightScaleFactor() const
232 {
233   return mIblScaleFactor;
234 }
235
236 void SceneView::UseFramebuffer(bool useFramebuffer)
237 {
238   if(mUseFrameBuffer != useFramebuffer)
239   {
240     mUseFrameBuffer = useFramebuffer;
241     UpdateRenderTask();
242   }
243 }
244
245 bool SceneView::IsUsingFramebuffer() const
246 {
247   return mUseFrameBuffer;
248 }
249
250 ///////////////////////////////////////////////////////////
251 //
252 // Private methods
253 //
254
255 void SceneView::OnSceneConnection(int depth)
256 {
257   UpdateRenderTask();
258
259   Window window = DevelWindow::Get(Self());
260   if(window)
261   {
262     window.ResizeSignal().Connect(this, &SceneView::OnWindowResized);
263   }
264
265   Control::OnSceneConnection(depth);
266 }
267
268 void SceneView::OnSceneDisconnection()
269 {
270   mModels.clear();
271
272   Window window = DevelWindow::Get(Self());
273   if(window)
274   {
275     window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized);
276   }
277
278   Control::OnSceneDisconnection();
279 }
280
281 void SceneView::OnInitialize()
282 {
283   Actor self = Self();
284   mRootLayer = Layer::New();
285   mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
286   mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true);
287   // The models in the SceneView should be have independent coordinate with DALi default coordinate.
288   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false);
289   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false);
290   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false);
291   self.Add(mRootLayer);
292
293   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
294   mRenderTask             = taskList.CreateTask();
295   mRenderTask.SetSourceActor(mRootLayer);
296   mRenderTask.SetExclusive(true);
297   mRenderTask.SetInputEnabled(true);
298   mRenderTask.SetCullMode(false);
299   mRenderTask.SetScreenToFrameBufferMappingActor(Self());
300
301   mDefaultCamera = Dali::CameraActor::New();
302   mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
303   mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
304   mDefaultCamera.SetNearClippingPlane(1.0f);
305   AddCamera(mDefaultCamera);
306   UpdateCamera(mDefaultCamera);
307 }
308
309 void SceneView::OnChildAdd(Actor& child)
310 {
311   if(child != mRootLayer)
312   {
313     mRootLayer.Add(child);
314   }
315   Control::OnChildAdd(child);
316 }
317
318 void SceneView::OnChildRemove(Actor& child)
319 {
320   mRootLayer.Remove(child);
321   Control::OnChildRemove(child);
322 }
323
324 float SceneView::GetHeightForWidth(float width)
325 {
326   Extents padding;
327   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
328   return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
329 }
330
331 float SceneView::GetWidthForHeight(float height)
332 {
333   Extents padding;
334   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
335   return Control::GetWidthForHeight(height) + padding.start + padding.end;
336 }
337
338 void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container)
339 {
340   Control::OnRelayout(size, container);
341   // Change canvas size of camera actor.
342   UpdateRenderTask();
343 }
344
345 bool SceneView::IsResourceReady() const
346 {
347   return mIBLResourceReady;
348 }
349
350 void SceneView::UpdateCamera(CameraActor camera)
351 {
352   if(camera)
353   {
354     if(mSelectedCamera && mSelectedCamera.GetParent())
355     {
356       mSelectedCamera.Unparent();
357     }
358     mRootLayer.Add(camera);
359   }
360
361   mSelectedCamera = camera;
362   UpdateRenderTask();
363 }
364
365 void SceneView::UpdateRenderTask()
366 {
367   if(mRenderTask)
368   {
369     if(mSelectedCamera != mRenderTask.GetCameraActor())
370     {
371       mRenderTask.SetCameraActor(mSelectedCamera);
372     }
373
374     Vector3     size        = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
375     const float aspectRatio = size.width / size.height;
376     mSelectedCamera.SetAspectRatio(aspectRatio);
377     const float halfHeight                                              = mSelectedCamera[Dali::CameraActor::Property::TOP_PLANE_DISTANCE];
378     const float halfWidth                                               = aspectRatio * halfHeight;
379     mSelectedCamera[Dali::CameraActor::Property::LEFT_PLANE_DISTANCE]   = -halfWidth;
380     mSelectedCamera[Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE]  = halfWidth;
381     mSelectedCamera[Dali::CameraActor::Property::TOP_PLANE_DISTANCE]    = halfHeight;  // Top is +ve to keep consistency with orthographic values
382     mSelectedCamera[Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE] = -halfHeight; // Bottom is -ve to keep consistency with orthographic values
383     if(mUseFrameBuffer)
384     {
385       Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
386       if(!currentFrameBuffer ||
387          currentFrameBuffer.GetColorTexture().GetWidth() != size.width ||
388          currentFrameBuffer.GetColorTexture().GetHeight() != size.height)
389       {
390         mRenderTask.ResetViewportGuideActor();
391         mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
392
393         // create offscreen buffer of new size to render our child actors to
394         mTexture      = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height));
395         mRenderTarget = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
396         mRenderTarget.AttachColorTexture(mTexture);
397         Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mRenderTarget, 0u);
398
399         Property::Map imagePropertyMap;
400         imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
401         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
402         // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling.
403         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f));
404         mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap);
405
406         Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
407
408         mRenderTask.SetFrameBuffer(mRenderTarget);
409         mRenderTask.SetClearEnabled(true);
410         mRenderTask.SetClearColor(Color::TRANSPARENT);
411       }
412     }
413     else
414     {
415       mRenderTask.SetViewportGuideActor(Self());
416       if(mRenderTask.GetFrameBuffer())
417       {
418         FrameBuffer framebuffer;
419         mRenderTask.SetFrameBuffer(framebuffer);
420         mRenderTask.SetClearEnabled(false);
421
422         Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
423
424         mVisual.Reset();
425         mRenderTarget.Reset();
426         mTexture.Reset();
427       }
428     }
429
430     RotateCamera();
431   }
432 }
433
434 void SceneView::OnWindowResized(Window window, Window::WindowSize size)
435 {
436   mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
437   RotateCamera();
438 }
439
440 void SceneView::RotateCamera()
441 {
442   if(mUseFrameBuffer)
443   {
444     DevelCameraActor::RotateProjection(mSelectedCamera, DEFAULT_ORIENTATION);
445   }
446   else
447   {
448     DevelCameraActor::RotateProjection(mSelectedCamera, mWindowOrientation);
449   }
450 }
451
452 } // namespace Internal
453 } // namespace Scene3D
454 } // namespace Dali