Refactoring model-impl.cpp
[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
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 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
66
67 Dali::Actor CreateSkybox()
68 {
69   struct Vertex
70   {
71     Vector3 aPosition;
72   };
73
74   Vertex skyboxVertices[] = {
75     // back
76     {Vector3(-1.0f, 1.0f, -1.0f)},
77     {Vector3(-1.0f, -1.0f, -1.0f)},
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
83     // left
84     {Vector3(-1.0f, -1.0f, 1.0f)},
85     {Vector3(-1.0f, -1.0f, -1.0f)},
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
91     // right
92     {Vector3(1.0f, -1.0f, -1.0f)},
93     {Vector3(1.0f, -1.0f, 1.0f)},
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
99     // front
100     {Vector3(-1.0f, -1.0f, 1.0f)},
101     {Vector3(-1.0f, 1.0f, 1.0f)},
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
107     // botton
108     {Vector3(-1.0f, 1.0f, -1.0f)},
109     {Vector3(1.0f, 1.0f, -1.0f)},
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
115     // top
116     {Vector3(-1.0f, -1.0f, -1.0f)},
117     {Vector3(-1.0f, -1.0f, 1.0f)},
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
123   Dali::VertexBuffer vertexBuffer = Dali::VertexBuffer::New(Property::Map().Add("aPosition", Property::VECTOR3));
124   vertexBuffer.SetData(skyboxVertices, sizeof(skyboxVertices) / sizeof(Vertex));
125
126   Dali::Geometry skyboxGeometry = Geometry::New();
127   skyboxGeometry.AddVertexBuffer(vertexBuffer);
128   skyboxGeometry.SetType(Geometry::TRIANGLES);
129
130   Dali::Shader   shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
131   Dali::Renderer skyboxRenderer;
132   skyboxRenderer = Renderer::New(skyboxGeometry, shaderSkybox);
133   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f);
134   // Enables the depth test.
135   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
136   // The fragment shader will run only is those pixels that have the max depth value.
137   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_FUNCTION, DepthFunction::LESS_EQUAL);
138
139   Dali::Actor skyboxActor = Actor::New();
140   skyboxActor.SetProperty(Dali::Actor::Property::NAME, "SkyBox");
141   skyboxActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
142   skyboxActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
143   skyboxActor.AddRenderer(skyboxRenderer);
144   return skyboxActor;
145 }
146
147 } // anonymous namespace
148
149 SceneView::SceneView()
150 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
151   mWindowOrientation(DEFAULT_ORIENTATION),
152   mSkybox(),
153   mSkyboxOrientation(Quaternion()),
154   mSkyboxIntensity(1.0f)
155 {
156 }
157
158 SceneView::~SceneView()
159 {
160   if(Dali::Adaptor::IsAvailable())
161   {
162     if(mIblDiffuseLoadTask)
163     {
164       Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
165       mIblDiffuseLoadTask.Reset();
166     }
167     if(mIblSpecularLoadTask)
168     {
169       Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
170       mIblSpecularLoadTask.Reset();
171     }
172     if(mSkyboxLoadTask)
173     {
174       Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
175       mSkyboxLoadTask.Reset();
176     }
177   }
178 }
179
180 Dali::Scene3D::SceneView SceneView::New()
181 {
182   SceneView* impl = new SceneView();
183
184   Dali::Scene3D::SceneView handle = Dali::Scene3D::SceneView(*impl);
185
186   // Second-phase init of the implementation
187   // This can only be done after the CustomActor connection has been made...
188   impl->Initialize();
189
190   return handle;
191 }
192
193 void SceneView::AddCamera(CameraActor camera)
194 {
195   if(camera)
196   {
197     if(mCameras.empty())
198     {
199       UpdateCamera(camera);
200     }
201     mCameras.push_back(camera);
202   }
203 }
204
205 void SceneView::RemoveCamera(CameraActor camera)
206 {
207   if(camera == mDefaultCamera)
208   {
209     DALI_LOG_ERROR("Default Camera cannot removed.\n");
210     return;
211   }
212
213   if(camera)
214   {
215     for(uint32_t i = 0; i < mCameras.size(); ++i)
216     {
217       if(mCameras[i] == camera)
218       {
219         mCameras.erase(mCameras.begin() + i);
220         break;
221       }
222     }
223
224     if(mSelectedCamera == camera)
225     {
226       CameraActor newCurrentCamera = *mCameras.begin();
227       UpdateCamera(newCurrentCamera);
228     }
229   }
230 }
231
232 uint32_t SceneView::GetCameraCount() const
233 {
234   return mCameras.size();
235 }
236
237 CameraActor SceneView::GetSelectedCamera() const
238 {
239   return mSelectedCamera;
240 }
241
242 CameraActor SceneView::GetCamera(uint32_t index) const
243 {
244   if(index < mCameras.size())
245   {
246     return mCameras[index];
247   }
248   DALI_LOG_ERROR("Input index is out of bounds\n");
249   return CameraActor();
250 }
251
252 CameraActor SceneView::GetCamera(const std::string& name) const
253 {
254   CameraActor returnCamera;
255   for(auto&& camera : mCameras)
256   {
257     if(camera.GetProperty<std::string>(Actor::Property::NAME) == name)
258     {
259       returnCamera = camera;
260       break;
261     }
262   }
263   return returnCamera;
264 }
265
266 void SceneView::SelectCamera(uint32_t index)
267 {
268   UpdateCamera(GetCamera(index));
269 }
270
271 void SceneView::SelectCamera(const std::string& name)
272 {
273   UpdateCamera(GetCamera(name));
274 }
275
276 void SceneView::RegisterSceneItem(Scene3D::Internal::ImageBasedLightObserver* item)
277 {
278   if(item)
279   {
280     item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
281     mItems.push_back(item);
282   }
283 }
284
285 void SceneView::UnregisterSceneItem(Scene3D::Internal::ImageBasedLightObserver* item)
286 {
287   if(item)
288   {
289     for(uint32_t i = 0; i < mItems.size(); ++i)
290     {
291       if(mItems[i] == item)
292       {
293         mItems.erase(mItems.begin() + i);
294         break;
295       }
296     }
297   }
298 }
299
300 void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
301 {
302   bool needIblReset = false;
303   bool isOnScene    = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
304   if(mDiffuseIblUrl != diffuseUrl)
305   {
306     mDiffuseIblUrl = diffuseUrl;
307     if(mDiffuseIblUrl.empty())
308     {
309       needIblReset = true;
310     }
311     else
312     {
313       mIblDiffuseDirty         = true;
314       mIblDiffuseResourceReady = false;
315     }
316   }
317
318   if(mSpecularIblUrl != specularUrl)
319   {
320     mSpecularIblUrl = specularUrl;
321     if(mSpecularIblUrl.empty())
322     {
323       needIblReset = true;
324     }
325     else
326     {
327       mIblSpecularDirty         = true;
328       mIblSpecularResourceReady = false;
329     }
330   }
331
332   // If one or both of diffuse url and specular url are empty,
333   // we don't need to request to load texture.
334   if(needIblReset)
335   {
336     if(mIblDiffuseLoadTask)
337     {
338       Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
339       mIblDiffuseLoadTask.Reset();
340     }
341
342     if(mIblSpecularLoadTask)
343     {
344       Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
345       mIblSpecularLoadTask.Reset();
346     }
347
348     mIblDiffuseDirty          = false;
349     mIblSpecularDirty         = false;
350     mIblDiffuseResourceReady  = true;
351     mIblSpecularResourceReady = true;
352
353     mDiffuseTexture.Reset();
354     mSpecularTexture.Reset();
355
356     NotifyImageBasedLightTextureChange();
357   }
358   else
359   {
360     if(isOnScene && mIblDiffuseDirty)
361     {
362       if(mIblDiffuseLoadTask)
363       {
364         Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
365         mIblDiffuseLoadTask.Reset();
366       }
367       mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblDiffuseLoadComplete));
368       Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
369       mIblDiffuseDirty = false;
370     }
371
372     if(isOnScene && mIblSpecularDirty)
373     {
374       if(mIblSpecularLoadTask)
375       {
376         Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
377         mIblSpecularLoadTask.Reset();
378       }
379       mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblSpecularLoadComplete));
380       Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
381       mIblSpecularDirty = false;
382     }
383   }
384
385   if(!Dali::Equals(mIblScaleFactor, scaleFactor))
386   {
387     SetImageBasedLightScaleFactor(scaleFactor);
388   }
389
390   // If diffuse and specular textures are already loaded, emits resource ready signal here.
391   if(IsResourceReady())
392   {
393     Control::SetResourceReady(false);
394   }
395 }
396
397 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
398 {
399   mIblScaleFactor = scaleFactor;
400   for(auto&& item : mItems)
401   {
402     if(item)
403     {
404       item->NotifyImageBasedLightScaleFactor(scaleFactor);
405     }
406   }
407 }
408
409 float SceneView::GetImageBasedLightScaleFactor() const
410 {
411   return mIblScaleFactor;
412 }
413
414 void SceneView::UseFramebuffer(bool useFramebuffer)
415 {
416   if(mUseFrameBuffer != useFramebuffer)
417   {
418     mUseFrameBuffer = useFramebuffer;
419     UpdateRenderTask();
420   }
421 }
422
423 bool SceneView::IsUsingFramebuffer() const
424 {
425   return mUseFrameBuffer;
426 }
427
428 void SceneView::SetFramebufferMultiSamplingLevel(uint8_t multiSamplingLevel)
429 {
430   if(mFrameBufferMultiSamplingLevel != multiSamplingLevel)
431   {
432     mFrameBufferMultiSamplingLevel = multiSamplingLevel;
433
434     // Create new framebuffer with changed multiSamplingLevel.
435     if(mRenderTask && mFrameBuffer && mTexture)
436     {
437       Vector3 size = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
438
439       mFrameBuffer = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
440       mFrameBuffer.AttachColorTexture(mTexture);
441       DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
442       mRenderTask.SetFrameBuffer(mFrameBuffer);
443
444       // Note : we don't need to create new visual since visual's url is depend on mTexture.
445     }
446   }
447 }
448
449 uint8_t SceneView::GetFramebufferMultiSamplingLevel() const
450 {
451   return mFrameBufferMultiSamplingLevel;
452 }
453
454 void SceneView::SetSkybox(const std::string& skyboxUrl)
455 {
456   if(mSkyboxUrl != skyboxUrl)
457   {
458     UpdateSkybox(skyboxUrl, mSkyboxEnvironmentMapType);
459   }
460 }
461
462 void SceneView::SetSkyboxEnvironmentMapType(Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
463 {
464   if(mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
465   {
466     UpdateSkybox(mSkyboxUrl, skyboxEnvironmentMapType);
467   }
468 }
469
470 void SceneView::SetSkyboxIntensity(float intensity)
471 {
472   mSkyboxIntensity = intensity;
473   if(intensity < 0)
474   {
475     DALI_LOG_ERROR("Intensity should be greater than or equal to 0.\n");
476     mSkyboxIntensity = 0.0f;
477   }
478
479   if(mSkybox)
480   {
481     mSkybox.RegisterProperty(SKYBOX_INTENSITY_STRING.data(), mSkyboxIntensity);
482   }
483 }
484
485 float SceneView::GetSkyboxIntensity() const
486 {
487   return mSkyboxIntensity;
488 }
489
490 void SceneView::SetSkyboxOrientation(const Quaternion& orientation)
491 {
492   mSkyboxOrientation = orientation;
493   if(mSkybox)
494   {
495     mSkybox.SetProperty(Dali::Actor::Property::ORIENTATION, orientation);
496   }
497 }
498
499 Quaternion SceneView::GetSkyboxOrientation() const
500 {
501   return mSkyboxOrientation;
502 }
503
504 ///////////////////////////////////////////////////////////
505 //
506 // Private methods
507 //
508
509 void SceneView::OnSceneConnection(int depth)
510 {
511   // If diffuse and specular url is not valid, IBL does not need to be loaded.
512   if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
513   {
514     SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
515   }
516
517   if(!mSkyboxUrl.empty())
518   {
519     UpdateSkybox(mSkyboxUrl, mSkyboxEnvironmentMapType);
520   }
521
522   Window window = DevelWindow::Get(Self());
523   if(window)
524   {
525     window.ResizeSignal().Connect(this, &SceneView::OnWindowResized);
526     RenderTaskList taskList = window.GetRenderTaskList();
527     mRenderTask             = taskList.CreateTask();
528     mRenderTask.SetSourceActor(mRootLayer);
529     mRenderTask.SetExclusive(true);
530     mRenderTask.SetInputEnabled(true);
531     mRenderTask.SetCullMode(false);
532     mRenderTask.SetScreenToFrameBufferMappingActor(Self());
533
534     UpdateRenderTask();
535     mWindow = window;
536   }
537
538   Control::OnSceneConnection(depth);
539 }
540
541 void SceneView::OnSceneDisconnection()
542 {
543   mItems.clear();
544
545   Window window = mWindow.GetHandle();
546   if(window)
547   {
548     window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized);
549     RenderTaskList taskList = window.GetRenderTaskList();
550     if(mRenderTask)
551     {
552       taskList.RemoveTask(mRenderTask);
553       mFrameBuffer.Reset();
554     }
555   }
556   mWindow.Reset();
557
558   Control::OnSceneDisconnection();
559 }
560
561 void SceneView::OnInitialize()
562 {
563   Actor self = Self();
564   mRootLayer = Layer::New();
565   mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
566   mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true);
567   // The models in the SceneView should be have independent coordinate with DALi default coordinate.
568   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false);
569   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false);
570   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false);
571   self.Add(mRootLayer);
572
573   mDefaultCamera = Dali::CameraActor::New3DCamera();
574   mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
575   mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
576   AddCamera(mDefaultCamera);
577   UpdateCamera(mDefaultCamera);
578 }
579
580 void SceneView::OnChildAdd(Actor& child)
581 {
582   if(child != mRootLayer)
583   {
584     mRootLayer.Add(child);
585   }
586   Control::OnChildAdd(child);
587 }
588
589 void SceneView::OnChildRemove(Actor& child)
590 {
591   mRootLayer.Remove(child);
592   Control::OnChildRemove(child);
593 }
594
595 float SceneView::GetHeightForWidth(float width)
596 {
597   Extents padding;
598   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
599   return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
600 }
601
602 float SceneView::GetWidthForHeight(float height)
603 {
604   Extents padding;
605   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
606   return Control::GetWidthForHeight(height) + padding.start + padding.end;
607 }
608
609 void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container)
610 {
611   Control::OnRelayout(size, container);
612   // Change canvas size of camera actor.
613   UpdateRenderTask();
614 }
615
616 bool SceneView::IsResourceReady() const
617 {
618   return mIblDiffuseResourceReady && mIblSpecularResourceReady && mSkyboxResourceReady;
619 }
620
621 void SceneView::UpdateCamera(CameraActor camera)
622 {
623   if(camera)
624   {
625     if(mSelectedCamera && mSelectedCamera.GetParent())
626     {
627       mSelectedCamera.Unparent();
628     }
629     mRootLayer.Add(camera);
630   }
631
632   mSelectedCamera = camera;
633   UpdateRenderTask();
634 }
635
636 void SceneView::UpdateRenderTask()
637 {
638   if(mRenderTask)
639   {
640     if(mSelectedCamera != mRenderTask.GetCameraActor())
641     {
642       mRenderTask.SetCameraActor(mSelectedCamera);
643     }
644
645     Vector3     size        = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
646     const float aspectRatio = size.width / size.height;
647     mSelectedCamera.SetAspectRatio(aspectRatio);
648
649     if(mUseFrameBuffer)
650     {
651       Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
652       if(!currentFrameBuffer ||
653          !Dali::Equals(currentFrameBuffer.GetColorTexture().GetWidth(), size.width) ||
654          !Dali::Equals(currentFrameBuffer.GetColorTexture().GetHeight(), size.height))
655       {
656         mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_COLOR);
657         mRenderTask.ResetViewportGuideActor();
658         mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
659
660         // create offscreen buffer of new size to render our child actors to
661         mTexture     = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height));
662         mFrameBuffer = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
663         mFrameBuffer.AttachColorTexture(mTexture);
664         DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
665         Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mFrameBuffer, 0u);
666
667         Property::Map imagePropertyMap;
668         imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
669         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
670         // To make sure this visual call LoadTexture API immediate.
671         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, Toolkit::ImageVisual::LoadPolicy::IMMEDIATE);
672         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, Toolkit::ImageVisual::ReleasePolicy::DESTROYED);
673         // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling.
674         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f));
675         mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap);
676
677         // Use premultiplied alpha when we use FBO
678         if(mVisual)
679         {
680           Toolkit::GetImplementation(mVisual).EnablePreMultipliedAlpha(true);
681         }
682
683         Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
684
685         mRenderTask.SetFrameBuffer(mFrameBuffer);
686         mRenderTask.SetClearEnabled(true);
687         mRenderTask.SetClearColor(Color::TRANSPARENT);
688       }
689     }
690     else
691     {
692       mRenderTask.SetViewportGuideActor(Self());
693       if(mRenderTask.GetFrameBuffer())
694       {
695         mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA);
696         FrameBuffer framebuffer;
697         mRenderTask.SetFrameBuffer(framebuffer);
698         mRenderTask.SetClearEnabled(false);
699
700         Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
701
702         mVisual.Reset();
703         mFrameBuffer.Reset();
704         mTexture.Reset();
705       }
706     }
707
708     RotateCamera();
709   }
710 }
711
712 void SceneView::OnWindowResized(Window window, Window::WindowSize size)
713 {
714   mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
715   RotateCamera();
716 }
717
718 void SceneView::RotateCamera()
719 {
720   if(mUseFrameBuffer)
721   {
722     DevelCameraActor::RotateProjection(mSelectedCamera, DEFAULT_ORIENTATION);
723   }
724   else
725   {
726     DevelCameraActor::RotateProjection(mSelectedCamera, mWindowOrientation);
727   }
728 }
729
730 void SceneView::UpdateSkybox(const std::string& skyboxUrl, Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
731 {
732   bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
733   if(mSkyboxUrl != skyboxUrl || mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
734   {
735     mSkyboxDirty              = true;
736     mSkyboxResourceReady      = false;
737     mSkyboxUrl                = skyboxUrl;
738     mSkyboxEnvironmentMapType = skyboxEnvironmentMapType;
739   }
740
741   if(mSkyboxUrl.empty())
742   {
743     if(mSkyboxLoadTask)
744     {
745       Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
746       mSkyboxLoadTask.Reset();
747     }
748     mSkyboxDirty         = false;
749     mSkyboxResourceReady = true;
750   }
751   else
752   {
753     if(isOnScene && mSkyboxDirty)
754     {
755       if(mSkyboxLoadTask)
756       {
757         Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
758         mSkyboxLoadTask.Reset();
759       }
760
761       mSkyboxLoadTask = new EnvironmentMapLoadTask(mSkyboxUrl, mSkyboxEnvironmentMapType, MakeCallback(this, &SceneView::OnSkyboxLoadComplete));
762       Dali::AsyncTaskManager::Get().AddTask(mSkyboxLoadTask);
763       mSkyboxDirty = false;
764     }
765   }
766
767   if(IsResourceReady())
768   {
769     Control::SetResourceReady(false);
770   }
771 }
772
773 void SceneView::OnSkyboxLoadComplete()
774 {
775   if(!mSkybox)
776   {
777     mSkybox = CreateSkybox();
778     SetSkyboxIntensity(mSkyboxIntensity);
779     SetSkyboxOrientation(mSkyboxOrientation);
780     if(mRootLayer)
781     {
782       mRootLayer.Add(mSkybox);
783     }
784   }
785
786   mSkyboxResourceReady = true;
787   if(IsResourceReady())
788   {
789     Control::SetResourceReady(false);
790   }
791
792   mSkyboxTexture = mSkyboxLoadTask->GetLoadedTexture();
793   Shader skyboxShader;
794   if(mSkyboxEnvironmentMapType == Scene3D::EnvironmentMapType::CUBEMAP)
795   {
796     skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
797   }
798   else
799   {
800     skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_EQUIRECTANGULAR_SHADER_FRAG.data());
801   }
802
803   Renderer skyboxRenderer = (mSkybox.GetRendererCount() > 0u) ? mSkybox.GetRendererAt(0u) : Renderer();
804   if(skyboxRenderer)
805   {
806     Dali::TextureSet skyboxTextures = TextureSet::New();
807     skyboxTextures.SetTexture(0, mSkyboxTexture);
808     skyboxRenderer.SetTextures(skyboxTextures);
809     skyboxRenderer.SetShader(skyboxShader);
810   }
811
812   mSkyboxLoadTask.Reset();
813 }
814
815 void SceneView::OnIblDiffuseLoadComplete()
816 {
817   mDiffuseTexture          = mIblDiffuseLoadTask->GetLoadedTexture();
818   mIblDiffuseResourceReady = true;
819   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
820   {
821     OnIblLoadComplete();
822   }
823   mIblDiffuseLoadTask.Reset();
824 }
825
826 void SceneView::OnIblSpecularLoadComplete()
827 {
828   mSpecularTexture          = mIblSpecularLoadTask->GetLoadedTexture();
829   mIblSpecularResourceReady = true;
830   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
831   {
832     OnIblLoadComplete();
833   }
834   mIblSpecularLoadTask.Reset();
835 }
836
837 void SceneView::OnIblLoadComplete()
838 {
839   NotifyImageBasedLightTextureChange();
840   if(IsResourceReady())
841   {
842     Control::SetResourceReady(false);
843   }
844 }
845
846 void SceneView::NotifyImageBasedLightTextureChange()
847 {
848   for(auto&& item : mItems)
849   {
850     if(item)
851     {
852       item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
853     }
854   }
855 }
856
857 } // namespace Internal
858 } // namespace Scene3D
859 } // namespace Dali