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