DALi Version 2.2.11
[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/debug.h>
33 #include <dali/public-api/math/math-utils.h>
34 #include <dali/public-api/object/type-registry-helper.h>
35 #include <dali/public-api/object/type-registry.h>
36 #include <dali/integration-api/adaptor-framework/adaptor.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
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()
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::ImageBasedLightObserver* item)
279 {
280   if(item)
281   {
282     item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
283     mItems.push_back(item);
284   }
285 }
286
287 void SceneView::UnregisterSceneItem(Scene3D::Internal::ImageBasedLightObserver* item)
288 {
289   if(item)
290   {
291     for(uint32_t i = 0; i < mItems.size(); ++i)
292     {
293       if(mItems[i] == item)
294       {
295         mItems.erase(mItems.begin() + i);
296         break;
297       }
298     }
299   }
300 }
301
302 void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
303 {
304   bool needIblReset = false;
305   bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
306   if(mDiffuseIblUrl != diffuseUrl)
307   {
308     mDiffuseIblUrl = diffuseUrl;
309     if(mDiffuseIblUrl.empty())
310     {
311       needIblReset             = true;
312     }
313     else
314     {
315       mIblDiffuseDirty         = true;
316       mIblDiffuseResourceReady = false;
317     }
318   }
319
320   if(mSpecularIblUrl != specularUrl)
321   {
322     mSpecularIblUrl = specularUrl;
323     if(mSpecularIblUrl.empty())
324     {
325       needIblReset              = true;
326     }
327     else
328     {
329       mIblSpecularDirty         = true;
330       mIblSpecularResourceReady = false;
331     }
332   }
333
334   // If one or both of diffuse url and specular url are empty,
335   // we don't need to request to load texture.
336   if(needIblReset)
337   {
338     if(mIblDiffuseLoadTask)
339     {
340       Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
341       mIblDiffuseLoadTask.Reset();
342     }
343
344     if(mIblSpecularLoadTask)
345     {
346       Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
347       mIblSpecularLoadTask.Reset();
348     }
349
350     mIblDiffuseDirty          = false;
351     mIblSpecularDirty         = false;
352     mIblDiffuseResourceReady  = true;
353     mIblSpecularResourceReady = true;
354
355     mDiffuseTexture.Reset();
356     mSpecularTexture.Reset();
357
358     NotifyImageBasedLightTextureChange();
359   }
360   else
361   {
362     if(isOnScene && mIblDiffuseDirty)
363     {
364       if(mIblDiffuseLoadTask)
365       {
366         Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
367         mIblDiffuseLoadTask.Reset();
368       }
369       mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblDiffuseLoadComplete));
370       Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
371       mIblDiffuseDirty = false;
372     }
373
374     if(isOnScene && mIblSpecularDirty)
375     {
376       if(mIblSpecularLoadTask)
377       {
378         Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
379         mIblSpecularLoadTask.Reset();
380       }
381       mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblSpecularLoadComplete));
382       Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
383       mIblSpecularDirty = false;
384     }
385   }
386
387   if(!Dali::Equals(mIblScaleFactor, scaleFactor))
388   {
389     SetImageBasedLightScaleFactor(scaleFactor);
390   }
391
392   // If diffuse and specular textures are already loaded, emits resource ready signal here.
393   if(IsResourceReady())
394   {
395     Control::SetResourceReady(false);
396   }
397 }
398
399 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
400 {
401   mIblScaleFactor = scaleFactor;
402   for(auto&& item : mItems)
403   {
404     if(item)
405     {
406       item->NotifyImageBasedLightScaleFactor(scaleFactor);
407     }
408   }
409 }
410
411 float SceneView::GetImageBasedLightScaleFactor() const
412 {
413   return mIblScaleFactor;
414 }
415
416 void SceneView::UseFramebuffer(bool useFramebuffer)
417 {
418   if(mUseFrameBuffer != useFramebuffer)
419   {
420     mUseFrameBuffer = useFramebuffer;
421     UpdateRenderTask();
422   }
423 }
424
425 bool SceneView::IsUsingFramebuffer() const
426 {
427   return mUseFrameBuffer;
428 }
429
430 void SceneView::SetSkybox(const std::string& skyboxUrl)
431 {
432   if(mSkyboxUrl != skyboxUrl)
433   {
434     UpdateSkybox(skyboxUrl, mSkyboxEnvironmentMapType);
435   }
436 }
437
438 void SceneView::SetSkyboxEnvironmentMapType(Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
439 {
440   if(mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
441   {
442     UpdateSkybox(mSkyboxUrl, skyboxEnvironmentMapType);
443   }
444 }
445
446 void SceneView::SetSkyboxIntensity(float intensity)
447 {
448   mSkyboxIntensity = intensity;
449   if(intensity < 0)
450   {
451     DALI_LOG_ERROR("Intensity should be greater than or equal to 0.\n");
452     mSkyboxIntensity = 0.0f;
453   }
454
455   if(mSkybox)
456   {
457     mSkybox.RegisterProperty(SKYBOX_INTENSITY_STRING.data(), mSkyboxIntensity);
458   }
459 }
460
461 float SceneView::GetSkyboxIntensity() const
462 {
463   return mSkyboxIntensity;
464 }
465
466 void SceneView::SetSkyboxOrientation(const Quaternion& orientation)
467 {
468   mSkyboxOrientation = orientation;
469   if(mSkybox)
470   {
471     mSkybox.SetProperty(Dali::Actor::Property::ORIENTATION, orientation);
472   }
473 }
474
475 Quaternion SceneView::GetSkyboxOrientation() const
476 {
477   return mSkyboxOrientation;
478 }
479
480 ///////////////////////////////////////////////////////////
481 //
482 // Private methods
483 //
484
485 void SceneView::OnSceneConnection(int depth)
486 {
487   // If diffuse and specular url is not valid, IBL does not need to be loaded.
488   if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
489   {
490     SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
491   }
492
493   if(!mSkyboxUrl.empty())
494   {
495     UpdateSkybox(mSkyboxUrl, mSkyboxEnvironmentMapType);
496   }
497
498   Window window = DevelWindow::Get(Self());
499   if(window)
500   {
501     window.ResizeSignal().Connect(this, &SceneView::OnWindowResized);
502     RenderTaskList taskList = window.GetRenderTaskList();
503     mRenderTask             = taskList.CreateTask();
504     mRenderTask.SetSourceActor(mRootLayer);
505     mRenderTask.SetExclusive(true);
506     mRenderTask.SetInputEnabled(true);
507     mRenderTask.SetCullMode(false);
508     mRenderTask.SetScreenToFrameBufferMappingActor(Self());
509
510     UpdateRenderTask();
511     mWindow = window;
512   }
513
514   Control::OnSceneConnection(depth);
515 }
516
517 void SceneView::OnSceneDisconnection()
518 {
519   mItems.clear();
520
521   Window window = mWindow.GetHandle();
522   if(window)
523   {
524     window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized);
525     RenderTaskList taskList = window.GetRenderTaskList();
526     if(mRenderTask)
527     {
528       taskList.RemoveTask(mRenderTask);
529       mFrameBuffer.Reset();
530     }
531   }
532   mWindow.Reset();
533
534   Control::OnSceneDisconnection();
535 }
536
537 void SceneView::OnInitialize()
538 {
539   Actor self = Self();
540   mRootLayer = Layer::New();
541   mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
542   mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true);
543   // The models in the SceneView should be have independent coordinate with DALi default coordinate.
544   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false);
545   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false);
546   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false);
547   self.Add(mRootLayer);
548
549   mDefaultCamera = Dali::CameraActor::New();
550   mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
551   mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
552   mDefaultCamera.SetNearClippingPlane(1.0f);
553   AddCamera(mDefaultCamera);
554   UpdateCamera(mDefaultCamera);
555 }
556
557 void SceneView::OnChildAdd(Actor& child)
558 {
559   if(child != mRootLayer)
560   {
561     mRootLayer.Add(child);
562   }
563   Control::OnChildAdd(child);
564 }
565
566 void SceneView::OnChildRemove(Actor& child)
567 {
568   mRootLayer.Remove(child);
569   Control::OnChildRemove(child);
570 }
571
572 float SceneView::GetHeightForWidth(float width)
573 {
574   Extents padding;
575   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
576   return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
577 }
578
579 float SceneView::GetWidthForHeight(float height)
580 {
581   Extents padding;
582   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
583   return Control::GetWidthForHeight(height) + padding.start + padding.end;
584 }
585
586 void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container)
587 {
588   Control::OnRelayout(size, container);
589   // Change canvas size of camera actor.
590   UpdateRenderTask();
591 }
592
593 bool SceneView::IsResourceReady() const
594 {
595   return mIblDiffuseResourceReady && mIblSpecularResourceReady && mSkyboxResourceReady;
596 }
597
598 void SceneView::UpdateCamera(CameraActor camera)
599 {
600   if(camera)
601   {
602     if(mSelectedCamera && mSelectedCamera.GetParent())
603     {
604       mSelectedCamera.Unparent();
605     }
606     mRootLayer.Add(camera);
607   }
608
609   mSelectedCamera = camera;
610   UpdateRenderTask();
611 }
612
613 void SceneView::UpdateRenderTask()
614 {
615   if(mRenderTask)
616   {
617     if(mSelectedCamera != mRenderTask.GetCameraActor())
618     {
619       mRenderTask.SetCameraActor(mSelectedCamera);
620     }
621
622     Vector3     size        = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
623     const float aspectRatio = size.width / size.height;
624     mSelectedCamera.SetAspectRatio(aspectRatio);
625
626     if(mUseFrameBuffer)
627     {
628       Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
629       if(!currentFrameBuffer ||
630          !Dali::Equals(currentFrameBuffer.GetColorTexture().GetWidth(), size.width) ||
631          !Dali::Equals(currentFrameBuffer.GetColorTexture().GetHeight(), size.height))
632       {
633         mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_COLOR);
634         mRenderTask.ResetViewportGuideActor();
635         mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
636
637         // create offscreen buffer of new size to render our child actors to
638         mTexture     = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height));
639         mFrameBuffer = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
640         mFrameBuffer.AttachColorTexture(mTexture);
641         DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, DEFAULT_FRAME_BUFFER_MULTI_SAMPLING_LEVEL);
642         Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mFrameBuffer, 0u);
643
644         Property::Map imagePropertyMap;
645         imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
646         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
647         // To make sure this visual call LoadTexture API immediate.
648         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, Toolkit::ImageVisual::LoadPolicy::IMMEDIATE);
649         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, Toolkit::ImageVisual::ReleasePolicy::DESTROYED);
650         // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling.
651         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f));
652         mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap);
653
654         // Use premultiplied alpha when we use FBO
655         if(mVisual)
656         {
657           Toolkit::GetImplementation(mVisual).EnablePreMultipliedAlpha(true);
658         }
659
660         Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
661
662         mRenderTask.SetFrameBuffer(mFrameBuffer);
663         mRenderTask.SetClearEnabled(true);
664         mRenderTask.SetClearColor(Color::TRANSPARENT);
665       }
666     }
667     else
668     {
669       mRenderTask.SetViewportGuideActor(Self());
670       if(mRenderTask.GetFrameBuffer())
671       {
672         mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA);
673         FrameBuffer framebuffer;
674         mRenderTask.SetFrameBuffer(framebuffer);
675         mRenderTask.SetClearEnabled(false);
676
677         Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
678
679         mVisual.Reset();
680         mFrameBuffer.Reset();
681         mTexture.Reset();
682       }
683     }
684
685     RotateCamera();
686   }
687 }
688
689 void SceneView::OnWindowResized(Window window, Window::WindowSize size)
690 {
691   mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
692   RotateCamera();
693 }
694
695 void SceneView::RotateCamera()
696 {
697   if(mUseFrameBuffer)
698   {
699     DevelCameraActor::RotateProjection(mSelectedCamera, DEFAULT_ORIENTATION);
700   }
701   else
702   {
703     DevelCameraActor::RotateProjection(mSelectedCamera, mWindowOrientation);
704   }
705 }
706
707 void SceneView::UpdateSkybox(const std::string& skyboxUrl, Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
708 {
709   bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
710   if(mSkyboxUrl != skyboxUrl || mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
711   {
712     mSkyboxDirty         = true;
713     mSkyboxResourceReady = false;
714     mSkyboxUrl           = skyboxUrl;
715     mSkyboxEnvironmentMapType = skyboxEnvironmentMapType;
716   }
717
718   if(mSkyboxUrl.empty())
719   {
720     if(mSkyboxLoadTask)
721     {
722       Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
723       mSkyboxLoadTask.Reset();
724     }
725     mSkyboxDirty         = false;
726     mSkyboxResourceReady = true;
727   }
728   else
729   {
730     if(isOnScene && mSkyboxDirty)
731     {
732       if(mSkyboxLoadTask)
733       {
734         Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
735         mSkyboxLoadTask.Reset();
736       }
737
738       mSkyboxLoadTask = new EnvironmentMapLoadTask(mSkyboxUrl, mSkyboxEnvironmentMapType, MakeCallback(this, &SceneView::OnSkyboxLoadComplete));
739       Dali::AsyncTaskManager::Get().AddTask(mSkyboxLoadTask);
740       mSkyboxDirty = false;
741     }
742   }
743
744   if(IsResourceReady())
745   {
746     Control::SetResourceReady(false);
747   }
748 }
749
750 void SceneView::OnSkyboxLoadComplete()
751 {
752   if(!mSkybox)
753   {
754     mSkybox = CreateSkybox();
755     SetSkyboxIntensity(mSkyboxIntensity);
756     SetSkyboxOrientation(mSkyboxOrientation);
757     if(mRootLayer)
758     {
759       mRootLayer.Add(mSkybox);
760     }
761   }
762
763   mSkyboxResourceReady = true;
764   if(IsResourceReady())
765   {
766     Control::SetResourceReady(false);
767   }
768
769   mSkyboxTexture = (mSkyboxLoadTask->HasSucceeded()) ? mSkyboxLoadTask->GetEnvironmentMap().GetTexture() : Texture();
770   Shader skyboxShader;
771   if(mSkyboxEnvironmentMapType == Scene3D::EnvironmentMapType::CUBEMAP)
772   {
773     skyboxShader   = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
774   }
775   else
776   {
777     skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_EQUIRECTANGULAR_SHADER_FRAG.data());
778   }
779
780   Renderer skyboxRenderer = (mSkybox.GetRendererCount() > 0u) ? mSkybox.GetRendererAt(0u) : Renderer();
781   if(skyboxRenderer)
782   {
783     Dali::TextureSet skyboxTextures = TextureSet::New();
784     skyboxTextures.SetTexture(0, mSkyboxTexture);
785     skyboxRenderer.SetTextures(skyboxTextures);
786     skyboxRenderer.SetShader(skyboxShader);
787   }
788
789   mSkyboxLoadTask.Reset();
790 }
791
792 void SceneView::OnIblDiffuseLoadComplete()
793 {
794   mDiffuseTexture          = (mIblDiffuseLoadTask->HasSucceeded()) ? mIblDiffuseLoadTask->GetEnvironmentMap().GetTexture() : Texture();
795   mIblDiffuseResourceReady = true;
796   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
797   {
798     OnIblLoadComplete();
799   }
800   mIblDiffuseLoadTask.Reset();
801 }
802
803 void SceneView::OnIblSpecularLoadComplete()
804 {
805   mSpecularTexture          = (mIblSpecularLoadTask->HasSucceeded()) ? mIblSpecularLoadTask->GetEnvironmentMap().GetTexture() : Texture();
806   mIblSpecularResourceReady = true;
807   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
808   {
809     OnIblLoadComplete();
810   }
811   mIblSpecularLoadTask.Reset();
812 }
813
814 void SceneView::OnIblLoadComplete()
815 {
816   NotifyImageBasedLightTextureChange();
817   if(IsResourceReady())
818   {
819     Control::SetResourceReady(false);
820   }
821 }
822
823 void SceneView::NotifyImageBasedLightTextureChange()
824 {
825   for(auto&& item : mItems)
826   {
827     if(item)
828     {
829       item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
830     }
831   }
832 }
833
834 } // namespace Internal
835 } // namespace Scene3D
836 } // namespace Dali