Asynchronous loading of Scene3D resources
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / controls / scene-view / scene-view-impl.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-scene3d/internal/controls/scene-view/scene-view-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali-toolkit/dali-toolkit.h>
23 #include <dali-toolkit/devel-api/controls/control-devel.h>
24 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
25 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
26 #include <dali-toolkit/public-api/image-loader/image-url.h>
27 #include <dali-toolkit/public-api/image-loader/image.h>
28 #include <dali/devel-api/actors/camera-actor-devel.h>
29 #include <dali/devel-api/adaptor-framework/window-devel.h>
30 #include <dali/devel-api/common/stage.h>
31 #include <dali/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 #include <dali-scene3d/public-api/loader/cube-map-loader.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
66 constexpr uint8_t DEFAULT_FRAME_BUFFER_MULTI_SAMPLING_LEVEL = 4u;
67
68 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
69
70 Dali::Actor CreateSkybox()
71 {
72   struct Vertex
73   {
74     Vector3 aPosition;
75   };
76
77   Vertex skyboxVertices[] = {
78     // back
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     {Vector3(-1.0f, 1.0f, -1.0f)},
85
86     // left
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     {Vector3(-1.0f, -1.0f, 1.0f)},
93
94     // right
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     {Vector3(1.0f, -1.0f, -1.0f)},
101
102     // front
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     {Vector3(-1.0f, -1.0f, 1.0f)},
109
110     // botton
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     {Vector3(-1.0f, 1.0f, -1.0f)},
117
118     // top
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     {Vector3(1.0f, -1.0f, 1.0f)}};
125
126   Dali::VertexBuffer vertexBuffer = Dali::VertexBuffer::New(Property::Map().Add("aPosition", Property::VECTOR3));
127   vertexBuffer.SetData(skyboxVertices, sizeof(skyboxVertices) / sizeof(Vertex));
128
129   Dali::Geometry skyboxGeometry = Geometry::New();
130   skyboxGeometry.AddVertexBuffer(vertexBuffer);
131   skyboxGeometry.SetType(Geometry::TRIANGLES);
132
133   Dali::Shader   shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
134   Dali::Renderer skyboxRenderer;
135   skyboxRenderer = Renderer::New(skyboxGeometry, shaderSkybox);
136   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f);
137   // Enables the depth test.
138   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
139   // The fragment shader will run only is those pixels that have the max depth value.
140   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_FUNCTION, DepthFunction::LESS_EQUAL);
141
142   Dali::Actor skyboxActor = Actor::New();
143   skyboxActor.SetProperty(Dali::Actor::Property::NAME, "SkyBox");
144   skyboxActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
145   skyboxActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
146   skyboxActor.AddRenderer(skyboxRenderer);
147   return skyboxActor;
148 }
149
150 } // anonymous namespace
151
152 SceneView::SceneView()
153 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
154   mWindowOrientation(DEFAULT_ORIENTATION),
155   mSkybox(),
156   mSkyboxOrientation(Quaternion()),
157   mSkyboxIntensity(1.0f)
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::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   bool needIblReset = false;
306   bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
307   if(mDiffuseIblUrl != diffuseUrl)
308   {
309     mDiffuseIblUrl = diffuseUrl;
310     if(mDiffuseIblUrl.empty())
311     {
312       needIblReset             = true;
313     }
314     else
315     {
316       mIblDiffuseDirty         = true;
317       mIblDiffuseResourceReady = false;
318     }
319   }
320
321   if(mSpecularIblUrl != specularUrl)
322   {
323     mSpecularIblUrl = specularUrl;
324     if(mSpecularIblUrl.empty())
325     {
326       needIblReset              = true;
327     }
328     else
329     {
330       mIblSpecularDirty         = true;
331       mIblSpecularResourceReady = false;
332     }
333   }
334
335   // If one or both of diffuse url and specular url are empty,
336   // we don't need to request to load texture.
337   if(needIblReset)
338   {
339     if(mIblDiffuseLoadTask)
340     {
341       Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
342       mIblDiffuseLoadTask.Reset();
343     }
344
345     if(mIblSpecularLoadTask)
346     {
347       Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
348       mIblSpecularLoadTask.Reset();
349     }
350
351     mIblDiffuseDirty          = false;
352     mIblSpecularDirty         = false;
353     mIblDiffuseResourceReady  = true;
354     mIblSpecularResourceReady = true;
355
356     mDiffuseTexture.Reset();
357     mSpecularTexture.Reset();
358
359     NotifyImageBasedLightTextureChange();
360   }
361   else
362   {
363     if(isOnScene && mIblDiffuseDirty)
364     {
365       if(mIblDiffuseLoadTask)
366       {
367         Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
368         mIblDiffuseLoadTask.Reset();
369       }
370       mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, MakeCallback(this, &SceneView::OnIblDiffuseLoadComplete));
371       Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
372       mIblDiffuseDirty = false;
373     }
374
375     if(isOnScene && mIblSpecularDirty)
376     {
377       if(mIblSpecularLoadTask)
378       {
379         Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
380         mIblSpecularLoadTask.Reset();
381       }
382       mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, MakeCallback(this, &SceneView::OnIblSpecularLoadComplete));
383       Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
384       mIblSpecularDirty = false;
385     }
386   }
387
388   if(!Dali::Equals(mIblScaleFactor, scaleFactor))
389   {
390     SetImageBasedLightScaleFactor(scaleFactor);
391   }
392
393   // If diffuse and specular textures are already loaded, emits resource ready signal here.
394   if(IsResourceReady())
395   {
396     Control::SetResourceReady(false);
397   }
398 }
399
400 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
401 {
402   mIblScaleFactor = scaleFactor;
403   for(auto&& item : mItems)
404   {
405     if(item)
406     {
407       item->NotifyImageBasedLightScaleFactor(scaleFactor);
408     }
409   }
410 }
411
412 float SceneView::GetImageBasedLightScaleFactor() const
413 {
414   return mIblScaleFactor;
415 }
416
417 void SceneView::UseFramebuffer(bool useFramebuffer)
418 {
419   if(mUseFrameBuffer != useFramebuffer)
420   {
421     mUseFrameBuffer = useFramebuffer;
422     UpdateRenderTask();
423   }
424 }
425
426 bool SceneView::IsUsingFramebuffer() const
427 {
428   return mUseFrameBuffer;
429 }
430
431 void SceneView::SetSkybox(const std::string& skyboxUrl, Scene3D::SceneView::SkyboxType skyboxType)
432 {
433   mSkyboxEnvironmentMapType = skyboxType;
434   bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
435   if(mSkyboxUrl != skyboxUrl)
436   {
437     mSkyboxDirty         = true;
438     mSkyboxResourceReady = false;
439     mSkyboxUrl           = skyboxUrl;
440   }
441
442   if(mSkyboxUrl.empty())
443   {
444     if(mSkyboxLoadTask)
445     {
446       Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
447       mSkyboxLoadTask.Reset();
448     }
449     if(mSkyboxImageLoader)
450     {
451       mSkyboxImageLoader.Cancel(mSkyboxImageId);
452     }
453     mSkyboxDirty         = false;
454     mSkyboxResourceReady = true;
455   }
456   else
457   {
458     if(isOnScene && mSkyboxDirty)
459     {
460       if(mSkyboxLoadTask)
461       {
462         Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
463         mSkyboxLoadTask.Reset();
464       }
465       if(mSkyboxImageLoader)
466       {
467         mSkyboxImageLoader.Cancel(mSkyboxImageId);
468       }
469       if(mSkyboxEnvironmentMapType == Scene3D::SceneView::SkyboxType::CUBEMAP)
470       {
471         mSkyboxLoadTask = new EnvironmentMapLoadTask(mSkyboxUrl, MakeCallback(this, &SceneView::OnSkyboxLoadComplete));
472         Dali::AsyncTaskManager::Get().AddTask(mSkyboxLoadTask);
473       }
474       else
475       {
476         mSkyboxImageLoader = Dali::Toolkit::AsyncImageLoader::New();
477         mSkyboxImageLoader.ImageLoadedSignal().Connect(this, &SceneView::OnSkyboxEquirectangularLoadComplete);
478         mSkyboxImageId = mSkyboxImageLoader.Load(mSkyboxUrl);
479       }
480       mSkyboxDirty = false;
481     }
482   }
483
484   if(IsResourceReady())
485   {
486     Control::SetResourceReady(false);
487   }
488 }
489
490 void SceneView::SetSkyboxIntensity(float intensity)
491 {
492   mSkyboxIntensity = intensity;
493   if(intensity < 0)
494   {
495     DALI_LOG_ERROR("Intensity should be greater than or equal to 0.\n");
496     mSkyboxIntensity = 0.0f;
497   }
498
499   if(mSkybox)
500   {
501     mSkybox.RegisterProperty(SKYBOX_INTENSITY_STRING.data(), mSkyboxIntensity);
502   }
503 }
504
505 float SceneView::GetSkyboxIntensity() const
506 {
507   return mSkyboxIntensity;
508 }
509
510 void SceneView::SetSkyboxOrientation(const Quaternion& orientation)
511 {
512   mSkyboxOrientation = orientation;
513   if(mSkybox)
514   {
515     mSkybox.SetProperty(Dali::Actor::Property::ORIENTATION, orientation);
516   }
517 }
518
519 Quaternion SceneView::GetSkyboxOrientation() const
520 {
521   return mSkyboxOrientation;
522 }
523
524 ///////////////////////////////////////////////////////////
525 //
526 // Private methods
527 //
528
529 void SceneView::OnSceneConnection(int depth)
530 {
531   // If diffuse and specular url is not valid, IBL does not need to be loaded.
532   if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
533   {
534     SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
535   }
536
537   if(!mSkyboxUrl.empty())
538   {
539     SetSkybox(mSkyboxUrl, mSkyboxEnvironmentMapType);
540   }
541
542   Window window = DevelWindow::Get(Self());
543   if(window)
544   {
545     window.ResizeSignal().Connect(this, &SceneView::OnWindowResized);
546     RenderTaskList taskList = window.GetRenderTaskList();
547     mRenderTask             = taskList.CreateTask();
548     mRenderTask.SetSourceActor(mRootLayer);
549     mRenderTask.SetExclusive(true);
550     mRenderTask.SetInputEnabled(true);
551     mRenderTask.SetCullMode(false);
552     mRenderTask.SetScreenToFrameBufferMappingActor(Self());
553
554     UpdateRenderTask();
555     mWindow = window;
556   }
557
558   Control::OnSceneConnection(depth);
559 }
560
561 void SceneView::OnSceneDisconnection()
562 {
563   mItems.clear();
564
565   Window window = mWindow.GetHandle();
566   if(window)
567   {
568     window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized);
569     RenderTaskList taskList = window.GetRenderTaskList();
570     if(mRenderTask)
571     {
572       taskList.RemoveTask(mRenderTask);
573       mFrameBuffer.Reset();
574     }
575   }
576   mWindow.Reset();
577
578   Control::OnSceneDisconnection();
579 }
580
581 void SceneView::OnInitialize()
582 {
583   Actor self = Self();
584   mRootLayer = Layer::New();
585   mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
586   mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true);
587   // The models in the SceneView should be have independent coordinate with DALi default coordinate.
588   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false);
589   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false);
590   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false);
591   self.Add(mRootLayer);
592
593   mDefaultCamera = Dali::CameraActor::New();
594   mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
595   mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
596   mDefaultCamera.SetNearClippingPlane(1.0f);
597   AddCamera(mDefaultCamera);
598   UpdateCamera(mDefaultCamera);
599 }
600
601 void SceneView::OnChildAdd(Actor& child)
602 {
603   if(child != mRootLayer)
604   {
605     mRootLayer.Add(child);
606   }
607   Control::OnChildAdd(child);
608 }
609
610 void SceneView::OnChildRemove(Actor& child)
611 {
612   mRootLayer.Remove(child);
613   Control::OnChildRemove(child);
614 }
615
616 float SceneView::GetHeightForWidth(float width)
617 {
618   Extents padding;
619   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
620   return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
621 }
622
623 float SceneView::GetWidthForHeight(float height)
624 {
625   Extents padding;
626   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
627   return Control::GetWidthForHeight(height) + padding.start + padding.end;
628 }
629
630 void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container)
631 {
632   Control::OnRelayout(size, container);
633   // Change canvas size of camera actor.
634   UpdateRenderTask();
635 }
636
637 bool SceneView::IsResourceReady() const
638 {
639   return mIblDiffuseResourceReady && mIblSpecularResourceReady && mSkyboxResourceReady;
640 }
641
642 void SceneView::UpdateCamera(CameraActor camera)
643 {
644   if(camera)
645   {
646     if(mSelectedCamera && mSelectedCamera.GetParent())
647     {
648       mSelectedCamera.Unparent();
649     }
650     mRootLayer.Add(camera);
651   }
652
653   mSelectedCamera = camera;
654   UpdateRenderTask();
655 }
656
657 void SceneView::UpdateRenderTask()
658 {
659   if(mRenderTask)
660   {
661     if(mSelectedCamera != mRenderTask.GetCameraActor())
662     {
663       mRenderTask.SetCameraActor(mSelectedCamera);
664     }
665
666     Vector3     size        = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
667     const float aspectRatio = size.width / size.height;
668     mSelectedCamera.SetAspectRatio(aspectRatio);
669
670     if(mUseFrameBuffer)
671     {
672       Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
673       if(!currentFrameBuffer ||
674          !Dali::Equals(currentFrameBuffer.GetColorTexture().GetWidth(), size.width) ||
675          !Dali::Equals(currentFrameBuffer.GetColorTexture().GetHeight(), size.height))
676       {
677         mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_COLOR);
678         mRenderTask.ResetViewportGuideActor();
679         mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
680
681         // create offscreen buffer of new size to render our child actors to
682         mTexture     = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height));
683         mFrameBuffer = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
684         mFrameBuffer.AttachColorTexture(mTexture);
685         DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, DEFAULT_FRAME_BUFFER_MULTI_SAMPLING_LEVEL);
686         Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mFrameBuffer, 0u);
687
688         Property::Map imagePropertyMap;
689         imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
690         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
691         // To make sure this visual call LoadTexture API immediate.
692         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, Toolkit::ImageVisual::LoadPolicy::IMMEDIATE);
693         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, Toolkit::ImageVisual::ReleasePolicy::DESTROYED);
694         // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling.
695         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f));
696         mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap);
697
698         // Use premultiplied alpha when we use FBO
699         if(mVisual)
700         {
701           Toolkit::GetImplementation(mVisual).EnablePreMultipliedAlpha(true);
702         }
703
704         Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
705
706         mRenderTask.SetFrameBuffer(mFrameBuffer);
707         mRenderTask.SetClearEnabled(true);
708         mRenderTask.SetClearColor(Color::TRANSPARENT);
709       }
710     }
711     else
712     {
713       mRenderTask.SetViewportGuideActor(Self());
714       if(mRenderTask.GetFrameBuffer())
715       {
716         mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA);
717         FrameBuffer framebuffer;
718         mRenderTask.SetFrameBuffer(framebuffer);
719         mRenderTask.SetClearEnabled(false);
720
721         Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
722
723         mVisual.Reset();
724         mFrameBuffer.Reset();
725         mTexture.Reset();
726       }
727     }
728
729     RotateCamera();
730   }
731 }
732
733 void SceneView::OnWindowResized(Window window, Window::WindowSize size)
734 {
735   mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
736   RotateCamera();
737 }
738
739 void SceneView::RotateCamera()
740 {
741   if(mUseFrameBuffer)
742   {
743     DevelCameraActor::RotateProjection(mSelectedCamera, DEFAULT_ORIENTATION);
744   }
745   else
746   {
747     DevelCameraActor::RotateProjection(mSelectedCamera, mWindowOrientation);
748   }
749 }
750
751 void SceneView::OnSkyboxEquirectangularLoadComplete(uint32_t loadedTaskId, PixelData pixelData)
752 {
753   mSkyboxTexture = Texture::New(TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
754   mSkyboxTexture.Upload(pixelData, 0, 0, 0, 0, pixelData.GetWidth(), pixelData.GetHeight());
755   OnSkyboxLoadComplete();
756 }
757
758 void SceneView::OnSkyboxLoadComplete()
759 {
760   if(!mSkybox)
761   {
762     mSkybox = CreateSkybox();
763     SetSkyboxIntensity(mSkyboxIntensity);
764     SetSkyboxOrientation(mSkyboxOrientation);
765     if(mRootLayer)
766     {
767       mRootLayer.Add(mSkybox);
768     }
769   }
770
771   mSkyboxResourceReady = true;
772   if(IsResourceReady())
773   {
774     Control::SetResourceReady(false);
775   }
776
777   Shader skyboxShader;
778   if(mSkyboxEnvironmentMapType == Scene3D::SceneView::SkyboxType::CUBEMAP)
779   {
780     mSkyboxTexture = (mSkyboxLoadTask->HasSucceeded()) ? mSkyboxLoadTask->GetEnvironmentMap().CreateTexture() : Texture();
781     skyboxShader   = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
782     Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
783     mSkyboxLoadTask.Reset();
784   }
785   else
786   {
787     skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_EQUIRECTANGULAR_SHADER_FRAG.data());
788   }
789
790   Renderer skyboxRenderer = (mSkybox.GetRendererCount() > 0u) ? mSkybox.GetRendererAt(0u) : Renderer();
791   if(skyboxRenderer)
792   {
793     Dali::TextureSet skyboxTextures = TextureSet::New();
794     skyboxTextures.SetTexture(0, mSkyboxTexture);
795     skyboxRenderer.SetTextures(skyboxTextures);
796     skyboxRenderer.SetShader(skyboxShader);
797   }
798 }
799
800 void SceneView::OnIblDiffuseLoadComplete()
801 {
802   mDiffuseTexture          = (mIblDiffuseLoadTask->HasSucceeded()) ? mIblDiffuseLoadTask->GetEnvironmentMap().CreateTexture() : Texture();
803   mIblDiffuseResourceReady = true;
804   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
805   {
806     OnIblLoadComplete();
807   }
808   mIblDiffuseLoadTask.Reset();
809 }
810
811 void SceneView::OnIblSpecularLoadComplete()
812 {
813   mSpecularTexture          = (mIblSpecularLoadTask->HasSucceeded()) ? mIblSpecularLoadTask->GetEnvironmentMap().CreateTexture() : Texture();
814   mIblSpecularResourceReady = true;
815   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
816   {
817     OnIblLoadComplete();
818   }
819   mIblSpecularLoadTask.Reset();
820 }
821
822 void SceneView::OnIblLoadComplete()
823 {
824   NotifyImageBasedLightTextureChange();
825   if(IsResourceReady())
826   {
827     Control::SetResourceReady(false);
828   }
829 }
830
831 void SceneView::NotifyImageBasedLightTextureChange()
832 {
833   for(auto&& item : mItems)
834   {
835     if(item)
836     {
837       item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
838     }
839   }
840 }
841
842 } // namespace Internal
843 } // namespace Scene3D
844 } // namespace Dali