1457e19f49d1efa2fe1dbed5516988a1c96ea720
[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 #include <string_view>
35
36 // INTERNAL INCLUDES
37 #include <dali-scene3d/internal/controls/model/model-impl.h>
38 #include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
39 #include <dali-scene3d/public-api/loader/cube-map-loader.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 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
64
65 Dali::Actor CreateSkybox(const std::string& skyboxUrl)
66 {
67   struct Vertex
68   {
69     Vector3 aPosition;
70   };
71
72   Vertex skyboxVertices[] = {
73     // back
74     {Vector3(-1.0f, 1.0f, -1.0f)},
75     {Vector3(-1.0f, -1.0f, -1.0f)},
76     {Vector3(1.0f, -1.0f, -1.0f)},
77     {Vector3(1.0f, -1.0f, -1.0f)},
78     {Vector3(1.0f, 1.0f, -1.0f)},
79     {Vector3(-1.0f, 1.0f, -1.0f)},
80
81     // left
82     {Vector3(-1.0f, -1.0f, 1.0f)},
83     {Vector3(-1.0f, -1.0f, -1.0f)},
84     {Vector3(-1.0f, 1.0f, -1.0f)},
85     {Vector3(-1.0f, 1.0f, -1.0f)},
86     {Vector3(-1.0f, 1.0f, 1.0f)},
87     {Vector3(-1.0f, -1.0f, 1.0f)},
88
89     // right
90     {Vector3(1.0f, -1.0f, -1.0f)},
91     {Vector3(1.0f, -1.0f, 1.0f)},
92     {Vector3(1.0f, 1.0f, 1.0f)},
93     {Vector3(1.0f, 1.0f, 1.0f)},
94     {Vector3(1.0f, 1.0f, -1.0f)},
95     {Vector3(1.0f, -1.0f, -1.0f)},
96
97     // front
98     {Vector3(-1.0f, -1.0f, 1.0f)},
99     {Vector3(-1.0f, 1.0f, 1.0f)},
100     {Vector3(1.0f, 1.0f, 1.0f)},
101     {Vector3(1.0f, 1.0f, 1.0f)},
102     {Vector3(1.0f, -1.0f, 1.0f)},
103     {Vector3(-1.0f, -1.0f, 1.0f)},
104
105     // botton
106     {Vector3(-1.0f, 1.0f, -1.0f)},
107     {Vector3(1.0f, 1.0f, -1.0f)},
108     {Vector3(1.0f, 1.0f, 1.0f)},
109     {Vector3(1.0f, 1.0f, 1.0f)},
110     {Vector3(-1.0f, 1.0f, 1.0f)},
111     {Vector3(-1.0f, 1.0f, -1.0f)},
112
113     // top
114     {Vector3(-1.0f, -1.0f, -1.0f)},
115     {Vector3(-1.0f, -1.0f, 1.0f)},
116     {Vector3(1.0f, -1.0f, -1.0f)},
117     {Vector3(1.0f, -1.0f, -1.0f)},
118     {Vector3(-1.0f, -1.0f, 1.0f)},
119     {Vector3(1.0f, -1.0f, 1.0f)}};
120
121   Dali::Shader       shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
122   Dali::VertexBuffer vertexBuffer = Dali::VertexBuffer::New(Property::Map().Add("aPosition", Property::VECTOR3));
123   vertexBuffer.SetData(skyboxVertices, sizeof(skyboxVertices) / sizeof(Vertex));
124
125   Dali::Geometry skyboxGeometry = Geometry::New();
126   skyboxGeometry.AddVertexBuffer(vertexBuffer);
127   skyboxGeometry.SetType(Geometry::TRIANGLES);
128
129   Dali::Texture    skyboxTexture  = Dali::Scene3D::Loader::LoadCubeMap(skyboxUrl);
130   Dali::TextureSet skyboxTextures = TextureSet::New();
131   skyboxTextures.SetTexture(0, skyboxTexture);
132
133   Dali::Renderer skyboxRenderer = Renderer::New(skyboxGeometry, shaderSkybox);
134   skyboxRenderer.SetTextures(skyboxTextures);
135   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f);
136   // Enables the depth test.
137   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
138   // The fragment shader will run only is those pixels that have the max depth value.
139   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_FUNCTION, DepthFunction::LESS_EQUAL);
140
141   Dali::Actor skyboxActor = Actor::New();
142   skyboxActor.SetProperty(Dali::Actor::Property::NAME, "SkyBox");
143   skyboxActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
144   skyboxActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
145   skyboxActor.AddRenderer(skyboxRenderer);
146   return skyboxActor;
147 }
148
149 } // anonymous namespace
150
151 SceneView::SceneView()
152 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
153   mWindowOrientation(DEFAULT_ORIENTATION),
154   mSkybox(),
155   mSkyboxOrientation(Quaternion()),
156   mSkyboxIntensity(1.0f)
157 {
158 }
159
160 SceneView::~SceneView() = default;
161
162 Dali::Scene3D::SceneView SceneView::New()
163 {
164   SceneView* impl = new SceneView();
165
166   Dali::Scene3D::SceneView handle = Dali::Scene3D::SceneView(*impl);
167
168   // Second-phase init of the implementation
169   // This can only be done after the CustomActor connection has been made...
170   impl->Initialize();
171
172   return handle;
173 }
174
175 void SceneView::AddCamera(CameraActor camera)
176 {
177   if(camera)
178   {
179     if(mCameras.empty())
180     {
181       UpdateCamera(camera);
182     }
183     mCameras.push_back(camera);
184   }
185 }
186
187 void SceneView::RemoveCamera(CameraActor camera)
188 {
189   if(camera == mDefaultCamera)
190   {
191     DALI_LOG_ERROR("Default Camera cannot removed.\n");
192     return;
193   }
194
195   if(camera)
196   {
197     for(uint32_t i = 0; i < mCameras.size(); ++i)
198     {
199       if(mCameras[i] == camera)
200       {
201         mCameras.erase(mCameras.begin() + i);
202         break;
203       }
204     }
205
206     if(mSelectedCamera == camera)
207     {
208       CameraActor newCurrentCamera = *mCameras.begin();
209       UpdateCamera(newCurrentCamera);
210     }
211   }
212 }
213
214 uint32_t SceneView::GetCameraCount() const
215 {
216   return mCameras.size();
217 }
218
219 CameraActor SceneView::GetSelectedCamera() const
220 {
221   return mSelectedCamera;
222 }
223
224 CameraActor SceneView::GetCamera(uint32_t index) const
225 {
226   if(index < mCameras.size())
227   {
228     return mCameras[index];
229   }
230   DALI_LOG_ERROR("Input index is out of bounds\n");
231   return CameraActor();
232 }
233
234 CameraActor SceneView::GetCamera(const std::string& name) const
235 {
236   CameraActor returnCamera;
237   for(auto&& camera : mCameras)
238   {
239     if(camera.GetProperty<std::string>(Actor::Property::NAME) == name)
240     {
241       returnCamera = camera;
242       break;
243     }
244   }
245   return returnCamera;
246 }
247
248 void SceneView::SelectCamera(uint32_t index)
249 {
250   UpdateCamera(GetCamera(index));
251 }
252
253 void SceneView::SelectCamera(const std::string& name)
254 {
255   UpdateCamera(GetCamera(name));
256 }
257
258 void SceneView::RegisterSceneItem(Scene3D::Internal::ImageBasedLightObserver *item)
259 {
260   if(item)
261   {
262     item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
263     mItems.push_back(item);
264   }
265 }
266
267 void SceneView::UnregisterSceneItem(Scene3D::Internal::ImageBasedLightObserver *item)
268 {
269   if(item)
270   {
271     for(uint32_t i = 0; i < mItems.size(); ++i)
272     {
273       if(mItems[i] == item)
274       {
275         mItems.erase(mItems.begin() + i);
276         break;
277       }
278     }
279   }
280 }
281
282 void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
283 {
284   mIBLResourceReady = false;
285
286   // If url is empty or invalid, reset IBL.
287   mDiffuseTexture  = (!diffuseUrl.empty()) ? Dali::Scene3D::Loader::LoadCubeMap(diffuseUrl) : Texture();
288   mSpecularTexture = (!specularUrl.empty()) ? Dali::Scene3D::Loader::LoadCubeMap(specularUrl) : Texture();
289
290   mIblScaleFactor = scaleFactor;
291
292   for(auto&& item : mItems)
293   {
294     if(item)
295     {
296       item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
297     }
298   }
299
300   mIBLResourceReady = true;
301   if(IsResourceReady())
302   {
303     Control::SetResourceReady(false);
304   }
305 }
306
307 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
308 {
309   mIblScaleFactor = scaleFactor;
310   for(auto&& item : mItems)
311   {
312     if(item)
313     {
314       item->NotifyImageBasedLightScaleFactor(scaleFactor);
315     }
316   }
317 }
318
319 float SceneView::GetImageBasedLightScaleFactor() const
320 {
321   return mIblScaleFactor;
322 }
323
324 void SceneView::UseFramebuffer(bool useFramebuffer)
325 {
326   if(mUseFrameBuffer != useFramebuffer)
327   {
328     mUseFrameBuffer = useFramebuffer;
329     UpdateRenderTask();
330   }
331 }
332
333 bool SceneView::IsUsingFramebuffer() const
334 {
335   return mUseFrameBuffer;
336 }
337
338 void SceneView::SetSkybox(const std::string& skyboxUrl)
339 {
340   mSkyboxResourceReady = false;
341   if(mSkybox)
342   {
343     mSkybox.Unparent();
344     mSkybox.Reset();
345   }
346   mSkybox = CreateSkybox(skyboxUrl);
347   SetSkyboxIntensity(mSkyboxIntensity);
348   SetSkyboxOrientation(mSkyboxOrientation);
349   if(mRootLayer)
350   {
351     mRootLayer.Add(mSkybox);
352   }
353
354   mSkyboxResourceReady = true;
355   if(IsResourceReady())
356   {
357     Control::SetResourceReady(false);
358   }
359 }
360
361 void SceneView::SetSkyboxIntensity(float intensity)
362 {
363   mSkyboxIntensity = intensity;
364   if(intensity < 0)
365   {
366     DALI_LOG_ERROR("Intensity should be greater than or equal to 0.\n");
367     mSkyboxIntensity = 0.0f;
368   }
369
370   if(mSkybox)
371   {
372     mSkybox.RegisterProperty(SKYBOX_INTENSITY_STRING.data(), mSkyboxIntensity);
373   }
374 }
375
376 float SceneView::GetSkyboxIntensity() const
377 {
378   return mSkyboxIntensity;
379 }
380
381 void SceneView::SetSkyboxOrientation(const Quaternion& orientation)
382 {
383   mSkyboxOrientation = orientation;
384   if(mSkybox)
385   {
386     mSkybox.SetProperty(Dali::Actor::Property::ORIENTATION, orientation);
387   }
388 }
389
390 Quaternion SceneView::GetSkyboxOrientation() const
391 {
392   return mSkyboxOrientation;
393 }
394
395 ///////////////////////////////////////////////////////////
396 //
397 // Private methods
398 //
399
400 void SceneView::OnSceneConnection(int depth)
401 {
402   Window window = DevelWindow::Get(Self());
403   if(window)
404   {
405     window.ResizeSignal().Connect(this, &SceneView::OnWindowResized);
406     RenderTaskList taskList = window.GetRenderTaskList();
407     mRenderTask             = taskList.CreateTask();
408     mRenderTask.SetSourceActor(mRootLayer);
409     mRenderTask.SetExclusive(true);
410     mRenderTask.SetInputEnabled(true);
411     mRenderTask.SetCullMode(false);
412     mRenderTask.SetScreenToFrameBufferMappingActor(Self());
413
414     UpdateRenderTask();
415     mWindow = window;
416   }
417
418   Control::OnSceneConnection(depth);
419 }
420
421 void SceneView::OnSceneDisconnection()
422 {
423   mItems.clear();
424
425   Window window = mWindow.GetHandle();
426   if(window)
427   {
428     window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized);
429     RenderTaskList taskList = window.GetRenderTaskList();
430     if(mRenderTask)
431     {
432       taskList.RemoveTask(mRenderTask);
433       mRenderTarget.Reset();
434     }
435   }
436   mWindow.Reset();
437
438   Control::OnSceneDisconnection();
439 }
440
441 void SceneView::OnInitialize()
442 {
443   Actor self = Self();
444   mRootLayer = Layer::New();
445   mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
446   mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true);
447   // The models in the SceneView should be have independent coordinate with DALi default coordinate.
448   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false);
449   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false);
450   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false);
451   self.Add(mRootLayer);
452
453   mDefaultCamera = Dali::CameraActor::New();
454   mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
455   mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
456   mDefaultCamera.SetNearClippingPlane(1.0f);
457   AddCamera(mDefaultCamera);
458   UpdateCamera(mDefaultCamera);
459 }
460
461 void SceneView::OnChildAdd(Actor& child)
462 {
463   if(child != mRootLayer)
464   {
465     mRootLayer.Add(child);
466   }
467   Control::OnChildAdd(child);
468 }
469
470 void SceneView::OnChildRemove(Actor& child)
471 {
472   mRootLayer.Remove(child);
473   Control::OnChildRemove(child);
474 }
475
476 float SceneView::GetHeightForWidth(float width)
477 {
478   Extents padding;
479   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
480   return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
481 }
482
483 float SceneView::GetWidthForHeight(float height)
484 {
485   Extents padding;
486   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
487   return Control::GetWidthForHeight(height) + padding.start + padding.end;
488 }
489
490 void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container)
491 {
492   Control::OnRelayout(size, container);
493   // Change canvas size of camera actor.
494   UpdateRenderTask();
495 }
496
497 bool SceneView::IsResourceReady() const
498 {
499   return mIBLResourceReady & mSkyboxResourceReady;
500 }
501
502 void SceneView::UpdateCamera(CameraActor camera)
503 {
504   if(camera)
505   {
506     if(mSelectedCamera && mSelectedCamera.GetParent())
507     {
508       mSelectedCamera.Unparent();
509     }
510     mRootLayer.Add(camera);
511   }
512
513   mSelectedCamera = camera;
514   UpdateRenderTask();
515 }
516
517 void SceneView::UpdateRenderTask()
518 {
519   if(mRenderTask)
520   {
521     if(mSelectedCamera != mRenderTask.GetCameraActor())
522     {
523       mRenderTask.SetCameraActor(mSelectedCamera);
524     }
525
526     Vector3     size        = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
527     const float aspectRatio = size.width / size.height;
528     mSelectedCamera.SetAspectRatio(aspectRatio);
529
530     if(mUseFrameBuffer)
531     {
532       Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
533       if(!currentFrameBuffer ||
534          currentFrameBuffer.GetColorTexture().GetWidth() != size.width ||
535          currentFrameBuffer.GetColorTexture().GetHeight() != size.height)
536       {
537         mRenderTask.ResetViewportGuideActor();
538         mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
539
540         // create offscreen buffer of new size to render our child actors to
541         mTexture      = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height));
542         mRenderTarget = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
543         mRenderTarget.AttachColorTexture(mTexture);
544         Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mRenderTarget, 0u);
545
546         Property::Map imagePropertyMap;
547         imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
548         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
549         // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling.
550         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f));
551         mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap);
552
553         Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
554
555         mRenderTask.SetFrameBuffer(mRenderTarget);
556         mRenderTask.SetClearEnabled(true);
557         mRenderTask.SetClearColor(Color::TRANSPARENT);
558       }
559     }
560     else
561     {
562       mRenderTask.SetViewportGuideActor(Self());
563       if(mRenderTask.GetFrameBuffer())
564       {
565         FrameBuffer framebuffer;
566         mRenderTask.SetFrameBuffer(framebuffer);
567         mRenderTask.SetClearEnabled(false);
568
569         Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
570
571         mVisual.Reset();
572         mRenderTarget.Reset();
573         mTexture.Reset();
574       }
575     }
576
577     RotateCamera();
578   }
579 }
580
581 void SceneView::OnWindowResized(Window window, Window::WindowSize size)
582 {
583   mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
584   RotateCamera();
585 }
586
587 void SceneView::RotateCamera()
588 {
589   if(mUseFrameBuffer)
590   {
591     DevelCameraActor::RotateProjection(mSelectedCamera, DEFAULT_ORIENTATION);
592   }
593   else
594   {
595     DevelCameraActor::RotateProjection(mSelectedCamera, mWindowOrientation);
596   }
597 }
598
599 } // namespace Internal
600 } // namespace Scene3D
601 } // namespace Dali