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