Merge "Makes Models use common shader manager" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / controls / scene-view / scene-view-impl.cpp
1 /*
2  * Copyright (c) 2023 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/devel-api/rendering/frame-buffer-devel.h>
32 #include <dali/integration-api/adaptor-framework/adaptor.h>
33 #include <dali/integration-api/debug.h>
34 #include <dali/public-api/math/math-utils.h>
35 #include <dali/public-api/object/type-registry-helper.h>
36 #include <dali/public-api/object/type-registry.h>
37 #include <string_view>
38
39 // INTERNAL INCLUDES
40 #include <dali-scene3d/internal/controls/model/model-impl.h>
41 #include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
42 #include <dali-scene3d/internal/light/light-impl.h>
43
44 using namespace Dali;
45
46 namespace Dali
47 {
48 namespace Scene3D
49 {
50 namespace Internal
51 {
52 namespace
53 {
54 BaseHandle Create()
55 {
56   return Scene3D::SceneView::New();
57 }
58
59 // Setup properties, signals and actions using the type-registry.
60 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::SceneView, Toolkit::Control, Create);
61 DALI_TYPE_REGISTRATION_END()
62
63 Property::Index   RENDERING_BUFFER    = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1;
64 constexpr int32_t DEFAULT_ORIENTATION = 0;
65 constexpr int32_t INVALID_INDEX       = -1;
66
67 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
68
69 Dali::Actor CreateSkybox()
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::Shader   shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
133   Dali::Renderer skyboxRenderer;
134   skyboxRenderer = Renderer::New(skyboxGeometry, shaderSkybox);
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   mShaderManager(new Scene3D::Loader::ShaderManager())
158 {
159 }
160
161 SceneView::~SceneView()
162 {
163   if(Dali::Adaptor::IsAvailable())
164   {
165     if(mIblDiffuseLoadTask)
166     {
167       Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
168       mIblDiffuseLoadTask.Reset();
169     }
170     if(mIblSpecularLoadTask)
171     {
172       Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
173       mIblSpecularLoadTask.Reset();
174     }
175     if(mSkyboxLoadTask)
176     {
177       Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
178       mSkyboxLoadTask.Reset();
179     }
180   }
181 }
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::LightObserver* item)
280 {
281   if(item)
282   {
283     item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
284
285     if(mActivatedLightCount > 0)
286     {
287       uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
288       for(uint32_t i = 0; i < maxLightCount; ++i)
289       {
290         if(mActivatedLights[i])
291         {
292           item->NotifyLightAdded(i, mActivatedLights[i]);
293         }
294       }
295     }
296     mItems.push_back(item);
297   }
298 }
299
300 void SceneView::UnregisterSceneItem(Scene3D::Internal::LightObserver* item)
301 {
302   if(item)
303   {
304     for(uint32_t i = 0; i < mItems.size(); ++i)
305     {
306       if(mItems[i] == item)
307       {
308         if(mActivatedLightCount > 0)
309         {
310           uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
311           for(uint32_t i = 0; i < maxLightCount; ++i)
312           {
313             if(mActivatedLights[i])
314             {
315               item->NotifyLightRemoved(i);
316             }
317           }
318         }
319         mItems.erase(mItems.begin() + i);
320         break;
321       }
322     }
323   }
324 }
325
326 void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
327 {
328   bool needIblReset = false;
329   bool isOnScene    = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
330   if(mDiffuseIblUrl != diffuseUrl)
331   {
332     mDiffuseIblUrl = diffuseUrl;
333     if(mDiffuseIblUrl.empty())
334     {
335       needIblReset = true;
336     }
337     else
338     {
339       mIblDiffuseDirty         = true;
340       mIblDiffuseResourceReady = false;
341     }
342   }
343
344   if(mSpecularIblUrl != specularUrl)
345   {
346     mSpecularIblUrl = specularUrl;
347     if(mSpecularIblUrl.empty())
348     {
349       needIblReset = true;
350     }
351     else
352     {
353       mIblSpecularDirty         = true;
354       mIblSpecularResourceReady = false;
355     }
356   }
357
358   // If one or both of diffuse url and specular url are empty,
359   // we don't need to request to load texture.
360   if(needIblReset)
361   {
362     if(mIblDiffuseLoadTask)
363     {
364       Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
365       mIblDiffuseLoadTask.Reset();
366     }
367
368     if(mIblSpecularLoadTask)
369     {
370       Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
371       mIblSpecularLoadTask.Reset();
372     }
373
374     mIblDiffuseDirty          = false;
375     mIblSpecularDirty         = false;
376     mIblDiffuseResourceReady  = true;
377     mIblSpecularResourceReady = true;
378
379     mDiffuseTexture.Reset();
380     mSpecularTexture.Reset();
381
382     mSpecularMipmapLevels = 1u;
383     NotifyImageBasedLightTextureChange();
384   }
385   else
386   {
387     if(isOnScene && mIblDiffuseDirty)
388     {
389       if(mIblDiffuseLoadTask)
390       {
391         Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
392         mIblDiffuseLoadTask.Reset();
393       }
394       mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblDiffuseLoadComplete));
395       Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
396       mIblDiffuseDirty = false;
397     }
398
399     if(isOnScene && mIblSpecularDirty)
400     {
401       if(mIblSpecularLoadTask)
402       {
403         Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
404         mIblSpecularLoadTask.Reset();
405       }
406       mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblSpecularLoadComplete));
407       Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
408       mIblSpecularDirty = false;
409     }
410   }
411
412   if(!Dali::Equals(mIblScaleFactor, scaleFactor))
413   {
414     SetImageBasedLightScaleFactor(scaleFactor);
415   }
416
417   // If diffuse and specular textures are already loaded, emits resource ready signal here.
418   if(IsResourceReady())
419   {
420     Control::SetResourceReady();
421   }
422 }
423
424 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
425 {
426   mIblScaleFactor = scaleFactor;
427   for(auto&& item : mItems)
428   {
429     if(item)
430     {
431       item->NotifyImageBasedLightScaleFactor(scaleFactor);
432     }
433   }
434 }
435
436 float SceneView::GetImageBasedLightScaleFactor() const
437 {
438   return mIblScaleFactor;
439 }
440
441 void SceneView::AddLight(Scene3D::Light light)
442 {
443   bool enabled = AddLightInternal(light);
444   mLights.push_back(std::make_pair(light, enabled));
445 }
446
447 void SceneView::RemoveLight(Scene3D::Light light)
448 {
449   if(mActivatedLights.empty())
450   {
451     return;
452   }
453
454   bool needToDisable = false;
455   for(uint32_t i = 0; i < mLights.size(); ++i)
456   {
457     if(mLights[i].first == light)
458     {
459       // If mLights[i].second is true, it means the light is currently activated in Scene.
460       // Then it should be removed from mActivatedLights list too.
461       needToDisable = mLights[i].second;
462       mLights.erase(mLights.begin() + i);
463       break;
464     }
465   }
466
467   uint32_t maxNumberOfLight = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
468   if(needToDisable)
469   {
470     uint32_t removedIndex = RemoveLightInternal(light);
471     if(mActivatedLightCount < maxNumberOfLight && mLights.size() >= maxNumberOfLight)
472     {
473       for(auto&& lightItem : mLights)
474       {
475         if(lightItem.second == false)
476         {
477           lightItem.second = AddLightInternal(lightItem.first);
478           break;
479         }
480       }
481     }
482
483     // To remove empty entity of mActivatedLights, moves last object to empty position.
484     // Because one Light is removed, mActivatedLights[mActivatedLightCount] is current last object of the list.
485     if(!mActivatedLights[removedIndex] && mActivatedLightCount > 0 && removedIndex < mActivatedLightCount)
486     {
487       Scene3D::Light reorderingLight = mActivatedLights[mActivatedLightCount];
488       RemoveLightInternal(reorderingLight);
489       AddLightInternal(reorderingLight);
490     }
491   }
492 }
493
494 uint32_t SceneView::GetActivatedLightCount() const
495 {
496   return mActivatedLightCount;
497 }
498
499 void SceneView::UseFramebuffer(bool useFramebuffer)
500 {
501   if(mUseFrameBuffer != useFramebuffer)
502   {
503     mUseFrameBuffer = useFramebuffer;
504     UpdateRenderTask();
505   }
506 }
507
508 bool SceneView::IsUsingFramebuffer() const
509 {
510   return mUseFrameBuffer;
511 }
512
513 void SceneView::SetFramebufferMultiSamplingLevel(uint8_t multiSamplingLevel)
514 {
515   if(mFrameBufferMultiSamplingLevel != multiSamplingLevel)
516   {
517     mFrameBufferMultiSamplingLevel = multiSamplingLevel;
518
519     // Create new framebuffer with changed multiSamplingLevel.
520     if(mRenderTask && mFrameBuffer && mTexture)
521     {
522       Vector3 size = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
523
524       mFrameBuffer = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
525       mFrameBuffer.AttachColorTexture(mTexture);
526       DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
527       mRenderTask.SetFrameBuffer(mFrameBuffer);
528
529       // Note : we don't need to create new visual since visual's url is depend on mTexture.
530     }
531   }
532 }
533
534 uint8_t SceneView::GetFramebufferMultiSamplingLevel() const
535 {
536   return mFrameBufferMultiSamplingLevel;
537 }
538
539 void SceneView::SetSkybox(const std::string& skyboxUrl)
540 {
541   if(mSkyboxUrl != skyboxUrl)
542   {
543     UpdateSkybox(skyboxUrl, mSkyboxEnvironmentMapType);
544   }
545 }
546
547 void SceneView::SetSkyboxEnvironmentMapType(Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
548 {
549   if(mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
550   {
551     UpdateSkybox(mSkyboxUrl, skyboxEnvironmentMapType);
552   }
553 }
554
555 void SceneView::SetSkyboxIntensity(float intensity)
556 {
557   mSkyboxIntensity = intensity;
558   if(intensity < 0)
559   {
560     DALI_LOG_ERROR("Intensity should be greater than or equal to 0.\n");
561     mSkyboxIntensity = 0.0f;
562   }
563
564   if(mSkybox)
565   {
566     mSkybox.RegisterProperty(SKYBOX_INTENSITY_STRING.data(), mSkyboxIntensity);
567   }
568 }
569
570 float SceneView::GetSkyboxIntensity() const
571 {
572   return mSkyboxIntensity;
573 }
574
575 void SceneView::SetSkyboxOrientation(const Quaternion& orientation)
576 {
577   mSkyboxOrientation = orientation;
578   if(mSkybox)
579   {
580     mSkybox.SetProperty(Dali::Actor::Property::ORIENTATION, orientation);
581   }
582 }
583
584 Quaternion SceneView::GetSkyboxOrientation() const
585 {
586   return mSkyboxOrientation;
587 }
588
589 Dali::Scene3D::Loader::ShaderManagerPtr SceneView::GetShaderManager() const
590 {
591   return mShaderManager;
592 }
593
594 ///////////////////////////////////////////////////////////
595 //
596 // Private methods
597 //
598
599 void SceneView::OnSceneConnection(int depth)
600 {
601   // If diffuse and specular url is not valid, IBL does not need to be loaded.
602   if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
603   {
604     SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
605   }
606
607   if(!mSkyboxUrl.empty())
608   {
609     UpdateSkybox(mSkyboxUrl, mSkyboxEnvironmentMapType);
610   }
611
612   Window window = DevelWindow::Get(Self());
613   if(window)
614   {
615     // Only for on-screen window
616     window.ResizeSignal().Connect(this, &SceneView::OnWindowResized);
617
618     mWindow            = window;
619     mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
620   }
621
622   // On-screen / Off-screen window
623   mSceneHolder = Integration::SceneHolder::Get(Self());
624   if(mSceneHolder)
625   {
626     RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
627     mRenderTask             = taskList.CreateTask();
628     mRenderTask.SetSourceActor(mRootLayer);
629     mRenderTask.SetExclusive(true);
630     mRenderTask.SetInputEnabled(true);
631     mRenderTask.SetCullMode(false);
632     mRenderTask.SetScreenToFrameBufferMappingActor(Self());
633
634     UpdateRenderTask();
635   }
636
637   Control::OnSceneConnection(depth);
638 }
639
640 void SceneView::OnSceneDisconnection()
641 {
642   mItems.clear();
643
644   Window window = mWindow.GetHandle();
645   if(window)
646   {
647     window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized);
648   }
649   mWindow.Reset();
650
651   if(mSceneHolder)
652   {
653     if(mRenderTask)
654     {
655       RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
656       taskList.RemoveTask(mRenderTask);
657       mRenderTask.Reset();
658     }
659     mSceneHolder.Reset();
660   }
661   mFrameBuffer.Reset();
662
663   Control::OnSceneDisconnection();
664 }
665
666 void SceneView::OnInitialize()
667 {
668   Actor self = Self();
669   mRootLayer = Layer::New();
670   mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
671   mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true);
672   // The models in the SceneView should be have independent coordinate with DALi default coordinate.
673   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false);
674   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false);
675   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false);
676   self.Add(mRootLayer);
677
678   mDefaultCamera = Dali::CameraActor::New3DCamera();
679   mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
680   mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
681   AddCamera(mDefaultCamera);
682   UpdateCamera(mDefaultCamera);
683 }
684
685 void SceneView::OnChildAdd(Actor& child)
686 {
687   if(child != mRootLayer)
688   {
689     mRootLayer.Add(child);
690   }
691   Control::OnChildAdd(child);
692 }
693
694 void SceneView::OnChildRemove(Actor& child)
695 {
696   mRootLayer.Remove(child);
697   Control::OnChildRemove(child);
698 }
699
700 float SceneView::GetHeightForWidth(float width)
701 {
702   Extents padding;
703   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
704   return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
705 }
706
707 float SceneView::GetWidthForHeight(float height)
708 {
709   Extents padding;
710   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
711   return Control::GetWidthForHeight(height) + padding.start + padding.end;
712 }
713
714 void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container)
715 {
716   Control::OnRelayout(size, container);
717   // Change canvas size of camera actor.
718   UpdateRenderTask();
719 }
720
721 bool SceneView::IsResourceReady() const
722 {
723   return mIblDiffuseResourceReady && mIblSpecularResourceReady && mSkyboxResourceReady;
724 }
725
726 void SceneView::UpdateCamera(CameraActor camera)
727 {
728   if(camera)
729   {
730     if(mSelectedCamera && mSelectedCamera.GetParent())
731     {
732       mSelectedCamera.Unparent();
733     }
734     mRootLayer.Add(camera);
735   }
736
737   mSelectedCamera = camera;
738   UpdateRenderTask();
739 }
740
741 void SceneView::UpdateRenderTask()
742 {
743   if(mRenderTask)
744   {
745     if(mSelectedCamera != mRenderTask.GetCameraActor())
746     {
747       mRenderTask.SetCameraActor(mSelectedCamera);
748     }
749
750     Vector3     size        = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
751     const float aspectRatio = size.width / size.height;
752     mSelectedCamera.SetAspectRatio(aspectRatio);
753
754     if(mUseFrameBuffer)
755     {
756       Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
757       if(!currentFrameBuffer ||
758          !Dali::Equals(currentFrameBuffer.GetColorTexture().GetWidth(), size.width) ||
759          !Dali::Equals(currentFrameBuffer.GetColorTexture().GetHeight(), size.height))
760       {
761         mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_COLOR);
762         mRenderTask.ResetViewportGuideActor();
763         mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
764
765         // create offscreen buffer of new size to render our child actors to
766         mTexture     = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height));
767         mFrameBuffer = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
768         mFrameBuffer.AttachColorTexture(mTexture);
769         DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
770         Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mFrameBuffer, 0u);
771
772         Property::Map imagePropertyMap;
773         imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
774         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
775         // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling.
776         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f));
777         mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap);
778
779         Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
780
781         mRenderTask.SetFrameBuffer(mFrameBuffer);
782         mRenderTask.SetClearEnabled(true);
783         mRenderTask.SetClearColor(Color::TRANSPARENT);
784       }
785     }
786     else
787     {
788       mRenderTask.SetViewportGuideActor(Self());
789       if(mRenderTask.GetFrameBuffer())
790       {
791         mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA);
792         FrameBuffer framebuffer;
793         mRenderTask.SetFrameBuffer(framebuffer);
794         mRenderTask.SetClearEnabled(false);
795
796         Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
797
798         mVisual.Reset();
799         mFrameBuffer.Reset();
800         mTexture.Reset();
801       }
802     }
803
804     RotateCamera();
805   }
806 }
807
808 void SceneView::OnWindowResized(Window window, Window::WindowSize size)
809 {
810   mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
811   RotateCamera();
812 }
813
814 void SceneView::RotateCamera()
815 {
816   if(mUseFrameBuffer)
817   {
818     DevelCameraActor::RotateProjection(mSelectedCamera, DEFAULT_ORIENTATION);
819   }
820   else
821   {
822     DevelCameraActor::RotateProjection(mSelectedCamera, mWindowOrientation);
823   }
824 }
825
826 void SceneView::UpdateSkybox(const std::string& skyboxUrl, Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
827 {
828   bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
829   if(mSkyboxUrl != skyboxUrl || mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
830   {
831     mSkyboxDirty              = true;
832     mSkyboxResourceReady      = false;
833     mSkyboxUrl                = skyboxUrl;
834     mSkyboxEnvironmentMapType = skyboxEnvironmentMapType;
835   }
836
837   if(mSkyboxUrl.empty())
838   {
839     if(mSkyboxLoadTask)
840     {
841       Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
842       mSkyboxLoadTask.Reset();
843     }
844
845     if(mSkybox)
846     {
847       mSkybox.Unparent();
848       mSkybox.Reset();
849       mSkyboxTexture.Reset();
850     }
851
852     mSkyboxDirty         = false;
853     mSkyboxResourceReady = true;
854   }
855   else
856   {
857     if(isOnScene && mSkyboxDirty)
858     {
859       if(mSkyboxLoadTask)
860       {
861         Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
862         mSkyboxLoadTask.Reset();
863       }
864
865       mSkyboxLoadTask = new EnvironmentMapLoadTask(mSkyboxUrl, mSkyboxEnvironmentMapType, MakeCallback(this, &SceneView::OnSkyboxLoadComplete));
866       Dali::AsyncTaskManager::Get().AddTask(mSkyboxLoadTask);
867       mSkyboxDirty = false;
868     }
869   }
870
871   if(IsResourceReady())
872   {
873     Control::SetResourceReady();
874   }
875 }
876
877 void SceneView::OnSkyboxLoadComplete()
878 {
879   if(!mSkybox)
880   {
881     mSkybox = CreateSkybox();
882     SetSkyboxIntensity(mSkyboxIntensity);
883     SetSkyboxOrientation(mSkyboxOrientation);
884     if(mRootLayer)
885     {
886       mRootLayer.Add(mSkybox);
887     }
888   }
889
890   mSkyboxResourceReady = true;
891   if(IsResourceReady())
892   {
893     Control::SetResourceReady();
894   }
895
896   mSkyboxTexture = mSkyboxLoadTask->GetLoadedTexture();
897   Shader skyboxShader;
898   if(mSkyboxLoadTask->GetEnvironmentMapType() == Scene3D::EnvironmentMapType::CUBEMAP)
899   {
900     skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
901   }
902   else
903   {
904     skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_EQUIRECTANGULAR_SHADER_FRAG.data());
905   }
906
907   Renderer skyboxRenderer = (mSkybox.GetRendererCount() > 0u) ? mSkybox.GetRendererAt(0u) : Renderer();
908   if(skyboxRenderer)
909   {
910     Dali::TextureSet skyboxTextures = TextureSet::New();
911     skyboxTextures.SetTexture(0, mSkyboxTexture);
912     skyboxRenderer.SetTextures(skyboxTextures);
913     skyboxRenderer.SetShader(skyboxShader);
914   }
915
916   mSkyboxLoadTask.Reset();
917 }
918
919 void SceneView::OnIblDiffuseLoadComplete()
920 {
921   mDiffuseTexture          = mIblDiffuseLoadTask->GetLoadedTexture();
922   mIblDiffuseResourceReady = true;
923   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
924   {
925     OnIblLoadComplete();
926   }
927   mIblDiffuseLoadTask.Reset();
928 }
929
930 void SceneView::OnIblSpecularLoadComplete()
931 {
932   mSpecularTexture          = mIblSpecularLoadTask->GetLoadedTexture();
933   mSpecularMipmapLevels     = mIblSpecularLoadTask->GetMipmapLevels();
934   mIblSpecularResourceReady = true;
935   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
936   {
937     OnIblLoadComplete();
938   }
939   mIblSpecularLoadTask.Reset();
940 }
941
942 void SceneView::OnIblLoadComplete()
943 {
944   NotifyImageBasedLightTextureChange();
945   if(IsResourceReady())
946   {
947     Control::SetResourceReady();
948   }
949 }
950
951 void SceneView::NotifyImageBasedLightTextureChange()
952 {
953   for(auto&& item : mItems)
954   {
955     if(item)
956     {
957       item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
958     }
959   }
960 }
961
962 bool SceneView::AddLightInternal(Scene3D::Light light)
963 {
964   uint32_t maxNumberOfLight = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
965   if(mActivatedLightCount == 0)
966   {
967     mActivatedLights.resize(maxNumberOfLight);
968   }
969
970   bool enabled = false;
971   if(mActivatedLightCount < maxNumberOfLight)
972   {
973     uint32_t newLightIndex = 0u;
974     for(; newLightIndex < maxNumberOfLight; ++newLightIndex)
975     {
976       if(!mActivatedLights[newLightIndex])
977       {
978         mActivatedLights[newLightIndex] = light;
979         break;
980       }
981     }
982
983     for(auto&& item : mItems)
984     {
985       if(item)
986       {
987         item->NotifyLightAdded(newLightIndex, light);
988       }
989     }
990
991     mActivatedLightCount++;
992     enabled = true;
993   }
994   return enabled;
995 }
996
997 int32_t SceneView::RemoveLightInternal(Scene3D::Light light)
998 {
999   int32_t  removedIndex     = INVALID_INDEX;
1000   uint32_t maxNumberOfLight = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
1001   for(uint32_t i = 0; i < maxNumberOfLight; ++i)
1002   {
1003     if(mActivatedLights[i] == light)
1004     {
1005       for(auto&& item : mItems)
1006       {
1007         if(item)
1008         {
1009           item->NotifyLightRemoved(i);
1010         }
1011       }
1012       mActivatedLights[i].Reset();
1013       mActivatedLightCount--;
1014       removedIndex = i;
1015       break;
1016     }
1017   }
1018
1019   return removedIndex;
1020 }
1021
1022 } // namespace Internal
1023 } // namespace Scene3D
1024 } // namespace Dali